• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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/skia_canvas_image.h"
17 
18 #include "third_party/skia/include/core/SkColorFilter.h"
19 
20 #include "base/image/pixel_map.h"
21 #include "core/components_ng/render/drawing.h"
22 #ifdef ENABLE_ROSEN_BACKEND
23 #include "pipeline/rs_recording_canvas.h"
24 #endif
25 
26 namespace OHOS::Ace::NG {
27 namespace {
28 constexpr uint8_t RADIUS_POINTS_SIZE = 4;
29 
30 const float GRAY_COLOR_MATRIX[20] = { 0.30f, 0.59f, 0.11f, 0, 0, // red
31     0.30f, 0.59f, 0.11f, 0, 0,                                   // green
32     0.30f, 0.59f, 0.11f, 0, 0,                                   // blue
33     0, 0, 0, 1.0f, 0 };                                          // alpha transparency
34 
CloneSkPixmap(SkPixmap & srcPixmap,const std::unique_ptr<uint8_t[]> & dstPixels)35 SkPixmap CloneSkPixmap(SkPixmap& srcPixmap, const std::unique_ptr<uint8_t[]>& dstPixels)
36 {
37     // Media::PixelMap::Create only accepts BGRA ColorType pixmap, have to clone and change ColorType.
38     SkImageInfo dstImageInfo = SkImageInfo::Make(srcPixmap.info().width(), srcPixmap.info().height(),
39         SkColorType::kBGRA_8888_SkColorType, srcPixmap.alphaType());
40     SkPixmap dstPixmap(dstImageInfo, dstPixels.get(), srcPixmap.rowBytes());
41 
42     SkBitmap dstBitmap;
43     if (!dstBitmap.installPixels(dstPixmap)) {
44         return dstPixmap;
45     }
46     if (!dstBitmap.writePixels(srcPixmap, 0, 0)) {
47         return dstPixmap;
48     }
49     return dstPixmap;
50 }
51 } // namespace
52 
Create(void * rawImage)53 RefPtr<CanvasImage> CanvasImage::Create(void* rawImage)
54 {
55 #ifdef NG_BUILD
56     return AceType::MakeRefPtr<SkiaCanvasImage>();
57 #else
58     auto* imageRef = reinterpret_cast<fml::RefPtr<flutter::CanvasImage>*>(rawImage);
59     CHECK_NULL_RETURN(imageRef, nullptr);
60 
61     return AceType::MakeRefPtr<SkiaCanvasImage>(*imageRef);
62 #endif
63 }
64 
MakeSkImageInfoFromPixelMap(const RefPtr<PixelMap> & pixmap)65 SkImageInfo SkiaCanvasImage::MakeSkImageInfoFromPixelMap(const RefPtr<PixelMap>& pixmap)
66 {
67     SkColorType colorType = PixelFormatToSkColorType(pixmap);
68     SkAlphaType alphaType = AlphaTypeToSkAlphaType(pixmap);
69     sk_sp<SkColorSpace> colorSpace = ColorSpaceToSkColorSpace(pixmap);
70     return SkImageInfo::Make(pixmap->GetWidth(), pixmap->GetHeight(), colorType, alphaType, colorSpace);
71 }
72 
ColorSpaceToSkColorSpace(const RefPtr<PixelMap> & pixmap)73 sk_sp<SkColorSpace> SkiaCanvasImage::ColorSpaceToSkColorSpace(const RefPtr<PixelMap>& pixmap)
74 {
75     return SkColorSpace::MakeSRGB(); // Media::PixelMap has not support wide gamut yet.
76 }
77 
AlphaTypeToSkAlphaType(const RefPtr<PixelMap> & pixmap)78 SkAlphaType SkiaCanvasImage::AlphaTypeToSkAlphaType(const RefPtr<PixelMap>& pixmap)
79 {
80     switch (pixmap->GetAlphaType()) {
81         case AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
82             return SkAlphaType::kUnknown_SkAlphaType;
83         case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
84             return SkAlphaType::kOpaque_SkAlphaType;
85         case AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
86             return SkAlphaType::kPremul_SkAlphaType;
87         case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
88             return SkAlphaType::kUnpremul_SkAlphaType;
89         default:
90             return SkAlphaType::kUnknown_SkAlphaType;
91     }
92 }
93 
PixelFormatToSkColorType(const RefPtr<PixelMap> & pixmap)94 SkColorType SkiaCanvasImage::PixelFormatToSkColorType(const RefPtr<PixelMap>& pixmap)
95 {
96     switch (pixmap->GetPixelFormat()) {
97         case PixelFormat::RGB_565:
98             return SkColorType::kRGB_565_SkColorType;
99         case PixelFormat::RGBA_8888:
100             return SkColorType::kRGBA_8888_SkColorType;
101         case PixelFormat::BGRA_8888:
102             return SkColorType::kBGRA_8888_SkColorType;
103         case PixelFormat::ALPHA_8:
104             return SkColorType::kAlpha_8_SkColorType;
105         case PixelFormat::RGBA_F16:
106             return SkColorType::kRGBA_F16_SkColorType;
107         case PixelFormat::UNKNOWN:
108         case PixelFormat::ARGB_8888:
109         case PixelFormat::RGB_888:
110         case PixelFormat::NV21:
111         case PixelFormat::NV12:
112         case PixelFormat::CMYK:
113         default:
114             return SkColorType::kUnknown_SkColorType;
115     }
116 }
117 
ReplaceSkImage(flutter::SkiaGPUObject<SkImage> newSkGpuObjSkImage)118 void SkiaCanvasImage::ReplaceSkImage(flutter::SkiaGPUObject<SkImage> newSkGpuObjSkImage)
119 {
120 #ifndef NG_BUILD
121     image_->set_image(std::move(newSkGpuObjSkImage));
122 #endif
123 }
124 
GetWidth() const125 int32_t SkiaCanvasImage::GetWidth() const
126 {
127 #ifdef NG_BUILD
128     return 0;
129 #else
130     return image_->image() ? image_->width() : image_->compressWidth();
131 #endif
132 }
133 
GetHeight() const134 int32_t SkiaCanvasImage::GetHeight() const
135 {
136 #ifdef NG_BUILD
137     return 0;
138 #else
139     return image_->image() ? image_->height() : image_->compressHeight();
140 #endif
141 }
142 
Clone()143 RefPtr<CanvasImage> SkiaCanvasImage::Clone()
144 {
145     auto clone = MakeRefPtr<SkiaCanvasImage>(image_);
146     clone->uniqueId_ = uniqueId_;
147     return clone;
148 }
149 
AddFilter(SkPaint & paint)150 void SkiaCanvasImage::AddFilter(SkPaint& paint)
151 {
152     auto config = GetPaintConfig();
153     paint.setFilterQuality(SkFilterQuality(config.imageInterpolation_));
154     if (ImageRenderMode::TEMPLATE == config.renderMode_ || config.colorFilter_) {
155         RSColorMatrix colorFilterMatrix;
156         if (config.colorFilter_) {
157             paint.setColorFilter(SkColorFilters::Matrix(config.colorFilter_->data()));
158         } else if (ImageRenderMode::TEMPLATE == config.renderMode_) {
159             paint.setColorFilter(SkColorFilters::Matrix(GRAY_COLOR_MATRIX));
160         }
161     }
162 }
163 
GetPixelMap()164 RefPtr<PixelMap> SkiaCanvasImage::GetPixelMap()
165 {
166     CHECK_NULL_RETURN(GetCanvasImage(), nullptr);
167     auto rasterImage = GetCanvasImage()->makeRasterImage();
168     SkPixmap srcPixmap;
169     if (!rasterImage->peekPixels(&srcPixmap)) {
170         return nullptr;
171     }
172     auto dstPixels = std::make_unique<uint8_t[]>(srcPixmap.computeByteSize());
173     SkPixmap newSrcPixmap = CloneSkPixmap(srcPixmap, dstPixels);
174     const auto* addr = newSrcPixmap.addr32();
175     auto width = static_cast<int32_t>(newSrcPixmap.width());
176     auto height = static_cast<int32_t>(newSrcPixmap.height());
177     int32_t length = width * height;
178     return PixelMap::ConvertSkImageToPixmap(addr, length, width, height);
179 }
180 
ClipRRect(RSCanvas & canvas,const RSRect & dstRect,const BorderRadiusArray & radiusXY)181 void SkiaCanvasImage::ClipRRect(RSCanvas& canvas, const RSRect& dstRect, const BorderRadiusArray& radiusXY)
182 {
183     std::vector<RSPoint> radius(RADIUS_POINTS_SIZE);
184     for (size_t i = 0; i < radius.size(); ++i) {
185         radius[i] = RSPoint(radiusXY[i].GetX(), radiusXY[i].GetY());
186     }
187     RSRoundRect rRect(dstRect, radius);
188     canvas.ClipRoundRect(rRect, RSClipOp::INTERSECT);
189 }
190 
DrawToRSCanvas(RSCanvas & canvas,const RSRect & srcRect,const RSRect & dstRect,const BorderRadiusArray & radiusXY)191 void SkiaCanvasImage::DrawToRSCanvas(
192     RSCanvas& canvas, const RSRect& srcRect, const RSRect& dstRect, const BorderRadiusArray& radiusXY)
193 {
194     auto image = GetCanvasImage();
195     CHECK_NULL_VOID(image || GetCompressData());
196     if (!DrawWithRecordingCanvas(canvas, srcRect, dstRect, radiusXY)) {
197         RSImage rsImage(&image);
198         RSSamplingOptions options;
199         ClipRRect(canvas, dstRect, radiusXY);
200         canvas.DrawImageRect(rsImage, srcRect, dstRect, options);
201     }
202 }
203 
DrawWithRecordingCanvas(RSCanvas & canvas,const RSRect & srcRect,const RSRect & dstRect,const BorderRadiusArray & radiusXY)204 bool SkiaCanvasImage::DrawWithRecordingCanvas(
205     RSCanvas& canvas, const RSRect& srcRect, const RSRect& dstRect, const BorderRadiusArray& radiusXY)
206 {
207 #ifdef ENABLE_ROSEN_BACKEND
208     auto rsCanvas = canvas.GetImpl<RSSkCanvas>();
209     CHECK_NULL_RETURN(rsCanvas, false);
210     auto skCanvas = rsCanvas->ExportSkCanvas();
211     CHECK_NULL_RETURN(skCanvas, false);
212     auto recordingCanvas = static_cast<Rosen::RSRecordingCanvas*>(skCanvas);
213     CHECK_NULL_RETURN(recordingCanvas, false);
214 
215     SkPaint paint;
216     AddFilter(paint);
217     SkVector radii[RADIUS_POINTS_SIZE] = { { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 } };
218     if (radiusXY.size() == RADIUS_POINTS_SIZE) {
219         radii[SkRRect::kUpperLeft_Corner].set(
220             SkFloatToScalar(std::max(radiusXY[SkRRect::kUpperLeft_Corner].GetX(), 0.0f)),
221             SkFloatToScalar(std::max(radiusXY[SkRRect::kUpperLeft_Corner].GetY(), 0.0f)));
222         radii[SkRRect::kUpperRight_Corner].set(
223             SkFloatToScalar(std::max(radiusXY[SkRRect::kUpperRight_Corner].GetX(), 0.0f)),
224             SkFloatToScalar(std::max(radiusXY[SkRRect::kUpperRight_Corner].GetY(), 0.0f)));
225         radii[SkRRect::kLowerLeft_Corner].set(
226             SkFloatToScalar(std::max(radiusXY[SkRRect::kLowerRight_Corner].GetX(), 0.0f)),
227             SkFloatToScalar(std::max(radiusXY[SkRRect::kLowerRight_Corner].GetY(), 0.0f)));
228         radii[SkRRect::kLowerRight_Corner].set(
229             SkFloatToScalar(std::max(radiusXY[SkRRect::kLowerLeft_Corner].GetX(), 0.0f)),
230             SkFloatToScalar(std::max(radiusXY[SkRRect::kLowerLeft_Corner].GetY(), 0.0f)));
231     }
232     recordingCanvas->ClipAdaptiveRRect(radii);
233     auto config = GetPaintConfig();
234     if (config.imageFit_ == ImageFit::TOP_LEFT) {
235         SkAutoCanvasRestore acr(recordingCanvas, true);
236         auto skSrcRect = SkRect::MakeXYWH(srcRect.GetLeft(), srcRect.GetTop(), srcRect.GetWidth(), srcRect.GetHeight());
237         auto skDstRect = SkRect::MakeXYWH(dstRect.GetLeft(), dstRect.GetTop(), dstRect.GetWidth(), dstRect.GetHeight());
238         recordingCanvas->concat(SkMatrix::MakeRectToRect(skSrcRect, skDstRect, SkMatrix::kFill_ScaleToFit));
239     }
240     recordingCanvas->scale(config.scaleX_, config.scaleY_);
241 
242     Rosen::RsImageInfo rsImageInfo((int)(config.imageFit_), (int)(config.imageRepeat_), radii, 1.0, GetUniqueID(),
243         GetCompressWidth(), GetCompressHeight());
244     auto data = GetCompressData();
245     recordingCanvas->DrawImageWithParm(GetCanvasImage(), std::move(data), rsImageInfo, paint);
246     return true;
247 #else
248     return false;
249 #endif
250 }
251 } // namespace OHOS::Ace::NG
252