transform.cc (13696B)
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 /* Library for preprocessing fonts as part of the WOFF 2.0 conversion. */ 8 9 #include "./transform.h" 10 11 #include <complex> // for std::abs 12 13 #include "./buffer.h" 14 #include "./font.h" 15 #include "./glyph.h" 16 #include "./table_tags.h" 17 #include "./variable_length.h" 18 19 namespace woff2 { 20 21 namespace { 22 23 const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0; 24 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8; 25 const int FLAG_OVERLAP_SIMPLE_BITMAP = 1 << 0; 26 27 void WriteBytes(std::vector<uint8_t>* out, const uint8_t* data, size_t len) { 28 if (len == 0) return; 29 size_t offset = out->size(); 30 out->resize(offset + len); 31 memcpy(&(*out)[offset], data, len); 32 } 33 34 void WriteBytes(std::vector<uint8_t>* out, const std::vector<uint8_t>& in) { 35 for (size_t i = 0; i < in.size(); ++i) { 36 out->push_back(in[i]); 37 } 38 } 39 40 void WriteUShort(std::vector<uint8_t>* out, int value) { 41 out->push_back(value >> 8); 42 out->push_back(value & 255); 43 } 44 45 void WriteLong(std::vector<uint8_t>* out, int value) { 46 out->push_back((value >> 24) & 255); 47 out->push_back((value >> 16) & 255); 48 out->push_back((value >> 8) & 255); 49 out->push_back(value & 255); 50 } 51 52 // Glyf table preprocessing, based on 53 // GlyfEncoder.java 54 class GlyfEncoder { 55 public: 56 explicit GlyfEncoder(int num_glyphs) 57 : n_glyphs_(num_glyphs) { 58 bbox_bitmap_.resize(((num_glyphs + 31) >> 5) << 2); 59 } 60 61 bool Encode(int glyph_id, const Glyph& glyph) { 62 if (glyph.composite_data_size > 0) { 63 WriteCompositeGlyph(glyph_id, glyph); 64 } else if (glyph.contours.size() > 0) { 65 WriteSimpleGlyph(glyph_id, glyph); 66 } else { 67 WriteUShort(&n_contour_stream_, 0); 68 } 69 return true; 70 } 71 72 void GetTransformedGlyfBytes(std::vector<uint8_t>* result) { 73 WriteUShort(result, 0); // Version 74 WriteUShort(result, overlap_bitmap_.empty() 75 ? 0x00 76 : FLAG_OVERLAP_SIMPLE_BITMAP); // Flags 77 WriteUShort(result, n_glyphs_); 78 WriteUShort(result, 0); // index_format, will be set later 79 WriteLong(result, n_contour_stream_.size()); 80 WriteLong(result, n_points_stream_.size()); 81 WriteLong(result, flag_byte_stream_.size()); 82 WriteLong(result, glyph_stream_.size()); 83 WriteLong(result, composite_stream_.size()); 84 WriteLong(result, bbox_bitmap_.size() + bbox_stream_.size()); 85 WriteLong(result, instruction_stream_.size()); 86 WriteBytes(result, n_contour_stream_); 87 WriteBytes(result, n_points_stream_); 88 WriteBytes(result, flag_byte_stream_); 89 WriteBytes(result, glyph_stream_); 90 WriteBytes(result, composite_stream_); 91 WriteBytes(result, bbox_bitmap_); 92 WriteBytes(result, bbox_stream_); 93 WriteBytes(result, instruction_stream_); 94 if (!overlap_bitmap_.empty()) { 95 WriteBytes(result, overlap_bitmap_); 96 } 97 } 98 99 private: 100 void WriteInstructions(const Glyph& glyph) { 101 Write255UShort(&glyph_stream_, glyph.instructions_size); 102 WriteBytes(&instruction_stream_, 103 glyph.instructions_data, glyph.instructions_size); 104 } 105 106 bool ShouldWriteSimpleGlyphBbox(const Glyph& glyph) { 107 if (glyph.contours.empty() || glyph.contours[0].empty()) { 108 return glyph.x_min || glyph.y_min || glyph.x_max || glyph.y_max; 109 } 110 111 int16_t x_min = glyph.contours[0][0].x; 112 int16_t y_min = glyph.contours[0][0].y; 113 int16_t x_max = x_min; 114 int16_t y_max = y_min; 115 for (const auto& contour : glyph.contours) { 116 for (const auto& point : contour) { 117 if (point.x < x_min) x_min = point.x; 118 if (point.x > x_max) x_max = point.x; 119 if (point.y < y_min) y_min = point.y; 120 if (point.y > y_max) y_max = point.y; 121 } 122 } 123 124 if (glyph.x_min != x_min) 125 return true; 126 if (glyph.y_min != y_min) 127 return true; 128 if (glyph.x_max != x_max) 129 return true; 130 if (glyph.y_max != y_max) 131 return true; 132 133 return false; 134 } 135 136 void WriteSimpleGlyph(int glyph_id, const Glyph& glyph) { 137 if (glyph.overlap_simple_flag_set) { 138 EnsureOverlapBitmap(); 139 overlap_bitmap_[glyph_id >> 3] |= 0x80 >> (glyph_id & 7); 140 } 141 int num_contours = glyph.contours.size(); 142 WriteUShort(&n_contour_stream_, num_contours); 143 if (ShouldWriteSimpleGlyphBbox(glyph)) { 144 WriteBbox(glyph_id, glyph); 145 } 146 for (int i = 0; i < num_contours; i++) { 147 Write255UShort(&n_points_stream_, glyph.contours[i].size()); 148 } 149 int lastX = 0; 150 int lastY = 0; 151 for (int i = 0; i < num_contours; i++) { 152 int num_points = glyph.contours[i].size(); 153 for (int j = 0; j < num_points; j++) { 154 int x = glyph.contours[i][j].x; 155 int y = glyph.contours[i][j].y; 156 int dx = x - lastX; 157 int dy = y - lastY; 158 WriteTriplet(glyph.contours[i][j].on_curve, dx, dy); 159 lastX = x; 160 lastY = y; 161 } 162 } 163 if (num_contours > 0) { 164 WriteInstructions(glyph); 165 } 166 } 167 168 void WriteCompositeGlyph(int glyph_id, const Glyph& glyph) { 169 WriteUShort(&n_contour_stream_, -1); 170 WriteBbox(glyph_id, glyph); 171 WriteBytes(&composite_stream_, 172 glyph.composite_data, 173 glyph.composite_data_size); 174 if (glyph.have_instructions) { 175 WriteInstructions(glyph); 176 } 177 } 178 179 void WriteBbox(int glyph_id, const Glyph& glyph) { 180 bbox_bitmap_[glyph_id >> 3] |= 0x80 >> (glyph_id & 7); 181 WriteUShort(&bbox_stream_, glyph.x_min); 182 WriteUShort(&bbox_stream_, glyph.y_min); 183 WriteUShort(&bbox_stream_, glyph.x_max); 184 WriteUShort(&bbox_stream_, glyph.y_max); 185 } 186 187 void WriteTriplet(bool on_curve, int x, int y) { 188 int abs_x = std::abs(x); 189 int abs_y = std::abs(y); 190 int on_curve_bit = on_curve ? 0 : 128; 191 int x_sign_bit = (x < 0) ? 0 : 1; 192 int y_sign_bit = (y < 0) ? 0 : 1; 193 int xy_sign_bits = x_sign_bit + 2 * y_sign_bit; 194 if (x == 0 && abs_y < 1280) { 195 flag_byte_stream_.push_back(on_curve_bit + 196 ((abs_y & 0xf00) >> 7) + y_sign_bit); 197 glyph_stream_.push_back(abs_y & 0xff); 198 } else if (y == 0 && abs_x < 1280) { 199 flag_byte_stream_.push_back(on_curve_bit + 10 + 200 ((abs_x & 0xf00) >> 7) + x_sign_bit); 201 glyph_stream_.push_back(abs_x & 0xff); 202 } else if (abs_x < 65 && abs_y < 65) { 203 flag_byte_stream_.push_back(on_curve_bit + 20 + 204 ((abs_x - 1) & 0x30) + 205 (((abs_y - 1) & 0x30) >> 2) + 206 xy_sign_bits); 207 glyph_stream_.push_back((((abs_x - 1) & 0xf) << 4) | ((abs_y - 1) & 0xf)); 208 } else if (abs_x < 769 && abs_y < 769) { 209 flag_byte_stream_.push_back(on_curve_bit + 84 + 210 12 * (((abs_x - 1) & 0x300) >> 8) + 211 (((abs_y - 1) & 0x300) >> 6) + xy_sign_bits); 212 glyph_stream_.push_back((abs_x - 1) & 0xff); 213 glyph_stream_.push_back((abs_y - 1) & 0xff); 214 } else if (abs_x < 4096 && abs_y < 4096) { 215 flag_byte_stream_.push_back(on_curve_bit + 120 + xy_sign_bits); 216 glyph_stream_.push_back(abs_x >> 4); 217 glyph_stream_.push_back(((abs_x & 0xf) << 4) | (abs_y >> 8)); 218 glyph_stream_.push_back(abs_y & 0xff); 219 } else { 220 flag_byte_stream_.push_back(on_curve_bit + 124 + xy_sign_bits); 221 glyph_stream_.push_back(abs_x >> 8); 222 glyph_stream_.push_back(abs_x & 0xff); 223 glyph_stream_.push_back(abs_y >> 8); 224 glyph_stream_.push_back(abs_y & 0xff); 225 } 226 } 227 228 void EnsureOverlapBitmap() { 229 if (overlap_bitmap_.empty()) { 230 overlap_bitmap_.resize((n_glyphs_ + 7) >> 3); 231 } 232 } 233 234 std::vector<uint8_t> n_contour_stream_; 235 std::vector<uint8_t> n_points_stream_; 236 std::vector<uint8_t> flag_byte_stream_; 237 std::vector<uint8_t> composite_stream_; 238 std::vector<uint8_t> bbox_bitmap_; 239 std::vector<uint8_t> bbox_stream_; 240 std::vector<uint8_t> glyph_stream_; 241 std::vector<uint8_t> instruction_stream_; 242 std::vector<uint8_t> overlap_bitmap_; 243 int n_glyphs_; 244 }; 245 246 } // namespace 247 248 bool TransformGlyfAndLocaTables(Font* font) { 249 // no transform for CFF 250 const Font::Table* glyf_table = font->FindTable(kGlyfTableTag); 251 const Font::Table* loca_table = font->FindTable(kLocaTableTag); 252 253 // If you don't have glyf/loca this transform isn't very interesting 254 if (loca_table == NULL && glyf_table == NULL) { 255 return true; 256 } 257 // It would be best if you didn't have just one of glyf/loca 258 if ((glyf_table == NULL) != (loca_table == NULL)) { 259 return FONT_COMPRESSION_FAILURE(); 260 } 261 // Must share neither or both loca & glyf 262 if (loca_table->IsReused() != glyf_table->IsReused()) { 263 return FONT_COMPRESSION_FAILURE(); 264 } 265 if (loca_table->IsReused()) { 266 return true; 267 } 268 269 Font::Table* transformed_glyf = &font->tables[kGlyfTableTag ^ 0x80808080]; 270 Font::Table* transformed_loca = &font->tables[kLocaTableTag ^ 0x80808080]; 271 272 int num_glyphs = NumGlyphs(*font); 273 GlyfEncoder encoder(num_glyphs); 274 for (int i = 0; i < num_glyphs; ++i) { 275 Glyph glyph; 276 const uint8_t* glyph_data; 277 size_t glyph_size; 278 if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) || 279 (glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) { 280 return FONT_COMPRESSION_FAILURE(); 281 } 282 encoder.Encode(i, glyph); 283 } 284 encoder.GetTransformedGlyfBytes(&transformed_glyf->buffer); 285 286 const Font::Table* head_table = font->FindTable(kHeadTableTag); 287 if (head_table == NULL || head_table->length < 52) { 288 return FONT_COMPRESSION_FAILURE(); 289 } 290 transformed_glyf->buffer[7] = head_table->data[51]; // index_format 291 292 transformed_glyf->tag = kGlyfTableTag ^ 0x80808080; 293 transformed_glyf->length = transformed_glyf->buffer.size(); 294 transformed_glyf->data = transformed_glyf->buffer.data(); 295 296 transformed_loca->tag = kLocaTableTag ^ 0x80808080; 297 transformed_loca->length = 0; 298 transformed_loca->data = NULL; 299 300 return true; 301 } 302 303 // See https://www.microsoft.com/typography/otspec/hmtx.htm 304 // See WOFF2 spec, 5.4. Transformed hmtx table format 305 bool TransformHmtxTable(Font* font) { 306 const Font::Table* glyf_table = font->FindTable(kGlyfTableTag); 307 const Font::Table* hmtx_table = font->FindTable(kHmtxTableTag); 308 const Font::Table* hhea_table = font->FindTable(kHheaTableTag); 309 310 // If you don't have hmtx or a glyf not much is going to happen here 311 if (hmtx_table == NULL || glyf_table == NULL) { 312 return true; 313 } 314 315 // hmtx without hhea doesn't make sense 316 if (hhea_table == NULL) { 317 return FONT_COMPRESSION_FAILURE(); 318 } 319 320 // Skip 34 to reach 'hhea' numberOfHMetrics 321 Buffer hhea_buf(hhea_table->data, hhea_table->length); 322 uint16_t num_hmetrics; 323 if (!hhea_buf.Skip(34) || !hhea_buf.ReadU16(&num_hmetrics)) { 324 return FONT_COMPRESSION_FAILURE(); 325 } 326 327 // Must have at least one hMetric 328 if (num_hmetrics < 1) { 329 return FONT_COMPRESSION_FAILURE(); 330 } 331 332 int num_glyphs = NumGlyphs(*font); 333 334 // Most fonts can be transformed; assume it's a go until proven otherwise 335 std::vector<uint16_t> advance_widths; 336 std::vector<int16_t> proportional_lsbs; 337 std::vector<int16_t> monospace_lsbs; 338 339 bool remove_proportional_lsb = true; 340 bool remove_monospace_lsb = (num_glyphs - num_hmetrics) > 0; 341 342 Buffer hmtx_buf(hmtx_table->data, hmtx_table->length); 343 for (int i = 0; i < num_glyphs; i++) { 344 Glyph glyph; 345 const uint8_t* glyph_data; 346 size_t glyph_size; 347 if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) || 348 (glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) { 349 return FONT_COMPRESSION_FAILURE(); 350 } 351 352 uint16_t advance_width = 0; 353 int16_t lsb = 0; 354 355 if (i < num_hmetrics) { 356 // [0, num_hmetrics) are proportional hMetrics 357 if (!hmtx_buf.ReadU16(&advance_width)) { 358 return FONT_COMPRESSION_FAILURE(); 359 } 360 361 if (!hmtx_buf.ReadS16(&lsb)) { 362 return FONT_COMPRESSION_FAILURE(); 363 } 364 365 if (glyph_size > 0 && glyph.x_min != lsb) { 366 remove_proportional_lsb = false; 367 } 368 369 advance_widths.push_back(advance_width); 370 proportional_lsbs.push_back(lsb); 371 } else { 372 // [num_hmetrics, num_glyphs) are monospace leftSideBearing's 373 if (!hmtx_buf.ReadS16(&lsb)) { 374 return FONT_COMPRESSION_FAILURE(); 375 } 376 if (glyph_size > 0 && glyph.x_min != lsb) { 377 remove_monospace_lsb = false; 378 } 379 monospace_lsbs.push_back(lsb); 380 } 381 382 // If we know we can't optimize, bail out completely 383 if (!remove_proportional_lsb && !remove_monospace_lsb) { 384 return true; 385 } 386 } 387 388 Font::Table* transformed_hmtx = &font->tables[kHmtxTableTag ^ 0x80808080]; 389 390 uint8_t flags = 0; 391 size_t transformed_size = 1 + 2 * advance_widths.size(); 392 if (remove_proportional_lsb) { 393 flags |= 1; 394 } else { 395 transformed_size += 2 * proportional_lsbs.size(); 396 } 397 if (remove_monospace_lsb) { 398 flags |= 1 << 1; 399 } else { 400 transformed_size += 2 * monospace_lsbs.size(); 401 } 402 403 transformed_hmtx->buffer.reserve(transformed_size); 404 std::vector<uint8_t>* out = &transformed_hmtx->buffer; 405 WriteBytes(out, &flags, 1); 406 for (uint16_t advance_width : advance_widths) { 407 WriteUShort(out, advance_width); 408 } 409 410 if (!remove_proportional_lsb) { 411 for (int16_t lsb : proportional_lsbs) { 412 WriteUShort(out, lsb); 413 } 414 } 415 if (!remove_monospace_lsb) { 416 for (int16_t lsb : monospace_lsbs) { 417 WriteUShort(out, lsb); 418 } 419 } 420 421 transformed_hmtx->tag = kHmtxTableTag ^ 0x80808080; 422 transformed_hmtx->flag_byte = 1 << 6; 423 transformed_hmtx->length = transformed_hmtx->buffer.size(); 424 transformed_hmtx->data = transformed_hmtx->buffer.data(); 425 426 427 return true; 428 } 429 430 } // namespace woff2