aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar halcanary <halcanary@google.com>2015-01-23 04:18:53 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-01-23 04:18:53 -0800
commitbc59ac6b12bbded2117fe3aa9643b2d138e5ddda (patch)
tree1205bc82c09b10c727ce2cb56071fa16bf451b65
parentcada95ad9b8e6be9bdffe1a70968a2102cc3f09d (diff)
Simplify SkPDFShader class. Now invalid objects are never created.
"Constructors should not do real work" I have verified that all test PDFs render identically. Review URL: https://codereview.chromium.org/862113004
-rw-r--r--src/pdf/SkPDFShader.cpp280
-rw-r--r--src/pdf/SkPDFShader.h5
2 files changed, 155 insertions, 130 deletions
diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp
index 1b9d9eb5b8..aad62f53ca 100644
--- a/src/pdf/SkPDFShader.cpp
+++ b/src/pdf/SkPDFShader.cpp
@@ -505,16 +505,21 @@ private:
void AllocateGradientInfoStorage();
};
+static void remove_from_canon(SkPDFShader* shader) {
+ SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex());
+ SkPDFCanon::GetCanon().removeShader(shader);
+}
+
class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader {
SK_DECLARE_INST_COUNT(SkPDFFunctionShader)
public:
- explicit SkPDFFunctionShader(SkPDFShader::State* state);
+ static SkPDFObject* Create(SkAutoTDelete<SkPDFShader::State>*);
+
virtual ~SkPDFFunctionShader() {
- SkPDFShader::RemoveFromCanonIfValid(this);
+ remove_from_canon(this);
fResources.unrefAll();
}
- bool isValid() SK_OVERRIDE { return fResources.count() > 0; }
SkPDFObject* toPDFObject() SK_OVERRIDE { return this; }
void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
@@ -525,11 +530,9 @@ public:
}
private:
- static SkPDFObject* RangeObject();
-
SkTDArray<SkPDFObject*> fResources;
-
- SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain);
+ explicit SkPDFFunctionShader(SkPDFShader::State* state)
+ : SkPDFDict("Pattern"), SkPDFShader(state) {}
typedef SkPDFDict INHERITED;
};
@@ -540,18 +543,17 @@ private:
*/
class SkPDFAlphaFunctionShader : public SkPDFStream, public SkPDFShader {
public:
- explicit SkPDFAlphaFunctionShader(SkPDFShader::State* state);
- virtual ~SkPDFAlphaFunctionShader() {
- SkPDFShader::RemoveFromCanonIfValid(this);
- }
+ static SkPDFObject* Create(SkAutoTDelete<SkPDFShader::State>*);
+
+ virtual ~SkPDFAlphaFunctionShader() { remove_from_canon(this); }
- bool isValid() SK_OVERRIDE {
- return fColorShader.get() != NULL;
- }
SkPDFObject* toPDFObject() SK_OVERRIDE { return this; }
private:
- SkPDFGraphicState* CreateSMaskGraphicState();
+ explicit SkPDFAlphaFunctionShader(SkPDFShader::State* state);
+
+ static SkPDFGraphicState* CreateSMaskGraphicState(
+ const SkPDFShader::State&);
void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE {
@@ -566,13 +568,13 @@ private:
class SkPDFImageShader : public SkPDFStream, public SkPDFShader {
public:
- explicit SkPDFImageShader(SkPDFShader::State* state);
+ static SkPDFObject* Create(SkAutoTDelete<SkPDFShader::State>*);
+
virtual ~SkPDFImageShader() {
- SkPDFShader::RemoveFromCanonIfValid(this);
+ remove_from_canon(this);
fResources.unrefAll();
}
- bool isValid() SK_OVERRIDE { return size() > 0; }
SkPDFObject* toPDFObject() SK_OVERRIDE { return this; }
void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
@@ -584,37 +586,22 @@ public:
private:
SkTSet<SkPDFObject*> fResources;
+ explicit SkPDFImageShader(SkPDFShader::State* state) : SkPDFShader(state) {}
};
SkPDFShader::SkPDFShader(SkPDFShader::State* s) : fShaderState(s) {}
SkPDFShader::~SkPDFShader() {}
-void SkPDFShader::RemoveFromCanonIfValid(SkPDFShader* shader) {
- if (shader->isValid()) {
- SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex());
- SkPDFCanon::GetCanon().removeShader(shader);
- }
-}
-
bool SkPDFShader::equals(const SkPDFShader::State& state) const {
return state == *fShaderState.get();
}
-SkPDFObject* SkPDFShader::AddToCanonIfValid(SkPDFShader* shader) {
- if (!shader->isValid()) {
- SkDELETE(shader);
- return NULL;
- }
- SkPDFCanon::GetCanon().addShader(shader);
- return shader->toPDFObject();
-}
-
// static
-SkPDFObject* SkPDFShader::GetPDFShaderByState(State* inState) {
- SkAutoTDelete<State> state(inState);
- if (state->fType == SkShader::kNone_GradientType &&
- state->fImage.isNull()) {
+SkPDFObject* SkPDFShader::GetPDFShaderByState(
+ SkAutoTDelete<SkPDFShader::State>* autoState) {
+ const State& state = **autoState;
+ if (state.fType == SkShader::kNone_GradientType && state.fImage.isNull()) {
// TODO(vandebo) This drops SKComposeShader on the floor. We could
// handle compose shader by pulling things up to a layer, drawing with
// the first shader, applying the xfer mode and drawing again with the
@@ -622,22 +609,18 @@ SkPDFObject* SkPDFShader::GetPDFShaderByState(State* inState) {
return NULL;
}
- SkPDFShader* pdfShader = SkPDFCanon::GetCanon().findShader(*state);
+ SkPDFShader* pdfShader = SkPDFCanon::GetCanon().findShader(state);
if (pdfShader) {
- SkASSERT(pdfShader->isValid());
return SkRef(pdfShader->toPDFObject());
}
// The PDFShader takes ownership of the shaderSate.
- if (state->fType == SkShader::kNone_GradientType) {
- return SkPDFShader::AddToCanonIfValid(
- SkNEW_ARGS(SkPDFImageShader, (state.detach())));
- } else if (state->GradientHasAlpha()) {
- return SkPDFShader::AddToCanonIfValid(
- SkNEW_ARGS(SkPDFAlphaFunctionShader, (state.detach())));
+ if (state.fType == SkShader::kNone_GradientType) {
+ return SkPDFImageShader::Create(autoState);
+ } else if (state.GradientHasAlpha()) {
+ return SkPDFAlphaFunctionShader::Create(autoState);
} else {
- return SkPDFShader::AddToCanonIfValid(
- SkNEW_ARGS(SkPDFFunctionShader, (state.detach())));
+ return SkPDFFunctionShader::Create(autoState);
}
}
@@ -647,28 +630,9 @@ SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader,
const SkIRect& surfaceBBox,
SkScalar rasterScale) {
SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex());
- return GetPDFShaderByState(
+ SkAutoTDelete<SkPDFShader::State> state(
SkNEW_ARGS(State, (shader, matrix, surfaceBBox, rasterScale)));
-}
-
-
-// static
-SkPDFObject* SkPDFFunctionShader::RangeObject() {
- SkPDFCanon::GetShaderMutex().assertHeld();
- static SkPDFArray* range = NULL;
- // This method is only used with CanonicalShadersMutex, so it's safe to
- // populate domain.
- if (range == NULL) {
- range = new SkPDFArray;
- range->reserve(6);
- range->appendInt(0);
- range->appendInt(1);
- range->appendInt(0);
- range->appendInt(1);
- range->appendInt(0);
- range->appendInt(1);
- }
- return range;
+ return GetPDFShaderByState(&state);
}
static SkPDFResourceDict* get_gradient_resource_dict(
@@ -730,12 +694,15 @@ static SkStream* create_pattern_fill_content(int gsIndex, SkRect& bounds) {
* Creates a ExtGState with the SMask set to the luminosityShader in
* luminosity mode. The shader pattern extends to the bbox.
*/
-SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState() {
+SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState(
+ const SkPDFShader::State& state) {
SkRect bbox;
- bbox.set(fShaderState->fBBox);
+ bbox.set(state.fBBox);
- SkAutoTUnref<SkPDFObject> luminosityShader(SkPDFShader::GetPDFShaderByState(
- fShaderState->CreateAlphaToLuminosityState()));
+ SkAutoTDelete<SkPDFShader::State> alphaToLuminosityState(
+ state.CreateAlphaToLuminosityState());
+ SkAutoTUnref<SkPDFObject> luminosityShader(
+ SkPDFShader::GetPDFShaderByState(&alphaToLuminosityState));
SkAutoTDelete<SkStream> alphaStream(create_pattern_fill_content(-1, bbox));
@@ -750,28 +717,46 @@ SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState() {
SkPDFGraphicState::kLuminosity_SMaskMode);
}
-SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state)
- : SkPDFShader(state) {
+SkPDFObject* SkPDFAlphaFunctionShader::Create(
+ SkAutoTDelete<SkPDFShader::State>* autoState) {
+ const SkPDFShader::State& state = **autoState;
SkRect bbox;
- bbox.set(fShaderState->fBBox);
+ bbox.set(state.fBBox);
- fColorShader.reset(
- SkPDFShader::GetPDFShaderByState(state->CreateOpaqueState()));
+ SkAutoTDelete<SkPDFShader::State> opaqueState(state.CreateOpaqueState());
+
+ SkPDFObject* colorShader = SkPDFShader::GetPDFShaderByState(&opaqueState);
+ if (!colorShader) {
+ return NULL;
+ }
// Create resource dict with alpha graphics state as G0 and
// pattern shader as P0, then write content stream.
- SkAutoTUnref<SkPDFGraphicState> alphaGs(CreateSMaskGraphicState());
- fResourceDict.reset(
- get_gradient_resource_dict(fColorShader.get(), alphaGs.get()));
+ SkAutoTUnref<SkPDFGraphicState> alphaGs(
+ SkPDFAlphaFunctionShader::CreateSMaskGraphicState(state));
+
+ SkPDFAlphaFunctionShader* alphaFunctionShader =
+ SkNEW_ARGS(SkPDFAlphaFunctionShader, (autoState->detach()));
+
+ alphaFunctionShader->fColorShader.reset(colorShader);
+
+ alphaFunctionShader->fResourceDict.reset(get_gradient_resource_dict(
+ alphaFunctionShader->fColorShader.get(), alphaGs.get()));
SkAutoTDelete<SkStream> colorStream(
create_pattern_fill_content(0, bbox));
- setData(colorStream.get());
+ alphaFunctionShader->setData(colorStream.get());
- populate_tiling_pattern_dict(this, bbox, fResourceDict.get(),
+ populate_tiling_pattern_dict(alphaFunctionShader, bbox,
+ alphaFunctionShader->fResourceDict.get(),
SkMatrix::I());
+ SkPDFCanon::GetCanon().addShader(alphaFunctionShader);
+ return alphaFunctionShader;
}
+SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state)
+ : SkPDFShader(state) {}
+
// Finds affine and persp such that in = affine * persp.
// but it returns the inverse of perspective matrix.
static bool split_perspective(const SkMatrix in, SkMatrix* affine,
@@ -810,18 +795,50 @@ static bool split_perspective(const SkMatrix in, SkMatrix* affine,
return true;
}
-SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
- : SkPDFDict("Pattern"), SkPDFShader(state) {
+namespace {
+SkPDFObject* create_range_object() {
+ SkPDFArray* range = SkNEW(SkPDFArray);
+ range->reserve(6);
+ range->appendInt(0);
+ range->appendInt(1);
+ range->appendInt(0);
+ range->appendInt(1);
+ range->appendInt(0);
+ range->appendInt(1);
+ return range;
+}
+
+template <typename T> void unref(T* ptr) { ptr->unref();}
+} // namespace
+
+SK_DECLARE_STATIC_LAZY_PTR(SkPDFObject, rangeObject,
+ create_range_object, unref<SkPDFObject>);
+
+static SkPDFStream* make_ps_function(const SkString& psCode,
+ SkPDFArray* domain) {
+ SkAutoDataUnref funcData(
+ SkData::NewWithCopy(psCode.c_str(), psCode.size()));
+ SkPDFStream* result = SkNEW_ARGS(SkPDFStream, (funcData.get()));
+ result->insertInt("FunctionType", 4);
+ result->insert("Domain", domain);
+ result->insert("Range", rangeObject.get());
+ return result;
+}
+
+SkPDFObject* SkPDFFunctionShader::Create(
+ SkAutoTDelete<SkPDFShader::State>* autoState) {
+ const SkPDFShader::State& state = **autoState;
+
SkString (*codeFunction)(const SkShader::GradientInfo& info,
const SkMatrix& perspectiveRemover) = NULL;
SkPoint transformPoints[2];
// Depending on the type of the gradient, we want to transform the
// coordinate space in different ways.
- const SkShader::GradientInfo* info = &fShaderState->fInfo;
+ const SkShader::GradientInfo* info = &state.fInfo;
transformPoints[0] = info->fPoint[0];
transformPoints[1] = info->fPoint[1];
- switch (fShaderState->fType) {
+ switch (state.fType) {
case SkShader::kLinear_GradientType:
codeFunction = &linearCode;
break;
@@ -831,10 +848,9 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
codeFunction = &radialCode;
break;
case SkShader::kRadial2_GradientType: {
- // Bail out if the radii are the same. Empty fResources signals
- // an error and isValid will return false.
+ // Bail out if the radii are the same.
if (info->fRadius[0] == info->fRadius[1]) {
- return;
+ return NULL;
}
transformPoints[1] = transformPoints[0];
SkScalar dr = info->fRadius[1] - info->fRadius[0];
@@ -856,7 +872,7 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
case SkShader::kColor_GradientType:
case SkShader::kNone_GradientType:
default:
- return;
+ return NULL;
}
// Move any scaling (assuming a unit gradient) or translation
@@ -866,8 +882,8 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
SkMatrix mapperMatrix;
unitToPointsMatrix(transformPoints, &mapperMatrix);
- SkMatrix finalMatrix = fShaderState->fCanvasTransform;
- finalMatrix.preConcat(fShaderState->fShaderTransform);
+ SkMatrix finalMatrix = state.fCanvasTransform;
+ finalMatrix.preConcat(state.fShaderTransform);
finalMatrix.preConcat(mapperMatrix);
// Preserves as much as posible in the final matrix, and only removes
@@ -879,14 +895,14 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
if (finalMatrix.hasPerspective()) {
if (!split_perspective(finalMatrix,
&finalMatrix, &perspectiveInverseOnly)) {
- return;
+ return NULL;
}
}
SkRect bbox;
- bbox.set(fShaderState->fBBox);
+ bbox.set(state.fBBox);
if (!inverseTransformBBox(finalMatrix, &bbox)) {
- return;
+ return NULL;
}
SkAutoTUnref<SkPDFArray> domain(new SkPDFArray);
@@ -898,14 +914,14 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
SkString functionCode;
// The two point radial gradient further references
- // fShaderState->fInfo
+ // state.fInfo
// in translating from x, y coordinates to the t parameter. So, we have
// to transform the points and radii according to the calculated matrix.
- if (fShaderState->fType == SkShader::kRadial2_GradientType) {
+ if (state.fType == SkShader::kRadial2_GradientType) {
SkShader::GradientInfo twoPointRadialInfo = *info;
SkMatrix inverseMapperMatrix;
if (!mapperMatrix.invert(&inverseMapperMatrix)) {
- return;
+ return NULL;
}
inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2);
twoPointRadialInfo.fRadius[0] =
@@ -922,18 +938,31 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
pdfShader->insertName("ColorSpace", "DeviceRGB");
pdfShader->insert("Domain", domain.get());
- SkPDFStream* function = makePSFunction(functionCode, domain.get());
+ SkPDFStream* function = make_ps_function(functionCode, domain.get());
pdfShader->insert("Function", new SkPDFObjRef(function))->unref();
- fResources.push(function); // Pass ownership to resource list.
- insertInt("PatternType", 2);
- insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
- insert("Shading", pdfShader.get());
+ SkAutoTUnref<SkPDFArray> matrixArray(
+ SkPDFUtils::MatrixToArray(finalMatrix));
+
+ SkPDFFunctionShader* pdfFunctionShader =
+ SkNEW_ARGS(SkPDFFunctionShader, (autoState->detach()));
+
+ pdfFunctionShader->fResources.push(function);
+ // Pass ownership to resource list.
+
+ pdfFunctionShader->insertInt("PatternType", 2);
+ pdfFunctionShader->insert("Matrix", matrixArray.get());
+ pdfFunctionShader->insert("Shading", pdfShader.get());
+
+ SkPDFCanon::GetCanon().addShader(pdfFunctionShader);
+ return pdfFunctionShader;
}
-SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state)
- : SkPDFShader(state) {
- fShaderState->fImage.lockPixels();
+SkPDFObject* SkPDFImageShader::Create(
+ SkAutoTDelete<SkPDFShader::State>* autoState) {
+ const SkPDFShader::State& state = **autoState;
+
+ state.fImage.lockPixels();
// The image shader pattern cell will be drawn into a separate device
// in pattern cell space (no scaling on the bitmap, though there may be
@@ -941,15 +970,15 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state)
// Map clip bounds to shader space to ensure the device is large enough
// to handle fake clamping.
- SkMatrix finalMatrix = fShaderState->fCanvasTransform;
- finalMatrix.preConcat(fShaderState->fShaderTransform);
+ SkMatrix finalMatrix = state.fCanvasTransform;
+ finalMatrix.preConcat(state.fShaderTransform);
SkRect deviceBounds;
- deviceBounds.set(fShaderState->fBBox);
+ deviceBounds.set(state.fBBox);
if (!inverseTransformBBox(finalMatrix, &deviceBounds)) {
- return;
+ return NULL;
}
- const SkBitmap* image = &fShaderState->fImage;
+ const SkBitmap* image = &state.fImage;
SkRect bitmapBounds;
image->getBounds(&bitmapBounds);
@@ -958,8 +987,8 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state)
// For clamp modes, we're only interested in the clip region, whether
// or not the main bitmap is in it.
SkShader::TileMode tileModes[2];
- tileModes[0] = fShaderState->fImageTileModes[0];
- tileModes[1] = fShaderState->fImageTileModes[1];
+ tileModes[0] = state.fImageTileModes[0];
+ tileModes[1] = state.fImageTileModes[1];
if (tileModes[0] != SkShader::kClamp_TileMode ||
tileModes[1] != SkShader::kClamp_TileMode) {
deviceBounds.join(bitmapBounds);
@@ -1132,23 +1161,22 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state)
// Put the canvas into the pattern stream (fContent).
SkAutoTDelete<SkStream> content(pattern.content());
- setData(content.get());
+
+ SkPDFImageShader* imageShader =
+ SkNEW_ARGS(SkPDFImageShader, (autoState->detach()));
+ imageShader->setData(content.get());
+
SkPDFResourceDict* resourceDict = pattern.getResourceDict();
- resourceDict->getReferencedResources(fResources, &fResources, false);
+ resourceDict->getReferencedResources(imageShader->fResources,
+ &imageShader->fResources, false);
- populate_tiling_pattern_dict(this, patternBBox,
+ populate_tiling_pattern_dict(imageShader, patternBBox,
pattern.getResourceDict(), finalMatrix);
- fShaderState->fImage.unlockPixels();
-}
+ imageShader->fShaderState->fImage.unlockPixels();
-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;
+ SkPDFCanon::GetCanon().addShader(imageShader);
+ return imageShader;
}
bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const {
diff --git a/src/pdf/SkPDFShader.h b/src/pdf/SkPDFShader.h
index e0abff8f68..10532156ad 100644
--- a/src/pdf/SkPDFShader.h
+++ b/src/pdf/SkPDFShader.h
@@ -54,14 +54,11 @@ protected:
// This is an internal method.
// CanonicalShadersMutex() should already be acquired.
// This also takes ownership of shaderState.
- static SkPDFObject* GetPDFShaderByState(State* shaderState);
- static SkPDFObject* AddToCanonIfValid(SkPDFShader*);
- static void RemoveFromCanonIfValid(SkPDFShader*);
+ static SkPDFObject* GetPDFShaderByState(SkAutoTDelete<SkPDFShader::State>*);
SkPDFShader(State*);
virtual ~SkPDFShader();
- virtual bool isValid() = 0;
virtual SkPDFObject* toPDFObject() = 0;
};