OLD | NEW |
1 // Copyright 2013 Google Inc. All Rights Reserved. | 1 // Copyright 2013 Google Inc. All Rights Reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with 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 | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 transformed_glyf->length = transformed_glyf->buffer.size(); | 283 transformed_glyf->length = transformed_glyf->buffer.size(); |
284 transformed_glyf->data = transformed_glyf->buffer.data(); | 284 transformed_glyf->data = transformed_glyf->buffer.data(); |
285 | 285 |
286 transformed_loca->tag = kLocaTableTag ^ 0x80808080; | 286 transformed_loca->tag = kLocaTableTag ^ 0x80808080; |
287 transformed_loca->length = 0; | 287 transformed_loca->length = 0; |
288 transformed_loca->data = NULL; | 288 transformed_loca->data = NULL; |
289 | 289 |
290 return true; | 290 return true; |
291 } | 291 } |
292 | 292 |
| 293 // See https://www.microsoft.com/typography/otspec/hmtx.htm |
| 294 // See WOFF2 spec, 5.4. Transformed hmtx table format |
| 295 bool TransformHmtxTable(Font* font) { |
| 296 const Font::Table* glyf_table = font->FindTable(kGlyfTableTag); |
| 297 const Font::Table* hmtx_table = font->FindTable(kHmtxTableTag); |
| 298 const Font::Table* hhea_table = font->FindTable(kHheaTableTag); |
| 299 |
| 300 // If you don't have hmtx or a glyf not much is going to happen here |
| 301 if (hmtx_table == NULL || glyf_table == NULL) { |
| 302 return true; |
| 303 } |
| 304 |
| 305 // hmtx without hhea doesn't make sense |
| 306 if (hhea_table == NULL) { |
| 307 return FONT_COMPRESSION_FAILURE(); |
| 308 } |
| 309 |
| 310 // Skip 34 to reach 'hhea' numberOfHMetrics |
| 311 Buffer hhea_buf(hhea_table->data, hhea_table->length); |
| 312 uint16_t num_hmetrics; |
| 313 if (!hhea_buf.Skip(34) || !hhea_buf.ReadU16(&num_hmetrics)) { |
| 314 return FONT_COMPRESSION_FAILURE(); |
| 315 } |
| 316 |
| 317 // Must have at least one hMetric |
| 318 if (num_hmetrics < 1) { |
| 319 return FONT_COMPRESSION_FAILURE(); |
| 320 } |
| 321 |
| 322 int num_glyphs = NumGlyphs(*font); |
| 323 |
| 324 // Most fonts can be transformed; assume it's a go until proven otherwise |
| 325 std::vector<uint16_t> advance_widths; |
| 326 std::vector<int16_t> proportional_lsbs; |
| 327 std::vector<int16_t> monospace_lsbs; |
| 328 |
| 329 bool remove_proportional_lsb = true; |
| 330 bool remove_monospace_lsb = (num_glyphs - num_hmetrics) > 0; |
| 331 |
| 332 Buffer hmtx_buf(hmtx_table->data, hmtx_table->length); |
| 333 for (int i = 0; i < num_glyphs; i++) { |
| 334 Glyph glyph; |
| 335 const uint8_t* glyph_data; |
| 336 size_t glyph_size; |
| 337 if (!GetGlyphData(*font, i, &glyph_data, &glyph_size) || |
| 338 (glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) { |
| 339 return FONT_COMPRESSION_FAILURE(); |
| 340 } |
| 341 |
| 342 uint16_t advance_width = 0; |
| 343 int16_t lsb = 0; |
| 344 |
| 345 if (i < num_hmetrics) { |
| 346 // [0, num_hmetrics) are proportional hMetrics |
| 347 if (!hmtx_buf.ReadU16(&advance_width)) { |
| 348 return FONT_COMPRESSION_FAILURE(); |
| 349 } |
| 350 |
| 351 if (!hmtx_buf.ReadS16(&lsb)) { |
| 352 return FONT_COMPRESSION_FAILURE(); |
| 353 } |
| 354 |
| 355 if (glyph_size > 0 && glyph.x_min != lsb) { |
| 356 remove_proportional_lsb = false; |
| 357 } |
| 358 |
| 359 advance_widths.push_back(advance_width); |
| 360 proportional_lsbs.push_back(lsb); |
| 361 } else { |
| 362 // [num_hmetrics, num_glyphs) are monospace leftSideBearing's |
| 363 if (!hmtx_buf.ReadS16(&lsb)) { |
| 364 return FONT_COMPRESSION_FAILURE(); |
| 365 } |
| 366 if (glyph_size > 0 && glyph.x_min != lsb) { |
| 367 remove_monospace_lsb = false; |
| 368 } |
| 369 monospace_lsbs.push_back(lsb); |
| 370 } |
| 371 |
| 372 // If we know we can't optimize, bail out completely |
| 373 if (!remove_proportional_lsb && !remove_monospace_lsb) { |
| 374 return true; |
| 375 } |
| 376 } |
| 377 |
| 378 Font::Table* transformed_hmtx = &font->tables[kHmtxTableTag ^ 0x80808080]; |
| 379 |
| 380 uint8_t flags = 0; |
| 381 size_t transformed_size = 1 + 2 * advance_widths.size(); |
| 382 if (remove_proportional_lsb) { |
| 383 flags |= 1; |
| 384 } else { |
| 385 transformed_size += 2 * proportional_lsbs.size(); |
| 386 } |
| 387 if (remove_monospace_lsb) { |
| 388 flags |= 1 << 1; |
| 389 } else { |
| 390 transformed_size += 2 * monospace_lsbs.size(); |
| 391 } |
| 392 |
| 393 transformed_hmtx->buffer.reserve(transformed_size); |
| 394 std::vector<uint8_t>* out = &transformed_hmtx->buffer; |
| 395 WriteBytes(out, &flags, 1); |
| 396 for (uint16_t advance_width : advance_widths) { |
| 397 WriteUShort(out, advance_width); |
| 398 } |
| 399 |
| 400 if (!remove_proportional_lsb) { |
| 401 for (int16_t lsb : proportional_lsbs) { |
| 402 WriteUShort(out, lsb); |
| 403 } |
| 404 } |
| 405 if (!remove_monospace_lsb) { |
| 406 for (int16_t lsb : monospace_lsbs) { |
| 407 WriteUShort(out, lsb); |
| 408 } |
| 409 } |
| 410 |
| 411 transformed_hmtx->tag = kHmtxTableTag ^ 0x80808080; |
| 412 transformed_hmtx->flag_byte = 1 << 6; |
| 413 transformed_hmtx->length = transformed_hmtx->buffer.size(); |
| 414 transformed_hmtx->data = transformed_hmtx->buffer.data(); |
| 415 |
| 416 |
| 417 return true; |
| 418 } |
| 419 |
293 } // namespace woff2 | 420 } // namespace woff2 |
OLD | NEW |