Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /*
2 * Test for APNG encoding in libpr0n
3 *
4 */
7 const Ci = Components.interfaces;
8 const Cc = Components.classes;
10 // dispose=[none|background|previous]
11 // blend=[source|over]
13 var apng1A = {
14 // A 3x3 image with 3 frames, alternating red, green, blue. RGB format.
15 width : 3, height : 3, skipFirstFrame : false,
16 format : Ci.imgIEncoder.INPUT_FORMAT_RGB,
17 transparency : null,
18 plays : 0,
20 frames : [
21 { // frame #1
22 width : 3, height : 3,
23 x_offset : 0, y_offset : 0,
24 dispose : "none", blend : "source", delay : 500,
26 format : Ci.imgIEncoder.INPUT_FORMAT_RGB, stride : 9,
27 transparency : null,
29 pixels : [
30 255,0,0, 255,0,0, 255,0,0,
31 255,0,0, 255,0,0, 255,0,0,
32 255,0,0, 255,0,0, 255,0,0
33 ]
34 },
36 { // frame #2
37 width : 3, height : 3,
38 x_offset : 0, y_offset : 0,
39 dispose : "none", blend : "source", delay : 500,
41 format : Ci.imgIEncoder.INPUT_FORMAT_RGB, stride : 9,
42 transparency : null,
44 pixels : [
45 0,255,0, 0,255,0, 0,255,0,
46 0,255,0, 0,255,0, 0,255,0,
47 0,255,0, 0,255,0, 0,255,0
48 ]
49 },
51 { // frame #3
52 width : 3, height : 3,
53 x_offset : 0, y_offset : 0,
54 dispose : "none", blend : "source", delay : 500,
56 format : Ci.imgIEncoder.INPUT_FORMAT_RGB, stride : 9,
57 transparency : null,
59 pixels : [
60 0,0,255, 0,0,255, 0,0,255,
61 0,0,255, 0,0,255, 0,0,255,
62 0,0,255, 0,0,255, 0,0,255
63 ]
64 }
66 ],
67 expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABBJREFUCJlj+M/AAEEMWFgAj44I+H2CySsAAAAaZmNUTAAAAAEAAAADAAAAAwAAAAAAAAAAAfQD6AAA7mXKzAAAABNmZEFUAAAAAgiZY2D4zwBFWFgAhpcI+I731VcAAAAaZmNUTAAAAAMAAAADAAAAAwAAAAAAAAAAAfQD6AAAA/MZJQAAABNmZEFUAAAABAiZY2Bg+A9DmCwAfaAI+AGmQVoAAAAASUVORK5CYII="
68 };
71 var apng1B = {
72 // A 3x3 image with 3 frames, alternating red, green, blue. RGBA format.
73 width : 3, height : 3, skipFirstFrame : false,
74 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA,
75 transparency : null,
76 plays : 0,
78 frames : [
79 { // frame #1
80 width : 3, height : 3,
81 x_offset : 0, y_offset : 0,
82 dispose : "none", blend : "source", delay : 500,
84 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
86 pixels : [
87 255,0,0,255, 255,0,0,255, 255,0,0,255,
88 255,0,0,255, 255,0,0,255, 255,0,0,255,
89 255,0,0,255, 255,0,0,255, 255,0,0,255
90 ]
91 },
93 { // frame #2
94 width : 3, height : 3,
95 x_offset : 0, y_offset : 0,
96 dispose : "none", blend : "source", delay : 500,
98 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
100 pixels : [
101 0,255,0,255, 0,255,0,255, 0,255,0,255,
102 0,255,0,255, 0,255,0,255, 0,255,0,255,
103 0,255,0,255, 0,255,0,255, 0,255,0,255
104 ]
105 },
107 { // frame #3
108 width : 3, height : 3,
109 x_offset : 0, y_offset : 0,
110 dispose : "none", blend : "source", delay : 500,
112 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
114 pixels : [
115 0,0,255,255, 0,0,255,255, 0,0,255,255,
116 0,0,255,255, 0,0,255,255, 0,0,255,255,
117 0,0,255,255, 0,0,255,255, 0,0,255,255
118 ]
119 }
121 ],
122 expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABFJREFUCJlj+M/A8B+GGXByAF3XEe/CoiJ1AAAAGmZjVEwAAAABAAAAAwAAAAMAAAAAAAAAAAH0A+gAAO5lyswAAAASZmRBVAAAAAIImWNg+I8EcXIAVOAR77Vyl9QAAAAaZmNUTAAAAAMAAAADAAAAAwAAAAAAAAAAAfQD6AAAA/MZJQAAABRmZEFUAAAABAiZY2Bg+P8fgXFxAEvpEe8rClxSAAAAAElFTkSuQmCC"
123 };
126 var apng1C = {
127 // A 3x3 image with 3 frames, alternating red, green, blue. RGBA format.
128 // The first frame is skipped, so it will only flash green/blue (or static red in an APNG-unaware viewer)
129 width : 3, height : 3, skipFirstFrame : true,
130 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA,
131 transparency : null,
132 plays : 0,
134 frames : [
135 { // frame #1
136 width : 3, height : 3,
137 x_offset : 0, y_offset : 0,
138 dispose : "none", blend : "source", delay : 500,
140 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
142 pixels : [
143 255,0,0,255, 255,0,0,255, 255,0,0,255,
144 255,0,0,255, 255,0,0,255, 255,0,0,255,
145 255,0,0,255, 255,0,0,255, 255,0,0,255
146 ]
147 },
149 { // frame #2
150 width : 3, height : 3,
151 x_offset : 0, y_offset : 0,
152 dispose : "none", blend : "source", delay : 500,
154 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
156 pixels : [
157 0,255,0,255, 0,255,0,255, 0,255,0,255,
158 0,255,0,255, 0,255,0,255, 0,255,0,255,
159 0,255,0,255, 0,255,0,255, 0,255,0,255
160 ]
161 },
163 { // frame #3
164 width : 3, height : 3,
165 x_offset : 0, y_offset : 0,
166 dispose : "none", blend : "source", delay : 500,
168 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
170 pixels : [
171 0,0,255,255, 0,0,255,255, 0,0,255,255,
172 0,0,255,255, 0,0,255,255, 0,0,255,255,
173 0,0,255,255, 0,0,255,255, 0,0,255,255
174 ]
175 }
177 ],
178 expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAACAAAAAPONk3AAAAARSURBVAiZY/jPwPAfhhlwcgBd1xHvwqIidQAAABpmY1RMAAAAAAAAAAMAAAADAAAAAAAAAAAB9APoAAB1FiAYAAAAEmZkQVQAAAABCJljYPiPBHFyAFTgEe+kD/2tAAAAGmZjVEwAAAACAAAAAwAAAAMAAAAAAAAAAAH0A+gAAJiA8/EAAAAUZmRBVAAAAAMImWNgYPj/H4FxcQBL6RHvC5ggGQAAAABJRU5ErkJggg=="
179 };
182 var apng2A = {
183 // A 3x3 image with 3 frames, alternating red, green, blue. RGBA format.
184 // blend = over mode
185 // (The green frame is a horizontal gradient, and the blue frame is a
186 // vertical gradient. They stack as they animate.)
187 width : 3, height : 3, skipFirstFrame : false,
188 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA,
189 transparency : null,
190 plays : 0,
192 frames : [
193 { // frame #1
194 width : 3, height : 3,
195 x_offset : 0, y_offset : 0,
196 dispose : "none", blend : "source", delay : 500,
198 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
200 pixels : [
201 255,0,0,255, 255,0,0,255, 255,0,0,255,
202 255,0,0,255, 255,0,0,255, 255,0,0,255,
203 255,0,0,255, 255,0,0,255, 255,0,0,255
204 ]
205 },
207 { // frame #2
208 width : 3, height : 3,
209 x_offset : 0, y_offset : 0,
210 dispose : "none", blend : "over", delay : 500,
212 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
214 pixels : [
215 0,255,0,255, 0,255,0,180, 0,255,0,75,
216 0,255,0,255, 0,255,0,180, 0,255,0,75,
217 0,255,0,255, 0,255,0,180, 0,255,0,75
218 ]
219 },
221 { // frame #3
222 width : 3, height : 3,
223 x_offset : 0, y_offset : 0,
224 dispose : "none", blend : "over", delay : 500,
226 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
228 pixels : [
229 0,0,255,75, 0,0,255,75, 0,0,255,75,
230 0,0,255,180, 0,0,255,180, 0,0,255,180,
231 0,0,255,255, 0,0,255,255, 0,0,255,255
232 ]
233 }
235 ],
236 expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABFJREFUCJlj+M/A8B+GGXByAF3XEe/CoiJ1AAAAGmZjVEwAAAABAAAAAwAAAAMAAAAAAAAAAAH0A+gAAZli+loAAAAcZmRBVAAAAAIImWNg+M/wn+E/wxaG/wzeDDg5ACeGDvKVa3pyAAAAGmZjVEwAAAADAAAAAwAAAAMAAAAAAAAAAAH0A+gAAXT0KbMAAAAcZmRBVAAAAAQImWNgYPjvjcAM/7cgMMP//zAMAPqkDvLn1m3SAAAAAElFTkSuQmCC"
237 };
240 var apng2B = {
241 // A 3x3 image with 3 frames, alternating red, green, blue. RGBA format.
242 // blend = over, dispose = background
243 // (The green frame is a horizontal gradient, and the blue frame is a
244 // vertical gradient. Each frame is displayed individually, blended to
245 // whatever the background is.)
246 width : 3, height : 3, skipFirstFrame : false,
247 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA,
248 transparency : null,
249 plays : 0,
251 frames : [
252 { // frame #1
253 width : 3, height : 3,
254 x_offset : 0, y_offset : 0,
255 dispose : "background", blend : "source", delay : 500,
257 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
259 pixels : [
260 255,0,0,255, 255,0,0,255, 255,0,0,255,
261 255,0,0,255, 255,0,0,255, 255,0,0,255,
262 255,0,0,255, 255,0,0,255, 255,0,0,255
263 ]
264 },
266 { // frame #2
267 width : 3, height : 3,
268 x_offset : 0, y_offset : 0,
269 dispose : "background", blend : "over", delay : 500,
271 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
273 pixels : [
274 0,255,0,255, 0,255,0,180, 0,255,0,75,
275 0,255,0,255, 0,255,0,180, 0,255,0,75,
276 0,255,0,255, 0,255,0,180, 0,255,0,75
277 ]
278 },
280 { // frame #3
281 width : 3, height : 3,
282 x_offset : 0, y_offset : 0,
283 dispose : "background", blend : "over", delay : 500,
285 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
287 pixels : [
288 0,0,255,75, 0,0,255,75, 0,0,255,75,
289 0,0,255,180, 0,0,255,180, 0,0,255,180,
290 0,0,255,255, 0,0,255,255, 0,0,255,255
291 ]
292 }
294 ],
295 expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AEAbA0RWQAAABFJREFUCJlj+M/A8B+GGXByAF3XEe/CoiJ1AAAAGmZjVEwAAAABAAAAAwAAAAMAAAAAAAAAAAH0A+gBAYB5yxsAAAAcZmRBVAAAAAIImWNg+M/wn+E/wxaG/wzeDDg5ACeGDvKVa3pyAAAAGmZjVEwAAAADAAAAAwAAAAMAAAAAAAAAAAH0A+gBAW3vGPIAAAAcZmRBVAAAAAQImWNgYPjvjcAM/7cgMMP//zAMAPqkDvLn1m3SAAAAAElFTkSuQmCC"
296 };
299 var apng3 = {
300 // A 3x3 image with 4 frames. First frame is white, then 1x1 frames draw a diagonal line
301 width : 3, height : 3, skipFirstFrame : false,
302 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA,
303 transparency : null,
304 plays : 0,
306 frames : [
307 { // frame #1
308 width : 3, height : 3,
309 x_offset : 0, y_offset : 0,
310 dispose : "none", blend : "source", delay : 500,
312 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
314 pixels : [
316 255,255,255,255, 255,255,255,255, 255,255,255,255,
317 255,255,255,255, 255,255,255,255, 255,255,255,255,
318 255,255,255,255, 255,255,255,255, 255,255,255,255
319 ]
320 },
322 { // frame #2
323 width : 1, height : 1,
324 x_offset : 0, y_offset : 0,
325 dispose : "none", blend : "source", delay : 500,
327 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
329 pixels : [
330 0,0,0,255
331 ]
332 },
334 { // frame #3
335 width : 1, height : 1,
336 x_offset : 1, y_offset : 1,
337 dispose : "none", blend : "source", delay : 500,
339 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
341 pixels : [
342 0,0,0,255
343 ]
344 },
346 { // frame #4
347 width : 1, height : 1,
348 x_offset : 2, y_offset : 2,
349 dispose : "none", blend : "source", delay : 500,
351 format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12,
353 pixels : [
354 0,0,0,255
355 ]
356 }
357 ],
359 expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAAEAAAAAHzNZtAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAAA5JREFUCJlj+I8EGHByALuHI91kueRqAAAAGmZjVEwAAAABAAAAAQAAAAEAAAAAAAAAAAH0A+gAADJXfawAAAARZmRBVAAAAAIImWNgYGD4DwABBAEAbr5mpgAAABpmY1RMAAAAAwAAAAEAAAABAAAAAQAAAAEB9APoAAC4OHoxAAAAEWZkQVQAAAAECJljYGBg+A8AAQQBAJZ8LRAAAAAaZmNUTAAAAAUAAAABAAAAAQAAAAIAAAACAfQD6AAA/fh01wAAABFmZEFUAAAABgiZY2BgYPgPAAEEAQB3Eum9AAAAAElFTkSuQmCC"
360 };
362 // Main test entry point.
363 function run_test() {
364 dump("Checking apng1A...\n");
365 run_test_for(apng1A);
366 dump("Checking apng1B...\n");
367 run_test_for(apng1B);
368 dump("Checking apng1C...\n");
369 run_test_for(apng1C);
371 dump("Checking apng2A...\n");
372 run_test_for(apng2A);
373 dump("Checking apng2B...\n");
374 run_test_for(apng2B);
376 dump("Checking apng3...\n");
377 run_test_for(apng3);
378 };
381 function run_test_for(input) {
382 var encoder, dataURL;
384 encoder = encodeImage(input);
385 dataURL = makeDataURL(encoder, "image/png");
386 do_check_eq(dataURL, input.expected);
387 };
390 function encodeImage(input) {
391 var encoder = Cc["@mozilla.org/image/encoder;2?type=image/png"].createInstance();
392 encoder.QueryInterface(Ci.imgIEncoder);
394 var options = "";
395 if (input.transparency) { options += "transparency=" + input.transparency; }
396 options += ";frames=" + input.frames.length;
397 options += ";skipfirstframe=" + (input.skipFirstFrame ? "yes" : "no");
398 options += ";plays=" + input.plays;
399 encoder.startImageEncode(input.width, input.height, input.format, options);
401 for (var i = 0; i < input.frames.length; i++) {
402 var frame = input.frames[i];
404 options = "";
405 if (frame.transparency) { options += "transparency=" + input.transparency; }
406 options += ";delay=" + frame.delay;
407 options += ";dispose=" + frame.dispose;
408 options += ";blend=" + frame.blend;
409 if (frame.x_offset > 0) { options += ";xoffset=" + frame.x_offset; }
410 if (frame.y_offset > 0) { options += ";yoffset=" + frame.y_offset; }
412 encoder.addImageFrame(frame.pixels, frame.pixels.length,
413 frame.width, frame.height, frame.stride, frame.format, options);
414 }
416 encoder.endImageEncode();
418 return encoder;
419 }
422 function makeDataURL(encoder, mimetype) {
423 var rawStream = encoder.QueryInterface(Ci.nsIInputStream);
425 var stream = Cc["@mozilla.org/binaryinputstream;1"].createInstance();
426 stream.QueryInterface(Ci.nsIBinaryInputStream);
428 stream.setInputStream(rawStream);
430 var bytes = stream.readByteArray(stream.available()); // returns int[]
432 var base64String = toBase64(bytes);
434 return "data:" + mimetype + ";base64," + base64String;
435 }
437 /* toBase64 copied from extensions/xml-rpc/src/nsXmlRpcClient.js */
439 /* Convert data (an array of integers) to a Base64 string. */
440 const toBase64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' +
441 '0123456789+/';
442 const base64Pad = '=';
443 function toBase64(data) {
444 var result = '';
445 var length = data.length;
446 var i;
447 // Convert every three bytes to 4 ascii characters.
448 for (i = 0; i < (length - 2); i += 3) {
449 result += toBase64Table[data[i] >> 2];
450 result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
451 result += toBase64Table[((data[i+1] & 0x0f) << 2) + (data[i+2] >> 6)];
452 result += toBase64Table[data[i+2] & 0x3f];
453 }
455 // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
456 if (length%3) {
457 i = length - (length%3);
458 result += toBase64Table[data[i] >> 2];
459 if ((length%3) == 2) {
460 result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
461 result += toBase64Table[(data[i+1] & 0x0f) << 2];
462 result += base64Pad;
463 } else {
464 result += toBase64Table[(data[i] & 0x03) << 4];
465 result += base64Pad + base64Pad;
466 }
467 }
469 return result;
470 }