• 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 #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