Index: src/pdf/SkPDFShader.cpp |
diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp |
index 890bf447d5c46a8b0e4943ab0704bfef233195d7..2a144a6926f6a63a456cdb16038ea924d83c2e87 100644 |
--- a/src/pdf/SkPDFShader.cpp |
+++ b/src/pdf/SkPDFShader.cpp |
@@ -10,6 +10,7 @@ |
#include "SkPDFShader.h" |
#include "SkData.h" |
+#include "SkPDFCanon.h" |
#include "SkPDFCatalog.h" |
#include "SkPDFDevice.h" |
#include "SkPDFFormXObject.h" |
@@ -509,13 +510,12 @@ class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader { |
public: |
explicit SkPDFFunctionShader(SkPDFShader::State* state); |
virtual ~SkPDFFunctionShader() { |
- if (isValid()) { |
- RemoveShader(this); |
- } |
+ SkPDFShader::RemoveFromCanonIfValid(this); |
fResources.unrefAll(); |
} |
bool isValid() SK_OVERRIDE { return fResources.count() > 0; } |
+ SkPDFObject* toPDFObject() SK_OVERRIDE { return this; } |
void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE { |
@@ -528,7 +528,6 @@ private: |
static SkPDFObject* RangeObject(); |
SkTDArray<SkPDFObject*> fResources; |
- SkAutoTDelete<const SkPDFShader::State> fState; |
SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain); |
typedef SkPDFDict INHERITED; |
@@ -543,18 +542,15 @@ class SkPDFAlphaFunctionShader : public SkPDFStream, public SkPDFShader { |
public: |
explicit SkPDFAlphaFunctionShader(SkPDFShader::State* state); |
virtual ~SkPDFAlphaFunctionShader() { |
- if (isValid()) { |
- RemoveShader(this); |
- } |
+ SkPDFShader::RemoveFromCanonIfValid(this); |
} |
bool isValid() SK_OVERRIDE { |
return fColorShader.get() != NULL; |
} |
+ SkPDFObject* toPDFObject() SK_OVERRIDE { return this; } |
private: |
- SkAutoTDelete<const SkPDFShader::State> fState; |
- |
SkPDFGraphicState* CreateSMaskGraphicState(); |
void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
@@ -572,13 +568,12 @@ class SkPDFImageShader : public SkPDFStream, public SkPDFShader { |
public: |
explicit SkPDFImageShader(SkPDFShader::State* state); |
virtual ~SkPDFImageShader() { |
- if (isValid()) { |
- RemoveShader(this); |
- } |
+ SkPDFShader::RemoveFromCanonIfValid(this); |
fResources.unrefAll(); |
} |
bool isValid() SK_OVERRIDE { return size() > 0; } |
+ SkPDFObject* toPDFObject() SK_OVERRIDE { return this; } |
void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE { |
@@ -589,18 +584,37 @@ public: |
private: |
SkTSet<SkPDFObject*> fResources; |
- SkAutoTDelete<const SkPDFShader::State> fState; |
}; |
-SkPDFShader::SkPDFShader() {} |
+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) { |
- SkPDFObject* result; |
- |
- SkAutoTDelete<State> shaderState(inState); |
- if (shaderState.get()->fType == SkShader::kNone_GradientType && |
- shaderState.get()->fImage.isNull()) { |
+ SkAutoTDelete<State> state(inState); |
+ 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 |
@@ -608,50 +622,23 @@ SkPDFObject* SkPDFShader::GetPDFShaderByState(State* inState) { |
return NULL; |
} |
- ShaderCanonicalEntry entry(NULL, shaderState.get()); |
- int index = CanonicalShaders().find(entry); |
- if (index >= 0) { |
- result = CanonicalShaders()[index].fPDFShader; |
- result->ref(); |
- return result; |
+ SkPDFShader* pdfShader = SkPDFCanon::GetCanon().findShader(*state); |
+ if (pdfShader) { |
+ SkASSERT(pdfShader->isValid()); |
+ return SkRef(pdfShader->toPDFObject()); |
} |
- bool valid = false; |
// The PDFShader takes ownership of the shaderSate. |
- if (shaderState.get()->fType == SkShader::kNone_GradientType) { |
- SkPDFImageShader* imageShader = |
- new SkPDFImageShader(shaderState.detach()); |
- valid = imageShader->isValid(); |
- result = imageShader; |
+ 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()))); |
} else { |
- if (shaderState.get()->GradientHasAlpha()) { |
- SkPDFAlphaFunctionShader* gradientShader = |
- SkNEW_ARGS(SkPDFAlphaFunctionShader, (shaderState.detach())); |
- valid = gradientShader->isValid(); |
- result = gradientShader; |
- } else { |
- SkPDFFunctionShader* functionShader = |
- SkNEW_ARGS(SkPDFFunctionShader, (shaderState.detach())); |
- valid = functionShader->isValid(); |
- result = functionShader; |
- } |
- } |
- if (!valid) { |
- delete result; |
- return NULL; |
+ return SkPDFShader::AddToCanonIfValid( |
+ SkNEW_ARGS(SkPDFFunctionShader, (state.detach()))); |
} |
- entry.fPDFShader = result; |
- CanonicalShaders().push(entry); |
- return result; // return the reference that came from new. |
-} |
- |
-// 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 |
@@ -659,27 +646,15 @@ SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader, |
const SkMatrix& matrix, |
const SkIRect& surfaceBBox, |
SkScalar rasterScale) { |
- SkAutoMutexAcquire lock(CanonicalShadersMutex()); |
+ SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex()); |
return GetPDFShaderByState( |
SkNEW_ARGS(State, (shader, matrix, surfaceBBox, rasterScale))); |
} |
-// static |
-SkTDArray<SkPDFShader::ShaderCanonicalEntry>& SkPDFShader::CanonicalShaders() { |
- SkPDFShader::CanonicalShadersMutex().assertHeld(); |
- static SkTDArray<ShaderCanonicalEntry> gCanonicalShaders; |
- return gCanonicalShaders; |
-} |
- |
-SK_DECLARE_STATIC_MUTEX(gCanonicalShadersMutex); |
-// static |
-SkBaseMutex& SkPDFShader::CanonicalShadersMutex() { |
- return gCanonicalShadersMutex; |
-} |
// static |
SkPDFObject* SkPDFFunctionShader::RangeObject() { |
- SkPDFShader::CanonicalShadersMutex().assertHeld(); |
+ SkPDFCanon::GetShaderMutex().assertHeld(); |
static SkPDFArray* range = NULL; |
// This method is only used with CanonicalShadersMutex, so it's safe to |
// populate domain. |
@@ -757,11 +732,10 @@ static SkStream* create_pattern_fill_content(int gsIndex, SkRect& bounds) { |
*/ |
SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState() { |
SkRect bbox; |
- bbox.set(fState.get()->fBBox); |
+ bbox.set(fShaderState->fBBox); |
- SkAutoTUnref<SkPDFObject> luminosityShader( |
- SkPDFShader::GetPDFShaderByState( |
- fState->CreateAlphaToLuminosityState())); |
+ SkAutoTUnref<SkPDFObject> luminosityShader(SkPDFShader::GetPDFShaderByState( |
+ fShaderState->CreateAlphaToLuminosityState())); |
SkAutoTUnref<SkStream> alphaStream(create_pattern_fill_content(-1, bbox)); |
@@ -777,9 +751,9 @@ SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState() { |
} |
SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state) |
- : fState(state) { |
+ : SkPDFShader(state) { |
SkRect bbox; |
- bbox.set(fState.get()->fBBox); |
+ bbox.set(fShaderState->fBBox); |
fColorShader.reset( |
SkPDFShader::GetPDFShaderByState(state->CreateOpaqueState())); |
@@ -837,18 +811,17 @@ static bool split_perspective(const SkMatrix in, SkMatrix* affine, |
} |
SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) |
- : SkPDFDict("Pattern"), |
- fState(state) { |
+ : SkPDFDict("Pattern"), SkPDFShader(state) { |
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 = &fState.get()->fInfo; |
+ const SkShader::GradientInfo* info = &fShaderState->fInfo; |
transformPoints[0] = info->fPoint[0]; |
transformPoints[1] = info->fPoint[1]; |
- switch (fState.get()->fType) { |
+ switch (fShaderState->fType) { |
case SkShader::kLinear_GradientType: |
codeFunction = &linearCode; |
break; |
@@ -893,8 +866,8 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) |
SkMatrix mapperMatrix; |
unitToPointsMatrix(transformPoints, &mapperMatrix); |
- SkMatrix finalMatrix = fState.get()->fCanvasTransform; |
- finalMatrix.preConcat(fState.get()->fShaderTransform); |
+ SkMatrix finalMatrix = fShaderState->fCanvasTransform; |
+ finalMatrix.preConcat(fShaderState->fShaderTransform); |
finalMatrix.preConcat(mapperMatrix); |
// Preserves as much as posible in the final matrix, and only removes |
@@ -911,7 +884,7 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) |
} |
SkRect bbox; |
- bbox.set(fState.get()->fBBox); |
+ bbox.set(fShaderState->fBBox); |
if (!inverseTransformBBox(finalMatrix, &bbox)) { |
return; |
} |
@@ -924,10 +897,11 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) |
domain->appendScalar(bbox.fBottom); |
SkString functionCode; |
- // The two point radial gradient further references fState.get()->fInfo |
+ // The two point radial gradient further references |
+ // fShaderState->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 (fState.get()->fType == SkShader::kRadial2_GradientType) { |
+ if (fShaderState->fType == SkShader::kRadial2_GradientType) { |
SkShader::GradientInfo twoPointRadialInfo = *info; |
SkMatrix inverseMapperMatrix; |
if (!mapperMatrix.invert(&inverseMapperMatrix)) { |
@@ -957,8 +931,9 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) |
insert("Shading", pdfShader.get()); |
} |
-SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) { |
- fState.get()->fImage.lockPixels(); |
+SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) |
+ : SkPDFShader(state) { |
+ fShaderState->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 |
@@ -966,15 +941,15 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) { |
// Map clip bounds to shader space to ensure the device is large enough |
// to handle fake clamping. |
- SkMatrix finalMatrix = fState.get()->fCanvasTransform; |
- finalMatrix.preConcat(fState.get()->fShaderTransform); |
+ SkMatrix finalMatrix = fShaderState->fCanvasTransform; |
+ finalMatrix.preConcat(fShaderState->fShaderTransform); |
SkRect deviceBounds; |
- deviceBounds.set(fState.get()->fBBox); |
+ deviceBounds.set(fShaderState->fBBox); |
if (!inverseTransformBBox(finalMatrix, &deviceBounds)) { |
return; |
} |
- const SkBitmap* image = &fState.get()->fImage; |
+ const SkBitmap* image = &fShaderState->fImage; |
SkRect bitmapBounds; |
image->getBounds(&bitmapBounds); |
@@ -983,8 +958,8 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(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] = fState.get()->fImageTileModes[0]; |
- tileModes[1] = fState.get()->fImageTileModes[1]; |
+ tileModes[0] = fShaderState->fImageTileModes[0]; |
+ tileModes[1] = fShaderState->fImageTileModes[1]; |
if (tileModes[0] != SkShader::kClamp_TileMode || |
tileModes[1] != SkShader::kClamp_TileMode) { |
deviceBounds.join(bitmapBounds); |
@@ -1164,7 +1139,7 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) { |
populate_tiling_pattern_dict(this, patternBBox, |
pattern.getResourceDict(), finalMatrix); |
- fState.get()->fImage.unlockPixels(); |
+ fShaderState->fImage.unlockPixels(); |
} |
SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode, SkPDFArray* domain) { |
@@ -1176,16 +1151,6 @@ SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode, SkPDFAr |
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 || |