tor-browser

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

test_utils-inl.h (15547B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 // This template file is included in both the libjpeg_test_util.cc and the
      7 // test_utils.cc files with different JPEG_API_FN macros and possibly different
      8 // include paths for the jpeg headers.
      9 
     10 // Sequential non-interleaved.
     11 constexpr jpeg_scan_info kScript1[] = {
     12    {1, {0}, 0, 63, 0, 0},
     13    {1, {1}, 0, 63, 0, 0},
     14    {1, {2}, 0, 63, 0, 0},
     15 };
     16 // Sequential partially interleaved, chroma first.
     17 constexpr jpeg_scan_info kScript2[] = {
     18    {2, {1, 2}, 0, 63, 0, 0},
     19    {1, {0}, 0, 63, 0, 0},
     20 };
     21 
     22 // Rest of the scan scripts are progressive.
     23 
     24 constexpr jpeg_scan_info kScript3[] = {
     25    // Interleaved full DC.
     26    {3, {0, 1, 2}, 0, 0, 0, 0},
     27    // Full AC scans.
     28    {1, {0}, 1, 63, 0, 0},
     29    {1, {1}, 1, 63, 0, 0},
     30    {1, {2}, 1, 63, 0, 0},
     31 };
     32 constexpr jpeg_scan_info kScript4[] = {
     33    // Non-interleaved full DC.
     34    {1, {0}, 0, 0, 0, 0},
     35    {1, {1}, 0, 0, 0, 0},
     36    {1, {2}, 0, 0, 0, 0},
     37    // Full AC scans.
     38    {1, {0}, 1, 63, 0, 0},
     39    {1, {1}, 1, 63, 0, 0},
     40    {1, {2}, 1, 63, 0, 0},
     41 };
     42 constexpr jpeg_scan_info kScript5[] = {
     43    // Partially interleaved full DC, chroma first.
     44    {2, {1, 2}, 0, 0, 0, 0},
     45    {1, {0}, 0, 0, 0, 0},
     46    // AC shifted by 1 bit.
     47    {1, {0}, 1, 63, 0, 1},
     48    {1, {1}, 1, 63, 0, 1},
     49    {1, {2}, 1, 63, 0, 1},
     50    // AC refinement scan.
     51    {1, {0}, 1, 63, 1, 0},
     52    {1, {1}, 1, 63, 1, 0},
     53    {1, {2}, 1, 63, 1, 0},
     54 };
     55 constexpr jpeg_scan_info kScript6[] = {
     56    // Interleaved DC shifted by 2 bits.
     57    {3, {0, 1, 2}, 0, 0, 0, 2},
     58    // Interleaved DC refinement scans.
     59    {3, {0, 1, 2}, 0, 0, 2, 1},
     60    {3, {0, 1, 2}, 0, 0, 1, 0},
     61    // Full AC scans.
     62    {1, {0}, 1, 63, 0, 0},
     63    {1, {1}, 1, 63, 0, 0},
     64    {1, {2}, 1, 63, 0, 0},
     65 };
     66 
     67 constexpr jpeg_scan_info kScript7[] = {
     68    // Non-interleaved DC shifted by 2 bits.
     69    {1, {0}, 0, 0, 0, 2},
     70    {1, {1}, 0, 0, 0, 2},
     71    {1, {2}, 0, 0, 0, 2},
     72    // Non-interleaved DC first refinement scans.
     73    {1, {0}, 0, 0, 2, 1},
     74    {1, {1}, 0, 0, 2, 1},
     75    {1, {2}, 0, 0, 2, 1},
     76    // Non-interleaved DC second refinement scans.
     77    {1, {0}, 0, 0, 1, 0},
     78    {1, {1}, 0, 0, 1, 0},
     79    {1, {2}, 0, 0, 1, 0},
     80    // Full AC scans.
     81    {1, {0}, 1, 63, 0, 0},
     82    {1, {1}, 1, 63, 0, 0},
     83    {1, {2}, 1, 63, 0, 0},
     84 };
     85 
     86 constexpr jpeg_scan_info kScript8[] = {
     87    // Partially interleaved DC shifted by 2 bits, chroma first
     88    {2, {1, 2}, 0, 0, 0, 2},
     89    {1, {0}, 0, 0, 0, 2},
     90    // Partially interleaved DC first refinement scans.
     91    {2, {0, 2}, 0, 0, 2, 1},
     92    {1, {1}, 0, 0, 2, 1},
     93    // Partially interleaved DC first refinement scans, chroma first.
     94    {2, {1, 2}, 0, 0, 1, 0},
     95    {1, {0}, 0, 0, 1, 0},
     96    // Full AC scans.
     97    {1, {0}, 1, 63, 0, 0},
     98    {1, {1}, 1, 63, 0, 0},
     99    {1, {2}, 1, 63, 0, 0},
    100 };
    101 
    102 constexpr jpeg_scan_info kScript9[] = {
    103    // Interleaved full DC.
    104    {3, {0, 1, 2}, 0, 0, 0, 0},
    105    // AC scans for component 0
    106    // shifted by 1 bit, two spectral ranges
    107    {1, {0}, 1, 6, 0, 1},
    108    {1, {0}, 7, 63, 0, 1},
    109    // refinement scan, full
    110    {1, {0}, 1, 63, 1, 0},
    111    // AC scans for component 1
    112    // shifted by 1 bit, full
    113    {1, {1}, 1, 63, 0, 1},
    114    // refinement scan, two spectral ranges
    115    {1, {1}, 1, 6, 1, 0},
    116    {1, {1}, 7, 63, 1, 0},
    117    // AC scans for component 2
    118    // shifted by 1 bit, two spectral ranges
    119    {1, {2}, 1, 6, 0, 1},
    120    {1, {2}, 7, 63, 0, 1},
    121    // refinement scan, two spectral ranges (but different from above)
    122    {1, {2}, 1, 16, 1, 0},
    123    {1, {2}, 17, 63, 1, 0},
    124 };
    125 
    126 constexpr jpeg_scan_info kScript10[] = {
    127    // Interleaved full DC.
    128    {3, {0, 1, 2}, 0, 0, 0, 0},
    129    // AC scans for spectral range 1..16
    130    // shifted by 1
    131    {1, {0}, 1, 16, 0, 1},
    132    {1, {1}, 1, 16, 0, 1},
    133    {1, {2}, 1, 16, 0, 1},
    134    // refinement scans, two sub-ranges
    135    {1, {0}, 1, 8, 1, 0},
    136    {1, {0}, 9, 16, 1, 0},
    137    {1, {1}, 1, 8, 1, 0},
    138    {1, {1}, 9, 16, 1, 0},
    139    {1, {2}, 1, 8, 1, 0},
    140    {1, {2}, 9, 16, 1, 0},
    141    // AC scans for spectral range 17..63
    142    {1, {0}, 17, 63, 0, 1},
    143    {1, {1}, 17, 63, 0, 1},
    144    {1, {2}, 17, 63, 0, 1},
    145    // refinement scans, two sub-ranges
    146    {1, {0}, 17, 28, 1, 0},
    147    {1, {0}, 29, 63, 1, 0},
    148    {1, {1}, 17, 28, 1, 0},
    149    {1, {1}, 29, 63, 1, 0},
    150    {1, {2}, 17, 28, 1, 0},
    151    {1, {2}, 29, 63, 1, 0},
    152 };
    153 
    154 struct ScanScript {
    155  int num_scans;
    156  const jpeg_scan_info* scans;
    157 };
    158 
    159 constexpr ScanScript kTestScript[] = {
    160    {ARRAY_SIZE(kScript1), kScript1}, {ARRAY_SIZE(kScript2), kScript2},
    161    {ARRAY_SIZE(kScript3), kScript3}, {ARRAY_SIZE(kScript4), kScript4},
    162    {ARRAY_SIZE(kScript5), kScript5}, {ARRAY_SIZE(kScript6), kScript6},
    163    {ARRAY_SIZE(kScript7), kScript7}, {ARRAY_SIZE(kScript8), kScript8},
    164    {ARRAY_SIZE(kScript9), kScript9}, {ARRAY_SIZE(kScript10), kScript10},
    165 };
    166 constexpr int kNumTestScripts = ARRAY_SIZE(kTestScript);
    167 
    168 void SetScanDecompressParams(const DecompressParams& dparams,
    169                             j_decompress_ptr cinfo, int scan_number) {
    170  const ScanDecompressParams* sparams = nullptr;
    171  for (const auto& sp : dparams.scan_params) {
    172    if (scan_number <= sp.max_scan_number) {
    173      sparams = &sp;
    174      break;
    175    }
    176  }
    177  if (sparams == nullptr) {
    178    return;
    179  }
    180  if (dparams.quantize_colors) {
    181    cinfo->dither_mode = static_cast<J_DITHER_MODE>(sparams->dither_mode);
    182    if (sparams->color_quant_mode == CQUANT_1PASS) {
    183      cinfo->two_pass_quantize = FALSE;
    184      cinfo->colormap = nullptr;
    185    } else if (sparams->color_quant_mode == CQUANT_2PASS) {
    186      Check(cinfo->out_color_space == JCS_RGB);
    187      cinfo->two_pass_quantize = TRUE;
    188      cinfo->colormap = nullptr;
    189    } else if (sparams->color_quant_mode == CQUANT_EXTERNAL) {
    190      Check(cinfo->out_color_space == JCS_RGB);
    191      cinfo->two_pass_quantize = FALSE;
    192      bool have_colormap = cinfo->colormap != nullptr;
    193      cinfo->actual_number_of_colors = kTestColorMapNumColors;
    194      cinfo->colormap = (*cinfo->mem->alloc_sarray)(
    195          reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE,
    196          cinfo->actual_number_of_colors, 3);
    197      jxl::msan::UnpoisonMemory(reinterpret_cast<void*>(cinfo->colormap),
    198                                3 * sizeof(JSAMPLE*));
    199      for (int i = 0; i < kTestColorMapNumColors; ++i) {
    200        cinfo->colormap[0][i] = (kTestColorMap[i] >> 16) & 0xff;
    201        cinfo->colormap[1][i] = (kTestColorMap[i] >> 8) & 0xff;
    202        cinfo->colormap[2][i] = (kTestColorMap[i] >> 0) & 0xff;
    203      }
    204      if (have_colormap) {
    205        JPEG_API_FN(new_colormap)(cinfo);
    206      }
    207    } else if (sparams->color_quant_mode == CQUANT_REUSE) {
    208      Check(cinfo->out_color_space == JCS_RGB);
    209      Check(cinfo->colormap);
    210    }
    211  }
    212 }
    213 
    214 void SetDecompressParams(const DecompressParams& dparams,
    215                         j_decompress_ptr cinfo) {
    216  cinfo->do_block_smoothing = dparams.do_block_smoothing ? 1 : 0;
    217  cinfo->do_fancy_upsampling = dparams.do_fancy_upsampling ? 1 : 0;
    218  if (dparams.output_mode == RAW_DATA) {
    219    cinfo->raw_data_out = TRUE;
    220  }
    221  if (dparams.set_out_color_space) {
    222    cinfo->out_color_space =
    223        static_cast<J_COLOR_SPACE>(dparams.out_color_space);
    224    if (dparams.out_color_space == JCS_UNKNOWN) {
    225      cinfo->jpeg_color_space = JCS_UNKNOWN;
    226    }
    227  }
    228  cinfo->scale_num = dparams.scale_num;
    229  cinfo->scale_denom = dparams.scale_denom;
    230  cinfo->quantize_colors = dparams.quantize_colors ? 1 : 0;
    231  cinfo->desired_number_of_colors = dparams.desired_number_of_colors;
    232  if (!dparams.scan_params.empty()) {
    233    if (cinfo->buffered_image) {
    234      for (const auto& sparams : dparams.scan_params) {
    235        if (sparams.color_quant_mode == CQUANT_1PASS) {
    236          cinfo->enable_1pass_quant = TRUE;
    237        } else if (sparams.color_quant_mode == CQUANT_2PASS) {
    238          cinfo->enable_2pass_quant = TRUE;
    239        } else if (sparams.color_quant_mode == CQUANT_EXTERNAL) {
    240          cinfo->enable_external_quant = TRUE;
    241        }
    242      }
    243      SetScanDecompressParams(dparams, cinfo, 1);
    244    } else {
    245      SetScanDecompressParams(dparams, cinfo, kLastScan);
    246    }
    247  }
    248 }
    249 
    250 void CheckMarkerPresent(j_decompress_ptr cinfo, uint8_t marker_type) {
    251  bool marker_found = false;
    252  for (jpeg_saved_marker_ptr marker = cinfo->marker_list; marker != nullptr;
    253       marker = marker->next) {
    254    jxl::msan::UnpoisonMemory(marker, sizeof(*marker));
    255    jxl::msan::UnpoisonMemory(marker->data, marker->data_length);
    256    if (marker->marker == marker_type &&
    257        marker->data_length == sizeof(kMarkerData) &&
    258        memcmp(marker->data, kMarkerData, sizeof(kMarkerData)) == 0) {
    259      marker_found = true;
    260    }
    261  }
    262  Check(marker_found);
    263 }
    264 
    265 void VerifyHeader(const CompressParams& jparams, j_decompress_ptr cinfo) {
    266  if (jparams.set_jpeg_colorspace) {
    267    Check(cinfo->jpeg_color_space == jparams.jpeg_color_space);
    268  }
    269  if (jparams.override_JFIF >= 0) {
    270    Check(cinfo->saw_JFIF_marker == jparams.override_JFIF);
    271  }
    272  if (jparams.override_Adobe >= 0) {
    273    Check(cinfo->saw_Adobe_marker == jparams.override_Adobe);
    274  }
    275  if (jparams.add_marker) {
    276    CheckMarkerPresent(cinfo, kSpecialMarker0);
    277    CheckMarkerPresent(cinfo, kSpecialMarker1);
    278  }
    279  jxl::msan::UnpoisonMemory(
    280      cinfo->comp_info, cinfo->num_components * sizeof(cinfo->comp_info[0]));
    281  int max_h_samp_factor = 1;
    282  int max_v_samp_factor = 1;
    283  for (int i = 0; i < cinfo->num_components; ++i) {
    284    jpeg_component_info* comp = &cinfo->comp_info[i];
    285    if (!jparams.comp_ids.empty()) {
    286      Check(comp->component_id == jparams.comp_ids[i]);
    287    }
    288    if (!jparams.h_sampling.empty()) {
    289      Check(comp->h_samp_factor == jparams.h_sampling[i]);
    290    }
    291    if (!jparams.v_sampling.empty()) {
    292      Check(comp->v_samp_factor == jparams.v_sampling[i]);
    293    }
    294    if (!jparams.quant_indexes.empty()) {
    295      Check(comp->quant_tbl_no == jparams.quant_indexes[i]);
    296    }
    297    max_h_samp_factor = std::max(max_h_samp_factor, comp->h_samp_factor);
    298    max_v_samp_factor = std::max(max_v_samp_factor, comp->v_samp_factor);
    299  }
    300  Check(max_h_samp_factor == cinfo->max_h_samp_factor);
    301  Check(max_v_samp_factor == cinfo->max_v_samp_factor);
    302  int referenced_tables[NUM_QUANT_TBLS] = {};
    303  for (int i = 0; i < cinfo->num_components; ++i) {
    304    jpeg_component_info* comp = &cinfo->comp_info[i];
    305    Check(comp->width_in_blocks ==
    306          DivCeil(cinfo->image_width * comp->h_samp_factor,
    307                  max_h_samp_factor * DCTSIZE));
    308    Check(comp->height_in_blocks ==
    309          DivCeil(cinfo->image_height * comp->v_samp_factor,
    310                  max_v_samp_factor * DCTSIZE));
    311    referenced_tables[comp->quant_tbl_no] = 1;
    312  }
    313  for (const auto& table : jparams.quant_tables) {
    314    JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[table.slot_idx];
    315    if (!referenced_tables[table.slot_idx]) {
    316      Check(quant_table == nullptr);
    317      continue;
    318    }
    319    Check(quant_table != nullptr);
    320    jxl::msan::UnpoisonMemory(quant_table, sizeof(*quant_table));
    321    for (int k = 0; k < DCTSIZE2; ++k) {
    322      Check(quant_table->quantval[k] == table.quantval[k]);
    323    }
    324  }
    325 }
    326 
    327 void VerifyScanHeader(const CompressParams& jparams, j_decompress_ptr cinfo) {
    328  Check(cinfo->input_scan_number > 0);
    329  if (cinfo->progressive_mode) {
    330    Check(cinfo->Ss != 0 || cinfo->Se != 63);
    331  } else {
    332    Check(cinfo->Ss == 0 && cinfo->Se == 63);
    333  }
    334  if (jparams.progressive_mode > 2) {
    335    Check(jparams.progressive_mode < 3 + kNumTestScripts);
    336    const ScanScript& script = kTestScript[jparams.progressive_mode - 3];
    337    Check(cinfo->input_scan_number <= script.num_scans);
    338    const jpeg_scan_info& scan = script.scans[cinfo->input_scan_number - 1];
    339    Check(cinfo->comps_in_scan == scan.comps_in_scan);
    340    for (int i = 0; i < cinfo->comps_in_scan; ++i) {
    341      Check(cinfo->cur_comp_info[i]->component_index ==
    342            scan.component_index[i]);
    343    }
    344    Check(cinfo->Ss == scan.Ss);
    345    Check(cinfo->Se == scan.Se);
    346    Check(cinfo->Ah == scan.Ah);
    347    Check(cinfo->Al == scan.Al);
    348  }
    349  if (jparams.restart_interval > 0) {
    350    Check(cinfo->restart_interval == jparams.restart_interval);
    351  } else if (jparams.restart_in_rows > 0) {
    352    Check(cinfo->restart_interval ==
    353          jparams.restart_in_rows * cinfo->MCUs_per_row);
    354  }
    355  if (jparams.progressive_mode == 0 && jparams.optimize_coding == 0) {
    356    if (cinfo->jpeg_color_space == JCS_RGB) {
    357      Check(cinfo->comp_info[0].dc_tbl_no == 0);
    358      Check(cinfo->comp_info[1].dc_tbl_no == 0);
    359      Check(cinfo->comp_info[2].dc_tbl_no == 0);
    360      Check(cinfo->comp_info[0].ac_tbl_no == 0);
    361      Check(cinfo->comp_info[1].ac_tbl_no == 0);
    362      Check(cinfo->comp_info[2].ac_tbl_no == 0);
    363    } else if (cinfo->jpeg_color_space == JCS_YCbCr) {
    364      Check(cinfo->comp_info[0].dc_tbl_no == 0);
    365      Check(cinfo->comp_info[1].dc_tbl_no == 1);
    366      Check(cinfo->comp_info[2].dc_tbl_no == 1);
    367      Check(cinfo->comp_info[0].ac_tbl_no == 0);
    368      Check(cinfo->comp_info[1].ac_tbl_no == 1);
    369      Check(cinfo->comp_info[2].ac_tbl_no == 1);
    370    } else if (cinfo->jpeg_color_space == JCS_CMYK) {
    371      Check(cinfo->comp_info[0].dc_tbl_no == 0);
    372      Check(cinfo->comp_info[1].dc_tbl_no == 0);
    373      Check(cinfo->comp_info[2].dc_tbl_no == 0);
    374      Check(cinfo->comp_info[3].dc_tbl_no == 0);
    375      Check(cinfo->comp_info[0].ac_tbl_no == 0);
    376      Check(cinfo->comp_info[1].ac_tbl_no == 0);
    377      Check(cinfo->comp_info[2].ac_tbl_no == 0);
    378      Check(cinfo->comp_info[3].ac_tbl_no == 0);
    379    } else if (cinfo->jpeg_color_space == JCS_YCCK) {
    380      Check(cinfo->comp_info[0].dc_tbl_no == 0);
    381      Check(cinfo->comp_info[1].dc_tbl_no == 1);
    382      Check(cinfo->comp_info[2].dc_tbl_no == 1);
    383      Check(cinfo->comp_info[3].dc_tbl_no == 0);
    384      Check(cinfo->comp_info[0].ac_tbl_no == 0);
    385      Check(cinfo->comp_info[1].ac_tbl_no == 1);
    386      Check(cinfo->comp_info[2].ac_tbl_no == 1);
    387      Check(cinfo->comp_info[3].ac_tbl_no == 0);
    388    }
    389    if (jparams.use_flat_dc_luma_code) {
    390      JHUFF_TBL* tbl = cinfo->dc_huff_tbl_ptrs[0];
    391      jxl::msan::UnpoisonMemory(tbl, sizeof(*tbl));
    392      for (int i = 0; i < 15; ++i) {
    393        Check(tbl->huffval[i] == i);
    394      }
    395    }
    396  }
    397 }
    398 
    399 void UnmapColors(uint8_t* row, size_t xsize, int components,
    400                 JSAMPARRAY colormap, size_t num_colors) {
    401  Check(colormap != nullptr);
    402  std::vector<uint8_t> tmp(xsize * components);
    403  for (size_t x = 0; x < xsize; ++x) {
    404    Check(row[x] < num_colors);
    405    for (int c = 0; c < components; ++c) {
    406      tmp[x * components + c] = colormap[c][row[x]];
    407    }
    408  }
    409  memcpy(row, tmp.data(), tmp.size());
    410 }
    411 
    412 void CopyCoefficients(j_decompress_ptr cinfo, jvirt_barray_ptr* coef_arrays,
    413                      TestImage* output) {
    414  output->xsize = cinfo->image_width;
    415  output->ysize = cinfo->image_height;
    416  output->components = cinfo->num_components;
    417  output->color_space = cinfo->out_color_space;
    418  j_common_ptr comptr = reinterpret_cast<j_common_ptr>(cinfo);
    419  for (int c = 0; c < cinfo->num_components; ++c) {
    420    jpeg_component_info* comp = &cinfo->comp_info[c];
    421    std::vector<JCOEF> coeffs(comp->width_in_blocks * comp->height_in_blocks *
    422                              DCTSIZE2);
    423    for (size_t by = 0; by < comp->height_in_blocks; ++by) {
    424      JBLOCKARRAY blocks = (*cinfo->mem->access_virt_barray)(
    425          comptr, coef_arrays[c], by, 1, TRUE);
    426      size_t stride = comp->width_in_blocks * sizeof(JBLOCK);
    427      size_t offset = by * comp->width_in_blocks * DCTSIZE2;
    428      memcpy(&coeffs[offset], blocks[0], stride);
    429    }
    430    output->coeffs.emplace_back(std::move(coeffs));
    431  }
    432 }