1 /*
2 * Copyright (c) 2021-2022 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 "render/rs_image.h"
17
18 #include "include/core/SkPaint.h"
19 #include "include/core/SkRRect.h"
20 #include "pixel_map_rosen_utils.h"
21 #include "platform/common/rs_log.h"
22 #include "property/rs_properties_painter.h"
23 #include "render/rs_image_cache.h"
24 #include "rs_trace.h"
25 #include "sandbox_utils.h"
26
27 namespace OHOS {
28 namespace Rosen {
29 namespace {
30 constexpr int32_t CORNER_SIZE = 4;
31 }
32
~RSImage()33 RSImage::~RSImage()
34 {
35 image_ = nullptr;
36 if (uniqueId_ > 0) {
37 RSImageCache::Instance().ReleaseSkiaImageCache(uniqueId_);
38 }
39 }
40
IsEqual(const RSImage & other) const41 bool RSImage::IsEqual(const RSImage& other) const
42 {
43 bool radiusEq = true;
44 for (auto i = 0; i < CORNER_SIZE; i++) {
45 radiusEq &= (radius_[i] == other.radius_[i]);
46 }
47 return (image_ == other.image_) && (pixelmap_ == other.pixelmap_) &&
48 (imageFit_ == other.imageFit_) && (imageRepeat_ == other.imageRepeat_) &&
49 (scale_ == other.scale_) && radiusEq && (compressData_ == other.compressData_);
50 }
51
CanvasDrawImage(SkCanvas & canvas,const SkRect & rect,const SkPaint & paint,bool isBackground)52 void RSImage::CanvasDrawImage(SkCanvas& canvas, const SkRect& rect, const SkPaint& paint, bool isBackground)
53 {
54 canvas.save();
55 frameRect_.SetAll(rect.left(), rect.top(), rect.width(), rect.height());
56 if (!isBackground) {
57 ApplyImageFit();
58 ApplyCanvasClip(canvas);
59 }
60 DrawImageRepeatRect(paint, canvas);
61 canvas.restore();
62 }
63
ApplyImageFit()64 void RSImage::ApplyImageFit()
65 {
66 const float srcW = srcRect_.width_ / scale_;
67 const float srcH = srcRect_.height_ / scale_;
68 const float frameW = frameRect_.width_;
69 const float frameH = frameRect_.height_;
70 float dstW = frameW;
71 float dstH = frameH;
72 float ratio = srcW / srcH;
73 switch (imageFit_) {
74 case ImageFit::TOP_LEFT:
75 dstRect_.SetAll(0.f, 0.f, srcW, srcH);
76 return;
77 case ImageFit::FILL:
78 break;
79 case ImageFit::NONE:
80 dstW = srcW;
81 dstH = srcH;
82 break;
83 case ImageFit::COVER:
84 dstW = std::max(frameW, frameH * ratio);
85 dstH = std::max(frameH, frameW / ratio);
86 break;
87 case ImageFit::FIT_WIDTH:
88 dstH = frameW / ratio;
89 break;
90 case ImageFit::FIT_HEIGHT:
91 dstW = frameH * ratio;
92 break;
93 case ImageFit::SCALE_DOWN:
94 if (srcW < frameW && srcH < frameH) {
95 dstW = srcW;
96 dstH = srcH;
97 } else {
98 dstW = std::min(frameW, frameH * ratio);
99 dstH = std::min(frameH, frameW / ratio);
100 }
101 break;
102 case ImageFit::CONTAIN:
103 default:
104 dstW = std::min(frameW, frameH * ratio);
105 dstH = std::min(frameH, frameW / ratio);
106 break;
107 }
108 dstRect_.SetAll((frameW - dstW) / 2, (frameH - dstH) / 2, dstW, dstH);
109 }
110
ApplyCanvasClip(SkCanvas & canvas)111 void RSImage::ApplyCanvasClip(SkCanvas& canvas)
112 {
113 auto rect = (imageRepeat_ == ImageRepeat::NO_REPEAT) ? dstRect_.IntersectRect(frameRect_) : frameRect_;
114 SkRRect rrect = SkRRect::MakeEmpty();
115 rrect.setRectRadii(RSPropertiesPainter::Rect2SkRect(rect), radius_);
116 canvas.clipRRect(rrect, true);
117 }
118
UploadGpu(SkCanvas & canvas)119 void RSImage::UploadGpu(SkCanvas& canvas)
120 {
121 #ifdef RS_ENABLE_GL
122 if (compressData_) {
123 auto cache = RSImageCache::Instance().GetSkiaImageCache(uniqueId_);
124 std::lock_guard<std::mutex> lock(mutex_);
125 if (cache) {
126 image_ = cache;
127 } else {
128 if (canvas.getGrContext() == nullptr) {
129 return;
130 }
131 RS_TRACE_NAME("make compress img");
132 auto image = SkImage::MakeFromCompressed(canvas.getGrContext(), compressData_,
133 static_cast<int>(srcRect_.width_), static_cast<int>(srcRect_.height_), SkImage::kASTC_CompressionType);
134 if (image) {
135 image_ = image;
136 RSImageCache::Instance().CacheSkiaImage(uniqueId_, image);
137 } else {
138 RS_LOGE("make astc image %d (%d, %d) failed, size:%d", uniqueId_,
139 (int)srcRect_.width_, (int)srcRect_.height_, compressData_->size());
140 }
141 compressData_ = nullptr;
142 }
143 }
144 #endif
145 }
146
DrawImageRepeatRect(const SkPaint & paint,SkCanvas & canvas)147 void RSImage::DrawImageRepeatRect(const SkPaint& paint, SkCanvas& canvas)
148 {
149 int minX = 0;
150 int minY = 0;
151 int maxX = 0;
152 int maxY = 0;
153 float left = frameRect_.left_;
154 float right = frameRect_.GetRight();
155 float top = frameRect_.top_;
156 float bottom = frameRect_.GetBottom();
157 // calculate REPEAT_XY
158 float eps = 0.01; // set epsilon
159 if (ImageRepeat::REPEAT_X == imageRepeat_ || ImageRepeat::REPEAT == imageRepeat_) {
160 while (dstRect_.left_ + minX * dstRect_.width_ > left + eps) {
161 --minX;
162 }
163 while (dstRect_.left_ + maxX * dstRect_.width_ < right - eps) {
164 ++maxX;
165 }
166 }
167 if (ImageRepeat::REPEAT_Y == imageRepeat_ || ImageRepeat::REPEAT == imageRepeat_) {
168 while (dstRect_.top_ + minY * dstRect_.height_ > top + eps) {
169 --minY;
170 }
171 while (dstRect_.top_ + maxY * dstRect_.height_ < bottom - eps) {
172 ++maxY;
173 }
174 }
175 // draw repeat rect
176 if (!image_ && pixelmap_) {
177 image_ = Media::PixelMapRosenUtils::ExtractSkImage(pixelmap_);
178 }
179 UploadGpu(canvas);
180 auto src = RSPropertiesPainter::Rect2SkRect(srcRect_);
181 for (int i = minX; i <= maxX; ++i) {
182 for (int j = minY; j <= maxY; ++j) {
183 auto dst = SkRect::MakeXYWH(dstRect_.left_ + i * dstRect_.width_, dstRect_.top_ + j * dstRect_.height_,
184 dstRect_.width_, dstRect_.height_);
185 canvas.drawImageRect(image_, src, dst, &paint, SkCanvas::kFast_SrcRectConstraint);
186 }
187 }
188 }
189
SetImage(const sk_sp<SkImage> image)190 void RSImage::SetImage(const sk_sp<SkImage> image)
191 {
192 image_ = image;
193 if (image_) {
194 srcRect_.SetAll(0.0, 0.0, image_->width(), image_->height());
195 static uint64_t pid = static_cast<uint64_t>(GetRealPid()) << 32; // 32 for 64-bit unsignd number shift
196 uniqueId_ = pid | image_->uniqueID();
197 }
198 }
199
SetCompressData(const sk_sp<SkData> data,const uint32_t id,const int width,const int height)200 void RSImage::SetCompressData(const sk_sp<SkData> data, const uint32_t id, const int width, const int height)
201 {
202 #ifdef RS_ENABLE_GL
203 compressData_ = data;
204 if (compressData_) {
205 srcRect_.SetAll(0.0, 0.0, width, height);
206 static uint64_t pid = static_cast<uint64_t>(GetRealPid()) << 32; // 32 for 64-bit unsignd number shift
207 uniqueId_ = image_ ? (pid | image_->uniqueID()) : (pid | id) ;
208 image_ = nullptr;
209 }
210 #endif
211 }
212
SetPixelMap(const std::shared_ptr<Media::PixelMap> & pixelmap)213 void RSImage::SetPixelMap(const std::shared_ptr<Media::PixelMap>& pixelmap)
214 {
215 pixelmap_ = pixelmap;
216 if (pixelmap_) {
217 srcRect_.SetAll(0.0, 0.0, pixelmap_->GetWidth(), pixelmap_->GetHeight());
218 image_ = nullptr;
219 }
220 }
221
SetDstRect(const RectF & dstRect)222 void RSImage::SetDstRect(const RectF& dstRect)
223 {
224 dstRect_ = dstRect;
225 }
226
SetImageFit(int fitNum)227 void RSImage::SetImageFit(int fitNum)
228 {
229 imageFit_ = static_cast<ImageFit>(fitNum);
230 }
231
SetImageRepeat(int repeatNum)232 void RSImage::SetImageRepeat(int repeatNum)
233 {
234 imageRepeat_ = static_cast<ImageRepeat>(repeatNum);
235 }
236
SetRadius(const SkVector radius[])237 void RSImage::SetRadius(const SkVector radius[])
238 {
239 for (auto i = 0; i < CORNER_SIZE; i++) {
240 radius_[i] = radius[i];
241 }
242 }
243
SetScale(double scale)244 void RSImage::SetScale(double scale)
245 {
246 if (scale > 0.0) {
247 scale_ = scale;
248 }
249 }
250
251 #ifdef ROSEN_OHOS
Marshalling(Parcel & parcel) const252 bool RSImage::Marshalling(Parcel& parcel) const
253 {
254 int imageFit = static_cast<int>(imageFit_);
255 int imageRepeat = static_cast<int>(imageRepeat_);
256
257 std::lock_guard<std::mutex> lock(mutex_);
258 bool success = RSMarshallingHelper::Marshalling(parcel, uniqueId_) &&
259 RSMarshallingHelper::Marshalling(parcel, image_) &&
260 RSMarshallingHelper::Marshalling(parcel, compressData_) &&
261 RSMarshallingHelper::Marshalling(parcel, static_cast<int>(srcRect_.width_)) &&
262 RSMarshallingHelper::Marshalling(parcel, static_cast<int>(srcRect_.height_)) &&
263 RSMarshallingHelper::Marshalling(parcel, pixelmap_) &&
264 RSMarshallingHelper::Marshalling(parcel, imageFit) &&
265 RSMarshallingHelper::Marshalling(parcel, imageRepeat) &&
266 RSMarshallingHelper::Marshalling(parcel, radius_) &&
267 RSMarshallingHelper::Marshalling(parcel, scale_);
268 return success;
269 }
Unmarshalling(Parcel & parcel)270 RSImage* RSImage::Unmarshalling(Parcel& parcel)
271 {
272 sk_sp<SkImage> img;
273 sk_sp<SkData> compressData;
274 int width = 0;
275 int height = 0;
276 std::shared_ptr<Media::PixelMap> pixelmap;
277 int fitNum;
278 int repeatNum;
279 SkVector radius[CORNER_SIZE];
280 double scale;
281 uint64_t uniqueId;
282 if (!RSMarshallingHelper::Unmarshalling(parcel, uniqueId)) {
283 return nullptr;
284 }
285 img = RSImageCache::Instance().GetSkiaImageCache(uniqueId);
286 if (img != nullptr) {
287 // match a cached skimage
288 if (!RSMarshallingHelper::SkipSkImage(parcel)) {
289 return nullptr;
290 }
291 } else if (RSMarshallingHelper::Unmarshalling(parcel, img)) {
292 // unmarshalling the skimage and cache it
293 RSImageCache::Instance().CacheSkiaImage(uniqueId, img);
294 } else {
295 return nullptr;
296 }
297 if (img != nullptr) {
298 if (!RSMarshallingHelper::SkipSkData(parcel)) {
299 return nullptr;
300 }
301 } else {
302 if (!RSMarshallingHelper::UnmarshallingWithCopy(parcel, compressData)) {
303 return nullptr;
304 }
305 }
306 if (!RSMarshallingHelper::Unmarshalling(parcel, width)) {
307 return nullptr;
308 }
309 if (!RSMarshallingHelper::Unmarshalling(parcel, height)) {
310 return nullptr;
311 }
312 if (!RSMarshallingHelper::Unmarshalling(parcel, pixelmap)) {
313 return nullptr;
314 }
315 if (!RSMarshallingHelper::Unmarshalling(parcel, fitNum)) {
316 return nullptr;
317 }
318 if (!RSMarshallingHelper::Unmarshalling(parcel, repeatNum)) {
319 return nullptr;
320 }
321 for (auto i = 0; i < CORNER_SIZE; i++) {
322 if (!RSMarshallingHelper::Unmarshalling(parcel, radius[i])) {
323 return nullptr;
324 }
325 }
326 if (!RSMarshallingHelper::Unmarshalling(parcel, scale)) {
327 return nullptr;
328 }
329
330 RSImage* rsImage = new RSImage();
331 rsImage->SetImage(img);
332 rsImage->SetCompressData(compressData, uniqueId, width, height);
333 rsImage->SetPixelMap(pixelmap);
334 rsImage->SetImageFit(fitNum);
335 rsImage->SetImageRepeat(repeatNum);
336 rsImage->SetRadius(radius);
337 rsImage->SetScale(scale);
338 rsImage->uniqueId_ = uniqueId;
339
340 return rsImage;
341 }
342 #endif
343 } // namespace Rosen
344 } // namespace OHOS
345