1 /*
2  * Copyright (c) 2023 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/components_ng/render/adapter/rosen/drawing_image.h"
17 
18 #include "include/core/SkGraphics.h"
19 #include "core/components_ng/property/measure_utils.h"
20 #include "frameworks/core/components_ng/render/adapter/image_painter_utils.h"
21 #include "frameworks/core/image/sk_image_cache.h"
22 #ifdef ENABLE_ROSEN_BACKEND
23 #include "pipeline/rs_recording_canvas.h"
24 #endif
25 
26 namespace OHOS::Ace::NG {
27 namespace {
28 // The [GRAY_COLOR_MATRIX] is of dimension [4 x 5], which transforms a RGB source color (R, G, B, A) to the
29 // destination color (R', G', B', A').
30 //
31 // A classic color image to grayscale conversion formula is [Gray = R * 0.3 + G * 0.59 + B * 0.11].
32 // Hence we get the following conversion:
33 //
34 // | M11 M12 M13 M14 M15 |   | R |   | R' |
35 // | M21 M22 M23 M24 M25 |   | G |   | G' |
36 // | M31 M32 M33 M34 M35 | x | B | = | B' |
37 // | M41 M42 M43 M44 M45 |   | A |   | A' |
38 //                           | 1 |
39 const float GRAY_COLOR_MATRIX[20] = { 0.30f, 0.59f, 0.11f, 0, 0, // red
40     0.30f, 0.59f, 0.11f, 0, 0,                                   // green
41     0.30f, 0.59f, 0.11f, 0, 0,                                   // blue
42     0, 0, 0, 1.0f, 0 };                                          // alpha transparency
43 
PrintDrawingLatticeConfig(const Rosen::Drawing::Lattice & lattice)44 void PrintDrawingLatticeConfig(const Rosen::Drawing::Lattice& lattice)
45 {
46     std::string drawingConfigStr;
47     drawingConfigStr.append("fXCount = " + std::to_string(lattice.fXCount));
48     drawingConfigStr.append("fXDivs = [");
49     for (int32_t idx = 0; idx < lattice.fXCount; ++idx) {
50         drawingConfigStr.append(std::to_string(lattice.fXDivs[idx]) + " ");
51     }
52     drawingConfigStr.append("] ");
53     drawingConfigStr.append("fYCount = " + std::to_string(lattice.fYCount));
54     drawingConfigStr.append("fYDivs = [");
55     for (int32_t idx = 0; idx < lattice.fYCount; ++idx) {
56         drawingConfigStr.append(std::to_string(lattice.fYDivs[idx]) + " ");
57     }
58     drawingConfigStr.append("] ");
59     TAG_LOGD(AceLogTag::ACE_IMAGE, "Begin to draw iamge with lattice : %{public}s", drawingConfigStr.c_str());
60 }
61 
ConvertSlice(const ImagePaintConfig & config,RectF & result,float rawImageWidth,float rawImageHeight)62 bool ConvertSlice(const ImagePaintConfig& config, RectF& result, float rawImageWidth, float rawImageHeight)
63 {
64     const auto& slice = config.resizableSlice_;
65     CHECK_NULL_RETURN(slice.Valid(), false);
66     TAG_LOGD(AceLogTag::ACE_IMAGE, "Draw image with slice = %{public}s.", slice.ToString().c_str());
67     result.SetLeft(ConvertToPx(slice.left, ScaleProperty::CreateScaleProperty(), rawImageWidth).value_or(0.0f));
68     result.SetTop(ConvertToPx(slice.top, ScaleProperty::CreateScaleProperty(), rawImageHeight).value_or(0.0f));
69     auto rightSliceValue = ConvertToPx(slice.right, ScaleProperty::CreateScaleProperty(), rawImageWidth).value_or(0.0f);
70     auto bottomSliceValue =
71         ConvertToPx(slice.bottom, ScaleProperty::CreateScaleProperty(), rawImageHeight).value_or(0.0f);
72     // illegal case if left position if larger than right, then rect has negative width
73     if (GreatNotEqual(rawImageWidth - rightSliceValue - result.GetX(), 0.0f)) {
74         result.SetWidth(rawImageWidth - rightSliceValue - result.GetX());
75     } else {
76         return false;
77     }
78     // same illegal case for height
79     if (GreatNotEqual(rawImageHeight - bottomSliceValue - result.GetY(), 0.0f)) {
80         result.SetHeight(rawImageHeight - bottomSliceValue - result.GetY());
81     } else {
82         return false;
83     }
84     return true;
85 }
86 
87 #ifndef USE_ROSEN_DRAWING
UpdateSKFilter(const ImagePaintConfig & config,SKPaint & paint)88 void UpdateSKFilter(const ImagePaintConfig& config, SKPaint& paint)
89 {
90     if (config.colorFilter_.colorFilterMatrix_) {
91         paint.setColorFilter(SkColorFilters::Matrix(config.colorFilter_.colorFilterMatrix_->data()));
92     } else if (ImageRenderMode::TEMPLATE == config.renderMode_) {
93         paint.setColorFilter(SkColorFilters::Matrix(GRAY_COLOR_MATRIX));
94     }
95 }
96 #else
UpdateRSFilter(const ImagePaintConfig & config,RSFilter & filter)97 void UpdateRSFilter(const ImagePaintConfig& config, RSFilter& filter)
98 {
99     if (config.colorFilter_.colorFilterMatrix_) {
100         RSColorMatrix colorMatrix;
101         colorMatrix.SetArray(config.colorFilter_.colorFilterMatrix_->data());
102         filter.SetColorFilter(RSRecordingColorFilter::CreateMatrixColorFilter(colorMatrix));
103     } else if (config.colorFilter_.colorFilterDrawing_) {
104         auto colorFilterSptrAddr = static_cast<std::shared_ptr<RSColorFilter>*>(
105             config.colorFilter_.colorFilterDrawing_->GetDrawingColorFilterSptrAddr());
106         if (colorFilterSptrAddr && (*colorFilterSptrAddr)) {
107             filter.SetColorFilter(*colorFilterSptrAddr);
108         }
109     } else if (ImageRenderMode::TEMPLATE == config.renderMode_) {
110         RSColorMatrix colorMatrix;
111         colorMatrix.SetArray(GRAY_COLOR_MATRIX);
112         filter.SetColorFilter(RSRecordingColorFilter::CreateMatrixColorFilter(colorMatrix));
113     }
114 }
115 #endif
116 } // namespace
117 
Create(void * rawImage)118 RefPtr<CanvasImage> CanvasImage::Create(void* rawImage)
119 {
120     auto* rsImagePtr = reinterpret_cast<std::shared_ptr<RSImage>*>(rawImage);
121     return AceType::MakeRefPtr<DrawingImage>(*rsImagePtr);
122 }
123 
Create()124 RefPtr<CanvasImage> CanvasImage::Create()
125 {
126     return AceType::MakeRefPtr<DrawingImage>();
127 }
128 
MakeRSImageFromPixmap(const RefPtr<PixelMap> & pixmap)129 std::shared_ptr<RSImage> DrawingImage::MakeRSImageFromPixmap(const RefPtr<PixelMap>& pixmap)
130 {
131     RSColorType colorType = PixelFormatToRSColorType(pixmap);
132     RSAlphaType alphaType = AlphaTypeToRSAlphaType(pixmap);
133     RSBitmapFormat bitmapFormat = { colorType, alphaType };
134     auto bitmap = std::make_shared<RSBitmap>();
135     bitmap->Build(pixmap->GetWidth(), pixmap->GetHeight(), bitmapFormat, pixmap->GetRowStride());
136     bitmap->SetPixels(const_cast<void*>(reinterpret_cast<const void*>(pixmap->GetPixels())));
137 
138     auto image = std::make_shared<RSImage>();
139     image->BuildFromBitmap(*bitmap);
140     return image;
141 }
142 
AlphaTypeToRSAlphaType(const RefPtr<PixelMap> & pixmap)143 RSAlphaType DrawingImage::AlphaTypeToRSAlphaType(const RefPtr<PixelMap>& pixmap)
144 {
145     switch (pixmap->GetAlphaType()) {
146         case AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
147             return RSAlphaType::ALPHATYPE_UNKNOWN;
148         case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
149             return RSAlphaType::ALPHATYPE_OPAQUE;
150         case AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
151             return RSAlphaType::ALPHATYPE_PREMUL;
152         case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
153             return RSAlphaType::ALPHATYPE_UNPREMUL;
154         default:
155             return RSAlphaType::ALPHATYPE_UNKNOWN;
156     }
157 }
158 
PixelFormatToRSColorType(const RefPtr<PixelMap> & pixmap)159 RSColorType DrawingImage::PixelFormatToRSColorType(const RefPtr<PixelMap>& pixmap)
160 {
161     switch (pixmap->GetPixelFormat()) {
162         case PixelFormat::RGB_565:
163             return RSColorType::COLORTYPE_RGB_565;
164         case PixelFormat::RGBA_8888:
165             return RSColorType::COLORTYPE_RGBA_8888;
166         case PixelFormat::BGRA_8888:
167             return RSColorType::COLORTYPE_BGRA_8888;
168         case PixelFormat::ALPHA_8:
169             return RSColorType::COLORTYPE_ALPHA_8;
170         case PixelFormat::RGBA_F16:
171             return RSColorType::COLORTYPE_RGBA_F16;
172         case PixelFormat::UNKNOWN:
173         case PixelFormat::ARGB_8888:
174         case PixelFormat::RGB_888:
175         case PixelFormat::NV21:
176         case PixelFormat::NV12:
177         case PixelFormat::CMYK:
178         default:
179             return RSColorType::COLORTYPE_UNKNOWN;
180     }
181 }
182 
ReplaceRSImage(std::shared_ptr<RSImage> image)183 void DrawingImage::ReplaceRSImage(std::shared_ptr<RSImage> image)
184 {
185     image_ = std::move(image);
186 }
187 
GetWidth() const188 int32_t DrawingImage::GetWidth() const
189 {
190     return image_ ? image_->GetWidth() : compressWidth_;
191 }
192 
GetHeight() const193 int32_t DrawingImage::GetHeight() const
194 {
195     return image_ ? image_->GetHeight() : compressHeight_;
196 }
197 
Clone()198 RefPtr<CanvasImage> DrawingImage::Clone()
199 {
200     auto clone = MakeRefPtr<DrawingImage>(image_);
201     clone->uniqueId_ = uniqueId_;
202     clone->compressData_ = std::move(compressData_);
203     clone->compressWidth_ = compressWidth_;
204     clone->compressHeight_ = compressHeight_;
205     return clone;
206 }
207 
Cache(const std::string & key)208 void DrawingImage::Cache(const std::string& key)
209 {
210     auto pipelineCtx = PipelineContext::GetCurrentContext();
211     CHECK_NULL_VOID(pipelineCtx);
212     auto cache = pipelineCtx->GetImageCache();
213     CHECK_NULL_VOID(cache);
214 
215     auto cached = std::make_shared<CachedImage>(GetImage());
216     cached->uniqueId = GetUniqueID();
217     pipelineCtx->GetImageCache()->CacheImage(key, cached);
218 }
219 
QueryFromCache(const std::string & key)220 RefPtr<CanvasImage> DrawingImage::QueryFromCache(const std::string& key)
221 {
222     auto pipelineCtx = PipelineContext::GetCurrentContext();
223     CHECK_NULL_RETURN(pipelineCtx, nullptr);
224     auto cache = pipelineCtx->GetImageCache();
225     CHECK_NULL_RETURN(cache, nullptr);
226     auto cacheImage = cache->GetCacheImage(key);
227     CHECK_NULL_RETURN(cacheImage, nullptr);
228 
229     auto rosenImage = MakeRefPtr<DrawingImage>(cacheImage->imagePtr);
230     rosenImage->SetUniqueID(cacheImage->uniqueId);
231 
232     return rosenImage;
233 }
234 
GetPixelMap() const235 RefPtr<PixelMap> DrawingImage::GetPixelMap() const
236 {
237     CHECK_NULL_RETURN(GetImage(), nullptr);
238     auto rsImage = GetImage();
239     RSBitmapFormat rsBitmapFormat = { RSColorType::COLORTYPE_BGRA_8888, rsImage->GetAlphaType() };
240     RSBitmap rsBitmap;
241     if (!rsBitmap.Build(rsImage->GetWidth(), rsImage->GetHeight(), rsBitmapFormat)) {
242         LOGW("rsBitmap build fail.");
243         return nullptr;
244     }
245     CHECK_NULL_RETURN(rsImage->ReadPixels(rsBitmap, 0, 0), nullptr);
246     const auto* addr = static_cast<uint32_t*>(rsBitmap.GetPixels());
247     auto width = static_cast<int32_t>(rsBitmap.GetWidth());
248     auto height = static_cast<int32_t>(rsBitmap.GetHeight());
249     int32_t length = width * height;
250     return PixelMap::ConvertSkImageToPixmap(addr, length, width, height);
251 }
252 
DrawToRSCanvas(RSCanvas & canvas,const RSRect & srcRect,const RSRect & dstRect,const BorderRadiusArray & radiusXY)253 void DrawingImage::DrawToRSCanvas(
254     RSCanvas& canvas, const RSRect& srcRect, const RSRect& dstRect, const BorderRadiusArray& radiusXY)
255 {
256     auto image = GetImage();
257     CHECK_NULL_VOID(image || GetCompressData());
258     if (isDrawAnimate_) {
259         RSSamplingOptions options;
260         ImagePainterUtils::ClipRRect(canvas, dstRect, radiusXY);
261         canvas.DrawImageRect(*image, srcRect, dstRect, options);
262     } else {
263         const auto& config = GetPaintConfig();
264         if (config.resizableLattice_ && DrawImageLattice(canvas, srcRect, dstRect, radiusXY)) {
265             return;
266         }
267         if (config.resizableSlice_.Valid() && DrawImageNine(canvas, srcRect, dstRect, radiusXY)) {
268             return;
269         }
270         DrawWithRecordingCanvas(canvas, radiusXY);
271     }
272 }
273 
DrawImageLattice(RSCanvas & canvas,const RSRect & srcRect,const RSRect & dstRect,const BorderRadiusArray & radiusXY)274 bool DrawingImage::DrawImageLattice(
275     RSCanvas& canvas, const RSRect& srcRect, const RSRect& dstRect, const BorderRadiusArray& radiusXY)
276 {
277     const auto& config = GetPaintConfig();
278     const auto& drawingLattice = config.resizableLattice_;
279     CHECK_NULL_RETURN(drawingLattice, false);
280 #ifdef ENABLE_ROSEN_BACKEND
281     auto latticeSptrAddr =
282         static_cast<std::shared_ptr<Rosen::Drawing::Lattice>*>(drawingLattice->GetDrawingLatticeSptrAddr());
283     RSBrush brush;
284     auto filterMode = RSFilterMode::NEAREST;
285     switch (config.imageInterpolation_) {
286         case ImageInterpolation::LOW:
287         case ImageInterpolation::MEDIUM:
288             filterMode = RSFilterMode::LINEAR;
289             break;
290         case ImageInterpolation::HIGH:
291         default:
292             break;
293     }
294 
295     auto filter = brush.GetFilter();
296     UpdateRSFilter(config, filter);
297     brush.SetFilter(filter);
298     auto& recordingCanvas = static_cast<Rosen::ExtendRecordingCanvas&>(canvas);
299     auto radii = ImagePainterUtils::ToRSRadius(radiusXY);
300     std::vector<RSPoint> radius;
301     for (size_t ii = 0; ii < 4; ii++) {
302         RSPoint point(radii[ii].GetX(), radii[ii].GetY());
303         radius.emplace_back(point);
304     }
305     recordingCanvas.ClipAdaptiveRoundRect(radius);
306     recordingCanvas.Scale(config.scaleX_, config.scaleY_);
307 
308     RSPoint pointRadius[4] = {};
309     for (size_t i = 0; i < 4; i++) {
310         pointRadius[i] = radius[i];
311     }
312     auto lattice = *(*latticeSptrAddr);
313     if (SystemProperties::GetDebugEnabled()) {
314         PrintDrawingLatticeConfig(lattice);
315     }
316     recordingCanvas.AttachBrush(brush);
317     recordingCanvas.DrawImageLattice(image_.get(), *(*latticeSptrAddr), dstRect, filterMode);
318     recordingCanvas.DetachBrush();
319     return true;
320 #endif
321     return false;
322 }
323 
DrawImageNine(RSCanvas & canvas,const RSRect & srcRect,const RSRect & dstRect,const BorderRadiusArray & radiusXY)324 bool DrawingImage::DrawImageNine(
325     RSCanvas& canvas, const RSRect& srcRect, const RSRect& dstRect, const BorderRadiusArray& radiusXY)
326 {
327     const auto& config = GetPaintConfig();
328     const auto& slice = GetPaintConfig().resizableSlice_;
329     CHECK_NULL_RETURN(slice.Valid(), false);
330     RectF centerRect;
331     CHECK_NULL_RETURN(ConvertSlice(config, centerRect, GetWidth(), GetHeight()), false);
332 #ifdef ENABLE_ROSEN_BACKEND
333 #ifndef USE_ROSEN_DRAWING
334     return false;
335 #endif
336     RSBrush brush;
337     auto filterMode = RSFilterMode::NEAREST;
338     switch (config.imageInterpolation_) {
339         case ImageInterpolation::LOW:
340         case ImageInterpolation::MEDIUM:
341             filterMode = RSFilterMode::LINEAR;
342             break;
343         case ImageInterpolation::HIGH:
344         default:
345             break;
346     }
347 
348     auto filter = brush.GetFilter();
349     UpdateRSFilter(config, filter);
350     brush.SetFilter(filter);
351     auto& recordingCanvas = static_cast<Rosen::ExtendRecordingCanvas&>(canvas);
352     auto radii = ImagePainterUtils::ToRSRadius(radiusXY);
353     std::vector<RSPoint> radius;
354     for (int ii = 0; ii < 4; ii++) {
355         RSPoint point(radii[ii].GetX(), radii[ii].GetY());
356         radius.emplace_back(point);
357     }
358     recordingCanvas.ClipAdaptiveRoundRect(radius);
359     recordingCanvas.Scale(config.scaleX_, config.scaleY_);
360 
361     RSPoint pointRadius[4] = {};
362     for (int i = 0; i < 4; i++) {
363         pointRadius[i] = radius[i];
364     }
365     RSRectI rsCenterRect(centerRect.GetX(), centerRect.GetY(), centerRect.GetX() + centerRect.Width(),
366         centerRect.GetY() + centerRect.Height());
367     recordingCanvas.AttachBrush(brush);
368     recordingCanvas.DrawImageNine(image_.get(), rsCenterRect, dstRect, filterMode, &brush);
369     recordingCanvas.DetachBrush();
370     return true;
371 #endif
372     return false;
373 }
374 
DrawWithRecordingCanvas(RSCanvas & canvas,const BorderRadiusArray & radiusXY)375 bool DrawingImage::DrawWithRecordingCanvas(RSCanvas& canvas, const BorderRadiusArray& radiusXY)
376 {
377 #ifdef ENABLE_ROSEN_BACKEND
378     RSBrush brush;
379     auto config = GetPaintConfig();
380     RSSamplingOptions options;
381     ImagePainterUtils::AddFilter(brush, options, config);
382     auto radii = ImagePainterUtils::ToRSRadius(radiusXY);
383     auto& recordingCanvas = static_cast<Rosen::ExtendRecordingCanvas&>(canvas);
384     std::vector<RSPoint> radius;
385     for (int ii = 0; ii < 4; ii++) {
386         RSPoint point(radii[ii].GetX(), radii[ii].GetY());
387         radius.emplace_back(point);
388     }
389     recordingCanvas.ClipAdaptiveRoundRect(radius);
390     recordingCanvas.Scale(config.scaleX_, config.scaleY_);
391 
392     RSPoint pointRadius[4] = {};
393     for (int i = 0; i < 4; i++) {
394         pointRadius[i] = radius[i];
395     }
396     Rosen::Drawing::AdaptiveImageInfo rsImageInfo = {
397         static_cast<int32_t>(config.imageFit_), static_cast<int32_t>(config.imageRepeat_),
398         {pointRadius[0], pointRadius[1], pointRadius[2], pointRadius[3]}, 1.0, GetUniqueID(),
399         GetCompressWidth(), GetCompressHeight()
400     };
401     auto data = GetCompressData();
402     recordingCanvas.AttachBrush(brush);
403     recordingCanvas.DrawImageWithParm(GetImage(), std::move(data), rsImageInfo, options);
404     recordingCanvas.DetachBrush();
405     return true;
406 #else // !ENABLE_ROSEN_BACKEND
407     return false;
408 #endif
409 }
410 
DrawRect(RSCanvas & canvas,const RSRect & srcRect,const RSRect & dstRect)411 void DrawingImage::DrawRect(RSCanvas& canvas, const RSRect& srcRect, const RSRect& dstRect)
412 {
413 #ifdef ENABLE_ROSEN_BACKEND
414     auto& recordingCanvas = static_cast<Rosen::Drawing::RecordingCanvas&>(canvas);
415     RSBrush brush;
416     RSSamplingOptions options;
417     RSRect dst = RSRect(dstRect.GetLeft(), dstRect.GetTop(), dstRect.GetRight(), dstRect.GetBottom());
418     RSRect src = RSRect(srcRect.GetLeft(), srcRect.GetTop(), srcRect.GetRight(), srcRect.GetBottom());
419     recordingCanvas.AttachBrush(brush);
420     auto imagePtr = GetImage();
421     recordingCanvas.DrawImageRect(*imagePtr, src, dst, options);
422     recordingCanvas.DetachBrush();
423 #else // !ENABLE_ROSEN_BACKEND
424 #endif
425 }
426 } // namespace OHOS::Ace::NG
427 
428 namespace OHOS::Ace {
Purge()429 void ImageCache::Purge()
430 {
431     SkGraphics::PurgeResourceCache();
432 }
433 } // namespace OHOS::Ace::NG
434