tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_encoder_apng.js (17800B)


      1 /*
      2 * Test for APNG encoding in ImageLib
      3 *
      4 */
      5 
      6 const { AppConstants } = ChromeUtils.importESModule(
      7  "resource://gre/modules/AppConstants.sys.mjs"
      8 );
      9 
     10 // dispose=[none|background|previous]
     11 // blend=[source|over]
     12 
     13 var apng1A = {
     14  // A 3x3 image with 3 frames, alternating red, green, blue. RGB format.
     15  width: 3,
     16  height: 3,
     17  skipFirstFrame: false,
     18  format: Ci.imgIEncoder.INPUT_FORMAT_RGB,
     19  transparency: null,
     20  plays: 0,
     21 
     22  frames: [
     23    {
     24      // frame #1
     25      width: 3,
     26      height: 3,
     27      x_offset: 0,
     28      y_offset: 0,
     29      dispose: "none",
     30      blend: "source",
     31      delay: 500,
     32 
     33      format: Ci.imgIEncoder.INPUT_FORMAT_RGB,
     34      stride: 9,
     35      transparency: null,
     36 
     37      pixels: [
     38        255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255,
     39        0, 0, 255, 0, 0, 255, 0, 0,
     40      ],
     41    },
     42 
     43    {
     44      // frame #2
     45      width: 3,
     46      height: 3,
     47      x_offset: 0,
     48      y_offset: 0,
     49      dispose: "none",
     50      blend: "source",
     51      delay: 500,
     52 
     53      format: Ci.imgIEncoder.INPUT_FORMAT_RGB,
     54      stride: 9,
     55      transparency: null,
     56 
     57      pixels: [
     58        0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0,
     59        255, 0, 0, 255, 0, 0, 255, 0,
     60      ],
     61    },
     62 
     63    {
     64      // frame #3
     65      width: 3,
     66      height: 3,
     67      x_offset: 0,
     68      y_offset: 0,
     69      dispose: "none",
     70      blend: "source",
     71      delay: 500,
     72 
     73      format: Ci.imgIEncoder.INPUT_FORMAT_RGB,
     74      stride: 9,
     75      transparency: null,
     76 
     77      pixels: [
     78        0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0,
     79        255, 0, 0, 255, 0, 0, 255,
     80      ],
     81    },
     82  ],
     83  expected:
     84    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAAA9JREFUCFtj/M8ABYxYWAA5IQMBD9nE1QAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAADuZcrMAAAAFGZkQVQAAAACCFtjZPjPAAGMWFgANiQDAVBdoI8AAAAaZmNUTAAAAAMAAAADAAAAAwAAAAAAAAAAAfQD6AAAA/MZJQAAABVmZEFUAAAABAhbY2Rg+M8ABoxYWAAzJwMBWk5KPwAAAABJRU5ErkJggg==",
     85 };
     86 
     87 var apng1B = {
     88  // A 3x3 image with 3 frames, alternating red, green, blue. RGBA format.
     89  width: 3,
     90  height: 3,
     91  skipFirstFrame: false,
     92  format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
     93  transparency: null,
     94  plays: 0,
     95 
     96  frames: [
     97    {
     98      // frame #1
     99      width: 3,
    100      height: 3,
    101      x_offset: 0,
    102      y_offset: 0,
    103      dispose: "none",
    104      blend: "source",
    105      delay: 500,
    106 
    107      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    108      stride: 12,
    109 
    110      pixels: [
    111        255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0,
    112        0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
    113      ],
    114    },
    115 
    116    {
    117      // frame #2
    118      width: 3,
    119      height: 3,
    120      x_offset: 0,
    121      y_offset: 0,
    122      dispose: "none",
    123      blend: "source",
    124      delay: 500,
    125 
    126      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    127      stride: 12,
    128 
    129      pixels: [
    130        0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
    131        0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
    132      ],
    133    },
    134 
    135    {
    136      // frame #3
    137      width: 3,
    138      height: 3,
    139      x_offset: 0,
    140      y_offset: 0,
    141      dispose: "none",
    142      blend: "source",
    143      delay: 500,
    144 
    145      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    146      stride: 12,
    147 
    148      pixels: [
    149        0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
    150        255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
    151        255,
    152      ],
    153    },
    154  ],
    155  expected: AppConstants.USE_LIBZ_RS
    156    ? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABJJREFUCFtj/M/A8J8BChhxcgCM6AX+QVLIVQAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAADuZcrMAAAAFmZkQVQAAAACCFtjZPjP8J8BChhxcgCJ6wX+aU5KcgAAABpmY1RMAAAAAwAAAAMAAAADAAAAAAAAAAAB9APoAAAD8xklAAAAFmZkQVQAAAAECFtjZGD4/58BChhxcgCG7gX+dDwqYgAAAABJRU5ErkJggg=="
    157    : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABJJREFUCFtj/M/AAEQQwIiTAwCM6AX+t+X3FQAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAADuZcrMAAAAFWZkQVQAAAACCFtjZPgPhFDAiJMDAInrBf4Q0nfOAAAAGmZjVEwAAAADAAAAAwAAAAMAAAAAAAAAAAH0A+gAAAPzGSUAAAAWZmRBVAAAAAQIW2NkYPj/nwEKGHFyAIbuBf50PCpiAAAAAElFTkSuQmCC",
    158 };
    159 
    160 var apng1C = {
    161  // A 3x3 image with 3 frames, alternating red, green, blue. RGBA format.
    162  // The first frame is skipped, so it will only flash green/blue (or static red in an APNG-unaware viewer)
    163  width: 3,
    164  height: 3,
    165  skipFirstFrame: true,
    166  format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    167  transparency: null,
    168  plays: 0,
    169 
    170  frames: [
    171    {
    172      // frame #1
    173      width: 3,
    174      height: 3,
    175      x_offset: 0,
    176      y_offset: 0,
    177      dispose: "none",
    178      blend: "source",
    179      delay: 500,
    180 
    181      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    182      stride: 12,
    183 
    184      pixels: [
    185        255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0,
    186        0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
    187      ],
    188    },
    189 
    190    {
    191      // frame #2
    192      width: 3,
    193      height: 3,
    194      x_offset: 0,
    195      y_offset: 0,
    196      dispose: "none",
    197      blend: "source",
    198      delay: 500,
    199 
    200      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    201      stride: 12,
    202 
    203      pixels: [
    204        0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
    205        0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
    206      ],
    207    },
    208 
    209    {
    210      // frame #3
    211      width: 3,
    212      height: 3,
    213      x_offset: 0,
    214      y_offset: 0,
    215      dispose: "none",
    216      blend: "source",
    217      delay: 500,
    218 
    219      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    220      stride: 12,
    221 
    222      pixels: [
    223        0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
    224        255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
    225        255,
    226      ],
    227    },
    228  ],
    229  expected: AppConstants.USE_LIBZ_RS
    230    ? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAACAAAAAPONk3AAAAASSURBVAhbY/zPwPCfAQoYcXIAjOgF/kFSyFUAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABZmZEFUAAAAAQhbY2T4z/CfAQoYcXIAiesF/soYzNsAAAAaZmNUTAAAAAIAAAADAAAAAwAAAAAAAAAAAfQD6AAAmIDz8QAAABZmZEFUAAAAAwhbY2Rg+P+fAQoYcXIAhu4F/j4CoSkAAAAASUVORK5CYII="
    231    : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAACAAAAAPONk3AAAAASSURBVAhbY/zPwABEEMCIkwMAjOgF/rfl9xUAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABVmZEFUAAAAAQhbY2T4D4RQwIiTAwCJ6wX++lSqrAAAABpmY1RMAAAAAgAAAAMAAAADAAAAAAAAAAAB9APoAACYgPPxAAAAFmZkQVQAAAADCFtjZGD4/58BChhxcgCG7gX+PgKhKQAAAABJRU5ErkJggg==",
    232 };
    233 
    234 var apng2A = {
    235  // A 3x3 image with 3 frames, alternating red, green, blue. RGBA format.
    236  // blend = over mode
    237  // (The green frame is a horizontal gradient, and the blue frame is a
    238  // vertical gradient. They stack as they animate.)
    239  width: 3,
    240  height: 3,
    241  skipFirstFrame: false,
    242  format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    243  transparency: null,
    244  plays: 0,
    245 
    246  frames: [
    247    {
    248      // frame #1
    249      width: 3,
    250      height: 3,
    251      x_offset: 0,
    252      y_offset: 0,
    253      dispose: "none",
    254      blend: "source",
    255      delay: 500,
    256 
    257      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    258      stride: 12,
    259 
    260      pixels: [
    261        255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0,
    262        0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
    263      ],
    264    },
    265 
    266    {
    267      // frame #2
    268      width: 3,
    269      height: 3,
    270      x_offset: 0,
    271      y_offset: 0,
    272      dispose: "none",
    273      blend: "over",
    274      delay: 500,
    275 
    276      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    277      stride: 12,
    278 
    279      pixels: [
    280        0, 255, 0, 255, 0, 255, 0, 180, 0, 255, 0, 75, 0, 255, 0, 255, 0, 255,
    281        0, 180, 0, 255, 0, 75, 0, 255, 0, 255, 0, 255, 0, 180, 0, 255, 0, 75,
    282      ],
    283    },
    284 
    285    {
    286      // frame #3
    287      width: 3,
    288      height: 3,
    289      x_offset: 0,
    290      y_offset: 0,
    291      dispose: "none",
    292      blend: "over",
    293      delay: 500,
    294 
    295      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    296      stride: 12,
    297 
    298      pixels: [
    299        0, 0, 255, 75, 0, 0, 255, 75, 0, 0, 255, 75, 0, 0, 255, 180, 0, 0, 255,
    300        180, 0, 0, 255, 180, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
    301      ],
    302    },
    303  ],
    304  expected: AppConstants.USE_LIBZ_RS
    305    ? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABJJREFUCFtj/M/A8J8BChhxcgCM6AX+QVLIVQAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAAGZYvpaAAAAHGZkQVQAAAACCFtjZPjP8J+BgWErAwPDdEacHADI3wnivbhTBAAAABpmY1RMAAAAAwAAAAMAAAADAAAAAAAAAAAB9APoAAF09CmzAAAAHWZkQVQAAAAECFtjZGD4780ABYwMDP+3IHP+wzgAZ+AE/9iH+yoAAAAASUVORK5CYII="
    306    : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABJJREFUCFtj/M/AAEQQwIiTAwCM6AX+t+X3FQAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAAGZYvpaAAAAGWZkQVQAAAACCFtjZPgPhAwMW4F4OiNODgDI3wnis0vjTAAAABpmY1RMAAAAAwAAAAMAAAADAAAAAAAAAAAB9APoAAF09CmzAAAAHGZkQVQAAAAECFtjZGD4780ABYxAzhZkzn8YBwBn4AT/ernr+wAAAABJRU5ErkJggg==",
    307 };
    308 
    309 var apng2B = {
    310  // A 3x3 image with 3 frames, alternating red, green, blue. RGBA format.
    311  // blend = over, dispose = background
    312  // (The green frame is a horizontal gradient, and the blue frame is a
    313  // vertical gradient. Each frame is displayed individually, blended to
    314  // whatever the background is.)
    315  width: 3,
    316  height: 3,
    317  skipFirstFrame: false,
    318  format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    319  transparency: null,
    320  plays: 0,
    321 
    322  frames: [
    323    {
    324      // frame #1
    325      width: 3,
    326      height: 3,
    327      x_offset: 0,
    328      y_offset: 0,
    329      dispose: "background",
    330      blend: "source",
    331      delay: 500,
    332 
    333      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    334      stride: 12,
    335 
    336      pixels: [
    337        255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0,
    338        0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255,
    339      ],
    340    },
    341 
    342    {
    343      // frame #2
    344      width: 3,
    345      height: 3,
    346      x_offset: 0,
    347      y_offset: 0,
    348      dispose: "background",
    349      blend: "over",
    350      delay: 500,
    351 
    352      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    353      stride: 12,
    354 
    355      pixels: [
    356        0, 255, 0, 255, 0, 255, 0, 180, 0, 255, 0, 75, 0, 255, 0, 255, 0, 255,
    357        0, 180, 0, 255, 0, 75, 0, 255, 0, 255, 0, 255, 0, 180, 0, 255, 0, 75,
    358      ],
    359    },
    360 
    361    {
    362      // frame #3
    363      width: 3,
    364      height: 3,
    365      x_offset: 0,
    366      y_offset: 0,
    367      dispose: "background",
    368      blend: "over",
    369      delay: 500,
    370 
    371      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    372      stride: 12,
    373 
    374      pixels: [
    375        0, 0, 255, 75, 0, 0, 255, 75, 0, 0, 255, 75, 0, 0, 255, 180, 0, 0, 255,
    376        180, 0, 0, 255, 180, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
    377      ],
    378    },
    379  ],
    380  expected: AppConstants.USE_LIBZ_RS
    381    ? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AEAbA0RWQAAABJJREFUCFtj/M/A8J8BChhxcgCM6AX+QVLIVQAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAQGAecsbAAAAHGZkQVQAAAACCFtjZPjP8J+BgWErAwPDdEacHADI3wnivbhTBAAAABpmY1RMAAAAAwAAAAMAAAADAAAAAAAAAAAB9APoAQFt7xjyAAAAHWZkQVQAAAAECFtjZGD4780ABYwMDP+3IHP+wzgAZ+AE/9iH+yoAAAAASUVORK5CYII="
    382    : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAADAAAAAM7tusAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AEAbA0RWQAAABJJREFUCFtj/M/AAEQQwIiTAwCM6AX+t+X3FQAAABpmY1RMAAAAAQAAAAMAAAADAAAAAAAAAAAB9APoAQGAecsbAAAAGWZkQVQAAAACCFtjZPgPhAwMW4F4OiNODgDI3wnis0vjTAAAABpmY1RMAAAAAwAAAAMAAAADAAAAAAAAAAAB9APoAQFt7xjyAAAAHGZkQVQAAAAECFtjZGD4780ABYxAzhZkzn8YBwBn4AT/ernr+wAAAABJRU5ErkJggg==",
    383 };
    384 
    385 var apng3 = {
    386  // A 3x3 image with 4 frames. First frame is white, then 1x1 frames draw a diagonal line
    387  width: 3,
    388  height: 3,
    389  skipFirstFrame: false,
    390  format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    391  transparency: null,
    392  plays: 0,
    393 
    394  frames: [
    395    {
    396      // frame #1
    397      width: 3,
    398      height: 3,
    399      x_offset: 0,
    400      y_offset: 0,
    401      dispose: "none",
    402      blend: "source",
    403      delay: 500,
    404 
    405      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    406      stride: 12,
    407 
    408      pixels: [
    409        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    410        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    411        255, 255, 255, 255, 255, 255, 255, 255,
    412      ],
    413    },
    414 
    415    {
    416      // frame #2
    417      width: 1,
    418      height: 1,
    419      x_offset: 0,
    420      y_offset: 0,
    421      dispose: "none",
    422      blend: "source",
    423      delay: 500,
    424 
    425      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    426      stride: 12,
    427 
    428      pixels: [0, 0, 0, 255],
    429    },
    430 
    431    {
    432      // frame #3
    433      width: 1,
    434      height: 1,
    435      x_offset: 1,
    436      y_offset: 1,
    437      dispose: "none",
    438      blend: "source",
    439      delay: 500,
    440 
    441      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    442      stride: 12,
    443 
    444      pixels: [0, 0, 0, 255],
    445    },
    446 
    447    {
    448      // frame #4
    449      width: 1,
    450      height: 1,
    451      x_offset: 2,
    452      y_offset: 2,
    453      dispose: "none",
    454      blend: "source",
    455      delay: 500,
    456 
    457      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
    458      stride: 12,
    459 
    460      pixels: [0, 0, 0, 255],
    461    },
    462  ],
    463 
    464  expected: AppConstants.USE_LIBZ_RS
    465    ? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAAEAAAAAHzNZtAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABNJREFUCFtj/P///38GKGDEyQEAGWoL+Bp453UAAAAaZmNUTAAAAAEAAAABAAAAAQAAAAAAAAAAAfQD6AAAMld9rAAAABFmZEFUAAAAAghbY2BgYPgPAAEEAQDSISApAAAAGmZjVEwAAAADAAAAAQAAAAEAAAABAAAAAQH0A+gAALg4ejEAAAARZmRBVAAAAAQIW2NgYGD4DwABBAEAKuNrnwAAABpmY1RMAAAABQAAAAEAAAABAAAAAgAAAAIB9APoAAD9+HTXAAAAEWZkQVQAAAAGCFtjYGBg+A8AAQQBAMuNrzIAAAAASUVORK5CYII="
    466    : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAACGFjVEwAAAAEAAAAAHzNZtAAAAAaZmNUTAAAAAAAAAADAAAAAwAAAAAAAAAAAfQD6AAAdRYgGAAAABFJREFUCFtj/A8EDFDAiJMDABlqC/jamhxvAAAAGmZjVEwAAAABAAAAAQAAAAEAAAAAAAAAAAH0A+gAADJXfawAAAARZmRBVAAAAAIIW2NgYGD4DwABBAEA0iEgKQAAABpmY1RMAAAAAwAAAAEAAAABAAAAAQAAAAEB9APoAAC4OHoxAAAAEWZkQVQAAAAECFtjYGBg+A8AAQQBACrja58AAAAaZmNUTAAAAAUAAAABAAAAAQAAAAIAAAACAfQD6AAA/fh01wAAABFmZEFUAAAABghbY2BgYPgPAAEEAQDLja8yAAAAAElFTkSuQmCC",
    467 };
    468 
    469 // Main test entry point.
    470 function run_test() {
    471  dump("Checking apng1A...\n");
    472  run_test_for(apng1A);
    473  dump("Checking apng1B...\n");
    474  run_test_for(apng1B);
    475  dump("Checking apng1C...\n");
    476  run_test_for(apng1C);
    477 
    478  dump("Checking apng2A...\n");
    479  run_test_for(apng2A);
    480  dump("Checking apng2B...\n");
    481  run_test_for(apng2B);
    482 
    483  dump("Checking apng3...\n");
    484  run_test_for(apng3);
    485 }
    486 
    487 function run_test_for(input) {
    488  var encoder, dataURL;
    489 
    490  encoder = encodeImage(input);
    491  dataURL = makeDataURL(encoder, "image/png");
    492  Assert.equal(dataURL, input.expected);
    493 }
    494 
    495 function encodeImage(input) {
    496  var encoder =
    497    Cc["@mozilla.org/image/encoder;2?type=image/png"].createInstance();
    498  encoder.QueryInterface(Ci.imgIEncoder);
    499 
    500  var options = "";
    501  if (input.transparency) {
    502    options += "transparency=" + input.transparency;
    503  }
    504  options += ";frames=" + input.frames.length;
    505  options += ";skipfirstframe=" + (input.skipFirstFrame ? "yes" : "no");
    506  options += ";plays=" + input.plays;
    507  encoder.startImageEncode(input.width, input.height, input.format, options);
    508 
    509  for (var i = 0; i < input.frames.length; i++) {
    510    var frame = input.frames[i];
    511 
    512    options = "";
    513    if (frame.transparency) {
    514      options += "transparency=" + input.transparency;
    515    }
    516    options += ";delay=" + frame.delay;
    517    options += ";dispose=" + frame.dispose;
    518    options += ";blend=" + frame.blend;
    519    if (frame.x_offset > 0) {
    520      options += ";xoffset=" + frame.x_offset;
    521    }
    522    if (frame.y_offset > 0) {
    523      options += ";yoffset=" + frame.y_offset;
    524    }
    525 
    526    encoder.addImageFrame(
    527      frame.pixels,
    528      frame.pixels.length,
    529      frame.width,
    530      frame.height,
    531      frame.stride,
    532      frame.format,
    533      options
    534    );
    535  }
    536 
    537  encoder.endImageEncode();
    538 
    539  return encoder;
    540 }
    541 
    542 function makeDataURL(encoder, mimetype) {
    543  var rawStream = encoder.QueryInterface(Ci.nsIInputStream);
    544 
    545  var stream = Cc["@mozilla.org/binaryinputstream;1"].createInstance();
    546  stream.QueryInterface(Ci.nsIBinaryInputStream);
    547 
    548  stream.setInputStream(rawStream);
    549 
    550  var bytes = stream.readByteArray(stream.available()); // returns int[]
    551 
    552  var base64String = toBase64(bytes);
    553 
    554  return "data:" + mimetype + ";base64," + base64String;
    555 }
    556 
    557 /* toBase64 copied from extensions/xml-rpc/src/nsXmlRpcClient.js */
    558 
    559 /* Convert data (an array of integers) to a Base64 string. */
    560 const toBase64Table =
    561  // eslint-disable-next-line no-useless-concat
    562  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789+/";
    563 const base64Pad = "=";
    564 function toBase64(data) {
    565  var result = "";
    566  var length = data.length;
    567  var i;
    568  // Convert every three bytes to 4 ascii characters.
    569  for (i = 0; i < length - 2; i += 3) {
    570    result += toBase64Table[data[i] >> 2];
    571    result += toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
    572    result += toBase64Table[((data[i + 1] & 0x0f) << 2) + (data[i + 2] >> 6)];
    573    result += toBase64Table[data[i + 2] & 0x3f];
    574  }
    575 
    576  // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
    577  if (length % 3) {
    578    i = length - (length % 3);
    579    result += toBase64Table[data[i] >> 2];
    580    if (length % 3 == 2) {
    581      result += toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
    582      result += toBase64Table[(data[i + 1] & 0x0f) << 2];
    583      result += base64Pad;
    584    } else {
    585      result += toBase64Table[(data[i] & 0x03) << 4];
    586      result += base64Pad + base64Pad;
    587    }
    588  }
    589 
    590  return result;
    591 }