tor-browser

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

test_encoder_png.js (7127B)


      1 /*
      2 * Test for PNG encoding in ImageLib
      3 *
      4 */
      5 
      6 const { AppConstants } = ChromeUtils.importESModule(
      7  "resource://gre/modules/AppConstants.sys.mjs"
      8 );
      9 
     10 var png1A = {
     11  // A 3x3 image, rows are red, green, blue.
     12  // RGB format, transparency defaults.
     13 
     14  transparency: null,
     15 
     16  frames: [
     17    {
     18      width: 3,
     19      height: 3,
     20 
     21      format: Ci.imgIEncoder.INPUT_FORMAT_RGB,
     22      stride: 9,
     23 
     24      pixels: [
     25        255, 0, 0, 255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 0,
     26        255, 0, 0, 255, 0, 0, 255,
     27      ],
     28    },
     29  ],
     30  expected:
     31    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAFElEQVQIW2P8zwAFjAwwJiMDjAkANiQDAUpvlioAAAAASUVORK5CYII=",
     32 };
     33 
     34 var png1B = {
     35  // A 3x3 image, rows are red, green, blue.
     36  // RGB format, transparency=none.
     37 
     38  transparency: "none",
     39 
     40  frames: [
     41    {
     42      width: 3,
     43      height: 3,
     44 
     45      format: Ci.imgIEncoder.INPUT_FORMAT_RGB,
     46      stride: 9,
     47 
     48      pixels: [
     49        255, 0, 0, 255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 0,
     50        255, 0, 0, 255, 0, 0, 255,
     51      ],
     52    },
     53  ],
     54  expected:
     55    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAFElEQVQIW2P8zwAFjAwwJiMDjAkANiQDAUpvlioAAAAASUVORK5CYII=",
     56 };
     57 
     58 var png2A = {
     59  // A 3x3 image, rows are: red, green, blue. Columns are: 0%, 33%, 66% transparent.
     60 
     61  transparency: null,
     62 
     63  frames: [
     64    {
     65      width: 3,
     66      height: 3,
     67 
     68      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
     69      stride: 12,
     70 
     71      pixels: [
     72        255, 0, 0, 255, 255, 0, 0, 170, 255, 0, 0, 85, 0, 255, 0, 255, 0, 255,
     73        0, 170, 0, 255, 0, 85, 0, 0, 255, 255, 0, 0, 255, 170, 0, 0, 255, 85,
     74      ],
     75    },
     76  ],
     77  expected: AppConstants.USE_LIBZ_RS
     78    ? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAAG0lEQVQIW2P8z8Dwn4GBYTUIMzL8R+Yw/IdzAMoLCgDGywYPAAAAAElFTkSuQmCC"
     79    : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAAGUlEQVQIW2P8z8AARAyrQZgRyETiMPyHcwDKCwoAGxxLEQAAAABJRU5ErkJggg==",
     80 };
     81 
     82 var png2B = {
     83  // A 3x3 image, rows are: red, green, blue. Columns are: 0%, 33%, 66% transparent,
     84  // but transparency will be ignored.
     85 
     86  transparency: "none",
     87 
     88  frames: [
     89    {
     90      width: 3,
     91      height: 3,
     92 
     93      format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
     94      stride: 12,
     95 
     96      pixels: [
     97        255, 0, 0, 255, 255, 0, 0, 170, 255, 0, 0, 85, 0, 255, 0, 255, 0, 255,
     98        0, 170, 0, 255, 0, 85, 0, 0, 255, 255, 0, 0, 255, 170, 0, 0, 255, 85,
     99      ],
    100    },
    101  ],
    102  expected:
    103    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAFElEQVQIW2P8zwAFjAwwJiMDjAkANiQDAUpvlioAAAAASUVORK5CYII=",
    104 };
    105 
    106 // Main test entry point.
    107 function run_test() {
    108  dump("Checking png1A...\n");
    109  run_test_for(png1A);
    110  dump("Checking png1B...\n");
    111  run_test_for(png1B);
    112  dump("Checking png2A...\n");
    113  run_test_for(png2A);
    114  dump("Checking png2B...\n");
    115  run_test_for(png2B);
    116 }
    117 
    118 function run_test_for(input) {
    119  var encoder, dataURL;
    120 
    121  encoder = encodeImage(input);
    122  dataURL = makeDataURL(encoder, "image/png");
    123  Assert.equal(dataURL, input.expected);
    124 
    125  encoder = encodeImageAsync(input);
    126  dataURL = makeDataURLFromAsync(encoder, "image/png", input.expected);
    127 }
    128 
    129 function encodeImage(input) {
    130  var encoder =
    131    Cc["@mozilla.org/image/encoder;2?type=image/png"].createInstance();
    132  encoder.QueryInterface(Ci.imgIEncoder);
    133 
    134  var options = "";
    135  if (input.transparency) {
    136    options += "transparency=" + input.transparency;
    137  }
    138 
    139  var frame = input.frames[0];
    140  encoder.initFromData(
    141    frame.pixels,
    142    frame.pixels.length,
    143    frame.width,
    144    frame.height,
    145    frame.stride,
    146    frame.format,
    147    options,
    148    null
    149  );
    150  return encoder;
    151 }
    152 
    153 function _encodeImageAsyncFactory(frame, options, encoder) {
    154  function finishEncode() {
    155    encoder.addImageFrame(
    156      frame.pixels,
    157      frame.pixels.length,
    158      frame.width,
    159      frame.height,
    160      frame.stride,
    161      frame.format,
    162      options
    163    );
    164    encoder.endImageEncode();
    165  }
    166  return finishEncode;
    167 }
    168 
    169 function encodeImageAsync(input) {
    170  var encoder =
    171    Cc["@mozilla.org/image/encoder;2?type=image/png"].createInstance();
    172  encoder.QueryInterface(Ci.imgIEncoder);
    173 
    174  var options = "";
    175  if (input.transparency) {
    176    options += "transparency=" + input.transparency;
    177  }
    178 
    179  var frame = input.frames[0];
    180  encoder.startImageEncode(frame.width, frame.height, frame.format, options);
    181 
    182  do_timeout(50, _encodeImageAsyncFactory(frame, options, encoder));
    183  return encoder;
    184 }
    185 
    186 function makeDataURL(encoder, mimetype) {
    187  var rawStream = encoder.QueryInterface(Ci.nsIInputStream);
    188 
    189  var stream = Cc["@mozilla.org/binaryinputstream;1"].createInstance();
    190  stream.QueryInterface(Ci.nsIBinaryInputStream);
    191 
    192  stream.setInputStream(rawStream);
    193 
    194  var bytes = stream.readByteArray(stream.available()); // returns int[]
    195 
    196  var base64String = toBase64(bytes);
    197 
    198  return "data:" + mimetype + ";base64," + base64String;
    199 }
    200 
    201 function makeDataURLFromAsync(encoder, mimetype, expected) {
    202  do_test_pending();
    203  var rawStream = encoder.QueryInterface(Ci.nsIAsyncInputStream);
    204 
    205  var currentThread =
    206    Cc["@mozilla.org/thread-manager;1"].getService().currentThread;
    207 
    208  var bytes = [];
    209 
    210  var binarystream = Cc["@mozilla.org/binaryinputstream;1"].createInstance();
    211  binarystream.QueryInterface(Ci.nsIBinaryInputStream);
    212 
    213  var asyncReader = {
    214    onInputStreamReady(stream) {
    215      binarystream.setInputStream(stream);
    216      var available = 0;
    217      try {
    218        available = stream.available();
    219      } catch (e) {}
    220 
    221      if (available > 0) {
    222        bytes = bytes.concat(binarystream.readByteArray(available));
    223        stream.asyncWait(this, 0, 0, currentThread);
    224      } else {
    225        var base64String = toBase64(bytes);
    226        var dataURL = "data:" + mimetype + ";base64," + base64String;
    227        Assert.equal(dataURL, expected);
    228        do_test_finished();
    229      }
    230    },
    231  };
    232  rawStream.asyncWait(asyncReader, 0, 0, currentThread);
    233 }
    234 
    235 /* toBase64 copied from extensions/xml-rpc/src/nsXmlRpcClient.js */
    236 
    237 /* Convert data (an array of integers) to a Base64 string. */
    238 const toBase64Table =
    239  // eslint-disable-next-line no-useless-concat
    240  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789+/";
    241 const base64Pad = "=";
    242 function toBase64(data) {
    243  var result = "";
    244  var length = data.length;
    245  var i;
    246  // Convert every three bytes to 4 ascii characters.
    247  for (i = 0; i < length - 2; i += 3) {
    248    result += toBase64Table[data[i] >> 2];
    249    result += toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
    250    result += toBase64Table[((data[i + 1] & 0x0f) << 2) + (data[i + 2] >> 6)];
    251    result += toBase64Table[data[i + 2] & 0x3f];
    252  }
    253 
    254  // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
    255  if (length % 3) {
    256    i = length - (length % 3);
    257    result += toBase64Table[data[i] >> 2];
    258    if (length % 3 == 2) {
    259      result += toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
    260      result += toBase64Table[(data[i + 1] & 0x0f) << 2];
    261      result += base64Pad;
    262    } else {
    263      result += toBase64Table[(data[i] & 0x03) << 4];
    264      result += base64Pad + base64Pad;
    265    }
    266  }
    267 
    268  return result;
    269 }