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