• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "property/rs_properties_painter.h"
17 
18 #include "include/core/SkCanvas.h"
19 #include "include/core/SkColorFilter.h"
20 #include "include/core/SkMaskFilter.h"
21 #include "include/core/SkPaint.h"
22 #include "include/core/SkPoint3.h"
23 #include "include/core/SkRRect.h"
24 #include "include/core/SkSurface.h"
25 #include "include/effects/Sk1DPathEffect.h"
26 #include "include/effects/SkDashPathEffect.h"
27 #include "include/effects/SkLumaColorFilter.h"
28 #include "include/utils/SkShadowUtils.h"
29 
30 #include "common/rs_obj_abs_geometry.h"
31 #include "common/rs_vector2.h"
32 #include "pipeline/rs_draw_cmd_list.h"
33 #include "pipeline/rs_paint_filter_canvas.h"
34 #include "pipeline/rs_root_render_node.h"
35 #include "platform/common/rs_log.h"
36 #include "render/rs_blur_filter.h"
37 #include "render/rs_image.h"
38 #include "render/rs_mask.h"
39 #include "render/rs_path.h"
40 #include "render/rs_shader.h"
41 #include "render/rs_skia_filter.h"
42 
43 namespace OHOS {
44 namespace Rosen {
45 namespace {
46 bool g_forceBgAntiAlias = true;
47 constexpr int PARAM_DOUBLE = 2;
48 constexpr float MIN_TRANS_RATIO = 0.0f;
49 constexpr float MAX_TRANS_RATIO = 0.95f;
50 constexpr float MIN_SPOT_RATIO = 1.0f;
51 constexpr float MAX_SPOT_RATIO = 1.95f;
52 constexpr float MAX_AMBIENT_RADIUS = 150.0f;
53 } // namespace
54 
Rect2SkRect(const RectF & r)55 SkRect RSPropertiesPainter::Rect2SkRect(const RectF& r)
56 {
57     return SkRect::MakeXYWH(r.left_, r.top_, r.width_, r.height_);
58 }
59 
RRect2SkRRect(const RRect & rr)60 SkRRect RSPropertiesPainter::RRect2SkRRect(const RRect& rr)
61 {
62     SkRect rect = SkRect::MakeXYWH(rr.rect_.left_, rr.rect_.top_, rr.rect_.width_, rr.rect_.height_);
63     SkRRect rrect = SkRRect::MakeEmpty();
64 
65     // set radius for all 4 corner of RRect
66     constexpr uint32_t NUM_OF_CORNERS_IN_RECT = 4;
67     SkVector vec[NUM_OF_CORNERS_IN_RECT];
68     for (uint32_t i = 0; i < NUM_OF_CORNERS_IN_RECT; i++) {
69         vec[i].set(rr.radius_[i].x_, rr.radius_[i].y_);
70     }
71 
72     rrect.setRectRadii(rect, vec);
73     return rrect;
74 }
75 
GetGravityMatrix(Gravity gravity,RectF rect,float w,float h,SkMatrix & mat)76 bool RSPropertiesPainter::GetGravityMatrix(Gravity gravity, RectF rect, float w, float h, SkMatrix& mat)
77 {
78     if (w == rect.width_ && h == rect.height_) {
79         return false;
80     }
81     mat.reset();
82     switch (gravity) {
83         case Gravity::CENTER: {
84             mat.preTranslate((rect.width_ - w) / PARAM_DOUBLE, (rect.height_ - h) / PARAM_DOUBLE);
85             return true;
86         }
87         case Gravity::TOP: {
88             mat.preTranslate((rect.width_ - w) / PARAM_DOUBLE, 0);
89             return true;
90         }
91         case Gravity::BOTTOM: {
92             mat.preTranslate((rect.width_ - w) / PARAM_DOUBLE, rect.height_ - h);
93             return true;
94         }
95         case Gravity::LEFT: {
96             mat.preTranslate(0, (rect.height_ - h) / PARAM_DOUBLE);
97             return true;
98         }
99         case Gravity::RIGHT: {
100             mat.preTranslate(rect.width_ - w, (rect.height_ - h) / PARAM_DOUBLE);
101             return true;
102         }
103         case Gravity::TOP_LEFT: {
104             return false;
105         }
106         case Gravity::TOP_RIGHT: {
107             mat.preTranslate(rect.width_ - w, 0);
108             return true;
109         }
110         case Gravity::BOTTOM_LEFT: {
111             mat.preTranslate(0, rect.height_ - h);
112             return true;
113         }
114         case Gravity::BOTTOM_RIGHT: {
115             mat.preTranslate(rect.width_ - w, rect.height_ - h);
116             return true;
117         }
118         case Gravity::RESIZE: {
119             mat.preScale(rect.width_ / w, rect.height_ / h);
120             return true;
121         }
122         case Gravity::RESIZE_ASPECT: {
123             float scale = std::min(rect.width_ / w, rect.height_ / h);
124             mat.preScale(scale, scale);
125             mat.preTranslate((rect.width_ / scale - w) / PARAM_DOUBLE, (rect.height_ / scale - h) / PARAM_DOUBLE);
126             return true;
127         }
128         case Gravity::RESIZE_ASPECT_FILL: {
129             float scale = std::max(rect.width_ / w, rect.height_ / h);
130             mat.preScale(scale, scale);
131             mat.preTranslate((rect.width_ / scale - w) / PARAM_DOUBLE, (rect.height_ / scale - h) / PARAM_DOUBLE);
132             return true;
133         }
134         default: {
135             ROSEN_LOGE("GetGravityMatrix unknow gravity=[%d]", gravity);
136             return false;
137         }
138     }
139 }
140 
Clip(SkCanvas & canvas,RectF rect)141 void RSPropertiesPainter::Clip(SkCanvas& canvas, RectF rect)
142 {
143     canvas.clipRect(Rect2SkRect(rect), true);
144 }
145 
GetShadowDirtyRect(RectI & dirtyShadow,const RSProperties & properties,const RRect * rrect)146 void RSPropertiesPainter::GetShadowDirtyRect(RectI& dirtyShadow, const RSProperties& properties, const RRect* rrect)
147 {
148     // [Planning]: After Skia being updated, we should directly call SkShadowUtils::GetLocalBounds here.
149     if (!properties.IsShadowValid()) {
150         return;
151     }
152     SkPath skPath;
153     if (properties.GetShadowPath() && !properties.GetShadowPath()->GetSkiaPath().isEmpty()) {
154         skPath = properties.GetShadowPath()->GetSkiaPath();
155     } else if (properties.GetClipBounds()) {
156         skPath = properties.GetClipBounds()->GetSkiaPath();
157     } else {
158         if (rrect != nullptr) {
159             skPath.addRRect(RRect2SkRRect(*rrect));
160         } else {
161             skPath.addRRect(RRect2SkRRect(properties.GetRRect()));
162         }
163     }
164     skPath.offset(properties.GetShadowOffsetX(), properties.GetShadowOffsetY());
165 
166     SkRect shadowRect = skPath.getBounds();
167     if (properties.shadow_->GetHardwareAcceleration()) {
168         if (properties.GetShadowElevation() <= 0.f) {
169             return;
170         }
171         float elevation = properties.GetShadowElevation() + DEFAULT_TRANSLATION_Z;
172 
173         float userTransRatio = (elevation != DEFAULT_LIGHT_HEIGHT) ?
174             elevation / (DEFAULT_LIGHT_HEIGHT - elevation) : MAX_TRANS_RATIO;
175         float transRatio = std::max(MIN_TRANS_RATIO, std::min(userTransRatio, MAX_TRANS_RATIO));
176 
177         float userSpotRatio = (elevation != DEFAULT_LIGHT_HEIGHT) ?
178             DEFAULT_LIGHT_HEIGHT / (DEFAULT_LIGHT_HEIGHT - elevation) : MAX_SPOT_RATIO;
179         float spotRatio = std::max(MIN_SPOT_RATIO, std::min(userSpotRatio, MAX_SPOT_RATIO));
180 
181         SkRect ambientRect = skPath.getBounds();
182         SkRect spotRect = SkRect::MakeLTRB(ambientRect.left() * spotRatio, ambientRect.top() * spotRatio,
183             ambientRect.right() * spotRatio, ambientRect.bottom() * spotRatio);
184         spotRect.offset(-transRatio * DEFAULT_LIGHT_POSITION_X, -transRatio * DEFAULT_LIGHT_POSITION_Y);
185         spotRect.outset(transRatio * DEFAULT_LIGHT_RADIUS, transRatio * DEFAULT_LIGHT_RADIUS);
186 
187         shadowRect = ambientRect;
188         float ambientBlur = std::min(elevation * 0.5f, MAX_AMBIENT_RADIUS);
189         shadowRect.outset(ambientBlur, ambientBlur);
190         shadowRect.join(spotRect);
191         shadowRect.outset(1, 1);
192     } else {
193         SkPaint paint;
194         paint.setAntiAlias(true);
195         paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, properties.GetShadowRadius()));
196         if (paint.canComputeFastBounds()) {
197             paint.computeFastBounds(shadowRect, &shadowRect);
198         }
199     }
200 
201     auto geoPtr = std::static_pointer_cast<RSObjAbsGeometry>(properties.GetBoundsGeometry());
202     SkMatrix matrix = geoPtr ? geoPtr->GetAbsMatrix() : SkMatrix::I();
203     matrix.mapRect(&shadowRect);
204 
205     dirtyShadow.left_ = shadowRect.left();
206     dirtyShadow.top_ = shadowRect.top();
207     dirtyShadow.width_ = shadowRect.width();
208     dirtyShadow.height_ = shadowRect.height();
209 }
210 
DrawShadow(const RSProperties & properties,RSPaintFilterCanvas & canvas,const RRect * rrect)211 void RSPropertiesPainter::DrawShadow(const RSProperties& properties, RSPaintFilterCanvas& canvas, const RRect* rrect)
212 {
213     // skip shadow if not valid or cache is enabled
214     if (!properties.IsShadowValid() || canvas.isCacheEnabled()) {
215         return;
216     }
217     SkAutoCanvasRestore acr(&canvas, true);
218     SkPath skPath;
219     if (properties.GetShadowPath() && !properties.GetShadowPath()->GetSkiaPath().isEmpty()) {
220         skPath = properties.GetShadowPath()->GetSkiaPath();
221         canvas.clipPath(skPath, SkClipOp::kDifference, true);
222     } else if (properties.GetClipBounds()) {
223         skPath = properties.GetClipBounds()->GetSkiaPath();
224         canvas.clipPath(skPath, SkClipOp::kDifference, true);
225     } else {
226         if (rrect != nullptr) {
227             skPath.addRRect(RRect2SkRRect(*rrect));
228             canvas.clipRRect(RRect2SkRRect(*rrect), SkClipOp::kDifference, true);
229         } else {
230             skPath.addRRect(RRect2SkRRect(properties.GetRRect()));
231             canvas.clipRRect(RRect2SkRRect(properties.GetRRect()), SkClipOp::kDifference, true);
232         }
233     }
234     skPath.offset(properties.GetShadowOffsetX(), properties.GetShadowOffsetY());
235     Color spotColor = properties.GetShadowColor();
236     if (properties.shadow_->GetHardwareAcceleration()) {
237         if (properties.GetShadowElevation() <= 0.f) {
238             return;
239         }
240         SkPoint3 planeParams = { 0.0f, 0.0f, properties.GetShadowElevation() };
241         SkPoint3 lightPos = { canvas.getTotalMatrix().getTranslateX() + skPath.getBounds().centerX(),
242             canvas.getTotalMatrix().getTranslateY() + skPath.getBounds().centerY(), DEFAULT_LIGHT_HEIGHT };
243         Color ambientColor = Color::FromArgbInt(DEFAULT_AMBIENT_COLOR);
244         ambientColor.MultiplyAlpha(canvas.GetAlpha());
245         spotColor.MultiplyAlpha(canvas.GetAlpha());
246         SkShadowUtils::DrawShadow(&canvas, skPath, planeParams, lightPos, DEFAULT_LIGHT_RADIUS,
247             ambientColor.AsArgbInt(), spotColor.AsArgbInt(), SkShadowFlags::kTransparentOccluder_ShadowFlag);
248     } else {
249         SkPaint paint;
250         paint.setColor(spotColor.AsArgbInt());
251         paint.setAntiAlias(true);
252         paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, properties.GetShadowRadius()));
253         canvas.drawPath(skPath, paint);
254     }
255 }
256 
DrawFilter(const RSProperties & properties,RSPaintFilterCanvas & canvas,std::shared_ptr<RSSkiaFilter> & filter,const std::unique_ptr<SkRect> & rect,SkSurface * skSurface)257 void RSPropertiesPainter::DrawFilter(const RSProperties& properties, RSPaintFilterCanvas& canvas,
258     std::shared_ptr<RSSkiaFilter>& filter, const std::unique_ptr<SkRect>& rect, SkSurface* skSurface)
259 {
260     g_blurCnt++;
261     SkAutoCanvasRestore acr(&canvas, true);
262     if (rect != nullptr) {
263         canvas.clipRect((*rect), true);
264     } else if (properties.GetClipBounds() != nullptr) {
265         canvas.clipPath(properties.GetClipBounds()->GetSkiaPath(), true);
266     } else {
267         canvas.clipRRect(RRect2SkRRect(properties.GetRRect()), true);
268     }
269     auto paint = filter->GetPaint();
270     if (skSurface == nullptr) {
271         ROSEN_LOGD("RSPropertiesPainter::DrawFilter skSurface null");
272         SkCanvas::SaveLayerRec slr(nullptr, &paint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
273         canvas.saveLayer(slr);
274         filter->PostProcess(canvas);
275         return;
276     }
277 
278     // canvas draw by snapshot instead of SaveLayer, since the blur layer moves while using saveLayer
279     auto imageSnapshot = skSurface->makeImageSnapshot(canvas.getDeviceClipBounds());
280     if (imageSnapshot == nullptr) {
281         ROSEN_LOGE("RSPropertiesPainter::DrawFilter image null");
282         return;
283     }
284 
285     filter->PreProcess(imageSnapshot);
286     auto clipBounds = SkRect::Make(canvas.getDeviceClipBounds());
287     canvas.resetMatrix();
288     auto visibleRect = canvas.GetVisibleRect();
289     if (visibleRect.intersect(clipBounds)) {
290         // the snapshot only contains the clip region, so we need to offset the src rect
291         canvas.drawImageRect(
292             imageSnapshot.get(), visibleRect.makeOffset(-clipBounds.left(), -clipBounds.top()), visibleRect, &paint);
293     } else {
294         // the snapshot only contains the clip region, so we need to offset the src rect
295         canvas.drawImageRect(
296             imageSnapshot.get(), clipBounds.makeOffset(-clipBounds.left(), -clipBounds.top()), clipBounds, &paint);
297     }
298     filter->PostProcess(canvas);
299 }
300 
CalcAverageColor(sk_sp<SkImage> imageSnapshot)301 SkColor RSPropertiesPainter::CalcAverageColor(sk_sp<SkImage> imageSnapshot)
302 {
303     // create a 1x1 SkPixmap
304     uint32_t pixel[1] = { 0 };
305     auto single_pixel_info = SkImageInfo::MakeN32Premul(1, 1);
306     SkPixmap single_pixel(single_pixel_info, pixel, single_pixel_info.bytesPerPixel());
307 
308     // resize snapshot to 1x1 to calculate average color
309     // kMedium_SkFilterQuality will do bilerp + mipmaps for down-scaling, we can easily get average color
310     imageSnapshot->scalePixels(single_pixel, SkFilterQuality::kMedium_SkFilterQuality);
311 
312     // convert color format and return average color
313     return SkColor4f::FromBytes_RGBA(pixel[0]).toSkColor();
314 }
315 
GetAndResetBlurCnt()316 int RSPropertiesPainter::GetAndResetBlurCnt()
317 {
318     auto blurCnt = g_blurCnt;
319     g_blurCnt = 0;
320     return blurCnt;
321 }
322 
DrawBackground(const RSProperties & properties,RSPaintFilterCanvas & canvas)323 void RSPropertiesPainter::DrawBackground(const RSProperties& properties, RSPaintFilterCanvas& canvas)
324 {
325     DrawShadow(properties, canvas);
326     // only disable antialias when background is rect and g_forceBgAntiAlias is true
327     bool antiAlias = g_forceBgAntiAlias || !properties.GetCornerRadius().IsZero();
328     // clip
329     if (properties.GetClipBounds() != nullptr) {
330         canvas.clipPath(properties.GetClipBounds()->GetSkiaPath(), antiAlias);
331     } else if (properties.GetClipToBounds()) {
332         canvas.clipRRect(RRect2SkRRect(properties.GetRRect()), antiAlias);
333     }
334     // paint backgroundColor
335     SkPaint paint;
336     paint.setAntiAlias(antiAlias);
337     canvas.save();
338     auto bgColor = properties.GetBackgroundColor();
339     if (bgColor != RgbPalette::Transparent()) {
340         paint.setColor(bgColor.AsArgbInt());
341         canvas.drawRRect(RRect2SkRRect(properties.GetRRect()), paint);
342     } else if (const auto& bgImage = properties.GetBgImage()) {
343         canvas.clipRRect(RRect2SkRRect(properties.GetRRect()), antiAlias);
344         auto boundsRect = Rect2SkRect(properties.GetBoundsRect());
345         bgImage->SetDstRect(properties.GetBgImageRect());
346         bgImage->CanvasDrawImage(canvas, boundsRect, paint, true);
347     } else if (const auto& bgShader = properties.GetBackgroundShader()) {
348         canvas.clipRRect(RRect2SkRRect(properties.GetRRect()), antiAlias);
349         paint.setShader(bgShader->GetSkShader());
350         canvas.drawPaint(paint);
351     }
352     canvas.restore();
353 }
354 
SetBgAntiAlias(bool forceBgAntiAlias)355 void RSPropertiesPainter::SetBgAntiAlias(bool forceBgAntiAlias)
356 {
357     g_forceBgAntiAlias = forceBgAntiAlias;
358 }
359 
GetBgAntiAlias()360 bool RSPropertiesPainter::GetBgAntiAlias()
361 {
362     return g_forceBgAntiAlias;
363 }
364 
DrawFrame(const RSProperties & properties,RSPaintFilterCanvas & canvas,DrawCmdListPtr & cmds)365 void RSPropertiesPainter::DrawFrame(const RSProperties& properties, RSPaintFilterCanvas& canvas, DrawCmdListPtr& cmds)
366 {
367     if (cmds == nullptr) {
368         return;
369     }
370     SkMatrix mat;
371     if (GetGravityMatrix(
372             properties.GetFrameGravity(), properties.GetFrameRect(), cmds->GetWidth(), cmds->GetHeight(), mat)) {
373         canvas.concat(mat);
374     }
375     auto frameRect = Rect2SkRect(properties.GetFrameRect());
376     // Generate or clear cache on demand
377     if (canvas.isCacheEnabled()) {
378         cmds->GenerateCache(canvas.GetSurface());
379     } else {
380         cmds->ClearCache();
381     }
382     cmds->Playback(canvas, &frameRect);
383 }
384 
DrawBorder(const RSProperties & properties,SkCanvas & canvas)385 void RSPropertiesPainter::DrawBorder(const RSProperties& properties, SkCanvas& canvas)
386 {
387     auto border = properties.GetBorder();
388     if (!border || !border->HasBorder()) {
389         return;
390     }
391     SkPaint paint;
392     paint.setAntiAlias(true);
393     if (properties.GetCornerRadius().IsZero() && border->ApplyFourLine(paint)) {
394         RectF rect = properties.GetBoundsRect();
395         border->PaintFourLine(canvas, paint, rect);
396     } else if (border->ApplyFillStyle(paint)) {
397         canvas.drawDRRect(RRect2SkRRect(properties.GetRRect()), RRect2SkRRect(properties.GetInnerRRect()), paint);
398     } else if (border->ApplyPathStyle(paint)) {
399         auto borderWidth = border->GetWidth();
400         RRect rrect = properties.GetRRect();
401         rrect.rect_.width_ -= borderWidth;
402         rrect.rect_.height_ -= borderWidth;
403         rrect.rect_.Move(borderWidth / PARAM_DOUBLE, borderWidth / PARAM_DOUBLE);
404         SkPath borderPath;
405         borderPath.addRRect(RRect2SkRRect(rrect));
406         canvas.drawPath(borderPath, paint);
407     } else {
408         SkAutoCanvasRestore acr(&canvas, true);
409         canvas.clipRRect(RRect2SkRRect(properties.GetInnerRRect()), SkClipOp::kDifference, true);
410         SkRRect rrect = RRect2SkRRect(properties.GetRRect());
411         paint.setStyle(SkPaint::Style::kStroke_Style);
412         border->PaintTopPath(canvas, paint, rrect);
413         border->PaintRightPath(canvas, paint, rrect);
414         border->PaintBottomPath(canvas, paint, rrect);
415         border->PaintLeftPath(canvas, paint, rrect);
416     }
417 }
418 
DrawForegroundColor(const RSProperties & properties,SkCanvas & canvas)419 void RSPropertiesPainter::DrawForegroundColor(const RSProperties& properties, SkCanvas& canvas)
420 {
421     auto bgColor = properties.GetForegroundColor();
422     if (bgColor == RgbPalette::Transparent()) {
423         return;
424     }
425     // clip
426     if (properties.GetClipBounds() != nullptr) {
427         canvas.clipPath(properties.GetClipBounds()->GetSkiaPath(), true);
428     } else if (properties.GetClipToBounds()) {
429         canvas.clipRect(Rect2SkRect(properties.GetBoundsRect()), true);
430     }
431 
432     SkPaint paint;
433     paint.setColor(bgColor.AsArgbInt());
434     paint.setAntiAlias(true);
435     canvas.drawRRect(RRect2SkRRect(properties.GetRRect()), paint);
436 }
437 
DrawMask(const RSProperties & properties,SkCanvas & canvas,SkRect maskBounds)438 void RSPropertiesPainter::DrawMask(const RSProperties& properties, SkCanvas& canvas, SkRect maskBounds)
439 {
440     std::shared_ptr<RSMask> mask = properties.GetMask();
441     if (mask == nullptr) {
442         return;
443     }
444     if (mask->IsSvgMask() && !mask->GetSvgDom() && !mask->GetSvgPicture()) {
445         ROSEN_LOGD("RSPropertiesPainter::DrawMask not has Svg Mask property");
446         return;
447     }
448 
449     canvas.save();
450     canvas.saveLayer(maskBounds, nullptr);
451     int tmpLayer = canvas.getSaveCount();
452 
453     SkPaint maskfilter;
454     auto filter = SkColorFilters::Compose(SkLumaColorFilter::Make(), SkColorFilters::SRGBToLinearGamma());
455     maskfilter.setColorFilter(filter);
456     canvas.saveLayer(maskBounds, &maskfilter);
457     if (mask->IsSvgMask()) {
458         SkAutoCanvasRestore maskSave(&canvas, true);
459         canvas.translate(maskBounds.fLeft + mask->GetSvgX(), maskBounds.fTop + mask->GetSvgY());
460         canvas.scale(mask->GetScaleX(), mask->GetScaleY());
461         if (mask->GetSvgDom()) {
462             mask->GetSvgDom()->render(&canvas);
463         } else if (mask->GetSvgPicture()) {
464             canvas.drawPicture(mask->GetSvgPicture());
465         }
466     } else if (mask->IsGradientMask()) {
467         SkAutoCanvasRestore maskSave(&canvas, true);
468         canvas.translate(maskBounds.fLeft, maskBounds.fTop);
469         SkRect skRect = SkRect::MakeIWH(maskBounds.fRight - maskBounds.fLeft, maskBounds.fBottom - maskBounds.fTop);
470         canvas.drawRect(skRect, mask->GetMaskPaint());
471     } else if (mask->IsPathMask()) {
472         SkAutoCanvasRestore maskSave(&canvas, true);
473         canvas.translate(maskBounds.fLeft, maskBounds.fTop);
474         canvas.drawPath(mask->GetMaskPath(), mask->GetMaskPaint());
475     }
476 
477     // back to mask layer
478     canvas.restoreToCount(tmpLayer);
479     // create content layer
480     SkPaint maskPaint;
481     maskPaint.setBlendMode(SkBlendMode::kSrcIn);
482     canvas.saveLayer(maskBounds, &maskPaint);
483     canvas.clipRect(maskBounds, true);
484 }
485 
DrawMask(const RSProperties & properties,SkCanvas & canvas)486 void RSPropertiesPainter::DrawMask(const RSProperties& properties, SkCanvas& canvas)
487 {
488     SkRect maskBounds = Rect2SkRect(properties.GetBoundsRect());
489     DrawMask(properties, canvas, maskBounds);
490 }
491 } // namespace Rosen
492 } // namespace OHOS
493