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