1a3e0fd82Sopenharmony_ci/*
2a3e0fd82Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3a3e0fd82Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4a3e0fd82Sopenharmony_ci * you may not use this file except in compliance with the License.
5a3e0fd82Sopenharmony_ci * You may obtain a copy of the License at
6a3e0fd82Sopenharmony_ci *
7a3e0fd82Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8a3e0fd82Sopenharmony_ci *
9a3e0fd82Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10a3e0fd82Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11a3e0fd82Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12a3e0fd82Sopenharmony_ci * See the License for the specific language governing permissions and
13a3e0fd82Sopenharmony_ci * limitations under the License.
14a3e0fd82Sopenharmony_ci */
15a3e0fd82Sopenharmony_ci
16a3e0fd82Sopenharmony_ci#include "components/ui_image_view.h"
17a3e0fd82Sopenharmony_ci#include "common/image.h"
18a3e0fd82Sopenharmony_ci#include "common/typed_text.h"
19a3e0fd82Sopenharmony_ci#include "draw/draw_image.h"
20a3e0fd82Sopenharmony_ci#include "draw/draw_label.h"
21a3e0fd82Sopenharmony_ci#include "engines/gfx/gfx_engine_manager.h"
22a3e0fd82Sopenharmony_ci#include "gfx_utils/file.h"
23a3e0fd82Sopenharmony_ci#include "gfx_utils/image_info.h"
24a3e0fd82Sopenharmony_ci#include "gfx_utils/mem_api.h"
25a3e0fd82Sopenharmony_ci#include "imgdecode/cache_manager.h"
26a3e0fd82Sopenharmony_ci#if defined(ENABLE_GIF) && (ENABLE_GIF == 1)
27a3e0fd82Sopenharmony_ci#include "gif_lib.h"
28a3e0fd82Sopenharmony_ci#endif
29a3e0fd82Sopenharmony_ci
30a3e0fd82Sopenharmony_cinamespace OHOS {
31a3e0fd82Sopenharmony_ci#if defined(ENABLE_GIF) && (ENABLE_GIF == 1)
32a3e0fd82Sopenharmony_ciclass GifImageAnimator : public Animator, public AnimatorCallback {
33a3e0fd82Sopenharmony_cipublic:
34a3e0fd82Sopenharmony_ci    GifImageAnimator(UIView* view, const char* src)
35a3e0fd82Sopenharmony_ci        : Animator(this, view, 0, true),
36a3e0fd82Sopenharmony_ci          gifFileType_(nullptr),
37a3e0fd82Sopenharmony_ci          imageIndex_(0),
38a3e0fd82Sopenharmony_ci          delayTime_(0),
39a3e0fd82Sopenharmony_ci          lastRunTime_(0),
40a3e0fd82Sopenharmony_ci          deltaTime_(0),
41a3e0fd82Sopenharmony_ci          gifDataSize_(0),
42a3e0fd82Sopenharmony_ci          src_(src)
43a3e0fd82Sopenharmony_ci    {
44a3e0fd82Sopenharmony_ci    }
45a3e0fd82Sopenharmony_ci
46a3e0fd82Sopenharmony_ci    virtual ~GifImageAnimator()
47a3e0fd82Sopenharmony_ci    {
48a3e0fd82Sopenharmony_ci        CloseGifFile();
49a3e0fd82Sopenharmony_ci    }
50a3e0fd82Sopenharmony_ci
51a3e0fd82Sopenharmony_ci    void Callback(UIView* view) override;
52a3e0fd82Sopenharmony_ci
53a3e0fd82Sopenharmony_ci    void SetGifFileType(GifFileType* gifFileType)
54a3e0fd82Sopenharmony_ci    {
55a3e0fd82Sopenharmony_ci        gifFileType_ = gifFileType;
56a3e0fd82Sopenharmony_ci    }
57a3e0fd82Sopenharmony_ci
58a3e0fd82Sopenharmony_ci    uint32_t SetGifFrame(GifFileType* gifFileType, int32_t imageIndex, UIImageView* imageView) const;
59a3e0fd82Sopenharmony_ci    void DealGifImageData(const GifFileType* gifFileType,
60a3e0fd82Sopenharmony_ci                          const GifImageDesc* gifImageDesc,
61a3e0fd82Sopenharmony_ci                          const SavedImage* savedImage,
62a3e0fd82Sopenharmony_ci                          GraphicsControlBlock gcb,
63a3e0fd82Sopenharmony_ci                          const ColorMapObject* colorMap) const;
64a3e0fd82Sopenharmony_ci    void OpenGifFile(const char* src);
65a3e0fd82Sopenharmony_ci    void CloseGifFile();
66a3e0fd82Sopenharmony_ci
67a3e0fd82Sopenharmony_ciprivate:
68a3e0fd82Sopenharmony_ci    GifFileType* GetGifFileType()
69a3e0fd82Sopenharmony_ci    {
70a3e0fd82Sopenharmony_ci        if (gifFileType_ == nullptr) {
71a3e0fd82Sopenharmony_ci            OpenGifFile(src_);
72a3e0fd82Sopenharmony_ci        }
73a3e0fd82Sopenharmony_ci        return gifFileType_;
74a3e0fd82Sopenharmony_ci    }
75a3e0fd82Sopenharmony_ci
76a3e0fd82Sopenharmony_ci    GifFileType* gifFileType_;
77a3e0fd82Sopenharmony_ci    int32_t imageIndex_;
78a3e0fd82Sopenharmony_ci    uint32_t delayTime_;
79a3e0fd82Sopenharmony_ci    uint32_t lastRunTime_;
80a3e0fd82Sopenharmony_ci    uint32_t deltaTime_;
81a3e0fd82Sopenharmony_ci    uint32_t gifDataSize_;
82a3e0fd82Sopenharmony_ci    uint8_t* gifImageData_ = nullptr;
83a3e0fd82Sopenharmony_ci    const char* src_;
84a3e0fd82Sopenharmony_ci};
85a3e0fd82Sopenharmony_ci
86a3e0fd82Sopenharmony_civoid GifImageAnimator::OpenGifFile(const char* src)
87a3e0fd82Sopenharmony_ci{
88a3e0fd82Sopenharmony_ci    int error = D_GIF_SUCCEEDED;
89a3e0fd82Sopenharmony_ci    GifFileType* gifFileType = DGifOpenFileName(src, &error);
90a3e0fd82Sopenharmony_ci    if (error != D_GIF_SUCCEEDED) {
91a3e0fd82Sopenharmony_ci        return;
92a3e0fd82Sopenharmony_ci    }
93a3e0fd82Sopenharmony_ci    DGifSlurp(gifFileType);
94a3e0fd82Sopenharmony_ci    /* 3 : when change single pixel to byte, the buffer should divided by 8, equal to shift right 3 bits. */
95a3e0fd82Sopenharmony_ci    uint8_t pixelByteSize = DrawUtils::GetPxSizeByColorMode(ARGB8888) >> 3;
96a3e0fd82Sopenharmony_ci    gifDataSize_ = gifFileType->SWidth * gifFileType->SHeight * pixelByteSize;
97a3e0fd82Sopenharmony_ci    gifImageData_ = static_cast<uint8_t*>(UIMalloc(gifDataSize_));
98a3e0fd82Sopenharmony_ci    if (gifImageData_ == nullptr) {
99a3e0fd82Sopenharmony_ci        CloseGifFile();
100a3e0fd82Sopenharmony_ci        return;
101a3e0fd82Sopenharmony_ci    }
102a3e0fd82Sopenharmony_ci    SetGifFileType(gifFileType);
103a3e0fd82Sopenharmony_ci}
104a3e0fd82Sopenharmony_ci
105a3e0fd82Sopenharmony_civoid GifImageAnimator::CloseGifFile()
106a3e0fd82Sopenharmony_ci{
107a3e0fd82Sopenharmony_ci    GifFileType* gifFileType = GetGifFileType();
108a3e0fd82Sopenharmony_ci    if (gifFileType != nullptr) {
109a3e0fd82Sopenharmony_ci        DGifCloseFile(gifFileType, nullptr);
110a3e0fd82Sopenharmony_ci    }
111a3e0fd82Sopenharmony_ci    if (gifImageData_ != nullptr) {
112a3e0fd82Sopenharmony_ci        UIFree(reinterpret_cast<void*>(const_cast<uint8_t*>(gifImageData_)));
113a3e0fd82Sopenharmony_ci        gifImageData_ = nullptr;
114a3e0fd82Sopenharmony_ci    }
115a3e0fd82Sopenharmony_ci}
116a3e0fd82Sopenharmony_ci
117a3e0fd82Sopenharmony_civoid GifImageAnimator::Callback(UIView* view)
118a3e0fd82Sopenharmony_ci{
119a3e0fd82Sopenharmony_ci    if (view == nullptr) {
120a3e0fd82Sopenharmony_ci        return;
121a3e0fd82Sopenharmony_ci    }
122a3e0fd82Sopenharmony_ci    UIImageView* imageView = static_cast<UIImageView*>(view);
123a3e0fd82Sopenharmony_ci    uint32_t curTime = GetRunTime();
124a3e0fd82Sopenharmony_ci    if (curTime != 0) {
125a3e0fd82Sopenharmony_ci        if (curTime + deltaTime_ - lastRunTime_ >= delayTime_) {
126a3e0fd82Sopenharmony_ci            deltaTime_ = curTime + deltaTime_ - lastRunTime_ - delayTime_;
127a3e0fd82Sopenharmony_ci            lastRunTime_ = curTime;
128a3e0fd82Sopenharmony_ci        } else {
129a3e0fd82Sopenharmony_ci            return;
130a3e0fd82Sopenharmony_ci        }
131a3e0fd82Sopenharmony_ci    }
132a3e0fd82Sopenharmony_ci    GifFileType* gifFileType = GetGifFileType();
133a3e0fd82Sopenharmony_ci    if (gifFileType != nullptr) {
134a3e0fd82Sopenharmony_ci        delayTime_ = SetGifFrame(gifFileType, imageIndex_, imageView);
135a3e0fd82Sopenharmony_ci        imageIndex_ = (imageIndex_ < gifFileType->ImageCount - 1) ? (imageIndex_ + 1) : 0;
136a3e0fd82Sopenharmony_ci    }
137a3e0fd82Sopenharmony_ci}
138a3e0fd82Sopenharmony_ci
139a3e0fd82Sopenharmony_ciuint32_t GifImageAnimator::SetGifFrame(GifFileType* gifFileType, int32_t imageIndex, UIImageView* imageView) const
140a3e0fd82Sopenharmony_ci{
141a3e0fd82Sopenharmony_ci    SavedImage* savedImage = &(gifFileType->SavedImages[imageIndex]);
142a3e0fd82Sopenharmony_ci    if (savedImage == nullptr) {
143a3e0fd82Sopenharmony_ci        return 0;
144a3e0fd82Sopenharmony_ci    }
145a3e0fd82Sopenharmony_ci    GifImageDesc* gifImageDesc = &(savedImage->ImageDesc);
146a3e0fd82Sopenharmony_ci    if (gifImageDesc == nullptr) {
147a3e0fd82Sopenharmony_ci        return 0;
148a3e0fd82Sopenharmony_ci    }
149a3e0fd82Sopenharmony_ci    GraphicsControlBlock gcb;
150a3e0fd82Sopenharmony_ci    int32_t ret = DGifSavedExtensionToGCB(gifFileType, imageIndex, &gcb);
151a3e0fd82Sopenharmony_ci    if (ret != GIF_OK) {
152a3e0fd82Sopenharmony_ci        return 0;
153a3e0fd82Sopenharmony_ci    }
154a3e0fd82Sopenharmony_ci    ColorMapObject* colorMap = nullptr;
155a3e0fd82Sopenharmony_ci    if (gifImageDesc->ColorMap != nullptr) {
156a3e0fd82Sopenharmony_ci        colorMap = gifImageDesc->ColorMap;
157a3e0fd82Sopenharmony_ci    } else {
158a3e0fd82Sopenharmony_ci        colorMap = gifFileType->SColorMap;
159a3e0fd82Sopenharmony_ci    }
160a3e0fd82Sopenharmony_ci
161a3e0fd82Sopenharmony_ci    DealGifImageData(gifFileType, gifImageDesc, savedImage, gcb, colorMap);
162a3e0fd82Sopenharmony_ci    if (gifImageData_ == nullptr) {
163a3e0fd82Sopenharmony_ci        return 0;
164a3e0fd82Sopenharmony_ci    }
165a3e0fd82Sopenharmony_ci    imageView->gifFrameFlag_ = true;
166a3e0fd82Sopenharmony_ci    ImageInfo gifFrame;
167a3e0fd82Sopenharmony_ci    gifFrame.header.width = gifFileType->SWidth;
168a3e0fd82Sopenharmony_ci    gifFrame.header.height = gifFileType->SHeight;
169a3e0fd82Sopenharmony_ci    gifFrame.header.colorMode = ARGB8888;
170a3e0fd82Sopenharmony_ci    gifFrame.dataSize = gifDataSize_;
171a3e0fd82Sopenharmony_ci    gifFrame.data = gifImageData_;
172a3e0fd82Sopenharmony_ci    imageView->SetSrc(&gifFrame);
173a3e0fd82Sopenharmony_ci
174a3e0fd82Sopenharmony_ci    if (gcb.DelayTime >= 0) {
175a3e0fd82Sopenharmony_ci        return static_cast<uint32_t>(gcb.DelayTime) * 10; // 10: change hundredths (1/100) of a second to millisecond
176a3e0fd82Sopenharmony_ci    } else {
177a3e0fd82Sopenharmony_ci        return 0;
178a3e0fd82Sopenharmony_ci    }
179a3e0fd82Sopenharmony_ci}
180a3e0fd82Sopenharmony_ci
181a3e0fd82Sopenharmony_civoid GifImageAnimator::DealGifImageData(const GifFileType* gifFileType,
182a3e0fd82Sopenharmony_ci                                        const GifImageDesc* gifImageDesc,
183a3e0fd82Sopenharmony_ci                                        const SavedImage* savedImage,
184a3e0fd82Sopenharmony_ci                                        GraphicsControlBlock gcb,
185a3e0fd82Sopenharmony_ci                                        const ColorMapObject* colorMap) const
186a3e0fd82Sopenharmony_ci{
187a3e0fd82Sopenharmony_ci    if ((gifFileType == nullptr) || (gifImageDesc == nullptr) || (savedImage == nullptr) ||
188a3e0fd82Sopenharmony_ci        (savedImage->RasterBits == nullptr) || (colorMap == nullptr) || (colorMap->Colors == nullptr)) {
189a3e0fd82Sopenharmony_ci        return;
190a3e0fd82Sopenharmony_ci    }
191a3e0fd82Sopenharmony_ci    uint8_t colorIndex = 0;
192a3e0fd82Sopenharmony_ci    GifColorType* gifColorType = nullptr;
193a3e0fd82Sopenharmony_ci    uint32_t index = 0;
194a3e0fd82Sopenharmony_ci
195a3e0fd82Sopenharmony_ci    for (int32_t x = 0; x < gifFileType->SHeight; x++) {
196a3e0fd82Sopenharmony_ci        for (int32_t y = 0; y < gifFileType->SWidth; y++) {
197a3e0fd82Sopenharmony_ci            bool transparentColor = true;
198a3e0fd82Sopenharmony_ci            if ((x >= gifImageDesc->Top) && (x < gifImageDesc->Top + gifImageDesc->Height) &&
199a3e0fd82Sopenharmony_ci                (y >= gifImageDesc->Left) && (y < gifImageDesc->Left + gifImageDesc->Width)) {
200a3e0fd82Sopenharmony_ci                int32_t loc = (x - gifImageDesc->Top) * gifImageDesc->Width + (y - gifImageDesc->Left);
201a3e0fd82Sopenharmony_ci                colorIndex = savedImage->RasterBits[loc];
202a3e0fd82Sopenharmony_ci
203a3e0fd82Sopenharmony_ci                if ((gcb.DisposalMode != DISPOSE_DO_NOT) || (gcb.TransparentColor == NO_TRANSPARENT_COLOR) ||
204a3e0fd82Sopenharmony_ci                    (colorIndex != gcb.TransparentColor)) {
205a3e0fd82Sopenharmony_ci                    transparentColor = false;
206a3e0fd82Sopenharmony_ci                }
207a3e0fd82Sopenharmony_ci            }
208a3e0fd82Sopenharmony_ci            if (transparentColor) {
209a3e0fd82Sopenharmony_ci                index += 4; // 4: skip color index, keep last frame color
210a3e0fd82Sopenharmony_ci            } else {
211a3e0fd82Sopenharmony_ci                gifColorType = &colorMap->Colors[colorIndex];
212a3e0fd82Sopenharmony_ci                gifImageData_[index++] = gifColorType->Blue;
213a3e0fd82Sopenharmony_ci                gifImageData_[index++] = gifColorType->Green;
214a3e0fd82Sopenharmony_ci                gifImageData_[index++] = gifColorType->Red;
215a3e0fd82Sopenharmony_ci                gifImageData_[index++] = OPA_OPAQUE;
216a3e0fd82Sopenharmony_ci            }
217a3e0fd82Sopenharmony_ci        }
218a3e0fd82Sopenharmony_ci    }
219a3e0fd82Sopenharmony_ci}
220a3e0fd82Sopenharmony_ci#endif
221a3e0fd82Sopenharmony_ci
222a3e0fd82Sopenharmony_ciUIImageView::UIImageView()
223a3e0fd82Sopenharmony_ci    : imageWidth_(0),
224a3e0fd82Sopenharmony_ci      imageHeight_(0),
225a3e0fd82Sopenharmony_ci      autoEnable_(true),
226a3e0fd82Sopenharmony_ci      needRefresh_(false),
227a3e0fd82Sopenharmony_ci      colorFormat_(UNKNOWN),
228a3e0fd82Sopenharmony_ci      blurLevel_(BlurLevel::LEVEL0),
229a3e0fd82Sopenharmony_ci      algorithm_(TransformAlgorithm::BILINEAR),
230a3e0fd82Sopenharmony_ci      reserve_(0)
231a3e0fd82Sopenharmony_ci{
232a3e0fd82Sopenharmony_ci    style_ = &(StyleDefault::GetBackgroundTransparentStyle());
233a3e0fd82Sopenharmony_ci#if defined(ENABLE_GIF) && (ENABLE_GIF == 1)
234a3e0fd82Sopenharmony_ci    gifImageAnimator_ = nullptr;
235a3e0fd82Sopenharmony_ci    gifFrameFlag_ = false;
236a3e0fd82Sopenharmony_ci#endif
237a3e0fd82Sopenharmony_ci}
238a3e0fd82Sopenharmony_ci
239a3e0fd82Sopenharmony_ciUIImageView::~UIImageView()
240a3e0fd82Sopenharmony_ci{
241a3e0fd82Sopenharmony_ci#if defined(ENABLE_GIF) && (ENABLE_GIF == 1)
242a3e0fd82Sopenharmony_ci    RemoveAndStopGifAnimator();
243a3e0fd82Sopenharmony_ci#endif
244a3e0fd82Sopenharmony_ci    if (drawTransMap_ != nullptr) {
245a3e0fd82Sopenharmony_ci        delete drawTransMap_;
246a3e0fd82Sopenharmony_ci        drawTransMap_ = nullptr;
247a3e0fd82Sopenharmony_ci    }
248a3e0fd82Sopenharmony_ci    if (contentMatrix_ != nullptr) {
249a3e0fd82Sopenharmony_ci        delete contentMatrix_;
250a3e0fd82Sopenharmony_ci        contentMatrix_ = nullptr;
251a3e0fd82Sopenharmony_ci    }
252a3e0fd82Sopenharmony_ci}
253a3e0fd82Sopenharmony_ci
254a3e0fd82Sopenharmony_civoid UIImageView::SetResizeMode(ImageResizeMode mode)
255a3e0fd82Sopenharmony_ci{
256a3e0fd82Sopenharmony_ci    // when automatic adaptation is enabled only save the mode, no need to update the DrawtransMap
257a3e0fd82Sopenharmony_ci    if (autoEnable_) {
258a3e0fd82Sopenharmony_ci        imageResizeMode_ = mode;
259a3e0fd82Sopenharmony_ci    } else if (imageResizeMode_ != mode) {
260a3e0fd82Sopenharmony_ci        needRefresh_ = true;
261a3e0fd82Sopenharmony_ci        ReMeasure();
262a3e0fd82Sopenharmony_ci        // must update the mode, before calling UpdateDrawTransMap
263a3e0fd82Sopenharmony_ci        imageResizeMode_ = mode;
264a3e0fd82Sopenharmony_ci        UpdateDrawTransMap(true);
265a3e0fd82Sopenharmony_ci    }
266a3e0fd82Sopenharmony_ci}
267a3e0fd82Sopenharmony_ci
268a3e0fd82Sopenharmony_civoid UIImageView::AdjustScaleAndTranslate(Vector3<float>& scale, Vector3<int16_t>& translate,
269a3e0fd82Sopenharmony_ci    int16_t widgetWidth, int16_t widgetHeight) const
270a3e0fd82Sopenharmony_ci{
271a3e0fd82Sopenharmony_ci    // adjust scale
272a3e0fd82Sopenharmony_ci    float ratio = 1.0f;
273a3e0fd82Sopenharmony_ci    switch (imageResizeMode_) {
274a3e0fd82Sopenharmony_ci        case ImageResizeMode::COVER:
275a3e0fd82Sopenharmony_ci            ratio = MATH_MAX(scale.x_, scale.y_);
276a3e0fd82Sopenharmony_ci            break;
277a3e0fd82Sopenharmony_ci        case ImageResizeMode::CONTAIN:
278a3e0fd82Sopenharmony_ci            ratio = MATH_MIN(scale.x_, scale.y_);
279a3e0fd82Sopenharmony_ci            break;
280a3e0fd82Sopenharmony_ci        case ImageResizeMode::CENTER: // ratio is 1.0f
281a3e0fd82Sopenharmony_ci            break;
282a3e0fd82Sopenharmony_ci        case ImageResizeMode::SCALE_DOWN:
283a3e0fd82Sopenharmony_ci            ratio = MATH_MIN(scale.x_, scale.y_);
284a3e0fd82Sopenharmony_ci            ratio = MATH_MIN(ratio, 1.0f);
285a3e0fd82Sopenharmony_ci            break;
286a3e0fd82Sopenharmony_ci        case ImageResizeMode::FILL: // do nothing
287a3e0fd82Sopenharmony_ci            return;
288a3e0fd82Sopenharmony_ci        default:
289a3e0fd82Sopenharmony_ci            break;
290a3e0fd82Sopenharmony_ci    }
291a3e0fd82Sopenharmony_ci    if (scale.x_ != ratio) {
292a3e0fd82Sopenharmony_ci        scale.x_ = ratio;
293a3e0fd82Sopenharmony_ci        // 0.5: adjust the x-coordinate of the content to the center of widget
294a3e0fd82Sopenharmony_ci        translate.x_ += (static_cast<float>(widgetWidth) - static_cast<float>(imageWidth_) * ratio) * 0.5f;
295a3e0fd82Sopenharmony_ci    }
296a3e0fd82Sopenharmony_ci    if (scale.y_ != ratio) {
297a3e0fd82Sopenharmony_ci        scale.y_ = ratio;
298a3e0fd82Sopenharmony_ci        // 0.5: adjust the y-coordinate of the content to the center of widget
299a3e0fd82Sopenharmony_ci        translate.y_ += (static_cast<float>(widgetHeight) - static_cast<float>(imageHeight_) * ratio) * 0.5f;
300a3e0fd82Sopenharmony_ci    }
301a3e0fd82Sopenharmony_ci}
302a3e0fd82Sopenharmony_ci
303a3e0fd82Sopenharmony_civoid UIImageView::UpdateContentMatrix()
304a3e0fd82Sopenharmony_ci{
305a3e0fd82Sopenharmony_ci    Rect viewRect = GetOrigRect();
306a3e0fd82Sopenharmony_ci    if (autoEnable_ || (imageResizeMode_ == ImageResizeMode::NONE) ||
307a3e0fd82Sopenharmony_ci        (imageWidth_ == viewRect.GetWidth() && imageHeight_ == viewRect.GetHeight()) ||
308a3e0fd82Sopenharmony_ci        imageWidth_ == 0 || imageHeight_ == 0) {
309a3e0fd82Sopenharmony_ci        if (contentMatrix_ != nullptr) {
310a3e0fd82Sopenharmony_ci            delete contentMatrix_;
311a3e0fd82Sopenharmony_ci            contentMatrix_ = nullptr;
312a3e0fd82Sopenharmony_ci        }
313a3e0fd82Sopenharmony_ci        return;
314a3e0fd82Sopenharmony_ci    }
315a3e0fd82Sopenharmony_ci    if (contentMatrix_ == nullptr) {
316a3e0fd82Sopenharmony_ci        contentMatrix_ = new Matrix4<float>();
317a3e0fd82Sopenharmony_ci        if (contentMatrix_ == nullptr) {
318a3e0fd82Sopenharmony_ci            GRAPHIC_LOGE("can not new contentMatrix");
319a3e0fd82Sopenharmony_ci            return;
320a3e0fd82Sopenharmony_ci        }
321a3e0fd82Sopenharmony_ci    }
322a3e0fd82Sopenharmony_ci    int16_t widgetWidth = viewRect.GetWidth() - style_->paddingLeft_ - style_->paddingRight_ -
323a3e0fd82Sopenharmony_ci        style_->borderWidth_ * 2; // 2: excludes the border-left and border-right
324a3e0fd82Sopenharmony_ci    int16_t widgetHeight = viewRect.GetHeight() - style_->paddingTop_ - style_->paddingBottom_ -
325a3e0fd82Sopenharmony_ci        style_->borderWidth_ * 2; // 2: excludes the border-top and border-bottom
326a3e0fd82Sopenharmony_ci
327a3e0fd82Sopenharmony_ci    float scaleX = static_cast<float>(widgetWidth) / static_cast<float>(imageWidth_);
328a3e0fd82Sopenharmony_ci    float scaleY = static_cast<float>(widgetHeight) / static_cast<float>(imageHeight_);
329a3e0fd82Sopenharmony_ci    Vector3<float> scale(scaleX, scaleY, 1.0f);
330a3e0fd82Sopenharmony_ci    Vector3<int16_t> translate(style_->paddingLeft_ + style_->borderWidth_,
331a3e0fd82Sopenharmony_ci        style_->paddingTop_ + style_->borderWidth_, 0);
332a3e0fd82Sopenharmony_ci    AdjustScaleAndTranslate(scale, translate, widgetWidth, widgetHeight);
333a3e0fd82Sopenharmony_ci
334a3e0fd82Sopenharmony_ci    auto scaleMatrix = Matrix4<float>::Scale(scale, Vector3<float>(viewRect.GetX(), viewRect.GetY(), 0));
335a3e0fd82Sopenharmony_ci    auto translateMatrix = Matrix4<float>::Translate(Vector3<float>(translate.x_, translate.y_, 0));
336a3e0fd82Sopenharmony_ci    *contentMatrix_ = translateMatrix * scaleMatrix;
337a3e0fd82Sopenharmony_ci}
338a3e0fd82Sopenharmony_ci
339a3e0fd82Sopenharmony_civoid UIImageView::UpdateDrawTransMap(bool updateContentMatrix)
340a3e0fd82Sopenharmony_ci{
341a3e0fd82Sopenharmony_ci    auto viewRect = GetOrigRect();
342a3e0fd82Sopenharmony_ci    if (updateContentMatrix || (drawTransMap_ != nullptr &&
343a3e0fd82Sopenharmony_ci        (drawTransMap_->GetTransMapRect().GetX() != viewRect.GetX() ||
344a3e0fd82Sopenharmony_ci        drawTransMap_->GetTransMapRect().GetY() != viewRect.GetY()))) {
345a3e0fd82Sopenharmony_ci        UpdateContentMatrix();
346a3e0fd82Sopenharmony_ci    }
347a3e0fd82Sopenharmony_ci    // has no transformation
348a3e0fd82Sopenharmony_ci    if ((contentMatrix_ == nullptr) && ((transMap_ == nullptr) || transMap_->IsInvalid())) {
349a3e0fd82Sopenharmony_ci        if (drawTransMap_ != nullptr) {
350a3e0fd82Sopenharmony_ci            delete drawTransMap_;
351a3e0fd82Sopenharmony_ci            drawTransMap_ = nullptr;
352a3e0fd82Sopenharmony_ci        }
353a3e0fd82Sopenharmony_ci        return;
354a3e0fd82Sopenharmony_ci    }
355a3e0fd82Sopenharmony_ci    if (drawTransMap_ == nullptr) {
356a3e0fd82Sopenharmony_ci        drawTransMap_ = new TransformMap();
357a3e0fd82Sopenharmony_ci        if (drawTransMap_ == nullptr) {
358a3e0fd82Sopenharmony_ci            GRAPHIC_LOGE("can not new drawTransMap");
359a3e0fd82Sopenharmony_ci            return;
360a3e0fd82Sopenharmony_ci        }
361a3e0fd82Sopenharmony_ci    }
362a3e0fd82Sopenharmony_ci    if (contentMatrix_ != nullptr) {
363a3e0fd82Sopenharmony_ci        drawTransMap_->SetTransMapRect(Rect(viewRect.GetX(), viewRect.GetY(),
364a3e0fd82Sopenharmony_ci            viewRect.GetX() + imageWidth_ - 1, viewRect.GetY() + imageHeight_ - 1));
365a3e0fd82Sopenharmony_ci    } else {
366a3e0fd82Sopenharmony_ci        drawTransMap_->SetTransMapRect(viewRect);
367a3e0fd82Sopenharmony_ci    }
368a3e0fd82Sopenharmony_ci    // only contentMatrix
369a3e0fd82Sopenharmony_ci    if (transMap_ == nullptr || transMap_->IsInvalid()) {
370a3e0fd82Sopenharmony_ci        if (contentMatrix_ == nullptr) {
371a3e0fd82Sopenharmony_ci            GRAPHIC_LOGE("Text: UpdateDrawTransMap contentMatrix_ is nullptr");
372a3e0fd82Sopenharmony_ci            return;
373a3e0fd82Sopenharmony_ci        }
374a3e0fd82Sopenharmony_ci        drawTransMap_->SetMatrix(*contentMatrix_);
375a3e0fd82Sopenharmony_ci        return;
376a3e0fd82Sopenharmony_ci    }
377a3e0fd82Sopenharmony_ci    // update the transMap, now the transMap is not nullptr
378a3e0fd82Sopenharmony_ci    if (!(transMap_->GetTransMapRect() == viewRect)) {
379a3e0fd82Sopenharmony_ci        transMap_->SetTransMapRect(viewRect);
380a3e0fd82Sopenharmony_ci    }
381a3e0fd82Sopenharmony_ci    // only transMap
382a3e0fd82Sopenharmony_ci    if (contentMatrix_ == nullptr) {
383a3e0fd82Sopenharmony_ci        *drawTransMap_ = *transMap_;
384a3e0fd82Sopenharmony_ci        return;
385a3e0fd82Sopenharmony_ci    }
386a3e0fd82Sopenharmony_ci    // merge the transMap and content matrix
387a3e0fd82Sopenharmony_ci    auto rect = transMap_->GetTransMapRect();
388a3e0fd82Sopenharmony_ci    auto translate = Matrix4<float>::Translate(Vector3<float>(-rect.GetX(), -rect.GetY(), 0));
389a3e0fd82Sopenharmony_ci    auto matrix = transMap_->GetTransformMatrix() * translate;
390a3e0fd82Sopenharmony_ci    matrix = matrix * (*contentMatrix_);
391a3e0fd82Sopenharmony_ci    drawTransMap_->SetMatrix(matrix);
392a3e0fd82Sopenharmony_ci}
393a3e0fd82Sopenharmony_ci
394a3e0fd82Sopenharmony_civoid UIImageView::SetHeight(int16_t height)
395a3e0fd82Sopenharmony_ci{
396a3e0fd82Sopenharmony_ci    if (GetHeight() != height) {
397a3e0fd82Sopenharmony_ci        UIView::SetHeight(height);
398a3e0fd82Sopenharmony_ci        UpdateDrawTransMap(true);
399a3e0fd82Sopenharmony_ci    }
400a3e0fd82Sopenharmony_ci}
401a3e0fd82Sopenharmony_ci
402a3e0fd82Sopenharmony_civoid UIImageView::SetWidth(int16_t width)
403a3e0fd82Sopenharmony_ci{
404a3e0fd82Sopenharmony_ci    if (GetWidth() != width) {
405a3e0fd82Sopenharmony_ci        UIView::SetWidth(width);
406a3e0fd82Sopenharmony_ci        UpdateDrawTransMap(true);
407a3e0fd82Sopenharmony_ci    }
408a3e0fd82Sopenharmony_ci}
409a3e0fd82Sopenharmony_ci
410a3e0fd82Sopenharmony_cibool UIImageView::OnPreDraw(Rect& invalidatedArea) const
411a3e0fd82Sopenharmony_ci{
412a3e0fd82Sopenharmony_ci    if ((image_.GetSrcType() == IMG_SRC_UNKNOWN)) {
413a3e0fd82Sopenharmony_ci        return true;
414a3e0fd82Sopenharmony_ci    }
415a3e0fd82Sopenharmony_ci
416a3e0fd82Sopenharmony_ci    if ((colorFormat_ == RGB565) || (colorFormat_ == RGB888)) {
417a3e0fd82Sopenharmony_ci        if (GetRect().IsContains(invalidatedArea)) {
418a3e0fd82Sopenharmony_ci            return true;
419a3e0fd82Sopenharmony_ci        }
420a3e0fd82Sopenharmony_ci        invalidatedArea.Intersect(invalidatedArea, GetRect());
421a3e0fd82Sopenharmony_ci    }
422a3e0fd82Sopenharmony_ci
423a3e0fd82Sopenharmony_ci    return false;
424a3e0fd82Sopenharmony_ci}
425a3e0fd82Sopenharmony_ci
426a3e0fd82Sopenharmony_civoid UIImageView::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
427a3e0fd82Sopenharmony_ci{
428a3e0fd82Sopenharmony_ci    OpacityType opa = GetMixOpaScale();
429a3e0fd82Sopenharmony_ci    BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
430a3e0fd82Sopenharmony_ci    baseGfxEngine->DrawRect(gfxDstBuffer, GetRect(), invalidatedArea, *style_, opa);
431a3e0fd82Sopenharmony_ci    if ((imageHeight_ == 0) || (imageWidth_ == 0)) {
432a3e0fd82Sopenharmony_ci        return;
433a3e0fd82Sopenharmony_ci    }
434a3e0fd82Sopenharmony_ci    UpdateDrawTransMap();
435a3e0fd82Sopenharmony_ci    Rect viewRect = GetContentRect();
436a3e0fd82Sopenharmony_ci    Rect trunc(invalidatedArea);
437a3e0fd82Sopenharmony_ci    if (trunc.Intersect(trunc, viewRect)) {
438a3e0fd82Sopenharmony_ci        uint8_t srcType = image_.GetSrcType();
439a3e0fd82Sopenharmony_ci        if ((srcType == IMG_SRC_FILE) || (srcType == IMG_SRC_VARIABLE)) {
440a3e0fd82Sopenharmony_ci            Rect cordsTmp;
441a3e0fd82Sopenharmony_ci            cordsTmp.SetTop(viewRect.GetY());
442a3e0fd82Sopenharmony_ci            cordsTmp.SetBottom(viewRect.GetY() + imageHeight_ - 1);
443a3e0fd82Sopenharmony_ci
444a3e0fd82Sopenharmony_ci            if ((drawTransMap_ == nullptr) || drawTransMap_->IsInvalid()) {
445a3e0fd82Sopenharmony_ci                SetCordsTmpRect(gfxDstBuffer, viewRect, trunc, cordsTmp, opa);
446a3e0fd82Sopenharmony_ci            } else if ((drawTransMap_ != nullptr) && !drawTransMap_->IsInvalid()) {
447a3e0fd82Sopenharmony_ci                ImageInfo imgInfo;
448a3e0fd82Sopenharmony_ci                if (srcType == IMG_SRC_FILE) {
449a3e0fd82Sopenharmony_ci                    CacheEntry entry;
450a3e0fd82Sopenharmony_ci                    RetCode ret = CacheManager::GetInstance().Open(GetPath(), *style_, entry);
451a3e0fd82Sopenharmony_ci                    if (ret != RetCode::OK) {
452a3e0fd82Sopenharmony_ci                        return;
453a3e0fd82Sopenharmony_ci                    }
454a3e0fd82Sopenharmony_ci                    imgInfo = entry.GetImageInfo();
455a3e0fd82Sopenharmony_ci                } else {
456a3e0fd82Sopenharmony_ci                    imgInfo = *(GetImageInfo());
457a3e0fd82Sopenharmony_ci                }
458a3e0fd82Sopenharmony_ci                uint8_t pxSize = DrawUtils::GetPxSizeByColorMode(imgInfo.header.colorMode);
459a3e0fd82Sopenharmony_ci                TransformDataInfo imageTranDataInfo = {imgInfo.header, imgInfo.data, pxSize,
460a3e0fd82Sopenharmony_ci                                                       static_cast<BlurLevel>(blurLevel_),
461a3e0fd82Sopenharmony_ci                                                       static_cast<TransformAlgorithm>(algorithm_)};
462a3e0fd82Sopenharmony_ci                OpacityType opaScale = DrawUtils::GetMixOpacity(opa, style_->imageOpa_);
463a3e0fd82Sopenharmony_ci                Matrix4<float> scaleMatrix = drawTransMap_->GetScaleMatrix();
464a3e0fd82Sopenharmony_ci                int16_t paddingX = style_->paddingLeft_ * scaleMatrix[0][0];
465a3e0fd82Sopenharmony_ci                int16_t paddingY = style_->paddingTop_ * scaleMatrix[1][1];
466a3e0fd82Sopenharmony_ci                baseGfxEngine->DrawTransform(gfxDstBuffer, trunc, {paddingX, paddingY}, Color::Black(),
467a3e0fd82Sopenharmony_ci                                             opaScale, *drawTransMap_, imageTranDataInfo);
468a3e0fd82Sopenharmony_ci            }
469a3e0fd82Sopenharmony_ci        }
470a3e0fd82Sopenharmony_ci    }
471a3e0fd82Sopenharmony_ci}
472a3e0fd82Sopenharmony_ci
473a3e0fd82Sopenharmony_civoid UIImageView::SetCordsTmpRect(BufferInfo& gfxDstBuffer, Rect& viewRect, Rect& trunc,
474a3e0fd82Sopenharmony_ci                                  Rect& cordsTmp, OpacityType opa)
475a3e0fd82Sopenharmony_ci{
476a3e0fd82Sopenharmony_ci    while (cordsTmp.GetTop() <= viewRect.GetBottom()) {
477a3e0fd82Sopenharmony_ci        cordsTmp.SetLeft(viewRect.GetX());
478a3e0fd82Sopenharmony_ci        cordsTmp.SetRight(viewRect.GetX() + imageWidth_ - 1);
479a3e0fd82Sopenharmony_ci        while (cordsTmp.GetLeft() <= viewRect.GetRight()) {
480a3e0fd82Sopenharmony_ci            image_.DrawImage(gfxDstBuffer, cordsTmp, trunc, *style_, opa);
481a3e0fd82Sopenharmony_ci            cordsTmp.SetLeft(cordsTmp.GetLeft() + imageWidth_);
482a3e0fd82Sopenharmony_ci            cordsTmp.SetRight(cordsTmp.GetRight() + imageWidth_);
483a3e0fd82Sopenharmony_ci        }
484a3e0fd82Sopenharmony_ci        cordsTmp.SetTop(cordsTmp.GetTop() + imageHeight_);
485a3e0fd82Sopenharmony_ci        cordsTmp.SetBottom(cordsTmp.GetBottom() + imageHeight_);
486a3e0fd82Sopenharmony_ci    }
487a3e0fd82Sopenharmony_ci}
488a3e0fd82Sopenharmony_ci
489a3e0fd82Sopenharmony_civoid UIImageView::SetSrc(const char* src)
490a3e0fd82Sopenharmony_ci{
491a3e0fd82Sopenharmony_ci#if defined(ENABLE_GIF) && (ENABLE_GIF == 1)
492a3e0fd82Sopenharmony_ci    if (src == nullptr) {
493a3e0fd82Sopenharmony_ci        return;
494a3e0fd82Sopenharmony_ci    }
495a3e0fd82Sopenharmony_ci    const static uint8_t IMG_BYTES_TO_CHECK = 4; // 4: check 4 bytes of image file
496a3e0fd82Sopenharmony_ci    char buf[IMG_BYTES_TO_CHECK] = {0};
497a3e0fd82Sopenharmony_ci    int32_t fd = open(src, O_RDONLY);
498a3e0fd82Sopenharmony_ci    if (fd < 0) {
499a3e0fd82Sopenharmony_ci        return;
500a3e0fd82Sopenharmony_ci    }
501a3e0fd82Sopenharmony_ci    if (read(fd, buf, IMG_BYTES_TO_CHECK) != IMG_BYTES_TO_CHECK) {
502a3e0fd82Sopenharmony_ci        close(fd);
503a3e0fd82Sopenharmony_ci        return;
504a3e0fd82Sopenharmony_ci    }
505a3e0fd82Sopenharmony_ci    close(fd);
506a3e0fd82Sopenharmony_ci    bool updated = false;
507a3e0fd82Sopenharmony_ci    RemoveAndStopGifAnimator();
508a3e0fd82Sopenharmony_ci    // 0x47 0x49 0x46: GIF file's header
509a3e0fd82Sopenharmony_ci    if ((static_cast<uint8_t>(buf[0]) == 0x47) && (static_cast<uint8_t>(buf[1]) == 0x49) &&
510a3e0fd82Sopenharmony_ci        (static_cast<uint8_t>(buf[2]) == 0x46)) { // 2: array index of GIF file's header
511a3e0fd82Sopenharmony_ci        if (gifImageAnimator_ == nullptr) {
512a3e0fd82Sopenharmony_ci            gifImageAnimator_ = new GifImageAnimator(this, src);
513a3e0fd82Sopenharmony_ci            if (gifImageAnimator_ == nullptr) {
514a3e0fd82Sopenharmony_ci                GRAPHIC_LOGE("new GifImageAnimator fail");
515a3e0fd82Sopenharmony_ci                return;
516a3e0fd82Sopenharmony_ci            }
517a3e0fd82Sopenharmony_ci        }
518a3e0fd82Sopenharmony_ci        AddAndStartGifAnimator();
519a3e0fd82Sopenharmony_ci        updated = true;
520a3e0fd82Sopenharmony_ci    } else {
521a3e0fd82Sopenharmony_ci        updated = image_.SetSrc(src);
522a3e0fd82Sopenharmony_ci    }
523a3e0fd82Sopenharmony_ci#else
524a3e0fd82Sopenharmony_ci    bool updated = image_.SetSrc(src);
525a3e0fd82Sopenharmony_ci#endif
526a3e0fd82Sopenharmony_ci    if (!updated) {
527a3e0fd82Sopenharmony_ci        return;
528a3e0fd82Sopenharmony_ci    }
529a3e0fd82Sopenharmony_ci    needRefresh_ = true;
530a3e0fd82Sopenharmony_ci    if (autoEnable_ || (imageResizeMode_ != ImageResizeMode::NONE)) {
531a3e0fd82Sopenharmony_ci        UIImageView::ReMeasure();
532a3e0fd82Sopenharmony_ci    }
533a3e0fd82Sopenharmony_ci    if (imageResizeMode_ != ImageResizeMode::NONE) {
534a3e0fd82Sopenharmony_ci        UpdateDrawTransMap(true);
535a3e0fd82Sopenharmony_ci    }
536a3e0fd82Sopenharmony_ci    Invalidate();
537a3e0fd82Sopenharmony_ci}
538a3e0fd82Sopenharmony_ci
539a3e0fd82Sopenharmony_civoid UIImageView::ReMeasure()
540a3e0fd82Sopenharmony_ci{
541a3e0fd82Sopenharmony_ci    if (!needRefresh_) {
542a3e0fd82Sopenharmony_ci        return;
543a3e0fd82Sopenharmony_ci    }
544a3e0fd82Sopenharmony_ci    needRefresh_ = false;
545a3e0fd82Sopenharmony_ci
546a3e0fd82Sopenharmony_ci    ImageHeader header = {0};
547a3e0fd82Sopenharmony_ci    image_.GetHeader(header);
548a3e0fd82Sopenharmony_ci
549a3e0fd82Sopenharmony_ci    imageWidth_ = header.width;
550a3e0fd82Sopenharmony_ci    imageHeight_ = header.height;
551a3e0fd82Sopenharmony_ci    colorFormat_ = header.colorMode;
552a3e0fd82Sopenharmony_ci
553a3e0fd82Sopenharmony_ci    if (autoEnable_) {
554a3e0fd82Sopenharmony_ci        Invalidate();
555a3e0fd82Sopenharmony_ci        Resize(imageWidth_, imageHeight_);
556a3e0fd82Sopenharmony_ci        Invalidate();
557a3e0fd82Sopenharmony_ci    }
558a3e0fd82Sopenharmony_ci}
559a3e0fd82Sopenharmony_ci
560a3e0fd82Sopenharmony_civoid UIImageView::SetSrc(const ImageInfo* src)
561a3e0fd82Sopenharmony_ci{
562a3e0fd82Sopenharmony_ci#if defined(ENABLE_GIF) && (ENABLE_GIF == 1)
563a3e0fd82Sopenharmony_ci    if (!gifFrameFlag_ && (gifImageAnimator_ != nullptr)) {
564a3e0fd82Sopenharmony_ci        RemoveAndStopGifAnimator();
565a3e0fd82Sopenharmony_ci    }
566a3e0fd82Sopenharmony_ci    gifFrameFlag_ = false;
567a3e0fd82Sopenharmony_ci#endif
568a3e0fd82Sopenharmony_ci    bool updated = image_.SetSrc(src);
569a3e0fd82Sopenharmony_ci    if (!updated) {
570a3e0fd82Sopenharmony_ci        return;
571a3e0fd82Sopenharmony_ci    }
572a3e0fd82Sopenharmony_ci    needRefresh_ = true;
573a3e0fd82Sopenharmony_ci    if (autoEnable_ || (imageResizeMode_ != ImageResizeMode::NONE)) {
574a3e0fd82Sopenharmony_ci        UIImageView::ReMeasure();
575a3e0fd82Sopenharmony_ci    }
576a3e0fd82Sopenharmony_ci    if (imageResizeMode_ != ImageResizeMode::NONE) {
577a3e0fd82Sopenharmony_ci        UpdateDrawTransMap(true);
578a3e0fd82Sopenharmony_ci    }
579a3e0fd82Sopenharmony_ci    Invalidate();
580a3e0fd82Sopenharmony_ci}
581a3e0fd82Sopenharmony_ci
582a3e0fd82Sopenharmony_ci#if defined(ENABLE_GIF) && (ENABLE_GIF == 1)
583a3e0fd82Sopenharmony_civoid UIImageView::AddAndStartGifAnimator()
584a3e0fd82Sopenharmony_ci{
585a3e0fd82Sopenharmony_ci    if (gifImageAnimator_ != nullptr) {
586a3e0fd82Sopenharmony_ci        gifImageAnimator_->Start();
587a3e0fd82Sopenharmony_ci    }
588a3e0fd82Sopenharmony_ci}
589a3e0fd82Sopenharmony_ci
590a3e0fd82Sopenharmony_civoid UIImageView::RemoveAndStopGifAnimator()
591a3e0fd82Sopenharmony_ci{
592a3e0fd82Sopenharmony_ci    if (gifImageAnimator_ != nullptr) {
593a3e0fd82Sopenharmony_ci        gifImageAnimator_->Stop();
594a3e0fd82Sopenharmony_ci        delete gifImageAnimator_;
595a3e0fd82Sopenharmony_ci        gifImageAnimator_ = nullptr;
596a3e0fd82Sopenharmony_ci    }
597a3e0fd82Sopenharmony_ci}
598a3e0fd82Sopenharmony_ci#endif
599a3e0fd82Sopenharmony_ci} // namespace OHOS
600