blob: 9f5c379c37d529ec096de6ebdc25c3683a6f9a5e [file] [log] [blame]
// 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.
// @dart = 2.6
part of engine;
/// An implementation of [ui.Canvas] that is backed by a CanvasKit canvas.
class CanvasKitCanvas implements ui.Canvas {
final SkCanvas _canvas;
factory CanvasKitCanvas(ui.PictureRecorder recorder, [ui.Rect cullRect]) {
assert(recorder != null);
if (recorder.isRecording) {
throw ArgumentError(
'"recorder" must not already be associated with another Canvas.');
}
cullRect ??= ui.Rect.largest;
final SkPictureRecorder skRecorder = recorder;
return CanvasKitCanvas._(skRecorder.beginRecording(cullRect));
}
CanvasKitCanvas._(this._canvas);
@override
void save() {
_canvas.save();
}
@override
void saveLayer(ui.Rect bounds, ui.Paint paint) {
assert(paint != null);
if (bounds == null) {
_saveLayerWithoutBounds(paint);
} else {
assert(rectIsValid(bounds));
_saveLayer(bounds, paint);
}
}
void _saveLayerWithoutBounds(ui.Paint paint) {
_canvas.saveLayerWithoutBounds(paint);
}
void _saveLayer(ui.Rect bounds, ui.Paint paint) {
_canvas.saveLayer(bounds, paint);
}
@override
void restore() {
_canvas.restore();
}
@override
int getSaveCount() {
return _canvas.saveCount;
}
@override
void translate(double dx, double dy) {
_canvas.translate(dx, dy);
}
@override
void scale(double sx, [double sy]) => _scale(sx, sy ?? sx);
void _scale(double sx, double sy) {
_canvas.scale(sx, sy);
}
@override
void rotate(double radians) {
_canvas.rotate(radians);
}
@override
void skew(double sx, double sy) {
_canvas.skew(sx, sy);
}
@override
void transform(Float64List matrix4) {
assert(matrix4 != null);
if (matrix4.length != 16) {
throw ArgumentError('"matrix4" must have 16 entries.');
}
_transform(toMatrix32(matrix4));
}
void _transform(Float32List matrix4) {
_canvas.transform(matrix4);
}
@override
void clipRect(ui.Rect rect,
{ui.ClipOp clipOp = ui.ClipOp.intersect, bool doAntiAlias = true}) {
assert(rectIsValid(rect));
assert(clipOp != null);
assert(doAntiAlias != null);
_clipRect(rect, clipOp, doAntiAlias);
}
void _clipRect(ui.Rect rect, ui.ClipOp clipOp, bool doAntiAlias) {
_canvas.clipRect(rect, clipOp, doAntiAlias);
}
@override
void clipRRect(ui.RRect rrect, {bool doAntiAlias = true}) {
assert(rrectIsValid(rrect));
assert(doAntiAlias != null);
_clipRRect(rrect, doAntiAlias);
}
void _clipRRect(ui.RRect rrect, bool doAntiAlias) {
_canvas.clipRRect(rrect, doAntiAlias);
}
@override
void clipPath(ui.Path path, {bool doAntiAlias = true}) {
assert(path != null); // path is checked on the engine side
assert(doAntiAlias != null);
_clipPath(path, doAntiAlias);
}
void _clipPath(ui.Path path, bool doAntiAlias) {
_canvas.clipPath(path, doAntiAlias);
}
@override
void drawColor(ui.Color color, ui.BlendMode blendMode) {
assert(color != null);
assert(blendMode != null);
_drawColor(color, blendMode);
}
void _drawColor(ui.Color color, ui.BlendMode blendMode) {
_canvas.drawColor(color, blendMode);
}
@override
void drawLine(ui.Offset p1, ui.Offset p2, ui.Paint paint) {
assert(_offsetIsValid(p1));
assert(_offsetIsValid(p2));
assert(paint != null);
_drawLine(p1, p2, paint);
}
void _drawLine(ui.Offset p1, ui.Offset p2, ui.Paint paint) {
_canvas.drawLine(p1, p2, paint);
}
@override
void drawPaint(ui.Paint paint) {
assert(paint != null);
_drawPaint(paint);
}
void _drawPaint(ui.Paint paint) {
_canvas.drawPaint(paint);
}
@override
void drawRect(ui.Rect rect, ui.Paint paint) {
assert(rectIsValid(rect));
assert(paint != null);
_drawRect(rect, paint);
}
void _drawRect(ui.Rect rect, ui.Paint paint) {
_canvas.drawRect(rect, paint);
}
@override
void drawRRect(ui.RRect rrect, ui.Paint paint) {
assert(rrectIsValid(rrect));
assert(paint != null);
_drawRRect(rrect, paint);
}
void _drawRRect(ui.RRect rrect, ui.Paint paint) {
_canvas.drawRRect(rrect, paint);
}
@override
void drawDRRect(ui.RRect outer, ui.RRect inner, ui.Paint paint) {
assert(rrectIsValid(outer));
assert(rrectIsValid(inner));
assert(paint != null);
_drawDRRect(outer, inner, paint);
}
void _drawDRRect(ui.RRect outer, ui.RRect inner, ui.Paint paint) {
_canvas.drawDRRect(outer, inner, paint);
}
@override
void drawOval(ui.Rect rect, ui.Paint paint) {
assert(rectIsValid(rect));
assert(paint != null);
_drawOval(rect, paint);
}
void _drawOval(ui.Rect rect, ui.Paint paint) {
_canvas.drawOval(rect, paint);
}
@override
void drawCircle(ui.Offset c, double radius, ui.Paint paint) {
assert(_offsetIsValid(c));
assert(paint != null);
_drawCircle(c, radius, paint);
}
void _drawCircle(ui.Offset c, double radius, ui.Paint paint) {
_canvas.drawCircle(c, radius, paint);
}
@override
void drawArc(ui.Rect rect, double startAngle, double sweepAngle,
bool useCenter, ui.Paint paint) {
assert(rectIsValid(rect));
assert(paint != null);
_drawArc(rect, startAngle, sweepAngle, useCenter, paint);
}
void _drawArc(ui.Rect rect, double startAngle, double sweepAngle,
bool useCenter, ui.Paint paint) {
_canvas.drawArc(rect, startAngle, sweepAngle, useCenter, paint);
}
@override
void drawPath(ui.Path path, ui.Paint paint) {
assert(path != null); // path is checked on the engine side
assert(paint != null);
_drawPath(path, paint);
}
void _drawPath(ui.Path path, ui.Paint paint) {
_canvas.drawPath(path, paint);
}
@override
void drawImage(ui.Image image, ui.Offset p, ui.Paint paint) {
assert(image != null); // image is checked on the engine side
assert(_offsetIsValid(p));
assert(paint != null);
_drawImage(image, p, paint);
}
void _drawImage(ui.Image image, ui.Offset p, ui.Paint paint) {
_canvas.drawImage(image, p, paint);
}
@override
void drawImageRect(ui.Image image, ui.Rect src, ui.Rect dst, ui.Paint paint) {
assert(image != null); // image is checked on the engine side
assert(rectIsValid(src));
assert(rectIsValid(dst));
assert(paint != null);
_drawImageRect(image, src, dst, paint);
}
void _drawImageRect(
ui.Image image, ui.Rect src, ui.Rect dst, ui.Paint paint) {
_canvas.drawImageRect(image, src, dst, paint);
}
@override
void drawImageNine(
ui.Image image, ui.Rect center, ui.Rect dst, ui.Paint paint) {
assert(image != null); // image is checked on the engine side
assert(rectIsValid(center));
assert(rectIsValid(dst));
assert(paint != null);
_drawImageNine(image, center, dst, paint);
}
void _drawImageNine(
ui.Image image, ui.Rect center, ui.Rect dst, ui.Paint paint) {
_canvas.drawImageNine(image, center, dst, paint);
}
@override
void drawPicture(ui.Picture picture) {
assert(picture != null); // picture is checked on the engine side
_drawPicture(picture);
}
void _drawPicture(ui.Picture picture) {
_canvas.drawPicture(picture);
}
@override
void drawParagraph(ui.Paragraph paragraph, ui.Offset offset) {
assert(paragraph != null);
assert(_offsetIsValid(offset));
_drawParagraph(paragraph, offset);
}
void _drawParagraph(ui.Paragraph paragraph, ui.Offset offset) {
_canvas.drawParagraph(paragraph, offset);
}
@override
void drawPoints(
ui.PointMode pointMode, List<ui.Offset> points, ui.Paint paint) {
assert(pointMode != null);
assert(points != null);
assert(paint != null);
_drawPoints(paint, pointMode, encodePointList(points));
}
@override
void drawRawPoints(
ui.PointMode pointMode, Float32List points, ui.Paint paint) {
assert(pointMode != null);
assert(points != null);
assert(paint != null);
if (points.length % 2 != 0) {
throw ArgumentError('"points" must have an even number of values.');
}
_drawPoints(paint, pointMode, points);
}
void _drawPoints(ui.Paint paint, ui.PointMode pointMode, Float32List points) {
_canvas.drawPoints(paint, pointMode, points);
}
@override
void drawVertices(
ui.Vertices vertices, ui.BlendMode blendMode, ui.Paint paint) {
assert(vertices != null); // vertices is checked on the engine side
assert(paint != null);
assert(blendMode != null);
_drawVertices(vertices, blendMode, paint);
}
void _drawVertices(
ui.Vertices vertices, ui.BlendMode blendMode, ui.Paint paint) {
_canvas.drawVertices(vertices, blendMode, paint);
}
@override
void drawAtlas(
ui.Image atlas,
List<ui.RSTransform> transforms,
List<ui.Rect> rects,
List<ui.Color> colors,
ui.BlendMode blendMode,
ui.Rect cullRect,
ui.Paint paint) {
assert(atlas != null); // atlas is checked on the engine side
assert(transforms != null);
assert(rects != null);
assert(colors != null);
assert(blendMode != null);
assert(paint != null);
final int rectCount = rects.length;
if (transforms.length != rectCount) {
throw ArgumentError('"transforms" and "rects" lengths must match.');
}
if (colors.isNotEmpty && colors.length != rectCount) {
throw ArgumentError(
'If non-null, "colors" length must match that of "transforms" and "rects".');
}
final Float32List rstTransformBuffer = Float32List(rectCount * 4);
final Float32List rectBuffer = Float32List(rectCount * 4);
for (int i = 0; i < rectCount; ++i) {
final int index0 = i * 4;
final int index1 = index0 + 1;
final int index2 = index0 + 2;
final int index3 = index0 + 3;
final ui.RSTransform rstTransform = transforms[i];
final ui.Rect rect = rects[i];
assert(rectIsValid(rect));
rstTransformBuffer[index0] = rstTransform.scos;
rstTransformBuffer[index1] = rstTransform.ssin;
rstTransformBuffer[index2] = rstTransform.tx;
rstTransformBuffer[index3] = rstTransform.ty;
rectBuffer[index0] = rect.left;
rectBuffer[index1] = rect.top;
rectBuffer[index2] = rect.right;
rectBuffer[index3] = rect.bottom;
}
final Int32List colorBuffer =
colors.isEmpty ? null : _encodeColorList(colors);
_drawAtlas(
paint, atlas, rstTransformBuffer, rectBuffer, colorBuffer, blendMode);
}
@override
void drawRawAtlas(
ui.Image atlas,
Float32List rstTransforms,
Float32List rects,
Int32List colors,
ui.BlendMode blendMode,
ui.Rect cullRect,
ui.Paint paint) {
assert(atlas != null); // atlas is checked on the engine side
assert(rstTransforms != null);
assert(rects != null);
assert(colors != null);
assert(blendMode != null);
assert(paint != null);
final int rectCount = rects.length;
if (rstTransforms.length != rectCount)
throw ArgumentError('"rstTransforms" and "rects" lengths must match.');
if (rectCount % 4 != 0)
throw ArgumentError(
'"rstTransforms" and "rects" lengths must be a multiple of four.');
if (colors != null && colors.length * 4 != rectCount)
throw ArgumentError(
'If non-null, "colors" length must be one fourth the length of "rstTransforms" and "rects".');
_drawAtlas(paint, atlas, rstTransforms, rects, colors, blendMode);
}
// TODO(hterkelsen): Pass a cull_rect once CanvasKit supports that.
void _drawAtlas(
ui.Paint paint,
ui.Image atlas,
Float32List rstTransforms,
Float32List rects,
Int32List colors,
ui.BlendMode blendMode,
) {
_canvas.drawAtlasRaw(paint, atlas, rstTransforms, rects, colors, blendMode);
}
@override
void drawShadow(ui.Path path, ui.Color color, double elevation,
bool transparentOccluder) {
assert(path != null); // path is checked on the engine side
assert(color != null);
assert(transparentOccluder != null);
_drawShadow(path, color, elevation, transparentOccluder);
}
void _drawShadow(ui.Path path, ui.Color color, double elevation,
bool transparentOccluder) {
_canvas.drawShadow(path, color, elevation, transparentOccluder);
}
}