Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / LayoutTests / fast / canvas / canvas-composite-stroke-alpha.html
1 <html>
2   <head>
3     <title>A canvas globalCompositeOperation test with alpha blending</title>
4     <!-- This test was inspired by http://canvex.lazyilluminati.com/misc/compositex.html -->
5     <script type="application/x-javascript">
6       if (window.testRunner) {
7           testRunner.dumpAsText();
8           testRunner.waitUntilDone();
9       }
10
11       var compositeTypes = [
12           'source-over','source-in','source-out','source-atop',
13           'destination-over','destination-in','destination-out','destination-atop',
14           'lighter','copy','xor'
15       ];
16       var inputColors = [
17           { source: [255, 0, 0, 255], destination: [0, 255, 0, 255] },
18           { source: [255, 0, 0, 255], destination: [0, 255, 0, 0] },
19           { source: [255, 0, 0, 255], destination: [0, 255, 0, 1] },
20           { source: [0, 255, 0, 0], destination: [255, 0, 0, 255] },
21           { source: [0, 255, 0, 1], destination: [255, 0, 0, 255] },
22           { source: [255, 0, 0, 0], destination: [0, 255, 0, 255] },
23           { source: [255, 0, 0, 127], destination: [0, 255, 0, 127] },
24           { source: [255, 0, 0, 255], destination: [0, 255, 0, 127] },
25           { source: [255, 0, 0, 127], destination: [0, 255, 0, 255] },
26           { source: [127, 0, 0, 255], destination: [0, 127, 0, 127] },
27           { source: [127, 0, 0, 127], destination: [0, 127, 0, 255] },
28           { source: [255, 0, 0, 127], destination: [255, 0, 0, 63] },
29           { source: [255, 127, 0, 32], destination: [255, 63, 0, 63] },
30           { source: [255, 0, 0, 191], destination: [0, 255, 0, 127] },
31           { source: [255, 0, 255, 191], destination: [0, 255, 255, 127] }
32       ];
33       var expectedColors = [
34           [
35               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 255, 0, 255] },
36               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
37               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 255, 0, 1] },
38               { source: [0, 0, 0, 0], composition: [255, 0, 0, 255], destination: [255, 0, 0, 255] },
39               { source: [0, 255, 0, 1], composition: [254, 1, 0, 255], destination: [255, 0, 0, 255] },
40               { source: [0, 0, 0, 0], composition: [0, 255, 0, 255], destination: [0, 255, 0, 255] },
41               { source: [255, 0, 0, 127], composition: [170, 84, 0, 190], destination: [0, 255, 0, 127] },
42               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 255, 0, 127] },
43               { source: [255, 0, 0, 127], composition: [127, 128, 0, 255], destination: [0, 255, 0, 255] },
44               { source: [127, 0, 0, 255], composition: [127, 0, 0, 255], destination: [0, 126, 0, 127] },
45               { source: [126, 0, 0, 127], composition: [63, 63, 0, 255], destination: [0, 127, 0, 255] },
46               { source: [255, 0, 0, 127], composition: [255, 0, 0, 158], destination: [255, 0, 0, 63] },
47               { source: [255, 127, 0, 32], composition: [255, 85, 0, 87], destination: [255, 64, 0, 63] },
48               { source: [255, 0, 0, 191], composition: [219, 35, 0, 222], destination: [0, 255, 0, 127] },
49               { source: [255, 0, 255, 191], composition: [219, 35, 255, 222], destination: [0, 255, 255, 127] }
50           ],
51           [
52               { source: [0, 0, 0, 0], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
53               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
54               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
55               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
56               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
57               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
58               { source: [0, 0, 0, 0], composition: [255, 0, 0, 64], destination: [0, 0, 0, 0] },
59               { source: [0, 0, 0, 0], composition: [255, 0, 0, 127], destination: [0, 0, 0, 0] },
60               { source: [0, 0, 0, 0], composition: [255, 0, 0, 127], destination: [0, 0, 0, 0] },
61               { source: [0, 0, 0, 0], composition: [128, 0, 0, 127], destination: [0, 0, 0, 0] },
62               { source: [0, 0, 0, 0], composition: [126, 0, 0, 127], destination: [0, 0, 0, 0] },
63               { source: [0, 0, 0, 0], composition: [255, 0, 0, 32], destination: [0, 0, 0, 0] },
64               { source: [0, 0, 0, 0], composition: [255, 127, 0, 8], destination: [0, 0, 0, 0] },
65               { source: [0, 0, 0, 0], composition: [255, 0, 0, 96], destination: [0, 0, 0, 0] },
66               { source: [0, 0, 0, 0], composition: [255, 0, 255, 96], destination: [0, 0, 0, 0] }
67           ],
68           [
69               { source: [255, 0, 0, 255], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
70               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
71               { source: [255, 0, 0, 255], composition: [255, 0, 0, 254], destination: [0, 0, 0, 0] },
72               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
73               { source: [0, 255, 0, 1], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
74               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
75               { source: [255, 0, 0, 127], composition: [255, 0, 0, 64], destination: [0, 0, 0, 0] },
76               { source: [255, 0, 0, 255], composition: [255, 0, 0, 128], destination: [0, 0, 0, 0] },
77               { source: [255, 0, 0, 127], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
78               { source: [127, 0, 0, 255], composition: [127, 0, 0, 128], destination: [0, 0, 0, 0] },
79               { source: [126, 0, 0, 127], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
80               { source: [255, 0, 0, 127], composition: [255, 0, 0, 96], destination: [0, 0, 0, 0] },
81               { source: [255, 127, 0, 32], composition: [255, 132, 0, 25], destination: [0, 0, 0, 0] },
82               { source: [255, 0, 0, 191], composition: [255, 0, 0, 96], destination: [0, 0, 0, 0] },
83               { source: [255, 0, 255, 191], composition: [255, 0, 255, 96], destination: [0, 0, 0, 0] }
84           ],
85           [
86               { source: [0, 0, 0, 0], composition: [255, 0, 0, 255], destination: [0, 255, 0, 255] },
87               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
88               { source: [0, 0, 0, 0], composition: [255, 0, 0, 1], destination: [0, 255, 0, 1] },
89               { source: [0, 0, 0, 0], composition: [255, 0, 0, 255], destination: [255, 0, 0, 255] },
90               { source: [0, 0, 0, 0], composition: [254, 1, 0, 255], destination: [255, 0, 0, 255] },
91               { source: [0, 0, 0, 0], composition: [0, 255, 0, 255], destination: [0, 255, 0, 255] },
92               { source: [0, 0, 0, 0], composition: [126, 126, 0, 127], destination: [0, 255, 0, 127] },
93               { source: [0, 0, 0, 0], composition: [255, 0, 0, 127], destination: [0, 255, 0, 127] },
94               { source: [0, 0, 0, 0], composition: [127, 128, 0, 255], destination: [0, 255, 0, 255] },
95               { source: [0, 0, 0, 0], composition: [128, 0, 0, 127], destination: [0, 126, 0, 127] },
96               { source: [0, 0, 0, 0], composition: [63, 63, 0, 255], destination: [0, 127, 0, 255] },
97               { source: [0, 0, 0, 0], composition: [255, 0, 0, 63], destination: [255, 0, 0, 63] },
98               { source: [0, 0, 0, 0], composition: [255, 68, 0, 63], destination: [255, 64, 0, 63] },
99               { source: [0, 0, 0, 0], composition: [190, 62, 0, 127], destination: [0, 255, 0, 127] },
100               { source: [0, 0, 0, 0], composition: [190, 62, 255, 127], destination: [0, 255, 255, 127] }
101           ],
102           [
103               { source: [255, 0, 0, 255], composition: [0, 255, 0, 255], destination: [0, 255, 0, 255] },
104               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
105               { source: [255, 0, 0, 255], composition: [254, 1, 0, 255], destination: [0, 255, 0, 1] },
106               { source: [0, 0, 0, 0], composition: [255, 0, 0, 255], destination: [255, 0, 0, 255] },
107               { source: [0, 255, 0, 1], composition: [255, 0, 0, 255], destination: [255, 0, 0, 255] },
108               { source: [0, 0, 0, 0], composition: [0, 255, 0, 255], destination: [0, 255, 0, 255] },
109               { source: [255, 0, 0, 127], composition: [84, 170, 0, 190], destination: [0, 255, 0, 127] },
110               { source: [255, 0, 0, 255], composition: [128, 127, 0, 255], destination: [0, 255, 0, 127] },
111               { source: [255, 0, 0, 127], composition: [0, 255, 0, 255], destination: [0, 255, 0, 255] },
112               { source: [127, 0, 0, 255], composition: [63, 63, 0, 255], destination: [0, 126, 0, 127] },
113               { source: [126, 0, 0, 127], composition: [0, 127, 0, 255], destination: [0, 127, 0, 255] },
114               { source: [255, 0, 0, 127], composition: [255, 0, 0, 158], destination: [255, 0, 0, 63] },
115               { source: [255, 127, 0, 32], composition: [255, 82, 0, 87], destination: [255, 64, 0, 63] },
116               { source: [255, 0, 0, 191], composition: [109, 145, 0, 222], destination: [0, 255, 0, 127] },
117               { source: [255, 0, 255, 191], composition: [109, 145, 255, 222], destination: [0, 255, 255, 127] }
118           ],
119           [
120               { source: [0, 0, 0, 0], composition: [0, 255, 0, 255], destination: [0, 0, 0, 0] },
121               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
122               { source: [0, 0, 0, 0], composition: [0, 255, 0, 1], destination: [0, 0, 0, 0] },
123               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
124               { source: [0, 0, 0, 0], composition: [255, 0, 0, 1], destination: [0, 0, 0, 0] },
125               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
126               { source: [0, 0, 0, 0], composition: [0, 255, 0, 64], destination: [0, 0, 0, 0] },
127               { source: [0, 0, 0, 0], composition: [0, 255, 0, 127], destination: [0, 0, 0, 0] },
128               { source: [0, 0, 0, 0], composition: [0, 255, 0, 127], destination: [0, 0, 0, 0] },
129               { source: [0, 0, 0, 0], composition: [0, 126, 0, 127], destination: [0, 0, 0, 0] },
130               { source: [0, 0, 0, 0], composition: [0, 128, 0, 127], destination: [0, 0, 0, 0] },
131               { source: [0, 0, 0, 0], composition: [255, 0, 0, 32], destination: [0, 0, 0, 0] },
132               { source: [0, 0, 0, 0], composition: [255, 95, 0, 8], destination: [0, 0, 0, 0] },
133               { source: [0, 0, 0, 0], composition: [0, 255, 0, 96], destination: [0, 0, 0, 0] },
134               { source: [0, 0, 0, 0], composition: [0, 255, 255, 96], destination: [0, 0, 0, 0] }
135           ],
136           [
137               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 255, 0, 255] },
138               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
139               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 255, 0, 1] },
140               { source: [0, 0, 0, 0], composition: [255, 0, 0, 255], destination: [255, 0, 0, 255] },
141               { source: [0, 0, 0, 0], composition: [255, 0, 0, 254], destination: [255, 0, 0, 255] },
142               { source: [0, 0, 0, 0], composition: [0, 255, 0, 255], destination: [0, 255, 0, 255] },
143               { source: [0, 0, 0, 0], composition: [0, 255, 0, 64], destination: [0, 255, 0, 127] },
144               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 255, 0, 127] },
145               { source: [0, 0, 0, 0], composition: [0, 255, 0, 128], destination: [0, 255, 0, 255] },
146               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 126, 0, 127] },
147               { source: [0, 0, 0, 0], composition: [0, 127, 0, 128], destination: [0, 127, 0, 255] },
148               { source: [0, 0, 0, 0], composition: [255, 0, 0, 32], destination: [255, 0, 0, 63] },
149               { source: [0, 0, 0, 0], composition: [255, 63, 0, 56], destination: [255, 64, 0, 63] },
150               { source: [0, 0, 0, 0], composition: [0, 255, 0, 32], destination: [0, 255, 0, 127] },
151               { source: [0, 0, 0, 0], composition: [0, 255, 255, 32], destination: [0, 255, 255, 127] }
152           ],
153           [
154               { source: [255, 0, 0, 255], composition: [0, 255, 0, 255], destination: [0,0,0,0] },
155               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
156               { source: [255, 0, 0, 255], composition: [254, 1, 0, 255], destination: [0,0,0,0] },
157               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0,0,0,0] },
158               { source: [0, 255, 0, 1], composition: [255, 0, 0, 1], destination: [0,0,0,0] },
159               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0,0,0,0] },
160               { source: [255, 0, 0, 127], composition: [126, 126, 0, 127], destination: [0,0,0,0] },
161               { source: [255, 0, 0, 255], composition: [128, 127, 0, 255], destination: [0,0,0,0] },
162               { source: [255, 0, 0, 127], composition: [0, 255, 0, 127], destination: [0,0,0,0] },
163               { source: [127, 0, 0, 255], composition: [63, 63, 0, 255], destination: [0,0,0,0] },
164               { source: [126, 0, 0, 127], composition: [0, 126, 0, 127], destination: [0,0,0,0] },
165               { source: [255, 0, 0, 127], composition: [255, 0, 0, 127], destination: [0,0,0,0] },
166               { source: [255, 127, 0, 32], composition: [255, 111, 0, 32], destination: [0,0,0,0] },
167               { source: [255, 0, 0, 191], composition: [126, 126, 0, 191], destination: [0,0,0,0] },
168               { source: [255, 0, 255, 191], composition: [126, 126, 255, 191], destination: [0,0,0,0] }
169           ],
170           [
171               { source: [255, 0, 0, 255], composition: [255, 255, 0, 255], destination: [0, 255, 0, 255] },
172               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
173               { source: [255, 0, 0, 255], composition: [255, 1, 0, 255], destination: [0, 255, 0, 1] },
174               { source: [0, 0, 0, 0], composition: [255, 0, 0, 255], destination: [255, 0, 0, 255] },
175               { source: [0, 255, 0, 1], composition: [255, 1, 0, 255], destination: [255, 0, 0, 255] },
176               { source: [0, 0, 0, 0], composition: [0, 255, 0, 255], destination: [0, 255, 0, 255] },
177               { source: [255, 0, 0, 127], composition: [127, 127, 0, 254], destination: [0, 255, 0, 127] },
178               { source: [255, 0, 0, 255], composition: [255, 127, 0, 255], destination: [0, 255, 0, 127] },
179               { source: [255, 0, 0, 127], composition: [127, 255, 0, 255], destination: [0, 255, 0, 255] },
180               { source: [127, 0, 0, 255], composition: [127, 63, 0, 255], destination: [0, 126, 0, 127] },
181               { source: [126, 0, 0, 127], composition: [63, 127, 0, 255], destination: [0, 127, 0, 255] },
182               { source: [255, 0, 0, 127], composition: [255, 0, 0, 190], destination: [255, 0, 0, 63] },
183               { source: [255, 127, 0, 32], composition: [255, 85, 0, 95], destination: [255, 64, 0, 63] },
184               { source: [255, 0, 0, 191], composition: [191, 127, 0, 255], destination: [0, 255, 0, 127] },
185               { source: [255, 0, 255, 191], composition: [191, 127, 255, 255], destination: [0, 255, 255, 127] }
186           ],
187           [
188               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
189               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
190               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
191               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
192               { source: [0, 255, 0, 1], composition: [0, 255, 0, 1], destination: [0, 0, 0, 0] },
193               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
194               { source: [255, 0, 0, 127], composition: [255, 0, 0, 127], destination: [0, 0, 0, 0] },
195               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
196               { source: [255, 0, 0, 127], composition: [255, 0, 0, 127], destination: [0, 0, 0, 0] },
197               { source: [127, 0, 0, 255], composition: [127, 0, 0, 255], destination: [0, 0, 0, 0] },
198               { source: [126, 0, 0, 127], composition: [126, 0, 0, 127], destination: [0, 0, 0, 0] },
199               { source: [255, 0, 0, 127], composition: [255, 0, 0, 127], destination: [0, 0, 0, 0] },
200               { source: [255, 127, 0, 32], composition: [255, 127, 0, 32], destination: [0, 0, 0, 0] },
201               { source: [255, 0, 0, 191], composition: [255, 0, 0, 191], destination: [0, 0, 0, 0] },
202               { source: [255, 0, 255, 191], composition: [255, 0, 255, 191], destination: [0, 0, 0, 0] }
203           ],
204           [
205               { source: [255, 0, 0, 255], composition: [0, 0, 0, 0], destination: [0, 255, 0, 255] },
206               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
207               { source: [255, 0, 0, 255], composition: [255, 0, 0, 254], destination: [0, 255, 0, 1] },
208               { source: [0, 0, 0, 0], composition: [255, 0, 0, 255], destination: [255, 0, 0, 255] },
209               { source: [0, 255, 0, 1], composition: [255, 0, 0, 254], destination: [255, 0, 0, 255] },
210               { source: [0, 0, 0, 0], composition: [0, 255, 0, 255], destination: [0, 255, 0, 255] },
211               { source: [255, 0, 0, 127], composition: [126, 126, 0, 127], destination: [0, 255, 0, 127] },
212               { source: [255, 0, 0, 255], composition: [255, 0, 0, 128], destination: [0, 255, 0, 127] },
213               { source: [255, 0, 0, 127], composition: [0, 255, 0, 128], destination: [0, 255, 0, 255] },
214               { source: [127, 0, 0, 255], composition: [127, 0, 0, 128], destination: [0, 126, 0, 127] },
215               { source: [126, 0, 0, 127], composition: [0, 125, 0, 128], destination: [0, 127, 0, 255] },
216               { source: [255, 0, 0, 127], composition: [255, 0, 0, 127], destination: [255, 0, 0, 63] },
217               { source: [255, 127, 0, 32], composition: [255, 83, 0, 79], destination: [255, 64, 0, 63] },
218               { source: [255, 0, 0, 191], composition: [190, 62, 0, 127], destination: [0, 255, 0, 127] },
219               { source: [255, 0, 255, 191], composition: [190, 62, 255, 127], destination: [0, 255, 255, 127] }
220           ]
221       ];
222
223       var debugString = "";
224
225       // Compare two colors with a few margin.
226       function isDifferentColor(actualColor, expectedColor)
227       {
228           var actualAlpha = actualColor[3];
229           var expectedAlpha = expectedColor[3];
230           if (Math.abs(actualColor - expectedColor) > 3) return true;
231           // For the value of RGB, we compare the values the users actually see.
232           if (Math.abs(actualColor[0] * actualAlpha / 256 - expectedColor[0] * expectedAlpha / 256) > 3) return true;
233           if (Math.abs(actualColor[1] * actualAlpha / 256 - expectedColor[1] * expectedAlpha / 256) > 3) return true;
234           if (Math.abs(actualColor[2] * actualAlpha / 256 - expectedColor[2] * expectedAlpha / 256) > 3) return true;
235           return false;
236       }
237
238       function getRGBAString(a)
239       {
240           return "rgba(" + [a[0], a[1], a[2], a[3] / 255.0].join(",") + ")";
241       }
242
243       function drawTable(drawPolicy)
244       {
245           var tableElement = document.createElement("table");
246
247           // Create a header for source color.
248           var trElement = document.createElement("tr");
249           tableElement.appendChild(trElement);
250           trElement.appendChild(document.createElement("th"));
251           for (var column = 0; column < inputColors.length; column++) {
252               var inputColor = inputColors[column];
253               var thElement = document.createElement("th");
254               thElement.setAttribute("colspan", "2");
255               thElement.textContent = "src " + inputColor.source.join(", ");
256               trElement.appendChild(thElement);
257           }
258
259           // Create a header for destination color.
260           trElement = document.createElement("tr");
261           tableElement.appendChild(trElement);
262           trElement.appendChild(document.createElement("th"));
263           for (var column = 0; column < inputColors.length; column++) {
264               var inputColor = inputColors[column];
265               var thElement = document.createElement("th");
266               thElement.setAttribute("colspan", "2");
267               thElement.textContent = "dst " + inputColor.destination.join(", ");
268               trElement.appendChild(thElement);
269           }
270
271           var resultsElement = document.getElementById("results");
272           var titleElement = document.createElement("h1");
273           titleElement.textContent = "Tests for " + drawPolicy.name;
274           resultsElement.appendChild(titleElement);
275           resultsElement.appendChild(tableElement);
276
277           for (var row = 0; row < compositeTypes.length; row++){
278               var type = compositeTypes[row];
279
280               var trCanvasElement = document.createElement("tr");
281               var thElement = document.createElement("th");
282               thElement.setAttribute("rowspan", "2");
283               thElement.textContent = type;
284               trCanvasElement.appendChild(thElement);
285               var trMessageElement = document.createElement("tr");
286               tableElement.appendChild(trCanvasElement);
287               tableElement.appendChild(trMessageElement);
288
289               for (var column = 0; column < inputColors.length; column++) {
290                   var test = type + "-" + column;
291                   var inputColor = inputColors[column];
292                   var expectedColor = expectedColors[row][column];
293
294                   // Create canvas element for actual color.
295                   var actualCanvasElement = document.createElement("canvas");
296                   actualCanvasElement.setAttribute("width", "25");
297                   actualCanvasElement.setAttribute("height", "25");
298                   tdElement = document.createElement("td");
299                   tdElement.appendChild(actualCanvasElement);
300                   trCanvasElement.appendChild(tdElement);
301
302                   // Create canvas element for expected color.
303                   var expectedCanvasElement = document.createElement("canvas");
304                   expectedCanvasElement.setAttribute("width", "25");
305                   expectedCanvasElement.setAttribute("height", "25");
306                   var tdElement = document.createElement("td");
307                   tdElement.appendChild(expectedCanvasElement);
308                   trCanvasElement.appendChild(tdElement);
309
310                   // Create div element for pass/fail messages.
311                   var messageElement = document.createElement("div");
312                   tdElement = document.createElement("td");
313                   tdElement.setAttribute("colspan", "2");
314                   tdElement.appendChild(messageElement);
315                   trMessageElement.appendChild(tdElement);
316
317                   var ctx = expectedCanvasElement.getContext("2d");
318                   ctx.lineWidth = 10;
319                   // Draw expected image.
320                   ctx.globalCompositeOperation = "copy";
321                   ctx.fillStyle = getRGBAString(expectedColor.destination);
322                   ctx.strokeStyle = getRGBAString(expectedColor.destination);
323                   drawPolicy.drawDestination(ctx);
324                   ctx.fillStyle = getRGBAString(expectedColor.source);
325                   ctx.strokeStyle = getRGBAString(expectedColor.source);
326                   drawPolicy.drawSource(ctx);
327                   ctx.fillStyle = getRGBAString(expectedColor.composition);
328                   ctx.strokeStyle = getRGBAString(expectedColor.composition);
329                   drawPolicy.drawComposition(ctx);
330
331                   ctx = actualCanvasElement.getContext("2d");
332                   ctx.lineWidth = 10;
333
334                   // Draw destination rectangle.
335                   ctx.globalCompositeOperation = "copy";
336                   ctx.fillStyle = getRGBAString(inputColor.destination);
337                   ctx.strokeStyle = getRGBAString(inputColor.destination);
338                   drawPolicy.drawDestination(ctx);
339
340                   // Draw source rectangle.
341                   ctx.globalCompositeOperation = type;
342                   ctx.fillStyle = getRGBAString(inputColor.source);
343                   ctx.strokeStyle = getRGBAString(inputColor.source);
344                   drawPolicy.drawSource(ctx);
345
346                   // Let's check if the results are expected or not.
347                   var errorSuffix = ", composite type: " + type + ", source: " + inputColor.source + ", destination: " + inputColor.destination + "<br>";
348
349                   var results = "";
350                   // Note that (0, 0) may be affected by anti-alias.
351                   var img = ctx.getImageData(1, 1, 1, 1).data;
352                   var actualColor = [img[0], img[1], img[2], img[3]];
353                   if (isDifferentColor(actualColor, expectedColor.source)) {
354                       results += "Unexpected source! expected: " + expectedColor.source + " actual: " + actualColor + errorSuffix;
355                   }
356                   // Note that (24, 24) may be affected by anti-alias.
357                   img = ctx.getImageData(23, 23, 1, 1).data;
358                   actualColor = [img[0], img[1], img[2], img[3]];
359                   if (isDifferentColor(actualColor, expectedColor.destination)) {
360                       results += "Unexpected destination! expected: " + expectedColor.destination + " actual: " + actualColor + errorSuffix;
361                   }
362                   img = ctx.getImageData(12, 12, 1, 1).data;
363                   actualColor = [img[0], img[1], img[2], img[3]];
364                   if (isDifferentColor(actualColor, expectedColor.composition)) {
365                       results += "Unexpected composition! expected: " + expectedColor.composition + " actual: " + actualColor + errorSuffix;
366                   }
367
368                   if (results == "") {
369                       messageElement.style.backgroundColor = "green";
370                       messageElement.innerHTML = results = "PASS";
371                   } else {
372                       messageElement.style.backgroundColor = "red";
373                       messageElement.innerHTML = results;
374                   }
375
376                   img = ctx.getImageData(0, 0, 1, 1).data;
377                   debugString += img[0] + "," + img[1] + "," + img[2] + "," + img[3] + "\n";
378                   img = ctx.getImageData(12, 12, 1, 1).data;
379                   debugString += img[0] + "," + img[1] + "," + img[2] + "," + img[3] + "\n";
380                   img = ctx.getImageData(24, 24, 1, 1).data;
381                   debugString += img[0] + "," + img[1] + "," + img[2] + "," + img[3] + "\n";
382               }
383           }
384       }
385
386       var useStrokeRect = {
387           drawSource: function(ctx) {
388               ctx.strokeRect(5, 5, 10, 10);
389           },
390
391           drawDestination: function(ctx) {
392               ctx.fillRect(5, 5, 20, 20);
393           },
394
395           drawComposition: function(ctx) {
396               ctx.fillRect(5, 5, 15, 15);
397           },
398
399           name: "stroke rect"
400       };
401
402       var usePathAndStroke = {
403           drawSource: function(ctx) {
404               ctx.beginPath();
405               ctx.moveTo(5, 5);
406               ctx.lineTo(15, 5);
407               ctx.lineTo(15, 15);
408               ctx.lineTo(5, 15);
409               ctx.closePath();
410               ctx.stroke();
411           },
412
413           drawDestination: function(ctx) {
414               ctx.fillRect(5, 5, 20, 20);
415           },
416
417           drawComposition: function(ctx) {
418               ctx.fillRect(5, 5, 15, 15);
419           },
420
421           name: "path and stroke"
422       };
423
424       function draw()
425       {
426           drawTable(useStrokeRect);
427           drawTable(usePathAndStroke);
428           // Dump colors into text area for debugging purpose.
429           document.getElementById("debug").value = debugString;
430           if (window.testRunner)
431               testRunner.notifyDone();
432       }
433     </script>
434     <style type="text/css">
435       body { margin: 20px; font-family: arial,verdana,helvetica; background: #fff;}
436       h1 { font-size: 140%; font-weight:normal; color: #036; border-bottom: 1px solid #ccc; }
437       canvas { border: 2px solid #000; margin-bottom: 5px; }
438       table { background: #00f; }
439       th { font-size: 70%; padding: 0; }
440       td { font-size: 70%; padding: 0; }
441       pre { float:left; display:block; background: rgb(238,238,238); border: 1px dashed #666; padding: 15px 20px; margin: 0 0 10px 0; }
442     </style>
443   </head>
444   <body onload="draw();">
445     <p>This test exercises a bunch of alpha composition checks with stroking. The top-left rectangles are the source images and bottom-right rectangles are the destination images.</p>
446     <div id="results">
447     </div>
448     <textarea id="debug"></textarea>
449   </body>
450 </html>