| |
| /* |
| * Copyright 2006 The Android Open Source Project |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| |
| #include "SkScalar.h" |
| #include "SkShader.h" |
| #include "SkPaint.h" |
| #include "SkMallocPixelRef.h" |
| |
| SkShader::SkShader() : fLocalMatrix(NULL) { |
| SkDEBUGCODE(fInSession = false;) |
| } |
| |
| SkShader::SkShader(SkFlattenableReadBuffer& buffer) |
| : INHERITED(buffer), fLocalMatrix(NULL) { |
| if (buffer.readBool()) { |
| SkMatrix matrix; |
| SkReadMatrix(&buffer, &matrix); |
| setLocalMatrix(matrix); |
| } |
| SkDEBUGCODE(fInSession = false;) |
| } |
| |
| SkShader::~SkShader() { |
| SkASSERT(!fInSession); |
| sk_free(fLocalMatrix); |
| } |
| |
| void SkShader::beginSession() { |
| SkASSERT(!fInSession); |
| SkDEBUGCODE(fInSession = true;) |
| } |
| |
| void SkShader::endSession() { |
| SkASSERT(fInSession); |
| SkDEBUGCODE(fInSession = false;) |
| } |
| |
| void SkShader::flatten(SkFlattenableWriteBuffer& buffer) { |
| this->INHERITED::flatten(buffer); |
| buffer.writeBool(fLocalMatrix != NULL); |
| if (fLocalMatrix) { |
| SkWriteMatrix(&buffer, *fLocalMatrix); |
| } |
| } |
| |
| bool SkShader::getLocalMatrix(SkMatrix* localM) const { |
| if (fLocalMatrix) { |
| if (localM) { |
| *localM = *fLocalMatrix; |
| } |
| return true; |
| } else { |
| if (localM) { |
| localM->reset(); |
| } |
| return false; |
| } |
| } |
| |
| void SkShader::setLocalMatrix(const SkMatrix& localM) { |
| if (localM.isIdentity()) { |
| this->resetLocalMatrix(); |
| } else { |
| if (fLocalMatrix == NULL) { |
| fLocalMatrix = (SkMatrix*)sk_malloc_throw(sizeof(SkMatrix)); |
| } |
| *fLocalMatrix = localM; |
| } |
| } |
| |
| void SkShader::resetLocalMatrix() { |
| if (fLocalMatrix) { |
| sk_free(fLocalMatrix); |
| fLocalMatrix = NULL; |
| } |
| } |
| |
| bool SkShader::setContext(const SkBitmap& device, |
| const SkPaint& paint, |
| const SkMatrix& matrix) { |
| const SkMatrix* m = &matrix; |
| SkMatrix total; |
| |
| fDeviceConfig = SkToU8(device.getConfig()); |
| fPaintAlpha = paint.getAlpha(); |
| if (fLocalMatrix) { |
| total.setConcat(matrix, *fLocalMatrix); |
| m = &total; |
| } |
| if (m->invert(&fTotalInverse)) { |
| fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse); |
| return true; |
| } |
| return false; |
| } |
| |
| #include "SkColorPriv.h" |
| |
| void SkShader::shadeSpan16(int x, int y, uint16_t span16[], int count) { |
| SkASSERT(span16); |
| SkASSERT(count > 0); |
| SkASSERT(this->canCallShadeSpan16()); |
| |
| // basically, if we get here, the subclass screwed up |
| SkDEBUGFAIL("kHasSpan16 flag is set, but shadeSpan16() not implemented"); |
| } |
| |
| #define kTempColorQuadCount 6 // balance between speed (larger) and saving stack-space |
| #define kTempColorCount (kTempColorQuadCount << 2) |
| |
| #ifdef SK_CPU_BENDIAN |
| #define SkU32BitShiftToByteOffset(shift) (3 - ((shift) >> 3)) |
| #else |
| #define SkU32BitShiftToByteOffset(shift) ((shift) >> 3) |
| #endif |
| |
| void SkShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { |
| SkASSERT(count > 0); |
| |
| SkPMColor colors[kTempColorCount]; |
| |
| while ((count -= kTempColorCount) >= 0) { |
| this->shadeSpan(x, y, colors, kTempColorCount); |
| x += kTempColorCount; |
| |
| const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); |
| int quads = kTempColorQuadCount; |
| do { |
| U8CPU a0 = srcA[0]; |
| U8CPU a1 = srcA[4]; |
| U8CPU a2 = srcA[8]; |
| U8CPU a3 = srcA[12]; |
| srcA += 4*4; |
| *alpha++ = SkToU8(a0); |
| *alpha++ = SkToU8(a1); |
| *alpha++ = SkToU8(a2); |
| *alpha++ = SkToU8(a3); |
| } while (--quads != 0); |
| } |
| SkASSERT(count < 0); |
| SkASSERT(count + kTempColorCount >= 0); |
| if (count += kTempColorCount) { |
| this->shadeSpan(x, y, colors, count); |
| |
| const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); |
| do { |
| *alpha++ = *srcA; |
| srcA += 4; |
| } while (--count != 0); |
| } |
| #if 0 |
| do { |
| int n = count; |
| if (n > kTempColorCount) |
| n = kTempColorCount; |
| SkASSERT(n > 0); |
| |
| this->shadeSpan(x, y, colors, n); |
| x += n; |
| count -= n; |
| |
| const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); |
| do { |
| *alpha++ = *srcA; |
| srcA += 4; |
| } while (--n != 0); |
| } while (count > 0); |
| #endif |
| } |
| |
| SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) { |
| MatrixClass mc = kLinear_MatrixClass; |
| |
| if (mat.hasPerspective()) { |
| if (mat.fixedStepInX(0, NULL, NULL)) { |
| mc = kFixedStepInX_MatrixClass; |
| } else { |
| mc = kPerspective_MatrixClass; |
| } |
| } |
| return mc; |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*, |
| TileMode*, SkScalar*) const { |
| return kNone_BitmapType; |
| } |
| |
| SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const { |
| return kNone_GradientType; |
| } |
| |
| SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, |
| TileMode tmx, TileMode tmy) { |
| return SkShader::CreateBitmapShader(src, tmx, tmy, NULL, 0); |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| #include "SkColorShader.h" |
| #include "SkUtils.h" |
| |
| SkColorShader::SkColorShader() { |
| fFlags = 0; |
| fInheritColor = true; |
| } |
| |
| SkColorShader::SkColorShader(SkColor c) { |
| fFlags = 0; |
| fColor = c; |
| fInheritColor = false; |
| } |
| |
| SkColorShader::~SkColorShader() {} |
| |
| bool SkColorShader::isOpaque() const { |
| if (fInheritColor) { |
| return true; // using paint's alpha |
| } |
| return SkColorGetA(fColor) == 255; |
| } |
| |
| SkColorShader::SkColorShader(SkFlattenableReadBuffer& b) : INHERITED(b) { |
| fFlags = 0; // computed in setContext |
| |
| fInheritColor = b.readU8(); |
| if (fInheritColor) { |
| return; |
| } |
| fColor = b.readU32(); |
| } |
| |
| void SkColorShader::flatten(SkFlattenableWriteBuffer& buffer) { |
| this->INHERITED::flatten(buffer); |
| buffer.write8(fInheritColor); |
| if (fInheritColor) { |
| return; |
| } |
| buffer.write32(fColor); |
| } |
| |
| SkFlattenable* SkColorShader::CreateProc(SkFlattenableReadBuffer& buffer) { |
| return SkNEW_ARGS(SkColorShader, (buffer)); |
| } |
| |
| SkFlattenable::Factory SkColorShader::getFactory() { |
| return CreateProc; |
| } |
| |
| uint32_t SkColorShader::getFlags() { |
| return fFlags; |
| } |
| |
| uint8_t SkColorShader::getSpan16Alpha() const { |
| return SkGetPackedA32(fPMColor); |
| } |
| |
| bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint, |
| const SkMatrix& matrix) { |
| if (!this->INHERITED::setContext(device, paint, matrix)) { |
| return false; |
| } |
| |
| unsigned a; |
| |
| if (fInheritColor) { |
| fColor = paint.getColor(); |
| a = SkColorGetA(fColor); |
| } else { |
| a = SkAlphaMul(SkColorGetA(fColor), SkAlpha255To256(paint.getAlpha())); |
| } |
| |
| unsigned r = SkColorGetR(fColor); |
| unsigned g = SkColorGetG(fColor); |
| unsigned b = SkColorGetB(fColor); |
| |
| // we want this before we apply any alpha |
| fColor16 = SkPack888ToRGB16(r, g, b); |
| |
| if (a != 255) { |
| r = SkMulDiv255Round(r, a); |
| g = SkMulDiv255Round(g, a); |
| b = SkMulDiv255Round(b, a); |
| } |
| fPMColor = SkPackARGB32(a, r, g, b); |
| |
| fFlags = kConstInY32_Flag; |
| if (255 == a) { |
| fFlags |= kOpaqueAlpha_Flag; |
| if (paint.isDither() == false) { |
| fFlags |= kHasSpan16_Flag; |
| } |
| } |
| |
| return true; |
| } |
| |
| void SkColorShader::shadeSpan(int x, int y, SkPMColor span[], int count) { |
| sk_memset32(span, fPMColor, count); |
| } |
| |
| void SkColorShader::shadeSpan16(int x, int y, uint16_t span[], int count) { |
| sk_memset16(span, fColor16, count); |
| } |
| |
| void SkColorShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { |
| memset(alpha, SkGetPackedA32(fPMColor), count); |
| } |
| |
| // if we had a asAColor method, that would be more efficient... |
| SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix, |
| TileMode modes[], |
| SkScalar* twoPointRadialParams) const { |
| return kNone_BitmapType; |
| } |
| |
| SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const { |
| if (info) { |
| if (info->fColors && info->fColorCount >= 1) { |
| info->fColors[0] = fColor; |
| } |
| info->fColorCount = 1; |
| info->fTileMode = SkShader::kRepeat_TileMode; |
| } |
| return kColor_GradientType; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #include "SkEmptyShader.h" |
| |
| SkEmptyShader::SkEmptyShader(SkFlattenableReadBuffer& b) : INHERITED(b) {} |
| |
| uint32_t SkEmptyShader::getFlags() { return 0; } |
| uint8_t SkEmptyShader::getSpan16Alpha() const { return 0; } |
| |
| bool SkEmptyShader::setContext(const SkBitmap&, const SkPaint&, |
| const SkMatrix&) { return false; } |
| |
| void SkEmptyShader::shadeSpan(int x, int y, SkPMColor span[], int count) { |
| SkDEBUGFAIL("should never get called, since setContext() returned false"); |
| } |
| |
| void SkEmptyShader::shadeSpan16(int x, int y, uint16_t span[], int count) { |
| SkDEBUGFAIL("should never get called, since setContext() returned false"); |
| } |
| |
| void SkEmptyShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { |
| SkDEBUGFAIL("should never get called, since setContext() returned false"); |
| } |
| |
| SkFlattenable::Factory SkEmptyShader::getFactory() { return NULL; } |
| |
| void SkEmptyShader::flatten(SkFlattenableWriteBuffer& buffer) { |
| this->INHERITED::flatten(buffer); |
| } |
| |