aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pdf
diff options
context:
space:
mode:
authorGravatar halcanary <halcanary@google.com>2015-08-20 08:09:37 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-08-20 08:09:37 -0700
commit725c62054354dc0c7fb699bcd69687ec78083ae8 (patch)
treec9e97a7da4008d4d4ce2333dcf6a50890d272572 /src/pdf
parent9a5bd7e860a6b132146e0247c0da0a1510225b97 (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.cpp48
-rw-r--r--src/pdf/SkPDFStream.cpp2
-rw-r--r--src/pdf/SkPDFTypes.cpp52
-rw-r--r--src/pdf/SkPDFTypes.h43
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