Flutter Engine
canvas.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 "flutter/lib/ui/painting/canvas.h"
6 #include "flutter/lib/ui/painting/image_filter.h"
7 
8 #include <cmath>
9 
10 #include "flutter/flow/layers/physical_shape_layer.h"
11 #include "flutter/lib/ui/painting/image.h"
12 #include "flutter/lib/ui/painting/matrix.h"
13 #include "flutter/lib/ui/ui_dart_state.h"
14 #include "flutter/lib/ui/window/platform_configuration.h"
15 #include "flutter/lib/ui/window/window.h"
16 #include "third_party/skia/include/core/SkBitmap.h"
17 #include "third_party/skia/include/core/SkCanvas.h"
18 #include "third_party/skia/include/core/SkRSXform.h"
23 
24 using tonic::ToDart;
25 
26 namespace flutter {
27 
28 static void Canvas_constructor(Dart_NativeArguments args) {
31 }
32 
34 
35 #define FOR_EACH_BINDING(V) \
36  V(Canvas, save) \
37  V(Canvas, saveLayerWithoutBounds) \
38  V(Canvas, saveLayer) \
39  V(Canvas, restore) \
40  V(Canvas, getSaveCount) \
41  V(Canvas, translate) \
42  V(Canvas, scale) \
43  V(Canvas, rotate) \
44  V(Canvas, skew) \
45  V(Canvas, transform) \
46  V(Canvas, clipRect) \
47  V(Canvas, clipRRect) \
48  V(Canvas, clipPath) \
49  V(Canvas, drawColor) \
50  V(Canvas, drawLine) \
51  V(Canvas, drawPaint) \
52  V(Canvas, drawRect) \
53  V(Canvas, drawRRect) \
54  V(Canvas, drawDRRect) \
55  V(Canvas, drawOval) \
56  V(Canvas, drawCircle) \
57  V(Canvas, drawArc) \
58  V(Canvas, drawPath) \
59  V(Canvas, drawImage) \
60  V(Canvas, drawImageRect) \
61  V(Canvas, drawImageNine) \
62  V(Canvas, drawPicture) \
63  V(Canvas, drawPoints) \
64  V(Canvas, drawVertices) \
65  V(Canvas, drawAtlas) \
66  V(Canvas, drawShadow)
67 
69 
70 void Canvas::RegisterNatives(tonic::DartLibraryNatives* natives) {
71  natives->Register({{"Canvas_constructor", Canvas_constructor, 6, true},
73 }
74 
76  double left,
77  double top,
78  double right,
79  double bottom) {
80  if (!recorder) {
81  Dart_ThrowException(
82  ToDart("Canvas constructor called with non-genuine PictureRecorder."));
83  return nullptr;
84  }
85  fml::RefPtr<Canvas> canvas = fml::MakeRefCounted<Canvas>(
86  recorder->BeginRecording(SkRect::MakeLTRB(left, top, right, bottom)));
87  recorder->set_canvas(canvas);
88  canvas->display_list_recorder_ = recorder->display_list_recorder();
89  return canvas;
90 }
91 
92 Canvas::Canvas(SkCanvas* canvas) : canvas_(canvas) {}
93 
95 
96 void Canvas::save() {
97  if (!canvas_) {
98  return;
99  }
100  canvas_->save();
101 }
102 
104  const PaintData& paint_data) {
105  if (!canvas_) {
106  return;
107  }
108  canvas_->saveLayer(nullptr, paint.paint());
109 }
110 
111 void Canvas::saveLayer(double left,
112  double top,
113  double right,
114  double bottom,
115  const Paint& paint,
116  const PaintData& paint_data) {
117  if (!canvas_) {
118  return;
119  }
120  SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
121  canvas_->saveLayer(&bounds, paint.paint());
122 }
123 
125  if (!canvas_) {
126  return;
127  }
128  canvas_->restore();
129 }
130 
132  if (!canvas_) {
133  return 0;
134  }
135  return canvas_->getSaveCount();
136 }
137 
138 void Canvas::translate(double dx, double dy) {
139  if (!canvas_) {
140  return;
141  }
142  canvas_->translate(dx, dy);
143 }
144 
145 void Canvas::scale(double sx, double sy) {
146  if (!canvas_) {
147  return;
148  }
149  canvas_->scale(sx, sy);
150 }
151 
152 void Canvas::rotate(double radians) {
153  if (!canvas_) {
154  return;
155  }
156  canvas_->rotate(radians * 180.0 / M_PI);
157 }
158 
159 void Canvas::skew(double sx, double sy) {
160  if (!canvas_) {
161  return;
162  }
163  canvas_->skew(sx, sy);
164 }
165 
166 void Canvas::transform(const tonic::Float64List& matrix4) {
167  if (!canvas_) {
168  return;
169  }
170  canvas_->concat(SkM44(matrix4[0], matrix4[4], matrix4[8], matrix4[12],
171  matrix4[1], matrix4[5], matrix4[9], matrix4[13],
172  matrix4[2], matrix4[6], matrix4[10], matrix4[14],
173  matrix4[3], matrix4[7], matrix4[11], matrix4[15]));
174 }
175 
176 void Canvas::clipRect(double left,
177  double top,
178  double right,
179  double bottom,
180  SkClipOp clipOp,
181  bool doAntiAlias) {
182  if (!canvas_) {
183  return;
184  }
185  canvas_->clipRect(SkRect::MakeLTRB(left, top, right, bottom), clipOp,
186  doAntiAlias);
187 }
188 
189 void Canvas::clipRRect(const RRect& rrect, bool doAntiAlias) {
190  if (!canvas_) {
191  return;
192  }
193  canvas_->clipRRect(rrect.sk_rrect, doAntiAlias);
194 }
195 
196 void Canvas::clipPath(const CanvasPath* path, bool doAntiAlias) {
197  if (!canvas_) {
198  return;
199  }
200  if (!path) {
201  Dart_ThrowException(
202  ToDart("Canvas.clipPath called with non-genuine Path."));
203  return;
204  }
205  canvas_->clipPath(path->path(), doAntiAlias);
206 }
207 
208 void Canvas::drawColor(SkColor color, SkBlendMode blend_mode) {
209  if (!canvas_) {
210  return;
211  }
212  canvas_->drawColor(color, blend_mode);
213 }
214 
215 void Canvas::drawLine(double x1,
216  double y1,
217  double x2,
218  double y2,
219  const Paint& paint,
220  const PaintData& paint_data) {
221  if (!canvas_) {
222  return;
223  }
224  canvas_->drawLine(x1, y1, x2, y2, *paint.paint());
225 }
226 
227 void Canvas::drawPaint(const Paint& paint, const PaintData& paint_data) {
228  if (!canvas_) {
229  return;
230  }
231  canvas_->drawPaint(*paint.paint());
232 }
233 
234 void Canvas::drawRect(double left,
235  double top,
236  double right,
237  double bottom,
238  const Paint& paint,
239  const PaintData& paint_data) {
240  if (!canvas_) {
241  return;
242  }
243  canvas_->drawRect(SkRect::MakeLTRB(left, top, right, bottom), *paint.paint());
244 }
245 
246 void Canvas::drawRRect(const RRect& rrect,
247  const Paint& paint,
248  const PaintData& paint_data) {
249  if (!canvas_) {
250  return;
251  }
252  canvas_->drawRRect(rrect.sk_rrect, *paint.paint());
253 }
254 
255 void Canvas::drawDRRect(const RRect& outer,
256  const RRect& inner,
257  const Paint& paint,
258  const PaintData& paint_data) {
259  if (!canvas_) {
260  return;
261  }
262  canvas_->drawDRRect(outer.sk_rrect, inner.sk_rrect, *paint.paint());
263 }
264 
265 void Canvas::drawOval(double left,
266  double top,
267  double right,
268  double bottom,
269  const Paint& paint,
270  const PaintData& paint_data) {
271  if (!canvas_) {
272  return;
273  }
274  canvas_->drawOval(SkRect::MakeLTRB(left, top, right, bottom), *paint.paint());
275 }
276 
277 void Canvas::drawCircle(double x,
278  double y,
279  double radius,
280  const Paint& paint,
281  const PaintData& paint_data) {
282  if (!canvas_) {
283  return;
284  }
285  canvas_->drawCircle(x, y, radius, *paint.paint());
286 }
287 
288 void Canvas::drawArc(double left,
289  double top,
290  double right,
291  double bottom,
292  double startAngle,
293  double sweepAngle,
294  bool useCenter,
295  const Paint& paint,
296  const PaintData& paint_data) {
297  if (!canvas_) {
298  return;
299  }
300  canvas_->drawArc(SkRect::MakeLTRB(left, top, right, bottom),
301  startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI,
302  useCenter, *paint.paint());
303 }
304 
306  const Paint& paint,
307  const PaintData& paint_data) {
308  if (!canvas_) {
309  return;
310  }
311  if (!path) {
312  Dart_ThrowException(
313  ToDart("Canvas.drawPath called with non-genuine Path."));
314  return;
315  }
316  canvas_->drawPath(path->path(), *paint.paint());
317 }
318 
319 void Canvas::drawImage(const CanvasImage* image,
320  double x,
321  double y,
322  const Paint& paint,
323  const PaintData& paint_data,
324  int filterQualityIndex) {
325  if (!canvas_) {
326  return;
327  }
328  if (!image) {
329  Dart_ThrowException(
330  ToDart("Canvas.drawImage called with non-genuine Image."));
331  return;
332  }
333  auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex);
334  canvas_->drawImage(image->image(), x, y, sampling, paint.paint());
335 }
336 
338  double src_left,
339  double src_top,
340  double src_right,
341  double src_bottom,
342  double dst_left,
343  double dst_top,
344  double dst_right,
345  double dst_bottom,
346  const Paint& paint,
347  const PaintData& paint_data,
348  int filterQualityIndex) {
349  if (!canvas_) {
350  return;
351  }
352  if (!image) {
353  Dart_ThrowException(
354  ToDart("Canvas.drawImageRect called with non-genuine Image."));
355  return;
356  }
357  SkRect src = SkRect::MakeLTRB(src_left, src_top, src_right, src_bottom);
358  SkRect dst = SkRect::MakeLTRB(dst_left, dst_top, dst_right, dst_bottom);
359  auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex);
360  canvas_->drawImageRect(image->image(), src, dst, sampling, paint.paint(),
361  SkCanvas::kFast_SrcRectConstraint);
362 }
363 
365  double center_left,
366  double center_top,
367  double center_right,
368  double center_bottom,
369  double dst_left,
370  double dst_top,
371  double dst_right,
372  double dst_bottom,
373  const Paint& paint,
374  const PaintData& paint_data,
375  int bitmapSamplingIndex) {
376  if (!canvas_) {
377  return;
378  }
379  if (!image) {
380  Dart_ThrowException(
381  ToDart("Canvas.drawImageNine called with non-genuine Image."));
382  return;
383  }
384  SkRect center =
385  SkRect::MakeLTRB(center_left, center_top, center_right, center_bottom);
386  SkIRect icenter;
387  center.round(&icenter);
388  SkRect dst = SkRect::MakeLTRB(dst_left, dst_top, dst_right, dst_bottom);
389  auto filter = ImageFilter::FilterModeFromIndex(bitmapSamplingIndex);
390  if (display_list_recorder_) {
391  // SkCanvas turns a simple 2-rect DrawImageNine operation into a
392  // drawImageLattice operation which has arrays to allocate and
393  // pass along. For simplicity, we will bypass the canvas and ask
394  // the recorder to record our paint attributes and record a much
395  // simpler DrawImageNineOp record directly.
396  display_list_recorder_->RecordPaintAttributes(
398  builder()->drawImageNine(image->image(), icenter, dst, filter, true);
399  } else {
400  canvas_->drawImageNine(image->image().get(), icenter, dst, filter,
401  paint.paint());
402  }
403 }
404 
405 void Canvas::drawPicture(Picture* picture) {
406  if (!canvas_) {
407  return;
408  }
409  if (!picture) {
410  Dart_ThrowException(
411  ToDart("Canvas.drawPicture called with non-genuine Picture."));
412  return;
413  }
414  if (picture->picture()) {
415  canvas_->drawPicture(picture->picture().get());
416  } else if (picture->display_list()) {
417  if (display_list_recorder_) {
418  builder()->drawDisplayList(picture->display_list());
419  } else {
420  picture->display_list()->RenderTo(canvas_);
421  }
422  } else {
423  FML_DCHECK(false);
424  }
425 }
426 
427 void Canvas::drawPoints(const Paint& paint,
428  const PaintData& paint_data,
429  SkCanvas::PointMode point_mode,
430  const tonic::Float32List& points) {
431  if (!canvas_) {
432  return;
433  }
434 
435  static_assert(sizeof(SkPoint) == sizeof(float) * 2,
436  "SkPoint doesn't use floats.");
437 
438  canvas_->drawPoints(point_mode,
439  points.num_elements() / 2, // SkPoints have two floats.
440  reinterpret_cast<const SkPoint*>(points.data()),
441  *paint.paint());
442 }
443 
444 void Canvas::drawVertices(const Vertices* vertices,
445  SkBlendMode blend_mode,
446  const Paint& paint,
447  const PaintData& paint_data) {
448  if (!canvas_) {
449  return;
450  }
451  if (!vertices) {
452  Dart_ThrowException(
453  ToDart("Canvas.drawVertices called with non-genuine Vertices."));
454  return;
455  }
456  canvas_->drawVertices(vertices->vertices(), blend_mode, *paint.paint());
457 }
458 
459 void Canvas::drawAtlas(const Paint& paint,
460  const PaintData& paint_data,
461  int filterQualityIndex,
462  CanvasImage* atlas,
463  const tonic::Float32List& transforms,
464  const tonic::Float32List& rects,
465  const tonic::Int32List& colors,
466  SkBlendMode blend_mode,
467  const tonic::Float32List& cull_rect) {
468  if (!canvas_) {
469  return;
470  }
471  if (!atlas) {
472  Dart_ThrowException(
473  ToDart("Canvas.drawAtlas or Canvas.drawRawAtlas called with "
474  "non-genuine Image."));
475  return;
476  }
477 
478  sk_sp<SkImage> skImage = atlas->image();
479 
480  static_assert(sizeof(SkRSXform) == sizeof(float) * 4,
481  "SkRSXform doesn't use floats.");
482  static_assert(sizeof(SkRect) == sizeof(float) * 4,
483  "SkRect doesn't use floats.");
484 
485  auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex);
486 
487  canvas_->drawAtlas(
488  skImage.get(), reinterpret_cast<const SkRSXform*>(transforms.data()),
489  reinterpret_cast<const SkRect*>(rects.data()),
490  reinterpret_cast<const SkColor*>(colors.data()),
491  rects.num_elements() / 4, // SkRect have four floats.
492  blend_mode, sampling, reinterpret_cast<const SkRect*>(cull_rect.data()),
493  paint.paint());
494 }
495 
497  SkColor color,
498  double elevation,
499  bool transparentOccluder) {
500  if (!path) {
501  Dart_ThrowException(
502  ToDart("Canvas.drawShader called with non-genuine Path."));
503  return;
504  }
505  SkScalar dpr = UIDartState::Current()
507  ->get_window(0)
508  ->viewport_metrics()
510  if (display_list_recorder_) {
511  // The DrawShadow mechanism results in non-public operations to be
512  // performed on the canvas involving an SkDrawShadowRec. Since we
513  // cannot include the header that defines that structure, we cannot
514  // record an operation that it injects into an SkCanvas. To prevent
515  // that situation we bypass the canvas interface and inject the
516  // shadow parameters directly into the underlying DisplayList.
517  // See: https://bugs.chromium.org/p/skia/issues/detail?id=12125
518  builder()->drawShadow(path->path(), color, elevation, transparentOccluder,
519  dpr);
520  } else {
522  canvas_, path->path(), color, elevation, transparentOccluder, dpr);
523  }
524 }
525 
527  canvas_ = nullptr;
528  if (dart_wrapper()) {
530  }
531 }
532 
533 } // namespace flutter
void saveLayer(double left, double top, double right, double bottom, const Paint &paint, const PaintData &paint_data)
Definition: canvas.cc:111
G_BEGIN_DECLS FlValue * args
void drawColor(SkColor color, SkBlendMode blend_mode)
Definition: canvas.cc:208
SkRRect sk_rrect
Definition: rrect.h:16
DEF_SWITCHES_START snapshot asset path
Definition: switches.h:32
void saveLayerWithoutBounds(const Paint &paint, const PaintData &paint_data)
Definition: canvas.cc:103
void skew(double sx, double sy)
Definition: canvas.cc:159
static fml::RefPtr< Canvas > Create(PictureRecorder *recorder, double left, double top, double right, double bottom)
Definition: canvas.cc:75
#define FML_DCHECK(condition)
Definition: logging.h:86
void drawPaint(const Paint &paint, const PaintData &paint_data)
Definition: canvas.cc:227
const sk_sp< SkVertices > & vertices() const
Definition: vertices.h:34
void drawPicture(Picture *picture)
Definition: canvas.cc:405
void drawRRect(const RRect &rrect, const Paint &paint, const PaintData &paint_data)
Definition: canvas.cc:246
void DartCallConstructor(Sig func, Dart_NativeArguments args)
Definition: dart_args.h:218
void transform(const tonic::Float64List &matrix4)
Definition: canvas.cc:166
void drawOval(double left, double top, double right, double bottom, const Paint &paint, const PaintData &paint_data)
Definition: canvas.cc:265
SkCanvas * BeginRecording(SkRect bounds)
#define FOR_EACH_BINDING(V)
Definition: canvas.cc:35
void drawImageNine(const CanvasImage *image, double center_left, double center_top, double center_right, double center_bottom, double dst_left, double dst_top, double dst_right, double dst_bottom, const Paint &paint, const PaintData &paint_data, int bitmapSamplingIndex)
Definition: canvas.cc:364
void Invalidate()
Definition: canvas.cc:526
void drawLine(double x1, double y1, double x2, double y2, const Paint &paint, const PaintData &paint_data)
Definition: canvas.cc:215
void drawPath(const CanvasPath *path, const Paint &paint, const PaintData &paint_data)
Definition: canvas.cc:305
sk_sp< SkPicture > picture() const
Definition: picture.h:34
const SkPaint * paint() const
Definition: paint.h:18
sk_sp< DisplayList > display_list() const
Definition: picture.h:35
#define DART_NATIVE_CALLBACK(CLASS, METHOD)
void clipRect(double left, double top, double right, double bottom, SkClipOp clipOp, bool doAntiAlias=true)
Definition: canvas.cc:176
void clipRRect(const RRect &rrect, bool doAntiAlias=true)
Definition: canvas.cc:189
void save()
Definition: canvas.cc:96
void drawImage(const CanvasImage *image, double x, double y, const Paint &paint, const PaintData &paint_data, int filterQualityIndex)
Definition: canvas.cc:319
SkCanvas * canvas() const
Definition: canvas.h:171
IMPLEMENT_WRAPPERTYPEINFO(ui, Scene)
static SkFilterMode FilterModeFromIndex(int index)
Definition: image_filter.cc:60
void scale(double sx, double sy)
Definition: canvas.cc:145
const SkPath & path() const
Definition: path.h:112
void rotate(double radians)
Definition: canvas.cc:152
void drawDRRect(const RRect &outer, const RRect &inner, const Paint &paint, const PaintData &paint_data)
Definition: canvas.cc:255
static void ThrowIfUIOperationsProhibited()
sk_sp< DisplayListCanvasRecorder > display_list_recorder()
void drawAtlas(const Paint &paint, const PaintData &paint_data, int filterQualityIndex, CanvasImage *atlas, const tonic::Float32List &transforms, const tonic::Float32List &rects, const tonic::Int32List &colors, SkBlendMode blend_mode, const tonic::Float32List &cull_rect)
Definition: canvas.cc:459
PlatformConfiguration * platform_configuration() const
int getSaveCount()
Definition: canvas.cc:131
static SkSamplingOptions SamplingFromIndex(int filterQualityIndex)
Definition: image_filter.cc:50
void drawCircle(double x, double y, double radius, const Paint &paint, const PaintData &paint_data)
Definition: canvas.cc:277
void drawArc(double left, double top, double right, double bottom, double startAngle, double sweepAngle, bool useCenter, const Paint &paint, const PaintData &paint_data)
Definition: canvas.cc:288
void drawImageRect(const CanvasImage *image, double src_left, double src_top, double src_right, double src_bottom, double dst_left, double dst_top, double dst_right, double dst_bottom, const Paint &paint, const PaintData &paint_data, int filterQualityIndex)
Definition: canvas.cc:337
void restore()
Definition: canvas.cc:124
void clipPath(const CanvasPath *path, bool doAntiAlias=true)
Definition: canvas.cc:196
static void Canvas_constructor(Dart_NativeArguments args)
Definition: canvas.cc:28
~Canvas() override
Definition: canvas.cc:94
static void DrawShadow(SkCanvas *canvas, const SkPath &path, SkColor color, float elevation, bool transparentOccluder, SkScalar dpr)
#define DART_REGISTER_NATIVE(CLASS, METHOD)
Dart_Handle ToDart(const T &object)
void translate(double dx, double dy)
Definition: canvas.cc:138
constexpr SkColor colors[]
Window * get_window(int window_id)
Retrieves the Window with the given ID managed by the PlatformConfiguration.
void drawRect(double left, double top, double right, double bottom, const Paint &paint, const PaintData &paint_data)
Definition: canvas.cc:234
Dart_WeakPersistentHandle dart_wrapper() const
void drawShadow(const CanvasPath *path, SkColor color, double elevation, bool transparentOccluder)
Definition: canvas.cc:496
sk_sp< SkImage > image() const
Definition: image.h:37
const ViewportMetrics & viewport_metrics() const
Definition: window.h:29
void drawVertices(const Vertices *vertices, SkBlendMode blend_mode, const Paint &paint, const PaintData &paint_data)
Definition: canvas.cc:444
void drawPoints(const Paint &paint, const PaintData &paint_data, SkCanvas::PointMode point_mode, const tonic::Float32List &points)
Definition: canvas.cc:427
void set_canvas(fml::RefPtr< Canvas > canvas)
static UIDartState * Current()