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