From fe8f0e0d3126d27fe9fdd5bc4804392492f14e51 Mon Sep 17 00:00:00 2001 From: halcanary Date: Wed, 27 Jul 2016 14:14:04 -0700 Subject: SkPDF: refactor font subset: fewer copies BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2190643002 Review-Url: https://codereview.chromium.org/2190643002 --- src/pdf/SkPDFDocument.cpp | 3 +- src/pdf/SkPDFFont.cpp | 168 ++++++++++++++++++++---------------------- src/pdf/SkPDFGraphicState.cpp | 6 +- src/pdf/SkPDFStream.h | 11 ++- 4 files changed, 88 insertions(+), 100 deletions(-) (limited to 'src') diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp index 2b7eda1307..95857c1846 100644 --- a/src/pdf/SkPDFDocument.cpp +++ b/src/pdf/SkPDFDocument.cpp @@ -320,8 +320,7 @@ static sk_sp SkSrgbIcm() { } static sk_sp make_srgb_color_profile() { - sk_sp profile = SkSrgbIcm(); - sk_sp stream = sk_make_sp(profile.get()); + sk_sp stream = sk_make_sp(SkSrgbIcm()); stream->insertInt("N", 3); sk_sp array = sk_make_sp(); array->appendScalar(0.0f); diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp index 2f7137fd99..6e04c23e25 100644 --- a/src/pdf/SkPDFFont.cpp +++ b/src/pdf/SkPDFFont.cpp @@ -584,67 +584,10 @@ static sk_sp generate_tounicode_cmap( append_cmap_sections(glyphToUnicode, subset, &cmap, multiByteGlyphs, firstGlyphID, lastGlyphID); append_cmap_footer(&cmap); - sk_sp cmapData(cmap.copyToData()); - return sk_make_sp(cmapData.get()); + return sk_make_sp( + std::unique_ptr(cmap.detachAsStream())); } -#if defined (SK_SFNTLY_SUBSETTER) -static void sk_delete_array(const void* ptr, void*) { - // Use C-style cast to cast away const and cast type simultaneously. - delete[] (unsigned char*)ptr; -} -#endif - -#if defined(SK_SFNTLY_SUBSETTER) -static size_t get_subset_font_stream(const char* fontName, - const SkTypeface* typeface, - const SkTDArray& subset, - SkPDFStream** fontStream) { - int ttcIndex; - std::unique_ptr fontData(typeface->openStream(&ttcIndex)); - SkASSERT(fontData); - if (!fontData) { - return 0; - } - - size_t fontSize = fontData->getLength(); - - // Read font into buffer. - SkPDFStream* subsetFontStream = nullptr; - SkTDArray originalFont; - originalFont.setCount(SkToInt(fontSize)); - if (fontData->read(originalFont.begin(), fontSize) == fontSize) { - unsigned char* subsetFont = nullptr; - // sfntly requires unsigned int* to be passed in, as far as we know, - // unsigned int is equivalent to uint32_t on all platforms. - static_assert(sizeof(unsigned int) == sizeof(uint32_t), "unsigned_int_not_32_bits"); - int subsetFontSize = SfntlyWrapper::SubsetFont(fontName, - originalFont.begin(), - fontSize, - subset.begin(), - subset.count(), - &subsetFont); - if (subsetFontSize > 0 && subsetFont != nullptr) { - SkAutoDataUnref data(SkData::NewWithProc(subsetFont, - subsetFontSize, - sk_delete_array, - nullptr)); - subsetFontStream = new SkPDFStream(data.get()); - fontSize = subsetFontSize; - } - } - if (subsetFontStream) { - *fontStream = subsetFontStream; - return fontSize; - } - fontData->rewind(); - - // Fail over: just embed the whole font. - *fontStream = new SkPDFStream(std::move(fontData)); - return fontSize; -} -#endif - /////////////////////////////////////////////////////////////////////////////// // class SkPDFGlyphSet /////////////////////////////////////////////////////////////////////////////// @@ -665,7 +608,7 @@ bool SkPDFGlyphSet::has(uint16_t glyphID) const { void SkPDFGlyphSet::exportTo(SkTDArray* glyphIDs) const { fBitSet.exportTo(glyphIDs); } - + /////////////////////////////////////////////////////////////////////////////// // class SkPDFGlyphSetMap /////////////////////////////////////////////////////////////////////////////// @@ -1015,6 +958,59 @@ SkPDFCIDFont::SkPDFCIDFont(const SkAdvancedTypefaceMetrics* info, SkPDFCIDFont::~SkPDFCIDFont() {} +#ifdef SK_SFNTLY_SUBSETTER +// if possible, make no copy. +static sk_sp stream_to_data(std::unique_ptr stream) { + SkASSERT(stream); + (void)stream->rewind(); + SkASSERT(stream->hasLength()); + size_t size = stream->getLength(); + if (const void* base = stream->getMemoryBase()) { + SkData::ReleaseProc proc = + [](const void*, void* ctx) { delete (SkStream*)ctx; }; + return SkData::MakeWithProc(base, size, proc, stream.release()); + } + return SkData::MakeFromStream(stream.get(), size); +} + +static sk_sp get_subset_font_stream( + std::unique_ptr fontAsset, + const SkTDArray& subset, + const char* fontName) { + // sfntly requires unsigned int* to be passed in, + // as far as we know, unsigned int is equivalent + // to uint32_t on all platforms. + static_assert(sizeof(unsigned) == sizeof(uint32_t), ""); + + // TODO(halcanary): Use ttcIndex, not fontName. + + unsigned char* subsetFont{nullptr}; + int subsetFontSize{0}; + { + sk_sp fontData(stream_to_data(std::move(fontAsset))); + subsetFontSize = + SfntlyWrapper::SubsetFont(fontName, + fontData->bytes(), + fontData->size(), + subset.begin(), + subset.count(), + &subsetFont); + } + SkASSERT(subsetFontSize > 0 || subsetFont == nullptr); + if (subsetFontSize < 1) { + return nullptr; + } + SkASSERT(subsetFont != nullptr); + auto subsetStream = sk_make_sp( + SkData::MakeWithProc( + subsetFont, subsetFontSize, + [](const void* p, void*) { delete[] (unsigned char*)p; }, + nullptr)); + subsetStream->insertInt("Length1", subsetFontSize); + return subsetStream; +} +#endif // SK_SFNTLY_SUBSETTER + bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth, const SkTDArray* subset) { auto descriptor = sk_make_sp("FontDescriptor"); @@ -1027,36 +1023,32 @@ bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth, switch (getType()) { case SkAdvancedTypefaceMetrics::kTrueType_Font: { - size_t fontSize = 0; -#if defined(SK_SFNTLY_SUBSETTER) - if (this->canSubset()) { - sk_sp fontStream; - SkPDFStream* rawStream = nullptr; - fontSize = get_subset_font_stream(fontInfo()->fFontName.c_str(), - typeface(), - *subset, - &rawStream); - if (0 == fontSize) { - return false; - } - if (rawStream) { - fontStream.reset(rawStream); - fontStream->insertInt("Length1", fontSize); - descriptor->insertObjRef("FontFile2", std::move(fontStream)); - break; - } - } -#endif - sk_sp fontStream; - std::unique_ptr fontData( - this->typeface()->openStream(nullptr)); - SkASSERT(fontData); - if (!fontData || 0 == fontData->getLength()) { + int ttcIndex; + std::unique_ptr fontAsset( + this->typeface()->openStream(&ttcIndex)); + SkASSERT(fontAsset); + if (!fontAsset) { return false; } - fontSize = fontData->getLength(); + size_t fontSize = fontAsset->getLength(); SkASSERT(fontSize > 0); - fontStream.reset(new SkPDFSharedStream(fontData.release())); + if (fontSize == 0) { + return false; + } + + #ifdef SK_SFNTLY_SUBSETTER + if (this->canSubset() && subset) { + sk_sp subsetStream = get_subset_font_stream( + std::move(fontAsset), *subset, fontInfo()->fFontName.c_str()); + if (subsetStream) { + descriptor->insertObjRef("FontFile2", std::move(subsetStream)); + break; + } + // If subsetting fails, fall back to original font data. + fontAsset.reset(this->typeface()->openStream(&ttcIndex)); + } + #endif // SK_SFNTLY_SUBSETTER + auto fontStream = sk_make_sp(fontAsset.release()); fontStream->dict()->insertInt("Length1", fontSize); descriptor->insertObjRef("FontFile2", std::move(fontStream)); break; @@ -1207,7 +1199,7 @@ bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) { return false; } SkASSERT(this->canEmbed()); - auto fontStream = sk_make_sp(fontData.get()); + auto fontStream = sk_make_sp(std::move(fontData)); fontStream->insertInt("Length1", header); fontStream->insertInt("Length2", data); fontStream->insertInt("Length3", trailer); diff --git a/src/pdf/SkPDFGraphicState.cpp b/src/pdf/SkPDFGraphicState.cpp index 0752eac328..17129bb79d 100644 --- a/src/pdf/SkPDFGraphicState.cpp +++ b/src/pdf/SkPDFGraphicState.cpp @@ -135,10 +135,8 @@ sk_sp SkPDFGraphicState::MakeInvertFunction() { static const char psInvert[] = "{1 exch sub}"; // Do not copy the trailing '\0' into the SkData. - sk_sp psInvertStream( - SkData::NewWithoutCopy(psInvert, strlen(psInvert))); - - auto invertFunction = sk_make_sp(psInvertStream.get()); + auto invertFunction = sk_make_sp( + SkData::MakeWithoutCopy(psInvert, strlen(psInvert))); invertFunction->insertInt("FunctionType", 4); invertFunction->insertObject("Domain", domainAndRange); invertFunction->insertObject("Range", std::move(domainAndRange)); diff --git a/src/pdf/SkPDFStream.h b/src/pdf/SkPDFStream.h index 0cc2d4295e..32632c6699 100644 --- a/src/pdf/SkPDFStream.h +++ b/src/pdf/SkPDFStream.h @@ -22,9 +22,11 @@ class SkPDFStream : public SkPDFDict { public: /** Create a PDF stream. A Length entry is automatically added to the * stream dictionary. - * @param data The data part of the stream. Will not take ownership. - */ - explicit SkPDFStream(SkData* data) { this->setData(data); } + * @param data The data part of the stream. */ + explicit SkPDFStream(sk_sp data) { + this->setData(std::unique_ptr( + new SkMemoryStream(std::move(data)))); + } /** Create a PDF stream. A Length entry is automatically added to the * stream dictionary. @@ -50,9 +52,6 @@ protected: /** Only call this function once. */ void setData(std::unique_ptr stream); - void setData(SkData* data) { - this->setData(std::unique_ptr(new SkMemoryStream(data))); - } private: std::unique_ptr fCompressedData; -- cgit v1.2.3