• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "core/image/image_object.h"
17 
18 #include "base/thread/background_task_executor.h"
19 #include "core/common/container.h"
20 #include "core/common/container_scope.h"
21 #include "core/components/image/render_image.h"
22 #include "core/image/flutter_image_cache.h"
23 
24 namespace OHOS::Ace {
25 
GenerateCacheKey(const ImageSourceInfo & srcInfo,Size targetImageSize)26 std::string ImageObject::GenerateCacheKey(const ImageSourceInfo& srcInfo, Size targetImageSize)
27 {
28     return srcInfo.GetCacheKey() + std::to_string(static_cast<int32_t>(targetImageSize.Width())) +
29            std::to_string(static_cast<int32_t>(targetImageSize.Height()));
30 }
31 
BuildImageObject(ImageSourceInfo source,const RefPtr<PipelineContext> context,const sk_sp<SkData> & skData,bool useSkiaSvg)32 RefPtr<ImageObject> ImageObject::BuildImageObject(
33     ImageSourceInfo source,
34     const RefPtr<PipelineContext> context,
35     const sk_sp<SkData>& skData,
36     bool useSkiaSvg)
37 {
38     // build svg image object.
39     if (source.IsSvg()) {
40         const auto svgStream = std::make_unique<SkMemoryStream>(skData);
41         if (!svgStream) {
42             return nullptr;
43         }
44         auto color = source.GetFillColor();
45         if (!useSkiaSvg) {
46             auto svgDom = SvgDom::CreateSvgDom(*svgStream, context, color);
47             return svgDom ? MakeRefPtr<SvgImageObject>(source, Size(), 1, svgDom) : nullptr;
48         } else {
49             uint64_t colorValue = 0;
50             if (color.has_value()) {
51                 colorValue = color.value().GetValue();
52                 // skia svg relies on the 32th bit to determine whether or not to use the color we set.
53                 colorValue = colorValue | (static_cast<int64_t>(0b1) << 32);
54             }
55             auto skiaDom = SkSVGDOM::MakeFromStream(*svgStream, colorValue);
56             return skiaDom ? MakeRefPtr<SvgSkiaImageObject>(source, Size(), 1, skiaDom) : nullptr;
57         }
58     }
59     // build normal pixel image object.
60     auto codec = SkCodec::MakeFromData(skData);
61     int32_t totalFrames = 1;
62     Size imageSize;
63     if (codec) {
64         totalFrames = codec->getFrameCount();
65         switch (codec->getOrigin()) {
66             case SkEncodedOrigin::kLeftTop_SkEncodedOrigin:
67             case SkEncodedOrigin::kRightTop_SkEncodedOrigin:
68             case SkEncodedOrigin::kRightBottom_SkEncodedOrigin:
69             case SkEncodedOrigin::kLeftBottom_SkEncodedOrigin:
70                 imageSize.SetSize(Size(codec->dimensions().fHeight, codec->dimensions().fWidth));
71                 break;
72             default:
73                 imageSize.SetSize(Size(codec->dimensions().fWidth, codec->dimensions().fHeight));
74         }
75     }
76     if (totalFrames == 1) {
77         return MakeRefPtr<StaticImageObject>(source, imageSize, totalFrames, skData);
78     } else {
79         return MakeRefPtr<AnimatedImageObject>(source, imageSize, totalFrames, skData);
80     }
81 }
82 
MeasureForImage(RefPtr<RenderImage> image)83 Size ImageObject::MeasureForImage(RefPtr<RenderImage> image)
84 {
85     return image->MeasureForNormalImage();
86 }
87 
PerformLayoutImageObject(RefPtr<RenderImage> image)88 void SvgImageObject::PerformLayoutImageObject(RefPtr<RenderImage> image)
89 {
90     image->PerformLayoutSvgImage();
91 }
92 
MeasureForImage(RefPtr<RenderImage> image)93 Size SvgImageObject::MeasureForImage(RefPtr<RenderImage> image)
94 {
95     return image->MeasureForSvgImage();
96 }
97 
PerformLayoutImageObject(RefPtr<RenderImage> image)98 void SvgSkiaImageObject::PerformLayoutImageObject(RefPtr<RenderImage> image) {}
99 
MeasureForImage(RefPtr<RenderImage> image)100 Size SvgSkiaImageObject::MeasureForImage(RefPtr<RenderImage> image)
101 {
102     return image->MeasureForSvgImage();
103 }
104 
UploadToGpuForRender(const WeakPtr<PipelineContext> context,RefPtr<FlutterRenderTaskHolder> & renderTaskHolder,UploadSuccessCallback successCallback,FailedCallback failedCallback,Size imageSize,bool forceResize,bool syncMode)105 void StaticImageObject::UploadToGpuForRender(
106     const WeakPtr<PipelineContext> context,
107     RefPtr<FlutterRenderTaskHolder>& renderTaskHolder,
108     UploadSuccessCallback successCallback,
109     FailedCallback failedCallback,
110     Size imageSize,
111     bool forceResize,
112     bool syncMode)
113 {
114     auto task = [context, renderTaskHolder, successCallback, failedCallback, imageSize, forceResize, skData = skData_,
115                     imageSource = imageSource_, id = Container::CurrentId()]() mutable {
116         ContainerScope scope(id);
117         auto pipelineContext = context.Upgrade();
118         if (!pipelineContext) {
119             LOGE("pipline context has been released.");
120             return;
121         }
122         auto taskExecutor = pipelineContext->GetTaskExecutor();
123         if (!taskExecutor) {
124             LOGE("task executor is null.");
125             return;
126         }
127         fml::RefPtr<flutter::CanvasImage> cachedFlutterImage;
128         auto imageCache = pipelineContext->GetImageCache();
129         if (imageCache) {
130             auto cachedImage = imageCache->GetCacheImage(GenerateCacheKey(imageSource, imageSize));
131             LOGD("image cache valid");
132             if (cachedImage) {
133                 LOGD("cached image found.");
134                 cachedFlutterImage = cachedImage->imagePtr;
135             }
136         }
137         if (cachedFlutterImage) {
138             LOGD("get cached image success: %{public}s", GenerateCacheKey(imageSource, imageSize).c_str());
139             taskExecutor->PostTask([successCallback, imageSource,
140                                        cachedFlutterImage] { successCallback(imageSource, cachedFlutterImage); },
141                 TaskExecutor::TaskType::UI);
142             return;
143         }
144 
145         if (!skData) {
146             LOGD("reload sk data");
147             skData = ImageProvider::LoadImageRawData(imageSource, pipelineContext, imageSize);
148             if (!skData) {
149                 LOGE("reload image data failed. imageSource: %{private}s", imageSource.ToString().c_str());
150                 taskExecutor->PostTask(
151                     [failedCallback, imageSource] { failedCallback(imageSource); }, TaskExecutor::TaskType::UI);
152                 return;
153             }
154         }
155         auto rawImage = SkImage::MakeFromEncoded(skData);
156         if (!rawImage) {
157             LOGE("static image MakeFromEncoded fail! imageSource: %{private}s", imageSource.ToString().c_str());
158             taskExecutor->PostTask(
159                 [failedCallback, imageSource] { failedCallback(imageSource); }, TaskExecutor::TaskType::UI);
160             return;
161         }
162         auto image = ImageProvider::ResizeSkImage(rawImage, imageSource.GetSrc(), imageSize, forceResize);
163         auto callback =
164             [successCallback, imageSource, taskExecutor, imageCache, imageSize](flutter::SkiaGPUObject<SkImage> image) {
165                 auto canvasImage = flutter::CanvasImage::Create();
166                 canvasImage->set_image(std::move(image));
167                 if (imageCache) {
168                     LOGD("cache image key: %{public}s", GenerateCacheKey(imageSource, imageSize).c_str());
169                     imageCache->CacheImage(
170                         GenerateCacheKey(imageSource, imageSize),
171                         std::make_shared<CachedImage>(canvasImage));
172                 }
173                 taskExecutor->PostTask(
174                     [ successCallback, imageSource, canvasImage ] {
175                         successCallback(imageSource, canvasImage);
176                     },
177                     TaskExecutor::TaskType::UI);
178         };
179         ImageProvider::UploadImageToGPUForRender(image, callback, renderTaskHolder);
180     };
181     if (syncMode) {
182         task();
183         return;
184     }
185     uploadForPaintTask_ = CancelableTask(std::move(task));
186     BackgroundTaskExecutor::GetInstance().PostTask(uploadForPaintTask_);
187 }
188 
CancelBackgroundTasks()189 bool StaticImageObject::CancelBackgroundTasks()
190 {
191     return uploadForPaintTask_ ? uploadForPaintTask_.Cancel(false) : false;
192 }
193 
UploadToGpuForRender(const WeakPtr<PipelineContext> context,RefPtr<FlutterRenderTaskHolder> & renderTaskHolder,UploadSuccessCallback successCallback,FailedCallback failedCallback,Size imageSize,bool forceResize,bool syncMode)194 void AnimatedImageObject::UploadToGpuForRender(
195     const WeakPtr<PipelineContext> context,
196     RefPtr<FlutterRenderTaskHolder>& renderTaskHolder,
197     UploadSuccessCallback successCallback,
198     FailedCallback failedCallback,
199     Size imageSize,
200     bool forceResize,
201     bool syncMode)
202 {
203     if (!animatedPlayer_ && skData_) {
204         auto codec = SkCodec::MakeFromData(skData_);
205         int32_t dstWidth = -1;
206         int32_t dstHeight = -1;
207         if (forceResize) {
208             dstWidth = static_cast<int32_t>(imageSize.Width() + 0.5);
209             dstHeight = static_cast<int32_t>(imageSize.Height() + 0.5);
210         }
211         animatedPlayer_ = MakeRefPtr<AnimatedImagePlayer>(
212             imageSource_,
213             successCallback,
214             context,
215             renderTaskHolder->ioManager,
216             renderTaskHolder->unrefQueue,
217             std::move(codec),
218             dstWidth,
219             dstHeight);
220         ClearData();
221     } else if (animatedPlayer_ && forceResize && imageSize.IsValid()) {
222         LOGI("animated player has been construced, forceResize: %{public}s", imageSize.ToString().c_str());
223         int32_t dstWidth = static_cast<int32_t>(imageSize.Width() + 0.5);
224         int32_t dstHeight = static_cast<int32_t>(imageSize.Height() + 0.5);
225         animatedPlayer_->SetTargetSize(dstWidth, dstHeight);
226     } else if (!animatedPlayer_ && !skData_) {
227         LOGE("animated player is not constructed and image data is null, can not construct animated player!");
228     } else if (animatedPlayer_ && !forceResize) {
229         LOGI("animated player has been construced, do nothing!");
230     }
231 }
232 
PerformLayoutImageObject(RefPtr<RenderImage> image)233 void PixelMapImageObject::PerformLayoutImageObject(RefPtr<RenderImage> image)
234 {
235     image->PerformLayoutPixmap();
236 }
237 
MeasureForImage(RefPtr<RenderImage> image)238 Size PixelMapImageObject::MeasureForImage(RefPtr<RenderImage> image)
239 {
240     return image->MeasureForPixmap();
241 }
242 
243 } // namespace OHOS::Ace