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