diff options
author | 2015-08-20 08:09:37 -0700 | |
---|---|---|
committer | 2015-08-20 08:09:37 -0700 | |
commit | 725c62054354dc0c7fb699bcd69687ec78083ae8 (patch) | |
tree | c9e97a7da4008d4d4ce2333dcf6a50890d272572 /src/pdf | |
parent | 9a5bd7e860a6b132146e0247c0da0a1510225b97 (diff) |
SkPDF: Memory improvements for PDF Streams
ΔMEM = -15%
ΔCPU = -7%
BUG=skia:3030
Review URL: https://codereview.chromium.org/1227913008
Diffstat (limited to 'src/pdf')
-rw-r--r-- | src/pdf/SkPDFFont.cpp | 48 | ||||
-rw-r--r-- | src/pdf/SkPDFStream.cpp | 2 | ||||
-rw-r--r-- | src/pdf/SkPDFTypes.cpp | 52 | ||||
-rw-r--r-- | src/pdf/SkPDFTypes.h | 43 |
4 files changed, 104 insertions, 41 deletions
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp index 17623c7c3b..25ffc0b851 100644 --- a/src/pdf/SkPDFFont.cpp +++ b/src/pdf/SkPDFFont.cpp @@ -584,6 +584,7 @@ static void sk_delete_array(const void* ptr, void*) { } #endif +#if defined(SK_SFNTLY_SUBSETTER) static size_t get_subset_font_stream(const char* fontName, const SkTypeface* typeface, const SkTDArray<uint32_t>& subset, @@ -594,7 +595,6 @@ static size_t get_subset_font_stream(const char* fontName, size_t fontSize = fontData->getLength(); -#if defined (SK_SFNTLY_SUBSETTER) // Read font into buffer. SkPDFStream* subsetFontStream = NULL; SkTDArray<unsigned char> originalFont; @@ -624,15 +624,12 @@ static size_t get_subset_font_stream(const char* fontName, return fontSize; } fontData->rewind(); -#else - sk_ignore_unused_variable(fontName); - sk_ignore_unused_variable(subset); -#endif // Fail over: just embed the whole font. *fontStream = new SkPDFStream(fontData.get()); return fontSize; } +#endif /////////////////////////////////////////////////////////////////////////////// // class SkPDFGlyphSet @@ -1061,40 +1058,43 @@ bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth, switch (getType()) { case SkAdvancedTypefaceMetrics::kTrueType_Font: { - SkAutoTUnref<SkPDFStream> fontStream; size_t fontSize = 0; - if (canSubset()) { +#if defined(SK_SFNTLY_SUBSETTER) + if (this->canSubset()) { + SkAutoTUnref<SkPDFStream> fontStream; SkPDFStream* rawStream = NULL; fontSize = get_subset_font_stream(fontInfo()->fFontName.c_str(), typeface(), *subset, &rawStream); - fontStream.reset(rawStream); - } else { - int ttcIndex; - SkAutoTDelete<SkStream> fontData( - typeface()->openStream(&ttcIndex)); - fontStream.reset(new SkPDFStream(fontData.get())); - fontSize = fontData->getLength(); + if (rawStream) { + fontStream.reset(rawStream); + fontStream->insertInt("Length1", fontSize); + descriptor->insertObjRef("FontFile2", fontStream.detach()); + break; + } } - SkASSERT(fontSize); - SkASSERT(fontStream.get()); - - fontStream->insertInt("Length1", fontSize); +#endif + SkAutoTUnref<SkPDFSharedStream> fontStream; + SkAutoTDelete<SkStreamAsset> fontData( + this->typeface()->openStream(NULL)); + SkASSERT(fontData); + fontSize = fontData->getLength(); + SkASSERT(fontSize > 0); + fontStream.reset(new SkPDFSharedStream(fontData.detach())); + fontStream->dict()->insertInt("Length1", fontSize); descriptor->insertObjRef("FontFile2", fontStream.detach()); break; } case SkAdvancedTypefaceMetrics::kCFF_Font: case SkAdvancedTypefaceMetrics::kType1CID_Font: { - int ttcIndex; - SkAutoTDelete<SkStream> fontData(typeface()->openStream(&ttcIndex)); - SkAutoTUnref<SkPDFStream> fontStream( - new SkPDFStream(fontData.get())); + SkAutoTUnref<SkPDFSharedStream> fontStream( + new SkPDFSharedStream(this->typeface()->openStream(NULL))); if (getType() == SkAdvancedTypefaceMetrics::kCFF_Font) { - fontStream->insertName("Subtype", "Type1C"); + fontStream->dict()->insertName("Subtype", "Type1C"); } else { - fontStream->insertName("Subtype", "CIDFontType0c"); + fontStream->dict()->insertName("Subtype", "CIDFontType0c"); } descriptor->insertObjRef("FontFile3", fontStream.detach()); break; diff --git a/src/pdf/SkPDFStream.cpp b/src/pdf/SkPDFStream.cpp index 69ce317bb9..b8f2e4e92b 100644 --- a/src/pdf/SkPDFStream.cpp +++ b/src/pdf/SkPDFStream.cpp @@ -20,7 +20,7 @@ void SkPDFStream::emitObject(SkWStream* stream, const SkPDFSubstituteMap& substitutes) const { SkASSERT(fCompressedData); this->INHERITED::emitObject(stream, objNumMap, substitutes); - // Note: emitObject isn't marked const, but could be in the future + // duplicate (a cheap operation) preserves const on fCompressedData. SkAutoTDelete<SkStreamRewindable> dup(fCompressedData->duplicate()); SkASSERT(dup); SkASSERT(dup->hasLength()); diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp index 2fe408b1cc..9bb9dee497 100644 --- a/src/pdf/SkPDFTypes.cpp +++ b/src/pdf/SkPDFTypes.cpp @@ -6,15 +6,10 @@ * found in the LICENSE file. */ +#include "SkDeflate.h" #include "SkPDFTypes.h" #include "SkPDFUtils.h" -#include "SkStream.h" - -#ifdef SK_BUILD_FOR_WIN - #define SNPRINTF _snprintf -#else - #define SNPRINTF snprintf -#endif +#include "SkStreamPriv.h" //////////////////////////////////////////////////////////////////////////////// @@ -355,6 +350,13 @@ void SkPDFDict::emitObject(SkWStream* stream, const SkPDFObjNumMap& objNumMap, const SkPDFSubstituteMap& substitutes) const { stream->writeText("<<"); + this->emitAll(stream, objNumMap, substitutes); + stream->writeText(">>"); +} + +void SkPDFDict::emitAll(SkWStream* stream, + const SkPDFObjNumMap& objNumMap, + const SkPDFSubstituteMap& substitutes) const { for (int i = 0; i < fRecords.count(); i++) { fRecords[i].fKey.emitObject(stream, objNumMap, substitutes); stream->writeText(" "); @@ -363,7 +365,6 @@ void SkPDFDict::emitObject(SkWStream* stream, stream->writeText("\n"); } } - stream->writeText(">>"); } void SkPDFDict::addResources(SkPDFObjNumMap* catalog, @@ -439,6 +440,41 @@ void SkPDFDict::clear() { //////////////////////////////////////////////////////////////////////////////// +void SkPDFSharedStream::emitObject( + SkWStream* stream, + const SkPDFObjNumMap& objNumMap, + const SkPDFSubstituteMap& substitutes) const { + SkDynamicMemoryWStream buffer; + SkDeflateWStream deflateWStream(&buffer); + // Since emitObject is const, this function doesn't change the dictionary. + SkAutoTDelete<SkStreamAsset> dup(fAsset->duplicate()); // Cheap copy + SkASSERT(dup); + SkStreamCopy(&deflateWStream, dup.get()); + deflateWStream.finalize(); + size_t length = buffer.bytesWritten(); + stream->writeText("<<"); + fDict->emitAll(stream, objNumMap, substitutes); + stream->writeText("\n"); + SkPDFUnion::Name("Length").emitObject(stream, objNumMap, substitutes); + stream->writeText(" "); + SkPDFUnion::Int(length).emitObject(stream, objNumMap, substitutes); + stream->writeText("\n"); + SkPDFUnion::Name("Filter").emitObject(stream, objNumMap, substitutes); + stream->writeText(" "); + SkPDFUnion::Name("FlateDecode").emitObject(stream, objNumMap, substitutes); + stream->writeText(">>"); + stream->writeText(" stream\n"); + buffer.writeToStream(stream); + stream->writeText("\nendstream"); +} + +void SkPDFSharedStream::addResources( + SkPDFObjNumMap* catalog, const SkPDFSubstituteMap& substitutes) const { + fDict->addResources(catalog, substitutes); +} + +//////////////////////////////////////////////////////////////////////////////// + SkPDFSubstituteMap::~SkPDFSubstituteMap() { fSubstituteMap.foreach( [](SkPDFObject*, SkPDFObject** v) { (*v)->unref(); }); diff --git a/src/pdf/SkPDFTypes.h b/src/pdf/SkPDFTypes.h index 56e534bd5e..85aa0132ed 100644 --- a/src/pdf/SkPDFTypes.h +++ b/src/pdf/SkPDFTypes.h @@ -11,6 +11,7 @@ #include "SkRefCnt.h" #include "SkScalar.h" +#include "SkStream.h" #include "SkString.h" #include "SkTDArray.h" #include "SkTHash.h" @@ -19,7 +20,6 @@ class SkPDFObjNumMap; class SkPDFObject; class SkPDFSubstituteMap; -class SkWStream; /** \class SkPDFObject @@ -30,8 +30,6 @@ class SkWStream; */ class SkPDFObject : public SkRefCnt { public: - - /** Subclasses must implement this method to print the object to the * PDF file. * @param catalog The object catalog to use. @@ -77,7 +75,7 @@ public: static SkPDFUnion Int(int32_t); - static SkPDFUnion Int(size_t); + static SkPDFUnion Int(size_t v) { return SkPDFUnion::Int(SkToS32(v)); } static SkPDFUnion Bool(bool); @@ -188,8 +186,6 @@ private: */ class SkPDFArray : public SkPDFObject { public: - - static const int kMaxLen = 8191; /** Create a PDF array. Maximum length is 8191. @@ -239,8 +235,6 @@ private: */ class SkPDFDict : public SkPDFObject { public: - - /** Create a PDF dictionary. Maximum number of entries is 4095. */ SkPDFDict(); @@ -290,6 +284,12 @@ public: */ void clear(); + /** Emit the dictionary, without the "<<" and ">>". + */ + void emitAll(SkWStream* stream, + const SkPDFObjNumMap& objNumMap, + const SkPDFSubstituteMap& substitutes) const; + private: struct Record { SkPDFUnion fKey; @@ -303,6 +303,33 @@ private: typedef SkPDFObject INHERITED; }; +/** \class SkPDFSharedStream + + This class takes an asset and assumes that it is backed by + long-lived shared data (for example, an open file + descriptor). That is: no memory savings can be made by holding on + to a compressed version instead. + */ +class SkPDFSharedStream : public SkPDFObject { +public: + // Takes ownership of asset. + SkPDFSharedStream(SkStreamAsset* data) + : fAsset(data), fDict(SkNEW(SkPDFDict)) { + SkASSERT(data); + } + SkPDFDict* dict() { return fDict; } + void emitObject(SkWStream*, + const SkPDFObjNumMap&, + const SkPDFSubstituteMap&) const override; + void addResources(SkPDFObjNumMap*, + const SkPDFSubstituteMap&) const override; + +private: + SkAutoTDelete<SkStreamAsset> fAsset; + SkAutoTUnref<SkPDFDict> fDict; + typedef SkPDFObject INHERITED; +}; + //////////////////////////////////////////////////////////////////////////////// /** \class SkPDFObjNumMap |