Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 015c211

Browse files
authored
[web] Fix drawImage colorFilter with dstATop blend mode (#25165)
1 parent 8d73893 commit 015c211

File tree

6 files changed

+189
-129
lines changed

6 files changed

+189
-129
lines changed

lib/web_ui/dev/goldens_lock.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
repository: https://github.com/flutter/goldens.git
2-
revision: c5f999871e83142afb82a636e97bd67a62789c6e
2+
revision: 02ca90916f341a215d44fab6a13fefa7e865c372

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@ class BitmapCanvas extends EngineCanvas {
648648
case ui.BlendMode.color:
649649
case ui.BlendMode.luminosity:
650650
case ui.BlendMode.xor:
651+
case ui.BlendMode.dstATop:
651652
imgElement = _createImageElementWithSvgFilter(
652653
image, colorFilter.color, colorFilter.blendMode, paint);
653654
break;

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ String? svgFilterFromBlendMode(
149149
case ui.BlendMode.srcOut:
150150
svgFilter = _srcOutColorFilterToSvg(filterColor);
151151
break;
152+
case ui.BlendMode.dstATop:
153+
svgFilter = _dstATopColorFilterToSvg(filterColor);
154+
break;
152155
case ui.BlendMode.xor:
153156
svgFilter = _xorColorFilterToSvg(filterColor);
154157
break;
@@ -199,7 +202,6 @@ String? svgFilterFromBlendMode(
199202
break;
200203
case ui.BlendMode.src:
201204
case ui.BlendMode.dst:
202-
case ui.BlendMode.dstATop:
203205
case ui.BlendMode.dstIn:
204206
case ui.BlendMode.dstOut:
205207
case ui.BlendMode.dstOver:
@@ -246,6 +248,20 @@ String _srcInColorFilterToSvg(ui.Color? color) {
246248
'</filter></svg>';
247249
}
248250

251+
/// The destination that overlaps the source is composited with the source and
252+
/// replaces the destination. dst-atop CR = CB*αB*αA+CA*αA*(1-αB) αR=αA
253+
String _dstATopColorFilterToSvg(ui.Color? color) {
254+
_filterIdCounter += 1;
255+
return '$kSvgResourceHeader'
256+
'<filter id="_fcf$_filterIdCounter" '
257+
'filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">'
258+
'<feFlood flood-color="${colorToCssString(color)}" flood-opacity="1" result="flood">'
259+
'</feFlood>'
260+
'<feComposite in="SourceGraphic" in2="flood" operator="atop" result="comp">'
261+
'</feComposite>'
262+
'</filter></svg>';
263+
}
264+
249265
String _srcOutColorFilterToSvg(ui.Color? color) {
250266
_filterIdCounter += 1;
251267
return '$kSvgResourceHeader'

lib/web_ui/test/golden_tests/engine/canvas_image_blend_mode_test.dart

Lines changed: 11 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import 'package:ui/src/engine.dart';
1212

1313
import 'package:web_engine_tester/golden_tester.dart';
1414

15+
import 'testimage.dart';
16+
1517
void main() {
1618
internalBootstrapBrowserTest(() => testMain);
1719
}
@@ -81,28 +83,28 @@ void testMain() async {
8183
rc.drawRect(Rect.fromLTWH(200, top, 200, 50), Paint()
8284
..color = grey);
8385
BlendMode blendMode = blendModes[row];
84-
rc.drawImage(createTestImage(), Offset(0, top),
86+
rc.drawImage(createFlutterLogoTestImage(), Offset(0, top),
8587
Paint()
8688
..colorFilter = EngineColorFilter.mode(red, blendMode));
87-
rc.drawImage(createTestImage(), Offset(50, top),
89+
rc.drawImage(createFlutterLogoTestImage(), Offset(50, top),
8890
Paint()
8991
..colorFilter = EngineColorFilter.mode(green, blendMode));
90-
rc.drawImage(createTestImage(), Offset(100, top),
92+
rc.drawImage(createFlutterLogoTestImage(), Offset(100, top),
9193
Paint()
9294
..colorFilter = EngineColorFilter.mode(blue, blendMode));
93-
rc.drawImage(createTestImage(), Offset(150, top),
95+
rc.drawImage(createFlutterLogoTestImage(), Offset(150, top),
9496
Paint()
9597
..colorFilter = EngineColorFilter.mode(black, blendMode));
96-
rc.drawImage(createTestImage(), Offset(200, top),
98+
rc.drawImage(createFlutterLogoTestImage(), Offset(200, top),
9799
Paint()
98100
..colorFilter = EngineColorFilter.mode(red, blendMode));
99-
rc.drawImage(createTestImage(), Offset(250, top),
101+
rc.drawImage(createFlutterLogoTestImage(), Offset(250, top),
100102
Paint()
101103
..colorFilter = EngineColorFilter.mode(green, blendMode));
102-
rc.drawImage(createTestImage(), Offset(300, top),
104+
rc.drawImage(createFlutterLogoTestImage(), Offset(300, top),
103105
Paint()
104106
..colorFilter = EngineColorFilter.mode(blue, blendMode));
105-
rc.drawImage(createTestImage(), Offset(350, top),
107+
rc.drawImage(createFlutterLogoTestImage(), Offset(350, top),
106108
Paint()
107109
..colorFilter = EngineColorFilter.mode(black, blendMode));
108110
}
@@ -121,7 +123,7 @@ void testMain() async {
121123
rc.save();
122124
rc.drawRect(Rect.fromLTWH(0, 50, 200, 50), Paint()
123125
..color = white);
124-
rc.drawImage(createTestImage(), Offset(0, 50),
126+
rc.drawImage(createFlutterLogoTestImage(), Offset(0, 50),
125127
Paint()
126128
..colorFilter = EngineColorFilter.mode(red, BlendMode.srcIn));
127129

@@ -148,121 +150,3 @@ Paragraph createTestParagraph() {
148150
builder.addText('FOO');
149151
return builder.build();
150152
}
151-
152-
153-
// 50x50 pixel flutter logo image.
154-
const String _flutterLogoBase64 =
155-
'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAKRlWElm'
156-
'TU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgExAAIAAAAg'
157-
'AAAAWodpAAQAAAABAAAAegAAAAAAAABIAAAAAQAAAEgAAAABQWRvYmUgUGhvdG9zaG9wIENT'
158-
'NiAoTWFjaW50b3NoKQAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAMqADAAQAAAABAAAAMgAA'
159-
'AABWBXsWAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEemlUWHRYTUw6Y29tLmFkb2JlLnhtcAAA'
160-
'AAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENv'
161-
'cmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5'
162-
'OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjph'
163-
'Ym91dD0iIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94'
164-
'YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5j'
165-
'b20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiCiAgICAgICAgICAgIHhtbG5zOnhtcD0i'
166-
'aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0i'
167-
'aHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8eG1wTU06SW5zdGFu'
168-
'Y2VJRD54bXAuaWlkOjMyOERERjc5ODRCRjExRUE5QUE4OEM5NTZDREM5QkUyPC94bXBNTTp'
169-
'JbnN0YW5jZUlEPgogICAgICAgICA8eG1wTU06RG9jdW1lbnRJRD54bXAuZGlkOjMyOERERj'
170-
'dBODRCRjExRUE5QUE4OEM5NTZDREM5QkUyPC94bXBNTTpEb2N1bWVudElEPgogICAgICAgI'
171-
'CA8eG1wTU06T3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6MDE4MDExNzQwNzIwNjgxMTgy'
172-
'MkFBQjU0OEFBMDMwM0E8L3htcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD4KICAgICAgICAgPHht'
173-
'cE1NOkRlcml2ZWRGcm9tIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICA'
174-
'gPHN0UmVmOmluc3RhbmNlSUQ+eG1wLmlpZDowNDgwMTE3NDA3MjA2ODExODIyQUFCNTQ4QU'
175-
'EwMzAzQTwvc3RSZWY6aW5zdGFuY2VJRD4KICAgICAgICAgICAgPHN0UmVmOmRvY3VtZW50SU'
176-
'Q+eG1wLmRpZDowMTgwMTE3NDA3MjA2ODExODIyQUFCNTQ4QUEwMzAzQTwvc3RSZWY6ZG9jd'
177-
'W1lbnRJRD4KICAgICAgICAgPC94bXBNTTpEZXJpdmVkRnJvbT4KICAgICAgICAgPHhtcDpD'
178-
'cmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ1M2IChNYWNpbnRvc2gpPC94bXA6Q3JlYXRv'
179-
'clRvb2w+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb2'
180-
'4+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhP'
181-
'gr/+ApQAAAQNUlEQVRoBbVaDYxdRRWemTv3vt2WbrctpRYxtCVU4io1LomElrjYWnbbgtr2'
182-
'CbISwGpR0UBUjD8YHyZCNCqIP5GmtLWSAn3SVYqw7PbnFUQFXGOMRUFlW9G2gKalu/veu38'
183-
'zfufce3ff275dWtBJ5s7cuTPnnO+cM2d+3pN2urDiVSHEVCFuOpgT35vVIuaLV8Tgtw8Icf'
184-
'PZkZgntDggrhNCbhHCuihD9J402Y4OLUulqNy1+iwvFIscaaqRMWqyQRofIxFH2ohpwqjDc'
185-
't/OZyyYSTAVHQUtSoVIfPiL7xWu3i2i0KA7PnFmstpaEVMLBnHm1rFHhEbiQZ9PKtl83pPF'
186-
'YnB0xVVne2HlKcdz5wgTC62cZLwlGdJUSxXtWnngFItIOhdzj3xeiWIxzrpPVmpAZg4EJjc'
187-
'tAcmqazqNxjnJVwEOnKjDhMmuX+/KDRuCoeVXn9EcDf/K0c4cEwYBBmgBjSUJZVbnJiuh9'
188-
'1BZ4ZnYREpNucgtPfAMW7VYjHjM7Ldlg1MaJxYaxlnNzVCUP4THrLRTdRiVWVaEcQ54fpu2'
189-
'JoTTl9rid+3tBCL8a1d3S1M0/ARAnGWiyEcfjK+xaB0Icg0ZQXGekEoo4V0qdwNEatVR+q8'
190-
'8O6kCqZ+Wx0QPD6jgeTop72Xxd26Yx0/xYlJAFmJa4xdZO74kcwIgPpObF//rce3qhSYMAw'
191-
'zIpaqsEYSqaE0Kcmso04F/q/fr/uKeE0AQm5OwCCwqvCzn90MzMHEbsijsJ4f1RBuysFCa'
192-
'TGUaA0C1bGKjKufFh/Zo111kopAsQXQnTABAvu9IR6OiunX/jocagpiQQv0HDYJkhiS1Jc'
193-
'V+Lupe0g71BRg7mNjsbmHnml7t6IswJ3wog9xpggR4Uhh4mFTapTjwCb17xzbblgSJCQa9'
194-
'ZvOkIXGy0SkIjihh5+odcKfl6cSeBAQoSrinhYm1qwDi887uHXdbml/7i2MKnYzxBN9eFx'
195-
'ArCgqWYBDBpWu2wp0+aAKOTll0m4AdQbBGuZ4DELcCxHfINcXAwIRBhAmdxGQ/ZSAEQogC'
196-
'0w861/7Q9dyrGQTNqwkTzxaAEBFAaBOa7zq7dhTIqqJUogk/2XQ6uck+Ie8GH9i7O0oKjI3'
197-
'ftfabAPEpE/i00mPFz1IDmZKmUHmua6J4g7O753NMq9hGobDBADRaK7NcaJuNbkLMoaV5gn'
198-
'RqFunocGjr4XeuvcXT7heMXyWXIPLMiHk0FEsEsIQXh/F9zq6fX8/9CgWsxYWG4Zy/1zzmz'
199-
'n2e6U9VpMPGacIP47vbdqzaAxvCYEX+RtfRd2Jix8IaGq/qdJoteCkBdPCldnNxFO9EiL2'
200-
'cmmsDRdrtJIv3X+Rdc/6TQRiQAoj3qPyTGGuMNhhj/7QhCDrz61zlEAjonbwCIGrTOBD4xC'
201-
'BsFO3R/T2vCQKupCSiGkpsYcU25NORg7Q9eu6Fg7POu+lOMWN6kxyB65EUWXpNIAmIYlBen'
202-
'r/CddRGG4UEAiHUJrvAGmIZ0bQMEGJhiehpZ/Gi94n+nmTxzPZP4zqnr5mGSa7lyE3UDnB'
203-
'UiJmtrUJUA+u2NktaySEHPTjVazRrTUvb1ZWjnWz10vzKZi3vp9ULoacxiHpr+ADhYa/1p'
204-
'8PD8zpkoWDYNTG/xrEY/5pJRuWx9GNoDBhjl18ul7EJULzFoBBYmyYEwpZ49FG/0pV/T07Z'
205-
'h0l+YwlJaolaKmk9VWegHJ1DdHpBTZ1+8Vt+c0eFN5SYXw2GTNREpNJ9P0qJzVgSVFDWA8g'
206-
'INASSudPIijUXuNbsojkFrYR1IGrppdZAE0A4HhR4WLkti+XPtxwjWhcMDJwKiEy2sTLlVc'
207-
'uyZp5zvxPmSAbC78q/TRtbgiV1DEcHYneU0GgFNACC1IemUCkFEOaoEqctlo9sOZLRGpPo/'
208-
'1ers0jG+Njy/HzHmCeUElPh5yE6aZadHg1B4GCklItwU45k08Wy76eDGa3/jei1TDOK9W2'
209-
'jQHgyYmIPL/3wnGkqfsJx5EwTxwECRmKJ+nFsCSKJ5gjLFIGIY6kvyT123/4sSOCjPJVcEi'
210-
'WW55g4lk63TOjXLnlgttgd7fhAa5OuPgk/fzOBwHCP3b8WBDWkcwLfAULCPSWCSW6Z91jxab'
211-
'YEgkTBpmvMKUC5RF7CUa1VtNJ5pkGqFaT+s04ORhvCwY5rm07zjpccxznHhFEV3Wg7bngC0J'
212-
'h6GqQxCok43SkRW3mZ7r2/lFoCIAqqIJPtx3K7fOp0QWfoydM/8Xn1S6vVzXNu9ntF75xO0Z'
213-
'mNsbRI0mgc7vlJ9WSyjwnF1zbUfJZ3fJfWDk53URmvCQjqjmU1nc/ULUkSNzfQuMLNSGzVlb'
214-
'qv+HA6J/y8zTsAwVv8lfHSexGx3zsim4fQPwunqI4JwHXI1wIuj5/RL5eY86f+Otj31c6mTr'
215-
'o0mIOcbUcgDAHBZjIZnxLhHYbQe3EeWOLO6NeOWgwQw+iTA3AIkvQb8yLGQJToYAQUjo6ts0'
216-
'73bX8guz1JLcEgVkXLtjrK6Q5tSCvz3FHLMpnkQQIlWiZvBWPpisA/duvXf3v7FtEhvp52'
217-
'HQPCwmRWyZRB73CNDpwH7PLV/8FqBxFZ97Ryk6gpnaxg5CSkxRyaYoy4ESA28ekOtyckU0E'
218-
'UmPqqeOkPYK6rQxMeBxtsKhOmia8k9XFWiRylWlUgbnu6+R8F0GoBH+qe5URaFiUJ91yted'
219-
'C+2Kq+HWutMT3KUdNgPbgW+SSW8vpMExFhlkDILzt9D97F84sWu4S2gnrtqnjZ7VKpGyIT0f'
220-
'2lQxrJMt5JO2nmCw36FmuAcEJz1/bcL7+C79ibHKM+pLTaDFWTTKPg6uoKvs2+q/p7VsMQvT'
221-
'D1DHSukHsBJM0FIgYQ0ldStUTWfMPp+9ntPA7WJBAdogPbCBGvsku/BDG/iHu2oxhDWiRmpI'
222-
'AYQoAO5awuqa3iKDFdhXbjTm/fjeDPboCoReNGQaA9fZdp2xgtsGH6fPbmczNGymDRZRhUQn'
223-
'UmBKxAWxlBHxxmGmPvcPt6biENi/R0RyBKshQttUtuALvbsB/7NyihyygI0ABjChDImKoRWQ'
224-
'FtFSy4s5zAbtvplT6O/mJADIwGBLyOAsEcI2GjRLGkAIl60gY2JCPtPMAWu9IkDBewMMcrMe'
225-
'A3YNQK34ab2Qosejri8I+dXT2fpf50ZqfTXbttdwnEvOicaw6Yl+4oi+rLjlUkOBNHRxKYB'
226-
'E8si0WT2iAERcZZOrA7dub2daMu8ohq7aKdvlMiRVCdAWCK8ThugyIQSfGe0IL0iUXwkRODo'
227-
'WuZnTvL0puyCjr9Iz7QAacVN4Fbnf6eT1JHW8ANSgpiQA6EC6IFq+FyP8BN+n9eEEeiEVnF'
228-
'tbuC8BYMUhAQiN6BLgEhzUzHyN6HcvvWEk0K2UWOlPQ2mjIgMeYtA8KXpMzeUyuTpdki2VC'
229-
'Jicur/C+3HcWEXQlBDkN7jwDEtdSH5gWdLcgSBGK+Pfd9WBDvRph71REKBzZrB+3hqCICEF'
230-
'YQnMAkIFDSnCvD3VsB4okFB5rX4N122A5dlA1v3OuFz0DAAuRaRBd2G811QPBR0Lmc3ayv5'
231-
'2VldCe2UeuonUHgLqvNtnkE4hx7zkUw8T3wAdwa2ypOKwYzPoyFiV4Qh7A1qAHDmpMj6DcN'
232-
'IH4/52/hmu+f+6hPIMg1iX6DlAEJMW+5DhdDCdciS3Od3pN8wjaeCLKbJdehB+md3alQiF'
233-
'NLBPPtwkU4c2zGygJCxoeGcPUqcQam5VuJEPP8gDgsFoi52MNoeKmhfdt0x8q/tLwi8pvO'
234-
'e3IonV+TnVPoG+UIkx3GQ+IYQnakOjKVaWoIhL7RTSKH2DbcPcGdUu2FC+yCc42JtkB4zB'
235-
'U7hJ4uaAa8XIIwgdEAU4EMg+KInC/mRtq6LdLEL055VV1535l7/r0errkBVs2EaFCSiKTtD'
236-
'AwDgbK4KzZfKYgxJMmXBpTqmmgni0PiPDvvPBk7GyH0TAwsI5TiB5w6xWAY9I8nxVEf7jZN'
237-
'TvEWSOdwa1V//P7mPxxotwLziwWsY0EvtI5A+dhfWPqVaSfybGS6RSGjyAP/PCTmf+w2MfuM'
238-
'aeI4lkefGKXphDmSfRhXMmAbOXOxZM2AiY+DOKYDbvKtCGBxMGOGXNJ7bGTgKeWPhH82T93'
239-
'bdYRAEM0Bub2G/Tgu9a9kDXLJzCqoS3oHD4nfXlCX+J7mkwNCoRHuf9D9+14o7CaAyAEQX'
240-
'Sv5VCLeBtiIMBPYLmHoaNyiDcaV4mePlje8Y9G06++5O5HzQ7HIb69d+JLm+if5DB0lKFe'
241-
'w5HHJ75JAMEDwIZ5JPjkgoADksdgr9KAc7MeK/DVw8gDCxx4NHgTCsAATNSCsXJwsnw/K2'
242-
'z8TlO98Z6wXRkfiYdXe3L35W0RKFAEG6xHXGz/IA+goQfdaTeBH9WY+xBnrsxUYAPFMrDQ'
243-
'ZMYwdly7BBETIBJiHsFP+NgRvggWqWMwpI3oBmMj5Vj7nl39xvV/5xrt85/zAt1W4obWHs'
244-
'OAvabpq0y1MFQGkARiyBCVypz3IjyD3wgMeQ/nwSLn6lMi5EWIvpocEIALFwHz2fXQ6+YR'
245-
'whc40+eOzo7OvwvRchw0JXaZBKTn8RvycrfReJ6ufXizkhcmSaHCKhPWgPEVXSrOMUL/wt1'
246-
'33vYQpxTuOq8nrpM8FC5u683dh0SqDP8kxKv+pWYSY0BmcNoSIZAf1wW04Nf0E95dNiMJlg'
247-
'KgGu7v94NoLq84FcdUGsIVUsFbq7zguIigcQgC8tKl780eJXJI4eGcvXMIKKst79+7lZaJ9f'
248-
'Xeuis0sZKAzPeaNHc2nDoTYJGBoyZD/kINbrWl60Kq/5oJf5YcrH1tStctUNdROJdJuFf'
249-
'eSVei7CgCcMZbc5hDm1grvqs15tkbh1jrtMgtEFQrFlH/0o1fY5Q5VeIWniZ9k0ISpOb8'
250-
'+IMyJLUM18aJ+blP49BW9w99Z5oUXNg+FWlWMlVV4DJUVSAMtphlC4NcICptHsIG9PNd9T'
251-
'xfmCs2XE8AwcTyKbc8ykMMWgZAOfpJ3z2QZZMP59QMhLmSZNPq89O4HNsYt7uPWiTUCJB1x'
252-
'y7AENomU+VcA/BKQvBNAjIQmASY2l+srN1+cgDnRxTIwSakoaJQ5SzpiEKAkvzEgRL0m+lS'
253-
'3fnQjzn/PQEsKAQCLphgBGGQLUJSTd2onUABCIF9WNrrMvWLTu0QBR+zJwjJub2ENuiAhA'
254-
'NiEZtmOvHEg48Hcv24z/ABnGUnniFeh46HxGYCGpDVDCDzD+M0Ll14KkyDuyn3knrfWKia'
255-
'xQs2TNtcYC08YwrpFgOiaCVmB1v8ykTbZQnu19/zgSmXs6QjKFHKZD52U6pIBJPoGc+G6i'
256-
'koVGq9PFK/5FyISxuA7p7R+7c1vEqGzAusRBQwk2j0mabSSNbzhMgPTsVe7Zx54O85TYz9b'
257-
'G7q0QYqx43NQp5J+DyaxgBqC4d9IEn9j8Z8VxRvogo76E5ik7C7gmmjkHXjFDz64oKFxDs5'
258-
'rMQ4IqP4fUo0219/tijMXppoFq1LKbmHySy2/PY/v9H50hhEz8KvE0RkS2xhsP8YlvvGZ3S'
259-
'yapiT0mk/DqjIsBcr/Atffr8/hCjApAAAAAElFTkSuQmCC';
260-
261-
HtmlImage createTestImage() {
262-
return HtmlImage(
263-
html.ImageElement()
264-
..src = 'data:text/plain;base64,$_flutterLogoBase64',
265-
50,
266-
50,
267-
);
268-
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// @dart = 2.6
6+
7+
import 'package:test/bootstrap/browser.dart';
8+
import 'package:test/test.dart';
9+
import 'package:ui/ui.dart' hide TextStyle;
10+
import 'package:ui/src/engine.dart';
11+
12+
import 'screenshot.dart';
13+
import 'testimage.dart';
14+
15+
void main() {
16+
internalBootstrapBrowserTest(() => testMain);
17+
}
18+
19+
void testMain() async {
20+
const double screenWidth = 100.0;
21+
const double screenHeight = 100.0;
22+
const Rect region = Rect.fromLTWH(0, 0, screenWidth, screenHeight);
23+
24+
// Regression test for https://github.com/flutter/flutter/issues/76966
25+
test('Draws image with dstATop color filter', () async {
26+
final RecordingCanvas canvas = RecordingCanvas(region);
27+
canvas.drawImage(createFlutterLogoTestImage(), Offset(10, 10),
28+
Paint()
29+
..colorFilter = EngineColorFilter.mode(Color(0x40000000),
30+
BlendMode.dstATop));
31+
await canvasScreenshot(canvas, 'image_color_fiter_dstatop',
32+
region: region);
33+
});
34+
}

0 commit comments

Comments
 (0)