tor-browser

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

transform.cc (13696B)


      1 /* Copyright 2013 Google Inc. All Rights Reserved.
      2 
      3   Distributed under MIT license.
      4   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
      5 */
      6 
      7 /* Library for preprocessing fonts as part of the WOFF 2.0 conversion. */
      8 
      9 #include "./transform.h"
     10 
     11 #include <complex>  // for std::abs
     12 
     13 #include "./buffer.h"
     14 #include "./font.h"
     15 #include "./glyph.h"
     16 #include "./table_tags.h"
     17 #include "./variable_length.h"
     18 
     19 namespace woff2 {
     20 
     21 namespace {
     22 
     23 const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
     24 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
     25 const int FLAG_OVERLAP_SIMPLE_BITMAP = 1 << 0;
     26 
     27 void WriteBytes(std::vector<uint8_t>* out, const uint8_t* data, size_t len) {
     28  if (len == 0) return;
     29  size_t offset = out->size();
     30  out->resize(offset + len);
     31  memcpy(&(*out)[offset], data, len);
     32 }
     33 
     34 void WriteBytes(std::vector<uint8_t>* out, const std::vector<uint8_t>& in) {
     35  for (size_t i = 0; i < in.size(); ++i) {
     36    out->push_back(in[i]);
     37  }
     38 }
     39 
     40 void WriteUShort(std::vector<uint8_t>* out, int value) {
     41  out->push_back(value >> 8);
     42  out->push_back(value & 255);
     43 }
     44 
     45 void WriteLong(std::vector<uint8_t>* out, int value) {
     46  out->push_back((value >> 24) & 255);
     47  out->push_back((value >> 16) & 255);
     48  out->push_back((value >> 8) & 255);
     49  out->push_back(value & 255);
     50 }
     51 
     52 // Glyf table preprocessing, based on
     53 // GlyfEncoder.java
     54 class GlyfEncoder {
     55 public:
     56  explicit GlyfEncoder(int num_glyphs)
     57      : n_glyphs_(num_glyphs) {
     58    bbox_bitmap_.resize(((num_glyphs + 31) >> 5) << 2);
     59  }
     60 
     61  bool Encode(int glyph_id, const Glyph& glyph) {
     62    if (glyph.composite_data_size > 0) {
     63      WriteCompositeGlyph(glyph_id, glyph);
     64    } else if (glyph.contours.size() > 0) {
     65      WriteSimpleGlyph(glyph_id, glyph);
     66    } else {
     67      WriteUShort(&n_contour_stream_, 0);
     68    }
     69    return true;
     70  }
     71 
     72  void GetTransformedGlyfBytes(std::vector<uint8_t>* result) {
     73    WriteUShort(result, 0);  // Version
     74    WriteUShort(result, overlap_bitmap_.empty()
     75                            ? 0x00
     76                            : FLAG_OVERLAP_SIMPLE_BITMAP);  // Flags
     77    WriteUShort(result, n_glyphs_);
     78    WriteUShort(result, 0);  // index_format, will be set later
     79    WriteLong(result, n_contour_stream_.size());
     80    WriteLong(result, n_points_stream_.size());
     81    WriteLong(result, flag_byte_stream_.size());
     82    WriteLong(result, glyph_stream_.size());
     83    WriteLong(result, composite_stream_.size());
     84    WriteLong(result, bbox_bitmap_.size() + bbox_stream_.size());
     85    WriteLong(result, instruction_stream_.size());
     86    WriteBytes(result, n_contour_stream_);
     87    WriteBytes(result, n_points_stream_);
     88    WriteBytes(result, flag_byte_stream_);
     89    WriteBytes(result, glyph_stream_);
     90    WriteBytes(result, composite_stream_);
     91    WriteBytes(result, bbox_bitmap_);
     92    WriteBytes(result, bbox_stream_);
     93    WriteBytes(result, instruction_stream_);
     94    if (!overlap_bitmap_.empty()) {
     95      WriteBytes(result, overlap_bitmap_);
     96    }
     97  }
     98 
     99 private:
    100  void WriteInstructions(const Glyph& glyph) {
    101    Write255UShort(&glyph_stream_, glyph.instructions_size);
    102    WriteBytes(&instruction_stream_,
    103               glyph.instructions_data, glyph.instructions_size);
    104  }
    105 
    106  bool ShouldWriteSimpleGlyphBbox(const Glyph& glyph) {
    107    if (glyph.contours.empty() || glyph.contours[0].empty()) {
    108      return glyph.x_min || glyph.y_min || glyph.x_max || glyph.y_max;
    109    }
    110 
    111    int16_t x_min = glyph.contours[0][0].x;
    112    int16_t y_min = glyph.contours[0][0].y;
    113    int16_t x_max = x_min;
    114    int16_t y_max = y_min;
    115    for (const auto& contour : glyph.contours) {
    116      for (const auto& point : contour) {
    117        if (point.x < x_min) x_min = point.x;
    118        if (point.x > x_max) x_max = point.x;
    119        if (point.y < y_min) y_min = point.y;
    120        if (point.y > y_max) y_max = point.y;
    121      }
    122    }
    123 
    124    if (glyph.x_min != x_min)
    125      return true;
    126    if (glyph.y_min != y_min)
    127      return true;
    128    if (glyph.x_max != x_max)
    129      return true;
    130    if (glyph.y_max != y_max)
    131      return true;
    132 
    133    return false;
    134  }
    135 
    136  void WriteSimpleGlyph(int glyph_id, const Glyph& glyph) {
    137    if (glyph.overlap_simple_flag_set) {
    138      EnsureOverlapBitmap();
    139      overlap_bitmap_[glyph_id >> 3] |= 0x80 >> (glyph_id & 7);
    140    }
    141    int num_contours = glyph.contours.size();
    142    WriteUShort(&n_contour_stream_, num_contours);
    143    if (ShouldWriteSimpleGlyphBbox(glyph)) {
    144      WriteBbox(glyph_id, glyph);
    145    }
    146    for (int i = 0; i < num_contours; i++) {
    147      Write255UShort(&n_points_stream_, glyph.contours[i].size());
    148    }
    149    int lastX = 0;
    150    int lastY = 0;
    151    for (int i = 0; i < num_contours; i++) {
    152      int num_points = glyph.contours[i].size();
    153      for (int j = 0; j < num_points; j++) {
    154        int x = glyph.contours[i][j].x;
    155        int y = glyph.contours[i][j].y;
    156        int dx = x - lastX;
    157        int dy = y - lastY;
    158        WriteTriplet(glyph.contours[i][j].on_curve, dx, dy);
    159        lastX = x;
    160        lastY = y;
    161      }
    162    }
    163    if (num_contours > 0) {
    164      WriteInstructions(glyph);
    165    }
    166  }
    167 
    168  void WriteCompositeGlyph(int glyph_id, const Glyph& glyph) {
    169    WriteUShort(&n_contour_stream_, -1);
    170    WriteBbox(glyph_id, glyph);
    171    WriteBytes(&composite_stream_,
    172               glyph.composite_data,
    173               glyph.composite_data_size);
    174    if (glyph.have_instructions) {
    175      WriteInstructions(glyph);
    176    }
    177  }
    178 
    179  void WriteBbox(int glyph_id, const Glyph& glyph) {
    180    bbox_bitmap_[glyph_id >> 3] |= 0x80 >> (glyph_id & 7);
    181    WriteUShort(&bbox_stream_, glyph.x_min);
    182    WriteUShort(&bbox_stream_, glyph.y_min);
    183    WriteUShort(&bbox_stream_, glyph.x_max);
    184    WriteUShort(&bbox_stream_, glyph.y_max);
    185  }
    186 
    187  void WriteTriplet(bool on_curve, int x, int y) {
    188    int abs_x = std::abs(x);
    189    int abs_y = std::abs(y);
    190    int on_curve_bit = on_curve ? 0 : 128;
    191    int x_sign_bit = (x < 0) ? 0 : 1;
    192    int y_sign_bit = (y < 0) ? 0 : 1;
    193    int xy_sign_bits = x_sign_bit + 2 * y_sign_bit;
    194    if (x == 0 && abs_y < 1280) {
    195      flag_byte_stream_.push_back(on_curve_bit +
    196                                  ((abs_y & 0xf00) >> 7) + y_sign_bit);
    197      glyph_stream_.push_back(abs_y & 0xff);
    198    } else if (y == 0 && abs_x < 1280) {
    199      flag_byte_stream_.push_back(on_curve_bit + 10 +
    200                                  ((abs_x & 0xf00) >> 7) + x_sign_bit);
    201      glyph_stream_.push_back(abs_x & 0xff);
    202    } else if (abs_x < 65 && abs_y < 65) {
    203      flag_byte_stream_.push_back(on_curve_bit + 20 +
    204                                  ((abs_x - 1) & 0x30) +
    205                                  (((abs_y - 1) & 0x30) >> 2) +
    206                                  xy_sign_bits);
    207      glyph_stream_.push_back((((abs_x - 1) & 0xf) << 4) | ((abs_y - 1) & 0xf));
    208    } else if (abs_x < 769 && abs_y < 769) {
    209      flag_byte_stream_.push_back(on_curve_bit + 84 +
    210                                  12 * (((abs_x - 1) & 0x300) >> 8) +
    211                                  (((abs_y - 1) & 0x300) >> 6) + xy_sign_bits);
    212      glyph_stream_.push_back((abs_x - 1) & 0xff);
    213      glyph_stream_.push_back((abs_y - 1) & 0xff);
    214    } else if (abs_x < 4096 && abs_y < 4096) {
    215      flag_byte_stream_.push_back(on_curve_bit + 120 + xy_sign_bits);
    216      glyph_stream_.push_back(abs_x >> 4);
    217      glyph_stream_.push_back(((abs_x & 0xf) << 4) | (abs_y >> 8));
    218      glyph_stream_.push_back(abs_y & 0xff);
    219    } else {
    220      flag_byte_stream_.push_back(on_curve_bit + 124 + xy_sign_bits);
    221      glyph_stream_.push_back(abs_x >> 8);
    222      glyph_stream_.push_back(abs_x & 0xff);
    223      glyph_stream_.push_back(abs_y >> 8);
    224      glyph_stream_.push_back(abs_y & 0xff);
    225    }
    226  }
    227 
    228  void EnsureOverlapBitmap() {
    229    if (overlap_bitmap_.empty()) {
    230      overlap_bitmap_.resize((n_glyphs_ + 7) >> 3);
    231    }
    232  }
    233 
    234  std::vector<uint8_t> n_contour_stream_;
    235  std::vector<uint8_t> n_points_stream_;
    236  std::vector<uint8_t> flag_byte_stream_;
    237  std::vector<uint8_t> composite_stream_;
    238  std::vector<uint8_t> bbox_bitmap_;
    239  std::vector<uint8_t> bbox_stream_;
    240  std::vector<uint8_t> glyph_stream_;
    241  std::vector<uint8_t> instruction_stream_;
    242  std::vector<uint8_t> overlap_bitmap_;
    243  int n_glyphs_;
    244 };
    245 
    246 }  // namespace
    247 
    248 bool TransformGlyfAndLocaTables(Font* font) {
    249  // no transform for CFF
    250  const Font::Table* glyf_table = font->FindTable(kGlyfTableTag);
    251  const Font::Table* loca_table = font->FindTable(kLocaTableTag);
    252 
    253  // If you don't have glyf/loca this transform isn't very interesting
    254  if (loca_table == NULL && glyf_table == NULL) {
    255    return true;
    256  }
    257  // It would be best if you didn't have just one of glyf/loca
    258  if ((glyf_table == NULL) != (loca_table == NULL)) {
    259    return FONT_COMPRESSION_FAILURE();
    260  }
    261  // Must share neither or both loca & glyf
    262  if (loca_table->IsReused() != glyf_table->IsReused()) {
    263    return FONT_COMPRESSION_FAILURE();
    264  }
    265  if (loca_table->IsReused()) {
    266    return true;
    267  }
    268 
    269  Font::Table* transformed_glyf = &font->tables[kGlyfTableTag ^ 0x80808080];
    270  Font::Table* transformed_loca = &font->tables[kLocaTableTag ^ 0x80808080];
    271 
    272  int num_glyphs = NumGlyphs(*font);
    273  GlyfEncoder encoder(num_glyphs);
    274  for (int i = 0; i < num_glyphs; ++i) {
    275    Glyph glyph;
    276    const uint8_t* glyph_data;
    277    size_t glyph_size;
    278    if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) ||
    279        (glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) {
    280      return FONT_COMPRESSION_FAILURE();
    281    }
    282    encoder.Encode(i, glyph);
    283  }
    284  encoder.GetTransformedGlyfBytes(&transformed_glyf->buffer);
    285 
    286  const Font::Table* head_table = font->FindTable(kHeadTableTag);
    287  if (head_table == NULL || head_table->length < 52) {
    288    return FONT_COMPRESSION_FAILURE();
    289  }
    290  transformed_glyf->buffer[7] = head_table->data[51];  // index_format
    291 
    292  transformed_glyf->tag = kGlyfTableTag ^ 0x80808080;
    293  transformed_glyf->length = transformed_glyf->buffer.size();
    294  transformed_glyf->data = transformed_glyf->buffer.data();
    295 
    296  transformed_loca->tag = kLocaTableTag ^ 0x80808080;
    297  transformed_loca->length = 0;
    298  transformed_loca->data = NULL;
    299 
    300  return true;
    301 }
    302 
    303 // See https://www.microsoft.com/typography/otspec/hmtx.htm
    304 // See WOFF2 spec, 5.4. Transformed hmtx table format
    305 bool TransformHmtxTable(Font* font) {
    306  const Font::Table* glyf_table = font->FindTable(kGlyfTableTag);
    307  const Font::Table* hmtx_table = font->FindTable(kHmtxTableTag);
    308  const Font::Table* hhea_table = font->FindTable(kHheaTableTag);
    309 
    310  // If you don't have hmtx or a glyf not much is going to happen here
    311  if (hmtx_table == NULL || glyf_table == NULL) {
    312    return true;
    313  }
    314 
    315  // hmtx without hhea doesn't make sense
    316  if (hhea_table == NULL) {
    317    return FONT_COMPRESSION_FAILURE();
    318  }
    319 
    320  // Skip 34 to reach 'hhea' numberOfHMetrics
    321  Buffer hhea_buf(hhea_table->data, hhea_table->length);
    322  uint16_t num_hmetrics;
    323  if (!hhea_buf.Skip(34) || !hhea_buf.ReadU16(&num_hmetrics)) {
    324    return FONT_COMPRESSION_FAILURE();
    325  }
    326 
    327  // Must have at least one hMetric
    328  if (num_hmetrics < 1) {
    329    return FONT_COMPRESSION_FAILURE();
    330  }
    331 
    332  int num_glyphs = NumGlyphs(*font);
    333 
    334  // Most fonts can be transformed; assume it's a go until proven otherwise
    335  std::vector<uint16_t> advance_widths;
    336  std::vector<int16_t> proportional_lsbs;
    337  std::vector<int16_t> monospace_lsbs;
    338 
    339  bool remove_proportional_lsb = true;
    340  bool remove_monospace_lsb = (num_glyphs - num_hmetrics) > 0;
    341 
    342  Buffer hmtx_buf(hmtx_table->data, hmtx_table->length);
    343  for (int i = 0; i < num_glyphs; i++) {
    344    Glyph glyph;
    345    const uint8_t* glyph_data;
    346    size_t glyph_size;
    347    if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) ||
    348        (glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) {
    349      return FONT_COMPRESSION_FAILURE();
    350    }
    351 
    352    uint16_t advance_width = 0;
    353    int16_t lsb = 0;
    354 
    355    if (i < num_hmetrics) {
    356      // [0, num_hmetrics) are proportional hMetrics
    357      if (!hmtx_buf.ReadU16(&advance_width)) {
    358        return FONT_COMPRESSION_FAILURE();
    359      }
    360 
    361      if (!hmtx_buf.ReadS16(&lsb)) {
    362        return FONT_COMPRESSION_FAILURE();
    363      }
    364 
    365      if (glyph_size > 0 && glyph.x_min != lsb) {
    366        remove_proportional_lsb = false;
    367      }
    368 
    369      advance_widths.push_back(advance_width);
    370      proportional_lsbs.push_back(lsb);
    371    } else {
    372      // [num_hmetrics, num_glyphs) are monospace leftSideBearing's
    373      if (!hmtx_buf.ReadS16(&lsb)) {
    374        return FONT_COMPRESSION_FAILURE();
    375      }
    376      if (glyph_size > 0 && glyph.x_min != lsb) {
    377        remove_monospace_lsb = false;
    378      }
    379      monospace_lsbs.push_back(lsb);
    380    }
    381 
    382    // If we know we can't optimize, bail out completely
    383    if (!remove_proportional_lsb && !remove_monospace_lsb) {
    384      return true;
    385    }
    386  }
    387 
    388  Font::Table* transformed_hmtx = &font->tables[kHmtxTableTag ^ 0x80808080];
    389 
    390  uint8_t flags = 0;
    391  size_t transformed_size = 1 + 2 * advance_widths.size();
    392  if (remove_proportional_lsb) {
    393    flags |= 1;
    394  } else {
    395    transformed_size += 2 * proportional_lsbs.size();
    396  }
    397  if (remove_monospace_lsb) {
    398    flags |= 1 << 1;
    399  } else {
    400    transformed_size += 2 * monospace_lsbs.size();
    401  }
    402 
    403  transformed_hmtx->buffer.reserve(transformed_size);
    404  std::vector<uint8_t>* out = &transformed_hmtx->buffer;
    405  WriteBytes(out, &flags, 1);
    406  for (uint16_t advance_width : advance_widths) {
    407    WriteUShort(out, advance_width);
    408  }
    409 
    410  if (!remove_proportional_lsb) {
    411    for (int16_t lsb : proportional_lsbs) {
    412      WriteUShort(out, lsb);
    413    }
    414  }
    415  if (!remove_monospace_lsb) {
    416    for (int16_t lsb : monospace_lsbs) {
    417      WriteUShort(out, lsb);
    418    }
    419  }
    420 
    421  transformed_hmtx->tag = kHmtxTableTag ^ 0x80808080;
    422  transformed_hmtx->flag_byte = 1 << 6;
    423  transformed_hmtx->length = transformed_hmtx->buffer.size();
    424  transformed_hmtx->data = transformed_hmtx->buffer.data();
    425 
    426 
    427  return true;
    428 }
    429 
    430 } // namespace woff2