| Index: src/core/SkXfermode.cpp
|
| diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
|
| index e50e4f5ce58179cacbea609785d69a27bea8cb4f..66314958cc610b8d5d031c6217286e8566238485 100644
|
| --- a/src/core/SkXfermode.cpp
|
| +++ b/src/core/SkXfermode.cpp
|
| @@ -1688,26 +1688,66 @@ void SkDstOutXfermode::toString(SkString* str) const {
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| +SK_DECLARE_STATIC_MUTEX(gCachedXfermodesMutex);
|
| +static SkXfermode* gCachedXfermodes[SkXfermode::kLastMode + 1];
|
| +
|
| +void SkXfermode::Term() {
|
| + SkAutoMutexAcquire ac(gCachedXfermodesMutex);
|
| +
|
| + for (size_t i = 0; i < SK_ARRAY_COUNT(gCachedXfermodes); ++i) {
|
| + SkSafeUnref(gCachedXfermodes[i]);
|
| + gCachedXfermodes[i] = NULL;
|
| + }
|
| +}
|
| +
|
| SkXfermode* SkXfermode::Create(Mode mode) {
|
| SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
|
| - SkASSERT((unsigned)mode < kModeCount);
|
| + SkASSERT(SK_ARRAY_COUNT(gCachedXfermodes) == kModeCount);
|
|
|
| - const ProcCoeff& rec = gProcCoeffs[mode];
|
| + if ((unsigned)mode >= kModeCount) {
|
| + // report error
|
| + return NULL;
|
| + }
|
|
|
| - switch (mode) {
|
| - case kClear_Mode:
|
| - return SkNEW_ARGS(SkClearXfermode, (rec));
|
| - case kSrc_Mode:
|
| - return SkNEW_ARGS(SkSrcXfermode, (rec));
|
| - case kSrcOver_Mode:
|
| - return NULL;
|
| - case kDstIn_Mode:
|
| - return SkNEW_ARGS(SkDstInXfermode, (rec));
|
| - case kDstOut_Mode:
|
| - return SkNEW_ARGS(SkDstOutXfermode, (rec));
|
| - default:
|
| - return SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
|
| + // Skia's "defaut" mode is srcover. NULL in SkPaint is interpreted as srcover
|
| + // so we can just return NULL from the factory.
|
| + if (kSrcOver_Mode == mode) {
|
| + return NULL;
|
| + }
|
| +
|
| + // guard our access to gCachedXfermodes, since we may write into it
|
| + SkAutoMutexAcquire ac(gCachedXfermodesMutex);
|
| +
|
| + SkXfermode* xfer = gCachedXfermodes[mode];
|
| + if (NULL == xfer) {
|
| + const ProcCoeff& rec = gProcCoeffs[mode];
|
| + // All modes can in theory be represented by the ProcCoeff rec, since
|
| + // it contains function ptrs. However, a few modes are both simple and
|
| + // commonly used, so we call those out for their own subclasses here.
|
| + switch (mode) {
|
| + case kClear_Mode:
|
| + xfer = SkNEW_ARGS(SkClearXfermode, (rec));
|
| + break;
|
| + case kSrc_Mode:
|
| + xfer = SkNEW_ARGS(SkSrcXfermode, (rec));
|
| + break;
|
| + case kSrcOver_Mode:
|
| + SkASSERT(false); // should not land here
|
| + break;
|
| + case kDstIn_Mode:
|
| + xfer = SkNEW_ARGS(SkDstInXfermode, (rec));
|
| + break;
|
| + case kDstOut_Mode:
|
| + xfer = SkNEW_ARGS(SkDstOutXfermode, (rec));
|
| + break;
|
| + default:
|
| + // no special-case, just rely in the rec and its function-ptrs
|
| + xfer = SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
|
| + break;
|
| + }
|
| + gCachedXfermodes[mode] = xfer;
|
| }
|
| + return SkSafeRef(xfer);
|
| }
|
|
|
| SkXfermodeProc SkXfermode::GetProc(Mode mode) {
|
|
|