From 7c55c6bdda045c802c0e05cfe1b06da78f5df89b Mon Sep 17 00:00:00 2001 From: xieguo Date: Tue, 30 Aug 2022 17:07:06 +0800 Subject: [PATCH 1/8] Add function restoreToCount to Canvas. Signed-off-by: xieguo --- lib/ui/dart_ui.cc | 1 + lib/ui/painting.dart | 10 ++++++++++ lib/ui/painting/canvas.cc | 6 ++++++ lib/ui/painting/canvas.h | 1 + testing/dart/canvas_test.dart | 15 +++++++++++++++ 5 files changed, 33 insertions(+) diff --git a/lib/ui/dart_ui.cc b/lib/ui/dart_ui.cc index 61d35c5cd2a5c..ab113ac4df4be 100644 --- a/lib/ui/dart_ui.cc +++ b/lib/ui/dart_ui.cc @@ -147,6 +147,7 @@ typedef CanvasPath Path; V(Canvas, getSaveCount, 1) \ V(Canvas, getTransform, 2) \ V(Canvas, restore, 1) \ + V(Canvas, restoreToCount, 2) \ V(Canvas, rotate, 2) \ V(Canvas, save, 1) \ V(Canvas, saveLayer, 7) \ diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 90bb63654b396..39174d4887346 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -4615,6 +4615,16 @@ class Canvas extends NativeFieldWrapperClass1 { @FfiNative)>('Canvas::restore', isLeaf: true) external void restore(); + /// Pops the save stack until the count layer, if there is anything to pop. + /// Otherwise, does nothing. + /// + /// Use [save] and [saveLayer] to push state onto the stack. + /// + /// If the state was pushed with [saveLayer], then this call will also + /// cause the new layer to be composited into the previous layer. + @FfiNative, Int32)>('Canvas::restoreToCount', isLeaf: true) + external void restoreToCount(int count); + /// Returns the number of items on the save stack, including the /// initial state. This means it returns 1 for a clean canvas, and /// that each call to [save] and [saveLayer] increments it, and that diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc index ee39d8a9489b5..881c79f871add 100644 --- a/lib/ui/painting/canvas.cc +++ b/lib/ui/painting/canvas.cc @@ -117,6 +117,12 @@ int Canvas::getSaveCount() { } } +void Canvas::restoreToCount(size_t count) { + if (display_list_recorder_) { + builder()->restoreToCount(count); + } +} + void Canvas::translate(double dx, double dy) { if (display_list_recorder_) { builder()->translate(dx, dy); diff --git a/lib/ui/painting/canvas.h b/lib/ui/painting/canvas.h index 0fbe2d8b7f5f9..21255ab571dfa 100644 --- a/lib/ui/painting/canvas.h +++ b/lib/ui/painting/canvas.h @@ -48,6 +48,7 @@ class Canvas : public RefCountedDartWrappable, DisplayListOpFlags { void restore(); int getSaveCount(); + void restoreToCount(size_t count); void translate(double dx, double dy); void scale(double sx, double sy); diff --git a/testing/dart/canvas_test.dart b/testing/dart/canvas_test.dart index e9dc8b1337d51..8de95b6de4529 100644 --- a/testing/dart/canvas_test.dart +++ b/testing/dart/canvas_test.dart @@ -928,6 +928,21 @@ void main() { expect(canvas.getLocalClipBounds(), initialLocalBounds); expect(canvas.getDestinationClipBounds(), initialDestinationBounds); }); + + test('RestoreToCount can work', () async { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + expect(canvas.getSaveCount(), equals(6)); + canvas.restoreToCount(2); + expect(canvas.getSaveCount(), equals(2)); + canvas.restore(); + expect(canvas.getSaveCount(), equals(1)); + }); } Matcher listEquals(ByteData expected) => (dynamic v) { From 86cc918449827ad31e833199c5b775b200c41227 Mon Sep 17 00:00:00 2001 From: xieguo Date: Tue, 30 Aug 2022 17:24:45 +0800 Subject: [PATCH 2/8] Change type from size_t to int Signed-off-by: xieguo --- lib/ui/painting/canvas.cc | 2 +- lib/ui/painting/canvas.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc index 881c79f871add..aea3af6e6d111 100644 --- a/lib/ui/painting/canvas.cc +++ b/lib/ui/painting/canvas.cc @@ -117,7 +117,7 @@ int Canvas::getSaveCount() { } } -void Canvas::restoreToCount(size_t count) { +void Canvas::restoreToCount(int count) { if (display_list_recorder_) { builder()->restoreToCount(count); } diff --git a/lib/ui/painting/canvas.h b/lib/ui/painting/canvas.h index 21255ab571dfa..22ef44315ca09 100644 --- a/lib/ui/painting/canvas.h +++ b/lib/ui/painting/canvas.h @@ -48,7 +48,7 @@ class Canvas : public RefCountedDartWrappable, DisplayListOpFlags { void restore(); int getSaveCount(); - void restoreToCount(size_t count); + void restoreToCount(int count); void translate(double dx, double dy); void scale(double sx, double sy); From bdf23aa177341de172e0dcb98228d1d34110e61c Mon Sep 17 00:00:00 2001 From: xieguo Date: Tue, 30 Aug 2022 20:09:53 +0800 Subject: [PATCH 3/8] Add restoreToCount to web Signed-off-by: xieguo --- lib/web_ui/lib/canvas.dart | 1 + .../src/engine/canvaskit/canvaskit_canvas.dart | 5 +++++ lib/web_ui/lib/src/engine/html/canvas.dart | 5 +++++ .../lib/src/engine/html/recording_canvas.dart | 6 ++++++ lib/web_ui/test/engine/canvas_test.dart | 15 +++++++++++++++ 5 files changed, 32 insertions(+) diff --git a/lib/web_ui/lib/canvas.dart b/lib/web_ui/lib/canvas.dart index c9359b6930781..c9273bb83e325 100644 --- a/lib/web_ui/lib/canvas.dart +++ b/lib/web_ui/lib/canvas.dart @@ -95,6 +95,7 @@ abstract class Canvas { void saveLayer(Rect? bounds, Paint paint); void restore(); int getSaveCount(); + void restoreToCount(int count); void translate(double dx, double dy); void scale(double sx, [double? sy]); void rotate(double radians); diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart index 87c94858dd2c7..444860bae5649 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart @@ -65,6 +65,11 @@ class CanvasKitCanvas implements ui.Canvas { _canvas.restore(); } + @override + void restoreToCount(int count) { + _canvas.restoreToCount(count); + } + @override int getSaveCount() { return _canvas.saveCount!; diff --git a/lib/web_ui/lib/src/engine/html/canvas.dart b/lib/web_ui/lib/src/engine/html/canvas.dart index 8f310f3865207..b40df52a28ffa 100644 --- a/lib/web_ui/lib/src/engine/html/canvas.dart +++ b/lib/web_ui/lib/src/engine/html/canvas.dart @@ -58,6 +58,11 @@ class SurfaceCanvas implements ui.Canvas { _canvas.restore(); } + @override + void restoreToCount(int count) { + _canvas.restoreToCount(count); + } + @override int getSaveCount() => _canvas.saveCount; diff --git a/lib/web_ui/lib/src/engine/html/recording_canvas.dart b/lib/web_ui/lib/src/engine/html/recording_canvas.dart index 970009ef563f8..9fd8300630cae 100644 --- a/lib/web_ui/lib/src/engine/html/recording_canvas.dart +++ b/lib/web_ui/lib/src/engine/html/recording_canvas.dart @@ -244,6 +244,12 @@ class RecordingCanvas { _saveCount--; } + void restoreToCount(int count) { + while (count < _saveCount) { + restore(); + } + } + void translate(double dx, double dy) { assert(!_recordingEnded); _paintBounds.translate(dx, dy); diff --git a/lib/web_ui/test/engine/canvas_test.dart b/lib/web_ui/test/engine/canvas_test.dart index ef76c8676df33..21b303981d8a4 100644 --- a/lib/web_ui/test/engine/canvas_test.dart +++ b/lib/web_ui/test/engine/canvas_test.dart @@ -276,5 +276,20 @@ void runCanvasTests({required bool deviceClipRoundsOut}) { expect(canvas.getLocalClipBounds(), initialLocalBounds); expect(canvas.getDestinationClipBounds(), initialDestinationBounds); }); + + test('RestoreToCount can work', () async { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + expect(canvas.getSaveCount(), 6); + canvas.restoreToCount(2); + expect(canvas.getSaveCount(), 2); + canvas.restore(); + expect(canvas.getSaveCount(), 1); + }); }); } From 21cad6c7e5be74c17624e8abd687107bd317080f Mon Sep 17 00:00:00 2001 From: xieguo Date: Wed, 31 Aug 2022 16:04:46 +0800 Subject: [PATCH 4/8] Add more corner case test. Signed-off-by: xieguo --- lib/ui/painting.dart | 5 ++-- .../lib/src/engine/html/recording_canvas.dart | 2 +- lib/web_ui/test/engine/canvas_test.dart | 27 +++++++++++++++++++ testing/dart/canvas_test.dart | 26 ++++++++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 112846d42965e..f0000f3dd7b9f 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -4691,8 +4691,9 @@ class Canvas extends NativeFieldWrapperClass1 { @FfiNative)>('Canvas::restore', isLeaf: true) external void restore(); - /// Pops the save stack until the count layer, if there is anything to pop. - /// Otherwise, does nothing. + /// Restores the save stack to a previous level as might be obtained from [getSaveCount]. + /// If [count] is less than 1, the stack is restored to its initial state. + /// If [count] is greater than the current [getSaveCount] then nothing happens. /// /// Use [save] and [saveLayer] to push state onto the stack. /// diff --git a/lib/web_ui/lib/src/engine/html/recording_canvas.dart b/lib/web_ui/lib/src/engine/html/recording_canvas.dart index 9fd8300630cae..b1f86da42f8fe 100644 --- a/lib/web_ui/lib/src/engine/html/recording_canvas.dart +++ b/lib/web_ui/lib/src/engine/html/recording_canvas.dart @@ -245,7 +245,7 @@ class RecordingCanvas { } void restoreToCount(int count) { - while (count < _saveCount) { + while (count < _saveCount && _saveCount > 1) { restore(); } } diff --git a/lib/web_ui/test/engine/canvas_test.dart b/lib/web_ui/test/engine/canvas_test.dart index 21b303981d8a4..adf2ff2fc9983 100644 --- a/lib/web_ui/test/engine/canvas_test.dart +++ b/lib/web_ui/test/engine/canvas_test.dart @@ -291,5 +291,32 @@ void runCanvasTests({required bool deviceClipRoundsOut}) { canvas.restore(); expect(canvas.getSaveCount(), 1); }); + + test('RestoreToCount count less than 1, the stack should be reset', () async { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + expect(canvas.getSaveCount(), equals(6)); + canvas.restoreToCount(0); + expect(canvas.getSaveCount(), equals(1)); + }); + + test('RestoreToCount count greater than current [getSaveCount]', () async { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + expect(canvas.getSaveCount(), equals(6)); + canvas.restoreToCount(canvas.getSaveCount() + 1); + expect(canvas.getSaveCount(), equals(6)); + }); + }); } diff --git a/testing/dart/canvas_test.dart b/testing/dart/canvas_test.dart index 4322db83e16ba..7505012fbc350 100644 --- a/testing/dart/canvas_test.dart +++ b/testing/dart/canvas_test.dart @@ -944,6 +944,32 @@ void main() { canvas.restore(); expect(canvas.getSaveCount(), equals(1)); }); + + test('RestoreToCount count less than 1, the stack should be reset', () async { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + expect(canvas.getSaveCount(), equals(6)); + canvas.restoreToCount(0); + expect(canvas.getSaveCount(), equals(1)); + }); + + test('RestoreToCount count greater than current [getSaveCount], nothing would happend', () async { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + expect(canvas.getSaveCount(), equals(6)); + canvas.restoreToCount(canvas.getSaveCount() + 1); + expect(canvas.getSaveCount(), equals(6)); + }); } Matcher listEquals(ByteData expected) => (dynamic v) { From 01199f38bc1792cb36eab351f3700765875fe9e9 Mon Sep 17 00:00:00 2001 From: xieguo Date: Thu, 1 Sep 2022 13:53:10 +0800 Subject: [PATCH 5/8] add more comments. Signed-off-by: xieguo --- display_list/display_list_builder.cc | 2 +- lib/ui/painting.dart | 5 +++-- lib/ui/painting/canvas.cc | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/display_list/display_list_builder.cc b/display_list/display_list_builder.cc index 788938e4b05b7..f8c551bd6a28a 100644 --- a/display_list/display_list_builder.cc +++ b/display_list/display_list_builder.cc @@ -476,7 +476,7 @@ void DisplayListBuilder::restore() { } void DisplayListBuilder::restoreToCount(int restore_count) { FML_DCHECK(restore_count <= getSaveCount()); - while (restore_count < getSaveCount()) { + while ((restore_count < getSaveCount()) && (getSaveCount() > 1)) { restore(); } } diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index f0000f3dd7b9f..91653af0f922b 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -4697,8 +4697,9 @@ class Canvas extends NativeFieldWrapperClass1 { /// /// Use [save] and [saveLayer] to push state onto the stack. /// - /// If the state was pushed with [saveLayer], then this call will also - /// cause the new layer to be composited into the previous layer. + /// Restores the save stack to a previous level as might be obtained from [getSaveCount]. + /// If [count] is less than 1, the stack is restored to its initial state. If [count] is + /// greater than the current [getSaveCount] then nothing happens. @FfiNative, Int32)>('Canvas::restoreToCount', isLeaf: true) external void restoreToCount(int count); diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc index aea3af6e6d111..b1faf79174d32 100644 --- a/lib/ui/painting/canvas.cc +++ b/lib/ui/painting/canvas.cc @@ -118,7 +118,7 @@ int Canvas::getSaveCount() { } void Canvas::restoreToCount(int count) { - if (display_list_recorder_) { + if (display_list_recorder_ && (count < getSaveCount())) { builder()->restoreToCount(count); } } From 371593cf26a2acb2a4454e3f23dccde4fdb7ce3b Mon Sep 17 00:00:00 2001 From: xieguo Date: Thu, 1 Sep 2022 19:47:09 +0800 Subject: [PATCH 6/8] Do some code refine. Signed-off-by: xieguo --- display_list/display_list_builder.cc | 2 +- lib/web_ui/test/engine/canvas_test.dart | 51 +++++++++++++------------ 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/display_list/display_list_builder.cc b/display_list/display_list_builder.cc index f8c551bd6a28a..a71542fc93054 100644 --- a/display_list/display_list_builder.cc +++ b/display_list/display_list_builder.cc @@ -476,7 +476,7 @@ void DisplayListBuilder::restore() { } void DisplayListBuilder::restoreToCount(int restore_count) { FML_DCHECK(restore_count <= getSaveCount()); - while ((restore_count < getSaveCount()) && (getSaveCount() > 1)) { + while (restore_count < getSaveCount() && getSaveCount() > 1) { restore(); } } diff --git a/lib/web_ui/test/engine/canvas_test.dart b/lib/web_ui/test/engine/canvas_test.dart index adf2ff2fc9983..053cd9c155b6b 100644 --- a/lib/web_ui/test/engine/canvas_test.dart +++ b/lib/web_ui/test/engine/canvas_test.dart @@ -276,7 +276,9 @@ void runCanvasTests({required bool deviceClipRoundsOut}) { expect(canvas.getLocalClipBounds(), initialLocalBounds); expect(canvas.getDestinationClipBounds(), initialDestinationBounds); }); + }); + group('RestoreToCount function tests', () { test('RestoreToCount can work', () async { final ui.PictureRecorder recorder = ui.PictureRecorder(); final ui.Canvas canvas = ui.Canvas(recorder); @@ -292,31 +294,30 @@ void runCanvasTests({required bool deviceClipRoundsOut}) { expect(canvas.getSaveCount(), 1); }); - test('RestoreToCount count less than 1, the stack should be reset', () async { - final ui.PictureRecorder recorder = ui.PictureRecorder(); - final ui.Canvas canvas = ui.Canvas(recorder); - canvas.save(); - canvas.save(); - canvas.save(); - canvas.save(); - canvas.save(); - expect(canvas.getSaveCount(), equals(6)); - canvas.restoreToCount(0); - expect(canvas.getSaveCount(), equals(1)); - }); - - test('RestoreToCount count greater than current [getSaveCount]', () async { - final ui.PictureRecorder recorder = ui.PictureRecorder(); - final ui.Canvas canvas = ui.Canvas(recorder); - canvas.save(); - canvas.save(); - canvas.save(); - canvas.save(); - canvas.save(); - expect(canvas.getSaveCount(), equals(6)); - canvas.restoreToCount(canvas.getSaveCount() + 1); - expect(canvas.getSaveCount(), equals(6)); - }); + test('RestoreToCount count less than 1, the stack should be reset', () async { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + expect(canvas.getSaveCount(), equals(6)); + canvas.restoreToCount(0); + expect(canvas.getSaveCount(), equals(1)); + }); + test('RestoreToCount count greater than current [getSaveCount]', () async { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + canvas.save(); + expect(canvas.getSaveCount(), equals(6)); + canvas.restoreToCount(canvas.getSaveCount() + 1); + expect(canvas.getSaveCount(), equals(6)); + }); }); } From 762ef017d649bbf7c2a7c7d1d9de3986aafc33f6 Mon Sep 17 00:00:00 2001 From: xieguo Date: Thu, 1 Sep 2022 20:09:48 +0800 Subject: [PATCH 7/8] fix comment Signed-off-by: xieguo --- lib/ui/painting.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 571315b5b7a9d..b5d8f782956cd 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -4811,9 +4811,9 @@ class Canvas extends NativeFieldWrapperClass1 { /// /// Use [save] and [saveLayer] to push state onto the stack. /// - /// Restores the save stack to a previous level as might be obtained from [getSaveCount]. - /// If [count] is less than 1, the stack is restored to its initial state. If [count] is - /// greater than the current [getSaveCount] then nothing happens. + /// If any of the state stack levels restored by this call were pushed with + /// [saveLayer], then this call will also cause those layers to be composited + /// into their previous layers. @FfiNative, Int32)>('Canvas::restoreToCount', isLeaf: true) external void restoreToCount(int count); From c9962c78b74876641cc1d3862e12fb139d81e515 Mon Sep 17 00:00:00 2001 From: xieguo Date: Thu, 1 Sep 2022 20:10:44 +0800 Subject: [PATCH 8/8] code refine. Signed-off-by: xieguo --- lib/ui/painting/canvas.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc index b1faf79174d32..733b8a2903e71 100644 --- a/lib/ui/painting/canvas.cc +++ b/lib/ui/painting/canvas.cc @@ -118,7 +118,7 @@ int Canvas::getSaveCount() { } void Canvas::restoreToCount(int count) { - if (display_list_recorder_ && (count < getSaveCount())) { + if (display_list_recorder_ && count < getSaveCount()) { builder()->restoreToCount(count); } }