Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
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
2 changes: 1 addition & 1 deletion display_list/display_list_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Expand Down
1 change: 1 addition & 0 deletions lib/ui/dart_ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,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) \
Expand Down
12 changes: 12 additions & 0 deletions lib/ui/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4805,6 +4805,18 @@ class Canvas extends NativeFieldWrapperClass1 {
@FfiNative<Void Function(Pointer<Void>)>('Canvas::restore', isLeaf: true)
external void restore();

/// 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.
///
/// 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<Void Function(Pointer<Void>, 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
Expand Down
6 changes: 6 additions & 0 deletions lib/ui/painting/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ int Canvas::getSaveCount() {
}
}

void Canvas::restoreToCount(int count) {
if (display_list_recorder_ && count < getSaveCount()) {
builder()->restoreToCount(count);
}
}

void Canvas::translate(double dx, double dy) {
if (display_list_recorder_) {
builder()->translate(dx, dy);
Expand Down
1 change: 1 addition & 0 deletions lib/ui/painting/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class Canvas : public RefCountedDartWrappable<Canvas>, DisplayListOpFlags {

void restore();
int getSaveCount();
void restoreToCount(int count);

void translate(double dx, double dy);
void scale(double sx, double sy);
Expand Down
1 change: 1 addition & 0 deletions lib/web_ui/lib/canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,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);
Expand Down
5 changes: 5 additions & 0 deletions lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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!;
Expand Down
5 changes: 5 additions & 0 deletions lib/web_ui/lib/src/engine/html/canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ class SurfaceCanvas implements ui.Canvas {
_canvas.restore();
}

@override
void restoreToCount(int count) {
_canvas.restoreToCount(count);
}

@override
int getSaveCount() => _canvas.saveCount;

Expand Down
6 changes: 6 additions & 0 deletions lib/web_ui/lib/src/engine/html/recording_canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,12 @@ class RecordingCanvas {
_saveCount--;
}

void restoreToCount(int count) {
while (count < _saveCount && _saveCount > 1) {
restore();
}
}

void translate(double dx, double dy) {
assert(!_recordingEnded);
_paintBounds.translate(dx, dy);
Expand Down
43 changes: 43 additions & 0 deletions lib/web_ui/test/engine/canvas_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -277,4 +277,47 @@ void runCanvasTests({required bool deviceClipRoundsOut}) {
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);
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);
});

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));
});
});
}
41 changes: 41 additions & 0 deletions testing/dart/canvas_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,47 @@ 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));
});

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) {
Expand Down