Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include <ctype.h> | 8 #include <ctype.h> |
| 9 | 9 |
| 10 #include "SkData.h" | 10 #include "SkData.h" |
| (...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 335 appendAdvance(advanceInfo->fAdvance[0], emSize, result); | 335 appendAdvance(advanceInfo->fAdvance[0], emSize, result); |
| 336 break; | 336 break; |
| 337 } | 337 } |
| 338 } | 338 } |
| 339 } | 339 } |
| 340 return result; | 340 return result; |
| 341 } | 341 } |
| 342 | 342 |
| 343 } // namespace | 343 } // namespace |
| 344 | 344 |
| 345 static void append_tounicode_header(SkDynamicMemoryWStream* cmap) { | 345 static void append_tounicode_header(SkDynamicMemoryWStream* cmap, |
| 346 uint16_t firstGlypthID, | |
| 347 uint16_t lastGlypthID) { | |
| 346 // 12 dict begin: 12 is an Adobe-suggested value. Shall not change. | 348 // 12 dict begin: 12 is an Adobe-suggested value. Shall not change. |
| 347 // It's there to prevent old version Adobe Readers from malfunctioning. | 349 // It's there to prevent old version Adobe Readers from malfunctioning. |
| 348 const char* kHeader = | 350 const char* kHeader = |
| 349 "/CIDInit /ProcSet findresource begin\n" | 351 "/CIDInit /ProcSet findresource begin\n" |
| 350 "12 dict begin\n" | 352 "12 dict begin\n" |
| 351 "begincmap\n"; | 353 "begincmap\n"; |
| 352 cmap->writeText(kHeader); | 354 cmap->writeText(kHeader); |
| 353 | 355 |
| 354 // The /CIDSystemInfo must be consistent to the one in | 356 // The /CIDSystemInfo must be consistent to the one in |
| 355 // SkPDFFont::populateCIDFont(). | 357 // SkPDFFont::populateCIDFont(). |
| 356 // We can not pass over the system info object here because the format is | 358 // We can not pass over the system info object here because the format is |
| 357 // different. This is not a reference object. | 359 // different. This is not a reference object. |
| 358 const char* kSysInfo = | 360 const char* kSysInfo = |
| 359 "/CIDSystemInfo\n" | 361 "/CIDSystemInfo\n" |
| 360 "<< /Registry (Adobe)\n" | 362 "<< /Registry (Adobe)\n" |
| 361 "/Ordering (UCS)\n" | 363 "/Ordering (UCS)\n" |
| 362 "/Supplement 0\n" | 364 "/Supplement 0\n" |
| 363 ">> def\n"; | 365 ">> def\n"; |
| 364 cmap->writeText(kSysInfo); | 366 cmap->writeText(kSysInfo); |
| 365 | 367 |
| 366 // The CMapName must be consistent to /CIDSystemInfo above. | 368 // The CMapName must be consistent to /CIDSystemInfo above. |
| 367 // /CMapType 2 means ToUnicode. | 369 // /CMapType 2 means ToUnicode. |
| 368 // We specify codespacerange from 0x0000 to 0xFFFF because we convert our | 370 // Codespace range just tells the PDF processor the valid range. |
| 369 // code table from unsigned short (16-bits). Codespace range just tells the | 371 const char* kTypeInfoHeader = |
| 370 // PDF processor the valid range. It does not matter whether a complete | |
| 371 // mapping is provided or not. | |
| 372 const char* kTypeInfo = | |
| 373 "/CMapName /Adobe-Identity-UCS def\n" | 372 "/CMapName /Adobe-Identity-UCS def\n" |
| 374 "/CMapType 2 def\n" | 373 "/CMapType 2 def\n" |
| 375 "1 begincodespacerange\n" | 374 "1 begincodespacerange\n"; |
| 376 "<0000> <FFFF>\n" | 375 cmap->writeText(kTypeInfoHeader); |
| 377 "endcodespacerange\n"; | 376 |
| 378 cmap->writeText(kTypeInfo); | 377 // e.g. "<0000> <FFFF>\n" |
| 378 SkString range; | |
| 379 range.appendf("<%04X> <%04X>\n", firstGlypthID, lastGlypthID); | |
| 380 cmap->writeText(range.c_str()); | |
| 381 | |
| 382 const char* kTypeInfoFooter = "endcodespacerange\n"; | |
| 383 cmap->writeText(kTypeInfoFooter); | |
| 379 } | 384 } |
| 380 | 385 |
| 381 static void append_cmap_footer(SkDynamicMemoryWStream* cmap) { | 386 static void append_cmap_footer(SkDynamicMemoryWStream* cmap) { |
| 382 const char* kFooter = | 387 const char* kFooter = |
| 383 "endcmap\n" | 388 "endcmap\n" |
| 384 "CMapName currentdict /CMap defineresource pop\n" | 389 "CMapName currentdict /CMap defineresource pop\n" |
| 385 "end\n" | 390 "end\n" |
| 386 "end"; | 391 "end"; |
| 387 cmap->writeText(kFooter); | 392 cmap->writeText(kFooter); |
| 388 } | 393 } |
| 389 | 394 |
| 390 struct BFChar { | 395 struct BFChar { |
| 391 uint16_t fGlyphId; | 396 uint16_t fGlyphId; |
| 392 SkUnichar fUnicode; | 397 SkUnichar fUnicode; |
| 393 }; | 398 }; |
| 394 | 399 |
| 395 struct BFRange { | 400 struct BFRange { |
| 396 uint16_t fStart; | 401 uint16_t fStart; |
| 397 uint16_t fEnd; | 402 uint16_t fEnd; |
| 398 SkUnichar fUnicode; | 403 SkUnichar fUnicode; |
| 399 }; | 404 }; |
| 400 | 405 |
| 401 static void append_bfchar_section(const SkTDArray<BFChar>& bfchar, | 406 static void append_bfchar_section(const SkTDArray<BFChar>& bfchar, |
| 402 SkDynamicMemoryWStream* cmap) { | 407 SkDynamicMemoryWStream* cmap, |
| 408 uint16_t firstGlypthID, | |
| 409 uint16_t lastGlypthID) { | |
| 410 int32_t i = 0; | |
| 411 while (i < bfchar.count() && bfchar[i].fGlyphId < firstGlypthID) { | |
|
vandebo (ex-Chrome)
2013/09/04 22:07:53
While the end point probably doesn't take a lot of
edisonn
2013/09/06 18:54:38
N/A - moved filtering in the caller - fastest way
| |
| 412 i++; | |
| 413 } | |
| 414 | |
| 403 // PDF spec defines that every bf* list can have at most 100 entries. | 415 // PDF spec defines that every bf* list can have at most 100 entries. |
| 404 for (int i = 0; i < bfchar.count(); i += 100) { | 416 for (; i < bfchar.count(); i += 100) { |
| 417 if (bfchar[i].fGlyphId > lastGlypthID) { | |
| 418 return; | |
| 419 } | |
| 420 | |
| 405 int count = bfchar.count() - i; | 421 int count = bfchar.count() - i; |
| 406 count = SkMin32(count, 100); | 422 count = SkMin32(count, 100); |
| 423 // TODO(edisonn): perf, might be better to do a bsearch, but I think | |
| 424 // most of the times, we will have enough data to stop imediately. | |
| 425 while (count > 0 && bfchar[i + count - 1].fGlyphId > lastGlypthID) { | |
| 426 count--; | |
| 427 } | |
| 428 | |
| 429 if (count == 0) { | |
|
vandebo (ex-Chrome)
2013/09/04 22:07:53
Not possible, count must be >= 1 because of the ch
edisonn
2013/09/06 18:54:38
On 2013/09/04 22:07:53, vandebo wrote:
dead code
| |
| 430 return; | |
| 431 } | |
| 432 | |
| 407 cmap->writeDecAsText(count); | 433 cmap->writeDecAsText(count); |
| 408 cmap->writeText(" beginbfchar\n"); | 434 cmap->writeText(" beginbfchar\n"); |
| 409 for (int j = 0; j < count; ++j) { | 435 for (int j = 0; j < count; ++j) { |
| 410 cmap->writeText("<"); | 436 cmap->writeText("<"); |
| 411 cmap->writeHexAsText(bfchar[i + j].fGlyphId, 4); | 437 cmap->writeHexAsText(bfchar[i + j].fGlyphId, 4); |
| 412 cmap->writeText("> <"); | 438 cmap->writeText("> <"); |
| 413 cmap->writeHexAsText(bfchar[i + j].fUnicode, 4); | 439 cmap->writeHexAsText(bfchar[i + j].fUnicode, 4); |
| 414 cmap->writeText(">\n"); | 440 cmap->writeText(">\n"); |
| 415 } | 441 } |
| 416 cmap->writeText("endbfchar\n"); | 442 cmap->writeText("endbfchar\n"); |
| 417 } | 443 } |
| 418 } | 444 } |
| 419 | 445 |
| 420 static void append_bfrange_section(const SkTDArray<BFRange>& bfrange, | 446 static void append_bfrange_section(const SkTDArray<BFRange>& bfrange, |
| 421 SkDynamicMemoryWStream* cmap) { | 447 SkDynamicMemoryWStream* cmap, |
| 448 uint16_t firstGlypthID, | |
| 449 uint16_t lastGlypthID) { | |
| 450 int32_t i = 0; | |
| 451 while (i < bfrange.count() && bfrange[i].fEnd < firstGlypthID) { | |
|
vandebo (ex-Chrome)
2013/09/04 22:07:53
Same here re SkTSearch
edisonn
2013/09/06 18:54:38
dead code
On 2013/09/04 22:07:53, vandebo wrote:
| |
| 452 i++; | |
| 453 } | |
| 454 | |
| 422 // PDF spec defines that every bf* list can have at most 100 entries. | 455 // PDF spec defines that every bf* list can have at most 100 entries. |
| 423 for (int i = 0; i < bfrange.count(); i += 100) { | 456 for (; i < bfrange.count(); i += 100) { |
| 457 if (bfrange[i].fStart > lastGlypthID) { | |
| 458 return; | |
| 459 } | |
| 460 | |
| 424 int count = bfrange.count() - i; | 461 int count = bfrange.count() - i; |
| 425 count = SkMin32(count, 100); | 462 count = SkMin32(count, 100); |
| 426 cmap->writeDecAsText(count); | 463 cmap->writeDecAsText(count); |
| 427 cmap->writeText(" beginbfrange\n"); | 464 cmap->writeText(" beginbfrange\n"); |
| 465 | |
| 466 // first range might be chopped. | |
| 467 uint16_t start = SkMax32(firstGlypthID, bfrange[i].fStart); | |
| 468 | |
| 428 for (int j = 0; j < count; ++j) { | 469 for (int j = 0; j < count; ++j) { |
| 470 if (bfrange[i + j].fStart > lastGlypthID) { | |
| 471 break; | |
| 472 } | |
| 429 cmap->writeText("<"); | 473 cmap->writeText("<"); |
| 430 cmap->writeHexAsText(bfrange[i + j].fStart, 4); | 474 cmap->writeHexAsText(j == 0 ? start : bfrange[i + j].fStart, 4); |
|
vandebo (ex-Chrome)
2013/09/04 22:07:53
It's probably the same computational cost to do th
edisonn
2013/09/06 18:54:38
dead code
| |
| 431 cmap->writeText("> <"); | 475 cmap->writeText("> <"); |
| 432 cmap->writeHexAsText(bfrange[i + j].fEnd, 4); | 476 cmap->writeHexAsText(SkMin32(bfrange[i + j].fEnd, lastGlypthID), 4); |
| 433 cmap->writeText("> <"); | 477 cmap->writeText("> <"); |
| 434 cmap->writeHexAsText(bfrange[i + j].fUnicode, 4); | 478 cmap->writeHexAsText(bfrange[i + j].fUnicode, 4); |
| 435 cmap->writeText(">\n"); | 479 cmap->writeText(">\n"); |
| 436 } | 480 } |
| 437 cmap->writeText("endbfrange\n"); | 481 cmap->writeText("endbfrange\n"); |
| 438 } | 482 } |
| 439 } | 483 } |
| 440 | 484 |
| 441 // Generate <bfchar> and <bfrange> table according to PDF spec 1.4 and Adobe | 485 // Generate <bfchar> and <bfrange> table according to PDF spec 1.4 and Adobe |
| 442 // Technote 5014. | 486 // Technote 5014. |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 462 // the spec does not mention how will this kind of conflict being resolved. | 506 // the spec does not mention how will this kind of conflict being resolved. |
| 463 // | 507 // |
| 464 // For the worst case (having 65536 continuous unicode and we use every other | 508 // For the worst case (having 65536 continuous unicode and we use every other |
| 465 // one of them), the possible savings by aggressive optimization is 416KB | 509 // one of them), the possible savings by aggressive optimization is 416KB |
| 466 // pre-compressed and does not provide enough motivation for implementation. | 510 // pre-compressed and does not provide enough motivation for implementation. |
| 467 | 511 |
| 468 // FIXME: this should be in a header so that it is separately testable | 512 // FIXME: this should be in a header so that it is separately testable |
| 469 // ( see caller in tests/ToUnicode.cpp ) | 513 // ( see caller in tests/ToUnicode.cpp ) |
| 470 void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode, | 514 void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode, |
| 471 const SkPDFGlyphSet* subset, | 515 const SkPDFGlyphSet* subset, |
| 472 SkDynamicMemoryWStream* cmap); | 516 SkDynamicMemoryWStream* cmap, |
| 517 uint16_t firstGlypthID = 0x0000, | |
|
vandebo (ex-Chrome)
2013/09/04 22:07:53
No need for defaults, these args are always passed
edisonn
2013/09/06 18:54:38
Done.
| |
| 518 uint16_t lastGlypthID = 0xffff); | |
| 473 | 519 |
| 474 void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode, | 520 void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode, |
| 475 const SkPDFGlyphSet* subset, | 521 const SkPDFGlyphSet* subset, |
| 476 SkDynamicMemoryWStream* cmap) { | 522 SkDynamicMemoryWStream* cmap, |
| 523 uint16_t firstGlypthID, | |
| 524 uint16_t lastGlypthID) { | |
| 477 if (glyphToUnicode.isEmpty()) { | 525 if (glyphToUnicode.isEmpty()) { |
| 478 return; | 526 return; |
| 479 } | 527 } |
| 480 | 528 |
| 481 SkTDArray<BFChar> bfcharEntries; | 529 SkTDArray<BFChar> bfcharEntries; |
| 482 SkTDArray<BFRange> bfrangeEntries; | 530 SkTDArray<BFRange> bfrangeEntries; |
| 483 | 531 |
| 484 BFRange currentRangeEntry = {0, 0, 0}; | 532 BFRange currentRangeEntry = {0, 0, 0}; |
| 485 bool rangeEmpty = true; | 533 bool rangeEmpty = true; |
| 486 const int count = glyphToUnicode.count(); | 534 const int count = glyphToUnicode.count(); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 513 if (rangeEmpty) { | 561 if (rangeEmpty) { |
| 514 currentRangeEntry.fStart = i; | 562 currentRangeEntry.fStart = i; |
| 515 currentRangeEntry.fUnicode = glyphToUnicode[i]; | 563 currentRangeEntry.fUnicode = glyphToUnicode[i]; |
| 516 rangeEmpty = false; | 564 rangeEmpty = false; |
| 517 } | 565 } |
| 518 } | 566 } |
| 519 } | 567 } |
| 520 | 568 |
| 521 // The spec requires all bfchar entries for a font must come before bfrange | 569 // The spec requires all bfchar entries for a font must come before bfrange |
| 522 // entries. | 570 // entries. |
| 523 append_bfchar_section(bfcharEntries, cmap); | 571 append_bfchar_section(bfcharEntries, cmap, firstGlypthID, lastGlypthID); |
| 524 append_bfrange_section(bfrangeEntries, cmap); | 572 append_bfrange_section(bfrangeEntries, cmap, firstGlypthID, lastGlypthID); |
| 525 } | 573 } |
| 526 | 574 |
| 527 static SkPDFStream* generate_tounicode_cmap( | 575 static SkPDFStream* generate_tounicode_cmap( |
| 528 const SkTDArray<SkUnichar>& glyphToUnicode, | 576 const SkTDArray<SkUnichar>& glyphToUnicode, |
| 529 const SkPDFGlyphSet* subset) { | 577 const SkPDFGlyphSet* subset, |
| 578 uint16_t firstGlypthID, | |
| 579 uint16_t lastGlypthID) { | |
| 530 SkDynamicMemoryWStream cmap; | 580 SkDynamicMemoryWStream cmap; |
| 531 append_tounicode_header(&cmap); | 581 append_tounicode_header(&cmap, firstGlypthID, lastGlypthID); |
| 532 append_cmap_sections(glyphToUnicode, subset, &cmap); | 582 append_cmap_sections(glyphToUnicode, subset, &cmap, |
| 583 firstGlypthID, lastGlypthID); | |
| 533 append_cmap_footer(&cmap); | 584 append_cmap_footer(&cmap); |
| 534 SkAutoTUnref<SkMemoryStream> cmapStream(new SkMemoryStream()); | 585 SkAutoTUnref<SkMemoryStream> cmapStream(new SkMemoryStream()); |
| 535 cmapStream->setData(cmap.copyToData())->unref(); | 586 cmapStream->setData(cmap.copyToData())->unref(); |
| 536 return new SkPDFStream(cmapStream.get()); | 587 return new SkPDFStream(cmapStream.get()); |
| 537 } | 588 } |
| 538 | 589 |
| 539 #if defined (SK_SFNTLY_SUBSETTER) | 590 #if defined (SK_SFNTLY_SUBSETTER) |
| 540 static void sk_delete_array(const void* ptr, size_t, void*) { | 591 static void sk_delete_array(const void* ptr, size_t, void*) { |
| 541 // Use C-style cast to cast away const and cast type simultaneously. | 592 // Use C-style cast to cast away const and cast type simultaneously. |
| 542 delete[] (unsigned char*)ptr; | 593 delete[] (unsigned char*)ptr; |
| (...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1007 : fFont(font), | 1058 : fFont(font), |
| 1008 fFontID(fontID), | 1059 fFontID(fontID), |
| 1009 fGlyphID(glyphID) { | 1060 fGlyphID(glyphID) { |
| 1010 } | 1061 } |
| 1011 | 1062 |
| 1012 void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) { | 1063 void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) { |
| 1013 if (fFontInfo == NULL || fFontInfo->fGlyphToUnicode.begin() == NULL) { | 1064 if (fFontInfo == NULL || fFontInfo->fGlyphToUnicode.begin() == NULL) { |
| 1014 return; | 1065 return; |
| 1015 } | 1066 } |
| 1016 SkAutoTUnref<SkPDFStream> pdfCmap( | 1067 SkAutoTUnref<SkPDFStream> pdfCmap( |
| 1017 generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset)); | 1068 generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset, |
| 1069 firstGlyphID(), lastGlyphID())); | |
| 1018 addResource(pdfCmap.get()); | 1070 addResource(pdfCmap.get()); |
| 1019 insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref(); | 1071 insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref(); |
| 1020 } | 1072 } |
| 1021 | 1073 |
| 1022 /////////////////////////////////////////////////////////////////////////////// | 1074 /////////////////////////////////////////////////////////////////////////////// |
| 1023 // class SkPDFType0Font | 1075 // class SkPDFType0Font |
| 1024 /////////////////////////////////////////////////////////////////////////////// | 1076 /////////////////////////////////////////////////////////////////////////////// |
| 1025 | 1077 |
| 1026 SkPDFType0Font::SkPDFType0Font(SkAdvancedTypefaceMetrics* info, | 1078 SkPDFType0Font::SkPDFType0Font(SkAdvancedTypefaceMetrics* info, |
| 1027 SkTypeface* typeface) | 1079 SkTypeface* typeface) |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1408 | 1460 |
| 1409 insert("FontBBox", makeFontBBox(bbox, 1000))->unref(); | 1461 insert("FontBBox", makeFontBBox(bbox, 1000))->unref(); |
| 1410 insertInt("FirstChar", firstGlyphID()); | 1462 insertInt("FirstChar", firstGlyphID()); |
| 1411 insertInt("LastChar", lastGlyphID()); | 1463 insertInt("LastChar", lastGlyphID()); |
| 1412 insert("Widths", widthArray.get()); | 1464 insert("Widths", widthArray.get()); |
| 1413 insertName("CIDToGIDMap", "Identity"); | 1465 insertName("CIDToGIDMap", "Identity"); |
| 1414 | 1466 |
| 1415 populateToUnicodeTable(NULL); | 1467 populateToUnicodeTable(NULL); |
| 1416 return true; | 1468 return true; |
| 1417 } | 1469 } |
| OLD | NEW |