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 "SkColorShader.h" 10 #include "SkEmptyShader.h" 11 #include "SkReadBuffer.h" 12 #include "SkMallocPixelRef.h" 13 #include "SkPaint.h" 14 #include "SkPicture.h" 15 #include "SkPictureShader.h" 16 #include "SkScalar.h" 17 #include "SkShader.h" 18 #include "SkThread.h" 19 #include "SkWriteBuffer.h" 20 21 //#define SK_TRACK_SHADER_LIFETIME 22 23 #ifdef SK_TRACK_SHADER_LIFETIME 24 static int32_t gShaderCounter; 25 #endif 26 27 static inline void inc_shader_counter() { 28 #ifdef SK_TRACK_SHADER_LIFETIME 29 int32_t prev = sk_atomic_inc(&gShaderCounter); 30 SkDebugf("+++ shader counter %d\n", prev + 1); 31 #endif 32 } 33 static inline void dec_shader_counter() { 34 #ifdef SK_TRACK_SHADER_LIFETIME 35 int32_t prev = sk_atomic_dec(&gShaderCounter); 36 SkDebugf("--- shader counter %d\n", prev - 1); 37 #endif 38 } 39 40 SkShader::SkShader(const SkMatrix* localMatrix) { 41 inc_shader_counter(); 42 if (localMatrix) { 43 fLocalMatrix = *localMatrix; 44 } else { 45 fLocalMatrix.reset(); 46 } 47 // Pre-cache so future calls to fLocalMatrix.getType() are threadsafe. 48 (void)fLocalMatrix.getType(); 49 } 50 51 SkShader::~SkShader() { 52 dec_shader_counter(); 53 } 54 55 void SkShader::flatten(SkWriteBuffer& buffer) const { 56 this->INHERITED::flatten(buffer); 57 bool hasLocalM = !fLocalMatrix.isIdentity(); 58 buffer.writeBool(hasLocalM); 59 if (hasLocalM) { 60 buffer.writeMatrix(fLocalMatrix); 61 } 62 } 63 64 bool SkShader::computeTotalInverse(const ContextRec& rec, SkMatrix* totalInverse) const { 65 SkMatrix total; 66 total.setConcat(*rec.fMatrix, fLocalMatrix); 67 68 const SkMatrix* m = &total; 69 if (rec.fLocalMatrix) { 70 total.setConcat(*m, *rec.fLocalMatrix); 71 m = &total; 72 } 73 return m->invert(totalInverse); 74 } 75 76 bool SkShader::asLuminanceColor(SkColor* colorPtr) const { 77 SkColor storage; 78 if (NULL == colorPtr) { 79 colorPtr = &storage; 80 } 81 if (this->onAsLuminanceColor(colorPtr)) { 82 *colorPtr = SkColorSetA(*colorPtr, 0xFF); // we only return opaque 83 return true; 84 } 85 return false; 86 } 87 88 SkShader::Context* SkShader::createContext(const ContextRec& rec, void* storage) const { 89 if (!this->computeTotalInverse(rec, NULL)) { 90 return NULL; 91 } 92 return this->onCreateContext(rec, storage); 93 } 94 95 SkShader::Context* SkShader::onCreateContext(const ContextRec& rec, void*) const { 96 return NULL; 97 } 98 99 size_t SkShader::contextSize() const { 100 return 0; 101 } 102 103 SkShader::Context::Context(const SkShader& shader, const ContextRec& rec) 104 : fShader(shader), fCTM(*rec.fMatrix) 105 { 106 // Because the context parameters must be valid at this point, we know that the matrix is 107 // invertible. 108 SkAssertResult(fShader.computeTotalInverse(rec, &fTotalInverse)); 109 fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse); 110 111 fPaintAlpha = rec.fPaint->getAlpha(); 112 } 113 114 SkShader::Context::~Context() {} 115 116 SkShader::Context::ShadeProc SkShader::Context::asAShadeProc(void** ctx) { 117 return NULL; 118 } 119 120 #include "SkColorPriv.h" 121 122 void SkShader::Context::shadeSpan16(int x, int y, uint16_t span16[], int count) { 123 SkASSERT(span16); 124 SkASSERT(count > 0); 125 SkASSERT(this->canCallShadeSpan16()); 126 127 // basically, if we get here, the subclass screwed up 128 SkDEBUGFAIL("kHasSpan16 flag is set, but shadeSpan16() not implemented"); 129 } 130 131 #define kTempColorQuadCount 6 // balance between speed (larger) and saving stack-space 132 #define kTempColorCount (kTempColorQuadCount << 2) 133 134 #ifdef SK_CPU_BENDIAN 135 #define SkU32BitShiftToByteOffset(shift) (3 - ((shift) >> 3)) 136 #else 137 #define SkU32BitShiftToByteOffset(shift) ((shift) >> 3) 138 #endif 139 140 void SkShader::Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { 141 SkASSERT(count > 0); 142 143 SkPMColor colors[kTempColorCount]; 144 145 while ((count -= kTempColorCount) >= 0) { 146 this->shadeSpan(x, y, colors, kTempColorCount); 147 x += kTempColorCount; 148 149 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 150 int quads = kTempColorQuadCount; 151 do { 152 U8CPU a0 = srcA[0]; 153 U8CPU a1 = srcA[4]; 154 U8CPU a2 = srcA[8]; 155 U8CPU a3 = srcA[12]; 156 srcA += 4*4; 157 *alpha++ = SkToU8(a0); 158 *alpha++ = SkToU8(a1); 159 *alpha++ = SkToU8(a2); 160 *alpha++ = SkToU8(a3); 161 } while (--quads != 0); 162 } 163 SkASSERT(count < 0); 164 SkASSERT(count + kTempColorCount >= 0); 165 if (count += kTempColorCount) { 166 this->shadeSpan(x, y, colors, count); 167 168 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 169 do { 170 *alpha++ = *srcA; 171 srcA += 4; 172 } while (--count != 0); 173 } 174 #if 0 175 do { 176 int n = count; 177 if (n > kTempColorCount) 178 n = kTempColorCount; 179 SkASSERT(n > 0); 180 181 this->shadeSpan(x, y, colors, n); 182 x += n; 183 count -= n; 184 185 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 186 do { 187 *alpha++ = *srcA; 188 srcA += 4; 189 } while (--n != 0); 190 } while (count > 0); 191 #endif 192 } 193 194 SkShader::Context::MatrixClass SkShader::Context::ComputeMatrixClass(const SkMatrix& mat) { 195 MatrixClass mc = kLinear_MatrixClass; 196 197 if (mat.hasPerspective()) { 198 if (mat.fixedStepInX(0, NULL, NULL)) { 199 mc = kFixedStepInX_MatrixClass; 200 } else { 201 mc = kPerspective_MatrixClass; 202 } 203 } 204 return mc; 205 } 206 207 ////////////////////////////////////////////////////////////////////////////// 208 209 SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*, TileMode*) const { 210 return kNone_BitmapType; 211 } 212 213 SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const { 214 return kNone_GradientType; 215 } 216 217 bool SkShader::asFragmentProcessor(GrContext*, const SkPaint&, const SkMatrix&, const SkMatrix*, 218 GrColor*, GrFragmentProcessor**) const { 219 return false; 220 } 221 222 SkShader* SkShader::refAsALocalMatrixShader(SkMatrix*) const { 223 return NULL; 224 } 225 226 SkShader* SkShader::CreateEmptyShader() { 227 return SkNEW(SkEmptyShader); 228 } 229 230 SkShader* SkShader::CreateColorShader(SkColor color) { 231 return SkNEW_ARGS(SkColorShader, (color)); 232 } 233 234 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, 235 const SkMatrix* localMatrix) { 236 return SkCreateBitmapShader(src, tmx, tmy, localMatrix, NULL); 237 } 238 239 SkShader* SkShader::CreatePictureShader(const SkPicture* src, TileMode tmx, TileMode tmy, 240 const SkMatrix* localMatrix, const SkRect* tile) { 241 return SkPictureShader::Create(src, tmx, tmy, localMatrix, tile); 242 } 243 244 #ifndef SK_IGNORE_TO_STRING 245 void SkShader::toString(SkString* str) const { 246 if (!fLocalMatrix.isIdentity()) { 247 str->append(" "); 248 fLocalMatrix.toString(str); 249 } 250 } 251 #endif 252 253 ////////////////////////////////////////////////////////////////////////////// 254 255 #include "SkUtils.h" 256 257 SkColorShader::SkColorShader(SkColor c) 258 : fColor(c) { 259 } 260 261 bool SkColorShader::isOpaque() const { 262 return SkColorGetA(fColor) == 255; 263 } 264 265 SkFlattenable* SkColorShader::CreateProc(SkReadBuffer& buffer) { 266 return SkNEW_ARGS(SkColorShader, (buffer.readColor())); 267 } 268 269 void SkColorShader::flatten(SkWriteBuffer& buffer) const { 270 buffer.writeColor(fColor); 271 } 272 273 uint32_t SkColorShader::ColorShaderContext::getFlags() const { 274 return fFlags; 275 } 276 277 uint8_t SkColorShader::ColorShaderContext::getSpan16Alpha() const { 278 return SkGetPackedA32(fPMColor); 279 } 280 281 SkShader::Context* SkColorShader::onCreateContext(const ContextRec& rec, void* storage) const { 282 return SkNEW_PLACEMENT_ARGS(storage, ColorShaderContext, (*this, rec)); 283 } 284 285 SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader, 286 const ContextRec& rec) 287 : INHERITED(shader, rec) 288 { 289 SkColor color = shader.fColor; 290 unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha())); 291 292 unsigned r = SkColorGetR(color); 293 unsigned g = SkColorGetG(color); 294 unsigned b = SkColorGetB(color); 295 296 // we want this before we apply any alpha 297 fColor16 = SkPack888ToRGB16(r, g, b); 298 299 if (a != 255) { 300 r = SkMulDiv255Round(r, a); 301 g = SkMulDiv255Round(g, a); 302 b = SkMulDiv255Round(b, a); 303 } 304 fPMColor = SkPackARGB32(a, r, g, b); 305 306 fFlags = kConstInY32_Flag; 307 if (255 == a) { 308 fFlags |= kOpaqueAlpha_Flag; 309 if (rec.fPaint->isDither() == false) { 310 fFlags |= kHasSpan16_Flag; 311 } 312 } 313 } 314 315 void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) { 316 sk_memset32(span, fPMColor, count); 317 } 318 319 void SkColorShader::ColorShaderContext::shadeSpan16(int x, int y, uint16_t span[], int count) { 320 sk_memset16(span, fColor16, count); 321 } 322 323 void SkColorShader::ColorShaderContext::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { 324 memset(alpha, SkGetPackedA32(fPMColor), count); 325 } 326 327 // if we had a asAColor method, that would be more efficient... 328 SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix, 329 TileMode modes[]) const { 330 return kNone_BitmapType; 331 } 332 333 SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const { 334 if (info) { 335 if (info->fColors && info->fColorCount >= 1) { 336 info->fColors[0] = fColor; 337 } 338 info->fColorCount = 1; 339 info->fTileMode = SkShader::kRepeat_TileMode; 340 } 341 return kColor_GradientType; 342 } 343 344 #if SK_SUPPORT_GPU 345 346 #include "SkGr.h" 347 348 bool SkColorShader::asFragmentProcessor(GrContext*, const SkPaint& paint, const SkMatrix&, 349 const SkMatrix*, GrColor* paintColor, 350 GrFragmentProcessor** fp) const { 351 *fp = NULL; 352 SkColor skColor = fColor; 353 U8CPU newA = SkMulDiv255Round(SkColorGetA(fColor), paint.getAlpha()); 354 *paintColor = SkColor2GrColor(SkColorSetA(skColor, newA)); 355 return true; 356 } 357 358 #else 359 360 bool SkColorShader::asFragmentProcessor(GrContext*, const SkPaint&, const SkMatrix&, 361 const SkMatrix*, GrColor*, 362 GrFragmentProcessor**) const { 363 SkDEBUGFAIL("Should not call in GPU-less build"); 364 return false; 365 } 366 367 #endif 368 369 #ifndef SK_IGNORE_TO_STRING 370 void SkColorShader::toString(SkString* str) const { 371 str->append("SkColorShader: ("); 372 373 str->append("Color: "); 374 str->appendHex(fColor); 375 376 this->INHERITED::toString(str); 377 378 str->append(")"); 379 } 380 #endif 381 382 /////////////////////////////////////////////////////////////////////////////// 383 384 SkFlattenable* SkEmptyShader::CreateProc(SkReadBuffer&) { 385 return SkShader::CreateEmptyShader(); 386 } 387 388 #ifndef SK_IGNORE_TO_STRING 389 #include "SkEmptyShader.h" 390 391 void SkEmptyShader::toString(SkString* str) const { 392 str->append("SkEmptyShader: ("); 393 394 this->INHERITED::toString(str); 395 396 str->append(")"); 397 } 398 #endif 399