xref: /aosp_15_r20/external/skia/modules/canvaskit/tests/canvas2d_test.js (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Workerdescribe('Canvas 2D emulation', () => {
2*c8dee2aaSAndroid Build Coastguard Worker    let container;
3*c8dee2aaSAndroid Build Coastguard Worker
4*c8dee2aaSAndroid Build Coastguard Worker    beforeEach(async () => {
5*c8dee2aaSAndroid Build Coastguard Worker        await EverythingLoaded;
6*c8dee2aaSAndroid Build Coastguard Worker        container = document.createElement('div');
7*c8dee2aaSAndroid Build Coastguard Worker        container.innerHTML = `
8*c8dee2aaSAndroid Build Coastguard Worker            <canvas width=600 height=600 id=test></canvas>
9*c8dee2aaSAndroid Build Coastguard Worker            <canvas width=600 height=600 id=report></canvas>`;
10*c8dee2aaSAndroid Build Coastguard Worker        document.body.appendChild(container);
11*c8dee2aaSAndroid Build Coastguard Worker    });
12*c8dee2aaSAndroid Build Coastguard Worker
13*c8dee2aaSAndroid Build Coastguard Worker    afterEach(() => {
14*c8dee2aaSAndroid Build Coastguard Worker        document.body.removeChild(container);
15*c8dee2aaSAndroid Build Coastguard Worker    });
16*c8dee2aaSAndroid Build Coastguard Worker
17*c8dee2aaSAndroid Build Coastguard Worker    const expectColorCloseTo = (a, b) => {
18*c8dee2aaSAndroid Build Coastguard Worker        expect(a.length).toEqual(4);
19*c8dee2aaSAndroid Build Coastguard Worker        expect(b.length).toEqual(4);
20*c8dee2aaSAndroid Build Coastguard Worker        for (let i=0; i<4; i++) {
21*c8dee2aaSAndroid Build Coastguard Worker            expect(a[i]).toBeCloseTo(b[i], 3);
22*c8dee2aaSAndroid Build Coastguard Worker        }
23*c8dee2aaSAndroid Build Coastguard Worker    }
24*c8dee2aaSAndroid Build Coastguard Worker
25*c8dee2aaSAndroid Build Coastguard Worker    describe('color strings', () => {
26*c8dee2aaSAndroid Build Coastguard Worker        const hex = (s) => {
27*c8dee2aaSAndroid Build Coastguard Worker            return parseInt(s, 16);
28*c8dee2aaSAndroid Build Coastguard Worker        }
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker        it('parses hex color strings', () => {
31*c8dee2aaSAndroid Build Coastguard Worker            const parseColor = CanvasKit.parseColorString;
32*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('#FED'),
33*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(hex('FF'), hex('EE'), hex('DD'), 1));
34*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('#FEDC'),
35*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(hex('FF'), hex('EE'), hex('DD'), hex('CC')/255));
36*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('#fed'),
37*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(hex('FF'), hex('EE'), hex('DD'), 1));
38*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('#fedc'),
39*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(hex('FF'), hex('EE'), hex('DD'), hex('CC')/255));
40*c8dee2aaSAndroid Build Coastguard Worker        });
41*c8dee2aaSAndroid Build Coastguard Worker        it('parses rgba color strings', () => {
42*c8dee2aaSAndroid Build Coastguard Worker            const parseColor = CanvasKit.parseColorString;
43*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('rgba(117, 33, 64, 0.75)'),
44*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(117, 33, 64, 0.75));
45*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('rgb(117, 33, 64, 0.75)'),
46*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(117, 33, 64, 0.75));
47*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('rgba(117,33,64)'),
48*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(117, 33, 64, 1.0));
49*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('rgb(117,33, 64)'),
50*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(117, 33, 64, 1.0));
51*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('rgb(117,33, 64, 32%)'),
52*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(117, 33, 64, 0.32));
53*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('rgb(117,33, 64, 0.001)'),
54*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(117, 33, 64, 0.001));
55*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('rgb(117,33,64,0)'),
56*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(117, 33, 64, 0.0));
57*c8dee2aaSAndroid Build Coastguard Worker        });
58*c8dee2aaSAndroid Build Coastguard Worker        it('parses named color strings', () => {
59*c8dee2aaSAndroid Build Coastguard Worker            // Keep this one as the _testing version, because we don't include the large
60*c8dee2aaSAndroid Build Coastguard Worker            // color map by default.
61*c8dee2aaSAndroid Build Coastguard Worker            const parseColor = CanvasKit._testing.parseColor;
62*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('grey'),
63*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(128, 128, 128, 1.0));
64*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('blanchedalmond'),
65*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(255, 235, 205, 1.0));
66*c8dee2aaSAndroid Build Coastguard Worker            expectColorCloseTo(parseColor('transparent'),
67*c8dee2aaSAndroid Build Coastguard Worker                CanvasKit.Color(0, 0, 0, 0));
68*c8dee2aaSAndroid Build Coastguard Worker        });
69*c8dee2aaSAndroid Build Coastguard Worker
70*c8dee2aaSAndroid Build Coastguard Worker        it('properly produces color strings', () => {
71*c8dee2aaSAndroid Build Coastguard Worker            const colorToString = CanvasKit._testing.colorToString;
72*c8dee2aaSAndroid Build Coastguard Worker
73*c8dee2aaSAndroid Build Coastguard Worker            expect(colorToString(CanvasKit.Color(102, 51, 153, 1.0))).toEqual('#663399');
74*c8dee2aaSAndroid Build Coastguard Worker
75*c8dee2aaSAndroid Build Coastguard Worker            expect(colorToString(CanvasKit.Color(255, 235, 205, 0.5))).toEqual(
76*c8dee2aaSAndroid Build Coastguard Worker                                           'rgba(255, 235, 205, 0.50000000)');
77*c8dee2aaSAndroid Build Coastguard Worker        });
78*c8dee2aaSAndroid Build Coastguard Worker
79*c8dee2aaSAndroid Build Coastguard Worker        it('can multiply colors by alpha', () => {
80*c8dee2aaSAndroid Build Coastguard Worker            const multiplyByAlpha = CanvasKit.multiplyByAlpha;
81*c8dee2aaSAndroid Build Coastguard Worker
82*c8dee2aaSAndroid Build Coastguard Worker            const testCases = [
83*c8dee2aaSAndroid Build Coastguard Worker                   {
84*c8dee2aaSAndroid Build Coastguard Worker                    inColor:  CanvasKit.Color(102, 51, 153, 1.0),
85*c8dee2aaSAndroid Build Coastguard Worker                    inAlpha:  1.0,
86*c8dee2aaSAndroid Build Coastguard Worker                    outColor: CanvasKit.Color(102, 51, 153, 1.0),
87*c8dee2aaSAndroid Build Coastguard Worker                },
88*c8dee2aaSAndroid Build Coastguard Worker                {
89*c8dee2aaSAndroid Build Coastguard Worker                    inColor:  CanvasKit.Color(102, 51, 153, 1.0),
90*c8dee2aaSAndroid Build Coastguard Worker                    inAlpha:  0.8,
91*c8dee2aaSAndroid Build Coastguard Worker                    outColor: CanvasKit.Color(102, 51, 153, 0.8),
92*c8dee2aaSAndroid Build Coastguard Worker                },
93*c8dee2aaSAndroid Build Coastguard Worker                {
94*c8dee2aaSAndroid Build Coastguard Worker                    inColor:  CanvasKit.Color(102, 51, 153, 0.8),
95*c8dee2aaSAndroid Build Coastguard Worker                    inAlpha:  0.7,
96*c8dee2aaSAndroid Build Coastguard Worker                    outColor: CanvasKit.Color(102, 51, 153, 0.56),
97*c8dee2aaSAndroid Build Coastguard Worker                },
98*c8dee2aaSAndroid Build Coastguard Worker                {
99*c8dee2aaSAndroid Build Coastguard Worker                    inColor:  CanvasKit.Color(102, 51, 153, 0.8),
100*c8dee2aaSAndroid Build Coastguard Worker                    inAlpha:  1000,
101*c8dee2aaSAndroid Build Coastguard Worker                    outColor: CanvasKit.Color(102, 51, 153, 1.0),
102*c8dee2aaSAndroid Build Coastguard Worker                },
103*c8dee2aaSAndroid Build Coastguard Worker            ];
104*c8dee2aaSAndroid Build Coastguard Worker
105*c8dee2aaSAndroid Build Coastguard Worker            for (const tc of testCases) {
106*c8dee2aaSAndroid Build Coastguard Worker                // Print out the test case if the two don't match.
107*c8dee2aaSAndroid Build Coastguard Worker                expect(multiplyByAlpha(tc.inColor, tc.inAlpha))
108*c8dee2aaSAndroid Build Coastguard Worker                      .toEqual(tc.outColor, JSON.stringify(tc));
109*c8dee2aaSAndroid Build Coastguard Worker            }
110*c8dee2aaSAndroid Build Coastguard Worker        });
111*c8dee2aaSAndroid Build Coastguard Worker    }); // end describe('color string parsing')
112*c8dee2aaSAndroid Build Coastguard Worker
113*c8dee2aaSAndroid Build Coastguard Worker    describe('fonts', () => {
114*c8dee2aaSAndroid Build Coastguard Worker        it('can parse font sizes', () => {
115*c8dee2aaSAndroid Build Coastguard Worker            const parseFontString = CanvasKit._testing.parseFontString;
116*c8dee2aaSAndroid Build Coastguard Worker
117*c8dee2aaSAndroid Build Coastguard Worker            const tests = [{
118*c8dee2aaSAndroid Build Coastguard Worker                    'input': '10px monospace',
119*c8dee2aaSAndroid Build Coastguard Worker                    'output': {
120*c8dee2aaSAndroid Build Coastguard Worker                        'style': '',
121*c8dee2aaSAndroid Build Coastguard Worker                        'variant': '',
122*c8dee2aaSAndroid Build Coastguard Worker                        'weight': '',
123*c8dee2aaSAndroid Build Coastguard Worker                        'sizePx': 10,
124*c8dee2aaSAndroid Build Coastguard Worker                        'family': 'monospace',
125*c8dee2aaSAndroid Build Coastguard Worker                    }
126*c8dee2aaSAndroid Build Coastguard Worker                },
127*c8dee2aaSAndroid Build Coastguard Worker                {
128*c8dee2aaSAndroid Build Coastguard Worker                    'input': '15pt Arial',
129*c8dee2aaSAndroid Build Coastguard Worker                    'output': {
130*c8dee2aaSAndroid Build Coastguard Worker                        'style': '',
131*c8dee2aaSAndroid Build Coastguard Worker                        'variant': '',
132*c8dee2aaSAndroid Build Coastguard Worker                        'weight': '',
133*c8dee2aaSAndroid Build Coastguard Worker                        'sizePx': 20,
134*c8dee2aaSAndroid Build Coastguard Worker                        'family': 'Arial',
135*c8dee2aaSAndroid Build Coastguard Worker                    }
136*c8dee2aaSAndroid Build Coastguard Worker                },
137*c8dee2aaSAndroid Build Coastguard Worker                {
138*c8dee2aaSAndroid Build Coastguard Worker                    'input': '1.5in Arial, san-serif ',
139*c8dee2aaSAndroid Build Coastguard Worker                    'output': {
140*c8dee2aaSAndroid Build Coastguard Worker                        'style': '',
141*c8dee2aaSAndroid Build Coastguard Worker                        'variant': '',
142*c8dee2aaSAndroid Build Coastguard Worker                        'weight': '',
143*c8dee2aaSAndroid Build Coastguard Worker                        'sizePx': 144,
144*c8dee2aaSAndroid Build Coastguard Worker                        'family': 'Arial, san-serif',
145*c8dee2aaSAndroid Build Coastguard Worker                    }
146*c8dee2aaSAndroid Build Coastguard Worker                },
147*c8dee2aaSAndroid Build Coastguard Worker                {
148*c8dee2aaSAndroid Build Coastguard Worker                    'input': '1.5em SuperFont',
149*c8dee2aaSAndroid Build Coastguard Worker                    'output': {
150*c8dee2aaSAndroid Build Coastguard Worker                        'style': '',
151*c8dee2aaSAndroid Build Coastguard Worker                        'variant': '',
152*c8dee2aaSAndroid Build Coastguard Worker                        'weight': '',
153*c8dee2aaSAndroid Build Coastguard Worker                        'sizePx': 24,
154*c8dee2aaSAndroid Build Coastguard Worker                        'family': 'SuperFont',
155*c8dee2aaSAndroid Build Coastguard Worker                    }
156*c8dee2aaSAndroid Build Coastguard Worker                },
157*c8dee2aaSAndroid Build Coastguard Worker            ];
158*c8dee2aaSAndroid Build Coastguard Worker
159*c8dee2aaSAndroid Build Coastguard Worker            for (let i = 0; i < tests.length; i++) {
160*c8dee2aaSAndroid Build Coastguard Worker                expect(parseFontString(tests[i].input)).toEqual(tests[i].output);
161*c8dee2aaSAndroid Build Coastguard Worker            }
162*c8dee2aaSAndroid Build Coastguard Worker        });
163*c8dee2aaSAndroid Build Coastguard Worker
164*c8dee2aaSAndroid Build Coastguard Worker        it('can parse font attributes', () => {
165*c8dee2aaSAndroid Build Coastguard Worker            const parseFontString = CanvasKit._testing.parseFontString;
166*c8dee2aaSAndroid Build Coastguard Worker
167*c8dee2aaSAndroid Build Coastguard Worker            const tests = [{
168*c8dee2aaSAndroid Build Coastguard Worker                    'input': 'bold 10px monospace',
169*c8dee2aaSAndroid Build Coastguard Worker                    'output': {
170*c8dee2aaSAndroid Build Coastguard Worker                        'style': '',
171*c8dee2aaSAndroid Build Coastguard Worker                        'variant': '',
172*c8dee2aaSAndroid Build Coastguard Worker                        'weight': 'bold',
173*c8dee2aaSAndroid Build Coastguard Worker                        'sizePx': 10,
174*c8dee2aaSAndroid Build Coastguard Worker                        'family': 'monospace',
175*c8dee2aaSAndroid Build Coastguard Worker                    }
176*c8dee2aaSAndroid Build Coastguard Worker                },
177*c8dee2aaSAndroid Build Coastguard Worker                {
178*c8dee2aaSAndroid Build Coastguard Worker                    'input': 'italic bold 10px monospace',
179*c8dee2aaSAndroid Build Coastguard Worker                    'output': {
180*c8dee2aaSAndroid Build Coastguard Worker                        'style': 'italic',
181*c8dee2aaSAndroid Build Coastguard Worker                        'variant': '',
182*c8dee2aaSAndroid Build Coastguard Worker                        'weight': 'bold',
183*c8dee2aaSAndroid Build Coastguard Worker                        'sizePx': 10,
184*c8dee2aaSAndroid Build Coastguard Worker                        'family': 'monospace',
185*c8dee2aaSAndroid Build Coastguard Worker                    }
186*c8dee2aaSAndroid Build Coastguard Worker                },
187*c8dee2aaSAndroid Build Coastguard Worker                {
188*c8dee2aaSAndroid Build Coastguard Worker                    'input': 'italic small-caps bold 10px monospace',
189*c8dee2aaSAndroid Build Coastguard Worker                    'output': {
190*c8dee2aaSAndroid Build Coastguard Worker                        'style': 'italic',
191*c8dee2aaSAndroid Build Coastguard Worker                        'variant': 'small-caps',
192*c8dee2aaSAndroid Build Coastguard Worker                        'weight': 'bold',
193*c8dee2aaSAndroid Build Coastguard Worker                        'sizePx': 10,
194*c8dee2aaSAndroid Build Coastguard Worker                        'family': 'monospace',
195*c8dee2aaSAndroid Build Coastguard Worker                    }
196*c8dee2aaSAndroid Build Coastguard Worker                },
197*c8dee2aaSAndroid Build Coastguard Worker                {
198*c8dee2aaSAndroid Build Coastguard Worker                    'input': 'small-caps bold 10px monospace',
199*c8dee2aaSAndroid Build Coastguard Worker                    'output': {
200*c8dee2aaSAndroid Build Coastguard Worker                        'style': '',
201*c8dee2aaSAndroid Build Coastguard Worker                        'variant': 'small-caps',
202*c8dee2aaSAndroid Build Coastguard Worker                        'weight': 'bold',
203*c8dee2aaSAndroid Build Coastguard Worker                        'sizePx': 10,
204*c8dee2aaSAndroid Build Coastguard Worker                        'family': 'monospace',
205*c8dee2aaSAndroid Build Coastguard Worker                    }
206*c8dee2aaSAndroid Build Coastguard Worker                },
207*c8dee2aaSAndroid Build Coastguard Worker                {
208*c8dee2aaSAndroid Build Coastguard Worker                    'input': 'italic 10px monospace',
209*c8dee2aaSAndroid Build Coastguard Worker                    'output': {
210*c8dee2aaSAndroid Build Coastguard Worker                        'style': 'italic',
211*c8dee2aaSAndroid Build Coastguard Worker                        'variant': '',
212*c8dee2aaSAndroid Build Coastguard Worker                        'weight': '',
213*c8dee2aaSAndroid Build Coastguard Worker                        'sizePx': 10,
214*c8dee2aaSAndroid Build Coastguard Worker                        'family': 'monospace',
215*c8dee2aaSAndroid Build Coastguard Worker                    }
216*c8dee2aaSAndroid Build Coastguard Worker                },
217*c8dee2aaSAndroid Build Coastguard Worker                {
218*c8dee2aaSAndroid Build Coastguard Worker                    'input': 'small-caps 10px monospace',
219*c8dee2aaSAndroid Build Coastguard Worker                    'output': {
220*c8dee2aaSAndroid Build Coastguard Worker                        'style': '',
221*c8dee2aaSAndroid Build Coastguard Worker                        'variant': 'small-caps',
222*c8dee2aaSAndroid Build Coastguard Worker                        'weight': '',
223*c8dee2aaSAndroid Build Coastguard Worker                        'sizePx': 10,
224*c8dee2aaSAndroid Build Coastguard Worker                        'family': 'monospace',
225*c8dee2aaSAndroid Build Coastguard Worker                    }
226*c8dee2aaSAndroid Build Coastguard Worker                },
227*c8dee2aaSAndroid Build Coastguard Worker                {
228*c8dee2aaSAndroid Build Coastguard Worker                    'input': 'normal bold 10px monospace',
229*c8dee2aaSAndroid Build Coastguard Worker                    'output': {
230*c8dee2aaSAndroid Build Coastguard Worker                        'style': 'normal',
231*c8dee2aaSAndroid Build Coastguard Worker                        'variant': '',
232*c8dee2aaSAndroid Build Coastguard Worker                        'weight': 'bold',
233*c8dee2aaSAndroid Build Coastguard Worker                        'sizePx': 10,
234*c8dee2aaSAndroid Build Coastguard Worker                        'family': 'monospace',
235*c8dee2aaSAndroid Build Coastguard Worker                    }
236*c8dee2aaSAndroid Build Coastguard Worker                },
237*c8dee2aaSAndroid Build Coastguard Worker            ];
238*c8dee2aaSAndroid Build Coastguard Worker
239*c8dee2aaSAndroid Build Coastguard Worker            for (let i = 0; i < tests.length; i++) {
240*c8dee2aaSAndroid Build Coastguard Worker                expect(parseFontString(tests[i].input)).toEqual(tests[i].output);
241*c8dee2aaSAndroid Build Coastguard Worker            }
242*c8dee2aaSAndroid Build Coastguard Worker        });
243*c8dee2aaSAndroid Build Coastguard Worker    });
244*c8dee2aaSAndroid Build Coastguard Worker
245*c8dee2aaSAndroid Build Coastguard Worker    const multipleCanvasTest = (testname, done, test) => {
246*c8dee2aaSAndroid Build Coastguard Worker        const skcanvas = CanvasKit.MakeCanvas(CANVAS_WIDTH, CANVAS_HEIGHT);
247*c8dee2aaSAndroid Build Coastguard Worker        skcanvas._config = 'software_canvas';
248*c8dee2aaSAndroid Build Coastguard Worker        const realCanvas = document.getElementById('test');
249*c8dee2aaSAndroid Build Coastguard Worker        realCanvas._config = 'html_canvas';
250*c8dee2aaSAndroid Build Coastguard Worker        realCanvas.width = CANVAS_WIDTH;
251*c8dee2aaSAndroid Build Coastguard Worker        realCanvas.height = CANVAS_HEIGHT;
252*c8dee2aaSAndroid Build Coastguard Worker
253*c8dee2aaSAndroid Build Coastguard Worker        if (!done) {
254*c8dee2aaSAndroid Build Coastguard Worker            console.log('debugging canvaskit');
255*c8dee2aaSAndroid Build Coastguard Worker            test(realCanvas);
256*c8dee2aaSAndroid Build Coastguard Worker            test(skcanvas);
257*c8dee2aaSAndroid Build Coastguard Worker            const png = skcanvas.toDataURL();
258*c8dee2aaSAndroid Build Coastguard Worker            const img = document.createElement('img');
259*c8dee2aaSAndroid Build Coastguard Worker            document.body.appendChild(img);
260*c8dee2aaSAndroid Build Coastguard Worker            img.src = png;
261*c8dee2aaSAndroid Build Coastguard Worker            debugger;
262*c8dee2aaSAndroid Build Coastguard Worker            return;
263*c8dee2aaSAndroid Build Coastguard Worker        }
264*c8dee2aaSAndroid Build Coastguard Worker
265*c8dee2aaSAndroid Build Coastguard Worker        let promises = [];
266*c8dee2aaSAndroid Build Coastguard Worker
267*c8dee2aaSAndroid Build Coastguard Worker        for (let canvas of [skcanvas, realCanvas]) {
268*c8dee2aaSAndroid Build Coastguard Worker            test(canvas);
269*c8dee2aaSAndroid Build Coastguard Worker            // canvas has .toDataURL (even though skcanvas is not a real Canvas)
270*c8dee2aaSAndroid Build Coastguard Worker            // so this will work.
271*c8dee2aaSAndroid Build Coastguard Worker            promises.push(reportCanvas(canvas, testname, canvas._config));
272*c8dee2aaSAndroid Build Coastguard Worker        }
273*c8dee2aaSAndroid Build Coastguard Worker        Promise.all(promises).then(() => {
274*c8dee2aaSAndroid Build Coastguard Worker            skcanvas.dispose();
275*c8dee2aaSAndroid Build Coastguard Worker            done();
276*c8dee2aaSAndroid Build Coastguard Worker        }).catch(reportError(done));
277*c8dee2aaSAndroid Build Coastguard Worker    }
278*c8dee2aaSAndroid Build Coastguard Worker
279*c8dee2aaSAndroid Build Coastguard Worker    describe('CanvasContext2D API', () => {
280*c8dee2aaSAndroid Build Coastguard Worker        multipleCanvasGM('all_line_drawing_operations', (canvas) => {
281*c8dee2aaSAndroid Build Coastguard Worker            const ctx = canvas.getContext('2d');
282*c8dee2aaSAndroid Build Coastguard Worker            ctx.scale(3.0, 3.0);
283*c8dee2aaSAndroid Build Coastguard Worker            ctx.moveTo(20, 5);
284*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(30, 20);
285*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(40, 10);
286*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(50, 20);
287*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(60, 0);
288*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(20, 5);
289*c8dee2aaSAndroid Build Coastguard Worker
290*c8dee2aaSAndroid Build Coastguard Worker            ctx.moveTo(20, 80);
291*c8dee2aaSAndroid Build Coastguard Worker            ctx.bezierCurveTo(90, 10, 160, 150, 190, 10);
292*c8dee2aaSAndroid Build Coastguard Worker
293*c8dee2aaSAndroid Build Coastguard Worker            ctx.moveTo(36, 148);
294*c8dee2aaSAndroid Build Coastguard Worker            ctx.quadraticCurveTo(66, 188, 120, 136);
295*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(36, 148);
296*c8dee2aaSAndroid Build Coastguard Worker
297*c8dee2aaSAndroid Build Coastguard Worker            ctx.rect(5, 170, 20, 25);
298*c8dee2aaSAndroid Build Coastguard Worker
299*c8dee2aaSAndroid Build Coastguard Worker            ctx.moveTo(150, 180);
300*c8dee2aaSAndroid Build Coastguard Worker            ctx.arcTo(150, 100, 50, 200, 20);
301*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(160, 160);
302*c8dee2aaSAndroid Build Coastguard Worker
303*c8dee2aaSAndroid Build Coastguard Worker            ctx.moveTo(20, 120);
304*c8dee2aaSAndroid Build Coastguard Worker            ctx.arc(20, 120, 18, 0, 1.75 * Math.PI);
305*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(20, 120);
306*c8dee2aaSAndroid Build Coastguard Worker
307*c8dee2aaSAndroid Build Coastguard Worker            ctx.moveTo(150, 5);
308*c8dee2aaSAndroid Build Coastguard Worker            ctx.ellipse(130, 25, 30, 10, -1*Math.PI/8, Math.PI/6, 1.5*Math.PI)
309*c8dee2aaSAndroid Build Coastguard Worker
310*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineWidth = 2;
311*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
312*c8dee2aaSAndroid Build Coastguard Worker
313*c8dee2aaSAndroid Build Coastguard Worker            // Test edgecases and draw direction
314*c8dee2aaSAndroid Build Coastguard Worker            ctx.beginPath();
315*c8dee2aaSAndroid Build Coastguard Worker            ctx.arc(50, 100, 10, Math.PI, -Math.PI/2);
316*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
317*c8dee2aaSAndroid Build Coastguard Worker            ctx.beginPath();
318*c8dee2aaSAndroid Build Coastguard Worker            ctx.arc(75, 100, 10, Math.PI, -Math.PI/2, true);
319*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
320*c8dee2aaSAndroid Build Coastguard Worker            ctx.beginPath();
321*c8dee2aaSAndroid Build Coastguard Worker            ctx.arc(100, 100, 10, Math.PI, 100.1 * Math.PI, true);
322*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
323*c8dee2aaSAndroid Build Coastguard Worker            ctx.beginPath();
324*c8dee2aaSAndroid Build Coastguard Worker            ctx.arc(125, 100, 10, Math.PI, 100.1 * Math.PI, false);
325*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
326*c8dee2aaSAndroid Build Coastguard Worker            ctx.beginPath();
327*c8dee2aaSAndroid Build Coastguard Worker            ctx.ellipse(155, 100, 10, 15, Math.PI/8, 100.1 * Math.PI, Math.PI, true);
328*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
329*c8dee2aaSAndroid Build Coastguard Worker            ctx.beginPath();
330*c8dee2aaSAndroid Build Coastguard Worker            ctx.ellipse(180, 100, 10, 15, Math.PI/8, Math.PI, 100.1 * Math.PI, true);
331*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
332*c8dee2aaSAndroid Build Coastguard Worker        });
333*c8dee2aaSAndroid Build Coastguard Worker
334*c8dee2aaSAndroid Build Coastguard Worker        multipleCanvasGM('all_matrix_operations', (canvas) => {
335*c8dee2aaSAndroid Build Coastguard Worker            const ctx = canvas.getContext('2d');
336*c8dee2aaSAndroid Build Coastguard Worker            ctx.rect(10, 10, 20, 20);
337*c8dee2aaSAndroid Build Coastguard Worker
338*c8dee2aaSAndroid Build Coastguard Worker            ctx.scale(2.0, 4.0);
339*c8dee2aaSAndroid Build Coastguard Worker            ctx.rect(30, 10, 20, 20);
340*c8dee2aaSAndroid Build Coastguard Worker            ctx.resetTransform();
341*c8dee2aaSAndroid Build Coastguard Worker
342*c8dee2aaSAndroid Build Coastguard Worker            ctx.rotate(Math.PI / 3);
343*c8dee2aaSAndroid Build Coastguard Worker            ctx.rect(50, 10, 20, 20);
344*c8dee2aaSAndroid Build Coastguard Worker            ctx.resetTransform();
345*c8dee2aaSAndroid Build Coastguard Worker
346*c8dee2aaSAndroid Build Coastguard Worker            ctx.translate(30, -2);
347*c8dee2aaSAndroid Build Coastguard Worker            ctx.rect(70, 10, 20, 20);
348*c8dee2aaSAndroid Build Coastguard Worker            ctx.resetTransform();
349*c8dee2aaSAndroid Build Coastguard Worker
350*c8dee2aaSAndroid Build Coastguard Worker            ctx.translate(60, 0);
351*c8dee2aaSAndroid Build Coastguard Worker            ctx.rotate(Math.PI / 6);
352*c8dee2aaSAndroid Build Coastguard Worker            ctx.transform(1.5, 0, 0, 0.5, 0, 0); // effectively scale
353*c8dee2aaSAndroid Build Coastguard Worker            ctx.rect(90, 10, 20, 20);
354*c8dee2aaSAndroid Build Coastguard Worker            ctx.resetTransform();
355*c8dee2aaSAndroid Build Coastguard Worker
356*c8dee2aaSAndroid Build Coastguard Worker            ctx.save();
357*c8dee2aaSAndroid Build Coastguard Worker            ctx.setTransform(2, 0, -.5, 2.5, -40, 120);
358*c8dee2aaSAndroid Build Coastguard Worker            ctx.rect(110, 10, 20, 20);
359*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(110, 0);
360*c8dee2aaSAndroid Build Coastguard Worker            ctx.restore();
361*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(220, 120);
362*c8dee2aaSAndroid Build Coastguard Worker
363*c8dee2aaSAndroid Build Coastguard Worker            ctx.scale(3.0, 3.0);
364*c8dee2aaSAndroid Build Coastguard Worker            ctx.font = '6pt Noto Mono';
365*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillText('This text should be huge', 10, 80);
366*c8dee2aaSAndroid Build Coastguard Worker            ctx.resetTransform();
367*c8dee2aaSAndroid Build Coastguard Worker
368*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeStyle = 'black';
369*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineWidth = 2;
370*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
371*c8dee2aaSAndroid Build Coastguard Worker
372*c8dee2aaSAndroid Build Coastguard Worker            ctx.beginPath();
373*c8dee2aaSAndroid Build Coastguard Worker            ctx.moveTo(250, 30);
374*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(250, 80);
375*c8dee2aaSAndroid Build Coastguard Worker            ctx.scale(3.0, 3.0);
376*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(280/3, 90/3);
377*c8dee2aaSAndroid Build Coastguard Worker            ctx.closePath();
378*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeStyle = 'black';
379*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineWidth = 5;
380*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
381*c8dee2aaSAndroid Build Coastguard Worker        });
382*c8dee2aaSAndroid Build Coastguard Worker
383*c8dee2aaSAndroid Build Coastguard Worker        multipleCanvasGM('shadows_and_save_restore', (canvas) => {
384*c8dee2aaSAndroid Build Coastguard Worker            const ctx = canvas.getContext('2d');
385*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeStyle = '#000';
386*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillStyle = '#CCC';
387*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowColor = 'rebeccapurple';
388*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowBlur = 1;
389*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowOffsetX = 3;
390*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowOffsetY = -8;
391*c8dee2aaSAndroid Build Coastguard Worker            ctx.rect(10, 10, 30, 30);
392*c8dee2aaSAndroid Build Coastguard Worker
393*c8dee2aaSAndroid Build Coastguard Worker            ctx.save();
394*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeStyle = '#C00';
395*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillStyle = '#00C';
396*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowBlur = 0;
397*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowColor = 'transparent';
398*c8dee2aaSAndroid Build Coastguard Worker
399*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
400*c8dee2aaSAndroid Build Coastguard Worker
401*c8dee2aaSAndroid Build Coastguard Worker            ctx.restore();
402*c8dee2aaSAndroid Build Coastguard Worker            ctx.fill();
403*c8dee2aaSAndroid Build Coastguard Worker
404*c8dee2aaSAndroid Build Coastguard Worker            ctx.beginPath();
405*c8dee2aaSAndroid Build Coastguard Worker            ctx.moveTo(36, 148);
406*c8dee2aaSAndroid Build Coastguard Worker            ctx.quadraticCurveTo(66, 188, 120, 136);
407*c8dee2aaSAndroid Build Coastguard Worker            ctx.closePath();
408*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
409*c8dee2aaSAndroid Build Coastguard Worker
410*c8dee2aaSAndroid Build Coastguard Worker            ctx.beginPath();
411*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowColor = '#993366AA';
412*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowOffsetX = 8;
413*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowBlur = 5;
414*c8dee2aaSAndroid Build Coastguard Worker            ctx.setTransform(2, 0, -.5, 2.5, -40, 120);
415*c8dee2aaSAndroid Build Coastguard Worker            ctx.rect(110, 10, 20, 20);
416*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(110, 0);
417*c8dee2aaSAndroid Build Coastguard Worker            ctx.resetTransform();
418*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(220, 120);
419*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
420*c8dee2aaSAndroid Build Coastguard Worker
421*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillStyle = 'green';
422*c8dee2aaSAndroid Build Coastguard Worker            ctx.font = '16pt Noto Mono';
423*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillText('This should be shadowed', 20, 80);
424*c8dee2aaSAndroid Build Coastguard Worker
425*c8dee2aaSAndroid Build Coastguard Worker            ctx.beginPath();
426*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineWidth = 6;
427*c8dee2aaSAndroid Build Coastguard Worker            ctx.ellipse(10, 290, 30, 30, 0, 0, Math.PI * 2);
428*c8dee2aaSAndroid Build Coastguard Worker            ctx.scale(2, 1);
429*c8dee2aaSAndroid Build Coastguard Worker            ctx.moveTo(10, 290)
430*c8dee2aaSAndroid Build Coastguard Worker            ctx.ellipse(10, 290, 30, 60, 0, 0, Math.PI * 2);
431*c8dee2aaSAndroid Build Coastguard Worker            ctx.resetTransform();
432*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowColor = '#993366AA';
433*c8dee2aaSAndroid Build Coastguard Worker            ctx.scale(3, 1);
434*c8dee2aaSAndroid Build Coastguard Worker            ctx.moveTo(10, 290)
435*c8dee2aaSAndroid Build Coastguard Worker            ctx.ellipse(10, 290, 30, 90, 0, 0, Math.PI * 2);
436*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
437*c8dee2aaSAndroid Build Coastguard Worker        });
438*c8dee2aaSAndroid Build Coastguard Worker
439*c8dee2aaSAndroid Build Coastguard Worker        multipleCanvasGM('global_dashed_rects', (canvas) => {
440*c8dee2aaSAndroid Build Coastguard Worker            const ctx = canvas.getContext('2d');
441*c8dee2aaSAndroid Build Coastguard Worker            ctx.scale(1.1, 1.1);
442*c8dee2aaSAndroid Build Coastguard Worker            ctx.translate(10, 10);
443*c8dee2aaSAndroid Build Coastguard Worker            // Shouldn't impact the fillRect calls
444*c8dee2aaSAndroid Build Coastguard Worker            ctx.setLineDash([5, 3]);
445*c8dee2aaSAndroid Build Coastguard Worker
446*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillStyle = 'rgba(200, 0, 100, 0.81)';
447*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillRect(20, 30, 100, 100);
448*c8dee2aaSAndroid Build Coastguard Worker
449*c8dee2aaSAndroid Build Coastguard Worker            ctx.globalAlpha = 0.81;
450*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillStyle = 'rgba(200, 0, 100, 1.0)';
451*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillRect(120, 30, 100, 100);
452*c8dee2aaSAndroid Build Coastguard Worker            // This shouldn't do anything
453*c8dee2aaSAndroid Build Coastguard Worker            ctx.globalAlpha = 0.1;
454*c8dee2aaSAndroid Build Coastguard Worker
455*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillStyle = 'rgba(200, 0, 100, 0.9)';
456*c8dee2aaSAndroid Build Coastguard Worker            ctx.globalAlpha = 0.9;
457*c8dee2aaSAndroid Build Coastguard Worker            // Intentional no-op to check ordering
458*c8dee2aaSAndroid Build Coastguard Worker            ctx.clearRect(220, 30, 100, 100);
459*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillRect(220, 30, 100, 100);
460*c8dee2aaSAndroid Build Coastguard Worker
461*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillRect(320, 30, 100, 100);
462*c8dee2aaSAndroid Build Coastguard Worker            ctx.clearRect(330, 40, 80, 80);
463*c8dee2aaSAndroid Build Coastguard Worker
464*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeStyle = 'blue';
465*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineWidth = 3;
466*c8dee2aaSAndroid Build Coastguard Worker            ctx.setLineDash([5, 3]);
467*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeRect(20, 150, 100, 100);
468*c8dee2aaSAndroid Build Coastguard Worker            ctx.setLineDash([50, 30]);
469*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeRect(125, 150, 100, 100);
470*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineDashOffset = 25;
471*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeRect(230, 150, 100, 100);
472*c8dee2aaSAndroid Build Coastguard Worker            ctx.setLineDash([2, 5, 9]);
473*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeRect(335, 150, 100, 100);
474*c8dee2aaSAndroid Build Coastguard Worker
475*c8dee2aaSAndroid Build Coastguard Worker            ctx.setLineDash([5, 2]);
476*c8dee2aaSAndroid Build Coastguard Worker            ctx.moveTo(336, 400);
477*c8dee2aaSAndroid Build Coastguard Worker            ctx.quadraticCurveTo(366, 488, 120, 450);
478*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineTo(300, 400);
479*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
480*c8dee2aaSAndroid Build Coastguard Worker
481*c8dee2aaSAndroid Build Coastguard Worker            ctx.font = '36pt Noto Mono';
482*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeText('Dashed', 20, 350);
483*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillText('Not Dashed', 20, 400);
484*c8dee2aaSAndroid Build Coastguard Worker        });
485*c8dee2aaSAndroid Build Coastguard Worker
486*c8dee2aaSAndroid Build Coastguard Worker        multipleCanvasGM('gradients_clip', (canvas) => {
487*c8dee2aaSAndroid Build Coastguard Worker            const ctx = canvas.getContext('2d');
488*c8dee2aaSAndroid Build Coastguard Worker
489*c8dee2aaSAndroid Build Coastguard Worker            const rgradient = ctx.createRadialGradient(200, 300, 10, 100, 100, 300);
490*c8dee2aaSAndroid Build Coastguard Worker
491*c8dee2aaSAndroid Build Coastguard Worker            rgradient.addColorStop(0, 'red');
492*c8dee2aaSAndroid Build Coastguard Worker            rgradient.addColorStop(.7, 'white');
493*c8dee2aaSAndroid Build Coastguard Worker            rgradient.addColorStop(1, 'blue');
494*c8dee2aaSAndroid Build Coastguard Worker
495*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillStyle = rgradient;
496*c8dee2aaSAndroid Build Coastguard Worker            ctx.globalAlpha = 0.7;
497*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillRect(0,0,600,600);
498*c8dee2aaSAndroid Build Coastguard Worker            ctx.globalAlpha = 0.95;
499*c8dee2aaSAndroid Build Coastguard Worker
500*c8dee2aaSAndroid Build Coastguard Worker            ctx.beginPath();
501*c8dee2aaSAndroid Build Coastguard Worker            ctx.arc(300, 100, 90, 0, Math.PI*1.66);
502*c8dee2aaSAndroid Build Coastguard Worker            ctx.closePath();
503*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeStyle = 'yellow';
504*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineWidth = 5;
505*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke();
506*c8dee2aaSAndroid Build Coastguard Worker            ctx.save();
507*c8dee2aaSAndroid Build Coastguard Worker            ctx.clip();
508*c8dee2aaSAndroid Build Coastguard Worker
509*c8dee2aaSAndroid Build Coastguard Worker            const lgradient = ctx.createLinearGradient(200, 20, 420, 40);
510*c8dee2aaSAndroid Build Coastguard Worker
511*c8dee2aaSAndroid Build Coastguard Worker            lgradient.addColorStop(0, 'green');
512*c8dee2aaSAndroid Build Coastguard Worker            lgradient.addColorStop(.5, 'cyan');
513*c8dee2aaSAndroid Build Coastguard Worker            lgradient.addColorStop(1, 'orange');
514*c8dee2aaSAndroid Build Coastguard Worker
515*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillStyle = lgradient;
516*c8dee2aaSAndroid Build Coastguard Worker
517*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillRect(200, 30, 200, 300);
518*c8dee2aaSAndroid Build Coastguard Worker
519*c8dee2aaSAndroid Build Coastguard Worker            ctx.restore();
520*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillRect(550, 550, 40, 40);
521*c8dee2aaSAndroid Build Coastguard Worker        });
522*c8dee2aaSAndroid Build Coastguard Worker
523*c8dee2aaSAndroid Build Coastguard Worker        multipleCanvasGM('get_put_imagedata', (canvas) => {
524*c8dee2aaSAndroid Build Coastguard Worker            const ctx = canvas.getContext('2d');
525*c8dee2aaSAndroid Build Coastguard Worker            // Make a gradient so we see if the pixels copying worked
526*c8dee2aaSAndroid Build Coastguard Worker            const grad = ctx.createLinearGradient(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
527*c8dee2aaSAndroid Build Coastguard Worker            grad.addColorStop(0, 'yellow');
528*c8dee2aaSAndroid Build Coastguard Worker            grad.addColorStop(1, 'red');
529*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillStyle = grad;
530*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
531*c8dee2aaSAndroid Build Coastguard Worker
532*c8dee2aaSAndroid Build Coastguard Worker            const iData = ctx.getImageData(400, 100, 200, 150);
533*c8dee2aaSAndroid Build Coastguard Worker            expect(iData.width).toBe(200);
534*c8dee2aaSAndroid Build Coastguard Worker            expect(iData.height).toBe(150);
535*c8dee2aaSAndroid Build Coastguard Worker            expect(iData.data.byteLength).toBe(200*150*4);
536*c8dee2aaSAndroid Build Coastguard Worker            ctx.putImageData(iData, 10, 10);
537*c8dee2aaSAndroid Build Coastguard Worker            ctx.putImageData(iData, 350, 350, 100, 75, 45, 40);
538*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeRect(350, 350, 200, 150);
539*c8dee2aaSAndroid Build Coastguard Worker
540*c8dee2aaSAndroid Build Coastguard Worker            const box = ctx.createImageData(20, 40);
541*c8dee2aaSAndroid Build Coastguard Worker            ctx.putImageData(box, 10, 300);
542*c8dee2aaSAndroid Build Coastguard Worker            const biggerBox = ctx.createImageData(iData);
543*c8dee2aaSAndroid Build Coastguard Worker            ctx.putImageData(biggerBox, 10, 350);
544*c8dee2aaSAndroid Build Coastguard Worker            expect(biggerBox.width).toBe(iData.width);
545*c8dee2aaSAndroid Build Coastguard Worker            expect(biggerBox.height).toBe(iData.height);
546*c8dee2aaSAndroid Build Coastguard Worker        });
547*c8dee2aaSAndroid Build Coastguard Worker
548*c8dee2aaSAndroid Build Coastguard Worker        multipleCanvasGM('shadows_with_rotate_skbug_9947', (canvas) => {
549*c8dee2aaSAndroid Build Coastguard Worker            const ctx = canvas.getContext('2d');
550*c8dee2aaSAndroid Build Coastguard Worker            const angle = 240;
551*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillStyle = 'white';
552*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
553*c8dee2aaSAndroid Build Coastguard Worker            ctx.save();
554*c8dee2aaSAndroid Build Coastguard Worker            ctx.translate(80, 80);
555*c8dee2aaSAndroid Build Coastguard Worker            ctx.rotate((angle * Math.PI) / 180);
556*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowOffsetX = 10;
557*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowOffsetY = 10;
558*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowColor = 'rgba(100,100,100,0.5)';
559*c8dee2aaSAndroid Build Coastguard Worker            ctx.shadowBlur = 1;
560*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillStyle = 'black';
561*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeStyle = 'red';
562*c8dee2aaSAndroid Build Coastguard Worker            ctx.beginPath();
563*c8dee2aaSAndroid Build Coastguard Worker            ctx.rect(-20, -20, 40, 40);
564*c8dee2aaSAndroid Build Coastguard Worker            ctx.fill();
565*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillRect(30, 30, 40, 40);
566*c8dee2aaSAndroid Build Coastguard Worker            ctx.strokeRect(30, -20, 40, 40);
567*c8dee2aaSAndroid Build Coastguard Worker            ctx.fillText('text', -20, -30);
568*c8dee2aaSAndroid Build Coastguard Worker            ctx.restore();
569*c8dee2aaSAndroid Build Coastguard Worker        });
570*c8dee2aaSAndroid Build Coastguard Worker
571*c8dee2aaSAndroid Build Coastguard Worker        describe('using images', () => {
572*c8dee2aaSAndroid Build Coastguard Worker            let skImageData = null;
573*c8dee2aaSAndroid Build Coastguard Worker            let htmlImage = null;
574*c8dee2aaSAndroid Build Coastguard Worker            const skPromise = fetch('/assets/mandrill_512.png')
575*c8dee2aaSAndroid Build Coastguard Worker                .then((response) => response.arrayBuffer())
576*c8dee2aaSAndroid Build Coastguard Worker                .then((buffer) => {
577*c8dee2aaSAndroid Build Coastguard Worker                    skImageData = buffer;
578*c8dee2aaSAndroid Build Coastguard Worker
579*c8dee2aaSAndroid Build Coastguard Worker                });
580*c8dee2aaSAndroid Build Coastguard Worker            const realPromise = fetch('/assets/mandrill_512.png')
581*c8dee2aaSAndroid Build Coastguard Worker                .then((response) => response.blob())
582*c8dee2aaSAndroid Build Coastguard Worker                .then((blob) => createImageBitmap(blob))
583*c8dee2aaSAndroid Build Coastguard Worker                .then((bitmap) => {
584*c8dee2aaSAndroid Build Coastguard Worker                    htmlImage = bitmap;
585*c8dee2aaSAndroid Build Coastguard Worker                });
586*c8dee2aaSAndroid Build Coastguard Worker
587*c8dee2aaSAndroid Build Coastguard Worker            beforeEach(async () => {
588*c8dee2aaSAndroid Build Coastguard Worker                await skPromise;
589*c8dee2aaSAndroid Build Coastguard Worker                await realPromise;
590*c8dee2aaSAndroid Build Coastguard Worker            });
591*c8dee2aaSAndroid Build Coastguard Worker
592*c8dee2aaSAndroid Build Coastguard Worker            multipleCanvasGM('draw_patterns', (canvas) => {
593*c8dee2aaSAndroid Build Coastguard Worker                const ctx = canvas.getContext('2d');
594*c8dee2aaSAndroid Build Coastguard Worker                let img = htmlImage;
595*c8dee2aaSAndroid Build Coastguard Worker                if (canvas._config === 'software_canvas') {
596*c8dee2aaSAndroid Build Coastguard Worker                    img = canvas.decodeImage(skImageData);
597*c8dee2aaSAndroid Build Coastguard Worker                }
598*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillStyle = '#EEE';
599*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
600*c8dee2aaSAndroid Build Coastguard Worker                ctx.lineWidth = 20;
601*c8dee2aaSAndroid Build Coastguard Worker                ctx.scale(0.2, 0.4);
602*c8dee2aaSAndroid Build Coastguard Worker
603*c8dee2aaSAndroid Build Coastguard Worker                let pattern = ctx.createPattern(img, 'repeat');
604*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillStyle = pattern;
605*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillRect(0, 0, 1500, 750);
606*c8dee2aaSAndroid Build Coastguard Worker
607*c8dee2aaSAndroid Build Coastguard Worker                pattern = ctx.createPattern(img, 'repeat-x');
608*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillStyle = pattern;
609*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillRect(1500, 0, 3000, 750);
610*c8dee2aaSAndroid Build Coastguard Worker
611*c8dee2aaSAndroid Build Coastguard Worker                ctx.globalAlpha = 0.7
612*c8dee2aaSAndroid Build Coastguard Worker                pattern = ctx.createPattern(img, 'repeat-y');
613*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillStyle = pattern;
614*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillRect(0, 750, 1500, 1500);
615*c8dee2aaSAndroid Build Coastguard Worker                ctx.strokeRect(0, 750, 1500, 1500);
616*c8dee2aaSAndroid Build Coastguard Worker
617*c8dee2aaSAndroid Build Coastguard Worker                pattern = ctx.createPattern(img, 'no-repeat');
618*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillStyle = pattern;
619*c8dee2aaSAndroid Build Coastguard Worker                pattern.setTransform({a: 1, b: -.1, c:.1, d: 0.5, e: 1800, f:800});
620*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillRect(0, 0, 3000, 1500);
621*c8dee2aaSAndroid Build Coastguard Worker            });
622*c8dee2aaSAndroid Build Coastguard Worker
623*c8dee2aaSAndroid Build Coastguard Worker            multipleCanvasGM('draw_image', (canvas) => {
624*c8dee2aaSAndroid Build Coastguard Worker                let ctx = canvas.getContext('2d');
625*c8dee2aaSAndroid Build Coastguard Worker                let img = htmlImage;
626*c8dee2aaSAndroid Build Coastguard Worker                if (canvas._config === 'software_canvas') {
627*c8dee2aaSAndroid Build Coastguard Worker                    img = canvas.decodeImage(skImageData);
628*c8dee2aaSAndroid Build Coastguard Worker                }
629*c8dee2aaSAndroid Build Coastguard Worker                ctx.drawImage(img, 30, -200);
630*c8dee2aaSAndroid Build Coastguard Worker
631*c8dee2aaSAndroid Build Coastguard Worker                ctx.globalAlpha = 0.7
632*c8dee2aaSAndroid Build Coastguard Worker                ctx.rotate(.1);
633*c8dee2aaSAndroid Build Coastguard Worker                ctx.imageSmoothingQuality = 'medium';
634*c8dee2aaSAndroid Build Coastguard Worker                ctx.drawImage(img, 200, 350, 150, 100);
635*c8dee2aaSAndroid Build Coastguard Worker                ctx.rotate(-.2);
636*c8dee2aaSAndroid Build Coastguard Worker                ctx.imageSmoothingEnabled = false;
637*c8dee2aaSAndroid Build Coastguard Worker                ctx.drawImage(img, 100, 150, 400, 350, 10, 400, 150, 100);
638*c8dee2aaSAndroid Build Coastguard Worker            });
639*c8dee2aaSAndroid Build Coastguard Worker        }); // end describe('using images')
640*c8dee2aaSAndroid Build Coastguard Worker
641*c8dee2aaSAndroid Build Coastguard Worker        {
642*c8dee2aaSAndroid Build Coastguard Worker            const drawPoint = (ctx, x, y, color) => {
643*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillStyle = color;
644*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillRect(x, y, 1, 1);
645*c8dee2aaSAndroid Build Coastguard Worker            }
646*c8dee2aaSAndroid Build Coastguard Worker            const IN = 'purple';
647*c8dee2aaSAndroid Build Coastguard Worker            const OUT = 'orange';
648*c8dee2aaSAndroid Build Coastguard Worker            const SCALE = 8;
649*c8dee2aaSAndroid Build Coastguard Worker
650*c8dee2aaSAndroid Build Coastguard Worker            // Check to see if these points are in or out on each of the
651*c8dee2aaSAndroid Build Coastguard Worker            // test configurations.
652*c8dee2aaSAndroid Build Coastguard Worker            const pts = [[3, 3], [4, 4], [5, 5], [10, 10], [8, 10], [6, 10],
653*c8dee2aaSAndroid Build Coastguard Worker                         [6.5, 9], [15, 10], [17, 10], [17, 11], [24, 24],
654*c8dee2aaSAndroid Build Coastguard Worker                         [25, 25], [26, 26], [27, 27]];
655*c8dee2aaSAndroid Build Coastguard Worker            const tests = [
656*c8dee2aaSAndroid Build Coastguard Worker                {
657*c8dee2aaSAndroid Build Coastguard Worker                    xOffset: 0,
658*c8dee2aaSAndroid Build Coastguard Worker                    yOffset: 0,
659*c8dee2aaSAndroid Build Coastguard Worker                    fillType: 'nonzero',
660*c8dee2aaSAndroid Build Coastguard Worker                    strokeWidth: 0,
661*c8dee2aaSAndroid Build Coastguard Worker                    testFn: (ctx, x, y) => ctx.isPointInPath(x * SCALE, y * SCALE, 'nonzero'),
662*c8dee2aaSAndroid Build Coastguard Worker                },
663*c8dee2aaSAndroid Build Coastguard Worker                {
664*c8dee2aaSAndroid Build Coastguard Worker                    xOffset: 30,
665*c8dee2aaSAndroid Build Coastguard Worker                    yOffset: 0,
666*c8dee2aaSAndroid Build Coastguard Worker                    fillType: 'evenodd',
667*c8dee2aaSAndroid Build Coastguard Worker                    strokeWidth: 0,
668*c8dee2aaSAndroid Build Coastguard Worker                    testFn: (ctx, x, y) => ctx.isPointInPath(x * SCALE, y * SCALE, 'evenodd'),
669*c8dee2aaSAndroid Build Coastguard Worker                },
670*c8dee2aaSAndroid Build Coastguard Worker                {
671*c8dee2aaSAndroid Build Coastguard Worker                    xOffset: 0,
672*c8dee2aaSAndroid Build Coastguard Worker                    yOffset: 30,
673*c8dee2aaSAndroid Build Coastguard Worker                    fillType: null,
674*c8dee2aaSAndroid Build Coastguard Worker                    strokeWidth: 1,
675*c8dee2aaSAndroid Build Coastguard Worker                    testFn: (ctx, x, y) => ctx.isPointInStroke(x * SCALE, y * SCALE),
676*c8dee2aaSAndroid Build Coastguard Worker                },
677*c8dee2aaSAndroid Build Coastguard Worker                {
678*c8dee2aaSAndroid Build Coastguard Worker                    xOffset: 30,
679*c8dee2aaSAndroid Build Coastguard Worker                    yOffset: 30,
680*c8dee2aaSAndroid Build Coastguard Worker                    fillType: null,
681*c8dee2aaSAndroid Build Coastguard Worker                    strokeWidth: 2,
682*c8dee2aaSAndroid Build Coastguard Worker                    testFn: (ctx, x, y) => ctx.isPointInStroke(x * SCALE, y * SCALE),
683*c8dee2aaSAndroid Build Coastguard Worker                },
684*c8dee2aaSAndroid Build Coastguard Worker            ];
685*c8dee2aaSAndroid Build Coastguard Worker            multipleCanvasGM('points_in_path_stroke', (canvas) => {
686*c8dee2aaSAndroid Build Coastguard Worker                const ctx = canvas.getContext('2d');
687*c8dee2aaSAndroid Build Coastguard Worker                ctx.font = '20px Noto Mono';
688*c8dee2aaSAndroid Build Coastguard Worker                // Draw some visual aids
689*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillText('path-nonzero', 60, 30);
690*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillText('path-evenodd', 300, 30);
691*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillText('stroke-1px-wide', 60, 260);
692*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillText('stroke-2px-wide', 300, 260);
693*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillText('purple is IN, orange is OUT', 20, 560);
694*c8dee2aaSAndroid Build Coastguard Worker
695*c8dee2aaSAndroid Build Coastguard Worker                // Scale up to make single pixels easier to see
696*c8dee2aaSAndroid Build Coastguard Worker                ctx.scale(SCALE, SCALE);
697*c8dee2aaSAndroid Build Coastguard Worker                for (const test of tests) {
698*c8dee2aaSAndroid Build Coastguard Worker                    ctx.beginPath();
699*c8dee2aaSAndroid Build Coastguard Worker                    const xOffset = test.xOffset;
700*c8dee2aaSAndroid Build Coastguard Worker                    const yOffset = test.yOffset;
701*c8dee2aaSAndroid Build Coastguard Worker
702*c8dee2aaSAndroid Build Coastguard Worker                    ctx.fillStyle = '#AAA';
703*c8dee2aaSAndroid Build Coastguard Worker                    ctx.lineWidth = test.strokeWidth;
704*c8dee2aaSAndroid Build Coastguard Worker                    ctx.rect(5+xOffset, 5+yOffset, 20, 20);
705*c8dee2aaSAndroid Build Coastguard Worker                    ctx.arc(15+xOffset, 15+yOffset, 8, 0, Math.PI*2, false);
706*c8dee2aaSAndroid Build Coastguard Worker                    if (test.fillType) {
707*c8dee2aaSAndroid Build Coastguard Worker                        ctx.fill(test.fillType);
708*c8dee2aaSAndroid Build Coastguard Worker                    } else {
709*c8dee2aaSAndroid Build Coastguard Worker                        ctx.stroke();
710*c8dee2aaSAndroid Build Coastguard Worker                    }
711*c8dee2aaSAndroid Build Coastguard Worker
712*c8dee2aaSAndroid Build Coastguard Worker                    for (const pt of pts) {
713*c8dee2aaSAndroid Build Coastguard Worker                        let [x, y] = pt;
714*c8dee2aaSAndroid Build Coastguard Worker                        x += xOffset;
715*c8dee2aaSAndroid Build Coastguard Worker                        y += yOffset;
716*c8dee2aaSAndroid Build Coastguard Worker                        // naively apply transform when querying because the points queried
717*c8dee2aaSAndroid Build Coastguard Worker                        // ignore the CTM.
718*c8dee2aaSAndroid Build Coastguard Worker                        if (test.testFn(ctx, x, y)) {
719*c8dee2aaSAndroid Build Coastguard Worker                          drawPoint(ctx, x, y, IN);
720*c8dee2aaSAndroid Build Coastguard Worker                        } else {
721*c8dee2aaSAndroid Build Coastguard Worker                          drawPoint(ctx, x, y, OUT);
722*c8dee2aaSAndroid Build Coastguard Worker                        }
723*c8dee2aaSAndroid Build Coastguard Worker                    }
724*c8dee2aaSAndroid Build Coastguard Worker                }
725*c8dee2aaSAndroid Build Coastguard Worker            });
726*c8dee2aaSAndroid Build Coastguard Worker        }
727*c8dee2aaSAndroid Build Coastguard Worker
728*c8dee2aaSAndroid Build Coastguard Worker        describe('loading custom fonts', () => {
729*c8dee2aaSAndroid Build Coastguard Worker            const realFontLoaded = new FontFace('BungeeNonSystem', 'url(/assets/Bungee-Regular.ttf)', {
730*c8dee2aaSAndroid Build Coastguard Worker                'family': 'BungeeNonSystem', // Make sure the canvas does not use the system font
731*c8dee2aaSAndroid Build Coastguard Worker                'style': 'normal',
732*c8dee2aaSAndroid Build Coastguard Worker                'weight': '400',
733*c8dee2aaSAndroid Build Coastguard Worker            }).load().then((font) => {
734*c8dee2aaSAndroid Build Coastguard Worker                document.fonts.add(font);
735*c8dee2aaSAndroid Build Coastguard Worker            });
736*c8dee2aaSAndroid Build Coastguard Worker
737*c8dee2aaSAndroid Build Coastguard Worker            let fontBuffer = null;
738*c8dee2aaSAndroid Build Coastguard Worker            const skFontLoaded = fetch('/assets/Bungee-Regular.ttf').then(
739*c8dee2aaSAndroid Build Coastguard Worker                (response) => response.arrayBuffer()).then(
740*c8dee2aaSAndroid Build Coastguard Worker                (buffer) => {
741*c8dee2aaSAndroid Build Coastguard Worker                    fontBuffer = buffer;
742*c8dee2aaSAndroid Build Coastguard Worker                });
743*c8dee2aaSAndroid Build Coastguard Worker
744*c8dee2aaSAndroid Build Coastguard Worker            beforeEach(async () => {
745*c8dee2aaSAndroid Build Coastguard Worker                await realFontLoaded;
746*c8dee2aaSAndroid Build Coastguard Worker                await skFontLoaded;
747*c8dee2aaSAndroid Build Coastguard Worker            });
748*c8dee2aaSAndroid Build Coastguard Worker
749*c8dee2aaSAndroid Build Coastguard Worker            multipleCanvasGM('custom_font', (canvas) => {
750*c8dee2aaSAndroid Build Coastguard Worker                if (canvas.loadFont) {
751*c8dee2aaSAndroid Build Coastguard Worker                    canvas.loadFont(fontBuffer, {
752*c8dee2aaSAndroid Build Coastguard Worker                        'family': 'BungeeNonSystem',
753*c8dee2aaSAndroid Build Coastguard Worker                        'style': 'normal',
754*c8dee2aaSAndroid Build Coastguard Worker                        'weight': '400',
755*c8dee2aaSAndroid Build Coastguard Worker                    });
756*c8dee2aaSAndroid Build Coastguard Worker                }
757*c8dee2aaSAndroid Build Coastguard Worker                const ctx = canvas.getContext('2d');
758*c8dee2aaSAndroid Build Coastguard Worker
759*c8dee2aaSAndroid Build Coastguard Worker                ctx.font = '20px monospace';
760*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillText('20 px monospace', 10, 30);
761*c8dee2aaSAndroid Build Coastguard Worker
762*c8dee2aaSAndroid Build Coastguard Worker                ctx.font = '2.0em BungeeNonSystem';
763*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillText('2.0em Bungee filled', 10, 80);
764*c8dee2aaSAndroid Build Coastguard Worker                ctx.strokeText('2.0em Bungee stroked', 10, 130);
765*c8dee2aaSAndroid Build Coastguard Worker
766*c8dee2aaSAndroid Build Coastguard Worker                const m = ctx.measureText('A phrase in English');
767*c8dee2aaSAndroid Build Coastguard Worker                expect(m).toBeTruthy();
768*c8dee2aaSAndroid Build Coastguard Worker                expect(m['width']).toBeTruthy();
769*c8dee2aaSAndroid Build Coastguard Worker
770*c8dee2aaSAndroid Build Coastguard Worker                ctx.font = '40pt monospace';
771*c8dee2aaSAndroid Build Coastguard Worker                ctx.strokeText('40pt monospace', 10, 200);
772*c8dee2aaSAndroid Build Coastguard Worker
773*c8dee2aaSAndroid Build Coastguard Worker                // bold wasn't defined, so should fallback to just the 400 weight
774*c8dee2aaSAndroid Build Coastguard Worker                ctx.font = 'bold 45px BungeeNonSystem';
775*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillText('45px Bungee filled', 10, 260);
776*c8dee2aaSAndroid Build Coastguard Worker            });
777*c8dee2aaSAndroid Build Coastguard Worker        }); // describe('loading custom fonts')
778*c8dee2aaSAndroid Build Coastguard Worker
779*c8dee2aaSAndroid Build Coastguard Worker        it('can read default properties', () => {
780*c8dee2aaSAndroid Build Coastguard Worker            const skcanvas = CanvasKit.MakeCanvas(CANVAS_WIDTH, CANVAS_HEIGHT);
781*c8dee2aaSAndroid Build Coastguard Worker            const realCanvas = document.getElementById('test');
782*c8dee2aaSAndroid Build Coastguard Worker            realCanvas.width = CANVAS_WIDTH;
783*c8dee2aaSAndroid Build Coastguard Worker            realCanvas.height = CANVAS_HEIGHT;
784*c8dee2aaSAndroid Build Coastguard Worker
785*c8dee2aaSAndroid Build Coastguard Worker            const skcontext = skcanvas.getContext('2d');
786*c8dee2aaSAndroid Build Coastguard Worker            const realContext = realCanvas.getContext('2d');
787*c8dee2aaSAndroid Build Coastguard Worker            // The skia canvas only comes with a monospace font by default
788*c8dee2aaSAndroid Build Coastguard Worker            // Set the html canvas to be monospace too.
789*c8dee2aaSAndroid Build Coastguard Worker            realContext.font = '10px monospace';
790*c8dee2aaSAndroid Build Coastguard Worker
791*c8dee2aaSAndroid Build Coastguard Worker            const toTest = ['font', 'lineWidth', 'strokeStyle', 'lineCap',
792*c8dee2aaSAndroid Build Coastguard Worker                            'lineJoin', 'miterLimit', 'shadowOffsetY',
793*c8dee2aaSAndroid Build Coastguard Worker                            'shadowBlur', 'shadowColor', 'shadowOffsetX',
794*c8dee2aaSAndroid Build Coastguard Worker                            'globalAlpha', 'globalCompositeOperation',
795*c8dee2aaSAndroid Build Coastguard Worker                            'lineDashOffset', 'imageSmoothingEnabled',
796*c8dee2aaSAndroid Build Coastguard Worker                            'imageFilterQuality'];
797*c8dee2aaSAndroid Build Coastguard Worker
798*c8dee2aaSAndroid Build Coastguard Worker            // Compare all the default values of the properties of skcanvas
799*c8dee2aaSAndroid Build Coastguard Worker            // to the default values on the properties of a real canvas.
800*c8dee2aaSAndroid Build Coastguard Worker            for(let attr of toTest) {
801*c8dee2aaSAndroid Build Coastguard Worker                expect(skcontext[attr]).toBe(realContext[attr], attr);
802*c8dee2aaSAndroid Build Coastguard Worker            }
803*c8dee2aaSAndroid Build Coastguard Worker
804*c8dee2aaSAndroid Build Coastguard Worker            skcanvas.dispose();
805*c8dee2aaSAndroid Build Coastguard Worker        });
806*c8dee2aaSAndroid Build Coastguard Worker    }); // end describe('CanvasContext2D API')
807*c8dee2aaSAndroid Build Coastguard Worker
808*c8dee2aaSAndroid Build Coastguard Worker    describe('Path2D API', () => {
809*c8dee2aaSAndroid Build Coastguard Worker        multipleCanvasGM('path2d_line_drawing_operations', (canvas) => {
810*c8dee2aaSAndroid Build Coastguard Worker            const ctx = canvas.getContext('2d');
811*c8dee2aaSAndroid Build Coastguard Worker            let clock;
812*c8dee2aaSAndroid Build Coastguard Worker            let path;
813*c8dee2aaSAndroid Build Coastguard Worker            if (canvas.makePath2D) {
814*c8dee2aaSAndroid Build Coastguard Worker                clock = canvas.makePath2D('M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z');
815*c8dee2aaSAndroid Build Coastguard Worker                path = canvas.makePath2D();
816*c8dee2aaSAndroid Build Coastguard Worker            } else {
817*c8dee2aaSAndroid Build Coastguard Worker                clock = new Path2D('M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z')
818*c8dee2aaSAndroid Build Coastguard Worker                path = new Path2D();
819*c8dee2aaSAndroid Build Coastguard Worker            }
820*c8dee2aaSAndroid Build Coastguard Worker            path.moveTo(20, 5);
821*c8dee2aaSAndroid Build Coastguard Worker            path.lineTo(30, 20);
822*c8dee2aaSAndroid Build Coastguard Worker            path.lineTo(40, 10);
823*c8dee2aaSAndroid Build Coastguard Worker            path.lineTo(50, 20);
824*c8dee2aaSAndroid Build Coastguard Worker            path.lineTo(60, 0);
825*c8dee2aaSAndroid Build Coastguard Worker            path.lineTo(20, 5);
826*c8dee2aaSAndroid Build Coastguard Worker
827*c8dee2aaSAndroid Build Coastguard Worker            path.moveTo(20, 80);
828*c8dee2aaSAndroid Build Coastguard Worker            path.bezierCurveTo(90, 10, 160, 150, 190, 10);
829*c8dee2aaSAndroid Build Coastguard Worker
830*c8dee2aaSAndroid Build Coastguard Worker            path.moveTo(36, 148);
831*c8dee2aaSAndroid Build Coastguard Worker            path.quadraticCurveTo(66, 188, 120, 136);
832*c8dee2aaSAndroid Build Coastguard Worker            path.lineTo(36, 148);
833*c8dee2aaSAndroid Build Coastguard Worker
834*c8dee2aaSAndroid Build Coastguard Worker            path.rect(5, 170, 20, 25);
835*c8dee2aaSAndroid Build Coastguard Worker
836*c8dee2aaSAndroid Build Coastguard Worker            path.moveTo(150, 180);
837*c8dee2aaSAndroid Build Coastguard Worker            path.arcTo(150, 100, 50, 200, 20);
838*c8dee2aaSAndroid Build Coastguard Worker            path.lineTo(160, 160);
839*c8dee2aaSAndroid Build Coastguard Worker
840*c8dee2aaSAndroid Build Coastguard Worker            path.moveTo(20, 120);
841*c8dee2aaSAndroid Build Coastguard Worker            path.arc(20, 120, 18, 0, 1.75 * Math.PI);
842*c8dee2aaSAndroid Build Coastguard Worker            path.lineTo(20, 120);
843*c8dee2aaSAndroid Build Coastguard Worker
844*c8dee2aaSAndroid Build Coastguard Worker            path.moveTo(150, 5);
845*c8dee2aaSAndroid Build Coastguard Worker            path.ellipse(130, 25, 30, 10, -1*Math.PI/8, Math.PI/6, 1.5*Math.PI)
846*c8dee2aaSAndroid Build Coastguard Worker
847*c8dee2aaSAndroid Build Coastguard Worker            ctx.lineWidth = 2;
848*c8dee2aaSAndroid Build Coastguard Worker            ctx.scale(3.0, 3.0);
849*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke(path);
850*c8dee2aaSAndroid Build Coastguard Worker            ctx.stroke(clock);
851*c8dee2aaSAndroid Build Coastguard Worker        });
852*c8dee2aaSAndroid Build Coastguard Worker    }); // end describe('Path2D API')
853*c8dee2aaSAndroid Build Coastguard Worker});
854