SkPDF: PDFStream has-a not is-a PDFDict

Motivation:
SkPDFStream and SkPDFSharedStream now work the same.

Also:
- move SkPDFStream into SkPDFTypes (it's a fundamental PDF type).
- minor refactor of SkPDFSharedStream
- SkPDFSharedStream takes unique_ptr to represent ownership

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2190883003

Review-Url: https://codereview.chromium.org/2190883003
This commit is contained in:
halcanary 2016-07-29 10:13:18 -07:00 committed by Commit bot
parent d05a875273
commit fa25106f02
16 changed files with 161 additions and 181 deletions

View File

@ -137,8 +137,9 @@ protected:
SkASSERT(fAsset);
if (!fAsset) { return; }
while (loops-- > 0) {
sk_sp<SkPDFObject> object(
new SkPDFSharedStream(fAsset->duplicate()));
sk_sp<SkPDFObject> object =
sk_make_sp<SkPDFSharedStream>(
std::unique_ptr<SkStreamAsset>(fAsset->duplicate()));
test_pdf_object_serialization(object);
}
}

View File

@ -39,8 +39,6 @@
'<(skia_src_path)/pdf/SkPDFResourceDict.h',
'<(skia_src_path)/pdf/SkPDFShader.cpp',
'<(skia_src_path)/pdf/SkPDFShader.h',
'<(skia_src_path)/pdf/SkPDFStream.cpp',
'<(skia_src_path)/pdf/SkPDFStream.h',
'<(skia_src_path)/pdf/SkPDFTypes.cpp',
'<(skia_src_path)/pdf/SkPDFTypes.h',
'<(skia_src_path)/pdf/SkPDFUtils.cpp',

View File

@ -24,7 +24,6 @@
#include "SkPDFGraphicState.h"
#include "SkPDFResourceDict.h"
#include "SkPDFShader.h"
#include "SkPDFStream.h"
#include "SkPDFTypes.h"
#include "SkPDFUtils.h"
#include "SkRasterClip.h"

View File

@ -9,7 +9,6 @@
#include "SkPDFCanvas.h"
#include "SkPDFDevice.h"
#include "SkPDFDocument.h"
#include "SkPDFStream.h"
#include "SkPDFUtils.h"
#include "SkStream.h"
@ -321,7 +320,7 @@ static sk_sp<SkData> SkSrgbIcm() {
static sk_sp<SkPDFStream> make_srgb_color_profile() {
sk_sp<SkPDFStream> stream = sk_make_sp<SkPDFStream>(SkSrgbIcm());
stream->insertInt("N", 3);
stream->dict()->insertInt("N", 3);
sk_sp<SkPDFArray> array = sk_make_sp<SkPDFArray>();
array->appendScalar(0.0f);
array->appendScalar(1.0f);
@ -329,7 +328,7 @@ static sk_sp<SkPDFStream> make_srgb_color_profile() {
array->appendScalar(1.0f);
array->appendScalar(0.0f);
array->appendScalar(1.0f);
stream->insertObject("Range", std::move(array));
stream->dict()->insertObject("Range", std::move(array));
return stream;
}

View File

@ -14,7 +14,6 @@
#include "SkPDFDevice.h"
#include "SkPDFFont.h"
#include "SkPDFFontImpl.h"
#include "SkPDFStream.h"
#include "SkPDFUtils.h"
#include "SkRefCnt.h"
#include "SkScalar.h"
@ -1006,7 +1005,7 @@ static sk_sp<SkPDFObject> get_subset_font_stream(
subsetFont, subsetFontSize,
[](const void* p, void*) { delete[] (unsigned char*)p; },
nullptr));
subsetStream->insertInt("Length1", subsetFontSize);
subsetStream->dict()->insertInt("Length1", subsetFontSize);
return subsetStream;
}
#endif // SK_SFNTLY_SUBSETTER
@ -1048,7 +1047,7 @@ bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
fontAsset.reset(this->typeface()->openStream(&ttcIndex));
}
#endif // SK_SFNTLY_SUBSETTER
auto fontStream = sk_make_sp<SkPDFSharedStream>(fontAsset.release());
auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset));
fontStream->dict()->insertInt("Length1", fontSize);
descriptor->insertObjRef("FontFile2", std::move(fontStream));
break;
@ -1062,8 +1061,7 @@ bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
if (!fontData || 0 == fontData->getLength()) {
return false;
}
sk_sp<SkPDFSharedStream> fontStream(
new SkPDFSharedStream(fontData.release()));
auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontData));
if (getType() == SkAdvancedTypefaceMetrics::kCFF_Font) {
fontStream->dict()->insertName("Subtype", "Type1C");
} else {
@ -1200,9 +1198,9 @@ bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
}
SkASSERT(this->canEmbed());
auto fontStream = sk_make_sp<SkPDFStream>(std::move(fontData));
fontStream->insertInt("Length1", header);
fontStream->insertInt("Length2", data);
fontStream->insertInt("Length3", trailer);
fontStream->dict()->insertInt("Length1", header);
fontStream->dict()->insertInt("Length2", data);
fontStream->dict()->insertInt("Length3", trailer);
descriptor->insertObjRef("FontFile", std::move(fontStream));
this->insertObjRef("FontDescriptor", std::move(descriptor));

View File

@ -15,14 +15,14 @@ sk_sp<SkPDFObject> SkPDFMakeFormXObject(std::unique_ptr<SkStreamAsset> content,
const SkMatrix& inverseTransform,
const char* colorSpace) {
auto form = sk_make_sp<SkPDFStream>(std::move(content));
form->insertName("Type", "XObject");
form->insertName("Subtype", "Form");
form->dict()->insertName("Type", "XObject");
form->dict()->insertName("Subtype", "Form");
if (!inverseTransform.isIdentity()) {
form->insertObject("Matrix",
SkPDFUtils::MatrixToArray(inverseTransform));
sk_sp<SkPDFObject> mat(SkPDFUtils::MatrixToArray(inverseTransform));
form->dict()->insertObject("Matrix", std::move(mat));
}
form->insertObject("Resources", std::move(resourceDict));
form->insertObject("BBox", std::move(mediaBox));
form->dict()->insertObject("Resources", std::move(resourceDict));
form->dict()->insertObject("BBox", std::move(mediaBox));
// Right now FormXObject is only used for saveLayer, which implies
// isolated blending. Do this conditionally if that changes.
@ -34,6 +34,6 @@ sk_sp<SkPDFObject> SkPDFMakeFormXObject(std::unique_ptr<SkStreamAsset> content,
group->insertName("CS", colorSpace);
}
group->insertBool("I", true); // Isolated.
form->insertObject("Group", std::move(group));
form->dict()->insertObject("Group", std::move(group));
return form;
}

View File

@ -9,8 +9,8 @@
#ifndef SkPDFFormXObject_DEFINED
#define SkPDFFormXObject_DEFINED
#include "SkPDFStream.h"
#include "SkPDFDevice.h"
#include "SkPDFTypes.h"
/** A form XObject is a self contained description of a graphics
object. A form XObject is a page object with slightly different

View File

@ -137,9 +137,9 @@ sk_sp<SkPDFStream> SkPDFGraphicState::MakeInvertFunction() {
// Do not copy the trailing '\0' into the SkData.
auto invertFunction = sk_make_sp<SkPDFStream>(
SkData::MakeWithoutCopy(psInvert, strlen(psInvert)));
invertFunction->insertInt("FunctionType", 4);
invertFunction->insertObject("Domain", domainAndRange);
invertFunction->insertObject("Range", std::move(domainAndRange));
invertFunction->dict()->insertInt("FunctionType", 4);
invertFunction->dict()->insertObject("Domain", domainAndRange);
invertFunction->dict()->insertObject("Range", std::move(domainAndRange));
return invertFunction;
}

View File

@ -9,7 +9,7 @@
#ifndef SkPDFGraphicState_DEFINED
#define SkPDFGraphicState_DEFINED
#include "SkPDFStream.h"
#include "SkPDFTypes.h"
#include "SkChecksum.h"
class SkPaint;

View File

@ -743,8 +743,9 @@ SkPDFAlphaFunctionShader* SkPDFAlphaFunctionShader::Create(
create_pattern_fill_content(0, bbox));
alphaFunctionShader->setData(std::move(colorStream));
populate_tiling_pattern_dict(alphaFunctionShader, bbox, resourceDict.get(),
SkMatrix::I());
populate_tiling_pattern_dict(
alphaFunctionShader->dict(), bbox, resourceDict.get(),
SkMatrix::I());
doc->canon()->addAlphaShader(alphaFunctionShader);
return alphaFunctionShader;
}
@ -804,9 +805,9 @@ static sk_sp<SkPDFStream> make_ps_function(
SkPDFArray* domain,
sk_sp<SkPDFObject> range) {
auto result = sk_make_sp<SkPDFStream>(std::move(psCode));
result->insertInt("FunctionType", 4);
result->insertObject("Domain", sk_ref_sp(domain));
result->insertObject("Range", std::move(range));
result->dict()->insertInt("FunctionType", 4);
result->dict()->insertObject("Domain", sk_ref_sp(domain));
result->dict()->insertObject("Range", std::move(range));
return result;
}
@ -1213,7 +1214,7 @@ SkPDFImageShader* SkPDFImageShader::Create(
imageShader->setData(patternDevice->content());
auto resourceDict = patternDevice->makeResourceDict();
populate_tiling_pattern_dict(imageShader, patternBBox,
populate_tiling_pattern_dict(imageShader->dict(), patternBBox,
resourceDict.get(), finalMatrix);
imageShader->fShaderState->fImage.unlockPixels();

View File

@ -9,7 +9,6 @@
#ifndef SkPDFShader_DEFINED
#define SkPDFShader_DEFINED
#include "SkPDFStream.h"
#include "SkPDFTypes.h"
class SkPDFCanon;

View File

@ -1,64 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkData.h"
#include "SkDeflate.h"
#include "SkPDFStream.h"
#include "SkStreamPriv.h"
SkPDFStream::~SkPDFStream() {}
void SkPDFStream::drop() {
fCompressedData.reset(nullptr);
this->SkPDFDict::drop();
}
void SkPDFStream::emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) const {
SkASSERT(fCompressedData);
this->INHERITED::emitObject(stream, objNumMap, substitutes);
// duplicate (a cheap operation) preserves const on fCompressedData.
std::unique_ptr<SkStreamAsset> dup(fCompressedData->duplicate());
SkASSERT(dup);
SkASSERT(dup->hasLength());
stream->writeText(" stream\n");
stream->writeStream(dup.get(), dup->getLength());
stream->writeText("\nendstream");
}
void SkPDFStream::setData(std::unique_ptr<SkStreamAsset> stream) {
SkASSERT(!fCompressedData); // Only call this function once.
SkASSERT(stream);
// Code assumes that the stream starts at the beginning.
#ifdef SK_PDF_LESS_COMPRESSION
fCompressedData = std::move(stream);
SkASSERT(fCompressedData && fCompressedData->hasLength());
this->insertInt("Length", fCompressedData->getLength());
#else
SkASSERT(stream->hasLength());
SkDynamicMemoryWStream compressedData;
SkDeflateWStream deflateWStream(&compressedData);
SkStreamCopy(&deflateWStream, stream.get());
deflateWStream.finalize();
size_t compressedLength = compressedData.bytesWritten();
size_t originalLength = stream->getLength();
if (originalLength <= compressedLength + strlen("/Filter_/FlateDecode_")) {
SkAssertResult(stream->rewind());
fCompressedData = std::move(stream);
this->insertInt("Length", originalLength);
return;
}
fCompressedData.reset(compressedData.detachAsStream());
this->insertName("Filter", "FlateDecode");
this->insertInt("Length", compressedLength);
#endif
}

View File

@ -1,62 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPDFStream_DEFINED
#define SkPDFStream_DEFINED
#include "SkPDFTypes.h"
#include "SkStream.h"
/** \class SkPDFStream
A stream object in a PDF. Note, all streams must be indirect objects (via
SkObjRef).
*/
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. */
explicit SkPDFStream(sk_sp<SkData> data) {
this->setData(std::unique_ptr<SkStreamAsset>(
new SkMemoryStream(std::move(data))));
}
/** Create a PDF stream. A Length entry is automatically added to the
* stream dictionary.
* @param stream The data part of the stream.
*/
explicit SkPDFStream(std::unique_ptr<SkStreamAsset> stream) {
this->setData(std::move(stream));
}
virtual ~SkPDFStream();
// The SkPDFObject interface.
void emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) const override;
void drop() override;
protected:
/* Create a PDF stream with no data. The setData method must be called to
* set the data.
*/
SkPDFStream() {}
/** Only call this function once. */
void setData(std::unique_ptr<SkStreamAsset> stream);
private:
std::unique_ptr<SkStreamAsset> fCompressedData;
typedef SkPDFDict INHERITED;
};
#endif

View File

@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
#include "SkData.h"
#include "SkDeflate.h"
#include "SkPDFTypes.h"
#include "SkPDFUtils.h"
@ -456,18 +457,16 @@ void SkPDFDict::insertString(const char key[], const SkString& value) {
////////////////////////////////////////////////////////////////////////////////
SkPDFSharedStream::SkPDFSharedStream(SkStreamAsset* data)
: fAsset(data), fDict(new SkPDFDict) {
SkDEBUGCODE(fDumped = false;)
SkASSERT(data);
SkPDFSharedStream::SkPDFSharedStream(std::unique_ptr<SkStreamAsset> data)
: fAsset(std::move(data)) {
SkASSERT(fAsset);
}
SkPDFSharedStream::~SkPDFSharedStream() { this->drop(); }
void SkPDFSharedStream::drop() {
fAsset.reset();
fDict.reset(nullptr);
SkDEBUGCODE(fDumped = true;)
fAsset = nullptr;;
fDict.drop();
}
#ifdef SK_PDF_LESS_COMPRESSION
@ -475,12 +474,12 @@ void SkPDFSharedStream::emitObject(
SkWStream* stream,
const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) const {
SkASSERT(!fDumped);
SkASSERT(fAsset);
std::unique_ptr<SkStreamAsset> dup(fAsset->duplicate());
SkASSERT(dup && dup->hasLength());
size_t length = dup->getLength();
stream->writeText("<<");
fDict->emitAll(stream, objNumMap, substitutes);
fDict.emitAll(stream, objNumMap, substitutes);
stream->writeText("\n");
SkPDFUnion::Name("Length").emitObject(
stream, objNumMap, substitutes);
@ -496,7 +495,7 @@ void SkPDFSharedStream::emitObject(
SkWStream* stream,
const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) const {
SkASSERT(!fDumped);
SkASSERT(fAsset);
SkDynamicMemoryWStream buffer;
SkDeflateWStream deflateWStream(&buffer);
// Since emitObject is const, this function doesn't change the dictionary.
@ -506,7 +505,7 @@ void SkPDFSharedStream::emitObject(
deflateWStream.finalize();
size_t length = buffer.bytesWritten();
stream->writeText("<<");
fDict->emitAll(stream, objNumMap, substitutes);
fDict.emitAll(stream, objNumMap, substitutes);
stream->writeText("\n");
SkPDFUnion::Name("Length").emitObject(stream, objNumMap, substitutes);
stream->writeText(" ");
@ -524,8 +523,80 @@ void SkPDFSharedStream::emitObject(
void SkPDFSharedStream::addResources(
SkPDFObjNumMap* catalog, const SkPDFSubstituteMap& substitutes) const {
SkASSERT(!fDumped);
fDict->addResources(catalog, substitutes);
SkASSERT(fAsset);
fDict.addResources(catalog, substitutes);
}
////////////////////////////////////////////////////////////////////////////////
SkPDFStream:: SkPDFStream(sk_sp<SkData> data) {
this->setData(std::unique_ptr<SkStreamAsset>(
new SkMemoryStream(std::move(data))));
}
SkPDFStream::SkPDFStream(std::unique_ptr<SkStreamAsset> stream) {
this->setData(std::move(stream));
}
SkPDFStream::SkPDFStream() {}
SkPDFStream::~SkPDFStream() {}
void SkPDFStream::addResources(
SkPDFObjNumMap* catalog, const SkPDFSubstituteMap& substitutes) const {
SkASSERT(fCompressedData);
fDict.addResources(catalog, substitutes);
}
void SkPDFStream::drop() {
fCompressedData.reset(nullptr);
fDict.drop();
}
void SkPDFStream::emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) const {
SkASSERT(fCompressedData);
fDict.emitObject(stream, objNumMap, substitutes);
// duplicate (a cheap operation) preserves const on fCompressedData.
std::unique_ptr<SkStreamAsset> dup(fCompressedData->duplicate());
SkASSERT(dup);
SkASSERT(dup->hasLength());
stream->writeText(" stream\n");
stream->writeStream(dup.get(), dup->getLength());
stream->writeText("\nendstream");
}
void SkPDFStream::setData(std::unique_ptr<SkStreamAsset> stream) {
SkASSERT(!fCompressedData); // Only call this function once.
SkASSERT(stream);
// Code assumes that the stream starts at the beginning.
#ifdef SK_PDF_LESS_COMPRESSION
fCompressedData = std::move(stream);
SkASSERT(fCompressedData && fCompressedData->hasLength());
fDict.insertInt("Length", fCompressedData->getLength());
#else
SkASSERT(stream->hasLength());
SkDynamicMemoryWStream compressedData;
SkDeflateWStream deflateWStream(&compressedData);
SkStreamCopy(&deflateWStream, stream.get());
deflateWStream.finalize();
size_t compressedLength = compressedData.bytesWritten();
size_t originalLength = stream->getLength();
if (originalLength <= compressedLength + strlen("/Filter_/FlateDecode_")) {
SkAssertResult(stream->rewind());
fCompressedData = std::move(stream);
fDict.insertInt("Length", originalLength);
return;
}
fCompressedData.reset(compressedData.detachAsStream());
fDict.insertName("Filter", "FlateDecode");
fDict.insertInt("Length", compressedLength);
#endif
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -14,6 +14,7 @@
#include "SkTHash.h"
#include "SkTypes.h"
class SkData;
class SkPDFObjNumMap;
class SkPDFObject;
class SkPDFSubstituteMap;
@ -307,10 +308,9 @@ private:
*/
class SkPDFSharedStream final : public SkPDFObject {
public:
// Takes ownership of asset.
SkPDFSharedStream(SkStreamAsset* data);
SkPDFSharedStream(std::unique_ptr<SkStreamAsset> data);
~SkPDFSharedStream();
SkPDFDict* dict() { return fDict.get(); }
SkPDFDict* dict() { return &fDict; }
void emitObject(SkWStream*,
const SkPDFObjNumMap&,
const SkPDFSubstituteMap&) const override;
@ -320,11 +320,52 @@ public:
private:
std::unique_ptr<SkStreamAsset> fAsset;
sk_sp<SkPDFDict> fDict;
SkDEBUGCODE(bool fDumped;)
SkPDFDict fDict;
typedef SkPDFObject INHERITED;
};
/** \class SkPDFStream
This class takes an asset and assumes that it is the only owner of
the asset's data. It immediately compresses the asset to save
memory.
*/
class SkPDFStream : public SkPDFObject {
public:
/** Create a PDF stream. A Length entry is automatically added to the
* stream dictionary.
* @param data The data part of the stream.
* @param stream The data part of the stream. */
explicit SkPDFStream(sk_sp<SkData> data);
explicit SkPDFStream(std::unique_ptr<SkStreamAsset> stream);
virtual ~SkPDFStream();
SkPDFDict* dict() { return &fDict; }
// The SkPDFObject interface.
void emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) const override;
void addResources(SkPDFObjNumMap*, const SkPDFSubstituteMap&) const final;
void drop() override;
protected:
/* Create a PDF stream with no data. The setData method must be called to
* set the data. */
SkPDFStream();
/** Only call this function once. */
void setData(std::unique_ptr<SkStreamAsset> stream);
private:
std::unique_ptr<SkStreamAsset> fCompressedData;
SkPDFDict fDict;
typedef SkPDFDict INHERITED;
};
////////////////////////////////////////////////////////////////////////////////
/** \class SkPDFObjNumMap

View File

@ -16,7 +16,6 @@
#include "SkPDFCanon.h"
#include "SkPDFDevice.h"
#include "SkPDFFont.h"
#include "SkPDFStream.h"
#include "SkPDFTypes.h"
#include "SkPDFUtils.h"
#include "SkReadBuffer.h"
@ -89,7 +88,7 @@ static void TestPDFStream(skiatest::Reporter* reporter) {
assert_emit_eq(reporter,
*stream,
"<</Length 12>> stream\nTest\nFoo\tBar\nendstream");
stream->insertInt("Attribute", 42);
stream->dict()->insertInt("Attribute", 42);
assert_emit_eq(reporter,
*stream,
"<</Length 12\n/Attribute 42>> stream\n"