tor-browser

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

glyph.cc (11642B)


      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 /* Glyph manipulation */
      8 
      9 #include "./glyph.h"
     10 
     11 #include <stdlib.h>
     12 #include <limits>
     13 #include "./buffer.h"
     14 #include "./store_bytes.h"
     15 
     16 namespace woff2 {
     17 
     18 static const int32_t kFLAG_ONCURVE = 1;
     19 static const int32_t kFLAG_XSHORT = 1 << 1;
     20 static const int32_t kFLAG_YSHORT = 1 << 2;
     21 static const int32_t kFLAG_REPEAT = 1 << 3;
     22 static const int32_t kFLAG_XREPEATSIGN = 1 << 4;
     23 static const int32_t kFLAG_YREPEATSIGN = 1 << 5;
     24 static const int32_t kFLAG_OVERLAP_SIMPLE = 1 << 6;
     25 static const int32_t kFLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
     26 static const int32_t kFLAG_WE_HAVE_A_SCALE = 1 << 3;
     27 static const int32_t kFLAG_MORE_COMPONENTS = 1 << 5;
     28 static const int32_t kFLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
     29 static const int32_t kFLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
     30 static const int32_t kFLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
     31 
     32 bool ReadCompositeGlyphData(Buffer* buffer, Glyph* glyph) {
     33  glyph->have_instructions = false;
     34  glyph->composite_data = buffer->buffer() + buffer->offset();
     35  size_t start_offset = buffer->offset();
     36  uint16_t flags = kFLAG_MORE_COMPONENTS;
     37  while (flags & kFLAG_MORE_COMPONENTS) {
     38    if (!buffer->ReadU16(&flags)) {
     39      return FONT_COMPRESSION_FAILURE();
     40    }
     41    glyph->have_instructions |= (flags & kFLAG_WE_HAVE_INSTRUCTIONS) != 0;
     42    size_t arg_size = 2;  // glyph index
     43    if (flags & kFLAG_ARG_1_AND_2_ARE_WORDS) {
     44      arg_size += 4;
     45    } else {
     46      arg_size += 2;
     47    }
     48    if (flags & kFLAG_WE_HAVE_A_SCALE) {
     49      arg_size += 2;
     50    } else if (flags & kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
     51      arg_size += 4;
     52    } else if (flags & kFLAG_WE_HAVE_A_TWO_BY_TWO) {
     53      arg_size += 8;
     54    }
     55    if (!buffer->Skip(arg_size)) {
     56      return FONT_COMPRESSION_FAILURE();
     57    }
     58  }
     59  if (buffer->offset() - start_offset > std::numeric_limits<uint32_t>::max()) {
     60    return FONT_COMPRESSION_FAILURE();
     61  }
     62  glyph->composite_data_size = buffer->offset() - start_offset;
     63  return true;
     64 }
     65 
     66 bool ReadGlyph(const uint8_t* data, size_t len, Glyph* glyph) {
     67  Buffer buffer(data, len);
     68 
     69  int16_t num_contours;
     70  if (!buffer.ReadS16(&num_contours)) {
     71    return FONT_COMPRESSION_FAILURE();
     72  }
     73 
     74  // Read the bounding box.
     75  if (!buffer.ReadS16(&glyph->x_min) ||
     76      !buffer.ReadS16(&glyph->y_min) ||
     77      !buffer.ReadS16(&glyph->x_max) ||
     78      !buffer.ReadS16(&glyph->y_max)) {
     79    return FONT_COMPRESSION_FAILURE();
     80  }
     81 
     82  if (num_contours == 0) {
     83    // Empty glyph.
     84    return true;
     85  }
     86 
     87  if (num_contours > 0) {
     88    // Simple glyph.
     89    glyph->contours.resize(num_contours);
     90 
     91    // Read the number of points per contour.
     92    uint16_t last_point_index = 0;
     93    for (int i = 0; i < num_contours; ++i) {
     94      uint16_t point_index;
     95      if (!buffer.ReadU16(&point_index)) {
     96        return FONT_COMPRESSION_FAILURE();
     97      }
     98      uint16_t num_points = point_index - last_point_index + (i == 0 ? 1 : 0);
     99      glyph->contours[i].resize(num_points);
    100      last_point_index = point_index;
    101    }
    102 
    103    // Read the instructions.
    104    if (!buffer.ReadU16(&glyph->instructions_size)) {
    105      return FONT_COMPRESSION_FAILURE();
    106    }
    107    glyph->instructions_data = data + buffer.offset();
    108    if (!buffer.Skip(glyph->instructions_size)) {
    109      return FONT_COMPRESSION_FAILURE();
    110    }
    111 
    112    // Read the run-length coded flags.
    113    std::vector<std::vector<uint8_t> > flags(num_contours);
    114    {
    115      uint8_t flag = 0;
    116      uint8_t flag_repeat = 0;
    117      for (int i = 0; i < num_contours; ++i) {
    118        flags[i].resize(glyph->contours[i].size());
    119        for (size_t j = 0; j < glyph->contours[i].size(); ++j) {
    120          if (flag_repeat == 0) {
    121            if (!buffer.ReadU8(&flag)) {
    122              return FONT_COMPRESSION_FAILURE();
    123            }
    124            if (flag & kFLAG_REPEAT) {
    125              if (!buffer.ReadU8(&flag_repeat)) {
    126                return FONT_COMPRESSION_FAILURE();
    127              }
    128            }
    129          } else {
    130            flag_repeat--;
    131          }
    132          flags[i][j] = flag;
    133          glyph->contours[i][j].on_curve = flag & kFLAG_ONCURVE;
    134        }
    135      }
    136    }
    137 
    138    if (!flags.empty() && !flags[0].empty()) {
    139      glyph->overlap_simple_flag_set = (flags[0][0] & kFLAG_OVERLAP_SIMPLE);
    140    }
    141 
    142    // Read the x coordinates.
    143    int prev_x = 0;
    144    for (int i = 0; i < num_contours; ++i) {
    145      for (size_t j = 0; j < glyph->contours[i].size(); ++j) {
    146        uint8_t flag = flags[i][j];
    147        if (flag & kFLAG_XSHORT) {
    148          // single byte x-delta coord value
    149          uint8_t x_delta;
    150          if (!buffer.ReadU8(&x_delta)) {
    151            return FONT_COMPRESSION_FAILURE();
    152          }
    153          int sign = (flag & kFLAG_XREPEATSIGN) ? 1 : -1;
    154          glyph->contours[i][j].x = prev_x + sign * x_delta;
    155        } else {
    156          // double byte x-delta coord value
    157          int16_t x_delta = 0;
    158          if (!(flag & kFLAG_XREPEATSIGN)) {
    159            if (!buffer.ReadS16(&x_delta)) {
    160              return FONT_COMPRESSION_FAILURE();
    161            }
    162          }
    163          glyph->contours[i][j].x = prev_x + x_delta;
    164        }
    165        prev_x = glyph->contours[i][j].x;
    166      }
    167    }
    168 
    169    // Read the y coordinates.
    170    int prev_y = 0;
    171    for (int i = 0; i < num_contours; ++i) {
    172      for (size_t j = 0; j < glyph->contours[i].size(); ++j) {
    173        uint8_t flag = flags[i][j];
    174        if (flag & kFLAG_YSHORT) {
    175          // single byte y-delta coord value
    176          uint8_t y_delta;
    177          if (!buffer.ReadU8(&y_delta)) {
    178            return FONT_COMPRESSION_FAILURE();
    179          }
    180          int sign = (flag & kFLAG_YREPEATSIGN) ? 1 : -1;
    181          glyph->contours[i][j].y = prev_y + sign * y_delta;
    182        } else {
    183          // double byte y-delta coord value
    184          int16_t y_delta = 0;
    185          if (!(flag & kFLAG_YREPEATSIGN)) {
    186            if (!buffer.ReadS16(&y_delta)) {
    187              return FONT_COMPRESSION_FAILURE();
    188            }
    189          }
    190          glyph->contours[i][j].y = prev_y + y_delta;
    191        }
    192        prev_y = glyph->contours[i][j].y;
    193      }
    194    }
    195  } else if (num_contours == -1) {
    196    // Composite glyph.
    197    if (!ReadCompositeGlyphData(&buffer, glyph)) {
    198      return FONT_COMPRESSION_FAILURE();
    199    }
    200    // Read the instructions.
    201    if (glyph->have_instructions) {
    202      if (!buffer.ReadU16(&glyph->instructions_size)) {
    203        return FONT_COMPRESSION_FAILURE();
    204      }
    205      glyph->instructions_data = data + buffer.offset();
    206      if (!buffer.Skip(glyph->instructions_size)) {
    207        return FONT_COMPRESSION_FAILURE();
    208      }
    209    } else {
    210      glyph->instructions_size = 0;
    211    }
    212  } else {
    213    return FONT_COMPRESSION_FAILURE();
    214  }
    215  return true;
    216 }
    217 
    218 namespace {
    219 
    220 void StoreBbox(const Glyph& glyph, size_t* offset, uint8_t* dst) {
    221  Store16(glyph.x_min, offset, dst);
    222  Store16(glyph.y_min, offset, dst);
    223  Store16(glyph.x_max, offset, dst);
    224  Store16(glyph.y_max, offset, dst);
    225 }
    226 
    227 void StoreInstructions(const Glyph& glyph, size_t* offset, uint8_t* dst) {
    228  Store16(glyph.instructions_size, offset, dst);
    229  StoreBytes(glyph.instructions_data, glyph.instructions_size, offset, dst);
    230 }
    231 
    232 bool StoreEndPtsOfContours(const Glyph& glyph, size_t* offset, uint8_t* dst) {
    233  int end_point = -1;
    234  for (const auto& contour : glyph.contours) {
    235    end_point += contour.size();
    236    if (contour.size() > std::numeric_limits<uint16_t>::max() ||
    237        end_point > std::numeric_limits<uint16_t>::max()) {
    238      return FONT_COMPRESSION_FAILURE();
    239    }
    240    Store16(end_point, offset, dst);
    241  }
    242  return true;
    243 }
    244 
    245 bool StorePoints(const Glyph& glyph, size_t* offset,
    246                 uint8_t* dst, size_t dst_size) {
    247  int previous_flag = -1;
    248  int repeat_count = 0;
    249  int last_x = 0;
    250  int last_y = 0;
    251  size_t x_bytes = 0;
    252  size_t y_bytes = 0;
    253 
    254  // Store the flags and calculate the total size of the x and y coordinates.
    255  for (const auto& contour : glyph.contours) {
    256    for (const auto& point : contour) {
    257      int flag = point.on_curve ? kFLAG_ONCURVE : 0;
    258      if (previous_flag == -1 && glyph.overlap_simple_flag_set) {
    259        // First flag needs to have overlap simple bit set.
    260        flag = flag | kFLAG_OVERLAP_SIMPLE;
    261      }
    262      int dx = point.x - last_x;
    263      int dy = point.y - last_y;
    264      if (dx == 0) {
    265        flag |= kFLAG_XREPEATSIGN;
    266      } else if (dx > -256 && dx < 256) {
    267        flag |= kFLAG_XSHORT | (dx > 0 ? kFLAG_XREPEATSIGN : 0);
    268        x_bytes += 1;
    269      } else {
    270        x_bytes += 2;
    271      }
    272      if (dy == 0) {
    273        flag |= kFLAG_YREPEATSIGN;
    274      } else if (dy > -256 && dy < 256) {
    275        flag |= kFLAG_YSHORT | (dy > 0 ? kFLAG_YREPEATSIGN : 0);
    276        y_bytes += 1;
    277      } else {
    278        y_bytes += 2;
    279      }
    280      if (flag == previous_flag && repeat_count != 255) {
    281        dst[*offset - 1] |= kFLAG_REPEAT;
    282        repeat_count++;
    283      } else {
    284        if (repeat_count != 0) {
    285          if (*offset >= dst_size) {
    286            return FONT_COMPRESSION_FAILURE();
    287          }
    288          dst[(*offset)++] = repeat_count;
    289        }
    290        if (*offset >= dst_size) {
    291          return FONT_COMPRESSION_FAILURE();
    292        }
    293        dst[(*offset)++] = flag;
    294        repeat_count = 0;
    295      }
    296      last_x = point.x;
    297      last_y = point.y;
    298      previous_flag = flag;
    299    }
    300  }
    301  if (repeat_count != 0) {
    302    if (*offset >= dst_size) {
    303      return FONT_COMPRESSION_FAILURE();
    304    }
    305    dst[(*offset)++] = repeat_count;
    306  }
    307 
    308  if (*offset + x_bytes + y_bytes > dst_size) {
    309    return FONT_COMPRESSION_FAILURE();
    310  }
    311 
    312  // Store the x and y coordinates.
    313  size_t x_offset = *offset;
    314  size_t y_offset = *offset + x_bytes;
    315  last_x = 0;
    316  last_y = 0;
    317  for (const auto& contour : glyph.contours) {
    318    for (const auto& point : contour) {
    319      int dx = point.x - last_x;
    320      int dy = point.y - last_y;
    321      if (dx == 0) {
    322        // pass
    323      } else if (dx > -256 && dx < 256) {
    324        dst[x_offset++] = std::abs(dx);
    325      } else {
    326        Store16(dx, &x_offset, dst);
    327      }
    328      if (dy == 0) {
    329        // pass
    330      } else if (dy > -256 && dy < 256) {
    331        dst[y_offset++] = std::abs(dy);
    332      } else {
    333        Store16(dy, &y_offset, dst);
    334      }
    335      last_x += dx;
    336      last_y += dy;
    337    }
    338  }
    339  *offset = y_offset;
    340  return true;
    341 }
    342 
    343 }  // namespace
    344 
    345 bool StoreGlyph(const Glyph& glyph, uint8_t* dst, size_t* dst_size) {
    346  size_t offset = 0;
    347  if (glyph.composite_data_size > 0) {
    348    // Composite glyph.
    349    if (*dst_size < ((10ULL + glyph.composite_data_size) +
    350                     ((glyph.have_instructions ? 2ULL : 0) +
    351                      glyph.instructions_size))) {
    352      return FONT_COMPRESSION_FAILURE();
    353    }
    354    Store16(-1, &offset, dst);
    355    StoreBbox(glyph, &offset, dst);
    356    StoreBytes(glyph.composite_data, glyph.composite_data_size, &offset, dst);
    357    if (glyph.have_instructions) {
    358      StoreInstructions(glyph, &offset, dst);
    359    }
    360  } else if (glyph.contours.size() > 0) {
    361    // Simple glyph.
    362    if (glyph.contours.size() > std::numeric_limits<int16_t>::max()) {
    363      return FONT_COMPRESSION_FAILURE();
    364    }
    365    if (*dst_size < ((12ULL + 2 * glyph.contours.size()) +
    366                     glyph.instructions_size)) {
    367      return FONT_COMPRESSION_FAILURE();
    368    }
    369    Store16(glyph.contours.size(), &offset, dst);
    370    StoreBbox(glyph, &offset, dst);
    371    if (!StoreEndPtsOfContours(glyph, &offset, dst)) {
    372      return FONT_COMPRESSION_FAILURE();
    373    }
    374    StoreInstructions(glyph, &offset, dst);
    375    if (!StorePoints(glyph, &offset, dst, *dst_size)) {
    376      return FONT_COMPRESSION_FAILURE();
    377    }
    378  }
    379  *dst_size = offset;
    380  return true;
    381 }
    382 
    383 } // namespace woff2