SkPDF: Simplify PDFStream / emitObject() const

Compress SkPDFStream's data on setData(), not emitObject(); no longer stateful.

SkPDFObject::emitObject is now const.  This makes it easier to reason about state.

Minimal performance gains.

Review URL: https://codereview.chromium.org/1304493002
This commit is contained in:
halcanary 2015-08-19 12:26:46 -07:00 committed by Commit bot
parent 216b643fc7
commit a060eba083
9 changed files with 62 additions and 88 deletions

View File

@ -249,7 +249,7 @@ public:
~PDFAlphaBitmap() {} ~PDFAlphaBitmap() {}
void emitObject(SkWStream*, void emitObject(SkWStream*,
const SkPDFObjNumMap&, const SkPDFObjNumMap&,
const SkPDFSubstituteMap&) override; const SkPDFSubstituteMap&) const override;
private: private:
const SkBitmap fBitmap; const SkBitmap fBitmap;
@ -257,7 +257,7 @@ private:
void PDFAlphaBitmap::emitObject(SkWStream* stream, void PDFAlphaBitmap::emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap, const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) { const SkPDFSubstituteMap& substitutes) const {
SkAutoLockPixels autoLockPixels(fBitmap); SkAutoLockPixels autoLockPixels(fBitmap);
SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType || SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
fBitmap.getColorTable()); fBitmap.getColorTable());
@ -293,7 +293,7 @@ public:
const SkAutoTUnref<SkPDFObject> fSMask; const SkAutoTUnref<SkPDFObject> fSMask;
void emitObject(SkWStream*, void emitObject(SkWStream*,
const SkPDFObjNumMap&, const SkPDFObjNumMap&,
const SkPDFSubstituteMap&) override; const SkPDFSubstituteMap&) const override;
void addResources(SkPDFObjNumMap*, void addResources(SkPDFObjNumMap*,
const SkPDFSubstituteMap&) const override; const SkPDFSubstituteMap&) const override;
PDFDefaultBitmap(const SkBitmap& bm, SkPDFObject* smask) PDFDefaultBitmap(const SkBitmap& bm, SkPDFObject* smask)
@ -345,7 +345,7 @@ static SkPDFArray* make_indexed_color_space(const SkColorTable* table) {
void PDFDefaultBitmap::emitObject(SkWStream* stream, void PDFDefaultBitmap::emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap, const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) { const SkPDFSubstituteMap& substitutes) const {
SkAutoLockPixels autoLockPixels(fBitmap); SkAutoLockPixels autoLockPixels(fBitmap);
SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType || SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
fBitmap.getColorTable()); fBitmap.getColorTable());
@ -407,12 +407,12 @@ public:
: SkPDFBitmap(bm), fData(SkRef(data)), fIsYUV(isYUV) {} : SkPDFBitmap(bm), fData(SkRef(data)), fIsYUV(isYUV) {}
void emitObject(SkWStream*, void emitObject(SkWStream*,
const SkPDFObjNumMap&, const SkPDFObjNumMap&,
const SkPDFSubstituteMap&) override; const SkPDFSubstituteMap&) const override;
}; };
void PDFJpegBitmap::emitObject(SkWStream* stream, void PDFJpegBitmap::emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap, const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substituteMap) { const SkPDFSubstituteMap& substituteMap) const {
SkPDFDict pdfDict("XObject"); SkPDFDict pdfDict("XObject");
pdfDict.insertName("Subtype", "Image"); pdfDict.insertName("Subtype", "Image");
pdfDict.insertInt("Width", fBitmap.width()); pdfDict.insertInt("Width", fBitmap.width());

View File

@ -1011,7 +1011,7 @@ SkPDFFont* SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) {
#ifdef SK_DEBUG #ifdef SK_DEBUG
void SkPDFType0Font::emitObject(SkWStream* stream, void SkPDFType0Font::emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap, const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) { const SkPDFSubstituteMap& substitutes) const {
SkASSERT(fPopulated); SkASSERT(fPopulated);
return INHERITED::emitObject(stream, objNumMap, substitutes); return INHERITED::emitObject(stream, objNumMap, substitutes);
} }

View File

@ -18,9 +18,9 @@ public:
virtual bool multiByteGlyphs() const { return true; } virtual bool multiByteGlyphs() const { return true; }
virtual SkPDFFont* getFontSubset(const SkPDFGlyphSet* usage); virtual SkPDFFont* getFontSubset(const SkPDFGlyphSet* usage);
#ifdef SK_DEBUG #ifdef SK_DEBUG
virtual void emitObject(SkWStream*, void emitObject(SkWStream*,
const SkPDFObjNumMap&, const SkPDFObjNumMap&,
const SkPDFSubstituteMap&); const SkPDFSubstituteMap&) const override;
#endif #endif
private: private:

View File

@ -195,9 +195,10 @@ SkPDFDict* SkPDFGraphicState::GetNoSMaskGraphicState() {
return SkRef(noSMaskGraphicState.get()); return SkRef(noSMaskGraphicState.get());
} }
void SkPDFGraphicState::emitObject(SkWStream* stream, void SkPDFGraphicState::emitObject(
const SkPDFObjNumMap& objNumMap, SkWStream* stream,
const SkPDFSubstituteMap& substitutes) { const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) const {
SkAutoTUnref<SkPDFDict> dict(SkNEW_ARGS(SkPDFDict, ("ExtGState"))); SkAutoTUnref<SkPDFDict> dict(SkNEW_ARGS(SkPDFDict, ("ExtGState")));
dict->insertName("Type", "ExtGState"); dict->insertName("Type", "ExtGState");

View File

@ -32,9 +32,9 @@ public:
// Override emitObject so that we can populate the dictionary on // Override emitObject so that we can populate the dictionary on
// demand. // demand.
virtual void emitObject(SkWStream* stream, void emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap, const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes); const SkPDFSubstituteMap& substitutes) const override;
/** Get the graphic state for the passed SkPaint. The reference count of /** Get the graphic state for the passed SkPaint. The reference count of
* the object is incremented and it is the caller's responsibility to * the object is incremented and it is the caller's responsibility to

View File

@ -13,58 +13,43 @@
#include "SkStream.h" #include "SkStream.h"
#include "SkStreamPriv.h" #include "SkStreamPriv.h"
SkPDFStream::SkPDFStream(SkStream* stream) : fState(kUnused_State) {
this->setData(stream);
}
SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) {
this->setData(data);
}
SkPDFStream::~SkPDFStream() {} SkPDFStream::~SkPDFStream() {}
void SkPDFStream::emitObject(SkWStream* stream, void SkPDFStream::emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap, const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) { const SkPDFSubstituteMap& substitutes) const {
if (fState == kUnused_State) { SkASSERT(fCompressedData);
fState = kNoCompression_State;
SkDynamicMemoryWStream compressedData;
SkDeflateWStream deflateWStream(&compressedData);
SkAssertResult(SkStreamCopy(&deflateWStream, fDataStream.get()));
deflateWStream.finalize();
SkAssertResult(fDataStream->rewind());
if (compressedData.getOffset() < this->dataSize()) {
SkAutoTDelete<SkStream> compressed(
compressedData.detachAsStream());
this->setData(compressed.get());
this->insertName("Filter", "FlateDecode");
}
fState = kCompressed_State;
this->insertInt("Length", this->dataSize());
}
this->INHERITED::emitObject(stream, objNumMap, substitutes); this->INHERITED::emitObject(stream, objNumMap, substitutes);
// Note: emitObject isn't marked const, but could be in the future
SkAutoTDelete<SkStreamRewindable> dup(fCompressedData->duplicate());
SkASSERT(dup);
SkASSERT(dup->hasLength());
stream->writeText(" stream\n"); stream->writeText(" stream\n");
stream->writeStream(fDataStream.get(), fDataStream->getLength()); stream->writeStream(dup.get(), dup->getLength());
SkAssertResult(fDataStream->rewind());
stream->writeText("\nendstream"); stream->writeText("\nendstream");
} }
SkPDFStream::SkPDFStream() : fState(kUnused_State) {}
void SkPDFStream::setData(SkData* data) {
// FIXME: Don't swap if the data is the same.
fDataStream.reset(SkNEW_ARGS(SkMemoryStream, (data)));
}
void SkPDFStream::setData(SkStream* stream) { void SkPDFStream::setData(SkStream* stream) {
SkASSERT(!fCompressedData); // Only call this function once.
SkASSERT(stream); SkASSERT(stream);
// Code assumes that the stream starts at the beginning and is rewindable. // Code assumes that the stream starts at the beginning.
// SkStreamRewindableFromSkStream will try stream->duplicate().
fDataStream.reset(SkStreamRewindableFromSkStream(stream));
SkASSERT(fDataStream.get());
}
size_t SkPDFStream::dataSize() const { SkDynamicMemoryWStream compressedData;
SkASSERT(fDataStream->hasLength()); SkDeflateWStream deflateWStream(&compressedData);
return fDataStream->getLength(); SkStreamCopy(&deflateWStream, stream);
deflateWStream.finalize();
size_t length = compressedData.bytesWritten();
if (stream->hasLength()) {
SkAutoTDelete<SkStreamRewindable> dup(stream->duplicate());
if (dup && dup->hasLength() &&
dup->getLength() <= length + strlen("/Filter_/FlateDecode_")) {
this->insertInt("Length", dup->getLength());
fCompressedData.reset(dup.detach());
return;
}
}
fCompressedData.reset(compressedData.detachAsStream());
this->insertName("Filter", "FlateDecode");
this->insertInt("Length", length);
} }

View File

@ -27,50 +27,38 @@ class SkPDFStream : public SkPDFDict {
public: public:
/** Create a PDF stream. A Length entry is automatically added to the /** Create a PDF stream. A Length entry is automatically added to the
* stream dictionary. * stream dictionary.
* @param data The data part of the stream. Will be ref()ed. * @param data The data part of the stream. Will not take ownership.
*/ */
explicit SkPDFStream(SkData* data); explicit SkPDFStream(SkData* data) { this->setData(data); }
/** Create a PDF stream. A Length entry is automatically added to the /** Create a PDF stream. A Length entry is automatically added to the
* stream dictionary. * stream dictionary.
* @param stream The data part of the stream. Will be duplicate()d. * @param stream The data part of the stream. Will not take ownership.
*/ */
explicit SkPDFStream(SkStream* stream); explicit SkPDFStream(SkStream* stream) { this->setData(stream); }
virtual ~SkPDFStream(); virtual ~SkPDFStream();
// The SkPDFObject interface. // The SkPDFObject interface.
void emitObject(SkWStream* stream, void emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap, const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) override; const SkPDFSubstituteMap& substitutes) const override;
protected: protected:
enum State {
kUnused_State, //!< The stream hasn't been requested yet.
kNoCompression_State, //!< The stream's been requested in an
// uncompressed form.
kCompressed_State, //!< The stream's already been compressed.
};
/* Create a PDF stream with no data. The setData method must be called to /* Create a PDF stream with no data. The setData method must be called to
* set the data. * set the data.
*/ */
SkPDFStream(); SkPDFStream() {}
void setData(SkData* data); /** Only call this function once. */
void setData(SkStream* stream); void setData(SkStream* stream);
void setData(SkData* data) {
size_t dataSize() const; SkMemoryStream memoryStream(data);
this->setData(&memoryStream);
void setState(State state) {
fState = state;
} }
private: private:
// Indicates what form (or if) the stream has been requested. SkAutoTDelete<SkStreamRewindable> fCompressedData;
State fState;
SkAutoTDelete<SkStreamRewindable> fDataStream;
typedef SkPDFDict INHERITED; typedef SkPDFDict INHERITED;
}; };

View File

@ -260,7 +260,7 @@ SkPDFUnion SkPDFUnion::Object(SkPDFObject* ptr) {
#if 0 // Enable if needed. #if 0 // Enable if needed.
void SkPDFAtom::emitObject(SkWStream* stream, void SkPDFAtom::emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap, const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) { const SkPDFSubstituteMap& substitutes) const {
fValue.emitObject(stream, objNumMap, substitutes); fValue.emitObject(stream, objNumMap, substitutes);
} }
void SkPDFAtom::addResources(SkPDFObjNumMap* map, void SkPDFAtom::addResources(SkPDFObjNumMap* map,
@ -284,8 +284,8 @@ int SkPDFArray::size() const { return fValues.count(); }
void SkPDFArray::reserve(int length) { fValues.setReserve(length); } void SkPDFArray::reserve(int length) { fValues.setReserve(length); }
void SkPDFArray::emitObject(SkWStream* stream, void SkPDFArray::emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap, const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) { const SkPDFSubstituteMap& substitutes) const {
stream->writeText("["); stream->writeText("[");
for (int i = 0; i < fValues.count(); i++) { for (int i = 0; i < fValues.count(); i++) {
fValues[i].emitObject(stream, objNumMap, substitutes); fValues[i].emitObject(stream, objNumMap, substitutes);
@ -353,7 +353,7 @@ SkPDFDict::SkPDFDict(const char type[]) { this->insertName("Type", type); }
void SkPDFDict::emitObject(SkWStream* stream, void SkPDFDict::emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap, const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) { const SkPDFSubstituteMap& substitutes) const {
stream->writeText("<<"); stream->writeText("<<");
for (int i = 0; i < fRecords.count(); i++) { for (int i = 0; i < fRecords.count(); i++) {
fRecords[i].fKey.emitObject(stream, objNumMap, substitutes); fRecords[i].fKey.emitObject(stream, objNumMap, substitutes);

View File

@ -40,7 +40,7 @@ public:
// TODO(halcanary): make this method const // TODO(halcanary): make this method const
virtual void emitObject(SkWStream* stream, virtual void emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap, const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) = 0; const SkPDFSubstituteMap& substitutes) const = 0;
/** /**
* Adds all transitive dependencies of this object to the * Adds all transitive dependencies of this object to the
@ -200,7 +200,7 @@ public:
// The SkPDFObject interface. // The SkPDFObject interface.
void emitObject(SkWStream* stream, void emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap, const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) override; const SkPDFSubstituteMap& substitutes) const override;
void addResources(SkPDFObjNumMap*, void addResources(SkPDFObjNumMap*,
const SkPDFSubstituteMap&) const override; const SkPDFSubstituteMap&) const override;
@ -255,7 +255,7 @@ public:
// The SkPDFObject interface. // The SkPDFObject interface.
void emitObject(SkWStream* stream, void emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap, const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) override; const SkPDFSubstituteMap& substitutes) const override;
void addResources(SkPDFObjNumMap*, void addResources(SkPDFObjNumMap*,
const SkPDFSubstituteMap&) const override; const SkPDFSubstituteMap&) const override;