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 } |
(...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 firstGlypthID, | |
479 uint16_t lastGlypthID); | |
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 firstGlypthID, | |
485 uint16_t lastGlypthID) { | |
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 = 0; i < count + 1; ++i) { |
vandebo (ex-Chrome)
2013/09/06 21:22:55
How about just making this loop go from firstGlyph
edisonn
2013/09/09 14:36:53
Done, but the solution is a little bit more compli
vandebo (ex-Chrome)
2013/09/09 16:04:50
I don't see it, why do you need to start with the
| |
489 bool inSubset = i < count && (subset == NULL || subset->has(i)); | 498 bool inSubset = i < count && (subset == NULL || subset->has(i)); |
490 if (!rangeEmpty) { | 499 if (!rangeEmpty) { |
491 // PDF spec requires bfrange not changing the higher byte, | 500 // PDF spec requires bfrange not changing the higher byte, |
492 // e.g. <1035> <10FF> <2222> is ok, but | 501 // e.g. <1035> <10FF> <2222> is ok, but |
493 // <1035> <1100> <2222> is no good | 502 // <1035> <1100> <2222> is no good |
494 bool inRange = | 503 bool inRange = |
495 i == currentRangeEntry.fEnd + 1 && | 504 i == currentRangeEntry.fEnd + 1 && |
496 i >> 8 == currentRangeEntry.fStart >> 8 && | 505 i >> 8 == currentRangeEntry.fStart >> 8 && |
497 i < count && | 506 i < count && |
498 glyphToUnicode[i] == currentRangeEntry.fUnicode + i - | 507 glyphToUnicode[i] == currentRangeEntry.fUnicode + i - |
499 currentRangeEntry.fStart; | 508 currentRangeEntry.fStart; |
500 if (!inSubset || !inRange) { | 509 if (!inSubset || !inRange) { |
501 if (currentRangeEntry.fEnd > currentRangeEntry.fStart) { | 510 BFRange range = {(uint16_t)SkMax32(firstGlypthID, |
502 bfrangeEntries.push(currentRangeEntry); | 511 currentRangeEntry.fStart), |
503 } else { | 512 (uint16_t)SkMin32(lastGlypthID, |
513 currentRangeEntry.fEnd), | |
514 currentRangeEntry.fUnicode}; | |
515 if (range.fEnd > range.fStart) { | |
516 bfrangeEntries.push(range); | |
517 } else if (range.fStart == range.fEnd && | |
518 firstGlypthID <= range.fStart && | |
519 range.fEnd <= lastGlypthID) { | |
504 BFChar* entry = bfcharEntries.append(); | 520 BFChar* entry = bfcharEntries.append(); |
505 entry->fGlyphId = currentRangeEntry.fStart; | 521 entry->fGlyphId = range.fStart; |
506 entry->fUnicode = currentRangeEntry.fUnicode; | 522 entry->fUnicode = range.fUnicode; |
507 } | 523 } |
508 rangeEmpty = true; | 524 rangeEmpty = true; |
509 } | 525 } |
510 } | 526 } |
511 if (inSubset) { | 527 if (inSubset) { |
512 currentRangeEntry.fEnd = i; | 528 currentRangeEntry.fEnd = i; |
513 if (rangeEmpty) { | 529 if (rangeEmpty) { |
514 currentRangeEntry.fStart = i; | 530 currentRangeEntry.fStart = i; |
515 currentRangeEntry.fUnicode = glyphToUnicode[i]; | 531 currentRangeEntry.fUnicode = glyphToUnicode[i]; |
516 rangeEmpty = false; | 532 rangeEmpty = false; |
517 } | 533 } |
518 } | 534 } |
519 } | 535 } |
520 | 536 |
521 // The spec requires all bfchar entries for a font must come before bfrange | 537 // The spec requires all bfchar entries for a font must come before bfrange |
522 // entries. | 538 // entries. |
523 append_bfchar_section(bfcharEntries, cmap); | 539 append_bfchar_section(bfcharEntries, cmap); |
524 append_bfrange_section(bfrangeEntries, cmap); | 540 append_bfrange_section(bfrangeEntries, cmap); |
525 } | 541 } |
526 | 542 |
527 static SkPDFStream* generate_tounicode_cmap( | 543 static SkPDFStream* generate_tounicode_cmap( |
528 const SkTDArray<SkUnichar>& glyphToUnicode, | 544 const SkTDArray<SkUnichar>& glyphToUnicode, |
529 const SkPDFGlyphSet* subset) { | 545 const SkPDFGlyphSet* subset, |
546 uint16_t firstGlypthID, | |
547 uint16_t lastGlypthID) { | |
530 SkDynamicMemoryWStream cmap; | 548 SkDynamicMemoryWStream cmap; |
531 append_tounicode_header(&cmap); | 549 append_tounicode_header(&cmap, firstGlypthID, lastGlypthID); |
532 append_cmap_sections(glyphToUnicode, subset, &cmap); | 550 append_cmap_sections(glyphToUnicode, subset, &cmap, |
551 firstGlypthID, lastGlypthID); | |
533 append_cmap_footer(&cmap); | 552 append_cmap_footer(&cmap); |
534 SkAutoTUnref<SkMemoryStream> cmapStream(new SkMemoryStream()); | 553 SkAutoTUnref<SkMemoryStream> cmapStream(new SkMemoryStream()); |
535 cmapStream->setData(cmap.copyToData())->unref(); | 554 cmapStream->setData(cmap.copyToData())->unref(); |
536 return new SkPDFStream(cmapStream.get()); | 555 return new SkPDFStream(cmapStream.get()); |
537 } | 556 } |
538 | 557 |
539 #if defined (SK_SFNTLY_SUBSETTER) | 558 #if defined (SK_SFNTLY_SUBSETTER) |
540 static void sk_delete_array(const void* ptr, size_t, void*) { | 559 static void sk_delete_array(const void* ptr, size_t, void*) { |
541 // Use C-style cast to cast away const and cast type simultaneously. | 560 // Use C-style cast to cast away const and cast type simultaneously. |
542 delete[] (unsigned char*)ptr; | 561 delete[] (unsigned char*)ptr; |
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1007 : fFont(font), | 1026 : fFont(font), |
1008 fFontID(fontID), | 1027 fFontID(fontID), |
1009 fGlyphID(glyphID) { | 1028 fGlyphID(glyphID) { |
1010 } | 1029 } |
1011 | 1030 |
1012 void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) { | 1031 void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) { |
1013 if (fFontInfo == NULL || fFontInfo->fGlyphToUnicode.begin() == NULL) { | 1032 if (fFontInfo == NULL || fFontInfo->fGlyphToUnicode.begin() == NULL) { |
1014 return; | 1033 return; |
1015 } | 1034 } |
1016 SkAutoTUnref<SkPDFStream> pdfCmap( | 1035 SkAutoTUnref<SkPDFStream> pdfCmap( |
1017 generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset)); | 1036 generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset, |
1037 firstGlyphID(), lastGlyphID())); | |
1018 addResource(pdfCmap.get()); | 1038 addResource(pdfCmap.get()); |
1019 insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref(); | 1039 insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref(); |
1020 } | 1040 } |
1021 | 1041 |
1022 /////////////////////////////////////////////////////////////////////////////// | 1042 /////////////////////////////////////////////////////////////////////////////// |
1023 // class SkPDFType0Font | 1043 // class SkPDFType0Font |
1024 /////////////////////////////////////////////////////////////////////////////// | 1044 /////////////////////////////////////////////////////////////////////////////// |
1025 | 1045 |
1026 SkPDFType0Font::SkPDFType0Font(SkAdvancedTypefaceMetrics* info, | 1046 SkPDFType0Font::SkPDFType0Font(SkAdvancedTypefaceMetrics* info, |
1027 SkTypeface* typeface) | 1047 SkTypeface* typeface) |
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1408 | 1428 |
1409 insert("FontBBox", makeFontBBox(bbox, 1000))->unref(); | 1429 insert("FontBBox", makeFontBBox(bbox, 1000))->unref(); |
1410 insertInt("FirstChar", firstGlyphID()); | 1430 insertInt("FirstChar", firstGlyphID()); |
1411 insertInt("LastChar", lastGlyphID()); | 1431 insertInt("LastChar", lastGlyphID()); |
1412 insert("Widths", widthArray.get()); | 1432 insert("Widths", widthArray.get()); |
1413 insertName("CIDToGIDMap", "Identity"); | 1433 insertName("CIDToGIDMap", "Identity"); |
1414 | 1434 |
1415 populateToUnicodeTable(NULL); | 1435 populateToUnicodeTable(NULL); |
1416 return true; | 1436 return true; |
1417 } | 1437 } |
OLD | NEW |