Skip to content

Commit 7e6d582

Browse files
ferhatbfilmil
authored andcommitted
[web] Update CanvasPool documentation (flutter#27823)
1 parent 955dfb1 commit 7e6d582

File tree

2 files changed

+87
-40
lines changed

2 files changed

+87
-40
lines changed

lib/web_ui/lib/src/engine/canvas_pool.dart

Lines changed: 84 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,37 @@ class CanvasPool extends _SaveStackTracking {
5454
// List of canvases available to reuse from prior paint cycle.
5555
List<html.CanvasElement>? _reusablePool;
5656
// Current canvas element or null if marked for lazy allocation.
57-
html.CanvasElement? get canvas => _canvas;
5857
html.CanvasElement? _canvas;
5958

6059
html.HtmlElement? _rootElement;
6160
int _saveContextCount = 0;
6261
final double _density;
6362

63+
/// Initializes canvas pool for target size and dpi.
6464
CanvasPool(this._widthInBitmapPixels, this._heightInBitmapPixels,
6565
this._density);
6666

67+
/// Initializes canvas pool to be hosted on a surface.
68+
void mount(html.HtmlElement rootElement) {
69+
_rootElement = rootElement;
70+
}
71+
72+
/// Sets the translate transform to be applied to canvas to compensate for
73+
/// pixel padding applied to hosting [BitmapCanvas].
74+
///
75+
/// Should be called during initialization after [CanvasPool] is mounted.
76+
set initialTransform(ui.Offset transform) {
77+
translate(transform.dx, transform.dy);
78+
}
79+
80+
/// Returns true if no canvas has been allocated yet.
81+
bool get isEmpty => _canvas == null;
82+
83+
/// Returns true if a canvas has been allocated for use.
84+
bool get isNotEmpty => _canvas != null;
85+
86+
87+
/// Returns [CanvasRenderingContext2D] api to draw into this canvas.
6788
html.CanvasRenderingContext2D get context {
6889
html.CanvasRenderingContext2D? ctx = _context;
6990
if (ctx == null) {
@@ -75,6 +96,8 @@ class CanvasPool extends _SaveStackTracking {
7596
return ctx;
7697
}
7798

99+
/// Returns [ContextStateHandle] API to efficiently update state of
100+
/// drawing context.
78101
ContextStateHandle get contextHandle {
79102
if (_canvas == null) {
80103
_createCanvas();
@@ -84,11 +107,11 @@ class CanvasPool extends _SaveStackTracking {
84107
return _contextHandle!;
85108
}
86109

87-
// Prevents active canvas to be used for rendering and prepares a new
88-
// canvas allocation on next drawing request that will require one.
89-
//
90-
// Saves current canvas so we can dispose
91-
// and replay the clip/transform stack on top of new canvas.
110+
/// Prevents active canvas to be used for rendering and prepares a new
111+
/// canvas allocation on next drawing request that will require one.
112+
///
113+
/// Saves current canvas so we can dispose
114+
/// and replay the clip/transform stack on top of new canvas.
92115
void closeCurrentCanvas() {
93116
assert(_rootElement != null);
94117
// Place clean copy of current canvas with context stack restored and paint
@@ -104,10 +127,6 @@ class CanvasPool extends _SaveStackTracking {
104127
}
105128
}
106129

107-
void allocateCanvas(html.HtmlElement rootElement) {
108-
_rootElement = rootElement;
109-
}
110-
111130
void _createCanvas() {
112131
bool requiresClearRect = false;
113132
bool reused = false;
@@ -227,11 +246,6 @@ class CanvasPool extends _SaveStackTracking {
227246
}
228247
}
229248
reuse();
230-
resetTransform();
231-
}
232-
233-
set initialTransform(ui.Offset transform) {
234-
translate(transform.dx, transform.dy);
235249
}
236250

237251
int _replaySingleSaveEntry(int clipDepth, Matrix4 prevTransform,
@@ -311,7 +325,7 @@ class CanvasPool extends _SaveStackTracking {
311325
clipDepth, prevTransform, _currentTransform, clipStack);
312326
}
313327

314-
// Marks this pool for reuse.
328+
/// Marks this pool for reuse.
315329
void reuse() {
316330
if (_canvas != null) {
317331
_restoreContextSave();
@@ -326,8 +340,11 @@ class CanvasPool extends _SaveStackTracking {
326340
_canvas = null;
327341
_context = null;
328342
_contextHandle = null;
343+
_resetTransform();
329344
}
330345

346+
/// Signals to canvas pool the end of drawing commands so cached resources
347+
/// that are reused from last instance can be cleanup.
331348
void endOfPaint() {
332349
if (_reusablePool != null) {
333350
for (final html.CanvasElement e in _reusablePool!) {
@@ -375,16 +392,16 @@ class CanvasPool extends _SaveStackTracking {
375392
double get dpi =>
376393
EnginePlatformDispatcher.browserDevicePixelRatio * _density;
377394

378-
void resetTransform() {
395+
void _resetTransform() {
379396
final html.CanvasElement? canvas = _canvas;
380397
if (canvas != null) {
381398
canvas.style.transformOrigin = '';
382399
canvas.style.transform = '';
383400
}
384401
}
385402

386-
// Returns a "data://" URI containing a representation of the image in this
387-
// canvas in PNG format.
403+
/// Returns a "data://" URI containing a representation of the image in this
404+
/// canvas in PNG format.
388405
String toDataUrl() => _canvas?.toDataUrl() ?? '';
389406

390407
@override
@@ -518,6 +535,7 @@ class CanvasPool extends _SaveStackTracking {
518535
}
519536
}
520537

538+
/// Fill a virtually infinite rect with a color and optional blendMode.
521539
void drawColor(ui.Color color, ui.BlendMode blendMode) {
522540
final html.CanvasRenderingContext2D ctx = context;
523541
contextHandle.blendMode = blendMode;
@@ -531,7 +549,7 @@ class CanvasPool extends _SaveStackTracking {
531549
ctx.fillRect(-10000, -10000, 20000, 20000);
532550
}
533551

534-
// Fill a virtually infinite rect with the color.
552+
/// Fill a virtually infinite rect with the color.
535553
void fill() {
536554
final html.CanvasRenderingContext2D ctx = context;
537555
ctx.beginPath();
@@ -540,6 +558,7 @@ class CanvasPool extends _SaveStackTracking {
540558
ctx.fillRect(-10000, -10000, 20000, 20000);
541559
}
542560

561+
/// Draws a line from [p1] to [p2].
543562
void strokeLine(ui.Offset p1, ui.Offset p2) {
544563
final html.CanvasRenderingContext2D ctx = context;
545564
ctx.beginPath();
@@ -554,6 +573,8 @@ class CanvasPool extends _SaveStackTracking {
554573
ctx.stroke();
555574
}
556575

576+
/// Draws a set of points with given radius, lines between points or
577+
/// a polygon.
557578
void drawPoints(ui.PointMode pointMode, Float32List points, double radius) {
558579
final html.CanvasRenderingContext2D ctx = context;
559580
final int len = points.length;
@@ -634,6 +655,19 @@ class CanvasPool extends _SaveStackTracking {
634655
}
635656
}
636657

658+
/// Draws a rectangle filled or stroked based on [style].
659+
void drawRect(ui.Rect rect, ui.PaintingStyle? style) {
660+
context.beginPath();
661+
final ui.Rect? shaderBounds = contextHandle._shaderBounds;
662+
if (shaderBounds == null) {
663+
context.rect(rect.left, rect.top, rect.width, rect.height);
664+
} else {
665+
context.rect(rect.left - shaderBounds.left, rect.top - shaderBounds.top,
666+
rect.width, rect.height);
667+
}
668+
contextHandle.paint(style);
669+
}
670+
637671
/// Applies path to drawing context, preparing for fill and other operations.
638672
///
639673
/// WARNING: Don't refactor _runPath/_runPathWithOffset. Latency sensitive
@@ -682,18 +716,7 @@ class CanvasPool extends _SaveStackTracking {
682716
}
683717
}
684718

685-
void drawRect(ui.Rect rect, ui.PaintingStyle? style) {
686-
context.beginPath();
687-
final ui.Rect? shaderBounds = contextHandle._shaderBounds;
688-
if (shaderBounds == null) {
689-
context.rect(rect.left, rect.top, rect.width, rect.height);
690-
} else {
691-
context.rect(rect.left - shaderBounds.left, rect.top - shaderBounds.top,
692-
rect.width, rect.height);
693-
}
694-
contextHandle.paint(style);
695-
}
696-
719+
/// Draws a rounded rectangle filled or stroked based on [style].
697720
void drawRRect(ui.RRect roundRect, ui.PaintingStyle? style) {
698721
final ui.Rect? shaderBounds = contextHandle._shaderBounds;
699722
RRectToCanvasRenderer(context).render(
@@ -702,6 +725,9 @@ class CanvasPool extends _SaveStackTracking {
702725
contextHandle.paint(style);
703726
}
704727

728+
/// Fills or strokes the area between [outer] and [inner] rounded rectangles.
729+
///
730+
/// Typically used to draw a thick round border.
705731
void drawDRRect(ui.RRect outer, ui.RRect inner, ui.PaintingStyle? style) {
706732
final RRectRenderer renderer = RRectToCanvasRenderer(context);
707733
final ui.Rect? shaderBounds = contextHandle._shaderBounds;
@@ -716,6 +742,7 @@ class CanvasPool extends _SaveStackTracking {
716742
contextHandle.paint(style);
717743
}
718744

745+
/// Draws an axis-aligned oval that fills the given axis-aligned rectangle.
719746
void drawOval(ui.Rect rect, ui.PaintingStyle? style) {
720747
context.beginPath();
721748
final ui.Rect? shaderBounds = contextHandle._shaderBounds;
@@ -728,6 +755,7 @@ class CanvasPool extends _SaveStackTracking {
728755
contextHandle.paint(style);
729756
}
730757

758+
/// Draws a circle centered at [c] with [radius].
731759
void drawCircle(ui.Offset c, double radius, ui.PaintingStyle? style) {
732760
context.beginPath();
733761
final ui.Rect? shaderBounds = contextHandle._shaderBounds;
@@ -737,6 +765,7 @@ class CanvasPool extends _SaveStackTracking {
737765
contextHandle.paint(style);
738766
}
739767

768+
/// Draws or strokes a path based on [style] and current context state.
740769
void drawPath(ui.Path path, ui.PaintingStyle? style) {
741770
final ui.Rect? shaderBounds = contextHandle._shaderBounds;
742771
if (shaderBounds == null) {
@@ -748,6 +777,7 @@ class CanvasPool extends _SaveStackTracking {
748777
contextHandle.paintPath(style, path.fillType);
749778
}
750779

780+
/// Draws a shadow for a Path representing the given material elevation.
751781
void drawShadow(ui.Path path, ui.Color color, double elevation,
752782
bool transparentOccluder) {
753783
final SurfaceShadowData? shadow = computeShadow(path.getBounds(), elevation);
@@ -810,6 +840,11 @@ class CanvasPool extends _SaveStackTracking {
810840
}
811841
}
812842

843+
/// Disposes html canvas element(s) used by this pool when persistent surface
844+
/// is disposed.
845+
///
846+
/// When this pool is reused, [clear] is called instead to be able to
847+
/// draw using existing canvas elements.
813848
void dispose() {
814849
// Webkit has a threshold for the amount of canvas pixels an app can
815850
// allocate. Even though our canvases are being garbage-collected as
@@ -836,16 +871,18 @@ class CanvasPool extends _SaveStackTracking {
836871
}
837872
}
838873

839-
// Optimizes applying paint parameters to html canvas.
840-
//
841-
// See https://www.w3.org/TR/2dcontext/ for defaults used in this class
842-
// to initialize current values.
843-
//
874+
/// Optimizes applying paint parameters to html canvas.
875+
///
876+
/// See https://www.w3.org/TR/2dcontext/ for defaults used in this class
877+
/// to initialize current values.
844878
class ContextStateHandle {
879+
/// Associated canvas element context tracked by this context state.
845880
final html.CanvasRenderingContext2D context;
846881
final CanvasPool _canvasPool;
882+
/// Dpi of context.
847883
final double density;
848884

885+
/// Initializes context state for a [CanvasPool].
849886
ContextStateHandle(this._canvasPool, this.context, this.density);
850887
ui.BlendMode? _currentBlendMode = ui.BlendMode.srcOver;
851888
ui.StrokeCap? _currentStrokeCap = ui.StrokeCap.butt;
@@ -856,6 +893,7 @@ class ContextStateHandle {
856893
Object? _currentStrokeStyle;
857894
double _currentLineWidth = 1.0;
858895

896+
/// See [html.CanvasRenderingContext2D].
859897
set blendMode(ui.BlendMode? blendMode) {
860898
if (blendMode != _currentBlendMode) {
861899
_currentBlendMode = blendMode;
@@ -864,6 +902,7 @@ class ContextStateHandle {
864902
}
865903
}
866904

905+
/// See [html.CanvasRenderingContext2D].
867906
set strokeCap(ui.StrokeCap? strokeCap) {
868907
strokeCap ??= ui.StrokeCap.butt;
869908
if (strokeCap != _currentStrokeCap) {
@@ -872,13 +911,15 @@ class ContextStateHandle {
872911
}
873912
}
874913

914+
/// See [html.CanvasRenderingContext2D].
875915
set lineWidth(double lineWidth) {
876916
if (lineWidth != _currentLineWidth) {
877917
_currentLineWidth = lineWidth;
878918
context.lineWidth = lineWidth;
879919
}
880920
}
881921

922+
/// See [html.CanvasRenderingContext2D].
882923
set strokeJoin(ui.StrokeJoin? strokeJoin) {
883924
strokeJoin ??= ui.StrokeJoin.miter;
884925
if (strokeJoin != _currentStrokeJoin) {
@@ -887,13 +928,15 @@ class ContextStateHandle {
887928
}
888929
}
889930

931+
/// See [html.CanvasRenderingContext2D].
890932
set fillStyle(Object? colorOrGradient) {
891933
if (!identical(colorOrGradient, _currentFillStyle)) {
892934
_currentFillStyle = colorOrGradient;
893935
context.fillStyle = colorOrGradient;
894936
}
895937
}
896938

939+
/// See [html.CanvasRenderingContext2D].
897940
set strokeStyle(Object? colorOrGradient) {
898941
if (!identical(colorOrGradient, _currentStrokeStyle)) {
899942
_currentStrokeStyle = colorOrGradient;
@@ -1052,6 +1095,7 @@ class ContextStateHandle {
10521095
}
10531096
}
10541097

1098+
/// Fills or strokes the currently active path.
10551099
void paint(ui.PaintingStyle? style) {
10561100
if (style == ui.PaintingStyle.stroke) {
10571101
context.stroke();
@@ -1060,6 +1104,7 @@ class ContextStateHandle {
10601104
}
10611105
}
10621106

1107+
/// Fills or strokes the currently active path based on fill type.
10631108
void paintPath(ui.PaintingStyle? style, ui.PathFillType pathFillType) {
10641109
if (style == ui.PaintingStyle.stroke) {
10651110
context.stroke();
@@ -1072,6 +1117,8 @@ class ContextStateHandle {
10721117
}
10731118
}
10741119

1120+
/// Resets drawing context state to defaults for
1121+
/// [html.CanvasRenderingContext2D].
10751122
void reset() {
10761123
context.fillStyle = '';
10771124
// Read back fillStyle/strokeStyle values from context so that input such

lib/web_ui/lib/src/engine/html/bitmap_canvas.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ class BitmapCanvas extends EngineCanvas {
160160
_canvasPositionX = _bounds.left.floor() - kPaddingPixels;
161161
_canvasPositionY = _bounds.top.floor() - kPaddingPixels;
162162
_updateRootElementTransform();
163-
_canvasPool.allocateCanvas(rootElement as html.HtmlElement);
163+
_canvasPool.mount(rootElement as html.HtmlElement);
164164
_setupInitialTransform();
165165
}
166166

@@ -372,7 +372,7 @@ class BitmapCanvas extends EngineCanvas {
372372
_renderStrategy.isInsideSvgFilterTree ||
373373
(_preserveImageData == false && _contains3dTransform) ||
374374
(_childOverdraw &&
375-
_canvasPool.canvas == null &&
375+
_canvasPool.isEmpty &&
376376
paint.maskFilter == null &&
377377
paint.shader == null &&
378378
paint.style != ui.PaintingStyle.stroke);
@@ -386,7 +386,7 @@ class BitmapCanvas extends EngineCanvas {
386386
((_childOverdraw ||
387387
_renderStrategy.hasImageElements ||
388388
_renderStrategy.hasParagraphs) &&
389-
_canvasPool.canvas == null &&
389+
_canvasPool.isEmpty &&
390390
paint.maskFilter == null &&
391391
paint.shader == null);
392392

0 commit comments

Comments
 (0)