Skip to content

Commit

Permalink
[web] Fix HtmlImage state pollution due to image.clone optimization (#…
Browse files Browse the repository at this point in the history
…17370)

* fix drawImage style when destination width==source
* Add regression test
* dartfmt
* update golden lock
* Addressed review comment
* remove transform reset since _drawImage is called
  • Loading branch information
ferhatb committed Mar 30, 2020
1 parent 113ebf9 commit 40931c8
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 1 deletion.
9 changes: 8 additions & 1 deletion lib/web_ui/lib/src/engine/bitmap_canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,10 @@ class BitmapCanvas extends EngineCanvas {
final ui.BlendMode blendMode = paint.blendMode;
imgElement.style.mixBlendMode = _stringForBlendMode(blendMode);
if (_canvasPool.isClipped) {
// Reset width/height since they may have been previously set.
imgElement.style
..removeProperty('width')
..removeProperty('height');
final List<html.Element> clipElements = _clipContent(
_canvasPool._clipStack, imgElement, p, _canvasPool.currentTransform);
for (html.Element clipElement in clipElements) {
Expand All @@ -375,7 +379,10 @@ class BitmapCanvas extends EngineCanvas {
transformWithOffset(_canvasPool.currentTransform, p).storage);
imgElement.style
..transformOrigin = '0 0 0'
..transform = cssTransform;
..transform = cssTransform
// Reset width/height since they may have been previously set.
..removeProperty('width')
..removeProperty('height');
rootElement.append(imgElement);
_children.add(imgElement);
}
Expand Down
122 changes: 122 additions & 0 deletions lib/web_ui/test/golden_tests/engine/canvas_draw_picture_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// @dart = 2.6
import 'dart:html' as html;

import 'package:ui/ui.dart';
import 'package:ui/src/engine.dart';
import 'package:test/test.dart';

import 'package:web_engine_tester/golden_tester.dart';

final Rect region = Rect.fromLTWH(0, 0, 500, 100);

void main() async {
setUp(() async {
debugShowClipLayers = true;
SurfaceSceneBuilder.debugForgetFrameScene();
for (html.Node scene in html.document.querySelectorAll('flt-scene')) {
scene.remove();
}

await webOnlyInitializePlatform();
webOnlyFontCollection.debugRegisterTestFonts();
await webOnlyFontCollection.ensureFontsLoaded();
});

test('draw growing picture across frames', () async {
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushClipRect(
const Rect.fromLTRB(0, 0, 100, 100),
);

_drawTestPicture(builder, 100, false);
builder.pop();

html.Element elm1 = builder.build().webOnlyRootElement;
html.document.body.append(elm1);

// Now draw picture again but at larger size.
final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder();
builder2.pushClipRect(
const Rect.fromLTRB(0, 0, 100, 100),
);
// Now draw the picture at original target size, which will use a
// different code path that should normally not have width/height set
// on image element.
_drawTestPicture(builder2, 20, false);
builder2.pop();

elm1.remove();
html.document.body.append(builder2.build().webOnlyRootElement);

await matchGoldenFile('canvas_draw_picture_acrossframes.png',
region: region);
});

test('draw growing picture across frames clipped', () async {
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushClipRect(
const Rect.fromLTRB(0, 0, 100, 100),
);

_drawTestPicture(builder, 100, true);
builder.pop();

html.Element elm1 = builder.build().webOnlyRootElement;
html.document.body.append(elm1);

// Now draw picture again but at larger size.
final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder();
builder2.pushClipRect(
const Rect.fromLTRB(0, 0, 100, 100),
);
_drawTestPicture(builder2, 20, true);
builder2.pop();

elm1.remove();
html.document.body.append(builder2.build().webOnlyRootElement);

await matchGoldenFile('canvas_draw_picture_acrossframes_clipped.png',
region: region);
});
}

HtmlImage sharedImage;

void _drawTestPicture(SceneBuilder builder, double targetSize, bool clipped) {
sharedImage ??= _createRealTestImage();
final EnginePictureRecorder recorder = PictureRecorder();
final RecordingCanvas canvas =
recorder.beginRecording(const Rect.fromLTRB(0, 0, 100, 100));
canvas.debugEnforceArbitraryPaint();
if (clipped) {
canvas.clipRRect(
RRect.fromLTRBR(0, 0, targetSize, targetSize, Radius.circular(4)));
}
canvas.drawImageRect(sharedImage, Rect.fromLTWH(0, 0, 20, 20),
Rect.fromLTWH(0, 0, targetSize, targetSize), Paint());
final Picture picture = recorder.endRecording();
builder.addPicture(
Offset.zero,
picture,
);
}

typedef PaintCallback = void Function(RecordingCanvas canvas);

const String _base64Encoded20x20TestImage =
'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA'
'B3RJTUUH5AMFFBksg4i3gQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAj'
'SURBVDjLY2TAC/7jlWVioACMah4ZmhnxpyHG0QAb1UyZZgBjWAIm/clP0AAAAABJRU5ErkJggg==';

HtmlImage _createRealTestImage() {
return HtmlImage(
html.ImageElement()
..src = 'data:text/plain;base64,$_base64Encoded20x20TestImage',
20,
20,
);
}

0 comments on commit 40931c8

Please sign in to comment.