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