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/skia_image.h"
17 
18 #include <utility>
19 
20 #include "image_painter_utils.h"
21 #include "include/core/SkGraphics.h"
22 
23 #include "base/image/pixel_map.h"
24 #include "core/components_ng/render/drawing.h"
25 #include "core/image/sk_image_cache.h"
26 #ifdef ENABLE_ROSEN_BACKEND
27 #include "pipeline/rs_recording_canvas.h"
28 #endif
29 
30 namespace OHOS::Ace::NG {
31 namespace {
CloneSkPixmap(SkPixmap & srcPixmap,const std::unique_ptr<uint8_t[]> & dstPixels)32 SkPixmap CloneSkPixmap(SkPixmap& srcPixmap, const std::unique_ptr<uint8_t[]>& dstPixels)
33 {
34     // Media::PixelMap::Create only accepts BGRA ColorType pixmap, have to clone and change ColorType.
35     SkImageInfo dstImageInfo = SkImageInfo::Make(srcPixmap.info().width(), srcPixmap.info().height(),
36         SkColorType::kBGRA_8888_SkColorType, srcPixmap.alphaType());
37     SkPixmap dstPixmap(dstImageInfo, dstPixels.get(), srcPixmap.rowBytes());
38 
39     SkBitmap dstBitmap;
40     if (!dstBitmap.installPixels(dstPixmap)) {
41         return dstPixmap;
42     }
43     if (!dstBitmap.writePixels(srcPixmap, 0, 0)) {
44         return dstPixmap;
45     }
46     return dstPixmap;
47 }
48 } // namespace
49 
Create(void * rawImage)50 RefPtr<CanvasImage> CanvasImage::Create(void* rawImage)
51 {
52     auto* skImagePtr = reinterpret_cast<sk_sp<SkImage>*>(rawImage);
53     return AceType::MakeRefPtr<SkiaImage>(*skImagePtr);
54 }
55 
Create()56 RefPtr<CanvasImage> CanvasImage::Create()
57 {
58     return AceType::MakeRefPtr<SkiaImage>();
59 }
60 
MakeSkImageFromPixmap(const RefPtr<PixelMap> & pixmap)61 sk_sp<SkImage> SkiaImage::MakeSkImageFromPixmap(const RefPtr<PixelMap>& pixmap)
62 {
63     SkColorType colorType = PixelFormatToSkColorType(pixmap);
64     SkAlphaType alphaType = AlphaTypeToSkAlphaType(pixmap);
65     sk_sp<SkColorSpace> colorSpace = ColorSpaceToSkColorSpace(pixmap);
66     auto info = SkImageInfo::Make(pixmap->GetWidth(), pixmap->GetHeight(), colorType, alphaType, colorSpace);
67 
68     SkPixmap skPixmap(info, pixmap->GetPixels(), pixmap->GetRowBytes());
69     return SkImage::MakeFromRaster(skPixmap, &PixelMap::ReleaseProc, PixelMap::GetReleaseContext(pixmap));
70 }
71 
ColorSpaceToSkColorSpace(const RefPtr<PixelMap> & pixmap)72 sk_sp<SkColorSpace> SkiaImage::ColorSpaceToSkColorSpace(const RefPtr<PixelMap>& pixmap)
73 {
74     return SkColorSpace::MakeSRGB(); // Media::PixelMap has not support wide gamut yet.
75 }
76 
AlphaTypeToSkAlphaType(const RefPtr<PixelMap> & pixmap)77 SkAlphaType SkiaImage::AlphaTypeToSkAlphaType(const RefPtr<PixelMap>& pixmap)
78 {
79     switch (pixmap->GetAlphaType()) {
80         case AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
81             return SkAlphaType::kUnknown_SkAlphaType;
82         case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
83             return SkAlphaType::kOpaque_SkAlphaType;
84         case AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
85             return SkAlphaType::kPremul_SkAlphaType;
86         case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
87             return SkAlphaType::kUnpremul_SkAlphaType;
88         default:
89             return SkAlphaType::kUnknown_SkAlphaType;
90     }
91 }
92 
PixelFormatToSkColorType(const RefPtr<PixelMap> & pixmap)93 SkColorType SkiaImage::PixelFormatToSkColorType(const RefPtr<PixelMap>& pixmap)
94 {
95     switch (pixmap->GetPixelFormat()) {
96         case PixelFormat::RGB_565:
97             return SkColorType::kRGB_565_SkColorType;
98         case PixelFormat::RGBA_8888:
99             return SkColorType::kRGBA_8888_SkColorType;
100         case PixelFormat::BGRA_8888:
101             return SkColorType::kBGRA_8888_SkColorType;
102         case PixelFormat::ALPHA_8:
103             return SkColorType::kAlpha_8_SkColorType;
104         case PixelFormat::RGBA_F16:
105             return SkColorType::kRGBA_F16_SkColorType;
106         case PixelFormat::UNKNOWN:
107         case PixelFormat::ARGB_8888:
108         case PixelFormat::RGB_888:
109         case PixelFormat::NV21:
110         case PixelFormat::NV12:
111         case PixelFormat::CMYK:
112         default:
113             return SkColorType::kUnknown_SkColorType;
114     }
115 }
116 
ReplaceSkImage(sk_sp<SkImage> newSkImage)117 void SkiaImage::ReplaceSkImage(sk_sp<SkImage> newSkImage)
118 {
119     image_ = std::move(newSkImage);
120 }
121 
GetWidth() const122 int32_t SkiaImage::GetWidth() const
123 {
124     return image_ ? image_->width() : compressWidth_;
125 }
126 
GetHeight() const127 int32_t SkiaImage::GetHeight() const
128 {
129     return image_ ? image_->height() : compressHeight_;
130 }
131 
Clone()132 RefPtr<CanvasImage> SkiaImage::Clone()
133 {
134     auto clone = MakeRefPtr<SkiaImage>(image_);
135     clone->uniqueId_ = uniqueId_;
136     clone->compressData_ = std::move(compressData_);
137     clone->compressWidth_ = compressWidth_;
138     clone->compressHeight_ = compressHeight_;
139     return clone;
140 }
141 
Cache(const std::string & key)142 void SkiaImage::Cache(const std::string& key)
143 {
144     auto pipelineCtx = PipelineContext::GetCurrentContext();
145     CHECK_NULL_VOID(pipelineCtx);
146     auto cache = pipelineCtx->GetImageCache();
147     CHECK_NULL_VOID(cache);
148 
149     auto cached = std::make_shared<CachedImage>(GetImage());
150     cached->uniqueId = GetUniqueID();
151     pipelineCtx->GetImageCache()->CacheImage(key, cached);
152 }
153 
QueryFromCache(const std::string & key)154 RefPtr<CanvasImage> SkiaImage::QueryFromCache(const std::string& key)
155 {
156     auto pipelineCtx = PipelineContext::GetCurrentContext();
157     CHECK_NULL_RETURN(pipelineCtx, nullptr);
158     auto cache = pipelineCtx->GetImageCache();
159     CHECK_NULL_RETURN(cache, nullptr);
160     auto cacheImage = cache->GetCacheImage(key);
161     CHECK_NULL_RETURN(cacheImage, nullptr);
162 
163     auto skiaImage = MakeRefPtr<SkiaImage>(cacheImage->imagePtr);
164     skiaImage->SetUniqueID(cacheImage->uniqueId);
165 
166     return skiaImage;
167 }
168 
GetPixelMap() const169 RefPtr<PixelMap> SkiaImage::GetPixelMap() const
170 {
171     CHECK_NULL_RETURN(GetImage(), nullptr);
172     auto rasterImage = GetImage()->makeRasterImage();
173     SkPixmap srcPixmap;
174     if (!rasterImage->peekPixels(&srcPixmap)) {
175         return nullptr;
176     }
177     auto dstPixels = std::make_unique<uint8_t[]>(srcPixmap.computeByteSize());
178     SkPixmap newSrcPixmap = CloneSkPixmap(srcPixmap, dstPixels);
179     const auto* addr = newSrcPixmap.addr32();
180     auto width = static_cast<int32_t>(newSrcPixmap.width());
181     auto height = static_cast<int32_t>(newSrcPixmap.height());
182     int32_t length = width * height;
183     return PixelMap::ConvertSkImageToPixmap(addr, length, width, height);
184 }
185 
DrawToRSCanvas(RSCanvas & canvas,const RSRect & srcRect,const RSRect & dstRect,const BorderRadiusArray & radiusXY)186 void SkiaImage::DrawToRSCanvas(
187     RSCanvas& canvas, const RSRect& srcRect, const RSRect& dstRect, const BorderRadiusArray& radiusXY)
188 {
189     auto image = GetImage();
190     CHECK_NULL_VOID(image || GetCompressData());
191     if (isDrawAnimate_) {
192         RSImage rsImage(&image);
193         RSSamplingOptions options;
194         ImagePainterUtils::ClipRRect(canvas, dstRect, radiusXY);
195         canvas.DrawImageRect(rsImage, srcRect, dstRect, options);
196     } else {
197         DrawWithRecordingCanvas(canvas, radiusXY);
198     }
199 }
200 
DrawWithRecordingCanvas(RSCanvas & canvas,const BorderRadiusArray & radiusXY)201 bool SkiaImage::DrawWithRecordingCanvas(RSCanvas& canvas, const BorderRadiusArray& radiusXY)
202 {
203 #ifdef ENABLE_ROSEN_BACKEND
204     auto rsCanvas = canvas.GetImpl<RSSkCanvas>();
205     CHECK_NULL_RETURN(rsCanvas, false);
206     auto skCanvas = rsCanvas->ExportSkCanvas();
207     CHECK_NULL_RETURN(skCanvas, false);
208     auto recordingCanvas = static_cast<Rosen::RSRecordingCanvas*>(skCanvas);
209     CHECK_NULL_RETURN(recordingCanvas, false);
210 
211     SkPaint paint;
212     auto config = GetPaintConfig();
213 
214     SkSamplingOptions options;
215     ImagePainterUtils::AddFilter(paint, options, config);
216     auto radii = ImagePainterUtils::ToSkRadius(radiusXY);
217     recordingCanvas->ClipAdaptiveRRect(radii.get());
218     recordingCanvas->scale(config.scaleX_, config.scaleY_);
219 
220     Rosen::RsImageInfo rsImageInfo((int)(config.imageFit_), (int)(config.imageRepeat_), radii.get(), 1.0, GetUniqueID(),
221         GetCompressWidth(), GetCompressHeight());
222     auto data = GetCompressData();
223 
224     // Haw to set SamplingOptions?
225     recordingCanvas->DrawImageWithParm(GetImage(), std::move(data), rsImageInfo, options, paint);
226     return true;
227 #else // !ENABLE_ROSEN_BACKEND
228     return false;
229 #endif
230 }
231 } // namespace OHOS::Ace::NG
232 
233 namespace OHOS::Ace {
Purge()234 void ImageCache::Purge()
235 {
236     SkGraphics::PurgeResourceCache();
237 }
238 } // namespace OHOS::Ace
239