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 // Library for preprocessing fonts as part of the WOFF 2.0 conversion.
     16 
     17 #include "./transform.h"
     18 
     19 #include <complex>  // for std::abs
     20 
     21 #include "./buffer.h"
     22 #include "./font.h"
     23 #include "./glyph.h"
     24 #include "./table_tags.h"
     25 
     26 namespace woff2 {
     27 
     28 namespace {
     29 
     30 const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
     31 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
     32 
     33 void WriteBytes(std::vector<uint8_t>* out, const uint8_t* data, size_t len) {
     34   if (len == 0) return;
     35   size_t offset = out->size();
     36   out->resize(offset + len);
     37   memcpy(&(*out)[offset], data, len);
     38 }
     39 
     40 void WriteBytes(std::vector<uint8_t>* out, const std::vector<uint8_t>& in) {
     41   for (int i = 0; i < in.size(); ++i) {
     42     out->push_back(in[i]);
     43   }
     44 }
     45 
     46 void WriteUShort(std::vector<uint8_t>* out, int value) {
     47   out->push_back(value >> 8);
     48   out->push_back(value & 255);
     49 }
     50 
     51 void WriteLong(std::vector<uint8_t>* out, int value) {
     52   out->push_back((value >> 24) & 255);
     53   out->push_back((value >> 16) & 255);
     54   out->push_back((value >> 8) & 255);
     55   out->push_back(value & 255);
     56 }
     57 
     58 void Write255UShort(std::vector<uint8_t>* out, int value) {
     59   if (value < 253) {
     60     out->push_back(value);
     61   } else if (value < 506) {
     62     out->push_back(255);
     63     out->push_back(value - 253);
     64   } else if (value < 762) {
     65     out->push_back(254);
     66     out->push_back(value - 506);
     67   } else {
     68     out->push_back(253);
     69     out->push_back(value >> 8);
     70     out->push_back(value & 0xff);
     71   }
     72 }
     73 
     74 // Glyf table preprocessing, based on
     75 // GlyfEncoder.java
     76 // but only the "sbbox" and "cbbox" options are supported.
     77 class GlyfEncoder {
     78  public:
     79   explicit GlyfEncoder(int num_glyphs)
     80       : sbbox_(false), cbbox_(true), n_glyphs_(num_glyphs) {
     81     bbox_bitmap_.resize(((num_glyphs + 31) >> 5) << 2);
     82   }
     83 
     84   bool Encode(int glyph_id, const Glyph& glyph) {
     85     if (glyph.composite_data_size > 0) {
     86       WriteCompositeGlyph(glyph_id, glyph);
     87     } else if (glyph.contours.size() > 0) {
     88       WriteSimpleGlyph(glyph_id, glyph);
     89     } else {
     90       WriteUShort(&n_contour_stream_, 0);
     91     }
     92     return true;
     93   }
     94 
     95   void GetTransformedGlyfBytes(std::vector<uint8_t>* result) {
     96     WriteLong(result, 0);  // version
     97     WriteUShort(result, n_glyphs_);
     98     WriteUShort(result, 0);  // index_format, will be set later
     99     WriteLong(result, n_contour_stream_.size());
    100     WriteLong(result, n_points_stream_.size());
    101     WriteLong(result, flag_byte_stream_.size());
    102     WriteLong(result, glyph_stream_.size());
    103     WriteLong(result, composite_stream_.size());
    104     WriteLong(result, bbox_bitmap_.size() + bbox_stream_.size());
    105     WriteLong(result, instruction_stream_.size());
    106     WriteBytes(result, n_contour_stream_);
    107     WriteBytes(result, n_points_stream_);
    108     WriteBytes(result, flag_byte_stream_);
    109     WriteBytes(result, glyph_stream_);
    110     WriteBytes(result, composite_stream_);
    111     WriteBytes(result, bbox_bitmap_);
    112     WriteBytes(result, bbox_stream_);
    113     WriteBytes(result, instruction_stream_);
    114   }
    115 
    116  private:
    117   void WriteInstructions(const Glyph& glyph) {
    118     Write255UShort(&glyph_stream_, glyph.instructions_size);
    119     WriteBytes(&instruction_stream_,
    120                glyph.instructions_data, glyph.instructions_size);
    121   }
    122 
    123   void WriteSimpleGlyph(int glyph_id, const Glyph& glyph) {
    124     int num_contours = glyph.contours.size();
    125     WriteUShort(&n_contour_stream_, num_contours);
    126     if (sbbox_) {
    127       WriteBbox(glyph_id, glyph);
    128     }
    129     // TODO: check that bbox matches, write bbox if not
    130     for (int i = 0; i < num_contours; i++) {
    131       Write255UShort(&n_points_stream_, glyph.contours[i].size());
    132     }
    133     int lastX = 0;
    134     int lastY = 0;
    135     for (int i = 0; i < num_contours; i++) {
    136       int num_points = glyph.contours[i].size();
    137       for (int j = 0; j < num_points; j++) {
    138         int x = glyph.contours[i][j].x;
    139         int y = glyph.contours[i][j].y;
    140         int dx = x - lastX;
    141         int dy = y - lastY;
    142         WriteTriplet(glyph.contours[i][j].on_curve, dx, dy);
    143         lastX = x;
    144         lastY = y;
    145       }
    146     }
    147     if (num_contours > 0) {
    148       WriteInstructions(glyph);
    149     }
    150   }
    151 
    152   void WriteCompositeGlyph(int glyph_id, const Glyph& glyph) {
    153     WriteUShort(&n_contour_stream_, -1);
    154     if (cbbox_) {
    155       WriteBbox(glyph_id, glyph);
    156     }
    157     WriteBytes(&composite_stream_,
    158                glyph.composite_data,
    159                glyph.composite_data_size);
    160     if (glyph.have_instructions) {
    161       WriteInstructions(glyph);
    162     }
    163   }
    164 
    165   void WriteBbox(int glyph_id, const Glyph& glyph) {
    166     bbox_bitmap_[glyph_id >> 3] |= 0x80 >> (glyph_id & 7);
    167     WriteUShort(&bbox_stream_, glyph.x_min);
    168     WriteUShort(&bbox_stream_, glyph.y_min);
    169     WriteUShort(&bbox_stream_, glyph.x_max);
    170     WriteUShort(&bbox_stream_, glyph.y_max);
    171   }
    172 
    173   void WriteTriplet(bool on_curve, int x, int y) {
    174     int abs_x = std::abs(x);
    175     int abs_y = std::abs(y);
    176     int on_curve_bit = on_curve ? 0 : 128;
    177     int x_sign_bit = (x < 0) ? 0 : 1;
    178     int y_sign_bit = (y < 0) ? 0 : 1;
    179     int xy_sign_bits = x_sign_bit + 2 * y_sign_bit;
    180     if (x == 0 && abs_y < 1280) {
    181       flag_byte_stream_.push_back(on_curve_bit +
    182                                   ((abs_y & 0xf00) >> 7) + y_sign_bit);
    183       glyph_stream_.push_back(abs_y & 0xff);
    184     } else if (y == 0 && abs_x < 1280) {
    185       flag_byte_stream_.push_back(on_curve_bit + 10 +
    186                                   ((abs_x & 0xf00) >> 7) + x_sign_bit);
    187       glyph_stream_.push_back(abs_x & 0xff);
    188     } else if (abs_x < 65 && abs_y < 65) {
    189       flag_byte_stream_.push_back(on_curve_bit + 20 +
    190                                   ((abs_x - 1) & 0x30) +
    191                                   (((abs_y - 1) & 0x30) >> 2) +
    192                                   xy_sign_bits);
    193       glyph_stream_.push_back((((abs_x - 1) & 0xf) << 4) | ((abs_y - 1) & 0xf));
    194     } else if (abs_x < 769 && abs_y < 769) {
    195       flag_byte_stream_.push_back(on_curve_bit + 84 +
    196                                   12 * (((abs_x - 1) & 0x300) >> 8) +
    197                                   (((abs_y - 1) & 0x300) >> 6) + xy_sign_bits);
    198       glyph_stream_.push_back((abs_x - 1) & 0xff);
    199       glyph_stream_.push_back((abs_y - 1) & 0xff);
    200     } else if (abs_x < 4096 && abs_y < 4096) {
    201       flag_byte_stream_.push_back(on_curve_bit + 120 + xy_sign_bits);
    202       glyph_stream_.push_back(abs_x >> 4);
    203       glyph_stream_.push_back(((abs_x & 0xf) << 4) | (abs_y >> 8));
    204       glyph_stream_.push_back(abs_y & 0xff);
    205     } else {
    206       flag_byte_stream_.push_back(on_curve_bit + 124 + xy_sign_bits);
    207       glyph_stream_.push_back(abs_x >> 8);
    208       glyph_stream_.push_back(abs_x & 0xff);
    209       glyph_stream_.push_back(abs_y >> 8);
    210       glyph_stream_.push_back(abs_y & 0xff);
    211     }
    212   }
    213 
    214   std::vector<uint8_t> n_contour_stream_;
    215   std::vector<uint8_t> n_points_stream_;
    216   std::vector<uint8_t> flag_byte_stream_;
    217   std::vector<uint8_t> composite_stream_;
    218   std::vector<uint8_t> bbox_bitmap_;
    219   std::vector<uint8_t> bbox_stream_;
    220   std::vector<uint8_t> glyph_stream_;
    221   std::vector<uint8_t> instruction_stream_;
    222   bool sbbox_;
    223   bool cbbox_;
    224   int n_glyphs_;
    225 };
    226 
    227 }  // namespace
    228 
    229 bool TransformGlyfAndLocaTables(Font* font) {
    230   Font::Table* transformed_glyf = &font->tables[kGlyfTableTag ^ 0x80808080];
    231   Font::Table* transformed_loca = &font->tables[kLocaTableTag ^ 0x80808080];
    232 
    233   int num_glyphs = NumGlyphs(*font);
    234   GlyfEncoder encoder(num_glyphs);
    235   for (int i = 0; i < num_glyphs; ++i) {
    236     Glyph glyph;
    237     const uint8_t* glyph_data;
    238     size_t glyph_size;
    239     if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) ||
    240         (glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) {
    241       return FONT_COMPRESSION_FAILURE();
    242     }
    243     encoder.Encode(i, glyph);
    244   }
    245   encoder.GetTransformedGlyfBytes(&transformed_glyf->buffer);
    246 
    247   const Font::Table* head_table = font->FindTable(kHeadTableTag);
    248   if (head_table == NULL || head_table->length < 52) {
    249     return FONT_COMPRESSION_FAILURE();
    250   }
    251   transformed_glyf->buffer[7] = head_table->data[51];  // index_format
    252 
    253   transformed_glyf->tag = kGlyfTableTag ^ 0x80808080;
    254   transformed_glyf->length = transformed_glyf->buffer.size();
    255   transformed_glyf->data = transformed_glyf->buffer.data();
    256 
    257   transformed_loca->tag = kLocaTableTag ^ 0x80808080;
    258   transformed_loca->length = 0;
    259   transformed_loca->data = NULL;
    260 
    261   return true;
    262 }
    263 
    264 } // namespace woff2
    265