• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (ENABLE_GIF == 1)
27 #include "gif_lib.h"
28 #endif
29 
30 namespace OHOS {
31 #if (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     const 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 const 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     bool transparentColor = true;
195     int32_t loc = 0;
196     for (int32_t x = 0; x < gifFileType->SHeight; x++) {
197         for (int32_t y = 0; y < gifFileType->SWidth; y++) {
198             transparentColor = true;
199             if ((x >= gifImageDesc->Top) && (x < gifImageDesc->Top + gifImageDesc->Height) &&
200                 (y >= gifImageDesc->Left) && (y < gifImageDesc->Left + gifImageDesc->Width)) {
201                 loc = (x - gifImageDesc->Top) * gifImageDesc->Width + (y - gifImageDesc->Left);
202                 colorIndex = savedImage->RasterBits[loc];
203 
204                 if ((gcb.DisposalMode != DISPOSE_DO_NOT) || (gcb.TransparentColor == NO_TRANSPARENT_COLOR) ||
205                     (colorIndex != gcb.TransparentColor)) {
206                     transparentColor = false;
207                 }
208             }
209             if (transparentColor) {
210                 index += 4; // 4: skip color index, keep last frame color
211             } else {
212                 gifColorType = &colorMap->Colors[colorIndex];
213                 gifImageData_[index++] = gifColorType->Blue;
214                 gifImageData_[index++] = gifColorType->Green;
215                 gifImageData_[index++] = gifColorType->Red;
216                 gifImageData_[index++] = OPA_OPAQUE;
217             }
218         }
219     }
220 }
221 #endif
222 
UIImageView()223 UIImageView::UIImageView()
224     : imageWidth_(0),
225       imageHeight_(0),
226       autoEnable_(true),
227       needRefresh_(false),
228       colorFormat_(UNKNOW),
229       blurLevel_(BlurLevel::LEVEL0),
230       algorithm_(TransformAlgorithm::BILINEAR),
231       reserve_(0)
232 {
233     style_ = &(StyleDefault::GetBackgroundTransparentStyle());
234 #if (ENABLE_GIF == 1)
235     gifImageAnimator_ = nullptr;
236     gifFrameFlag_ = false;
237 #endif
238 }
239 
~UIImageView()240 UIImageView::~UIImageView()
241 {
242 #if (ENABLE_GIF == 1)
243     RemoveAndStopGifAnimator();
244 #endif
245     if (drawTransMap_ != nullptr) {
246         delete drawTransMap_;
247         drawTransMap_ = nullptr;
248     }
249     if (contentMatrix_ != nullptr) {
250         delete contentMatrix_;
251         contentMatrix_ = nullptr;
252     }
253 }
254 
SetResizeMode(ImageResizeMode mode)255 void UIImageView::SetResizeMode(ImageResizeMode mode)
256 {
257     // when automatic adaptation is enabled only save the mode, no need to update the DrawtransMap
258     if (autoEnable_) {
259         imageResizeMode_ = mode;
260     } else if (imageResizeMode_ != mode) {
261         needRefresh_ = true;
262         ReMeasure();
263         // must update the mode, before calling UpdateDrawTransMap
264         imageResizeMode_ = mode;
265         UpdateDrawTransMap(true);
266     }
267 }
268 
AdjustScaleAndTranslate(Vector3<float> & scale,Vector3<int16_t> & translate,int16_t widgetWidth,int16_t widgetHeight) const269 void UIImageView::AdjustScaleAndTranslate(Vector3<float>& scale, Vector3<int16_t>& translate,
270     int16_t widgetWidth, int16_t widgetHeight) const
271 {
272     // adjust scale
273     float ratio = 1.0f;
274     switch (imageResizeMode_) {
275         case ImageResizeMode::COVER:
276             ratio = MATH_MAX(scale.x_, scale.y_);
277             break;
278         case ImageResizeMode::CONTAIN:
279             ratio = MATH_MIN(scale.x_, scale.y_);
280             break;
281         case ImageResizeMode::CENTER: // ratio is 1.0f
282             break;
283         case ImageResizeMode::SCALE_DOWN:
284             ratio = MATH_MIN(scale.x_, scale.y_);
285             ratio = MATH_MIN(ratio, 1.0f);
286             break;
287         case ImageResizeMode::FILL: // do nothing
288             return;
289         default:
290             break;
291     }
292     if (scale.x_ != ratio) {
293         scale.x_ = ratio;
294         // 0.5: adjust the x-coordinate of the content to the center of widget
295         translate.x_ += (static_cast<float>(widgetWidth) - static_cast<float>(imageWidth_) * ratio) * 0.5f;
296     }
297     if (scale.y_ != ratio) {
298         scale.y_ = ratio;
299         // 0.5: adjust the y-coordinate of the content to the center of widget
300         translate.y_ += (static_cast<float>(widgetHeight) - static_cast<float>(imageHeight_) * ratio) * 0.5f;
301     }
302 }
303 
UpdateContentMatrix()304 void UIImageView::UpdateContentMatrix()
305 {
306     Rect viewRect = GetOrigRect();
307     if (autoEnable_ || (imageResizeMode_ == ImageResizeMode::NONE) ||
308         (imageWidth_ == viewRect.GetWidth() && imageHeight_ == viewRect.GetHeight()) ||
309         imageWidth_ == 0 || imageHeight_ == 0) {
310         if (contentMatrix_ != nullptr) {
311             delete contentMatrix_;
312             contentMatrix_ = nullptr;
313         }
314         return;
315     }
316     if (contentMatrix_ == nullptr) {
317         contentMatrix_ = new Matrix4<float>();
318         if (contentMatrix_ == nullptr) {
319             GRAPHIC_LOGE("can not new contentMatrix");
320             return;
321         }
322     }
323     int16_t widgetWidth = viewRect.GetWidth() - style_->paddingLeft_ - style_->paddingRight_ -
324         style_->borderWidth_ * 2; // 2: excludes the border-left and border-right
325     int16_t widgetHeight = viewRect.GetHeight() - style_->paddingTop_ - style_->paddingBottom_ -
326         style_->borderWidth_ * 2; // 2: excludes the border-top and border-bottom
327 
328     float scaleX = static_cast<float>(widgetWidth) / static_cast<float>(imageWidth_);
329     float scaleY = static_cast<float>(widgetHeight) / static_cast<float>(imageHeight_);
330     Vector3<float> scale(scaleX, scaleY, 1.0f);
331     Vector3<int16_t> translate(style_->paddingLeft_ + style_->borderWidth_,
332         style_->paddingTop_ + style_->borderWidth_, 0);
333     AdjustScaleAndTranslate(scale, translate, widgetWidth, widgetHeight);
334 
335     auto scaleMatrix = Matrix4<float>::Scale(scale, Vector3<float>(viewRect.GetX(), viewRect.GetY(), 0));
336     auto translateMatrix = Matrix4<float>::Translate(Vector3<float>(translate.x_, translate.y_, 0));
337     *contentMatrix_ = translateMatrix * scaleMatrix;
338 }
339 
UpdateDrawTransMap(bool updateContentMatrix)340 void UIImageView::UpdateDrawTransMap(bool updateContentMatrix)
341 {
342     auto viewRect = GetOrigRect();
343     if (updateContentMatrix || (drawTransMap_ != nullptr &&
344         (drawTransMap_->GetTransMapRect().GetX() != viewRect.GetX() ||
345         drawTransMap_->GetTransMapRect().GetY() != viewRect.GetY()))) {
346         UpdateContentMatrix();
347     }
348     // has no transformation
349     if ((contentMatrix_ == nullptr) && ((transMap_ == nullptr) || transMap_->IsInvalid())) {
350         if (drawTransMap_ != nullptr) {
351             delete drawTransMap_;
352             drawTransMap_ = nullptr;
353         }
354         return;
355     }
356     if (drawTransMap_ == nullptr) {
357         drawTransMap_ = new TransformMap();
358         if (drawTransMap_ == nullptr) {
359             GRAPHIC_LOGE("can not new drawTransMap");
360             return;
361         }
362     }
363     if (contentMatrix_ != nullptr) {
364         drawTransMap_->SetTransMapRect(Rect(viewRect.GetX(), viewRect.GetY(),
365             viewRect.GetX() + imageWidth_ - 1, viewRect.GetY() + imageHeight_ - 1));
366     } else {
367         drawTransMap_->SetTransMapRect(viewRect);
368     }
369     // only contentMatrix
370     if (transMap_ == nullptr || transMap_->IsInvalid()) {
371         drawTransMap_->SetMatrix(*contentMatrix_);
372         return;
373     }
374     // update the transMap, now the transMap is not nullptr
375     if (!(transMap_->GetTransMapRect() == viewRect)) {
376         transMap_->SetTransMapRect(viewRect);
377     }
378     // only transMap
379     if (contentMatrix_ == nullptr) {
380         *drawTransMap_ = *transMap_;
381         return;
382     }
383     // merge the transMap and content matrix
384     auto rect = transMap_->GetTransMapRect();
385     auto translate = Matrix4<float>::Translate(Vector3<float>(-rect.GetX(), -rect.GetY(), 0));
386     auto matrix = transMap_->GetTransformMatrix() * translate;
387     matrix = matrix * (*contentMatrix_);
388     drawTransMap_->SetMatrix(matrix);
389 }
390 
SetHeight(int16_t height)391 void UIImageView::SetHeight(int16_t height)
392 {
393     if (GetHeight() != height) {
394         UIView::SetHeight(height);
395         UpdateDrawTransMap(true);
396     }
397 }
398 
SetWidth(int16_t width)399 void UIImageView::SetWidth(int16_t width)
400 {
401     if (GetWidth() != width) {
402         UIView::SetWidth(width);
403         UpdateDrawTransMap(true);
404     }
405 }
406 
OnPreDraw(Rect & invalidatedArea) const407 bool UIImageView::OnPreDraw(Rect& invalidatedArea) const
408 {
409     if ((image_.GetSrcType() == IMG_SRC_UNKNOWN)) {
410         return true;
411     }
412 
413     if ((colorFormat_ == RGB565) || (colorFormat_ == RGB888)) {
414         if (GetRect().IsContains(invalidatedArea)) {
415             return true;
416         }
417         invalidatedArea.Intersect(invalidatedArea, GetRect());
418     }
419 
420     return false;
421 }
422 
OnDraw(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea)423 void UIImageView::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
424 {
425     OpacityType opa = GetMixOpaScale();
426     BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, GetRect(), invalidatedArea, *style_, opa);
427     if ((imageHeight_ == 0) || (imageWidth_ == 0)) {
428         return;
429     }
430     UpdateDrawTransMap();
431     Rect viewRect = GetContentRect();
432     Rect trunc(invalidatedArea);
433     if (trunc.Intersect(trunc, viewRect)) {
434         uint8_t srcType = image_.GetSrcType();
435         if ((srcType == IMG_SRC_FILE) || (srcType == IMG_SRC_VARIABLE)) {
436             Rect cordsTmp;
437             cordsTmp.SetTop(viewRect.GetY());
438             cordsTmp.SetBottom(viewRect.GetY() + imageHeight_ - 1);
439 
440             if ((drawTransMap_ == nullptr) || drawTransMap_->IsInvalid()) {
441                 while (cordsTmp.GetTop() <= viewRect.GetBottom()) {
442                     cordsTmp.SetLeft(viewRect.GetX());
443                     cordsTmp.SetRight(viewRect.GetX() + imageWidth_ - 1);
444                     while (cordsTmp.GetLeft() <= viewRect.GetRight()) {
445                         image_.DrawImage(gfxDstBuffer, cordsTmp, trunc, *style_, opa);
446                         cordsTmp.SetLeft(cordsTmp.GetLeft() + imageWidth_);
447                         cordsTmp.SetRight(cordsTmp.GetRight() + imageWidth_);
448                     }
449                     cordsTmp.SetTop(cordsTmp.GetTop() + imageHeight_);
450                     cordsTmp.SetBottom(cordsTmp.GetBottom() + imageHeight_);
451                 }
452             } else if ((drawTransMap_ != nullptr) && !drawTransMap_->IsInvalid()) {
453                 ImageInfo imgInfo;
454                 if (srcType == IMG_SRC_FILE) {
455                     CacheEntry entry;
456                     RetCode ret = CacheManager::GetInstance().Open(GetPath(), *style_, entry);
457                     if (ret != RetCode::OK) {
458                         return;
459                     }
460                     imgInfo = entry.GetImageInfo();
461                 } else {
462                     imgInfo = *(GetImageInfo());
463                 }
464                 uint8_t pxSize = DrawUtils::GetPxSizeByColorMode(imgInfo.header.colorMode);
465                 TransformDataInfo imageTranDataInfo = {imgInfo.header, imgInfo.data, pxSize,
466                                                        static_cast<BlurLevel>(blurLevel_),
467                                                        static_cast<TransformAlgorithm>(algorithm_)};
468                 OpacityType opaScale = DrawUtils::GetMixOpacity(opa, style_->imageOpa_);
469                 BaseGfxEngine::GetInstance()->DrawTransform(gfxDstBuffer, trunc, {0, 0}, Color::Black(),
470                                                             opaScale, *drawTransMap_, imageTranDataInfo);
471             }
472         }
473     }
474 }
475 
SetSrc(const char * src)476 void UIImageView::SetSrc(const char* src)
477 {
478 #if (ENABLE_GIF == 1)
479     if (src == nullptr) {
480         return;
481     }
482     const static uint8_t IMG_BYTES_TO_CHECK = 4; // 4: check 4 bytes of image file
483     char buf[IMG_BYTES_TO_CHECK] = {0};
484     int32_t fd = open(src, O_RDONLY);
485     if (fd < 0) {
486         return;
487     }
488     if (read(fd, buf, IMG_BYTES_TO_CHECK) != IMG_BYTES_TO_CHECK) {
489         close(fd);
490         return;
491     }
492     close(fd);
493     bool updated = false;
494     RemoveAndStopGifAnimator();
495     // 0x47 0x49 0x46: GIF file's header
496     if ((static_cast<uint8_t>(buf[0]) == 0x47) && (static_cast<uint8_t>(buf[1]) == 0x49) &&
497         (static_cast<uint8_t>(buf[2]) == 0x46)) { // 2: array index of GIF file's header
498         if (gifImageAnimator_ == nullptr) {
499             gifImageAnimator_ = new GifImageAnimator(this, src);
500             if (gifImageAnimator_ == nullptr) {
501                 GRAPHIC_LOGE("new GifImageAnimator fail");
502                 return;
503             }
504         }
505         AddAndStartGifAnimator();
506         updated = true;
507     } else {
508         updated = image_.SetSrc(src);
509     }
510 #else
511     bool updated = image_.SetSrc(src);
512 #endif
513     if (!updated) {
514         return;
515     }
516     needRefresh_ = true;
517     if (autoEnable_) {
518         UIImageView::ReMeasure();
519     }
520     Invalidate();
521 }
522 
ReMeasure()523 void UIImageView::ReMeasure()
524 {
525     if (!needRefresh_) {
526         return;
527     }
528     needRefresh_ = false;
529 
530     ImageHeader header = {0};
531     image_.GetHeader(header);
532 
533     imageWidth_ = header.width;
534     imageHeight_ = header.height;
535     colorFormat_ = header.colorMode;
536 
537     if (autoEnable_) {
538         Invalidate();
539         Resize(imageWidth_, imageHeight_);
540         Invalidate();
541     }
542 }
543 
SetSrc(const ImageInfo * src)544 void UIImageView::SetSrc(const ImageInfo* src)
545 {
546 #if (ENABLE_GIF == 1)
547     if (!gifFrameFlag_ && (gifImageAnimator_ != nullptr)) {
548         RemoveAndStopGifAnimator();
549     }
550     gifFrameFlag_ = false;
551 #endif
552     bool updated = image_.SetSrc(src);
553     if (!updated) {
554         return;
555     }
556     needRefresh_ = true;
557     if (autoEnable_) {
558         UIImageView::ReMeasure();
559     }
560     Invalidate();
561 }
562 
563 #if (ENABLE_GIF == 1)
AddAndStartGifAnimator()564 void UIImageView::AddAndStartGifAnimator()
565 {
566     if (gifImageAnimator_ != nullptr) {
567         gifImageAnimator_->Start();
568     }
569 }
570 
RemoveAndStopGifAnimator()571 void UIImageView::RemoveAndStopGifAnimator()
572 {
573     if (gifImageAnimator_ != nullptr) {
574         gifImageAnimator_->Stop();
575         delete gifImageAnimator_;
576         gifImageAnimator_ = nullptr;
577     }
578 }
579 #endif
580 } // namespace OHOS
581