Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(175)

Side by Side Diff: src/pdf/SkPDFFont.cpp

Issue 23519006: pdf: write only ToUnicode mappings needed by the font, trimming anything out of [firstChar, lastCha… (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/ToUnicode.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | tests/ToUnicode.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698