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

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 | no next file » | 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 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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698