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 #ifndef USE_ROSEN_DRAWING
19 #ifdef NEW_SKIA
20 #include <include/gpu/GrDirectContext.h>
21 #else
22 #include <include/gpu/GrContext.h>
23 #endif
24 #include "include/core/SkPaint.h"
25 #include "include/core/SkRRect.h"
26 #endif
27 #include "platform/common/rs_log.h"
28 #include "platform/common/rs_system_properties.h"
29 #include "property/rs_properties_painter.h"
30 #include "render/rs_image_cache.h"
31 #include "render/rs_pixel_map_util.h"
32 #include "rs_trace.h"
33 #include "sandbox_utils.h"
34
35 namespace OHOS {
36 namespace Rosen {
37 namespace {
38 constexpr int32_t CORNER_SIZE = 4;
39 }
40
~RSImage()41 RSImage::~RSImage()
42 {}
43
IsEqual(const RSImage & other) const44 bool RSImage::IsEqual(const RSImage& other) const
45 {
46 bool radiusEq = true;
47 for (auto i = 0; i < CORNER_SIZE; i++) {
48 radiusEq &= (radius_[i] == other.radius_[i]);
49 }
50 return (image_ == other.image_) && (pixelMap_ == other.pixelMap_) &&
51 (imageFit_ == other.imageFit_) && (imageRepeat_ == other.imageRepeat_) &&
52 (scale_ == other.scale_) && radiusEq && (compressData_ == other.compressData_);
53 }
54 #ifndef USE_ROSEN_DRAWING
55 #ifdef NEW_SKIA
CanvasDrawImage(SkCanvas & canvas,const SkRect & rect,const SkSamplingOptions & samplingOptions,const SkPaint & paint,bool isBackground)56 void RSImage::CanvasDrawImage(SkCanvas& canvas, const SkRect& rect, const SkSamplingOptions& samplingOptions,
57 const SkPaint& paint, bool isBackground)
58 #else
59 void RSImage::CanvasDrawImage(SkCanvas& canvas, const SkRect& rect, const SkPaint& paint, bool isBackground)
60 #endif
61 {
62 UpdateNodeIdToPicture(nodeId_);
63 SkAutoCanvasRestore acr(&canvas, HasRadius());
64 frameRect_.SetAll(rect.left(), rect.top(), rect.width(), rect.height());
65 #else
66 void RSImage::CanvasDrawImage(Drawing::Canvas& canvas, const Drawing::Rect& rect, bool isBackground)
67 {
68 canvas.Save();
69 frameRect_.SetAll(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight());
70 #endif
71 if (!isBackground) {
72 ApplyImageFit();
73 ApplyCanvasClip(canvas);
74 }
75 #ifndef USE_ROSEN_DRAWING
76 #ifdef NEW_SKIA
77 DrawImageRepeatRect(samplingOptions, paint, canvas);
78 #else
79 DrawImageRepeatRect(paint, canvas);
80 #endif
81 #else
82 DrawImageRepeatRect(canvas);
83 canvas.Restore();
84 #endif
85 }
86
87 void RSImage::ApplyImageFit()
88 {
89 const float srcW = srcRect_.width_ / scale_;
90 const float srcH = srcRect_.height_ / scale_;
91 const float frameW = frameRect_.width_;
92 const float frameH = frameRect_.height_;
93 float dstW = frameW;
94 float dstH = frameH;
95 float ratio = srcW / srcH;
96 switch (imageFit_) {
97 case ImageFit::TOP_LEFT:
98 dstRect_.SetAll(0.f, 0.f, srcW, srcH);
99 return;
100 case ImageFit::FILL:
101 break;
102 case ImageFit::NONE:
103 dstW = srcW;
104 dstH = srcH;
105 break;
106 case ImageFit::COVER:
107 dstW = std::max(frameW, frameH * ratio);
108 dstH = std::max(frameH, frameW / ratio);
109 break;
110 case ImageFit::FIT_WIDTH:
111 dstH = frameW / ratio;
112 break;
113 case ImageFit::FIT_HEIGHT:
114 dstW = frameH * ratio;
115 break;
116 case ImageFit::SCALE_DOWN:
117 if (srcW < frameW && srcH < frameH) {
118 dstW = srcW;
119 dstH = srcH;
120 } else {
121 dstW = std::min(frameW, frameH * ratio);
122 dstH = std::min(frameH, frameW / ratio);
123 }
124 break;
125 case ImageFit::CONTAIN:
126 default:
127 dstW = std::min(frameW, frameH * ratio);
128 dstH = std::min(frameH, frameW / ratio);
129 break;
130 }
131 dstRect_.SetAll((frameW - dstW) / 2, (frameH - dstH) / 2, dstW, dstH);
132 }
133
134 bool RSImage::HasRadius() const
135 {
136 return hasRadius_;
137 }
138
139 #ifndef USE_ROSEN_DRAWING
140 void RSImage::ApplyCanvasClip(SkCanvas& canvas)
141 {
142 if (!HasRadius()) {
143 return;
144 }
145 auto rect = (imageRepeat_ == ImageRepeat::NO_REPEAT) ? dstRect_.IntersectRect(frameRect_) : frameRect_;
146 SkRRect rrect = SkRRect::MakeEmpty();
147 rrect.setRectRadii(RSPropertiesPainter::Rect2SkRect(rect), radius_);
148 canvas.clipRRect(rrect, true);
149 }
150 #else
151 void RSImage::ApplyCanvasClip(Drawing::Canvas& canvas)
152 {
153 auto rect = (imageRepeat_ == ImageRepeat::NO_REPEAT) ? dstRect_.IntersectRect(frameRect_) : frameRect_;
154 Drawing::RoundRect rrect(RSPropertiesPainter::Rect2DrawingRect(rect), radius_);
155 canvas.ClipRoundRect(rrect, Drawing::ClipOp::INTERSECT, true);
156 }
157 #endif
158
159 #ifndef USE_ROSEN_DRAWING
160 void RSImage::UploadGpu(SkCanvas& canvas)
161 {
162 if (!RSSystemProperties::GetASTCEnabled()) {
163 return;
164 }
165 #ifdef RS_ENABLE_GL
166 if (compressData_) {
167 auto cache = RSImageCache::Instance().GetSkiaImageCache(uniqueId_);
168 std::lock_guard<std::mutex> lock(mutex_);
169 if (cache) {
170 image_ = cache;
171 } else {
172 #ifdef NEW_SKIA
173 if (canvas.recordingContext() == nullptr) {
174 #else
175 if (canvas.getGrContext() == nullptr) {
176 #endif
177 return;
178 }
179 RS_TRACE_NAME("make compress img");
180 #ifdef NEW_SKIA
181 // [planning] new skia remove enum kASTC_CompressionType
182 // Need to confirm if kBC1_RGBA8_UNORM and kASTC_CompressionType are the same
183 auto image = SkImage::MakeTextureFromCompressed(GrAsDirectContext(canvas.recordingContext()), compressData_,
184 static_cast<int>(srcRect_.width_), static_cast<int>(srcRect_.height_),
185 SkImage::CompressionType::kASTC_RGBA8_UNORM);
186 #else
187 auto image = SkImage::MakeFromCompressed(canvas.getGrContext(), compressData_,
188 static_cast<int>(srcRect_.width_), static_cast<int>(srcRect_.height_), SkImage::kASTC_CompressionType);
189 #endif
190 if (image) {
191 image_ = image;
192 RSImageCache::Instance().CacheSkiaImage(uniqueId_, image);
193 } else {
194 RS_LOGE("make astc image %d (%d, %d) failed, size:%d", uniqueId_,
195 (int)srcRect_.width_, (int)srcRect_.height_, compressData_->size());
196 }
197 compressData_ = nullptr;
198 }
199 }
200 #endif
201 }
202 #else
203 void RSImage::UploadGpu(Drawing::Canvas& canvas)
204 {
205 #ifdef RS_ENABLE_GL
206 if (compressData_) {
207 auto cache = RSImageCache::Instance().GetDrawingImageCache(uniqueId_);
208 std::lock_guard<std::mutex> lock(mutex_);
209 if (cache) {
210 image_ = cache;
211 } else {
212 if (canvas.GetGPUContext() == nullptr) {
213 return;
214 }
215 RS_TRACE_NAME("make compress img");
216 auto image = std::make_shared<Drawing::Image>();
217 image->BuildFromCompressed(*canvas.GetGPUContext(), compressData_, static_cast<int>(srcRect_.width_),
218 static_cast<int>(srcRect_.height_), Drawing::CompressedType::ASTC);
219 if (image) {
220 image_ = image;
221 RSImageCache::Instance().CacheDrawingImage(uniqueId_, image);
222 } else {
223 RS_LOGE("make astc image %d (%d, %d) failed", uniqueId_, (int)srcRect_.width_, (int)srcRect_.height_);
224 }
225 compressData_ = nullptr;
226 }
227 }
228 #endif
229 }
230 #endif
231
232 #ifndef USE_ROSEN_DRAWING
233 #ifdef NEW_SKIA
234 void RSImage::DrawImageRepeatRect(const SkSamplingOptions& samplingOptions, const SkPaint& paint, SkCanvas& canvas)
235 #else
236 void RSImage::DrawImageRepeatRect(const SkPaint& paint, SkCanvas& canvas)
237 #endif
238 #else
239 void RSImage::DrawImageRepeatRect(Drawing::Canvas& canvas)
240 #endif
241 {
242 int minX = 0;
243 int minY = 0;
244 int maxX = 0;
245 int maxY = 0;
246 float left = frameRect_.left_;
247 float right = frameRect_.GetRight();
248 float top = frameRect_.top_;
249 float bottom = frameRect_.GetBottom();
250 // calculate REPEAT_XY
251 float eps = 0.01; // set epsilon
252 if (ImageRepeat::REPEAT_X == imageRepeat_ || ImageRepeat::REPEAT == imageRepeat_) {
253 while (dstRect_.left_ + minX * dstRect_.width_ > left + eps) {
254 --minX;
255 }
256 while (dstRect_.left_ + maxX * dstRect_.width_ < right - eps) {
257 ++maxX;
258 }
259 }
260 if (ImageRepeat::REPEAT_Y == imageRepeat_ || ImageRepeat::REPEAT == imageRepeat_) {
261 while (dstRect_.top_ + minY * dstRect_.height_ > top + eps) {
262 --minY;
263 }
264 while (dstRect_.top_ + maxY * dstRect_.height_ < bottom - eps) {
265 ++maxY;
266 }
267 }
268 // draw repeat rect
269 #ifndef USE_ROSEN_DRAWING
270 #if defined(ROSEN_OHOS) && defined(RS_ENABLE_GL)
271 if (pixelMap_ != nullptr && pixelMap_->GetAllocatorType() != Media::AllocatorType::DMA_ALLOC) {
272 ConvertPixelMapToSkImage();
273 }
274 #else
275 ConvertPixelMapToSkImage();
276 #endif
277 #else
278 ConvertPixelMapToDrawingImage();
279 #endif
280 UploadGpu(canvas);
281 #ifndef USE_ROSEN_DRAWING
282 auto src = RSPropertiesPainter::Rect2SkRect(srcRect_);
283 #else
284 if (image_ == nullptr) {
285 RS_LOGE("RSImage::DrawImageRepeatRect failed, image is nullptr");
286 return;
287 }
288 auto src = RSPropertiesPainter::Rect2DrawingRect(srcRect_);
289 #endif
290 for (int i = minX; i <= maxX; ++i) {
291 for (int j = minY; j <= maxY; ++j) {
292 #ifndef USE_ROSEN_DRAWING
293 auto dst = SkRect::MakeXYWH(dstRect_.left_ + i * dstRect_.width_, dstRect_.top_ + j * dstRect_.height_,
294 dstRect_.width_, dstRect_.height_);
295 #ifdef NEW_SKIA
296 canvas.drawImageRect(image_, src, dst, samplingOptions, &paint, SkCanvas::kFast_SrcRectConstraint);
297 #else
298 canvas.drawImageRect(image_, src, dst, &paint, SkCanvas::kFast_SrcRectConstraint);
299 #endif
300 #else
301 auto dst = Drawing::Rect(dstRect_.left_ + i * dstRect_.width_, dstRect_.top_ + j * dstRect_.height_,
302 dstRect_.left_ + (i + 1) * dstRect_.width_, dstRect_.top_ + (j + 1) * dstRect_.height_);
303 Drawing::SamplingOptions samplingOptions;
304 canvas.DrawImageRect(*image_, src, dst, samplingOptions,
305 Drawing::SrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
306 #endif
307 }
308 }
309 }
310
311 #ifndef USE_ROSEN_DRAWING
312 void RSImage::SetCompressData(const sk_sp<SkData> data, const uint32_t id, const int width, const int height)
313 #else
314 void RSImage::SetCompressData(
315 const std::shared_ptr<Drawing::Data> data, const uint32_t id, const int width, const int height)
316 #endif
317 {
318 #ifdef RS_ENABLE_GL
319 compressData_ = data;
320 if (compressData_) {
321 srcRect_.SetAll(0.0, 0.0, width, height);
322 #ifndef USE_ROSEN_DRAWING
323 GenUniqueId(image_ ? image_->uniqueID() : id);
324 #else
325 GenUniqueId(image_ ? image_->GetUniqueID() : id);
326 #endif
327 image_ = nullptr;
328 }
329 #endif
330 }
331
332 void RSImage::SetImageFit(int fitNum)
333 {
334 imageFit_ = static_cast<ImageFit>(fitNum);
335 }
336
337 void RSImage::SetImageRepeat(int repeatNum)
338 {
339 imageRepeat_ = static_cast<ImageRepeat>(repeatNum);
340 }
341
342 #ifndef USE_ROSEN_DRAWING
343 void RSImage::SetRadius(const SkVector radius[])
344 #else
345 void RSImage::SetRadius(const std::vector<Drawing::Point>& radius)
346 #endif
347 {
348 hasRadius_ = false;
349 for (auto i = 0; i < CORNER_SIZE; i++) {
350 radius_[i] = radius[i];
351 #ifndef USE_ROSEN_DRAWING
352 hasRadius_ = hasRadius_ || !radius_[i].isZero();
353 #else
354 hasRadius_ = hasRadius_ || radius_[i].GetX() != 0 || radius_[i].GetY() != 0;
355 #endif
356 }
357 }
358
359 void RSImage::SetScale(double scale)
360 {
361 if (scale > 0.0) {
362 scale_ = scale;
363 }
364 }
365
366 void RSImage::SetNodeId(NodeId nodeId)
367 {
368 nodeId_ = nodeId;
369 }
370
371 #ifdef ROSEN_OHOS
372 static bool UnmarshallingIdAndSize(Parcel& parcel, uint64_t& uniqueId, int& width, int& height)
373 {
374 if (!RSMarshallingHelper::Unmarshalling(parcel, uniqueId)) {
375 RS_LOGE("RSImage::Unmarshalling uniqueId fail");
376 return false;
377 }
378 if (!RSMarshallingHelper::Unmarshalling(parcel, width)) {
379 RS_LOGE("RSImage::Unmarshalling width fail");
380 return false;
381 }
382 if (!RSMarshallingHelper::Unmarshalling(parcel, height)) {
383 RS_LOGE("RSImage::Unmarshalling height fail");
384 return false;
385 }
386 return true;
387 }
388
389 #ifndef USE_ROSEN_DRAWING
390 static bool UnmarshallingCompressData(Parcel& parcel, bool skipData, sk_sp<SkData>& compressData)
391 {
392 if (skipData) {
393 if (!RSMarshallingHelper::SkipSkData(parcel)) {
394 RS_LOGE("RSImage::Unmarshalling SkipSkData fail");
395 return false;
396 }
397 } else {
398 if (!RSMarshallingHelper::UnmarshallingWithCopy(parcel, compressData)) {
399 RS_LOGE("RSImage::Unmarshalling UnmarshallingWithCopy SkData fail");
400 return false;
401 }
402 }
403 return true;
404 }
405 #else
406 static bool UnmarshallingCompressData(Parcel& parcel, bool skipData, std::shared_ptr<Drawing::Data>& compressData)
407 {
408 if (skipData) {
409 if (!RSMarshallingHelper::SkipData(parcel)) {
410 RS_LOGE("RSImage::Unmarshalling SkipData fail");
411 return false;
412 }
413 } else {
414 if (!RSMarshallingHelper::UnmarshallingWithCopy(parcel, compressData)) {
415 RS_LOGE("RSImage::Unmarshalling UnmarshallingWithCopy Data fail");
416 return false;
417 }
418 }
419 return true;
420 }
421 #endif
422
423 bool RSImage::Marshalling(Parcel& parcel) const
424 {
425 int imageFit = static_cast<int>(imageFit_);
426 int imageRepeat = static_cast<int>(imageRepeat_);
427
428 std::lock_guard<std::mutex> lock(mutex_);
429 auto image = image_;
430 #ifndef USE_ROSEN_DRAWING
431 if (image && image->isTextureBacked()) {
432 #else
433 if (image && image->IsTextureBacked()) {
434 #endif
435 image = nullptr;
436 ROSEN_LOGE("RSImage::Marshalling skip texture image");
437 }
438 bool success = RSMarshallingHelper::Marshalling(parcel, uniqueId_) &&
439 RSMarshallingHelper::Marshalling(parcel, static_cast<int>(srcRect_.width_)) &&
440 RSMarshallingHelper::Marshalling(parcel, static_cast<int>(srcRect_.height_)) &&
441 RSMarshallingHelper::Marshalling(parcel, nodeId_) &&
442 parcel.WriteBool(pixelMap_ == nullptr) &&
443 #ifndef USE_ROSEN_DRAWING
444 RSMarshallingHelper::Marshalling(parcel, image) &&
445 #else
446 RSMarshallingHelper::Marshalling(parcel, image) &&
447 #endif
448 RSMarshallingHelper::Marshalling(parcel, pixelMap_) &&
449 RSMarshallingHelper::Marshalling(parcel, compressData_) &&
450 RSMarshallingHelper::Marshalling(parcel, imageFit) &&
451 RSMarshallingHelper::Marshalling(parcel, imageRepeat) &&
452 RSMarshallingHelper::Marshalling(parcel, radius_) &&
453 RSMarshallingHelper::Marshalling(parcel, scale_);
454 return success;
455 }
456
457 RSImage* RSImage::Unmarshalling(Parcel& parcel)
458 {
459 uint64_t uniqueId;
460 int width;
461 int height;
462 if (!UnmarshallingIdAndSize(parcel, uniqueId, width, height)) {
463 RS_LOGE("RSImage::Unmarshalling UnmarshallingIdAndSize fail");
464 return nullptr;
465 }
466 NodeId nodeId;
467 if (!RSMarshallingHelper::Unmarshalling(parcel, nodeId)) {
468 RS_LOGE("RSImage::Unmarshalling nodeId fail");
469 return nullptr;
470 }
471
472 #ifndef USE_ROSEN_DRAWING
473 bool useSkImage;
474 sk_sp<SkImage> img;
475 std::shared_ptr<Media::PixelMap> pixelMap;
476 void* imagepixelAddr = nullptr;
477 if (!UnmarshallingSkImageAndPixelMap(parcel, uniqueId, useSkImage, img, pixelMap, imagepixelAddr)) {
478 return nullptr;
479 }
480 sk_sp<SkData> compressData;
481 bool skipData = img != nullptr || !useSkImage;
482 if (!UnmarshallingCompressData(parcel, skipData, compressData)) {
483 return nullptr;
484 }
485 #else
486 bool useSkImage;
487 std::shared_ptr<Drawing::Image> img;
488 std::shared_ptr<Media::PixelMap> pixelMap;
489 void* imagepixelAddr = nullptr;
490 if (!UnmarshallingDrawingImageAndPixelMap(parcel, uniqueId, useSkImage, img, pixelMap, imagepixelAddr)) {
491 return nullptr;
492 }
493 std::shared_ptr<Drawing::Data> compressData;
494 bool skipData = img != nullptr || !useSkImage;
495 if (!UnmarshallingCompressData(parcel, skipData, compressData)) {
496 return nullptr;
497 }
498 #endif
499
500 int fitNum;
501 if (!RSMarshallingHelper::Unmarshalling(parcel, fitNum)) {
502 RS_LOGE("RSImage::Unmarshalling fitNum fail");
503 return nullptr;
504 }
505
506 int repeatNum;
507 if (!RSMarshallingHelper::Unmarshalling(parcel, repeatNum)) {
508 RS_LOGE("RSImage::Unmarshalling repeatNum fail");
509 return nullptr;
510 }
511
512 #ifndef USE_ROSEN_DRAWING
513 SkVector radius[CORNER_SIZE];
514 for (auto i = 0; i < CORNER_SIZE; i++) {
515 if (!RSMarshallingHelper::Unmarshalling(parcel, radius[i])) {
516 RS_LOGE("RSImage::Unmarshalling radius fail");
517 return nullptr;
518 }
519 }
520 #else
521 std::vector<Drawing::Point> radius(CORNER_SIZE);
522 if (!RSMarshallingHelper::Unmarshalling(parcel, radius)) {
523 RS_LOGE("RSImage::Unmarshalling radius fail");
524 return nullptr;
525 }
526 #endif
527
528 double scale;
529 if (!RSMarshallingHelper::Unmarshalling(parcel, scale)) {
530 RS_LOGE("RSImage::Unmarshalling scale fail");
531 return nullptr;
532 }
533
534 RSImage* rsImage = new RSImage();
535 rsImage->SetImage(img);
536 rsImage->SetImagePixelAddr(imagepixelAddr);
537 rsImage->SetCompressData(compressData, uniqueId, width, height);
538 rsImage->SetPixelMap(pixelMap);
539 rsImage->SetImageFit(fitNum);
540 rsImage->SetImageRepeat(repeatNum);
541 rsImage->SetRadius(radius);
542 rsImage->SetScale(scale);
543 rsImage->SetNodeId(nodeId);
544 rsImage->uniqueId_ = uniqueId;
545 rsImage->MarkRenderServiceImage();
546 RSImageBase::IncreaseCacheRefCount(uniqueId, useSkImage, pixelMap);
547 return rsImage;
548 }
549 #endif
550 } // namespace Rosen
551 } // namespace OHOS
552