• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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