Chromium Code Reviews| Index: src/pdf/SkPDFFont.cpp |
| =================================================================== |
| --- src/pdf/SkPDFFont.cpp (revision 11071) |
| +++ src/pdf/SkPDFFont.cpp (working copy) |
| @@ -342,7 +342,9 @@ |
| } // namespace |
| -static void append_tounicode_header(SkDynamicMemoryWStream* cmap) { |
| +static void append_tounicode_header(SkDynamicMemoryWStream* cmap, |
| + uint16_t firstGlypthID, |
| + uint16_t lastGlypthID) { |
| // 12 dict begin: 12 is an Adobe-suggested value. Shall not change. |
| // It's there to prevent old version Adobe Readers from malfunctioning. |
| const char* kHeader = |
| @@ -365,17 +367,20 @@ |
| // The CMapName must be consistent to /CIDSystemInfo above. |
| // /CMapType 2 means ToUnicode. |
| - // We specify codespacerange from 0x0000 to 0xFFFF because we convert our |
| - // code table from unsigned short (16-bits). Codespace range just tells the |
| - // PDF processor the valid range. It does not matter whether a complete |
| - // mapping is provided or not. |
| - const char* kTypeInfo = |
| + // Codespace range just tells the PDF processor the valid range. |
| + const char* kTypeInfoHeader = |
| "/CMapName /Adobe-Identity-UCS def\n" |
| "/CMapType 2 def\n" |
| - "1 begincodespacerange\n" |
| - "<0000> <FFFF>\n" |
| - "endcodespacerange\n"; |
| - cmap->writeText(kTypeInfo); |
| + "1 begincodespacerange\n"; |
| + cmap->writeText(kTypeInfoHeader); |
| + |
| + // e.g. "<0000> <FFFF>\n" |
| + SkString range; |
| + range.appendf("<%04X> <%04X>\n", firstGlypthID, lastGlypthID); |
| + cmap->writeText(range.c_str()); |
| + |
| + const char* kTypeInfoFooter = "endcodespacerange\n"; |
| + cmap->writeText(kTypeInfoFooter); |
| } |
| static void append_cmap_footer(SkDynamicMemoryWStream* cmap) { |
| @@ -399,11 +404,32 @@ |
| }; |
| static void append_bfchar_section(const SkTDArray<BFChar>& bfchar, |
| - SkDynamicMemoryWStream* cmap) { |
| + SkDynamicMemoryWStream* cmap, |
| + uint16_t firstGlypthID, |
| + uint16_t lastGlypthID) { |
| + int32_t i = 0; |
| + 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
|
| + i++; |
| + } |
| + |
| // PDF spec defines that every bf* list can have at most 100 entries. |
| - for (int i = 0; i < bfchar.count(); i += 100) { |
| + for (; i < bfchar.count(); i += 100) { |
| + if (bfchar[i].fGlyphId > lastGlypthID) { |
| + return; |
| + } |
| + |
| int count = bfchar.count() - i; |
| count = SkMin32(count, 100); |
| + // TODO(edisonn): perf, might be better to do a bsearch, but I think |
| + // most of the times, we will have enough data to stop imediately. |
| + while (count > 0 && bfchar[i + count - 1].fGlyphId > lastGlypthID) { |
| + count--; |
| + } |
| + |
| + 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
|
| + return; |
| + } |
| + |
| cmap->writeDecAsText(count); |
| cmap->writeText(" beginbfchar\n"); |
| for (int j = 0; j < count; ++j) { |
| @@ -418,18 +444,36 @@ |
| } |
| static void append_bfrange_section(const SkTDArray<BFRange>& bfrange, |
| - SkDynamicMemoryWStream* cmap) { |
| + SkDynamicMemoryWStream* cmap, |
| + uint16_t firstGlypthID, |
| + uint16_t lastGlypthID) { |
| + int32_t i = 0; |
| + 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:
|
| + i++; |
| + } |
| + |
| // PDF spec defines that every bf* list can have at most 100 entries. |
| - for (int i = 0; i < bfrange.count(); i += 100) { |
| + for (; i < bfrange.count(); i += 100) { |
| + if (bfrange[i].fStart > lastGlypthID) { |
| + return; |
| + } |
| + |
| int count = bfrange.count() - i; |
| count = SkMin32(count, 100); |
| cmap->writeDecAsText(count); |
| cmap->writeText(" beginbfrange\n"); |
| + |
| + // first range might be chopped. |
| + uint16_t start = SkMax32(firstGlypthID, bfrange[i].fStart); |
| + |
| for (int j = 0; j < count; ++j) { |
| + if (bfrange[i + j].fStart > lastGlypthID) { |
| + break; |
| + } |
| cmap->writeText("<"); |
| - cmap->writeHexAsText(bfrange[i + j].fStart, 4); |
| + 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
|
| cmap->writeText("> <"); |
| - cmap->writeHexAsText(bfrange[i + j].fEnd, 4); |
| + cmap->writeHexAsText(SkMin32(bfrange[i + j].fEnd, lastGlypthID), 4); |
| cmap->writeText("> <"); |
| cmap->writeHexAsText(bfrange[i + j].fUnicode, 4); |
| cmap->writeText(">\n"); |
| @@ -469,11 +513,15 @@ |
| // ( see caller in tests/ToUnicode.cpp ) |
| void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode, |
| const SkPDFGlyphSet* subset, |
| - SkDynamicMemoryWStream* cmap); |
| + SkDynamicMemoryWStream* cmap, |
| + 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.
|
| + uint16_t lastGlypthID = 0xffff); |
| void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode, |
| const SkPDFGlyphSet* subset, |
| - SkDynamicMemoryWStream* cmap) { |
| + SkDynamicMemoryWStream* cmap, |
| + uint16_t firstGlypthID, |
| + uint16_t lastGlypthID) { |
| if (glyphToUnicode.isEmpty()) { |
| return; |
| } |
| @@ -520,16 +568,19 @@ |
| // The spec requires all bfchar entries for a font must come before bfrange |
| // entries. |
| - append_bfchar_section(bfcharEntries, cmap); |
| - append_bfrange_section(bfrangeEntries, cmap); |
| + append_bfchar_section(bfcharEntries, cmap, firstGlypthID, lastGlypthID); |
| + append_bfrange_section(bfrangeEntries, cmap, firstGlypthID, lastGlypthID); |
| } |
| static SkPDFStream* generate_tounicode_cmap( |
| const SkTDArray<SkUnichar>& glyphToUnicode, |
| - const SkPDFGlyphSet* subset) { |
| + const SkPDFGlyphSet* subset, |
| + uint16_t firstGlypthID, |
| + uint16_t lastGlypthID) { |
| SkDynamicMemoryWStream cmap; |
| - append_tounicode_header(&cmap); |
| - append_cmap_sections(glyphToUnicode, subset, &cmap); |
| + append_tounicode_header(&cmap, firstGlypthID, lastGlypthID); |
| + append_cmap_sections(glyphToUnicode, subset, &cmap, |
| + firstGlypthID, lastGlypthID); |
| append_cmap_footer(&cmap); |
| SkAutoTUnref<SkMemoryStream> cmapStream(new SkMemoryStream()); |
| cmapStream->setData(cmap.copyToData())->unref(); |
| @@ -1014,7 +1065,8 @@ |
| return; |
| } |
| SkAutoTUnref<SkPDFStream> pdfCmap( |
| - generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset)); |
| + generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset, |
| + firstGlyphID(), lastGlyphID())); |
| addResource(pdfCmap.get()); |
| insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref(); |
| } |