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