// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "flutter/lib/ui/painting/canvas.h" // ACE PC preivew. #ifndef WINDOWS_PLATFORM // It cannot be passed to the sub-include of math.h, so define it in gn. #define _USE_MATH_DEFINES #endif #include #include "flutter/flow/layers/physical_shape_layer.h" #include "flutter/lib/ui/painting/image.h" #include "flutter/lib/ui/painting/matrix.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/window/window.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkRSXform.h" using tonic::ToDart; namespace flutter { IMPLEMENT_WRAPPERTYPEINFO(ui, Canvas); #define FOR_EACH_BINDING(V) \ V(Canvas, save) \ V(Canvas, saveLayerWithoutBounds) \ V(Canvas, saveLayer) \ V(Canvas, restore) \ V(Canvas, getSaveCount) \ V(Canvas, translate) \ V(Canvas, scale) \ V(Canvas, rotate) \ V(Canvas, skew) \ V(Canvas, transform) \ V(Canvas, clipRect) \ V(Canvas, clipRRect) \ V(Canvas, clipPath) \ V(Canvas, drawColor) \ V(Canvas, drawLine) \ V(Canvas, drawPaint) \ V(Canvas, drawRect) \ V(Canvas, drawRRect) \ V(Canvas, drawDRRect) \ V(Canvas, drawOval) \ V(Canvas, drawCircle) \ V(Canvas, drawArc) \ V(Canvas, drawPath) \ V(Canvas, drawImage) \ V(Canvas, drawImageRect) \ V(Canvas, drawImageNine) \ V(Canvas, drawPicture) \ V(Canvas, drawPoints) \ V(Canvas, drawVertices) \ V(Canvas, drawAtlas) \ V(Canvas, drawShadow) FOR_EACH_BINDING(DART_NATIVE_CALLBACK) void Canvas::RegisterNatives(tonic::DartLibraryNatives* natives) {} fml::RefPtr Canvas::Create(PictureRecorder* recorder, double left, double top, double right, double bottom) { if (!recorder) { FML_LOG(ERROR) << "Canvas constructor called with non-genuine PictureRecorder."; return nullptr; } FML_DCHECK(!recorder->isRecording()); // verified by Dart code fml::RefPtr canvas = fml::MakeRefCounted( recorder->BeginRecording(SkRect::MakeLTRB(left, top, right, bottom))); recorder->set_canvas(canvas); return canvas; } Canvas::Canvas(SkCanvas* canvas) : canvas_(canvas) {} Canvas::~Canvas() {} void Canvas::save() { if (!canvas_) return; canvas_->save(); } void Canvas::saveLayerWithoutBounds(const Paint& paint, const PaintData& paint_data) { if (!canvas_) return; canvas_->saveLayer(nullptr, paint.paint()); } void Canvas::saveLayer(double left, double top, double right, double bottom, const Paint& paint, const PaintData& paint_data) { if (!canvas_) return; SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); canvas_->saveLayer(&bounds, paint.paint()); } void Canvas::restore() { if (!canvas_) return; canvas_->restore(); } int Canvas::getSaveCount() { if (!canvas_) return 0; return canvas_->getSaveCount(); } void Canvas::translate(double dx, double dy) { if (!canvas_) return; canvas_->translate(dx, dy); } void Canvas::scale(double sx, double sy) { if (!canvas_) return; canvas_->scale(sx, sy); } void Canvas::rotate(double radians) { if (!canvas_) return; canvas_->rotate(radians * 180.0 / M_PI); } void Canvas::skew(double sx, double sy) { if (!canvas_) return; canvas_->skew(sx, sy); } void Canvas::transform(const tonic::Float64List& matrix4) { if (!canvas_) return; canvas_->concat(ToSkMatrix(matrix4)); } void Canvas::clipRect(double left, double top, double right, double bottom, SkClipOp clipOp, bool doAntiAlias) { if (!canvas_) return; canvas_->clipRect(SkRect::MakeLTRB(left, top, right, bottom), clipOp, doAntiAlias); } void Canvas::clipRRect(const RRect& rrect, bool doAntiAlias) { if (!canvas_) return; canvas_->clipRRect(rrect.sk_rrect, doAntiAlias); } void Canvas::clipPath(const CanvasPath* path, bool doAntiAlias) { if (!canvas_) return; if (!path) { FML_LOG(ERROR) << "Canvas.clipPath called with non-genuine Path."; return; } canvas_->clipPath(path->path(), doAntiAlias); } void Canvas::drawColor(SkColor color, SkBlendMode blend_mode) { if (!canvas_) return; canvas_->drawColor(color, blend_mode); } void Canvas::drawLine(double x1, double y1, double x2, double y2, const Paint& paint, const PaintData& paint_data) { if (!canvas_) return; canvas_->drawLine(x1, y1, x2, y2, *paint.paint()); } void Canvas::drawPaint(const Paint& paint, const PaintData& paint_data) { if (!canvas_) return; canvas_->drawPaint(*paint.paint()); } void Canvas::drawRect(double left, double top, double right, double bottom, const Paint& paint, const PaintData& paint_data) { if (!canvas_) return; canvas_->drawRect(SkRect::MakeLTRB(left, top, right, bottom), *paint.paint()); } void Canvas::drawRRect(const RRect& rrect, const Paint& paint, const PaintData& paint_data) { if (!canvas_) return; canvas_->drawRRect(rrect.sk_rrect, *paint.paint()); } void Canvas::drawDRRect(const RRect& outer, const RRect& inner, const Paint& paint, const PaintData& paint_data) { if (!canvas_) return; canvas_->drawDRRect(outer.sk_rrect, inner.sk_rrect, *paint.paint()); } void Canvas::drawOval(double left, double top, double right, double bottom, const Paint& paint, const PaintData& paint_data) { if (!canvas_) return; canvas_->drawOval(SkRect::MakeLTRB(left, top, right, bottom), *paint.paint()); } void Canvas::drawCircle(double x, double y, double radius, const Paint& paint, const PaintData& paint_data) { if (!canvas_) return; canvas_->drawCircle(x, y, radius, *paint.paint()); } void Canvas::drawArc(double left, double top, double right, double bottom, double startAngle, double sweepAngle, bool useCenter, const Paint& paint, const PaintData& paint_data) { if (!canvas_) return; canvas_->drawArc(SkRect::MakeLTRB(left, top, right, bottom), startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI, useCenter, *paint.paint()); } void Canvas::drawPath(const CanvasPath* path, const Paint& paint, const PaintData& paint_data) { if (!canvas_) return; if (!path) { FML_LOG(ERROR) << "Canvas.drawPath called with non-genuine Path."; return; } canvas_->drawPath(path->path(), *paint.paint()); } void Canvas::drawImage(const CanvasImage* image, double x, double y, const Paint& paint, const PaintData& paint_data) { if (!canvas_) return; if (!image) { FML_LOG(ERROR) << "Canvas.drawImage called with non-genuine Image."; return; } canvas_->drawImage(image->image(), x, y, paint.paint()); } void Canvas::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) { if (!canvas_) return; if (!image) { FML_LOG(ERROR) << "Canvas.drawImageRect called with non-genuine Image."; return; } SkRect src = SkRect::MakeLTRB(src_left, src_top, src_right, src_bottom); SkRect dst = SkRect::MakeLTRB(dst_left, dst_top, dst_right, dst_bottom); canvas_->drawImageRect(image->image(), src, dst, paint.paint(), SkCanvas::kFast_SrcRectConstraint); } void Canvas::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) { if (!canvas_) return; if (!image) { FML_LOG(ERROR) << "Canvas.drawImageNine called with non-genuine Image."; return; } SkRect center = SkRect::MakeLTRB(center_left, center_top, center_right, center_bottom); SkIRect icenter; center.round(&icenter); SkRect dst = SkRect::MakeLTRB(dst_left, dst_top, dst_right, dst_bottom); canvas_->drawImageNine(image->image(), icenter, dst, paint.paint()); } void Canvas::drawPicture(Picture* picture) { if (!canvas_) return; if (!picture) { FML_LOG(ERROR) << "Canvas.drawPicture called with non-genuine Picture."; return; } canvas_->drawPicture(picture->picture().get()); } void Canvas::drawPoints(const Paint& paint, const PaintData& paint_data, SkCanvas::PointMode point_mode, const tonic::Float32List& points) { if (!canvas_) return; static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint doesn't use floats."); canvas_->drawPoints(point_mode, points.size() / 2, // SkPoints have two floats. reinterpret_cast(points.data()), *paint.paint()); } void Canvas::drawVertices(const Vertices* vertices, SkBlendMode blend_mode, const Paint& paint, const PaintData& paint_data) { if (!canvas_) return; if (!vertices) { FML_LOG(ERROR) << "Canvas.drawVertices called with non-genuine Vertices."; return; } canvas_->drawVertices(vertices->vertices(), blend_mode, *paint.paint()); } void Canvas::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) { if (!canvas_) return; if (!atlas) { FML_LOG(ERROR) << "Canvas.drawAtlas or Canvas.drawRawAtlas called with " "non-genuine Image."; return; } sk_sp skImage = atlas->image(); static_assert(sizeof(SkRSXform) == sizeof(float) * 4, "SkRSXform doesn't use floats."); static_assert(sizeof(SkRect) == sizeof(float) * 4, "SkRect doesn't use floats."); canvas_->drawAtlas( skImage.get(), reinterpret_cast(transforms.data()), reinterpret_cast(rects.data()), reinterpret_cast(colors.data()), rects.size() / 4, // SkRect have four floats. blend_mode, reinterpret_cast(cull_rect.data()), paint.paint()); } void Canvas::drawShadow(const CanvasPath* path, SkColor color, double elevation, bool transparentOccluder) { if (!path) { FML_LOG(ERROR) << "Canvas.drawShader called with non-genuine Path."; return; } SkScalar dpr = UIDartState::Current()->window()->viewport_metrics().device_pixel_ratio; flutter::PhysicalShapeLayer::DrawShadow(canvas_, path->path(), color, elevation, transparentOccluder, dpr); } void Canvas::Clear() { canvas_ = nullptr; } bool Canvas::IsRecording() const { return !!canvas_; } } // namespace flutter