• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
7 // ACE PC preivew.
8 #ifndef WINDOWS_PLATFORM
9 // It cannot be passed to the sub-include of math.h, so define it in gn.
10 #define _USE_MATH_DEFINES
11 #endif
12 
13 #include <math.h>
14 
15 #include "flutter/flow/layers/physical_shape_layer.h"
16 #include "flutter/lib/ui/painting/image.h"
17 #include "flutter/lib/ui/painting/matrix.h"
18 #include "flutter/lib/ui/ui_dart_state.h"
19 #include "flutter/lib/ui/window/window.h"
20 #include "third_party/skia/include/core/SkBitmap.h"
21 #include "third_party/skia/include/core/SkCanvas.h"
22 #include "third_party/skia/include/core/SkRSXform.h"
23 
24 using tonic::ToDart;
25 
26 namespace flutter {
27 
28 IMPLEMENT_WRAPPERTYPEINFO(ui, Canvas);
29 
30 #define FOR_EACH_BINDING(V)         \
31   V(Canvas, save)                   \
32   V(Canvas, saveLayerWithoutBounds) \
33   V(Canvas, saveLayer)              \
34   V(Canvas, restore)                \
35   V(Canvas, getSaveCount)           \
36   V(Canvas, translate)              \
37   V(Canvas, scale)                  \
38   V(Canvas, rotate)                 \
39   V(Canvas, skew)                   \
40   V(Canvas, transform)              \
41   V(Canvas, clipRect)               \
42   V(Canvas, clipRRect)              \
43   V(Canvas, clipPath)               \
44   V(Canvas, drawColor)              \
45   V(Canvas, drawLine)               \
46   V(Canvas, drawPaint)              \
47   V(Canvas, drawRect)               \
48   V(Canvas, drawRRect)              \
49   V(Canvas, drawDRRect)             \
50   V(Canvas, drawOval)               \
51   V(Canvas, drawCircle)             \
52   V(Canvas, drawArc)                \
53   V(Canvas, drawPath)               \
54   V(Canvas, drawImage)              \
55   V(Canvas, drawImageRect)          \
56   V(Canvas, drawImageNine)          \
57   V(Canvas, drawPicture)            \
58   V(Canvas, drawPoints)             \
59   V(Canvas, drawVertices)           \
60   V(Canvas, drawAtlas)              \
61   V(Canvas, drawShadow)
62 
FOR_EACH_BINDING(DART_NATIVE_CALLBACK)63 FOR_EACH_BINDING(DART_NATIVE_CALLBACK)
64 
65 void Canvas::RegisterNatives(tonic::DartLibraryNatives* natives) {}
66 
Create(PictureRecorder * recorder,double left,double top,double right,double bottom)67 fml::RefPtr<Canvas> Canvas::Create(PictureRecorder* recorder,
68                                    double left,
69                                    double top,
70                                    double right,
71                                    double bottom) {
72   if (!recorder) {
73     FML_LOG(ERROR)
74         << "Canvas constructor called with non-genuine PictureRecorder.";
75     return nullptr;
76   }
77 
78   FML_DCHECK(!recorder->isRecording());  // verified by Dart code
79   fml::RefPtr<Canvas> canvas = fml::MakeRefCounted<Canvas>(
80       recorder->BeginRecording(SkRect::MakeLTRB(left, top, right, bottom)));
81   recorder->set_canvas(canvas);
82   return canvas;
83 }
84 
Canvas(SkCanvas * canvas)85 Canvas::Canvas(SkCanvas* canvas) : canvas_(canvas) {}
86 
~Canvas()87 Canvas::~Canvas() {}
88 
save()89 void Canvas::save() {
90   if (!canvas_)
91     return;
92   canvas_->save();
93 }
94 
saveLayerWithoutBounds(const Paint & paint,const PaintData & paint_data)95 void Canvas::saveLayerWithoutBounds(const Paint& paint,
96                                     const PaintData& paint_data) {
97   if (!canvas_)
98     return;
99   canvas_->saveLayer(nullptr, paint.paint());
100 }
101 
saveLayer(double left,double top,double right,double bottom,const Paint & paint,const PaintData & paint_data)102 void Canvas::saveLayer(double left,
103                        double top,
104                        double right,
105                        double bottom,
106                        const Paint& paint,
107                        const PaintData& paint_data) {
108   if (!canvas_)
109     return;
110   SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
111   canvas_->saveLayer(&bounds, paint.paint());
112 }
113 
restore()114 void Canvas::restore() {
115   if (!canvas_)
116     return;
117   canvas_->restore();
118 }
119 
getSaveCount()120 int Canvas::getSaveCount() {
121   if (!canvas_)
122     return 0;
123   return canvas_->getSaveCount();
124 }
125 
translate(double dx,double dy)126 void Canvas::translate(double dx, double dy) {
127   if (!canvas_)
128     return;
129   canvas_->translate(dx, dy);
130 }
131 
scale(double sx,double sy)132 void Canvas::scale(double sx, double sy) {
133   if (!canvas_)
134     return;
135   canvas_->scale(sx, sy);
136 }
137 
rotate(double radians)138 void Canvas::rotate(double radians) {
139   if (!canvas_)
140     return;
141   canvas_->rotate(radians * 180.0 / M_PI);
142 }
143 
skew(double sx,double sy)144 void Canvas::skew(double sx, double sy) {
145   if (!canvas_)
146     return;
147   canvas_->skew(sx, sy);
148 }
149 
transform(const tonic::Float64List & matrix4)150 void Canvas::transform(const tonic::Float64List& matrix4) {
151   if (!canvas_)
152     return;
153   canvas_->concat(ToSkMatrix(matrix4));
154 }
155 
clipRect(double left,double top,double right,double bottom,SkClipOp clipOp,bool doAntiAlias)156 void Canvas::clipRect(double left,
157                       double top,
158                       double right,
159                       double bottom,
160                       SkClipOp clipOp,
161                       bool doAntiAlias) {
162   if (!canvas_)
163     return;
164   canvas_->clipRect(SkRect::MakeLTRB(left, top, right, bottom), clipOp,
165                     doAntiAlias);
166 }
167 
clipRRect(const RRect & rrect,bool doAntiAlias)168 void Canvas::clipRRect(const RRect& rrect, bool doAntiAlias) {
169   if (!canvas_)
170     return;
171   canvas_->clipRRect(rrect.sk_rrect, doAntiAlias);
172 }
173 
clipPath(const CanvasPath * path,bool doAntiAlias)174 void Canvas::clipPath(const CanvasPath* path, bool doAntiAlias) {
175   if (!canvas_)
176     return;
177   if (!path) {
178     FML_LOG(ERROR) << "Canvas.clipPath called with non-genuine Path.";
179     return;
180   }
181 
182   canvas_->clipPath(path->path(), doAntiAlias);
183 }
184 
drawColor(SkColor color,SkBlendMode blend_mode)185 void Canvas::drawColor(SkColor color, SkBlendMode blend_mode) {
186   if (!canvas_)
187     return;
188   canvas_->drawColor(color, blend_mode);
189 }
190 
drawLine(double x1,double y1,double x2,double y2,const Paint & paint,const PaintData & paint_data)191 void Canvas::drawLine(double x1,
192                       double y1,
193                       double x2,
194                       double y2,
195                       const Paint& paint,
196                       const PaintData& paint_data) {
197   if (!canvas_)
198     return;
199   canvas_->drawLine(x1, y1, x2, y2, *paint.paint());
200 }
201 
drawPaint(const Paint & paint,const PaintData & paint_data)202 void Canvas::drawPaint(const Paint& paint, const PaintData& paint_data) {
203   if (!canvas_)
204     return;
205   canvas_->drawPaint(*paint.paint());
206 }
207 
drawRect(double left,double top,double right,double bottom,const Paint & paint,const PaintData & paint_data)208 void Canvas::drawRect(double left,
209                       double top,
210                       double right,
211                       double bottom,
212                       const Paint& paint,
213                       const PaintData& paint_data) {
214   if (!canvas_)
215     return;
216   canvas_->drawRect(SkRect::MakeLTRB(left, top, right, bottom), *paint.paint());
217 }
218 
drawRRect(const RRect & rrect,const Paint & paint,const PaintData & paint_data)219 void Canvas::drawRRect(const RRect& rrect,
220                        const Paint& paint,
221                        const PaintData& paint_data) {
222   if (!canvas_)
223     return;
224   canvas_->drawRRect(rrect.sk_rrect, *paint.paint());
225 }
226 
drawDRRect(const RRect & outer,const RRect & inner,const Paint & paint,const PaintData & paint_data)227 void Canvas::drawDRRect(const RRect& outer,
228                         const RRect& inner,
229                         const Paint& paint,
230                         const PaintData& paint_data) {
231   if (!canvas_)
232     return;
233   canvas_->drawDRRect(outer.sk_rrect, inner.sk_rrect, *paint.paint());
234 }
235 
drawOval(double left,double top,double right,double bottom,const Paint & paint,const PaintData & paint_data)236 void Canvas::drawOval(double left,
237                       double top,
238                       double right,
239                       double bottom,
240                       const Paint& paint,
241                       const PaintData& paint_data) {
242   if (!canvas_)
243     return;
244   canvas_->drawOval(SkRect::MakeLTRB(left, top, right, bottom), *paint.paint());
245 }
246 
drawCircle(double x,double y,double radius,const Paint & paint,const PaintData & paint_data)247 void Canvas::drawCircle(double x,
248                         double y,
249                         double radius,
250                         const Paint& paint,
251                         const PaintData& paint_data) {
252   if (!canvas_)
253     return;
254   canvas_->drawCircle(x, y, radius, *paint.paint());
255 }
256 
drawArc(double left,double top,double right,double bottom,double startAngle,double sweepAngle,bool useCenter,const Paint & paint,const PaintData & paint_data)257 void Canvas::drawArc(double left,
258                      double top,
259                      double right,
260                      double bottom,
261                      double startAngle,
262                      double sweepAngle,
263                      bool useCenter,
264                      const Paint& paint,
265                      const PaintData& paint_data) {
266   if (!canvas_)
267     return;
268   canvas_->drawArc(SkRect::MakeLTRB(left, top, right, bottom),
269                    startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI,
270                    useCenter, *paint.paint());
271 }
272 
drawPath(const CanvasPath * path,const Paint & paint,const PaintData & paint_data)273 void Canvas::drawPath(const CanvasPath* path,
274                       const Paint& paint,
275                       const PaintData& paint_data) {
276   if (!canvas_)
277     return;
278   if (!path) {
279     FML_LOG(ERROR) << "Canvas.drawPath called with non-genuine Path.";
280     return;
281   }
282 
283   canvas_->drawPath(path->path(), *paint.paint());
284 }
285 
drawImage(const CanvasImage * image,double x,double y,const Paint & paint,const PaintData & paint_data)286 void Canvas::drawImage(const CanvasImage* image,
287                        double x,
288                        double y,
289                        const Paint& paint,
290                        const PaintData& paint_data) {
291   if (!canvas_)
292     return;
293   if (!image) {
294     FML_LOG(ERROR) << "Canvas.drawImage called with non-genuine Image.";
295     return;
296   }
297   canvas_->drawImage(image->image(), x, y, paint.paint());
298 }
299 
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)300 void Canvas::drawImageRect(const CanvasImage* image,
301                            double src_left,
302                            double src_top,
303                            double src_right,
304                            double src_bottom,
305                            double dst_left,
306                            double dst_top,
307                            double dst_right,
308                            double dst_bottom,
309                            const Paint& paint,
310                            const PaintData& paint_data) {
311   if (!canvas_)
312     return;
313   if (!image) {
314     FML_LOG(ERROR) << "Canvas.drawImageRect called with non-genuine Image.";
315     return;
316   }
317 
318   SkRect src = SkRect::MakeLTRB(src_left, src_top, src_right, src_bottom);
319   SkRect dst = SkRect::MakeLTRB(dst_left, dst_top, dst_right, dst_bottom);
320   canvas_->drawImageRect(image->image(), src, dst, paint.paint(),
321                          SkCanvas::kFast_SrcRectConstraint);
322 }
323 
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)324 void Canvas::drawImageNine(const CanvasImage* image,
325                            double center_left,
326                            double center_top,
327                            double center_right,
328                            double center_bottom,
329                            double dst_left,
330                            double dst_top,
331                            double dst_right,
332                            double dst_bottom,
333                            const Paint& paint,
334                            const PaintData& paint_data) {
335   if (!canvas_)
336     return;
337   if (!image) {
338     FML_LOG(ERROR) << "Canvas.drawImageNine called with non-genuine Image.";
339     return;
340   }
341   SkRect center =
342       SkRect::MakeLTRB(center_left, center_top, center_right, center_bottom);
343   SkIRect icenter;
344   center.round(&icenter);
345   SkRect dst = SkRect::MakeLTRB(dst_left, dst_top, dst_right, dst_bottom);
346   canvas_->drawImageNine(image->image(), icenter, dst, paint.paint());
347 }
348 
drawPicture(Picture * picture)349 void Canvas::drawPicture(Picture* picture) {
350   if (!canvas_)
351     return;
352   if (!picture) {
353     FML_LOG(ERROR) << "Canvas.drawPicture called with non-genuine Picture.";
354     return;
355   }
356   canvas_->drawPicture(picture->picture().get());
357 }
358 
drawPoints(const Paint & paint,const PaintData & paint_data,SkCanvas::PointMode point_mode,const tonic::Float32List & points)359 void Canvas::drawPoints(const Paint& paint,
360                         const PaintData& paint_data,
361                         SkCanvas::PointMode point_mode,
362                         const tonic::Float32List& points) {
363   if (!canvas_)
364     return;
365 
366   static_assert(sizeof(SkPoint) == sizeof(float) * 2,
367                 "SkPoint doesn't use floats.");
368 
369   canvas_->drawPoints(point_mode,
370                       points.size() / 2,  // SkPoints have two floats.
371                       reinterpret_cast<const SkPoint*>(points.data()),
372                       *paint.paint());
373 }
374 
drawVertices(const Vertices * vertices,SkBlendMode blend_mode,const Paint & paint,const PaintData & paint_data)375 void Canvas::drawVertices(const Vertices* vertices,
376                           SkBlendMode blend_mode,
377                           const Paint& paint,
378                           const PaintData& paint_data) {
379   if (!canvas_)
380     return;
381   if (!vertices) {
382     FML_LOG(ERROR) << "Canvas.drawVertices called with non-genuine Vertices.";
383     return;
384   }
385   canvas_->drawVertices(vertices->vertices(), blend_mode, *paint.paint());
386 }
387 
drawAtlas(const Paint & paint,const PaintData & paint_data,CanvasImage * atlas,const tonic::Float32List & transforms,const tonic::Float32List & rects,const tonic::Int32List & colors,SkBlendMode blend_mode,const tonic::Float32List & cull_rect)388 void Canvas::drawAtlas(const Paint& paint,
389                        const PaintData& paint_data,
390                        CanvasImage* atlas,
391                        const tonic::Float32List& transforms,
392                        const tonic::Float32List& rects,
393                        const tonic::Int32List& colors,
394                        SkBlendMode blend_mode,
395                        const tonic::Float32List& cull_rect) {
396   if (!canvas_)
397     return;
398   if (!atlas) {
399     FML_LOG(ERROR) << "Canvas.drawAtlas or Canvas.drawRawAtlas called with "
400                       "non-genuine Image.";
401     return;
402   }
403   sk_sp<SkImage> skImage = atlas->image();
404 
405   static_assert(sizeof(SkRSXform) == sizeof(float) * 4,
406                 "SkRSXform doesn't use floats.");
407   static_assert(sizeof(SkRect) == sizeof(float) * 4,
408                 "SkRect doesn't use floats.");
409 
410   canvas_->drawAtlas(
411       skImage.get(), reinterpret_cast<const SkRSXform*>(transforms.data()),
412       reinterpret_cast<const SkRect*>(rects.data()),
413       reinterpret_cast<const SkColor*>(colors.data()),
414       rects.size() / 4,  // SkRect have four floats.
415       blend_mode, reinterpret_cast<const SkRect*>(cull_rect.data()),
416       paint.paint());
417 }
418 
drawShadow(const CanvasPath * path,SkColor color,double elevation,bool transparentOccluder)419 void Canvas::drawShadow(const CanvasPath* path,
420                         SkColor color,
421                         double elevation,
422                         bool transparentOccluder) {
423   if (!path) {
424     FML_LOG(ERROR) << "Canvas.drawShader called with non-genuine Path.";
425     return;
426   }
427 
428   SkScalar dpr =
429       UIDartState::Current()->window()->viewport_metrics().device_pixel_ratio;
430   flutter::PhysicalShapeLayer::DrawShadow(canvas_, path->path(), color,
431                                           elevation, transparentOccluder, dpr);
432 }
433 
Clear()434 void Canvas::Clear() {
435   canvas_ = nullptr;
436 }
437 
IsRecording() const438 bool Canvas::IsRecording() const {
439   return !!canvas_;
440 }
441 
442 }  // namespace flutter
443