Chromium Code Reviews| Index: src/pdf/SkPDFShader.cpp |
| diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp |
| index 40f7d93f8907b30ab5c9ae191c449c60fa292879..ec92742b6ea76e253f4e87ea7f1223cc4631aded 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" |
| @@ -475,7 +476,7 @@ static void drawBitmapMatrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatri |
| canvas->drawBitmap(bm, 0, 0); |
| } |
| -class SkPDFShader::State { |
| +class SkPDFShaderState { |
| public: |
| SkShader::GradientType fType; |
| SkShader::GradientInfo fInfo; |
| @@ -488,35 +489,41 @@ public: |
| uint32_t fPixelGeneration; |
| SkShader::TileMode fImageTileModes[2]; |
| - State(const SkShader& shader, const SkMatrix& canvasTransform, |
| - const SkIRect& bbox); |
| + SkPDFShaderState(const SkShader& shader, |
| + const SkMatrix& canvasTransform, |
| + const SkIRect& bbox); |
| - bool operator==(const State& b) const; |
| + bool operator==(const SkPDFShaderState& b) const; |
| - SkPDFShader::State* CreateAlphaToLuminosityState() const; |
| - SkPDFShader::State* CreateOpaqueState() const; |
| + SkPDFShaderState* CreateAlphaToLuminosityState() const; |
| + SkPDFShaderState* CreateOpaqueState() const; |
| bool GradientHasAlpha() const; |
| private: |
| - State(const State& other); |
| - State operator=(const State& rhs); |
| + SkPDFShaderState(const SkPDFShaderState& other); |
| + SkPDFShaderState operator=(const SkPDFShaderState& rhs); |
| void AllocateGradientInfoStorage(); |
| }; |
| class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader { |
| SK_DECLARE_INST_COUNT(SkPDFFunctionShader) |
| public: |
| - explicit SkPDFFunctionShader(SkPDFShader::State* state); |
| + explicit SkPDFFunctionShader(SkPDFShaderState* state); |
| virtual ~SkPDFFunctionShader() { |
| if (isValid()) { |
| - RemoveShader(this); |
| + SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex()); |
| + SkPDFCanon::GetCanon().removeShader(this); |
| } |
| fResources.unrefAll(); |
| } |
| bool isValid() SK_OVERRIDE { return fResources.count() > 0; } |
| + virtual SkPDFObject* toPDFObject() SK_OVERRIDE { |
| + return this; |
| + } |
| + |
| void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
| SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE { |
| GetResourcesHelper(&fResources, |
| @@ -528,7 +535,6 @@ private: |
| static SkPDFObject* RangeObject(); |
| SkTDArray<SkPDFObject*> fResources; |
| - SkAutoTDelete<const SkPDFShader::State> fState; |
| SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain); |
| typedef SkPDFDict INHERITED; |
| @@ -541,10 +547,11 @@ private: |
| */ |
| class SkPDFAlphaFunctionShader : public SkPDFStream, public SkPDFShader { |
| public: |
| - explicit SkPDFAlphaFunctionShader(SkPDFShader::State* state); |
| + explicit SkPDFAlphaFunctionShader(SkPDFShaderState* state); |
| virtual ~SkPDFAlphaFunctionShader() { |
| if (isValid()) { |
| - RemoveShader(this); |
| + SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex()); |
| + SkPDFCanon::GetCanon().removeShader(this); |
| } |
| } |
| @@ -552,9 +559,11 @@ public: |
| return fColorShader.get() != NULL; |
| } |
| -private: |
| - SkAutoTDelete<const SkPDFShader::State> fState; |
| + virtual SkPDFObject* toPDFObject() SK_OVERRIDE { |
| + return this; |
| + } |
| +private: |
| SkPDFGraphicState* CreateSMaskGraphicState(); |
| void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
| @@ -570,16 +579,21 @@ private: |
| class SkPDFImageShader : public SkPDFStream, public SkPDFShader { |
| public: |
| - explicit SkPDFImageShader(SkPDFShader::State* state); |
| + explicit SkPDFImageShader(SkPDFShaderState* state); |
| virtual ~SkPDFImageShader() { |
| if (isValid()) { |
| - RemoveShader(this); |
| + SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex()); |
| + SkPDFCanon::GetCanon().removeShader(this); |
| } |
| fResources.unrefAll(); |
| } |
| bool isValid() SK_OVERRIDE { return size() > 0; } |
| + virtual SkPDFObject* toPDFObject() SK_OVERRIDE { |
| + return this; |
| + } |
| + |
| void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
| SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE { |
| GetResourcesHelper(&fResources.toArray(), |
| @@ -589,16 +603,26 @@ public: |
| private: |
| SkTSet<SkPDFObject*> fResources; |
| - SkAutoTDelete<const SkPDFShader::State> fState; |
| }; |
| -SkPDFShader::SkPDFShader() {} |
| +SkPDFShader::SkPDFShader(const SkPDFShaderState* state) |
| + : fPDFShaderState(state) { |
| +} |
| -// static |
| -SkPDFObject* SkPDFShader::GetPDFShaderByState(State* inState) { |
| - SkPDFObject* result; |
| +SkPDFShader::~SkPDFShader() { |
| +} |
| + |
| +bool SkPDFShader::equals(const SkPDFShaderState& state) const { |
| + return state == this->pdfShaderState(); |
| +} |
| + |
| +const SkPDFShaderState& SkPDFShader::pdfShaderState() const { |
| + return *fPDFShaderState; |
| +} |
| - SkAutoTDelete<State> shaderState(inState); |
| +// static |
| +SkPDFObject* SkPDFShader::GetPDFShaderByState(SkPDFShaderState* inState) { |
| + SkAutoTDelete<SkPDFShaderState> shaderState(inState); |
| if (shaderState.get()->fType == SkShader::kNone_GradientType && |
| shaderState.get()->fImage.isNull()) { |
| // TODO(vandebo) This drops SKComposeShader on the floor. We could |
| @@ -608,77 +632,57 @@ 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(*shaderState); |
| + if (pdfShader) { |
| + return SkRef(pdfShader->toPDFObject()); |
| } |
| - bool valid = false; |
| // The PDFShader takes ownership of the shaderSate. |
| - if (shaderState.get()->fType == SkShader::kNone_GradientType) { |
| + if (shaderState->fType == SkShader::kNone_GradientType) { |
| SkPDFImageShader* imageShader = |
| new SkPDFImageShader(shaderState.detach()); |
| - valid = imageShader->isValid(); |
| - result = imageShader; |
| - } else { |
| - if (shaderState.get()->GradientHasAlpha()) { |
| - SkPDFAlphaFunctionShader* gradientShader = |
| + if (imageShader->isValid()) { |
|
mtklein
2015/01/20 21:59:52
Might want to extract this if-else block as add_to
hal.canary
2015/01/21 17:07:51
GREAT idea
|
| + SkPDFCanon::GetCanon().addShader(imageShader); |
| + return imageShader->toPDFObject(); |
| + } else { |
| + SkDELETE(imageShader); |
| + return NULL; |
| + } |
| + } else if (shaderState->GradientHasAlpha()) { |
| + SkPDFAlphaFunctionShader* gradientShader = |
| SkNEW_ARGS(SkPDFAlphaFunctionShader, (shaderState.detach())); |
| - valid = gradientShader->isValid(); |
| - result = gradientShader; |
| + if (gradientShader->isValid()) { |
| + SkPDFCanon::GetCanon().addShader(gradientShader); |
| + return gradientShader->toPDFObject(); |
| } else { |
| - SkPDFFunctionShader* functionShader = |
| + SkDELETE(gradientShader); |
| + return NULL; |
| + } |
| + } else { |
| + SkPDFFunctionShader* functionShader = |
| SkNEW_ARGS(SkPDFFunctionShader, (shaderState.detach())); |
| - valid = functionShader->isValid(); |
| - result = functionShader; |
| + if (functionShader->isValid()) { |
| + SkPDFCanon::GetCanon().addShader(functionShader); |
| + return functionShader->toPDFObject(); |
| + } else { |
| + SkDELETE(functionShader); |
| + return NULL; |
| } |
| } |
| - if (!valid) { |
| - delete result; |
| - return NULL; |
| - } |
| - 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 |
| SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader, |
| const SkMatrix& matrix, |
| const SkIRect& surfaceBBox) { |
| - SkAutoMutexAcquire lock(CanonicalShadersMutex()); |
| + SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex()); |
| return GetPDFShaderByState( |
| - SkNEW_ARGS(State, (shader, matrix, surfaceBBox))); |
| -} |
| - |
| -// 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; |
| + SkNEW_ARGS(SkPDFShaderState, (shader, matrix, surfaceBBox))); |
| } |
| // 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. |
| @@ -756,11 +760,10 @@ static SkStream* create_pattern_fill_content(int gsIndex, SkRect& bounds) { |
| */ |
| SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState() { |
| SkRect bbox; |
| - bbox.set(fState.get()->fBBox); |
| + bbox.set(this->pdfShaderState().fBBox); |
| - SkAutoTUnref<SkPDFObject> luminosityShader( |
| - SkPDFShader::GetPDFShaderByState( |
| - fState->CreateAlphaToLuminosityState())); |
| + SkAutoTUnref<SkPDFObject> luminosityShader(SkPDFShader::GetPDFShaderByState( |
| + this->pdfShaderState().CreateAlphaToLuminosityState())); |
| SkAutoTUnref<SkStream> alphaStream(create_pattern_fill_content(-1, bbox)); |
| @@ -775,10 +778,10 @@ SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState() { |
| SkPDFGraphicState::kLuminosity_SMaskMode); |
| } |
| -SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state) |
| - : fState(state) { |
| +SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShaderState* state) |
| + : SkPDFShader(state) { |
| SkRect bbox; |
| - bbox.set(fState.get()->fBBox); |
| + bbox.set(this->pdfShaderState().fBBox); |
| fColorShader.reset( |
| SkPDFShader::GetPDFShaderByState(state->CreateOpaqueState())); |
| @@ -835,19 +838,18 @@ static bool split_perspective(const SkMatrix in, SkMatrix* affine, |
| return true; |
| } |
| -SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) |
| - : SkPDFDict("Pattern"), |
| - fState(state) { |
| +SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShaderState* 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 = &this->pdfShaderState().fInfo; |
|
mtklein
2015/01/20 21:59:52
Why don't we just write "this->pdfShaderState()" a
hal.canary
2015/01/21 17:07:51
Done.
|
| transformPoints[0] = info->fPoint[0]; |
| transformPoints[1] = info->fPoint[1]; |
| - switch (fState.get()->fType) { |
| + switch (this->pdfShaderState().fType) { |
| case SkShader::kLinear_GradientType: |
| codeFunction = &linearCode; |
| break; |
| @@ -892,8 +894,8 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) |
| SkMatrix mapperMatrix; |
| unitToPointsMatrix(transformPoints, &mapperMatrix); |
| - SkMatrix finalMatrix = fState.get()->fCanvasTransform; |
| - finalMatrix.preConcat(fState.get()->fShaderTransform); |
| + SkMatrix finalMatrix = this->pdfShaderState().fCanvasTransform; |
| + finalMatrix.preConcat(this->pdfShaderState().fShaderTransform); |
| finalMatrix.preConcat(mapperMatrix); |
| // Preserves as much as posible in the final matrix, and only removes |
| @@ -910,7 +912,7 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) |
| } |
| SkRect bbox; |
| - bbox.set(fState.get()->fBBox); |
| + bbox.set(this->pdfShaderState().fBBox); |
| if (!inverseTransformBBox(finalMatrix, &bbox)) { |
| return; |
| } |
| @@ -923,10 +925,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 |
| + // this->pdfShaderState().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 (this->pdfShaderState().fType == SkShader::kRadial2_GradientType) { |
| SkShader::GradientInfo twoPointRadialInfo = *info; |
| SkMatrix inverseMapperMatrix; |
| if (!mapperMatrix.invert(&inverseMapperMatrix)) { |
| @@ -956,8 +959,9 @@ SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) |
| insert("Shading", pdfShader.get()); |
| } |
| -SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) { |
| - fState.get()->fImage.lockPixels(); |
| +SkPDFImageShader::SkPDFImageShader(SkPDFShaderState* state) |
| + : SkPDFShader(state) { |
| + this->pdfShaderState().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 |
| @@ -965,15 +969,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 = this->pdfShaderState().fCanvasTransform; |
| + finalMatrix.preConcat(this->pdfShaderState().fShaderTransform); |
| SkRect deviceBounds; |
| - deviceBounds.set(fState.get()->fBBox); |
| + deviceBounds.set(this->pdfShaderState().fBBox); |
| if (!inverseTransformBBox(finalMatrix, &deviceBounds)) { |
| return; |
| } |
| - const SkBitmap* image = &fState.get()->fImage; |
| + const SkBitmap* image = &this->pdfShaderState().fImage; |
| SkRect bitmapBounds; |
| image->getBounds(&bitmapBounds); |
| @@ -982,8 +986,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] = this->pdfShaderState().fImageTileModes[0]; |
| + tileModes[1] = this->pdfShaderState().fImageTileModes[1]; |
| if (tileModes[0] != SkShader::kClamp_TileMode || |
| tileModes[1] != SkShader::kClamp_TileMode) { |
| deviceBounds.join(bitmapBounds); |
| @@ -1163,7 +1167,7 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) { |
| populate_tiling_pattern_dict(this, patternBBox, |
| pattern.getResourceDict(), finalMatrix); |
| - fState.get()->fImage.unlockPixels(); |
| + this->pdfShaderState().fImage.unlockPixels(); |
| } |
| SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode, SkPDFArray* domain) { |
| @@ -1175,17 +1179,7 @@ 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 { |
| +bool SkPDFShaderState::operator==(const SkPDFShaderState& b) const { |
| if (fType != b.fType || |
| fCanvasTransform != b.fCanvasTransform || |
| fShaderTransform != b.fShaderTransform || |
| @@ -1239,11 +1233,10 @@ bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const { |
| return true; |
| } |
| -SkPDFShader::State::State(const SkShader& shader, |
| - const SkMatrix& canvasTransform, const SkIRect& bbox) |
| - : fCanvasTransform(canvasTransform), |
| - fBBox(bbox), |
| - fPixelGeneration(0) { |
| +SkPDFShaderState::SkPDFShaderState(const SkShader& shader, |
| + const SkMatrix& canvasTransform, |
| + const SkIRect& bbox) |
| + : fCanvasTransform(canvasTransform), fBBox(bbox), fPixelGeneration(0) { |
| fInfo.fColorCount = 0; |
| fInfo.fColors = NULL; |
| fInfo.fColorOffsets = NULL; |
| @@ -1268,12 +1261,11 @@ SkPDFShader::State::State(const SkShader& shader, |
| } |
| } |
| -SkPDFShader::State::State(const SkPDFShader::State& other) |
| - : fType(other.fType), |
| - fCanvasTransform(other.fCanvasTransform), |
| - fShaderTransform(other.fShaderTransform), |
| - fBBox(other.fBBox) |
| -{ |
| +SkPDFShaderState::SkPDFShaderState(const SkPDFShaderState& other) |
| + : fType(other.fType) |
| + , fCanvasTransform(other.fCanvasTransform) |
| + , fShaderTransform(other.fShaderTransform) |
| + , fBBox(other.fBBox) { |
| // Only gradients supported for now, since that is all that is used. |
| // If needed, image state copy constructor can be added here later. |
| SkASSERT(fType != SkShader::kNone_GradientType); |
| @@ -1293,10 +1285,10 @@ SkPDFShader::State::State(const SkPDFShader::State& other) |
| * Create a copy of this gradient state with alpha assigned to RGB luminousity. |
| * Only valid for gradient states. |
| */ |
| -SkPDFShader::State* SkPDFShader::State::CreateAlphaToLuminosityState() const { |
| +SkPDFShaderState* SkPDFShaderState::CreateAlphaToLuminosityState() const { |
| SkASSERT(fType != SkShader::kNone_GradientType); |
| - SkPDFShader::State* newState = new SkPDFShader::State(*this); |
| + SkPDFShaderState* newState = new SkPDFShaderState(*this); |
| for (int i = 0; i < fInfo.fColorCount; i++) { |
| SkAlpha alpha = SkColorGetA(fInfo.fColors[i]); |
| @@ -1310,10 +1302,10 @@ SkPDFShader::State* SkPDFShader::State::CreateAlphaToLuminosityState() const { |
| * Create a copy of this gradient state with alpha set to fully opaque |
| * Only valid for gradient states. |
| */ |
| -SkPDFShader::State* SkPDFShader::State::CreateOpaqueState() const { |
| +SkPDFShaderState* SkPDFShaderState::CreateOpaqueState() const { |
| SkASSERT(fType != SkShader::kNone_GradientType); |
| - SkPDFShader::State* newState = new SkPDFShader::State(*this); |
| + SkPDFShaderState* newState = new SkPDFShaderState(*this); |
| for (int i = 0; i < fInfo.fColorCount; i++) { |
| newState->fInfo.fColors[i] = SkColorSetA(fInfo.fColors[i], |
| SK_AlphaOPAQUE); |
| @@ -1325,7 +1317,7 @@ SkPDFShader::State* SkPDFShader::State::CreateOpaqueState() const { |
| /** |
| * Returns true if state is a gradient and the gradient has alpha. |
| */ |
| -bool SkPDFShader::State::GradientHasAlpha() const { |
| +bool SkPDFShaderState::GradientHasAlpha() const { |
| if (fType == SkShader::kNone_GradientType) { |
| return false; |
| } |
| @@ -1339,7 +1331,7 @@ bool SkPDFShader::State::GradientHasAlpha() const { |
| return false; |
| } |
| -void SkPDFShader::State::AllocateGradientInfoStorage() { |
| +void SkPDFShaderState::AllocateGradientInfoStorage() { |
| fColorData.set(sk_malloc_throw( |
| fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); |
| fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); |