Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[web:canvaskit] switch to temporary SkPaint objects #54818

Merged
merged 4 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions lib/web_ui/lib/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -325,14 +325,6 @@ abstract class Paint {
factory Paint() => engine.renderer.createPaint();

factory Paint.from(Paint other) {
// This is less efficient than copying the underlying buffer or object but
// it's a reasonable default, as if a user wanted to implement a copy of a
// paint object themselves they are unable to do much better than this.
//
// TODO(matanlurey): Web team, if important to optimize, could:
// 1. Add a `engine.renderer.copyPaint` method.
// 2. Use the below code as the default implementation.
// 3. Have renderer-specific implementations override with optimized code.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this comment because all the setters are cheap now.

final Paint paint = Paint();
paint
..blendMode = other.blendMode
Expand Down
79 changes: 58 additions & 21 deletions lib/web_ui/lib/src/engine/canvaskit/canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,16 @@ class CkCanvas {
CkPaint paint,
) {
const double toDegrees = 180 / math.pi;

final skPaint = paint.toSkPaint();
skCanvas.drawArc(
toSkRect(oval),
startAngle * toDegrees,
sweepAngle * toDegrees,
useCenter,
paint.skiaObject,
skPaint,
);
skPaint.delete();
}

// TODO(flar): CanvasKit does not expose sampling options available on SkCanvas.drawAtlas
Expand All @@ -98,23 +101,27 @@ class CkCanvas {
Uint32List? colors,
ui.BlendMode blendMode,
) {
final skPaint = paint.toSkPaint();
skCanvas.drawAtlas(
atlas.skImage,
rects,
rstTransforms,
paint.skiaObject,
skPaint,
toSkBlendMode(blendMode),
colors,
);
skPaint.delete();
}

void drawCircle(ui.Offset c, double radius, CkPaint paint) {
final skPaint = paint.toSkPaint();
skCanvas.drawCircle(
c.dx,
c.dy,
radius,
paint.skiaObject,
skPaint,
);
skPaint.delete();
}

void drawColor(ui.Color color, ui.BlendMode blendMode) {
Expand All @@ -125,23 +132,26 @@ class CkCanvas {
}

void drawDRRect(ui.RRect outer, ui.RRect inner, CkPaint paint) {
final skPaint = paint.toSkPaint();
skCanvas.drawDRRect(
toSkRRect(outer),
toSkRRect(inner),
paint.skiaObject,
skPaint,
);
skPaint.delete();
}

void drawImage(CkImage image, ui.Offset offset, CkPaint paint) {
final ui.FilterQuality filterQuality = paint.filterQuality;
final skPaint = paint.toSkPaint();
if (filterQuality == ui.FilterQuality.high) {
skCanvas.drawImageCubic(
image.skImage,
offset.dx,
offset.dy,
_kMitchellNetravali_B,
_kMitchellNetravali_C,
paint.skiaObject,
skPaint,
);
} else {
skCanvas.drawImageOptions(
Expand All @@ -150,21 +160,23 @@ class CkCanvas {
offset.dy,
toSkFilterMode(filterQuality),
toSkMipmapMode(filterQuality),
paint.skiaObject,
skPaint,
);
}
skPaint.delete();
}

void drawImageRect(CkImage image, ui.Rect src, ui.Rect dst, CkPaint paint) {
final ui.FilterQuality filterQuality = paint.filterQuality;
final skPaint = paint.toSkPaint();
if (filterQuality == ui.FilterQuality.high) {
skCanvas.drawImageRectCubic(
image.skImage,
toSkRect(src),
toSkRect(dst),
_kMitchellNetravali_B,
_kMitchellNetravali_C,
paint.skiaObject,
skPaint,
);
} else {
skCanvas.drawImageRectOptions(
Expand All @@ -173,41 +185,50 @@ class CkCanvas {
toSkRect(dst),
toSkFilterMode(filterQuality),
toSkMipmapMode(filterQuality),
paint.skiaObject,
skPaint,
);
}
skPaint.delete();
}

void drawImageNine(
CkImage image, ui.Rect center, ui.Rect dst, CkPaint paint) {
final skPaint = paint.toSkPaint();
skCanvas.drawImageNine(
image.skImage,
toSkRect(center),
toSkRect(dst),
toSkFilterMode(paint.filterQuality),
paint.skiaObject,
skPaint,
);
skPaint.delete();
}

void drawLine(ui.Offset p1, ui.Offset p2, CkPaint paint) {
final skPaint = paint.toSkPaint();
skCanvas.drawLine(
p1.dx,
p1.dy,
p2.dx,
p2.dy,
paint.skiaObject,
skPaint,
);
skPaint.delete();
}

void drawOval(ui.Rect rect, CkPaint paint) {
final skPaint = paint.toSkPaint();
skCanvas.drawOval(
toSkRect(rect),
paint.skiaObject,
skPaint,
);
skPaint.delete();
}

void drawPaint(CkPaint paint) {
skCanvas.drawPaint(paint.skiaObject);
final skPaint = paint.toSkPaint();
skCanvas.drawPaint(skPaint);
skPaint.delete();
}

void drawParagraph(CkParagraph paragraph, ui.Offset offset) {
Expand All @@ -219,7 +240,9 @@ class CkCanvas {
}

void drawPath(CkPath path, CkPaint paint) {
skCanvas.drawPath(path.skiaObject, paint.skiaObject);
final skPaint = paint.toSkPaint();
skCanvas.drawPath(path.skiaObject, skPaint);
skPaint.delete();
}

void drawPicture(CkPicture picture) {
Expand All @@ -228,22 +251,28 @@ class CkCanvas {
}

void drawPoints(CkPaint paint, ui.PointMode pointMode, Float32List points) {
final skPaint = paint.toSkPaint();
skCanvas.drawPoints(
toSkPointMode(pointMode),
points,
paint.skiaObject,
skPaint,
);
skPaint.delete();
}

void drawRRect(ui.RRect rrect, CkPaint paint) {
final skPaint = paint.toSkPaint();
skCanvas.drawRRect(
toSkRRect(rrect),
paint.skiaObject,
skPaint,
);
skPaint.delete();
}

void drawRect(ui.Rect rect, CkPaint paint) {
skCanvas.drawRect(toSkRect(rect), paint.skiaObject);
final skPaint = paint.toSkPaint();
skCanvas.drawRect(toSkRect(rect), skPaint);
skPaint.delete();
}

void drawShadow(
Expand All @@ -254,11 +283,13 @@ class CkCanvas {

void drawVertices(
CkVertices vertices, ui.BlendMode blendMode, CkPaint paint) {
final skPaint = paint.toSkPaint();
skCanvas.drawVertices(
vertices.skiaObject,
toSkBlendMode(blendMode),
paint.skiaObject,
skPaint,
);
skPaint.delete();
}

void restore() {
Expand All @@ -278,16 +309,20 @@ class CkCanvas {
}

void saveLayer(ui.Rect bounds, CkPaint? paint) {
final skPaint = paint?.toSkPaint();
skCanvas.saveLayer(
paint?.skiaObject,
skPaint,
toSkRect(bounds),
null,
null,
);
skPaint?.delete();
}

void saveLayerWithoutBounds(CkPaint? paint) {
skCanvas.saveLayer(paint?.skiaObject, null, null, null);
final skPaint = paint?.toSkPaint();
skCanvas.saveLayer(skPaint, null, null, null);
skPaint?.delete();
}

void saveLayerWithFilter(ui.Rect bounds, ui.ImageFilter filter,
Expand All @@ -298,13 +333,15 @@ class CkCanvas {
} else {
convertible = filter as CkManagedSkImageFilterConvertible;
}
convertible.imageFilter((SkImageFilter filter) {
convertible.withSkImageFilter((SkImageFilter filter) {
final skPaint = paint?.toSkPaint();
skCanvas.saveLayer(
paint?.skiaObject,
skPaint,
toSkRect(bounds),
filter,
0,
);
skPaint?.delete();
});
}

Expand Down
3 changes: 3 additions & 0 deletions lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1516,6 +1516,9 @@ class SkImageFilter {}
extension SkImageFilterExtension on SkImageFilter {
external JSVoid delete();

@JS('isDeleted')
external JSBoolean _isDeleted();
bool isDeleted() => _isDeleted().toDart;

@JS('getOutputBounds')
external JSInt32Array _getOutputBounds(JSFloat32Array bounds);
Expand Down
2 changes: 1 addition & 1 deletion lib/web_ui/lib/src/engine/canvaskit/color_filter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ abstract class CkColorFilter implements CkManagedSkImageFilterConvertible {
SkColorFilter _initRawColorFilter();

@override
void imageFilter(SkImageFilterBorrow borrow) {
void withSkImageFilter(SkImageFilterBorrow borrow) {
// Since ColorFilter has a const constructor it cannot store dynamically
// created Skia objects. Therefore a new SkImageFilter is created every time
// it's used. However, once used it's no longer needed, so it's deleted
Expand Down
1 change: 0 additions & 1 deletion lib/web_ui/lib/src/engine/canvaskit/image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,6 @@ CkImage scaleImage(SkImage image, int? targetWidth, int? targetHeight) {
ui.Rect.fromLTWH(0, 0, targetWidth!.toDouble(), targetHeight!.toDouble()),
paint,
);
paint.dispose();

final CkPicture picture = recorder.endRecording();
final ui.Image finalImage = picture.toImageSync(targetWidth, targetHeight);
Expand Down
Loading