tor-browser

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

source.html (28621B)


      1 <!DOCTYPE HTML>
      2 <title>APNG tests</title>
      3 <style>
      4 html {
      5    background-color: white;
      6    color: black;
      7 }
      8 body {
      9    font-family: sans-serif;
     10 }
     11 .testimage {
     12    border: 1px black solid;
     13    background: #ffa;
     14 }
     15 blockquote {
     16    font-style: italic;
     17 }
     18 blockquote[cite]:after {
     19    font-style: normal;
     20    font-size: x-small;
     21    padding-left: 2em;
     22    content: "(" attr(cite) ")";
     23 }
     24 blockquote[cite="#apng"]:after {
     25    content: "(APNG Specification)";
     26 }
     27 blockquote[cite="#png"]:after {
     28    content: "(PNG Specification)";
     29 }
     30 blockquote p {
     31    margin: 0;
     32 }
     33 div.case {
     34    border: 1px #888 solid;
     35    padding: 0.3em;
     36    margin: 0.3em;
     37 }
     38 div.case:target {
     39    border: 2px #000 solid;
     40 }
     41 div.case > p {
     42    margin: 0;
     43 }
     44 </style>
     45 
     46 <p><em>This page is somewhat incomplete and quite possibly incorrect &ndash; use with caution. <img src="underconstruction.png" style="vertical-align: middle" alt=""></em>
     47 
     48 <h1>APNG tests</h1>
     49 
     50 <p>For all these tests, wait at least a second after all the images have downloaded, before checking that the rendered output is correct.
     51 
     52 <p>Test output conventions:
     53 A solid green 128&times;64 rectangle means success.
     54 Any red means failure.
     55 Anything else means you need to read the instructions.
     56 "Transparent" is indicated by a <span style="background: #ffa">light yellow background</span>.
     57 
     58 <p>Sections of the relevant specifications are sometimes quoted when they clarify the expected behaviour.
     59 
     60 <p>Please don't link directly to the images in this page, since they may get renamed and will break any such links.
     61 
     62 <p>You can download <a href="generate.pl">the script</a> and <a href="source.html">the source data</a> for this page.
     63 
     64 
     65 <h2>Valid images</h2>
     66 
     67 
     68 <h3>Basic cases</h3>
     69 
     70 <div class="case">
     71 <p>Trivial static image.
     72 <p>This should be solid green.
     73 <png>
     74 IHDR => [W, H],
     75 IDAT => [create_surface(W, H, 'green')],
     76 IEND => [],
     77 </png>
     78 </div>
     79 
     80 <div class="case">
     81 <p>Trivial animated image - one frame; using default image.
     82 <p>This should be solid green.
     83 <png>
     84 IHDR => [W, H],
     85 acTL => [1, 0],
     86 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
     87 IDAT => [create_surface(W, H, 'green')],
     88 IEND => [],
     89 </png>
     90 </div>
     91 
     92 <div class="case">
     93 <p>Trivial animated image - one frame; ignoring default image.
     94 <p>This should be solid green.
     95 <png>
     96 IHDR => [W, H],
     97 acTL => [1, 0],
     98 IDAT => [create_surface(W, H, 'red')],
     99 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    100 fdAT => [1, create_surface(W, H, 'green')],
    101 IEND => [],
    102 </png>
    103 </div>
    104 
    105 
    106 <h3>IDAT, fdAT splitting</h3>
    107 <blockquote cite="#png"><p>There may be multiple IDAT chunks; if so, they shall appear consecutively with no other intervening chunks. The compressed datastream is then the concatenation of the contents of the data fields of all the IDAT chunks.</blockquote>
    108 <blockquote cite="#apng"><p>The compressed datastream is then the concatenation of the contents of the data fields of all the `fdAT` chunks within a frame.</blockquote>
    109 
    110 <div class="case">
    111 <p>Basic split IDAT.
    112 <p>This should be solid green.
    113 <png>
    114 IHDR => [W, H],
    115 IDAT_split => [0,32, create_surface(W, H, 'green')],
    116 IDAT_split => [32,-1, create_surface(W, H, 'green')],
    117 IEND => [],
    118 </png>
    119 </div>
    120 
    121 <div class="case">
    122 <p>Split IDAT with zero-length chunk.
    123 <p>This should be solid green.
    124 <png>
    125 IHDR => [W, H],
    126 IDAT_split => [0,32, create_surface(W, H, 'green')],
    127 IDAT_split => [32,32, create_surface(W, H, 'green')],
    128 IDAT_split => [32,-1, create_surface(W, H, 'green')],
    129 IEND => [],
    130 </png>
    131 </div>
    132 
    133 <div class="case">
    134 <p>Basic split fdAT.
    135 <p>This should be solid green.
    136 <png>
    137 IHDR => [W, H],
    138 acTL => [1, 0],
    139 IDAT => [create_surface(W, H, 'red')],
    140 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    141 fdAT_split => [1, 0,32, create_surface(W, H, 'green')],
    142 fdAT_split => [2, 32,-1, create_surface(W, H, 'green')],
    143 IEND => [],
    144 </png>
    145 </div>
    146 
    147 <div class="case">
    148 <p>Split fdAT with zero-length chunk.
    149 <p>This should be solid green.
    150 <!-- Opera bug 286566 -->
    151 <png>
    152 IHDR => [W, H],
    153 acTL => [1, 0],
    154 IDAT => [create_surface(W, H, 'red')],
    155 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    156 fdAT_split => [1, 0,32, create_surface(W, H, 'green')],
    157 fdAT_split => [2, 32,32, create_surface(W, H, 'green')],
    158 fdAT_split => [3, 32,-1, create_surface(W, H, 'green')],
    159 IEND => [],
    160 </png>
    161 </div>
    162 
    163 
    164 <h3>Dispose ops</h3>
    165 
    166 <div class="case">
    167 <p>APNG_DISPOSE_OP_NONE - basic.
    168 <p>This should be solid green.
    169 <png>
    170 IHDR => [W, H],
    171 acTL => [3, 1],
    172 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    173 IDAT => [create_surface(W, H, 'red')],
    174 fcTL => [1, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    175 fdAT => [2, create_surface(W, H, 'green')],
    176 fcTL => [3, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    177 fdAT => [4, create_surface(W, H, 'transparent')],
    178 IEND => [],
    179 </png>
    180 </div>
    181 
    182 <div class="case">
    183 <p>APNG_DISPOSE_OP_BACKGROUND - basic.
    184 <p>This should be transparent.
    185 <png>
    186 IHDR => [W, H],
    187 acTL => [3, 1],
    188 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    189 IDAT => [create_surface(W, H, 'red')],
    190 fcTL => [1, W, H, 0, 0, 10, 100, DISPOSE_BACKGROUND, BLEND_OVER],
    191 fdAT => [2, create_surface(W, H, 'red')],
    192 fcTL => [3, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    193 fdAT => [4, create_surface(W, H, 'transparent')],
    194 IEND => [],
    195 </png>
    196 </div>
    197 
    198 <div class="case">
    199 <p>APNG_DISPOSE_OP_BACKGROUND - final frame.
    200 <p>This should be solid green.
    201 <png>
    202 IHDR => [W, H],
    203 acTL => [2, 1],
    204 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    205 IDAT => [create_surface(W, H, 'red')],
    206 fcTL => [1, W, H, 0, 0, 10, 100, DISPOSE_BACKGROUND, BLEND_OVER],
    207 fdAT => [2, create_surface(W, H, 'green')],
    208 IEND => [],
    209 </png>
    210 </div>
    211 
    212 <div class="case">
    213 <p>APNG_DISPOSE_OP_PREVIOUS - basic.
    214 <p>This should be solid green.
    215 <png>
    216 IHDR => [W, H],
    217 acTL => [3, 1],
    218 IDAT => [create_surface(W, H, 'red')],
    219 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    220 fdAT => [1, create_surface(W, H, 'green')],
    221 fcTL => [2, W, H, 0, 0, 10, 100, DISPOSE_PREVIOUS, BLEND_OVER],
    222 fdAT => [3, create_surface(W, H, 'red')],
    223 fcTL => [4, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    224 fdAT => [5, create_surface(W, H, 'transparent')],
    225 IEND => [],
    226 </png>
    227 </div>
    228 
    229 <div class="case">
    230 <p>APNG_DISPOSE_OP_PREVIOUS - final frame.
    231 <p>This should be solid green.
    232 <png>
    233 IHDR => [W, H],
    234 acTL => [2, 1],
    235 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    236 IDAT => [create_surface(W, H, 'red')],
    237 fcTL => [1, W, H, 0, 0, 10, 100, DISPOSE_PREVIOUS, BLEND_OVER],
    238 fdAT => [2, create_surface(W, H, 'green')],
    239 IEND => [],
    240 </png>
    241 </div>
    242 
    243 <div class="case">
    244 <p>APNG_DISPOSE_OP_PREVIOUS - first frame.
    245 <p>This should be transparent.
    246 <png>
    247 IHDR => [W, H],
    248 acTL => [2, 1],
    249 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_PREVIOUS, BLEND_OVER],
    250 IDAT => [create_surface(W, H, 'red')],
    251 fcTL => [1, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    252 fdAT => [2, create_surface(W, H, 'transparent')],
    253 IEND => [],
    254 </png>
    255 </div>
    256 
    257 
    258 <h3>Dispose ops and regions</h3>
    259 
    260 <div class="case">
    261 <p>APNG_DISPOSE_OP_NONE in region.
    262 <p>This should be solid green.
    263 <png>
    264 IHDR => [W, H],
    265 acTL => [3, 1],
    266 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    267 IDAT => [create_surface(W, H, 'doublerect', 0,1,0,1, 1,0,0,1)],
    268 fcTL => [1, W/2, H/2, W/4, H/4, 10, 100, DISPOSE_NONE, BLEND_OVER],
    269 fdAT => [2, create_surface(W/2, H/2, 'green')],
    270 fcTL => [3, 1, 1, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    271 fdAT => [4, create_surface(1, 1, 'transparent')],
    272 IEND => [],
    273 </png>
    274 </div>
    275 
    276 <div class="case">
    277 <p>APNG_DISPOSE_OP_BACKGROUND before region.
    278 <p>This should be transparent.
    279 <png>
    280 IHDR => [W, H],
    281 acTL => [2, 1],
    282 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_BACKGROUND, BLEND_OVER],
    283 IDAT => [create_surface(W, H, 'red')],
    284 fcTL => [1, 1, 1, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    285 fdAT => [2, create_surface(1, 1, 'transparent')],
    286 IEND => [],
    287 </png>
    288 </div>
    289 
    290 <div class="case">
    291 <p>APNG_DISPOSE_OP_BACKGROUND in region.
    292 <p>This should be a solid blue rectangle containing a smaller transparent rectangle.
    293 <!-- Opera bug 286565 -->
    294 <png>
    295 IHDR => [W, H],
    296 acTL => [3, 1],
    297 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    298 IDAT => [create_surface(W, H, 'doublerect', 0,0,1,1, 1,0,0,1)],
    299 fcTL => [1, W/2, H/2, W/4, H/4, 10, 100, DISPOSE_BACKGROUND, BLEND_OVER],
    300 fdAT => [2, create_surface(W/2, H/2, 'red')],
    301 fcTL => [3, 1, 1, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    302 fdAT => [4, create_surface(1, 1, 'transparent')],
    303 IEND => [],
    304 </png>
    305 </div>
    306 
    307 <div class="case">
    308 <p>APNG_DISPOSE_OP_PREVIOUS in region.
    309 <p>This should be solid green.
    310 <png>
    311 IHDR => [W, H],
    312 acTL => [3, 1],
    313 IDAT => [create_surface(W, H, 'red')],
    314 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    315 fdAT => [1, create_surface(W, H, 'green')],
    316 fcTL => [2, W/2, H/2, W/4, H/4, 10, 100, DISPOSE_PREVIOUS, BLEND_OVER],
    317 fdAT => [3, create_surface(W/2, H/2, 'red')],
    318 fcTL => [4, 1, 1, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    319 fdAT => [5, create_surface(1, 1, 'transparent')],
    320 IEND => [],
    321 </png>
    322 </div>
    323 
    324 
    325 <h3>Blend ops</h3>
    326 
    327 <div class="case">
    328 <p>APNG_BLEND_OP_SOURCE on solid colour.
    329 <p>This should be solid green.
    330 <png>
    331 IHDR => [W, H],
    332 acTL => [2, 1],
    333 IDAT => [create_surface(W, H, 'red')],
    334 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    335 fdAT => [1, create_surface(W, H, 'red')],
    336 fcTL => [2, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_SOURCE],
    337 fdAT => [3, create_surface(W, H, 'green')],
    338 IEND => [],
    339 </png>
    340 </div>
    341 
    342 <div class="case">
    343 <p>APNG_BLEND_OP_SOURCE on transparent colour.
    344 <p>This should be transparent.
    345 <png>
    346 IHDR => [W, H],
    347 acTL => [2, 1],
    348 IDAT => [create_surface(W, H, 'red')],
    349 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    350 fdAT => [1, create_surface(W, H, 'red')],
    351 fcTL => [2, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_SOURCE],
    352 fdAT => [3, create_surface(W, H, 'transparent')],
    353 IEND => [],
    354 </png>
    355 </div>
    356 
    357 <div class="case">
    358 <p>APNG_BLEND_OP_SOURCE on nearly-transparent colour.
    359 <p>This should be very nearly transparent.
    360 <png>
    361 IHDR => [W, H],
    362 acTL => [2, 1],
    363 IDAT => [create_surface(W, H, 'red')],
    364 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    365 fdAT => [1, create_surface(W, H, 'red')],
    366 fcTL => [2, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_SOURCE],
    367 fdAT => [3, create_surface(W, H, 'solid', 0, 1, 0, 0.01)],
    368 IEND => [],
    369 </png>
    370 </div>
    371 
    372 <div class="case">
    373 <p>APNG_BLEND_OP_OVER on solid and transparent colours.
    374 <p>This should be solid green.
    375 <png>
    376 IHDR => [W, H],
    377 acTL => [2, 1],
    378 IDAT => [create_surface(W, H, 'red')],
    379 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    380 fdAT => [1, create_surface(W, H, 'green')],
    381 fcTL => [2, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    382 fdAT => [3, create_surface(W, H, 'transparent')],
    383 IEND => [],
    384 </png>
    385 </div>
    386 
    387 <div class="case">
    388 <p>APNG_BLEND_OP_OVER repeatedly with nearly-transparent colours.
    389 <p>This should be solid green.
    390 <png>
    391 IHDR => [W, H],
    392 acTL => [128, 1],
    393 IDAT => [create_surface(W, H, 'red')],
    394 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    395 fdAT => [1, create_surface(W, H, 'solid', 0, 1, 0, 1)],
    396 (map {
    397    (fcTL => [2+$_*2, W/2, H, 0, 0, 1, 100, DISPOSE_NONE, BLEND_OVER],
    398    fdAT => [3+$_*2, create_surface(W/2, H, 'solid', 0, 1, 0, 0.01)])
    399 } 0..126),
    400 IEND => [],
    401 </png>
    402 </div>
    403 
    404 
    405 <h3>Blending and gamma</h3>
    406 
    407 <div class="case">
    408 <p>APNG_BLEND_OP_OVER
    409 <p>This should be solid slightly-dark green.
    410 <png>
    411 IHDR => [W, H],
    412 gAMA => [1],
    413 acTL => [16, 1],
    414 IDAT => [create_surface(W, H, 'red')],
    415 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    416 fdAT => [1, create_surface(W, H, 'solid', 0, 1, 0, 1)],
    417 (map {
    418    (fcTL => [2+$_*2, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    419    fdAT => [3+$_*2, create_surface(W, H, 'solid', 0, 0.9, 0, 0.5)])
    420 } 0..14),
    421 IEND => [],
    422 </png>
    423 </div>
    424 
    425 <div class="case">
    426 <p>APNG_BLEND_OP_OVER
    427 <p>This should be solid nearly-black.
    428 <png>
    429 IHDR => [W, H],
    430 gAMA => [1/2200],
    431 acTL => [16, 1],
    432 IDAT => [create_surface(W, H, 'red')],
    433 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    434 fdAT => [1, create_surface(W, H, 'red')],
    435 (map {
    436    (fcTL => [2+$_*2, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    437    fdAT => [3+$_*2, create_surface(W, H, 'solid', 0.9, 0, 0, 0.5)])
    438 } 0..14),
    439 IEND => [],
    440 </png>
    441 </div>
    442 
    443 
    444 <h3>Chunk ordering</h3>
    445 
    446 <div class="case">
    447 <p>fcTL before acTL.
    448 <p>This should be solid green.
    449 <png>
    450 IHDR => [W, H],
    451 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    452 acTL => [2, 1],
    453 IDAT => [create_surface(W, H, 'red')],
    454 fcTL => [1, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    455 fdAT => [2, create_surface(W, H, 'green')],
    456 IEND => [],
    457 </png>
    458 </div>
    459 
    460 
    461 <h3>Delays</h3>
    462 
    463 <div class="case">
    464 <p>Basic delays.
    465 <p>This should flash blue for half a second, then yellow for one second, then repeat.
    466 <png>
    467 IHDR => [W, H],
    468 acTL => [4, 0],
    469 IDAT => [create_surface(W, H, 'red')],
    470 fcTL => [0, W, H, 0, 0, 50, 100, DISPOSE_NONE, BLEND_OVER],
    471 fdAT => [1, create_surface(W, H, 'blue')],
    472 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    473 fdAT => [3, create_surface(W, H, 'yellow')],
    474 fcTL => [4, W, H, 0, 0, 10000, 20000, DISPOSE_NONE, BLEND_OVER],
    475 fdAT => [5, create_surface(W, H, 'blue')],
    476 fcTL => [6, W, H, 0, 0, 1, 1, DISPOSE_NONE, BLEND_OVER],
    477 fdAT => [7, create_surface(W, H, 'yellow')],
    478 IEND => [],
    479 </png>
    480 </div>
    481 
    482 <div class="case">
    483 <p>Rounding of division.
    484 <p>This should flash blue for half a second, then yellow for one second, then repeat.
    485 <png>
    486 IHDR => [W, H],
    487 acTL => [2, 0],
    488 IDAT => [create_surface(W, H, 'red')],
    489 fcTL => [0, W, H, 0, 0, 1, 2, DISPOSE_NONE, BLEND_OVER],
    490 fdAT => [1, create_surface(W, H, 'blue')],
    491 fcTL => [2, W, H, 0, 0, 1, 1, DISPOSE_NONE, BLEND_OVER],
    492 fdAT => [3, create_surface(W, H, 'yellow')],
    493 IEND => [],
    494 </png>
    495 </div>
    496 
    497 <div class="case">
    498 <p>16-bit numerator/denominator.
    499 <p>This should flash blue for half a second, then yellow for one second, then repeat.
    500 <png>
    501 IHDR => [W, H],
    502 acTL => [2, 0],
    503 IDAT => [create_surface(W, H, 'red')],
    504 fcTL => [0, W, H, 0, 0, 32767, 65534, DISPOSE_NONE, BLEND_OVER],
    505 fdAT => [1, create_surface(W, H, 'blue')],
    506 fcTL => [2, W, H, 0, 0, 65535, 65535, DISPOSE_NONE, BLEND_OVER],
    507 fdAT => [3, create_surface(W, H, 'yellow')],
    508 IEND => [],
    509 </png>
    510 </div>
    511 
    512 <div class="case">
    513 <p>Zero denominator.
    514 <blockquote cite="#apng"><p>If the denominator is 0, it is to be treated as if it were 100</blockquote>
    515 <p>This should flash blue for half a second, then yellow for one second, then repeat.
    516 <png>
    517 IHDR => [W, H],
    518 acTL => [2, 0],
    519 IDAT => [create_surface(W, H, 'red')],
    520 fcTL => [0, W, H, 0, 0, 50, 0, DISPOSE_NONE, BLEND_OVER],
    521 fdAT => [1, create_surface(W, H, 'blue')],
    522 fcTL => [2, W, H, 0, 0, 1000, 1000, DISPOSE_NONE, BLEND_OVER],
    523 fdAT => [3, create_surface(W, H, 'yellow')],
    524 IEND => [],
    525 </png>
    526 </div>
    527 
    528 <div class="case">
    529 <p>Zero numerator.
    530 <blockquote cite="#apng"><p>If the value of the numerator is 0 the decoder should render the next frame as quickly as possible, though viewers may impose a reasonable lower bound.</blockquote>
    531 <p>This should flash cyan for a short period of time (perhaps zero), then magenta for the same short period of time, then blue for half a second, then yellow for one second, then repeat.
    532 <png>
    533 IHDR => [W, H],
    534 acTL => [4, 0],
    535 IDAT => [create_surface(W, H, 'red')],
    536 fcTL => [0, W, H, 0, 0, 0, 100, DISPOSE_NONE, BLEND_OVER],
    537 fdAT => [1, create_surface(W, H, 'cyan')],
    538 fcTL => [2, W, H, 0, 0, 0, 0, DISPOSE_NONE, BLEND_OVER],
    539 fdAT => [3, create_surface(W, H, 'magenta')],
    540 fcTL => [4, W, H, 0, 0, 500, 1000, DISPOSE_NONE, BLEND_OVER],
    541 fdAT => [5, create_surface(W, H, 'blue')],
    542 fcTL => [6, W, H, 0, 0, 1000, 1000, DISPOSE_NONE, BLEND_OVER],
    543 fdAT => [7, create_surface(W, H, 'yellow')],
    544 IEND => [],
    545 </png>
    546 </div>
    547 
    548 
    549 <h3>num_plays</h3>
    550 
    551 <div class="case">
    552 <p>num_plays = 0
    553 <p>This should flash yellow for one second, then blue for one second, then repeat forever.
    554 <png>
    555 IHDR => [W, H],
    556 acTL => [2, 0],
    557 IDAT => [create_surface(W, H, 'red')],
    558 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    559 fdAT => [1, create_surface(W, H, 'yellow')],
    560 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    561 fdAT => [3, create_surface(W, H, 'blue')],
    562 IEND => [],
    563 </png>
    564 </div>
    565 
    566 <div class="case">
    567 <p>num_plays = 1
    568 <p>When first loaded, this should flash yellow for one second, then stay blue forever.
    569 <png>
    570 IHDR => [W, H],
    571 acTL => [2, 1],
    572 IDAT => [create_surface(W, H, 'red')],
    573 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    574 fdAT => [1, create_surface(W, H, 'yellow')],
    575 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    576 fdAT => [3, create_surface(W, H, 'blue')],
    577 IEND => [],
    578 </png>
    579 </div>
    580 
    581 <div class="case">
    582 <p>num_plays = 2
    583 <p>When first loaded, this should flash yellow for one second, then blue for one second, then yellow for one second, then blue forever.
    584 <png>
    585 IHDR => [W, H],
    586 acTL => [2, 2],
    587 IDAT => [create_surface(W, H, 'red')],
    588 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    589 fdAT => [1, create_surface(W, H, 'yellow')],
    590 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    591 fdAT => [3, create_surface(W, H, 'blue')],
    592 IEND => [],
    593 </png>
    594 </div>
    595 
    596 
    597 <h3>Other depths and colour types</h3>
    598 
    599 <div class="case">
    600 <p>16-bit colour.
    601 <p>This should be dark blue.
    602 <png>
    603 IHDR => [W, H, 16, 6],
    604 acTL => [2, 1],
    605 IDAT => [create_raw_surface(W, H, 64, "\xFF\x00\x00\x00\x00\x00\xFF\xFF" x (W*H))],
    606 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    607 fdAT => [1, create_raw_surface(W, H, 64, "\x00\x00\x00\x00\x00\x00\xFF\xFF" x (W*H))],
    608 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    609 fdAT => [3, create_raw_surface(W, H, 64, "\x00\x00\x00\x00\xFF\xFF\x80\x00" x (W*H))],
    610 IEND => [],
    611 </png>
    612 </div>
    613 
    614 <div class="case">
    615 <p>8-bit greyscale.
    616 <p>This should be a solid grey rectangle containing a solid white rectangle.
    617 <png>
    618 IHDR => [W, H, 8, 0],
    619 acTL => [2, 1],
    620 IDAT => [create_raw_surface(W, H, 8, "\x00\xFF" x (W*H/2))],
    621 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    622 fdAT => [1, create_raw_surface(W, H, 8, "\x80" x (W*H))],
    623 fcTL => [2, W/2, H/2, W/4, H/4, 100, 100, DISPOSE_NONE, BLEND_OVER],
    624 fdAT => [3, create_raw_surface(W/2, H/2, 8, "\xFF" x (W*H/4))],
    625 IEND => [],
    626 </png>
    627 </div>
    628 
    629 <div class="case">
    630 <p>8-bit greyscale and alpha, with blending.
    631 <p>This should be solid grey.
    632 <png>
    633 IHDR => [W, H, 8, 4],
    634 acTL => [2, 1],
    635 IDAT => [create_raw_surface(W, H, 16, "\x00\xFF\xFF\xFF" x (W*H/2))],
    636 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    637 fdAT => [1, create_raw_surface(W, H, 16, "\x00\xFF" x (W*H))],
    638 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    639 fdAT => [3, create_raw_surface(W, H, 16, "\xFF\x80" x (W*H))],
    640 IEND => [],
    641 </png>
    642 </div>
    643 
    644 <div class="case">
    645 <p>2-color palette.
    646 <p>This should be solid green.
    647 <png>
    648 IHDR => [W, H, 1, 3],
    649 PLTE => [255,0,0, 0,255,0],
    650 acTL => [2, 1],
    651 IDAT => [create_raw_surface(W, H, 1, "\x00" x (W*H/8))],
    652 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    653 fdAT => [1, create_raw_surface(W, H, 1, "\x00" x (W*H/8))],
    654 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    655 fdAT => [3, create_raw_surface(W, H, 1, "\xFF" x (W*H/8))],
    656 IEND => [],
    657 </png>
    658 </div>
    659 
    660 <div class="case">
    661 <p>2-bit palette and alpha.
    662 <p>This should be solid green.
    663 <png>
    664 IHDR => [W, H, 2, 3],
    665 PLTE => [255,0,0, 255,0,0, 0,255,0],
    666 tRNS => [255, 0, 255],
    667 acTL => [2, 1],
    668 IDAT => [create_raw_surface(W, H, 2, "\x00" x (W*H/4))],
    669 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    670 fdAT => [1, create_raw_surface(W, H, 2, "\xAA" x (W*H/4))],
    671 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    672 fdAT => [3, create_raw_surface(W, H, 2, "\x55" x (W*H/4))],
    673 IEND => [],
    674 </png>
    675 </div>
    676 
    677 <div class="case">
    678 <p>1-bit palette and alpha, with blending.
    679 <p>This should be solid dark blue.
    680 <png>
    681 IHDR => [W, H, 1, 3],
    682 PLTE => [0,0,0, 0,0,255],
    683 tRNS => [255, 128],
    684 acTL => [2, 1],
    685 IDAT => [create_raw_surface(W, H, 1, "\x00" x (W*H/8))],
    686 fcTL => [0, W, H, 0, 0, 10, 100, DISPOSE_NONE, BLEND_OVER],
    687 fdAT => [1, create_raw_surface(W, H, 1, "\x00" x (W*H/8))],
    688 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    689 fdAT => [3, create_raw_surface(W, H, 1, "\xFF" x (W*H/8))],
    690 IEND => [],
    691 </png>
    692 </div>
    693 
    694 
    695 <h2>Invalid images</h2>
    696 
    697 <blockquote cite="#apng">
    698 <p>It is strongly recommended that when any error is encountered decoders should discard all subsequent frames, stop the animation, and revert to displaying the default image. A decoder which detects an error before the animation has started should display the default image. An error message may be displayed to the user if appropriate.
    699 </blockquote>
    700 <p>(If some decoders accept broken images, it seems quite possible that people will create and distribute broken images, and then the error-handling would have to be reverse-engineered by other implementations; hence all these tests to ensure errors get detected properly.)
    701 <p>For the following images, the default image (solid green) or an error should be displayed.
    702 
    703 
    704 <h3>Incorrect chunks</h3>
    705 
    706 <div class="case">
    707 <p>Missing acTL.
    708 <png>
    709 IHDR => [W, H],
    710 IDAT => [create_surface(W, H, 'green')],
    711 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    712 fdAT => [1, create_surface(W, H, 'red')],
    713 IEND => [],
    714 </png>
    715 </div>
    716 
    717 <div class="case">
    718 <p>Repeated acTL.
    719 <png>
    720 IHDR => [W, H],
    721 acTL => [1, 0],
    722 acTL => [1, 0],
    723 IDAT => [create_surface(W, H, 'green')],
    724 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    725 fdAT => [1, create_surface(W, H, 'red')],
    726 IEND => [],
    727 </png>
    728 </div>
    729 
    730 <div class="case">
    731 <p>acTL after IDAT.
    732 <png>
    733 IHDR => [W, H],
    734 IDAT => [create_surface(W, H, 'green')],
    735 acTL => [1, 0],
    736 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    737 fdAT => [1, create_surface(W, H, 'red')],
    738 IEND => [],
    739 </png>
    740 </div>
    741 
    742 <div class="case">
    743 <p>Missing fcTL.
    744 <p><em>Disabled for now, since it crashes Opera 9.5 alpha 1589 (bug 287173).</em>
    745 <!--
    746 <png>
    747 IHDR => [W, H],
    748 acTL => [1, 0],
    749 IDAT => [create_surface(W, H, 'green')],
    750 fdAT => [0, create_surface(W, H, 'red')],
    751 IEND => [],
    752 </png>
    753 -->
    754 </div>
    755 
    756 <div class="case">
    757 <p>Repeated fcTL.
    758 <png>
    759 IHDR => [W, H],
    760 acTL => [1, 0],
    761 IDAT => [create_surface(W, H, 'green')],
    762 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    763 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    764 fdAT => [1, create_surface(W, H, 'red')],
    765 IEND => [],
    766 </png>
    767 </div>
    768 
    769 <div class="case">
    770 <p>Missing fdAT.
    771 <png>
    772 IHDR => [W, H],
    773 acTL => [2, 0],
    774 IDAT => [create_surface(W, H, 'green')],
    775 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    776 fcTL => [1, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    777 fdAT => [2, create_surface(W, H, 'red')],
    778 IEND => [],
    779 </png>
    780 </div>
    781 
    782 
    783 <h3>num_frames</h3>
    784 
    785 <div class="case">
    786 <p>num_frames = 0; no default image.
    787 <blockquote cite="#apng"><p>0 is not a valid value.</blockquote>
    788 <png>
    789 IHDR => [W, H],
    790 acTL => [0, 0],
    791 IEND => [],
    792 </png>
    793 </div>
    794 
    795 <div class="case">
    796 <p>num_frames = 0; ignoring default image.
    797 <blockquote cite="#apng"><p>0 is not a valid value.</blockquote>
    798 <png>
    799 IHDR => [W, H],
    800 acTL => [0, 0],
    801 IDAT => [create_surface(W, H, 'green')],
    802 IEND => [],
    803 </png>
    804 </div>
    805 
    806 <div class="case">
    807 <p>num_frames too low.
    808 <blockquote cite="#apng"><p>This must equal the number of `fcTL` chunks. ... If this value does not equal the actual number of frames it should be treated as an error.</blockquote>
    809 <png>
    810 IHDR => [W, H],
    811 acTL => [1, 0],
    812 IDAT => [create_surface(W, H, 'green')],
    813 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    814 fdAT => [1, create_surface(W, H, 'red')],
    815 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    816 fdAT => [3, create_surface(W, H, 'red')],
    817 IEND => [],
    818 </png>
    819 </div>
    820 
    821 <div class="case">
    822 <p>num_frames too high by 1.
    823 <blockquote cite="#apng"><p>This must equal the number of `fcTL` chunks. ... If this value does not equal the actual number of frames it should be treated as an error.</blockquote>
    824 <png>
    825 IHDR => [W, H],
    826 acTL => [3, 0],
    827 IDAT => [create_surface(W, H, 'green')],
    828 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    829 fdAT => [1, create_surface(W, H, 'red')],
    830 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    831 fdAT => [3, create_surface(W, H, 'red')],
    832 IEND => [],
    833 </png>
    834 </div>
    835 
    836 <div class="case">
    837 <p>num_frames too high by 2.
    838 <blockquote cite="#apng"><p>This must equal the number of `fcTL` chunks. ... If this value does not equal the actual number of frames it should be treated as an error.</blockquote>
    839 <png>
    840 IHDR => [W, H],
    841 acTL => [4, 0],
    842 IDAT => [create_surface(W, H, 'green')],
    843 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    844 fdAT => [1, create_surface(W, H, 'red')],
    845 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    846 fdAT => [3, create_surface(W, H, 'red')],
    847 IEND => [],
    848 </png>
    849 </div>
    850 
    851 <div class="case">
    852 <p>num_frames outside valid range.
    853 <blockquote cite="#apng"><p>an "unsigned int" shall be a 32-bit unsigned integer in network byte order limited to the range 0 to (2^31)-1</blockquote>
    854 <png>
    855 IHDR => [W, H],
    856 acTL => [0x80000001, 0],
    857 IDAT => [create_surface(W, H, 'green')],
    858 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    859 fdAT => [1, create_surface(W, H, 'red')],
    860 IEND => [],
    861 </png>
    862 </div>
    863 
    864 
    865 <h3>Sequence numbers</h3>
    866 
    867 <div class="case">
    868 <p>Not starting from 0.
    869 <png>
    870 IHDR => [W, H],
    871 acTL => [2, 0],
    872 IDAT => [create_surface(W, H, 'green')],
    873 fcTL => [1, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    874 fdAT => [2, create_surface(W, H, 'red')],
    875 fcTL => [3, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    876 fdAT => [4, create_surface(W, H, 'red')],
    877 IEND => [],
    878 </png>
    879 </div>
    880 
    881 <div class="case">
    882 <p>Gap in sequence.
    883 <png>
    884 IHDR => [W, H],
    885 acTL => [2, 0],
    886 IDAT => [create_surface(W, H, 'green')],
    887 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    888 fdAT => [1, create_surface(W, H, 'red')],
    889 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    890 fdAT => [4, create_surface(W, H, 'red')],
    891 IEND => [],
    892 </png>
    893 </div>
    894 
    895 <div class="case">
    896 <p>Duplicated sequence number.
    897 <png>
    898 IHDR => [W, H],
    899 acTL => [2, 0],
    900 IDAT => [create_surface(W, H, 'green')],
    901 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    902 fdAT => [1, create_surface(W, H, 'red')],
    903 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    904 fdAT => [2, create_surface(W, H, 'red')],
    905 IEND => [],
    906 </png>
    907 </div>
    908 
    909 <div class="case">
    910 <p>Duplicated chunk.
    911 <png>
    912 IHDR => [W, H],
    913 acTL => [2, 0],
    914 IDAT => [create_surface(W, H, 'green')],
    915 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    916 fdAT => [1, create_surface(W, H, 'red')],
    917 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    918 fdAT => [3, create_surface(W, H, 'red')],
    919 fdAT => [3, create_surface(W, H, 'red')],
    920 IEND => [],
    921 </png>
    922 </div>
    923 
    924 <div class="case">
    925 <p>Reordered fdAT chunks.
    926 <png>
    927 IHDR => [W, H],
    928 acTL => [2, 0],
    929 IDAT => [create_surface(W, H, 'green')],
    930 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    931 fdAT => [1, create_surface(W, H, 'red')],
    932 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    933 fdAT_split => [4, 32,-1, create_surface(W, H, 'red')],
    934 fdAT_split => [3, 0,32, create_surface(W, H, 'red')],
    935 IEND => [],
    936 </png>
    937 </div>
    938 
    939 <div class="case">
    940 <p>Reordered sequence numbers.
    941 <png>
    942 IHDR => [W, H],
    943 acTL => [2, 0],
    944 IDAT => [create_surface(W, H, 'green')],
    945 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    946 fdAT => [1, create_surface(W, H, 'red')],
    947 fcTL => [2, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    948 fdAT_split => [4, 0,32, create_surface(W, H, 'red')],
    949 fdAT_split => [3, 32,-1, create_surface(W, H, 'red')],
    950 IEND => [],
    951 </png>
    952 </div>
    953 
    954 <div class="case">
    955 <p>Separated fdAT and fcTL sequences.
    956 <png>
    957 IHDR => [W, H],
    958 acTL => [2, 0],
    959 IDAT => [create_surface(W, H, 'green')],
    960 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    961 fdAT => [0, create_surface(W, H, 'red')],
    962 fcTL => [1, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    963 fdAT => [1, create_surface(W, H, 'red')],
    964 IEND => [],
    965 </png>
    966 </div>
    967 
    968 
    969 <h3>Invalid image-data sizes</h3>
    970 
    971 <div class="case">
    972 <p>Default image's fcTL size not matching IHDR.
    973 <png>
    974 IHDR => [W, H],
    975 acTL => [2, 0],
    976 fcTL => [0, W, H/2, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    977 IDAT => [create_surface(W, H/2, 'red')],
    978 fcTL => [1, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    979 fdAT => [2, create_surface(W, H, 'red')],
    980 IEND => [],
    981 </png>
    982 </div>
    983 
    984 <div class="case">
    985 <p>fdAT too small.
    986 <png>
    987 IHDR => [W, H],
    988 acTL => [1, 0],
    989 IDAT => [create_surface(W, H, 'green')],
    990 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
    991 fdAT => [1, create_surface(W, H/2, 'red')],
    992 IEND => [],
    993 </png>
    994 </div>
    995 
    996 <div class="case">
    997 <p>fdAT too large.
    998 <png>
    999 IHDR => [W, H],
   1000 acTL => [1, 0],
   1001 IDAT => [create_surface(W, H, 'green')],
   1002 fcTL => [0, W, H, 0, 0, 100, 100, DISPOSE_NONE, BLEND_OVER],
   1003 fdAT => [1, create_surface(W, H*2, 'red')],
   1004 IEND => [],
   1005 </png>
   1006 </div>
   1007 
   1008 <!-- TODO: invalid fcTL (negative offset, etc) -->
   1009 
   1010 <h2>References</h2>
   1011 <ul>
   1012 <li id="apng"><a href="http://wiki.mozilla.org/index.php?title=APNG_Specification&amp;oldid=64503">APNG Specification 1.0</a>
   1013 <li id="png"><a href="http://www.w3.org/TR/PNG/">PNG Specification (Second Edition)</a>
   1014 </ul>