aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pdf
diff options
context:
space:
mode:
authorGravatar vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-07-20 17:39:01 +0000
committerGravatar vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-07-20 17:39:01 +0000
commit421d6443fbd3a913dfa32b6492c4a2969bc6314b (patch)
tree5c02a30275d78adf764e0c91437bada0c6dcbd33 /src/pdf
parentf6c3ebdeb135dcdb9af225bd7af77f1fe1f92787 (diff)
[PDF] Make stream compression optional on a per device basis.
There are a lot of small pieces to make this change work: - SkPDFDocument (and SkPDFCatalog) take flags to disable compression (and font embedding - not implemented yet, can disable font subsetting for now). - SkPDFStream now defers compression until the size/emit step. - Classes that *had* a stream (because they didn't know the stream size at construction time) now *are* streams to make the substitution work correctly. - The SkPDFShader implementation got pulled apart into two classes, one that is a SkPDFDict, and one that is a SkPDFStream (making the common ancestor SkPDFObject). - Added helper methods in SkPDFObject for children that have simple resource lists. - Added an iterator to SkPDFDict so that a substitute SkPDFStream can get a copy of the stream dictionary. - Change SkPDFDocument to have a pointer to an SkPDFCatalog to remove a new circular header reference. Review URL: http://codereview.appspot.com/4700045 git-svn-id: http://skia.googlecode.com/svn/trunk@1911 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/pdf')
-rw-r--r--src/pdf/SkPDFCatalog.cpp5
-rw-r--r--src/pdf/SkPDFDevice.cpp2
-rw-r--r--src/pdf/SkPDFDocument.cpp74
-rwxr-xr-xsrc/pdf/SkPDFFont.cpp7
-rw-r--r--src/pdf/SkPDFFormXObject.cpp32
-rw-r--r--src/pdf/SkPDFGraphicState.cpp7
-rw-r--r--src/pdf/SkPDFImage.cpp36
-rw-r--r--src/pdf/SkPDFShader.cpp188
-rw-r--r--src/pdf/SkPDFStream.cpp106
-rw-r--r--src/pdf/SkPDFTypes.cpp44
10 files changed, 292 insertions, 209 deletions
diff --git a/src/pdf/SkPDFCatalog.cpp b/src/pdf/SkPDFCatalog.cpp
index 025c86d82f..420ce40511 100644
--- a/src/pdf/SkPDFCatalog.cpp
+++ b/src/pdf/SkPDFCatalog.cpp
@@ -19,10 +19,11 @@
#include "SkStream.h"
#include "SkTypes.h"
-SkPDFCatalog::SkPDFCatalog()
+SkPDFCatalog::SkPDFCatalog(SkPDFDocument::Flags flags)
: fFirstPageCount(0),
fNextObjNum(1),
- fNextFirstPageObjNum(0) {
+ fNextFirstPageObjNum(0),
+ fDocumentFlags(flags) {
}
SkPDFCatalog::~SkPDFCatalog() {
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 7833362b6c..caba8226b4 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1394,7 +1394,7 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint(
entry->fClipRegion = clipRegion;
// PDF treats a shader as a color, so we only set one or the other.
- SkRefPtr<SkPDFShader> pdfShader;
+ SkRefPtr<SkPDFObject> pdfShader;
const SkShader* shader = paint.getShader();
SkColor color = paint.getColor();
if (shader) {
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
index 1cfe64df12..d60512e7ac 100644
--- a/src/pdf/SkPDFDocument.cpp
+++ b/src/pdf/SkPDFDocument.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
#include "SkPDFDocument.h"
#include "SkPDFPage.h"
@@ -36,12 +37,13 @@ void addResourcesToCatalog(int firstIndex, bool firstPage,
}
}
-SkPDFDocument::SkPDFDocument()
+SkPDFDocument::SkPDFDocument(Flags flags)
: fXRefFileOffset(0),
fSecondPageFirstResourceIndex(0) {
+ fCatalog.reset(new SkPDFCatalog(flags));
fDocCatalog = new SkPDFDict("Catalog");
fDocCatalog->unref(); // SkRefPtr and new both took a reference.
- fCatalog.addObject(fDocCatalog.get(), true);
+ fCatalog->addObject(fDocCatalog.get(), true);
}
SkPDFDocument::~SkPDFDocument() {
@@ -68,7 +70,7 @@ bool SkPDFDocument::emitPDF(SkWStream* stream) {
// We haven't emitted the document before if fPageTree is empty.
if (fPageTree.count() == 0) {
SkPDFDict* pageTreeRoot;
- SkPDFPage::GeneratePageTree(fPages, &fCatalog, &fPageTree,
+ SkPDFPage::GeneratePageTree(fPages, fCatalog.get(), &fPageTree,
&pageTreeRoot);
fDocCatalog->insert("Pages", new SkPDFObjRef(pageTreeRoot))->unref();
@@ -87,9 +89,9 @@ bool SkPDFDocument::emitPDF(SkWStream* stream) {
bool firstPage = true;
for (int i = 0; i < fPages.count(); i++) {
int resourceCount = fPageResources.count();
- fPages[i]->finalizePage(&fCatalog, firstPage, &fPageResources);
+ fPages[i]->finalizePage(fCatalog.get(), firstPage, &fPageResources);
addResourcesToCatalog(resourceCount, firstPage, &fPageResources,
- &fCatalog);
+ fCatalog.get());
if (i == 0) {
firstPage = false;
fSecondPageFirstResourceIndex = fPageResources.count();
@@ -98,57 +100,67 @@ bool SkPDFDocument::emitPDF(SkWStream* stream) {
// Figure out the size of things and inform the catalog of file offsets.
off_t fileOffset = headerSize();
- fileOffset += fCatalog.setFileOffset(fDocCatalog.get(), fileOffset);
- fileOffset += fCatalog.setFileOffset(fPages[0], fileOffset);
- fileOffset += fPages[0]->getPageSize(&fCatalog, fileOffset);
- for (int i = 0; i < fSecondPageFirstResourceIndex; i++)
- fileOffset += fCatalog.setFileOffset(fPageResources[i], fileOffset);
+ fileOffset += fCatalog->setFileOffset(fDocCatalog.get(), fileOffset);
+ fileOffset += fCatalog->setFileOffset(fPages[0], fileOffset);
+ fileOffset += fPages[0]->getPageSize(fCatalog.get(), fileOffset);
+ for (int i = 0; i < fSecondPageFirstResourceIndex; i++) {
+ fileOffset += fCatalog->setFileOffset(fPageResources[i],
+ fileOffset);
+ }
// Add the size of resources of substitute objects used on page 1.
- fileOffset += fCatalog.setSubstituteResourcesOffsets(fileOffset, true);
+ fileOffset += fCatalog->setSubstituteResourcesOffsets(fileOffset, true);
if (fPages.count() > 1) {
// TODO(vandebo) For linearized format, save the start of the
// first page xref table and calculate the size.
}
for (int i = 0; i < fPageTree.count(); i++)
- fileOffset += fCatalog.setFileOffset(fPageTree[i], fileOffset);
+ fileOffset += fCatalog->setFileOffset(fPageTree[i], fileOffset);
for (int i = 1; i < fPages.count(); i++)
- fileOffset += fPages[i]->getPageSize(&fCatalog, fileOffset);
+ fileOffset += fPages[i]->getPageSize(fCatalog.get(), fileOffset);
for (int i = fSecondPageFirstResourceIndex;
i < fPageResources.count();
i++)
- fileOffset += fCatalog.setFileOffset(fPageResources[i], fileOffset);
+ fileOffset += fCatalog->setFileOffset(fPageResources[i],
+ fileOffset);
- fileOffset += fCatalog.setSubstituteResourcesOffsets(fileOffset, false);
+ fileOffset += fCatalog->setSubstituteResourcesOffsets(fileOffset,
+ false);
fXRefFileOffset = fileOffset;
}
emitHeader(stream);
- fDocCatalog->emitObject(stream, &fCatalog, true);
- fPages[0]->emitObject(stream, &fCatalog, true);
- fPages[0]->emitPage(stream, &fCatalog);
- for (int i = 0; i < fSecondPageFirstResourceIndex; i++)
- fPageResources[i]->emit(stream, &fCatalog, true);
- fCatalog.emitSubstituteResources(stream, true);
+ fDocCatalog->emitObject(stream, fCatalog.get(), true);
+ fPages[0]->emitObject(stream, fCatalog.get(), true);
+ fPages[0]->emitPage(stream, fCatalog.get());
+ for (int i = 0; i < fSecondPageFirstResourceIndex; i++) {
+ fPageResources[i]->emit(stream, fCatalog.get(), true);
+ }
+ fCatalog->emitSubstituteResources(stream, true);
// TODO(vandebo) support linearized format
//if (fPages.size() > 1) {
// // TODO(vandebo) save the file offset for the first page xref table.
- // fCatalog.emitXrefTable(stream, true);
+ // fCatalog->emitXrefTable(stream, true);
//}
- for (int i = 0; i < fPageTree.count(); i++)
- fPageTree[i]->emitObject(stream, &fCatalog, true);
+ for (int i = 0; i < fPageTree.count(); i++) {
+ fPageTree[i]->emitObject(stream, fCatalog.get(), true);
+ }
- for (int i = 1; i < fPages.count(); i++)
- fPages[i]->emitPage(stream, &fCatalog);
+ for (int i = 1; i < fPages.count(); i++) {
+ fPages[i]->emitPage(stream, fCatalog.get());
+ }
- for (int i = fSecondPageFirstResourceIndex; i < fPageResources.count(); i++)
- fPageResources[i]->emit(stream, &fCatalog, true);
+ for (int i = fSecondPageFirstResourceIndex;
+ i < fPageResources.count();
+ i++) {
+ fPageResources[i]->emit(stream, fCatalog.get(), true);
+ }
- fCatalog.emitSubstituteResources(stream, false);
- int64_t objCount = fCatalog.emitXrefTable(stream, fPages.count() > 1);
+ fCatalog->emitSubstituteResources(stream, false);
+ int64_t objCount = fCatalog->emitXrefTable(stream, fPages.count() > 1);
emitFooter(stream, objCount);
return true;
}
@@ -217,7 +229,7 @@ void SkPDFDocument::emitFooter(SkWStream* stream, int64_t objCount) {
}
stream->writeText("trailer\n");
- fTrailerDict->emitObject(stream, &fCatalog, false);
+ fTrailerDict->emitObject(stream, fCatalog.get(), false);
stream->writeText("\nstartxref\n");
stream->writeBigDecAsText(fXRefFileOffset);
stream->writeText("\n%%EOF");
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index 4602c68e1c..be16c76936 100755
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -435,12 +435,7 @@ SkPDFFont::~SkPDFFont() {
}
void SkPDFFont::getResources(SkTDArray<SkPDFObject*>* resourceList) {
- resourceList->setReserve(resourceList->count() + fResources.count());
- for (int i = 0; i < fResources.count(); i++) {
- resourceList->push(fResources[i]);
- fResources[i]->ref();
- fResources[i]->getResources(resourceList);
- }
+ GetResourcesHelper(&fResources, resourceList);
}
SkTypeface* SkPDFFont::typeface() {
diff --git a/src/pdf/SkPDFFormXObject.cpp b/src/pdf/SkPDFFormXObject.cpp
index 40a5564847..a8a3290e22 100644
--- a/src/pdf/SkPDFFormXObject.cpp
+++ b/src/pdf/SkPDFFormXObject.cpp
@@ -31,8 +31,7 @@ SkPDFFormXObject::SkPDFFormXObject(SkPDFDevice* device) {
SkRefPtr<SkStream> content = device->content();
content->unref(); // SkRefPtr and content() both took a reference.
- fStream = new SkPDFStream(content.get());
- fStream->unref(); // SkRefPtr and new both took a reference.
+ setData(content.get());
insert("Type", new SkPDFName("XObject"))->unref();
insert("Subtype", new SkPDFName("Form"))->unref();
@@ -62,33 +61,6 @@ SkPDFFormXObject::~SkPDFFormXObject() {
fResources.unrefAll();
}
-void SkPDFFormXObject::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
- bool indirect) {
- if (indirect)
- return emitIndirectObject(stream, catalog);
-
- fStream->emitObject(stream, catalog, indirect);
-}
-
-size_t SkPDFFormXObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
- if (indirect)
- return getIndirectOutputSize(catalog);
-
- return fStream->getOutputSize(catalog, indirect);
-}
-
void SkPDFFormXObject::getResources(SkTDArray<SkPDFObject*>* resourceList) {
- resourceList->setReserve(resourceList->count() + fResources.count());
- for (int i = 0; i < fResources.count(); i++) {
- resourceList->push(fResources[i]);
- fResources[i]->ref();
- }
-}
-
-SkPDFObject* SkPDFFormXObject::insert(SkPDFName* key, SkPDFObject* value) {
- return fStream->insert(key, value);
-}
-
-SkPDFObject* SkPDFFormXObject::insert(const char key[], SkPDFObject* value) {
- return fStream->insert(key, value);
+ GetResourcesHelper(&fResources, resourceList);
}
diff --git a/src/pdf/SkPDFGraphicState.cpp b/src/pdf/SkPDFGraphicState.cpp
index 59b2817518..0e6e23049c 100644
--- a/src/pdf/SkPDFGraphicState.cpp
+++ b/src/pdf/SkPDFGraphicState.cpp
@@ -67,12 +67,7 @@ SkPDFGraphicState::~SkPDFGraphicState() {
}
void SkPDFGraphicState::getResources(SkTDArray<SkPDFObject*>* resourceList) {
- resourceList->setReserve(resourceList->count() + fResources.count());
- for (int i = 0; i < fResources.count(); i++) {
- resourceList->push(fResources[i]);
- fResources[i]->ref();
- fResources[i]->getResources(resourceList);
- }
+ GetResourcesHelper(&fResources, resourceList);
}
void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
diff --git a/src/pdf/SkPDFImage.cpp b/src/pdf/SkPDFImage.cpp
index be69f7f757..ebbcd11a97 100644
--- a/src/pdf/SkPDFImage.cpp
+++ b/src/pdf/SkPDFImage.cpp
@@ -281,38 +281,14 @@ SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) {
return mask;
}
-void SkPDFImage::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
- bool indirect) {
- if (indirect)
- return emitIndirectObject(stream, catalog);
-
- fStream->emitObject(stream, catalog, indirect);
-}
-
-size_t SkPDFImage::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
- if (indirect)
- return getIndirectOutputSize(catalog);
-
- return fStream->getOutputSize(catalog, indirect);
-}
-
void SkPDFImage::getResources(SkTDArray<SkPDFObject*>* resourceList) {
- if (fResources.count()) {
- resourceList->setReserve(resourceList->count() + fResources.count());
- for (int i = 0; i < fResources.count(); i++) {
- resourceList->push(fResources[i]);
- fResources[i]->ref();
- fResources[i]->getResources(resourceList);
- }
- }
+ GetResourcesHelper(&fResources, resourceList);
}
SkPDFImage::SkPDFImage(SkStream* imageData, const SkBitmap& bitmap,
const SkIRect& srcRect, bool doingAlpha,
const SkPaint& paint) {
- fStream = new SkPDFStream(imageData);
- fStream->unref(); // SkRefPtr and new both took a reference.
-
+ this->setData(imageData);
SkBitmap::Config config = bitmap.getConfig();
bool alphaOnly = (config == SkBitmap::kA1_Config ||
config == SkBitmap::kA8_Config);
@@ -372,11 +348,3 @@ SkPDFImage::SkPDFImage(SkStream* imageData, const SkBitmap& bitmap,
insert("Decode", decodeValue.get());
}
}
-
-SkPDFObject* SkPDFImage::insert(SkPDFName* key, SkPDFObject* value) {
- return fStream->insert(key, value);
-}
-
-SkPDFObject* SkPDFImage::insert(const char key[], SkPDFObject* value) {
- return fStream->insert(key, value);
-}
diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp
index 95fdb612f0..ee225173b7 100644
--- a/src/pdf/SkPDFShader.cpp
+++ b/src/pdf/SkPDFShader.cpp
@@ -17,6 +17,7 @@
#include "SkPDFShader.h"
#include "SkCanvas.h"
+#include "SkData.h"
#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
#include "SkPDFTypes.h"
@@ -286,65 +287,107 @@ static SkString sweepCode(const SkShader::GradientInfo& info) {
return function;
}
-SkPDFShader::~SkPDFShader() {
- SkAutoMutexAcquire lock(CanonicalShadersMutex());
- ShaderCanonicalEntry entry(this, fState.get());
- int index = CanonicalShaders().find(entry);
- if (fContent.get()) {
- SkASSERT(index >= 0);
- CanonicalShaders().removeShuffle(index);
+class SkPDFShader::State {
+public:
+ SkShader::GradientType fType;
+ SkShader::GradientInfo fInfo;
+ SkAutoFree fColorData;
+ SkMatrix fCanvasTransform;
+ SkMatrix fShaderTransform;
+ SkIRect fBBox;
+
+ SkBitmap fImage;
+ uint32_t fPixelGeneration;
+ SkShader::TileMode fImageTileModes[2];
+
+ explicit State(const SkShader& shader, const SkMatrix& canvasTransform,
+ const SkIRect& bbox);
+ bool operator==(const State& b) const;
+};
+
+class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader {
+public:
+ SkPDFFunctionShader(SkPDFShader::State* state);
+ ~SkPDFFunctionShader() {
+ if (isValid()) {
+ RemoveShader(this);
+ }
+ fResources.unrefAll();
}
- fResources.unrefAll();
-}
-void SkPDFShader::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
- bool indirect) {
- if (indirect)
- return emitIndirectObject(stream, catalog);
+ bool isValid() { return fResources.count() > 0; }
- fContent->emitObject(stream, catalog, indirect);
-}
+ void getResources(SkTDArray<SkPDFObject*>* resourceList) {
+ GetResourcesHelper(&fResources, resourceList);
+ }
-size_t SkPDFShader::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
- if (indirect)
- return getIndirectOutputSize(catalog);
+private:
+ static SkPDFObject* RangeObject();
- return fContent->getOutputSize(catalog, indirect);
-}
+ SkTDArray<SkPDFObject*> fResources;
+ SkAutoTDelete<const SkPDFShader::State> fState;
-void SkPDFShader::getResources(SkTDArray<SkPDFObject*>* resourceList) {
- resourceList->setReserve(resourceList->count() + fResources.count());
- for (int i = 0; i < fResources.count(); i++) {
- resourceList->push(fResources[i]);
- fResources[i]->ref();
+ SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain);
+};
+
+class SkPDFImageShader : public SkPDFStream, public SkPDFShader {
+public:
+ SkPDFImageShader(SkPDFShader::State* state);
+ ~SkPDFImageShader() {
+ RemoveShader(this);
+ fResources.unrefAll();
+ }
+
+ void getResources(SkTDArray<SkPDFObject*>* resourceList) {
+ GetResourcesHelper(&fResources, resourceList);
}
+
+private:
+ SkTDArray<SkPDFObject*> fResources;
+ SkAutoTDelete<const SkPDFShader::State> fState;
+};
+
+SkPDFShader::SkPDFShader() {}
+
+// static
+void SkPDFShader::RemoveShader(SkPDFObject* shader) {
+ SkAutoMutexAcquire lock(CanonicalShadersMutex());
+ ShaderCanonicalEntry entry(shader, NULL);
+ int index = CanonicalShaders().find(entry);
+ SkASSERT(index >= 0);
+ CanonicalShaders().removeShuffle(index);
}
// static
-SkPDFShader* SkPDFShader::GetPDFShader(const SkShader& shader,
+SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader,
const SkMatrix& matrix,
const SkIRect& surfaceBBox) {
- SkRefPtr<SkPDFShader> pdfShader;
+ SkPDFObject* result;
SkAutoMutexAcquire lock(CanonicalShadersMutex());
SkAutoTDelete<State> shaderState(new State(shader, matrix, surfaceBBox));
ShaderCanonicalEntry entry(NULL, shaderState.get());
int index = CanonicalShaders().find(entry);
if (index >= 0) {
- SkPDFShader* result = CanonicalShaders()[index].fPDFShader;
+ result = CanonicalShaders()[index].fPDFShader;
result->ref();
return result;
}
// The PDFShader takes ownership of the shaderSate.
- pdfShader = new SkPDFShader(shaderState.detach());
- // Check for a valid shader.
- if (pdfShader->fContent.get() == NULL) {
- pdfShader->unref();
- return NULL;
+ if (shaderState.get()->fType == SkShader::kNone_GradientType) {
+ result = new SkPDFImageShader(shaderState.detach());
+ } else {
+ SkPDFFunctionShader* functionShader =
+ new SkPDFFunctionShader(shaderState.detach());
+ if (!functionShader->isValid()) {
+ delete functionShader;
+ return NULL;
+ }
+ result = functionShader;
}
- entry.fPDFShader = pdfShader.get();
+ entry.fPDFShader = result;
CanonicalShaders().push(entry);
- return pdfShader.get(); // return the reference that came from new.
+ return result; // return the reference that came from new.
}
// static
@@ -362,7 +405,7 @@ SkMutex& SkPDFShader::CanonicalShadersMutex() {
}
// static
-SkPDFObject* SkPDFShader::RangeObject() {
+SkPDFObject* SkPDFFunctionShader::RangeObject() {
// This initialization is only thread safe with gcc.
static SkPDFArray* range = NULL;
// This method is only used with CanonicalShadersMutex, so it's safe to
@@ -380,15 +423,9 @@ SkPDFObject* SkPDFShader::RangeObject() {
return range;
}
-SkPDFShader::SkPDFShader(State* state) : fState(state) {
- if (fState.get()->fType == SkShader::kNone_GradientType) {
- doImageShader();
- } else {
- doFunctionShader();
- }
-}
-
-void SkPDFShader::doFunctionShader() {
+SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
+ : SkPDFDict("Pattern"),
+ fState(state) {
SkString (*codeFunction)(const SkShader::GradientInfo& info) = NULL;
SkPoint transformPoints[2];
@@ -407,9 +444,8 @@ void SkPDFShader::doFunctionShader() {
codeFunction = &radialCode;
break;
case SkShader::kRadial2_GradientType: {
- // Bail out if the radii are the same. Not setting fContent will
- // cause the higher level code to detect the resulting object
- // as invalid.
+ // Bail out if the radii are the same. Empty fResources signals
+ // an error and isValid will return false.
if (info->fRadius[0] == info->fRadius[1]) {
return;
}
@@ -479,15 +515,12 @@ void SkPDFShader::doFunctionShader() {
pdfShader->insert("Domain", domain.get());
pdfShader->insert("Function", new SkPDFObjRef(function.get()))->unref();
- fContent = new SkPDFDict("Pattern");
- fContent->unref(); // SkRefPtr and new both took a reference.
- fContent->insertInt("PatternType", 2);
- fContent->insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
- fContent->insert("Shading", pdfShader.get());
+ insertInt("PatternType", 2);
+ insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
+ insert("Shading", pdfShader.get());
}
-// SkShader* shader, SkMatrix matrix, const SkRect& surfaceBBox
-void SkPDFShader::doImageShader() {
+SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
fState.get()->fImage.lockPixels();
SkMatrix finalMatrix = fState.get()->fCanvasTransform;
@@ -666,34 +699,43 @@ void SkPDFShader::doImageShader() {
content->unref(); // SkRefPtr and content() both took a reference.
pattern.getResources(&fResources);
- fContent = new SkPDFStream(content.get());
- fContent->unref(); // SkRefPtr and new both took a reference.
- fContent->insertName("Type", "Pattern");
- fContent->insertInt("PatternType", 1);
- fContent->insertInt("PaintType", 1);
- fContent->insertInt("TilingType", 1);
- fContent->insert("BBox", patternBBoxArray.get());
- fContent->insertScalar("XStep", patternBBox.width());
- fContent->insertScalar("YStep", patternBBox.height());
- fContent->insert("Resources", pattern.getResourceDict().get());
- fContent->insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
+ setData(content.get());
+ insertName("Type", "Pattern");
+ insertInt("PatternType", 1);
+ insertInt("PaintType", 1);
+ insertInt("TilingType", 1);
+ insert("BBox", patternBBoxArray.get());
+ insertScalar("XStep", patternBBox.width());
+ insertScalar("YStep", patternBBox.height());
+ insert("Resources", pattern.getResourceDict().get());
+ insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
fState.get()->fImage.unlockPixels();
}
-SkPDFStream* SkPDFShader::makePSFunction(const SkString& psCode,
- SkPDFArray* domain) {
- SkRefPtr<SkMemoryStream> funcStream =
- new SkMemoryStream(psCode.c_str(), psCode.size(), true);
- funcStream->unref(); // SkRefPtr and new both took a reference.
-
- SkPDFStream* result = new SkPDFStream(funcStream.get());
+SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode,
+ SkPDFArray* domain) {
+ SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(),
+ psCode.size()));
+ SkPDFStream* result = new SkPDFStream(funcData.get());
result->insertInt("FunctionType", 4);
result->insert("Domain", domain);
result->insert("Range", RangeObject());
return result;
}
+SkPDFShader::ShaderCanonicalEntry::ShaderCanonicalEntry(SkPDFObject* pdfShader,
+ const State* state)
+ : fPDFShader(pdfShader),
+ fState(state) {
+}
+
+bool SkPDFShader::ShaderCanonicalEntry::operator==(
+ const ShaderCanonicalEntry& b) const {
+ return fPDFShader == b.fPDFShader ||
+ (fState != NULL && b.fState != NULL && *fState == *b.fState);
+}
+
bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const {
if (fType != b.fType ||
fCanvasTransform != b.fCanvasTransform ||
diff --git a/src/pdf/SkPDFStream.cpp b/src/pdf/SkPDFStream.cpp
index 790cfaec3d..0ff7b49ff0 100644
--- a/src/pdf/SkPDFStream.cpp
+++ b/src/pdf/SkPDFStream.cpp
@@ -20,45 +20,105 @@
#include "SkPDFStream.h"
#include "SkStream.h"
-SkPDFStream::SkPDFStream(SkStream* stream) {
- if (SkFlate::HaveFlate())
- SkAssertResult(SkFlate::Deflate(stream, &fCompressedData));
+static bool skip_compression(SkPDFCatalog* catalog) {
+ return catalog->getDocumentFlags() & SkPDFDocument::kNoCompression_Flag;
+}
- if (SkFlate::HaveFlate() &&
- fCompressedData.getOffset() < stream->getLength()) {
- fLength = fCompressedData.getOffset();
- insert("Filter", new SkPDFName("FlateDecode"))->unref();
- } else {
- fCompressedData.reset();
- fPlainData = stream;
- fLength = fPlainData->getLength();
- }
- insertInt("Length", fLength);
+SkPDFStream::SkPDFStream(SkStream* stream)
+ : fState(kUnused_State),
+ fData(stream) {
}
-SkPDFStream::~SkPDFStream() {
+SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) {
+ SkMemoryStream* stream = new SkMemoryStream;
+ stream->setData(data);
+ fData = stream;
+ fData->unref(); // SkRefPtr and new both took a reference.
+}
+
+SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream)
+ : SkPDFDict(),
+ fState(kUnused_State),
+ fData(pdfStream.fData) {
+ bool removeLength = true;
+ // Don't uncompress an already compressed stream, but we could.
+ if (pdfStream.fState == kCompressed_State) {
+ fState = kCompressed_State;
+ removeLength = false;
+ }
+ SkPDFDict::Iter dict(pdfStream);
+ SkPDFName* key;
+ SkPDFObject* value;
+ SkPDFName lengthName("Length");
+ for (key = dict.next(&value); key != NULL; key = dict.next(&value)) {
+ if (removeLength && *key == lengthName) {
+ continue;
+ }
+ this->insert(key, value);
+ }
}
+SkPDFStream::~SkPDFStream() {}
+
void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
bool indirect) {
- if (indirect)
+ if (indirect) {
return emitIndirectObject(stream, catalog);
+ }
+ if (!this->populate(catalog)) {
+ return fSubstitute->emitObject(stream, catalog, indirect);
+ }
this->INHERITED::emitObject(stream, catalog, false);
stream->writeText(" stream\n");
- if (fPlainData.get()) {
- stream->write(fPlainData->getMemoryBase(), fLength);
- } else {
- SkAutoDataUnref data(fCompressedData.copyToData());
- stream->write(data.data(), fLength);
- }
+ stream->write(fData->getMemoryBase(), fData->getLength());
stream->writeText("\nendstream");
}
size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
- if (indirect)
+ if (indirect) {
return getIndirectOutputSize(catalog);
+ }
+ if (!this->populate(catalog)) {
+ return fSubstitute->getOutputSize(catalog, indirect);
+ }
return this->INHERITED::getOutputSize(catalog, false) +
- strlen(" stream\n\nendstream") + fLength;
+ strlen(" stream\n\nendstream") + fData->getLength();
+}
+
+SkPDFStream::SkPDFStream() : fState(kUnused_State) {}
+
+void SkPDFStream::setData(SkStream* stream) {
+ fData = stream;
+}
+
+bool SkPDFStream::populate(SkPDFCatalog* catalog) {
+ if (fState == kUnused_State) {
+ if (!skip_compression(catalog) && SkFlate::HaveFlate()) {
+ SkDynamicMemoryWStream compressedData;
+
+ SkAssertResult(SkFlate::Deflate(fData.get(), &compressedData));
+ if (compressedData.getOffset() < fData->getLength()) {
+ SkMemoryStream* stream = new SkMemoryStream;
+ stream->setData(compressedData.copyToData());
+ fData = stream;
+ fData->unref(); // SkRefPtr and new both took a reference.
+ insertName("Filter", "FlateDecode");
+ }
+ fState = kCompressed_State;
+ } else {
+ fState = kNoCompression_State;
+ }
+ insertInt("Length", fData->getLength());
+ } else if (fState == kNoCompression_State && !skip_compression(catalog) &&
+ SkFlate::HaveFlate()) {
+ if (!fSubstitute.get()) {
+ fSubstitute = new SkPDFStream(*this);
+ fSubstitute->unref(); // SkRefPtr and new both took a reference.
+ catalog->setSubstitute(this, fSubstitute.get());
+ }
+ return false;
+ }
+ return true;
}
diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp
index 810d8601fa..a026d6927b 100644
--- a/src/pdf/SkPDFTypes.cpp
+++ b/src/pdf/SkPDFTypes.cpp
@@ -48,14 +48,32 @@ void SkPDFObject::emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog) {
stream->writeText("\nendobj\n");
}
-SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {}
-SkPDFObjRef::~SkPDFObjRef() {}
-
size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) {
return catalog->getObjectNumberSize(this) + strlen(" obj\n") +
this->getOutputSize(catalog, false) + strlen("\nendobj\n");
}
+void SkPDFObject::AddResourceHelper(SkPDFObject* resource,
+ SkTDArray<SkPDFObject*>* list) {
+ list->push(resource);
+ resource->ref();
+}
+
+void SkPDFObject::GetResourcesHelper(SkTDArray<SkPDFObject*>* resources,
+ SkTDArray<SkPDFObject*>* result) {
+ if (resources->count()) {
+ result->setReserve(result->count() + resources->count());
+ for (int i = 0; i < resources->count(); i++) {
+ result->push((*resources)[i]);
+ (*resources)[i]->ref();
+ (*resources)[i]->getResources(result);
+ }
+ }
+}
+
+SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {}
+SkPDFObjRef::~SkPDFObjRef() {}
+
void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
bool indirect) {
SkASSERT(!indirect);
@@ -258,6 +276,10 @@ SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {}
SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {}
SkPDFName::~SkPDFName() {}
+bool SkPDFName::operator==(const SkPDFName& b) const {
+ return fValue == b.fValue;
+}
+
void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
bool indirect) {
SkASSERT(!indirect);
@@ -433,3 +455,19 @@ void SkPDFDict::clear() {
}
fValue.reset();
}
+
+SkPDFDict::Iter::Iter(const SkPDFDict& dict)
+ : fIter(dict.fValue.begin()),
+ fStop(dict.fValue.end()) {
+}
+
+SkPDFName* SkPDFDict::Iter::next(SkPDFObject** value) {
+ if (fIter != fStop) {
+ Rec* cur = fIter;
+ fIter++;
+ *value = cur->value;
+ return cur->key;
+ }
+ *value = NULL;
+ return NULL;
+}