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

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

Issue 2190643002: SkPDF: refactor font subset: fewer copies (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2016-07-27 (Wednesday) 15:53:56 EDT Created 4 years, 4 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
« no previous file with comments | « src/pdf/SkPDFDocument.cpp ('k') | src/pdf/SkPDFGraphicState.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 566 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 uint16_t lastGlyphID) { 577 uint16_t lastGlyphID) {
578 SkDynamicMemoryWStream cmap; 578 SkDynamicMemoryWStream cmap;
579 if (multiByteGlyphs) { 579 if (multiByteGlyphs) {
580 append_tounicode_header(&cmap, firstGlyphID, lastGlyphID); 580 append_tounicode_header(&cmap, firstGlyphID, lastGlyphID);
581 } else { 581 } else {
582 append_tounicode_header(&cmap, 1, lastGlyphID - firstGlyphID + 1); 582 append_tounicode_header(&cmap, 1, lastGlyphID - firstGlyphID + 1);
583 } 583 }
584 append_cmap_sections(glyphToUnicode, subset, &cmap, multiByteGlyphs, 584 append_cmap_sections(glyphToUnicode, subset, &cmap, multiByteGlyphs,
585 firstGlyphID, lastGlyphID); 585 firstGlyphID, lastGlyphID);
586 append_cmap_footer(&cmap); 586 append_cmap_footer(&cmap);
587 sk_sp<SkData> cmapData(cmap.copyToData()); 587 return sk_make_sp<SkPDFStream>(
588 return sk_make_sp<SkPDFStream>(cmapData.get()); 588 std::unique_ptr<SkStreamAsset>(cmap.detachAsStream()));
589 } 589 }
590 590
591 #if defined (SK_SFNTLY_SUBSETTER)
592 static void sk_delete_array(const void* ptr, void*) {
593 // Use C-style cast to cast away const and cast type simultaneously.
594 delete[] (unsigned char*)ptr;
595 }
596 #endif
597
598 #if defined(SK_SFNTLY_SUBSETTER)
599 static size_t get_subset_font_stream(const char* fontName,
600 const SkTypeface* typeface,
601 const SkTDArray<uint32_t>& subset,
602 SkPDFStream** fontStream) {
603 int ttcIndex;
604 std::unique_ptr<SkStreamAsset> fontData(typeface->openStream(&ttcIndex));
605 SkASSERT(fontData);
606 if (!fontData) {
607 return 0;
608 }
609
610 size_t fontSize = fontData->getLength();
611
612 // Read font into buffer.
613 SkPDFStream* subsetFontStream = nullptr;
614 SkTDArray<unsigned char> originalFont;
615 originalFont.setCount(SkToInt(fontSize));
616 if (fontData->read(originalFont.begin(), fontSize) == fontSize) {
617 unsigned char* subsetFont = nullptr;
618 // sfntly requires unsigned int* to be passed in, as far as we know,
619 // unsigned int is equivalent to uint32_t on all platforms.
620 static_assert(sizeof(unsigned int) == sizeof(uint32_t), "unsigned_int_no t_32_bits");
621 int subsetFontSize = SfntlyWrapper::SubsetFont(fontName,
622 originalFont.begin(),
623 fontSize,
624 subset.begin(),
625 subset.count(),
626 &subsetFont);
627 if (subsetFontSize > 0 && subsetFont != nullptr) {
628 SkAutoDataUnref data(SkData::NewWithProc(subsetFont,
629 subsetFontSize,
630 sk_delete_array,
631 nullptr));
632 subsetFontStream = new SkPDFStream(data.get());
633 fontSize = subsetFontSize;
634 }
635 }
636 if (subsetFontStream) {
637 *fontStream = subsetFontStream;
638 return fontSize;
639 }
640 fontData->rewind();
641
642 // Fail over: just embed the whole font.
643 *fontStream = new SkPDFStream(std::move(fontData));
644 return fontSize;
645 }
646 #endif
647
648 /////////////////////////////////////////////////////////////////////////////// 591 ///////////////////////////////////////////////////////////////////////////////
649 // class SkPDFGlyphSet 592 // class SkPDFGlyphSet
650 /////////////////////////////////////////////////////////////////////////////// 593 ///////////////////////////////////////////////////////////////////////////////
651 594
652 SkPDFGlyphSet::SkPDFGlyphSet() : fBitSet(SK_MaxU16 + 1) { 595 SkPDFGlyphSet::SkPDFGlyphSet() : fBitSet(SK_MaxU16 + 1) {
653 } 596 }
654 597
655 void SkPDFGlyphSet::set(const uint16_t* glyphIDs, int numGlyphs) { 598 void SkPDFGlyphSet::set(const uint16_t* glyphIDs, int numGlyphs) {
656 for (int i = 0; i < numGlyphs; ++i) { 599 for (int i = 0; i < numGlyphs; ++i) {
657 fBitSet.setBit(glyphIDs[i], true); 600 fBitSet.setBit(glyphIDs[i], true);
658 } 601 }
659 } 602 }
660 603
661 bool SkPDFGlyphSet::has(uint16_t glyphID) const { 604 bool SkPDFGlyphSet::has(uint16_t glyphID) const {
662 return fBitSet.isBitSet(glyphID); 605 return fBitSet.isBitSet(glyphID);
663 } 606 }
664 607
665 void SkPDFGlyphSet::exportTo(SkTDArray<unsigned int>* glyphIDs) const { 608 void SkPDFGlyphSet::exportTo(SkTDArray<unsigned int>* glyphIDs) const {
666 fBitSet.exportTo(glyphIDs); 609 fBitSet.exportTo(glyphIDs);
667 } 610 }
668 611
669 /////////////////////////////////////////////////////////////////////////////// 612 ///////////////////////////////////////////////////////////////////////////////
670 // class SkPDFGlyphSetMap 613 // class SkPDFGlyphSetMap
671 /////////////////////////////////////////////////////////////////////////////// 614 ///////////////////////////////////////////////////////////////////////////////
672 615
673 SkPDFGlyphSetMap::SkPDFGlyphSetMap() {} 616 SkPDFGlyphSetMap::SkPDFGlyphSetMap() {}
674 617
675 SkPDFGlyphSetMap::~SkPDFGlyphSetMap() { 618 SkPDFGlyphSetMap::~SkPDFGlyphSetMap() {
676 fMap.reset(); 619 fMap.reset();
677 } 620 }
678 621
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after
1008 951
1009 SkPDFCIDFont::SkPDFCIDFont(const SkAdvancedTypefaceMetrics* info, 952 SkPDFCIDFont::SkPDFCIDFont(const SkAdvancedTypefaceMetrics* info,
1010 SkTypeface* typeface, 953 SkTypeface* typeface,
1011 const SkPDFGlyphSet* subset) 954 const SkPDFGlyphSet* subset)
1012 : SkPDFFont(info, typeface, nullptr) { 955 : SkPDFFont(info, typeface, nullptr) {
1013 this->populate(subset); 956 this->populate(subset);
1014 } 957 }
1015 958
1016 SkPDFCIDFont::~SkPDFCIDFont() {} 959 SkPDFCIDFont::~SkPDFCIDFont() {}
1017 960
961 #ifdef SK_SFNTLY_SUBSETTER
962 // if possible, make no copy.
963 static sk_sp<SkData> stream_to_data(std::unique_ptr<SkStreamAsset> stream) {
964 SkASSERT(stream);
965 (void)stream->rewind();
966 SkASSERT(stream->hasLength());
967 size_t size = stream->getLength();
968 if (const void* base = stream->getMemoryBase()) {
969 SkData::ReleaseProc proc =
970 [](const void*, void* ctx) { delete (SkStream*)ctx; };
971 return SkData::MakeWithProc(base, size, proc, stream.release());
972 }
973 return SkData::MakeFromStream(stream.get(), size);
974 }
975
976 static sk_sp<SkPDFObject> get_subset_font_stream(
977 std::unique_ptr<SkStreamAsset> fontAsset,
978 const SkTDArray<uint32_t>& subset,
979 const char* fontName) {
980 sk_sp<SkData> fontData(stream_to_data(std::move(fontAsset)));
981 unsigned char* subsetFont = nullptr;
982 // sfntly requires unsigned int* to be passed in,
983 // as far as we know, unsigned int is equivalent
984 // to uint32_t on all platforms.
985 static_assert(sizeof(unsigned) == sizeof(uint32_t), "");
986 // TODO(halcanary): Use ttcIndex, not fontName.
987 int subsetFontSize =
988 SfntlyWrapper::SubsetFont(fontName,
989 fontData->bytes(),
990 fontData->size(),
991 subset.begin(),
992 subset.count(),
993 &subsetFont);
994 fontData = nullptr; // Release memory if necessary.
bungeman-skia 2016/07/27 20:15:59 Instead of doing this, can this be like unsigned
hal.canary 2016/07/27 20:23:04 Done.
995 SkASSERT(subsetFontSize > 0 || subsetFont == nullptr);
996 if (subsetFontSize > 0) {
bungeman-skia 2016/07/27 20:15:59 Can we reverse this so that less code goes into th
hal.canary 2016/07/27 20:23:04 Done.
997 SkASSERT(subsetFont != nullptr);
998 auto subset = sk_make_sp<SkPDFStream>(
999 SkData::MakeWithProc(
1000 subsetFont, subsetFontSize,
1001 [](const void* p, void*) {
1002 delete[] (unsigned char*)p;
1003 }, nullptr));
1004 subset->insertInt("Length1", subsetFontSize);
1005 return subset;
1006 }
1007 return nullptr;
1008 }
1009 #endif // SK_SFNTLY_SUBSETTER
1010
1018 bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth, 1011 bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
1019 const SkTDArray<uint32_t>* subset) { 1012 const SkTDArray<uint32_t>* subset) {
1020 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor"); 1013 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
1021 setFontDescriptor(descriptor.get()); 1014 setFontDescriptor(descriptor.get());
1022 if (!addCommonFontDescriptorEntries(defaultWidth)) { 1015 if (!addCommonFontDescriptorEntries(defaultWidth)) {
1023 this->insertObjRef("FontDescriptor", std::move(descriptor)); 1016 this->insertObjRef("FontDescriptor", std::move(descriptor));
1024 return false; 1017 return false;
1025 } 1018 }
1026 SkASSERT(this->canEmbed()); 1019 SkASSERT(this->canEmbed());
1027 1020
1028 switch (getType()) { 1021 switch (getType()) {
1029 case SkAdvancedTypefaceMetrics::kTrueType_Font: { 1022 case SkAdvancedTypefaceMetrics::kTrueType_Font: {
1030 size_t fontSize = 0; 1023 int ttcIndex;
1031 #if defined(SK_SFNTLY_SUBSETTER) 1024 std::unique_ptr<SkStreamAsset> fontAsset(
1032 if (this->canSubset()) { 1025 this->typeface()->openStream(&ttcIndex));
1033 sk_sp<SkPDFStream> fontStream; 1026 SkASSERT(fontAsset);
1034 SkPDFStream* rawStream = nullptr; 1027 if (!fontAsset) {
1035 fontSize = get_subset_font_stream(fontInfo()->fFontName.c_str(), 1028 return false;
1036 typeface(), 1029 }
1037 *subset, 1030 size_t fontSize = fontAsset->getLength();
1038 &rawStream); 1031 SkASSERT(fontSize > 0);
1039 if (0 == fontSize) { 1032 if (fontSize == 0) {
1040 return false; 1033 return false;
1041 } 1034 }
1042 if (rawStream) { 1035
1043 fontStream.reset(rawStream); 1036 #ifdef SK_SFNTLY_SUBSETTER
1044 fontStream->insertInt("Length1", fontSize); 1037 if (this->canSubset() && subset) {
1045 descriptor->insertObjRef("FontFile2", std::move(fontStream)) ; 1038 sk_sp<SkPDFObject> subsetStream = get_subset_font_stream(
1039 std::move(fontAsset), *subset, fontInfo()->fFontName.c_s tr());
1040 if (subsetStream) {
1041 descriptor->insertObjRef("FontFile2", std::move(subsetStream ));
1046 break; 1042 break;
1047 } 1043 }
1044 // If subsetting fails, fall back to original font data.
1045 fontAsset.reset(this->typeface()->openStream(&ttcIndex));
1048 } 1046 }
1049 #endif 1047 #endif // SK_SFNTLY_SUBSETTER
1050 sk_sp<SkPDFSharedStream> fontStream; 1048 auto fontStream = sk_make_sp<SkPDFSharedStream>(fontAsset.release()) ;
1051 std::unique_ptr<SkStreamAsset> fontData(
1052 this->typeface()->openStream(nullptr));
1053 SkASSERT(fontData);
1054 if (!fontData || 0 == fontData->getLength()) {
1055 return false;
1056 }
1057 fontSize = fontData->getLength();
1058 SkASSERT(fontSize > 0);
1059 fontStream.reset(new SkPDFSharedStream(fontData.release()));
1060 fontStream->dict()->insertInt("Length1", fontSize); 1049 fontStream->dict()->insertInt("Length1", fontSize);
1061 descriptor->insertObjRef("FontFile2", std::move(fontStream)); 1050 descriptor->insertObjRef("FontFile2", std::move(fontStream));
1062 break; 1051 break;
1063 } 1052 }
1064 case SkAdvancedTypefaceMetrics::kCFF_Font: 1053 case SkAdvancedTypefaceMetrics::kCFF_Font:
1065 case SkAdvancedTypefaceMetrics::kType1CID_Font: { 1054 case SkAdvancedTypefaceMetrics::kType1CID_Font: {
1066 std::unique_ptr<SkStreamAsset> fontData( 1055 std::unique_ptr<SkStreamAsset> fontData(
1067 this->typeface()->openStream(nullptr)); 1056 this->typeface()->openStream(nullptr));
1068 SkASSERT(fontData); 1057 SkASSERT(fontData);
1069 SkASSERT(fontData->getLength() > 0); 1058 SkASSERT(fontData->getLength() > 0);
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1200 SkASSERT(rawFontData->getLength() > 0); 1189 SkASSERT(rawFontData->getLength() > 0);
1201 if (!rawFontData || 0 == rawFontData->getLength()) { 1190 if (!rawFontData || 0 == rawFontData->getLength()) {
1202 return false; 1191 return false;
1203 } 1192 }
1204 sk_sp<SkData> fontData(handle_type1_stream(rawFontData.get(), &header, 1193 sk_sp<SkData> fontData(handle_type1_stream(rawFontData.get(), &header,
1205 &data, &trailer)); 1194 &data, &trailer));
1206 if (fontData.get() == nullptr) { 1195 if (fontData.get() == nullptr) {
1207 return false; 1196 return false;
1208 } 1197 }
1209 SkASSERT(this->canEmbed()); 1198 SkASSERT(this->canEmbed());
1210 auto fontStream = sk_make_sp<SkPDFStream>(fontData.get()); 1199 auto fontStream = sk_make_sp<SkPDFStream>(std::move(fontData));
1211 fontStream->insertInt("Length1", header); 1200 fontStream->insertInt("Length1", header);
1212 fontStream->insertInt("Length2", data); 1201 fontStream->insertInt("Length2", data);
1213 fontStream->insertInt("Length3", trailer); 1202 fontStream->insertInt("Length3", trailer);
1214 descriptor->insertObjRef("FontFile", std::move(fontStream)); 1203 descriptor->insertObjRef("FontFile", std::move(fontStream));
1215 1204
1216 this->insertObjRef("FontDescriptor", std::move(descriptor)); 1205 this->insertObjRef("FontDescriptor", std::move(descriptor));
1217 1206
1218 return addCommonFontDescriptorEntries(defaultWidth); 1207 return addCommonFontDescriptorEntries(defaultWidth);
1219 } 1208 }
1220 1209
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
1415 } 1404 }
1416 return *canon->fCanEmbedTypeface.set(id, canEmbed); 1405 return *canon->fCanEmbedTypeface.set(id, canEmbed);
1417 } 1406 }
1418 1407
1419 void SkPDFFont::drop() { 1408 void SkPDFFont::drop() {
1420 fTypeface = nullptr; 1409 fTypeface = nullptr;
1421 fFontInfo = nullptr; 1410 fFontInfo = nullptr;
1422 fDescriptor = nullptr; 1411 fDescriptor = nullptr;
1423 this->SkPDFDict::drop(); 1412 this->SkPDFDict::drop();
1424 } 1413 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFDocument.cpp ('k') | src/pdf/SkPDFGraphicState.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698