| // 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. |
| |
| import 'dart:math' as math; |
| import 'dart:typed_data'; |
| |
| import 'package:ui/ui.dart' as ui; |
| |
| import 'canvaskit_api.dart'; |
| import 'image.dart'; |
| import 'image_filter.dart'; |
| import 'painting.dart'; |
| import 'path.dart'; |
| import 'picture.dart'; |
| import 'text.dart'; |
| import 'util.dart'; |
| import 'vertices.dart'; |
| |
| /// Memoized value for ClipOp.Intersect, so we don't have to hit JS-interop |
| /// every time we need it. |
| final SkClipOp _clipOpIntersect = canvasKit.ClipOp.Intersect; |
| |
| /// A Dart wrapper around Skia's [SkCanvas]. |
| /// |
| /// This is intentionally not memory-managing the underlying [SkCanvas]. See |
| /// the docs on [SkCanvas], which explain the reason. |
| class CkCanvas { |
| // Cubic equation coefficients recommended by Mitchell & Netravali |
| // in their paper on cubic interpolation. |
| static const double _kMitchellNetravali_B = 1.0 / 3.0; |
| static const double _kMitchellNetravali_C = 1.0 / 3.0; |
| |
| final SkCanvas skCanvas; |
| |
| CkCanvas(this.skCanvas); |
| |
| int? get saveCount => skCanvas.getSaveCount(); |
| |
| void clear(ui.Color color) { |
| skCanvas.clear(toSharedSkColor1(color)); |
| } |
| |
| void clipPath(CkPath path, bool doAntiAlias) { |
| skCanvas.clipPath( |
| path.skiaObject, |
| _clipOpIntersect, |
| doAntiAlias, |
| ); |
| } |
| |
| void clipRRect(ui.RRect rrect, bool doAntiAlias) { |
| skCanvas.clipRRect( |
| toSkRRect(rrect), |
| _clipOpIntersect, |
| doAntiAlias, |
| ); |
| } |
| |
| void clipRect(ui.Rect rect, ui.ClipOp clipOp, bool doAntiAlias) { |
| skCanvas.clipRect( |
| toSkRect(rect), |
| toSkClipOp(clipOp), |
| doAntiAlias, |
| ); |
| } |
| |
| void drawArc( |
| ui.Rect oval, |
| double startAngle, |
| double sweepAngle, |
| bool useCenter, |
| CkPaint paint, |
| ) { |
| const double toDegrees = 180 / math.pi; |
| skCanvas.drawArc( |
| toSkRect(oval), |
| startAngle * toDegrees, |
| sweepAngle * toDegrees, |
| useCenter, |
| paint.skiaObject, |
| ); |
| } |
| |
| // TODO(flar): CanvasKit does not expose sampling options available on SkCanvas.drawAtlas |
| void drawAtlasRaw( |
| CkPaint paint, |
| CkImage atlas, |
| Float32List rstTransforms, |
| Float32List rects, |
| Uint32List? colors, |
| ui.BlendMode blendMode, |
| ) { |
| skCanvas.drawAtlas( |
| atlas.skImage, |
| rects, |
| rstTransforms, |
| paint.skiaObject, |
| toSkBlendMode(blendMode), |
| colors, |
| ); |
| } |
| |
| void drawCircle(ui.Offset c, double radius, CkPaint paint) { |
| skCanvas.drawCircle( |
| c.dx, |
| c.dy, |
| radius, |
| paint.skiaObject, |
| ); |
| } |
| |
| void drawColor(ui.Color color, ui.BlendMode blendMode) { |
| skCanvas.drawColorInt( |
| color.value, |
| toSkBlendMode(blendMode), |
| ); |
| } |
| |
| void drawDRRect(ui.RRect outer, ui.RRect inner, CkPaint paint) { |
| skCanvas.drawDRRect( |
| toSkRRect(outer), |
| toSkRRect(inner), |
| paint.skiaObject, |
| ); |
| } |
| |
| void drawImage(CkImage image, ui.Offset offset, CkPaint paint) { |
| final ui.FilterQuality filterQuality = paint.filterQuality; |
| if (filterQuality == ui.FilterQuality.high) { |
| skCanvas.drawImageCubic( |
| image.skImage, |
| offset.dx, |
| offset.dy, |
| _kMitchellNetravali_B, |
| _kMitchellNetravali_C, |
| paint.skiaObject, |
| ); |
| } else { |
| skCanvas.drawImageOptions( |
| image.skImage, |
| offset.dx, |
| offset.dy, |
| toSkFilterMode(filterQuality), |
| toSkMipmapMode(filterQuality), |
| paint.skiaObject, |
| ); |
| } |
| } |
| |
| void drawImageRect(CkImage image, ui.Rect src, ui.Rect dst, CkPaint paint) { |
| final ui.FilterQuality filterQuality = paint.filterQuality; |
| if (filterQuality == ui.FilterQuality.high) { |
| skCanvas.drawImageRectCubic( |
| image.skImage, |
| toSkRect(src), |
| toSkRect(dst), |
| _kMitchellNetravali_B, |
| _kMitchellNetravali_C, |
| paint.skiaObject, |
| ); |
| } else { |
| skCanvas.drawImageRectOptions( |
| image.skImage, |
| toSkRect(src), |
| toSkRect(dst), |
| toSkFilterMode(filterQuality), |
| toSkMipmapMode(filterQuality), |
| paint.skiaObject, |
| ); |
| } |
| } |
| |
| void drawImageNine( |
| CkImage image, ui.Rect center, ui.Rect dst, CkPaint paint) { |
| skCanvas.drawImageNine( |
| image.skImage, |
| toSkRect(center), |
| toSkRect(dst), |
| toSkFilterMode(paint.filterQuality), |
| paint.skiaObject, |
| ); |
| } |
| |
| void drawLine(ui.Offset p1, ui.Offset p2, CkPaint paint) { |
| skCanvas.drawLine( |
| p1.dx, |
| p1.dy, |
| p2.dx, |
| p2.dy, |
| paint.skiaObject, |
| ); |
| } |
| |
| void drawOval(ui.Rect rect, CkPaint paint) { |
| skCanvas.drawOval( |
| toSkRect(rect), |
| paint.skiaObject, |
| ); |
| } |
| |
| void drawPaint(CkPaint paint) { |
| skCanvas.drawPaint(paint.skiaObject); |
| } |
| |
| void drawParagraph(CkParagraph paragraph, ui.Offset offset) { |
| skCanvas.drawParagraph( |
| paragraph.skiaObject, |
| offset.dx, |
| offset.dy, |
| ); |
| paragraph.markUsed(); |
| } |
| |
| void drawPath(CkPath path, CkPaint paint) { |
| skCanvas.drawPath(path.skiaObject, paint.skiaObject); |
| } |
| |
| void drawPicture(CkPicture picture) { |
| skCanvas.drawPicture(picture.skiaObject); |
| } |
| |
| void drawPoints(CkPaint paint, ui.PointMode pointMode, Float32List points) { |
| skCanvas.drawPoints( |
| toSkPointMode(pointMode), |
| points, |
| paint.skiaObject, |
| ); |
| } |
| |
| void drawRRect(ui.RRect rrect, CkPaint paint) { |
| skCanvas.drawRRect( |
| toSkRRect(rrect), |
| paint.skiaObject, |
| ); |
| } |
| |
| void drawRect(ui.Rect rect, CkPaint paint) { |
| skCanvas.drawRect(toSkRect(rect), paint.skiaObject); |
| } |
| |
| void drawShadow( |
| CkPath path, ui.Color color, double elevation, bool transparentOccluder) { |
| drawSkShadow(skCanvas, path, color, elevation, transparentOccluder, |
| ui.window.devicePixelRatio); |
| } |
| |
| void drawVertices( |
| CkVertices vertices, ui.BlendMode blendMode, CkPaint paint) { |
| skCanvas.drawVertices( |
| vertices.skiaObject, |
| toSkBlendMode(blendMode), |
| paint.skiaObject, |
| ); |
| } |
| |
| void restore() { |
| skCanvas.restore(); |
| } |
| |
| void restoreToCount(int count) { |
| skCanvas.restoreToCount(count); |
| } |
| |
| void rotate(double radians) { |
| skCanvas.rotate(radians * 180.0 / math.pi, 0.0, 0.0); |
| } |
| |
| int save() { |
| return skCanvas.save(); |
| } |
| |
| void saveLayer(ui.Rect bounds, CkPaint? paint) { |
| skCanvas.saveLayer( |
| paint?.skiaObject, |
| toSkRect(bounds), |
| null, |
| null, |
| ); |
| } |
| |
| void saveLayerWithoutBounds(CkPaint? paint) { |
| skCanvas.saveLayer(paint?.skiaObject, null, null, null); |
| } |
| |
| void saveLayerWithFilter(ui.Rect bounds, ui.ImageFilter filter, |
| [CkPaint? paint]) { |
| final CkManagedSkImageFilterConvertible convertible = |
| filter as CkManagedSkImageFilterConvertible; |
| return skCanvas.saveLayer( |
| paint?.skiaObject, |
| toSkRect(bounds), |
| convertible.imageFilter.skiaObject, |
| 0, |
| ); |
| } |
| |
| void scale(double sx, double sy) { |
| skCanvas.scale(sx, sy); |
| } |
| |
| void skew(double sx, double sy) { |
| skCanvas.skew(sx, sy); |
| } |
| |
| void transform(Float32List matrix4) { |
| skCanvas.concat(toSkMatrixFromFloat32(matrix4)); |
| } |
| |
| void translate(double dx, double dy) { |
| skCanvas.translate(dx, dy); |
| } |
| |
| CkPictureSnapshot? get pictureSnapshot => null; |
| } |
| |
| class RecordingCkCanvas extends CkCanvas { |
| RecordingCkCanvas(SkCanvas skCanvas, ui.Rect bounds) |
| : pictureSnapshot = CkPictureSnapshot(bounds), |
| super(skCanvas); |
| |
| @override |
| final CkPictureSnapshot pictureSnapshot; |
| |
| void _addCommand(CkPaintCommand command) { |
| pictureSnapshot._commands.add(command); |
| } |
| |
| @override |
| void clear(ui.Color color) { |
| super.clear(color); |
| _addCommand(CkClearCommand(color)); |
| } |
| |
| @override |
| void clipPath(CkPath path, bool doAntiAlias) { |
| super.clipPath(path, doAntiAlias); |
| _addCommand(CkClipPathCommand(path, doAntiAlias)); |
| } |
| |
| @override |
| void clipRRect(ui.RRect rrect, bool doAntiAlias) { |
| super.clipRRect(rrect, doAntiAlias); |
| _addCommand(CkClipRRectCommand(rrect, doAntiAlias)); |
| } |
| |
| @override |
| void clipRect(ui.Rect rect, ui.ClipOp clipOp, bool doAntiAlias) { |
| super.clipRect(rect, clipOp, doAntiAlias); |
| _addCommand(CkClipRectCommand(rect, clipOp, doAntiAlias)); |
| } |
| |
| @override |
| void drawArc( |
| ui.Rect oval, |
| double startAngle, |
| double sweepAngle, |
| bool useCenter, |
| CkPaint paint, |
| ) { |
| super.drawArc(oval, startAngle, sweepAngle, useCenter, paint); |
| _addCommand( |
| CkDrawArcCommand(oval, startAngle, sweepAngle, useCenter, paint)); |
| } |
| |
| @override |
| void drawAtlasRaw( |
| CkPaint paint, |
| CkImage atlas, |
| Float32List rstTransforms, |
| Float32List rects, |
| Uint32List? colors, |
| ui.BlendMode blendMode, |
| ) { |
| super.drawAtlasRaw(paint, atlas, rstTransforms, rects, colors, blendMode); |
| _addCommand(CkDrawAtlasCommand( |
| paint, atlas, rstTransforms, rects, colors, blendMode)); |
| } |
| |
| @override |
| void drawCircle(ui.Offset c, double radius, CkPaint paint) { |
| super.drawCircle(c, radius, paint); |
| _addCommand(CkDrawCircleCommand(c, radius, paint)); |
| } |
| |
| @override |
| void drawColor(ui.Color color, ui.BlendMode blendMode) { |
| super.drawColor(color, blendMode); |
| _addCommand(CkDrawColorCommand(color, blendMode)); |
| } |
| |
| @override |
| void drawDRRect(ui.RRect outer, ui.RRect inner, CkPaint paint) { |
| super.drawDRRect(outer, inner, paint); |
| _addCommand(CkDrawDRRectCommand(outer, inner, paint)); |
| } |
| |
| @override |
| void drawImage(CkImage image, ui.Offset offset, CkPaint paint) { |
| super.drawImage(image, offset, paint); |
| _addCommand(CkDrawImageCommand(image, offset, paint)); |
| } |
| |
| @override |
| void drawImageRect(CkImage image, ui.Rect src, ui.Rect dst, CkPaint paint) { |
| super.drawImageRect(image, src, dst, paint); |
| _addCommand(CkDrawImageRectCommand(image, src, dst, paint)); |
| } |
| |
| @override |
| void drawImageNine( |
| CkImage image, ui.Rect center, ui.Rect dst, CkPaint paint) { |
| super.drawImageNine(image, center, dst, paint); |
| _addCommand(CkDrawImageNineCommand(image, center, dst, paint)); |
| } |
| |
| @override |
| void drawLine(ui.Offset p1, ui.Offset p2, CkPaint paint) { |
| super.drawLine(p1, p2, paint); |
| _addCommand(CkDrawLineCommand(p1, p2, paint)); |
| } |
| |
| @override |
| void drawOval(ui.Rect rect, CkPaint paint) { |
| super.drawOval(rect, paint); |
| _addCommand(CkDrawOvalCommand(rect, paint)); |
| } |
| |
| @override |
| void drawPaint(CkPaint paint) { |
| super.drawPaint(paint); |
| _addCommand(CkDrawPaintCommand(paint)); |
| } |
| |
| @override |
| void drawParagraph(CkParagraph paragraph, ui.Offset offset) { |
| super.drawParagraph(paragraph, offset); |
| _addCommand(CkDrawParagraphCommand(paragraph, offset)); |
| } |
| |
| @override |
| void drawPath(CkPath path, CkPaint paint) { |
| super.drawPath(path, paint); |
| _addCommand(CkDrawPathCommand(path, paint)); |
| } |
| |
| @override |
| void drawPicture(CkPicture picture) { |
| super.drawPicture(picture); |
| _addCommand(CkDrawPictureCommand(picture)); |
| } |
| |
| @override |
| void drawPoints(CkPaint paint, ui.PointMode pointMode, Float32List points) { |
| super.drawPoints(paint, pointMode, points); |
| _addCommand(CkDrawPointsCommand(pointMode, points, paint)); |
| } |
| |
| @override |
| void drawRRect(ui.RRect rrect, CkPaint paint) { |
| super.drawRRect(rrect, paint); |
| _addCommand(CkDrawRRectCommand(rrect, paint)); |
| } |
| |
| @override |
| void drawRect(ui.Rect rect, CkPaint paint) { |
| super.drawRect(rect, paint); |
| _addCommand(CkDrawRectCommand(rect, paint)); |
| } |
| |
| @override |
| void drawShadow( |
| CkPath path, ui.Color color, double elevation, bool transparentOccluder) { |
| super.drawShadow(path, color, elevation, transparentOccluder); |
| _addCommand( |
| CkDrawShadowCommand(path, color, elevation, transparentOccluder)); |
| } |
| |
| @override |
| void drawVertices( |
| CkVertices vertices, ui.BlendMode blendMode, CkPaint paint) { |
| super.drawVertices(vertices, blendMode, paint); |
| _addCommand(CkDrawVerticesCommand(vertices, blendMode, paint)); |
| } |
| |
| @override |
| void restore() { |
| super.restore(); |
| _addCommand(const CkRestoreCommand()); |
| } |
| |
| @override |
| void restoreToCount(int count) { |
| super.restoreToCount(count); |
| _addCommand(CkRestoreToCountCommand(count)); |
| } |
| |
| @override |
| void rotate(double radians) { |
| super.rotate(radians); |
| _addCommand(CkRotateCommand(radians)); |
| } |
| |
| @override |
| int save() { |
| _addCommand(const CkSaveCommand()); |
| return super.save(); |
| } |
| |
| @override |
| void saveLayer(ui.Rect bounds, CkPaint? paint) { |
| super.saveLayer(bounds, paint); |
| _addCommand(CkSaveLayerCommand(bounds, paint)); |
| } |
| |
| @override |
| void saveLayerWithoutBounds(CkPaint? paint) { |
| super.saveLayerWithoutBounds(paint); |
| _addCommand(CkSaveLayerWithoutBoundsCommand(paint)); |
| } |
| |
| @override |
| void saveLayerWithFilter(ui.Rect bounds, ui.ImageFilter filter, |
| [CkPaint? paint]) { |
| super.saveLayerWithFilter(bounds, filter, paint); |
| _addCommand(CkSaveLayerWithFilterCommand(bounds, filter, paint)); |
| } |
| |
| @override |
| void scale(double sx, double sy) { |
| super.scale(sx, sy); |
| _addCommand(CkScaleCommand(sx, sy)); |
| } |
| |
| @override |
| void skew(double sx, double sy) { |
| super.skew(sx, sy); |
| _addCommand(CkSkewCommand(sx, sy)); |
| } |
| |
| @override |
| void transform(Float32List matrix4) { |
| super.transform(matrix4); |
| _addCommand(CkTransformCommand(matrix4)); |
| } |
| |
| @override |
| void translate(double dx, double dy) { |
| super.translate(dx, dy); |
| _addCommand(CkTranslateCommand(dx, dy)); |
| } |
| } |
| |
| class CkPictureSnapshot { |
| CkPictureSnapshot(this._bounds); |
| |
| final ui.Rect _bounds; |
| final List<CkPaintCommand> _commands = <CkPaintCommand>[]; |
| |
| SkPicture toPicture() { |
| final SkPictureRecorder recorder = SkPictureRecorder(); |
| final Float32List skRect = toSkRect(_bounds); |
| final SkCanvas skCanvas = recorder.beginRecording(skRect); |
| for (final CkPaintCommand command in _commands) { |
| command.apply(skCanvas); |
| } |
| final SkPicture skPicture = recorder.finishRecordingAsPicture(); |
| recorder.delete(); |
| return skPicture; |
| } |
| |
| void dispose() { |
| for (final CkPaintCommand command in _commands) { |
| command.dispose(); |
| } |
| } |
| } |
| |
| /// A paint command recorded by [RecordingCkCanvas]. |
| /// |
| /// # Special rules when drawing images |
| /// |
| /// A command painting an image must clone the original image to bump the ref |
| /// count. Otherwise when the framework decides it doesn't need the image any |
| /// more it will bump the ref count down and delete the underlying Skia object, |
| /// leaving the picture that recorded this paint command with a dangling |
| /// pointer. If we attempt to resurrect the picture we'll hit a use-after-free |
| /// error. The command must call [CkImage.dispose] in its [dispose] |
| /// implementation. |
| abstract class CkPaintCommand { |
| const CkPaintCommand(); |
| |
| /// Applies the command onto the [canvas]. |
| void apply(SkCanvas canvas); |
| |
| /// Frees resources associated with the command. |
| void dispose() {} |
| } |
| |
| class CkClearCommand extends CkPaintCommand { |
| const CkClearCommand(this.color); |
| |
| final ui.Color color; |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.clear(toSharedSkColor1(color)); |
| } |
| } |
| |
| class CkSaveCommand extends CkPaintCommand { |
| const CkSaveCommand(); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.save(); |
| } |
| } |
| |
| class CkRestoreCommand extends CkPaintCommand { |
| const CkRestoreCommand(); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.restore(); |
| } |
| } |
| |
| class CkRestoreToCountCommand extends CkPaintCommand { |
| const CkRestoreToCountCommand(this.count); |
| |
| final int count; |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.restoreToCount(count); |
| } |
| } |
| |
| class CkTranslateCommand extends CkPaintCommand { |
| final double dx; |
| final double dy; |
| |
| CkTranslateCommand(this.dx, this.dy); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.translate(dx, dy); |
| } |
| } |
| |
| class CkScaleCommand extends CkPaintCommand { |
| final double sx; |
| final double sy; |
| |
| CkScaleCommand(this.sx, this.sy); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.scale(sx, sy); |
| } |
| } |
| |
| class CkRotateCommand extends CkPaintCommand { |
| final double radians; |
| |
| CkRotateCommand(this.radians); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.rotate(radians * 180.0 / math.pi, 0.0, 0.0); |
| } |
| } |
| |
| class CkTransformCommand extends CkPaintCommand { |
| final Float32List matrix4; |
| |
| CkTransformCommand(this.matrix4); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.concat(toSkMatrixFromFloat32(matrix4)); |
| } |
| } |
| |
| class CkSkewCommand extends CkPaintCommand { |
| final double sx; |
| final double sy; |
| |
| CkSkewCommand(this.sx, this.sy); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.skew(sx, sy); |
| } |
| } |
| |
| class CkClipRectCommand extends CkPaintCommand { |
| final ui.Rect rect; |
| final ui.ClipOp clipOp; |
| final bool doAntiAlias; |
| |
| CkClipRectCommand(this.rect, this.clipOp, this.doAntiAlias); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.clipRect( |
| toSkRect(rect), |
| toSkClipOp(clipOp), |
| doAntiAlias, |
| ); |
| } |
| } |
| |
| class CkDrawArcCommand extends CkPaintCommand { |
| CkDrawArcCommand( |
| this.oval, this.startAngle, this.sweepAngle, this.useCenter, this.paint); |
| |
| final ui.Rect oval; |
| final double startAngle; |
| final double sweepAngle; |
| final bool useCenter; |
| final CkPaint paint; |
| |
| @override |
| void apply(SkCanvas canvas) { |
| const double toDegrees = 180 / math.pi; |
| canvas.drawArc( |
| toSkRect(oval), |
| startAngle * toDegrees, |
| sweepAngle * toDegrees, |
| useCenter, |
| paint.skiaObject, |
| ); |
| } |
| } |
| |
| class CkDrawAtlasCommand extends CkPaintCommand { |
| CkDrawAtlasCommand(this.paint, this.atlas, this.rstTransforms, this.rects, |
| this.colors, this.blendMode); |
| |
| final CkPaint paint; |
| final CkImage atlas; |
| final Float32List rstTransforms; |
| final Float32List rects; |
| final Uint32List? colors; |
| final ui.BlendMode blendMode; |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawAtlas( |
| atlas.skImage, |
| rects, |
| rstTransforms, |
| paint.skiaObject, |
| toSkBlendMode(blendMode), |
| colors, |
| ); |
| } |
| } |
| |
| class CkClipRRectCommand extends CkPaintCommand { |
| final ui.RRect rrect; |
| final bool doAntiAlias; |
| |
| CkClipRRectCommand(this.rrect, this.doAntiAlias); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.clipRRect( |
| toSkRRect(rrect), |
| _clipOpIntersect, |
| doAntiAlias, |
| ); |
| } |
| } |
| |
| class CkClipPathCommand extends CkPaintCommand { |
| final CkPath path; |
| final bool doAntiAlias; |
| |
| CkClipPathCommand(this.path, this.doAntiAlias); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.clipPath( |
| path.skiaObject, |
| _clipOpIntersect, |
| doAntiAlias, |
| ); |
| } |
| } |
| |
| class CkDrawColorCommand extends CkPaintCommand { |
| final ui.Color color; |
| final ui.BlendMode blendMode; |
| |
| CkDrawColorCommand(this.color, this.blendMode); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawColorInt( |
| color.value, |
| toSkBlendMode(blendMode), |
| ); |
| } |
| } |
| |
| class CkDrawLineCommand extends CkPaintCommand { |
| final ui.Offset p1; |
| final ui.Offset p2; |
| final CkPaint paint; |
| |
| CkDrawLineCommand(this.p1, this.p2, this.paint); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawLine( |
| p1.dx, |
| p1.dy, |
| p2.dx, |
| p2.dy, |
| paint.skiaObject, |
| ); |
| } |
| } |
| |
| class CkDrawPaintCommand extends CkPaintCommand { |
| final CkPaint paint; |
| |
| CkDrawPaintCommand(this.paint); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawPaint(paint.skiaObject); |
| } |
| } |
| |
| class CkDrawVerticesCommand extends CkPaintCommand { |
| final CkVertices vertices; |
| final ui.BlendMode blendMode; |
| final CkPaint paint; |
| CkDrawVerticesCommand(this.vertices, this.blendMode, this.paint); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawVertices( |
| vertices.skiaObject, |
| toSkBlendMode(blendMode), |
| paint.skiaObject, |
| ); |
| } |
| } |
| |
| class CkDrawPointsCommand extends CkPaintCommand { |
| final Float32List points; |
| final ui.PointMode pointMode; |
| final CkPaint paint; |
| CkDrawPointsCommand(this.pointMode, this.points, this.paint); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawPoints( |
| toSkPointMode(pointMode), |
| points, |
| paint.skiaObject, |
| ); |
| } |
| } |
| |
| class CkDrawRectCommand extends CkPaintCommand { |
| final ui.Rect rect; |
| final CkPaint paint; |
| |
| CkDrawRectCommand(this.rect, this.paint); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawRect(toSkRect(rect), paint.skiaObject); |
| } |
| } |
| |
| class CkDrawRRectCommand extends CkPaintCommand { |
| final ui.RRect rrect; |
| final CkPaint paint; |
| |
| CkDrawRRectCommand(this.rrect, this.paint); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawRRect( |
| toSkRRect(rrect), |
| paint.skiaObject, |
| ); |
| } |
| } |
| |
| class CkDrawDRRectCommand extends CkPaintCommand { |
| final ui.RRect outer; |
| final ui.RRect inner; |
| final CkPaint paint; |
| |
| CkDrawDRRectCommand(this.outer, this.inner, this.paint); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawDRRect( |
| toSkRRect(outer), |
| toSkRRect(inner), |
| paint.skiaObject, |
| ); |
| } |
| } |
| |
| class CkDrawOvalCommand extends CkPaintCommand { |
| final ui.Rect rect; |
| final CkPaint paint; |
| |
| CkDrawOvalCommand(this.rect, this.paint); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawOval( |
| toSkRect(rect), |
| paint.skiaObject, |
| ); |
| } |
| } |
| |
| class CkDrawCircleCommand extends CkPaintCommand { |
| final ui.Offset c; |
| final double radius; |
| final CkPaint paint; |
| |
| CkDrawCircleCommand(this.c, this.radius, this.paint); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawCircle( |
| c.dx, |
| c.dy, |
| radius, |
| paint.skiaObject, |
| ); |
| } |
| } |
| |
| class CkDrawPathCommand extends CkPaintCommand { |
| final CkPath path; |
| final CkPaint paint; |
| |
| CkDrawPathCommand(this.path, this.paint); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawPath(path.skiaObject, paint.skiaObject); |
| } |
| } |
| |
| class CkDrawShadowCommand extends CkPaintCommand { |
| CkDrawShadowCommand( |
| this.path, this.color, this.elevation, this.transparentOccluder); |
| |
| final CkPath path; |
| final ui.Color color; |
| final double elevation; |
| final bool transparentOccluder; |
| |
| @override |
| void apply(SkCanvas canvas) { |
| drawSkShadow(canvas, path, color, elevation, transparentOccluder, |
| ui.window.devicePixelRatio); |
| } |
| } |
| |
| class CkDrawImageCommand extends CkPaintCommand { |
| final CkImage image; |
| final ui.Offset offset; |
| final CkPaint paint; |
| |
| CkDrawImageCommand(CkImage ckImage, this.offset, this.paint) |
| : image = ckImage.clone(); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| final ui.FilterQuality filterQuality = paint.filterQuality; |
| if (filterQuality == ui.FilterQuality.high) { |
| canvas.drawImageCubic( |
| image.skImage, |
| offset.dx, |
| offset.dy, |
| CkCanvas._kMitchellNetravali_B, |
| CkCanvas._kMitchellNetravali_C, |
| paint.skiaObject, |
| ); |
| } else { |
| canvas.drawImageOptions( |
| image.skImage, |
| offset.dx, |
| offset.dy, |
| toSkFilterMode(filterQuality), |
| toSkMipmapMode(filterQuality), |
| paint.skiaObject, |
| ); |
| } |
| } |
| |
| @override |
| void dispose() { |
| image.dispose(); |
| } |
| } |
| |
| class CkDrawImageRectCommand extends CkPaintCommand { |
| final CkImage image; |
| final ui.Rect src; |
| final ui.Rect dst; |
| final CkPaint paint; |
| |
| CkDrawImageRectCommand(CkImage ckImage, this.src, this.dst, this.paint) |
| : image = ckImage.clone(); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| final ui.FilterQuality filterQuality = paint.filterQuality; |
| if (filterQuality == ui.FilterQuality.high) { |
| canvas.drawImageRectCubic( |
| image.skImage, |
| toSkRect(src), |
| toSkRect(dst), |
| CkCanvas._kMitchellNetravali_B, |
| CkCanvas._kMitchellNetravali_C, |
| paint.skiaObject, |
| ); |
| } else { |
| canvas.drawImageRectOptions( |
| image.skImage, |
| toSkRect(src), |
| toSkRect(dst), |
| toSkFilterMode(filterQuality), |
| toSkMipmapMode(filterQuality), |
| paint.skiaObject, |
| ); |
| } |
| } |
| |
| @override |
| void dispose() { |
| image.dispose(); |
| } |
| } |
| |
| class CkDrawImageNineCommand extends CkPaintCommand { |
| CkDrawImageNineCommand(CkImage ckImage, this.center, this.dst, this.paint) |
| : image = ckImage.clone(); |
| |
| final CkImage image; |
| final ui.Rect center; |
| final ui.Rect dst; |
| final CkPaint paint; |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawImageNine( |
| image.skImage, |
| toSkRect(center), |
| toSkRect(dst), |
| toSkFilterMode(paint.filterQuality), |
| paint.skiaObject, |
| ); |
| } |
| |
| @override |
| void dispose() { |
| image.dispose(); |
| } |
| } |
| |
| class CkDrawParagraphCommand extends CkPaintCommand { |
| final CkParagraph paragraph; |
| final ui.Offset offset; |
| |
| CkDrawParagraphCommand(this.paragraph, this.offset); |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawParagraph( |
| paragraph.skiaObject, |
| offset.dx, |
| offset.dy, |
| ); |
| paragraph.markUsed(); |
| } |
| } |
| |
| class CkDrawPictureCommand extends CkPaintCommand { |
| CkDrawPictureCommand(this.picture); |
| |
| final CkPicture picture; |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.drawPicture(picture.skiaObject); |
| } |
| } |
| |
| class CkSaveLayerCommand extends CkPaintCommand { |
| CkSaveLayerCommand(this.bounds, this.paint); |
| |
| final ui.Rect bounds; |
| final CkPaint? paint; |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.saveLayer( |
| paint?.skiaObject, |
| toSkRect(bounds), |
| null, |
| null, |
| ); |
| } |
| } |
| |
| class CkSaveLayerWithoutBoundsCommand extends CkPaintCommand { |
| CkSaveLayerWithoutBoundsCommand(this.paint); |
| |
| final CkPaint? paint; |
| |
| @override |
| void apply(SkCanvas canvas) { |
| canvas.saveLayer( |
| paint?.skiaObject, |
| null, |
| null, |
| null, |
| ); |
| } |
| } |
| |
| class CkSaveLayerWithFilterCommand extends CkPaintCommand { |
| CkSaveLayerWithFilterCommand(this.bounds, this.filter, this.paint); |
| |
| final ui.Rect bounds; |
| final ui.ImageFilter filter; |
| final CkPaint? paint; |
| |
| @override |
| void apply(SkCanvas canvas) { |
| final CkManagedSkImageFilterConvertible convertible = |
| filter as CkManagedSkImageFilterConvertible; |
| return canvas.saveLayer( |
| paint?.skiaObject, |
| toSkRect(bounds), |
| convertible.imageFilter.skiaObject, |
| 0, |
| ); |
| } |
| } |