-
Notifications
You must be signed in to change notification settings - Fork 6k
Refactor BitmapCanvas. Fix image compositing bug #15114
Conversation
We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors. If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google. ℹ️ Googlers: Go here for more info. |
1 similar comment
We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors. If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google. ℹ️ Googlers: Go here for more info. |
_canvas.style.transform = ''; | ||
_canvasPool.reuse(); | ||
_setupInitialTransform(); | ||
_canvasPool.contextHandle.reset(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems the logic for resetting the context handle can move into _CanvasPool.reuse()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lazy allocation changes this quite a bit where initialTransform becomes setter. Not addressing in this PR.
-_bounds.top + canvasPositionCorrectionY + kPaddingPixels, | ||
); | ||
// Returns a data URI containing a representation of the image in this | ||
// canvas. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
///
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -0,0 +1,694 @@ | |||
part of engine; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file needs a license header.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -0,0 +1,694 @@ | |||
part of engine; | |||
|
|||
class _CanvasPool extends _SaveStackTracking { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although this class is private it's pretty non-trivial, so some docs could help understand what it does in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
} | ||
if (_reusablePool != null && _reusablePool.isNotEmpty) { | ||
_canvas = _reusablePool[0]; | ||
_reusablePool.removeAt(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_canvas = _reusablePool.removeAt(0);
will save one list look-up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
}); | ||
|
||
test('Inner RRect not completely inside Outer RRect', () { | ||
underTest.drawDRRect(rrect, rrect.deflate(1).shift(const Offset(0.0, 10)), somePaint); | ||
underTest.apply(mockCanvas); | ||
// Expect nothing to be called | ||
expect(mockCanvas.methodCallLog.length, equals(0)); | ||
expect(mockCanvas.methodCallLog.length, equals(1)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
}); | ||
|
||
test('Inner RRect same as Outer RRect', () { | ||
underTest.drawDRRect(rrect, rrect, somePaint); | ||
underTest.apply(mockCanvas); | ||
// Expect nothing to be called | ||
expect(mockCanvas.methodCallLog.length, equals(0)); | ||
expect(mockCanvas.methodCallLog.length, equals(1)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -50,6 +50,7 @@ void main() async { | |||
RecordingCanvas(const Rect.fromLTRB(0, 0, 400, 300)); | |||
rc.save(); | |||
rc.drawImage(createTestImage(), Offset(0, 0), new Paint()); | |||
rc.restore(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Restores are optional in Flutter AFAIK. What happens if you do not call it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed [_CanvasPool] to count save/restore to handle case.
// Circle should draw on top of image not below. | ||
test('Paints on top of image', () async { | ||
final RecordingCanvas rc = | ||
RecordingCanvas(const Rect.fromLTRB(0, 0, 400, 300)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: indentation is off (throughout the file)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dartfmt Done.
|
||
// Regression test for https://github.com/flutter/flutter/issues/44845 | ||
// Circle should draw on top of image not below. | ||
test('Paints on top of image', () async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also have a test that checks that we can still paint under the image :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. flutter/goldens#69
Added endOfPaint call on recording canvas to allow bitmap canvas to dispose after reuse.
Moved all immediate canvas calls from BitmapCanvas into CanvasPool.
Reduced context updates by creating ContextHandle class.
Added regression tests for drawing on top of image in a single Picture.
Fixes flutter/flutter#44845
Fixes flutter/flutter#48032