Flutter Engine
 
Loading...
Searching...
No Matches
dl_sk_dispatcher.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <cstdint>
6
8
16
17#include "third_party/skia/include/effects/SkDashPathEffect.h"
18#include "third_party/skia/include/utils/SkShadowUtils.h"
19
20namespace flutter {
21
22const SkPaint* DlSkCanvasDispatcher::safe_paint(bool use_attributes) {
23 if (use_attributes) {
24 // The accumulated SkPaint object will already have incorporated
25 // any attribute overrides.
26 // Any rendering operation that uses an optional paint will ignore
27 // the shader in the paint so we inform that |paint()| method so
28 // that it can set the dither flag appropriately.
29 return &paint(false);
30 } else if (has_opacity()) {
31 temp_paint_.setAlphaf(opacity());
32 return &temp_paint_;
33 } else {
34 return nullptr;
35 }
36}
37
39 canvas_->save();
40 // save has no impact on attributes, but it needs to register a record
41 // on the restore stack so that the eventual call to restore() will
42 // know what to do at that time. We could annotate the restore record
43 // with a flag that the record came from a save call, but it is simpler
44 // to just pass in the current opacity value as the value to be used by
45 // the children and let the utility calls notice that it didn't change.
47}
49 canvas_->restore();
51}
53 const SaveLayerOptions options,
54 const DlImageFilter* backdrop,
55 std::optional<int64_t> backdrop_id) {
56 if (!options.content_is_clipped() && options.can_distribute_opacity() &&
57 backdrop == nullptr) {
58 // We know that:
59 // - no bounds is needed for clipping here
60 // - no backdrop filter is used to initialize the layer
61 // - the current attributes only have an alpha
62 // - the children are compatible with individually rendering with
63 // an inherited opacity
64 // Therefore we can just use a save instead of a saveLayer and pass the
65 // intended opacity to the children.
66 canvas_->save();
67 // If the saveLayer does not use attributes, the children should continue
68 // to render with the inherited opacity unmodified. If attributes are to
69 // be applied, the children should render with the combination of the
70 // inherited opacity combined with the alpha from the current color.
72 : opacity());
73 } else {
74 TRACE_EVENT0("flutter", "Canvas::saveLayer");
75 const SkPaint* paint = safe_paint(options.renders_with_attributes());
76 const sk_sp<SkImageFilter> sk_backdrop = ToSk(backdrop);
77 const SkRect* sl_bounds =
78 options.bounds_from_caller() ? &ToSkRect(bounds) : nullptr;
79 SkCanvas::SaveLayerRec params(sl_bounds, paint, sk_backdrop.get(), 0);
80 if (sk_backdrop && backdrop->asBlur()) {
81 params.fBackdropTileMode = ToSk(backdrop->asBlur()->tile_mode());
82 }
83 canvas_->saveLayer(params);
84 // saveLayer will apply the current opacity on behalf of the children
85 // so they will inherit an opaque opacity.
86 save_opacity(SK_Scalar1);
87 }
88}
89
91 canvas_->translate(tx, ty);
92}
94 canvas_->scale(sx, sy);
95}
97 canvas_->rotate(degrees);
98}
100 canvas_->skew(sx, sy);
101}
102// clang-format off
103// 2x3 2D affine subset of a 4x4 transform in row major order
105 DlScalar mxx, DlScalar mxy, DlScalar mxt,
106 DlScalar myx, DlScalar myy, DlScalar myt) {
107 // Internally concat(SkMatrix) gets redirected to concat(SkM44)
108 // so we just jump directly to the SkM44 version
109 canvas_->concat(SkM44(mxx, mxy, 0, mxt,
110 myx, myy, 0, myt,
111 0, 0, 1, 0,
112 0, 0, 0, 1));
113}
114// full 4x4 transform in row major order
116 DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt,
117 DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt,
118 DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt,
119 DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt) {
120 canvas_->concat(SkM44(mxx, mxy, mxz, mxt,
121 myx, myy, myz, myt,
122 mzx, mzy, mzz, mzt,
123 mwx, mwy, mwz, mwt));
124}
125// clang-format on
127 canvas_->setMatrix(original_transform_);
128}
129
131 DlClipOp clip_op,
132 bool is_aa) {
133 canvas_->clipRect(ToSkRect(rect), ToSk(clip_op), is_aa);
134}
136 DlClipOp clip_op,
137 bool is_aa) {
138 canvas_->clipRRect(SkRRect::MakeOval(ToSkRect(bounds)), ToSk(clip_op), is_aa);
139}
141 DlClipOp clip_op,
142 bool is_aa) {
143 canvas_->clipRRect(ToSkRRect(rrect), ToSk(clip_op), is_aa);
144}
146 DlClipOp clip_op,
147 bool is_aa) {
148 // Skia doesn't support round superellipse, thus fall back to round rectangle.
149 canvas_->clipRRect(ToApproximateSkRRect(rse), ToSk(clip_op), is_aa);
150}
152 DlClipOp clip_op,
153 bool is_aa) {
154 path.WillRenderSkPath();
155 canvas_->clipPath(path.GetSkPath(), ToSk(clip_op), is_aa);
156}
157
159 const SkPaint& sk_paint = paint();
160 SkImageFilter* filter = sk_paint.getImageFilter();
161 if (filter && !filter->asColorFilter(nullptr)) {
162 // drawPaint does an implicit saveLayer if an SkImageFilter is
163 // present that cannot be replaced by an SkColorFilter.
164 TRACE_EVENT0("flutter", "Canvas::saveLayer");
165 }
166 canvas_->drawPaint(sk_paint);
167}
169 // SkCanvas::drawColor(SkColor) does the following conversion anyway
170 // We do it here manually to increase precision on applying opacity
171 SkColor4f color4f = ToSkColor4f(color);
172 color4f.fA *= opacity();
173 canvas_->drawColor(color4f, ToSk(mode));
174}
176 canvas_->drawLine(ToSkPoint(p0), ToSkPoint(p1), paint());
177}
179 const DlPoint& p1,
180 DlScalar on_length,
181 DlScalar off_length) {
182 SkPaint dash_paint = paint();
183 SkScalar intervals[] = {on_length, off_length};
184 dash_paint.setPathEffect(SkDashPathEffect::Make({intervals, 2}, 0.0f));
185 canvas_->drawLine(ToSkPoint(p0), ToSkPoint(p1), dash_paint);
186}
188 canvas_->drawRect(ToSkRect(rect), paint());
189}
191 canvas_->drawOval(ToSkRect(bounds), paint());
192}
194 canvas_->drawCircle(ToSkPoint(center), radius, paint());
195}
197 canvas_->drawRRect(ToSkRRect(rrect), paint());
198}
200 const DlRoundRect& inner) {
201 canvas_->drawDRRect(ToSkRRect(outer), ToSkRRect(inner), paint());
202}
204 const DlRoundSuperellipse& rse) {
205 // Skia doesn't support round superellipse, thus fall back to round rectangle.
206 canvas_->drawRRect(ToApproximateSkRRect(rse), paint());
207}
209 path.WillRenderSkPath();
210 canvas_->drawPath(path.GetSkPath(), paint());
211}
213 DlScalar start,
214 DlScalar sweep,
215 bool useCenter) {
216 canvas_->drawArc(ToSkRect(bounds), start, sweep, useCenter, paint());
217}
219 uint32_t count,
220 const DlPoint pts[]) {
221 canvas_->drawPoints(ToSk(mode), {ToSkPoints(pts), count}, paint());
222}
224 const std::shared_ptr<DlVertices>& vertices,
225 DlBlendMode mode) {
226 canvas_->drawVertices(ToSk(vertices), ToSk(mode), paint());
227}
228void DlSkCanvasDispatcher::drawImage(const sk_sp<DlImage> image,
229 const DlPoint& point,
230 DlImageSampling sampling,
231 bool render_with_attributes) {
232 canvas_->drawImage(image ? image->skia_image() : nullptr, point.x, point.y,
233 ToSk(sampling), safe_paint(render_with_attributes));
234}
236 const DlRect& src,
237 const DlRect& dst,
238 DlImageSampling sampling,
239 bool render_with_attributes,
240 DlSrcRectConstraint constraint) {
241 canvas_->drawImageRect(image ? image->skia_image() : nullptr, ToSkRect(src),
242 ToSkRect(dst), ToSk(sampling),
243 safe_paint(render_with_attributes), ToSk(constraint));
244}
246 const DlIRect& center,
247 const DlRect& dst,
248 DlFilterMode filter,
249 bool render_with_attributes) {
250 if (!image) {
251 return;
252 }
253 auto skia_image = image->skia_image();
254 if (!skia_image) {
255 return;
256 }
257 canvas_->drawImageNine(skia_image.get(), ToSkIRect(center), ToSkRect(dst),
258 ToSk(filter), safe_paint(render_with_attributes));
259}
260void DlSkCanvasDispatcher::drawAtlas(const sk_sp<DlImage> atlas,
261 const DlRSTransform xform[],
262 const DlRect tex[],
263 const DlColor colors[],
264 int count,
265 DlBlendMode mode,
266 DlImageSampling sampling,
267 const DlRect* cullRect,
268 bool render_with_attributes) {
269 if (!atlas) {
270 return;
271 }
272 auto skia_atlas = atlas->skia_image();
273 if (!skia_atlas) {
274 return;
275 }
276 std::vector<SkColor> sk_colors;
277 if (colors != nullptr) {
278 sk_colors.reserve(count);
279 for (int i = 0; i < count; ++i) {
280 sk_colors.push_back(colors[i].argb());
281 }
282 }
283 SkSpan<const SkColor> colorSpan;
284 if (!colors) {
285 colorSpan = {nullptr, 0};
286 } else {
287 colorSpan = {sk_colors.data(), count};
288 }
289 canvas_->drawAtlas(skia_atlas.get(), {ToSk(xform), count},
290 {ToSkRects(tex), count}, colorSpan, ToSk(mode),
291 ToSk(sampling), ToSkRect(cullRect),
292 safe_paint(render_with_attributes));
293}
295 const sk_sp<DisplayList> display_list,
296 DlScalar opacity) {
297 const int restore_count = canvas_->getSaveCount();
298
299 // Compute combined opacity and figure out whether we can apply it
300 // during dispatch or if we need a saveLayer.
301 SkScalar combined_opacity = opacity * this->opacity();
302 if (combined_opacity < SK_Scalar1 &&
303 !display_list->can_apply_group_opacity()) {
304 TRACE_EVENT0("flutter", "Canvas::saveLayer");
305 canvas_->saveLayerAlphaf(ToSkRect(&display_list->GetBounds()),
307 combined_opacity = SK_Scalar1;
308 } else {
309 canvas_->save();
310 }
311
312 // Create a new CanvasDispatcher to isolate the actions of the
313 // display_list from the current environment.
314 DlSkCanvasDispatcher dispatcher(canvas_, combined_opacity);
315 if (display_list->rtree()) {
316 display_list->Dispatch(dispatcher, ToDlRect(canvas_->getLocalClipBounds()));
317 } else {
318 display_list->Dispatch(dispatcher);
319 }
320
321 // Restore canvas state to what it was before dispatching.
322 canvas_->restoreToCount(restore_count);
323}
324void DlSkCanvasDispatcher::drawText(const std::shared_ptr<DlText>& text,
325 DlScalar x,
326 DlScalar y) {
327 auto blob = text->GetTextBlob();
328 FML_CHECK(blob) << "Impeller DlText cannot be drawn to a Skia canvas.";
329 canvas_->drawTextBlob(blob, x, y, paint());
330}
331
333 const SkPath& path,
334 DlColor color,
335 float elevation,
336 bool transparentOccluder,
337 DlScalar dpr) {
338 const SkScalar kAmbientAlpha = 0.039f;
339 const SkScalar kSpotAlpha = 0.25f;
340
341 uint32_t flags = transparentOccluder
342 ? SkShadowFlags::kTransparentOccluder_ShadowFlag
343 : SkShadowFlags::kNone_ShadowFlag;
344 flags |= SkShadowFlags::kDirectionalLight_ShadowFlag;
345 SkColor in_ambient =
346 SkColorSetA(ToSkColor(color), kAmbientAlpha * color.getAlpha());
347 SkColor in_spot =
348 SkColorSetA(ToSkColor(color), kSpotAlpha * color.getAlpha());
349 SkColor ambient_color, spot_color;
350 SkShadowUtils::ComputeTonalColors(in_ambient, in_spot, &ambient_color,
351 &spot_color);
352 SkShadowUtils::DrawShadow(
353 canvas, path, SkPoint3::Make(0, 0, dpr * elevation),
354 SkPoint3::Make(0, -1, 1),
356 ambient_color, spot_color, flags);
357}
358
360 const DlColor color,
361 const DlScalar elevation,
362 bool transparent_occluder,
363 DlScalar dpr) {
364 path.WillRenderSkPath();
365 DrawShadow(canvas_, path.GetSkPath(), color, elevation, transparent_occluder,
366 dpr);
367}
368
369} // namespace flutter
static constexpr DlScalar kShadowLightHeight
Definition dl_canvas.h:215
static constexpr DlScalar kShadowLightRadius
Definition dl_canvas.h:216
virtual const DlBlurImageFilter * asBlur() const
Backend implementation of |DlOpReceiver| for |SkCanvas|.
void transform2DAffine(DlScalar mxx, DlScalar mxy, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myt) override
void drawImage(const sk_sp< DlImage > image, const DlPoint &point, DlImageSampling sampling, bool render_with_attributes) override
void transformFullPerspective(DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt, DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt, DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt) override
void drawArc(const DlRect &bounds, DlScalar start, DlScalar sweep, bool useCenter) override
void drawImageRect(const sk_sp< DlImage > image, const DlRect &src, const DlRect &dst, DlImageSampling sampling, bool render_with_attributes, DlSrcRectConstraint constraint) override
void drawDashedLine(const DlPoint &p0, const DlPoint &p1, DlScalar on_length, DlScalar off_length) override
void drawVertices(const std::shared_ptr< DlVertices > &vertices, DlBlendMode mode) override
const SkPaint * safe_paint(bool use_attributes)
void saveLayer(const DlRect &bounds, const SaveLayerOptions options, const DlImageFilter *backdrop, std::optional< int64_t > backdrop_id) override
void drawRect(const DlRect &rect) override
void clipRect(const DlRect &rect, DlClipOp clip_op, bool is_aa) override
void rotate(DlScalar degrees) override
void drawText(const std::shared_ptr< DlText > &text, DlScalar x, DlScalar y) override
void drawCircle(const DlPoint &center, DlScalar radius) override
void drawAtlas(const sk_sp< DlImage > atlas, const DlRSTransform xform[], const DlRect tex[], const DlColor colors[], int count, DlBlendMode mode, DlImageSampling sampling, const DlRect *cullRect, bool render_with_attributes) override
void drawLine(const DlPoint &p0, const DlPoint &p1) override
void drawImageNine(const sk_sp< DlImage > image, const DlIRect &center, const DlRect &dst, DlFilterMode filter, bool render_with_attributes) override
void drawColor(DlColor color, DlBlendMode mode) override
void drawPoints(DlPointMode mode, uint32_t count, const DlPoint pts[]) override
void skew(DlScalar sx, DlScalar sy) override
void drawShadow(const DlPath &path, const DlColor color, const DlScalar elevation, bool transparent_occluder, DlScalar dpr) override
static void DrawShadow(SkCanvas *canvas, const SkPath &path, DlColor color, float elevation, bool transparentOccluder, DlScalar dpr)
void drawRoundSuperellipse(const DlRoundSuperellipse &rse) override
void clipOval(const DlRect &bounds, DlClipOp clip_op, bool is_aa) override
void drawRoundRect(const DlRoundRect &rrect) override
void drawPath(const DlPath &path) override
void drawOval(const DlRect &bounds) override
void drawDisplayList(const sk_sp< DisplayList > display_list, DlScalar opacity) override
void clipRoundRect(const DlRoundRect &rrect, DlClipOp clip_op, bool is_aa) override
void scale(DlScalar sx, DlScalar sy) override
void clipPath(const DlPath &path, DlClipOp clip_op, bool is_aa) override
void clipRoundSuperellipse(const DlRoundSuperellipse &rse, DlClipOp clip_op, bool is_aa) override
void translate(DlScalar tx, DlScalar ty) override
void drawDiffRoundRect(const DlRoundRect &outer, const DlRoundRect &inner) override
const SkPaint & paint(bool uses_shader=true)
void save_opacity(SkScalar opacity_for_children)
bool content_is_clipped() const
bool renders_with_attributes() const
bool bounds_from_caller() const
bool can_distribute_opacity() const
int32_t x
const EmbeddedViewParams * params
FlutterVulkanImage * image
#define FML_CHECK(condition)
Definition logging.h:104
std::u16string text
double y
impeller::Scalar DlScalar
SkPaint ToSk(const DlPaint &paint)
const SkPoint & ToSkPoint(const DlPoint &point)
const SkIRect & ToSkIRect(const DlIRect &rect)
SkColor ToSkColor(DlColor color)
const SkRRect ToApproximateSkRRect(const DlRoundSuperellipse &rse)
DlPointMode
Definition dl_types.h:15
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switch_defs.h:52
SkColor4f ToSkColor4f(DlColor color)
const SkPoint * ToSkPoints(const DlPoint *points)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
const SkRRect ToSkRRect(const DlRoundRect &round_rect)
const DlRect & ToDlRect(const SkRect &rect)
const SkRect & ToSkRect(const DlRect &rect)
DlSrcRectConstraint
Definition dl_types.h:21
BlendMode
Definition color.h:58
int getAlpha() const
Definition dl_color.h:102
const size_t start
#define TRACE_EVENT0(category_group, name)