SkShader.cpp revision f3e505984d08fb96e753be2b561f479dc3a4c544
1/* 2 * Copyright 2006 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkBitmapProcShader.h" 9#include "SkReadBuffer.h" 10#include "SkMallocPixelRef.h" 11#include "SkPaint.h" 12#include "SkPicture.h" 13#include "SkPictureShader.h" 14#include "SkScalar.h" 15#include "SkShader.h" 16#include "SkWriteBuffer.h" 17 18SkShader::SkShader(const SkMatrix* localMatrix) { 19 if (localMatrix) { 20 fLocalMatrix = *localMatrix; 21 } else { 22 fLocalMatrix.reset(); 23 } 24} 25 26SkShader::SkShader(SkReadBuffer& buffer) 27 : INHERITED(buffer) { 28 if (buffer.readBool()) { 29 buffer.readMatrix(&fLocalMatrix); 30 } else { 31 fLocalMatrix.reset(); 32 } 33} 34 35SkShader::~SkShader() { 36} 37 38void SkShader::flatten(SkWriteBuffer& buffer) const { 39 this->INHERITED::flatten(buffer); 40 bool hasLocalM = this->hasLocalMatrix(); 41 buffer.writeBool(hasLocalM); 42 if (hasLocalM) { 43 buffer.writeMatrix(fLocalMatrix); 44 } 45} 46 47bool SkShader::computeTotalInverse(const SkMatrix& matrix, SkMatrix* totalInverse) const { 48 const SkMatrix* m = &matrix; 49 SkMatrix total; 50 51 if (this->hasLocalMatrix()) { 52 total.setConcat(matrix, this->getLocalMatrix()); 53 m = &total; 54 } 55 56 return m->invert(totalInverse); 57} 58 59bool SkShader::validContext(const SkBitmap& device, 60 const SkPaint& paint, 61 const SkMatrix& matrix, 62 SkMatrix* totalInverse) const { 63 return this->computeTotalInverse(matrix, totalInverse); 64} 65 66SkShader::Context* SkShader::createContext(const SkBitmap&, const SkPaint&, const SkMatrix&, 67 void* storage) const { 68 return NULL; 69} 70 71size_t SkShader::contextSize() const { 72 return 0; 73} 74 75SkShader::Context::Context(const SkShader& shader, const SkBitmap& device, 76 const SkPaint& paint, const SkMatrix& matrix) 77 : fShader(shader) 78{ 79 SkASSERT(fShader.validContext(device, paint, matrix)); 80 81 // Because the context parameters must be valid at this point, we know that the matrix is 82 // invertible. 83 SkAssertResult(fShader.computeTotalInverse(matrix, &fTotalInverse)); 84 fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse); 85 86 fPaintAlpha = paint.getAlpha(); 87} 88 89SkShader::Context::~Context() {} 90 91SkShader::Context::ShadeProc SkShader::Context::asAShadeProc(void** ctx) { 92 return NULL; 93} 94 95#include "SkColorPriv.h" 96 97void SkShader::Context::shadeSpan16(int x, int y, uint16_t span16[], int count) { 98 SkASSERT(span16); 99 SkASSERT(count > 0); 100 SkASSERT(this->canCallShadeSpan16()); 101 102 // basically, if we get here, the subclass screwed up 103 SkDEBUGFAIL("kHasSpan16 flag is set, but shadeSpan16() not implemented"); 104} 105 106#define kTempColorQuadCount 6 // balance between speed (larger) and saving stack-space 107#define kTempColorCount (kTempColorQuadCount << 2) 108 109#ifdef SK_CPU_BENDIAN 110 #define SkU32BitShiftToByteOffset(shift) (3 - ((shift) >> 3)) 111#else 112 #define SkU32BitShiftToByteOffset(shift) ((shift) >> 3) 113#endif 114 115void SkShader::Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { 116 SkASSERT(count > 0); 117 118 SkPMColor colors[kTempColorCount]; 119 120 while ((count -= kTempColorCount) >= 0) { 121 this->shadeSpan(x, y, colors, kTempColorCount); 122 x += kTempColorCount; 123 124 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 125 int quads = kTempColorQuadCount; 126 do { 127 U8CPU a0 = srcA[0]; 128 U8CPU a1 = srcA[4]; 129 U8CPU a2 = srcA[8]; 130 U8CPU a3 = srcA[12]; 131 srcA += 4*4; 132 *alpha++ = SkToU8(a0); 133 *alpha++ = SkToU8(a1); 134 *alpha++ = SkToU8(a2); 135 *alpha++ = SkToU8(a3); 136 } while (--quads != 0); 137 } 138 SkASSERT(count < 0); 139 SkASSERT(count + kTempColorCount >= 0); 140 if (count += kTempColorCount) { 141 this->shadeSpan(x, y, colors, count); 142 143 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 144 do { 145 *alpha++ = *srcA; 146 srcA += 4; 147 } while (--count != 0); 148 } 149#if 0 150 do { 151 int n = count; 152 if (n > kTempColorCount) 153 n = kTempColorCount; 154 SkASSERT(n > 0); 155 156 this->shadeSpan(x, y, colors, n); 157 x += n; 158 count -= n; 159 160 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 161 do { 162 *alpha++ = *srcA; 163 srcA += 4; 164 } while (--n != 0); 165 } while (count > 0); 166#endif 167} 168 169SkShader::Context::MatrixClass SkShader::Context::ComputeMatrixClass(const SkMatrix& mat) { 170 MatrixClass mc = kLinear_MatrixClass; 171 172 if (mat.hasPerspective()) { 173 if (mat.fixedStepInX(0, NULL, NULL)) { 174 mc = kFixedStepInX_MatrixClass; 175 } else { 176 mc = kPerspective_MatrixClass; 177 } 178 } 179 return mc; 180} 181 182////////////////////////////////////////////////////////////////////////////// 183 184SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*, TileMode*) const { 185 return kNone_BitmapType; 186} 187 188SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const { 189 return kNone_GradientType; 190} 191 192GrEffectRef* SkShader::asNewEffect(GrContext*, const SkPaint&) const { 193 return NULL; 194} 195 196SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, 197 const SkMatrix* localMatrix) { 198 return ::CreateBitmapShader(src, tmx, tmy, localMatrix, NULL); 199} 200 201SkShader* SkShader::CreatePictureShader(SkPicture* src, TileMode tmx, TileMode tmy) { 202 return SkPictureShader::Create(src, tmx, tmy); 203} 204 205#ifndef SK_IGNORE_TO_STRING 206void SkShader::toString(SkString* str) const { 207 if (this->hasLocalMatrix()) { 208 str->append(" "); 209 this->getLocalMatrix().toString(str); 210 } 211} 212#endif 213 214////////////////////////////////////////////////////////////////////////////// 215 216#include "SkColorShader.h" 217#include "SkUtils.h" 218 219SkColorShader::SkColorShader(SkColor c) 220 : fColor(c) { 221} 222 223bool SkColorShader::isOpaque() const { 224 return SkColorGetA(fColor) == 255; 225} 226 227SkColorShader::SkColorShader(SkReadBuffer& b) : INHERITED(b) { 228 // V25_COMPATIBILITY_CODE We had a boolean to make the color shader inherit the paint's 229 // color. We don't support that any more. 230 if (b.pictureVersion() < 26 && 0 != b.pictureVersion()) { 231 if (b.readBool()) { 232 SkDEBUGFAIL("We shouldn't have pictures that recorded the inherited case."); 233 fColor = SK_ColorWHITE; 234 return; 235 } 236 } 237 fColor = b.readColor(); 238} 239 240void SkColorShader::flatten(SkWriteBuffer& buffer) const { 241 this->INHERITED::flatten(buffer); 242 buffer.writeColor(fColor); 243} 244 245uint32_t SkColorShader::ColorShaderContext::getFlags() const { 246 return fFlags; 247} 248 249uint8_t SkColorShader::ColorShaderContext::getSpan16Alpha() const { 250 return SkGetPackedA32(fPMColor); 251} 252 253SkShader::Context* SkColorShader::createContext(const SkBitmap& device, const SkPaint& paint, 254 const SkMatrix& matrix, void* storage) const { 255 if (!this->validContext(device, paint, matrix)) { 256 return NULL; 257 } 258 259 return SkNEW_PLACEMENT_ARGS(storage, ColorShaderContext, (*this, device, paint, matrix)); 260} 261 262SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader, 263 const SkBitmap& device, 264 const SkPaint& paint, 265 const SkMatrix& matrix) 266 : INHERITED(shader, device, paint, matrix) 267{ 268 SkColor color = shader.fColor; 269 unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(paint.getAlpha())); 270 271 unsigned r = SkColorGetR(color); 272 unsigned g = SkColorGetG(color); 273 unsigned b = SkColorGetB(color); 274 275 // we want this before we apply any alpha 276 fColor16 = SkPack888ToRGB16(r, g, b); 277 278 if (a != 255) { 279 r = SkMulDiv255Round(r, a); 280 g = SkMulDiv255Round(g, a); 281 b = SkMulDiv255Round(b, a); 282 } 283 fPMColor = SkPackARGB32(a, r, g, b); 284 285 fFlags = kConstInY32_Flag; 286 if (255 == a) { 287 fFlags |= kOpaqueAlpha_Flag; 288 if (paint.isDither() == false) { 289 fFlags |= kHasSpan16_Flag; 290 } 291 } 292} 293 294void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) { 295 sk_memset32(span, fPMColor, count); 296} 297 298void SkColorShader::ColorShaderContext::shadeSpan16(int x, int y, uint16_t span[], int count) { 299 sk_memset16(span, fColor16, count); 300} 301 302void SkColorShader::ColorShaderContext::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { 303 memset(alpha, SkGetPackedA32(fPMColor), count); 304} 305 306// if we had a asAColor method, that would be more efficient... 307SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix, 308 TileMode modes[]) const { 309 return kNone_BitmapType; 310} 311 312SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const { 313 if (info) { 314 if (info->fColors && info->fColorCount >= 1) { 315 info->fColors[0] = fColor; 316 } 317 info->fColorCount = 1; 318 info->fTileMode = SkShader::kRepeat_TileMode; 319 } 320 return kColor_GradientType; 321} 322 323#ifndef SK_IGNORE_TO_STRING 324void SkColorShader::toString(SkString* str) const { 325 str->append("SkColorShader: ("); 326 327 str->append("Color: "); 328 str->appendHex(fColor); 329 330 this->INHERITED::toString(str); 331 332 str->append(")"); 333} 334#endif 335 336/////////////////////////////////////////////////////////////////////////////// 337 338#ifndef SK_IGNORE_TO_STRING 339#include "SkEmptyShader.h" 340 341void SkEmptyShader::toString(SkString* str) const { 342 str->append("SkEmptyShader: ("); 343 344 this->INHERITED::toString(str); 345 346 str->append(")"); 347} 348#endif 349