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 firstGlyphID, | |
| 347 uint16_t lastGlyphID) { | |
| 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", firstGlyphID, lastGlyphID); | |
| 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 } |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 462 // the spec does not mention how will this kind of conflict being resolved. | 467 // the spec does not mention how will this kind of conflict being resolved. |
| 463 // | 468 // |
| 464 // For the worst case (having 65536 continuous unicode and we use every other | 469 // 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 | 470 // one of them), the possible savings by aggressive optimization is 416KB |
| 466 // pre-compressed and does not provide enough motivation for implementation. | 471 // pre-compressed and does not provide enough motivation for implementation. |
| 467 | 472 |
| 468 // FIXME: this should be in a header so that it is separately testable | 473 // FIXME: this should be in a header so that it is separately testable |
| 469 // ( see caller in tests/ToUnicode.cpp ) | 474 // ( see caller in tests/ToUnicode.cpp ) |
| 470 void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode, | 475 void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode, |
| 471 const SkPDFGlyphSet* subset, | 476 const SkPDFGlyphSet* subset, |
| 472 SkDynamicMemoryWStream* cmap); | 477 SkDynamicMemoryWStream* cmap, |
| 478 uint16_t firstGlyphID, | |
| 479 uint16_t lastGlyphID); | |
| 473 | 480 |
| 474 void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode, | 481 void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode, |
| 475 const SkPDFGlyphSet* subset, | 482 const SkPDFGlyphSet* subset, |
| 476 SkDynamicMemoryWStream* cmap) { | 483 SkDynamicMemoryWStream* cmap, |
| 484 uint16_t firstGlyphID, | |
| 485 uint16_t lastGlyphID) { | |
| 477 if (glyphToUnicode.isEmpty()) { | 486 if (glyphToUnicode.isEmpty()) { |
| 478 return; | 487 return; |
| 479 } | 488 } |
| 480 | 489 |
| 481 SkTDArray<BFChar> bfcharEntries; | 490 SkTDArray<BFChar> bfcharEntries; |
| 482 SkTDArray<BFRange> bfrangeEntries; | 491 SkTDArray<BFRange> bfrangeEntries; |
| 483 | 492 |
| 484 BFRange currentRangeEntry = {0, 0, 0}; | 493 BFRange currentRangeEntry = {0, 0, 0}; |
| 485 bool rangeEmpty = true; | 494 bool rangeEmpty = true; |
| 486 const int count = glyphToUnicode.count(); | 495 const int count = glyphToUnicode.count(); |
| 487 | 496 |
| 488 for (int i = 0; i < count + 1; ++i) { | 497 for (int i = SkMax32(firstGlyphID - 1, 0); |
| 498 i < SkMax32(count, lastGlyphID) + 1; ++i) { | |
| 489 bool inSubset = i < count && (subset == NULL || subset->has(i)); | 499 bool inSubset = i < count && (subset == NULL || subset->has(i)); |
| 490 if (!rangeEmpty) { | 500 if (!rangeEmpty) { |
| 491 // PDF spec requires bfrange not changing the higher byte, | 501 // PDF spec requires bfrange not changing the higher byte, |
| 492 // e.g. <1035> <10FF> <2222> is ok, but | 502 // e.g. <1035> <10FF> <2222> is ok, but |
| 493 // <1035> <1100> <2222> is no good | 503 // <1035> <1100> <2222> is no good |
| 494 bool inRange = | 504 bool inRange = |
| 495 i == currentRangeEntry.fEnd + 1 && | 505 i == currentRangeEntry.fEnd + 1 && |
| 496 i >> 8 == currentRangeEntry.fStart >> 8 && | 506 i >> 8 == currentRangeEntry.fStart >> 8 && |
| 497 i < count && | 507 i < count && |
|
vandebo (ex-Chrome)
2013/09/09 16:04:50
I think this line is meant to terminate the range
edisonn
2013/09/09 16:48:41
in this case i < count is to protect on OutOfBound
vandebo (ex-Chrome)
2013/09/09 17:13:11
But why do you think the loop goes to count + 1?
edisonn
2013/09/09 17:32:11
if (i < count && foo[i]) woks
if (i < max(count,
| |
| 498 glyphToUnicode[i] == currentRangeEntry.fUnicode + i - | 508 glyphToUnicode[i] == currentRangeEntry.fUnicode + i - |
| 499 currentRangeEntry.fStart; | 509 currentRangeEntry.fStart; |
| 500 if (!inSubset || !inRange) { | 510 if (!inSubset || !inRange) { |
| 501 if (currentRangeEntry.fEnd > currentRangeEntry.fStart) { | 511 BFRange range = {(uint16_t)SkMax32(firstGlyphID, |
|
vandebo (ex-Chrome)
2013/09/09 16:04:50
With the loop changed, I don't think you need any
edisonn
2013/09/09 16:48:41
I need it, I start from firstGlypthID - 1
vandebo (ex-Chrome)
2013/09/09 17:13:11
I don't see why you start at first - 1, please exp
edisonn
2013/09/09 17:32:11
Correct, it is not needed.
| |
| 502 bfrangeEntries.push(currentRangeEntry); | 512 currentRangeEntry.fStart), |
| 503 } else { | 513 (uint16_t)SkMin32(lastGlyphID, |
| 514 currentRangeEntry.fEnd), | |
| 515 currentRangeEntry.fUnicode}; | |
| 516 if (range.fEnd > range.fStart) { | |
| 517 bfrangeEntries.push(range); | |
| 518 } else if (range.fStart == range.fEnd && | |
| 519 firstGlyphID <= range.fStart && | |
| 520 range.fEnd <= lastGlyphID) { | |
| 504 BFChar* entry = bfcharEntries.append(); | 521 BFChar* entry = bfcharEntries.append(); |
| 505 entry->fGlyphId = currentRangeEntry.fStart; | 522 entry->fGlyphId = range.fStart; |
| 506 entry->fUnicode = currentRangeEntry.fUnicode; | 523 entry->fUnicode = range.fUnicode; |
| 507 } | 524 } |
| 508 rangeEmpty = true; | 525 rangeEmpty = true; |
| 526 } else if (i > lastGlyphID && !inSubset && !inRange) { | |
|
vandebo (ex-Chrome)
2013/09/09 16:04:50
or here
edisonn
2013/09/09 16:48:41
This one i need, we go to max(lastGlyphID, count)
vandebo (ex-Chrome)
2013/09/09 17:13:11
Isn't this break redundant with the loop condition
edisonn
2013/09/09 17:32:11
no, the loop goes to max(last, count), while this
| |
| 527 break; | |
| 509 } | 528 } |
| 510 } | 529 } |
| 511 if (inSubset) { | 530 if (inSubset) { |
| 512 currentRangeEntry.fEnd = i; | 531 currentRangeEntry.fEnd = i; |
| 513 if (rangeEmpty) { | 532 if (rangeEmpty) { |
| 514 currentRangeEntry.fStart = i; | 533 currentRangeEntry.fStart = i; |
| 515 currentRangeEntry.fUnicode = glyphToUnicode[i]; | 534 currentRangeEntry.fUnicode = glyphToUnicode[i]; |
| 516 rangeEmpty = false; | 535 rangeEmpty = false; |
| 517 } | 536 } |
| 518 } | 537 } |
| 519 } | 538 } |
| 520 | 539 |
| 521 // The spec requires all bfchar entries for a font must come before bfrange | 540 // The spec requires all bfchar entries for a font must come before bfrange |
| 522 // entries. | 541 // entries. |
| 523 append_bfchar_section(bfcharEntries, cmap); | 542 append_bfchar_section(bfcharEntries, cmap); |
| 524 append_bfrange_section(bfrangeEntries, cmap); | 543 append_bfrange_section(bfrangeEntries, cmap); |
| 525 } | 544 } |
| 526 | 545 |
| 527 static SkPDFStream* generate_tounicode_cmap( | 546 static SkPDFStream* generate_tounicode_cmap( |
| 528 const SkTDArray<SkUnichar>& glyphToUnicode, | 547 const SkTDArray<SkUnichar>& glyphToUnicode, |
| 529 const SkPDFGlyphSet* subset) { | 548 const SkPDFGlyphSet* subset, |
| 549 uint16_t firstGlyphID, | |
| 550 uint16_t lastGlyphID) { | |
| 530 SkDynamicMemoryWStream cmap; | 551 SkDynamicMemoryWStream cmap; |
| 531 append_tounicode_header(&cmap); | 552 append_tounicode_header(&cmap, firstGlyphID, lastGlyphID); |
| 532 append_cmap_sections(glyphToUnicode, subset, &cmap); | 553 append_cmap_sections(glyphToUnicode, subset, &cmap, |
| 554 firstGlyphID, lastGlyphID); | |
| 533 append_cmap_footer(&cmap); | 555 append_cmap_footer(&cmap); |
| 534 SkAutoTUnref<SkMemoryStream> cmapStream(new SkMemoryStream()); | 556 SkAutoTUnref<SkMemoryStream> cmapStream(new SkMemoryStream()); |
| 535 cmapStream->setData(cmap.copyToData())->unref(); | 557 cmapStream->setData(cmap.copyToData())->unref(); |
| 536 return new SkPDFStream(cmapStream.get()); | 558 return new SkPDFStream(cmapStream.get()); |
| 537 } | 559 } |
| 538 | 560 |
| 539 #if defined (SK_SFNTLY_SUBSETTER) | 561 #if defined (SK_SFNTLY_SUBSETTER) |
| 540 static void sk_delete_array(const void* ptr, size_t, void*) { | 562 static void sk_delete_array(const void* ptr, size_t, void*) { |
| 541 // Use C-style cast to cast away const and cast type simultaneously. | 563 // Use C-style cast to cast away const and cast type simultaneously. |
| 542 delete[] (unsigned char*)ptr; | 564 delete[] (unsigned char*)ptr; |
| (...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1008 : fFont(font), | 1030 : fFont(font), |
| 1009 fFontID(fontID), | 1031 fFontID(fontID), |
| 1010 fGlyphID(glyphID) { | 1032 fGlyphID(glyphID) { |
| 1011 } | 1033 } |
| 1012 | 1034 |
| 1013 void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) { | 1035 void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) { |
| 1014 if (fFontInfo == NULL || fFontInfo->fGlyphToUnicode.begin() == NULL) { | 1036 if (fFontInfo == NULL || fFontInfo->fGlyphToUnicode.begin() == NULL) { |
| 1015 return; | 1037 return; |
| 1016 } | 1038 } |
| 1017 SkAutoTUnref<SkPDFStream> pdfCmap( | 1039 SkAutoTUnref<SkPDFStream> pdfCmap( |
| 1018 generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset)); | 1040 generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset, |
| 1041 firstGlyphID(), lastGlyphID())); | |
| 1019 addResource(pdfCmap.get()); | 1042 addResource(pdfCmap.get()); |
| 1020 insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref(); | 1043 insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref(); |
| 1021 } | 1044 } |
| 1022 | 1045 |
| 1023 /////////////////////////////////////////////////////////////////////////////// | 1046 /////////////////////////////////////////////////////////////////////////////// |
| 1024 // class SkPDFType0Font | 1047 // class SkPDFType0Font |
| 1025 /////////////////////////////////////////////////////////////////////////////// | 1048 /////////////////////////////////////////////////////////////////////////////// |
| 1026 | 1049 |
| 1027 SkPDFType0Font::SkPDFType0Font(SkAdvancedTypefaceMetrics* info, | 1050 SkPDFType0Font::SkPDFType0Font(SkAdvancedTypefaceMetrics* info, |
| 1028 SkTypeface* typeface) | 1051 SkTypeface* typeface) |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1409 | 1432 |
| 1410 insert("FontBBox", makeFontBBox(bbox, 1000))->unref(); | 1433 insert("FontBBox", makeFontBBox(bbox, 1000))->unref(); |
| 1411 insertInt("FirstChar", firstGlyphID()); | 1434 insertInt("FirstChar", firstGlyphID()); |
| 1412 insertInt("LastChar", lastGlyphID()); | 1435 insertInt("LastChar", lastGlyphID()); |
| 1413 insert("Widths", widthArray.get()); | 1436 insert("Widths", widthArray.get()); |
| 1414 insertName("CIDToGIDMap", "Identity"); | 1437 insertName("CIDToGIDMap", "Identity"); |
| 1415 | 1438 |
| 1416 populateToUnicodeTable(NULL); | 1439 populateToUnicodeTable(NULL); |
| 1417 return true; | 1440 return true; |
| 1418 } | 1441 } |
| OLD | NEW |