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 normalization
     16 
     17 #include "./normalize.h"
     18 
     19 #include <inttypes.h>
     20 #include <stddef.h>
     21 
     22 #include "./buffer.h"
     23 #include "./port.h"
     24 #include "./font.h"
     25 #include "./glyph.h"
     26 #include "./round.h"
     27 #include "./store_bytes.h"
     28 #include "./table_tags.h"
     29 
     30 namespace woff2 {
     31 
     32 namespace {
     33 
     34 void StoreLoca(int index_fmt, uint32_t value, size_t* offset, uint8_t* dst) {
     35   if (index_fmt == 0) {
     36     Store16(value >> 1, offset, dst);
     37   } else {
     38     StoreU32(value, offset, dst);
     39   }
     40 }
     41 
     42 void NormalizeSimpleGlyphBoundingBox(Glyph* glyph) {
     43   if (glyph->contours.empty() || glyph->contours[0].empty()) {
     44     return;
     45   }
     46   int16_t x_min = glyph->contours[0][0].x;
     47   int16_t y_min = glyph->contours[0][0].y;
     48   int16_t x_max = x_min;
     49   int16_t y_max = y_min;
     50   for (const auto& contour : glyph->contours) {
     51     for (const auto& point : contour) {
     52       if (point.x < x_min) x_min = point.x;
     53       if (point.x > x_max) x_max = point.x;
     54       if (point.y < y_min) y_min = point.y;
     55       if (point.y > y_max) y_max = point.y;
     56     }
     57   }
     58   glyph->x_min = x_min;
     59   glyph->y_min = y_min;
     60   glyph->x_max = x_max;
     61   glyph->y_max = y_max;
     62 }
     63 
     64 }  // namespace
     65 
     66 bool NormalizeGlyphs(Font* font) {
     67   Font::Table* head_table = font->FindTable(kHeadTableTag);
     68   Font::Table* glyf_table = font->FindTable(kGlyfTableTag);
     69   Font::Table* loca_table = font->FindTable(kLocaTableTag);
     70   if (head_table == NULL || loca_table == NULL || glyf_table == NULL) {
     71     return FONT_COMPRESSION_FAILURE();
     72   }
     73   int index_fmt = head_table->data[51];
     74   int num_glyphs = NumGlyphs(*font);
     75 
     76   // We need to allocate a bit more than its original length for the normalized
     77   // glyf table, since it can happen that the glyphs in the original table are
     78   // 2-byte aligned, while in the normalized table they are 4-byte aligned.
     79   // That gives a maximum of 2 bytes increase per glyph. However, there is no
     80   // theoretical guarantee that the total size of the flags plus the coordinates
     81   // is the smallest possible in the normalized version, so we have to allow
     82   // some general overhead.
     83   // TODO(user) Figure out some more precise upper bound on the size of
     84   // the overhead.
     85   size_t max_normalized_glyf_size = 1.1 * glyf_table->length + 2 * num_glyphs;
     86 
     87   glyf_table->buffer.resize(max_normalized_glyf_size);
     88   loca_table->buffer.resize(Round4(loca_table->length));
     89   uint8_t* glyf_dst = &glyf_table->buffer[0];
     90   uint8_t* loca_dst = &loca_table->buffer[0];
     91   uint32_t glyf_offset = 0;
     92   size_t loca_offset = 0;
     93 
     94   for (int i = 0; i < num_glyphs; ++i) {
     95     StoreLoca(index_fmt, glyf_offset, &loca_offset, loca_dst);
     96     Glyph glyph;
     97     const uint8_t* glyph_data;
     98     size_t glyph_size;
     99     if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) ||
    100         (glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) {
    101       return FONT_COMPRESSION_FAILURE();
    102     }
    103     NormalizeSimpleGlyphBoundingBox(&glyph);
    104     size_t glyf_dst_size = glyf_table->buffer.size() - glyf_offset;
    105     if (!StoreGlyph(glyph, glyf_dst + glyf_offset, &glyf_dst_size)) {
    106       return FONT_COMPRESSION_FAILURE();
    107     }
    108     glyf_dst_size = Round4(glyf_dst_size);
    109     if (glyf_dst_size > std::numeric_limits<uint32_t>::max() ||
    110         glyf_offset + static_cast<uint32_t>(glyf_dst_size) < glyf_offset ||
    111         (index_fmt == 0 && glyf_offset + glyf_dst_size >= (1UL << 17))) {
    112       return FONT_COMPRESSION_FAILURE();
    113     }
    114     glyf_offset += glyf_dst_size;
    115   }
    116   StoreLoca(index_fmt, glyf_offset, &loca_offset, loca_dst);
    117 
    118   glyf_table->buffer.resize(glyf_offset);
    119   glyf_table->data = &glyf_table->buffer[0];
    120   glyf_table->length = glyf_offset;
    121   loca_table->data = &loca_table->buffer[0];
    122 
    123   return true;
    124 }
    125 
    126 bool NormalizeOffsets(Font* font) {
    127   uint32_t offset = 12 + 16 * font->num_tables;
    128   for (auto& i : font->tables) {
    129     i.second.offset = offset;
    130     offset += Round4(i.second.length);
    131   }
    132   return true;
    133 }
    134 
    135 namespace {
    136 
    137 uint32_t ComputeChecksum(const uint8_t* buf, size_t size) {
    138   uint32_t checksum = 0;
    139   for (size_t i = 0; i < size; i += 4) {
    140     checksum += ((buf[i] << 24) |
    141                  (buf[i + 1] << 16) |
    142                  (buf[i + 2] << 8) |
    143                  buf[i + 3]);
    144   }
    145   return checksum;
    146 }
    147 
    148 uint32_t ComputeHeaderChecksum(const Font& font) {
    149   uint32_t checksum = font.flavor;
    150   uint16_t max_pow2 = font.num_tables ? Log2Floor(font.num_tables) : 0;
    151   uint16_t search_range = max_pow2 ? 1 << (max_pow2 + 4) : 0;
    152   uint16_t range_shift = (font.num_tables << 4) - search_range;
    153   checksum += (font.num_tables << 16 | search_range);
    154   checksum += (max_pow2 << 16 | range_shift);
    155   for (const auto& i : font.tables) {
    156     checksum += i.second.tag;
    157     checksum += i.second.checksum;
    158     checksum += i.second.offset;
    159     checksum += i.second.length;
    160   }
    161   return checksum;
    162 }
    163 
    164 }  // namespace
    165 
    166 bool FixChecksums(Font* font) {
    167   Font::Table* head_table = font->FindTable(kHeadTableTag);
    168   if (head_table == NULL || head_table->length < 12) {
    169     return FONT_COMPRESSION_FAILURE();
    170   }
    171   head_table->buffer.resize(Round4(head_table->length));
    172   uint8_t* head_buf = &head_table->buffer[0];
    173   memcpy(head_buf, head_table->data, Round4(head_table->length));
    174   head_table->data = head_buf;
    175   size_t offset = 8;
    176   StoreU32(0, &offset, head_buf);
    177   uint32_t file_checksum = 0;
    178   for (auto& i : font->tables) {
    179     Font::Table* table = &i.second;
    180     table->checksum = ComputeChecksum(table->data, table->length);
    181     file_checksum += table->checksum;
    182   }
    183   file_checksum += ComputeHeaderChecksum(*font);
    184   offset = 8;
    185   StoreU32(0xb1b0afba - file_checksum, &offset, head_buf);
    186   return true;
    187 }
    188 
    189 bool NormalizeFont(Font* font) {
    190   return (RemoveDigitalSignature(font) &&
    191           NormalizeGlyphs(font) &&
    192           NormalizeOffsets(font) &&
    193           FixChecksums(font));
    194 }
    195 
    196 } // namespace woff2
    197