SkShader.cpp revision f51de259ada8dacd44eca41945b49a8dba1606ae
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 "SkEmptyShader.h" 10#include "SkReadBuffer.h" 11#include "SkMallocPixelRef.h" 12#include "SkPaint.h" 13#include "SkPicture.h" 14#include "SkPictureShader.h" 15#include "SkScalar.h" 16#include "SkShader.h" 17#include "SkThread.h" 18#include "SkWriteBuffer.h" 19 20//#define SK_TRACK_SHADER_LIFETIME 21 22#ifdef SK_TRACK_SHADER_LIFETIME 23 static int32_t gShaderCounter; 24#endif 25 26static inline void inc_shader_counter() { 27#ifdef SK_TRACK_SHADER_LIFETIME 28 int32_t prev = sk_atomic_inc(&gShaderCounter); 29 SkDebugf("+++ shader counter %d\n", prev + 1); 30#endif 31} 32static inline void dec_shader_counter() { 33#ifdef SK_TRACK_SHADER_LIFETIME 34 int32_t prev = sk_atomic_dec(&gShaderCounter); 35 SkDebugf("--- shader counter %d\n", prev - 1); 36#endif 37} 38 39SkShader::SkShader(const SkMatrix* localMatrix) { 40 inc_shader_counter(); 41 if (localMatrix) { 42 fLocalMatrix = *localMatrix; 43 } else { 44 fLocalMatrix.reset(); 45 } 46#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 47 fGenerationID = 0; 48#endif 49} 50 51SkShader::SkShader(SkReadBuffer& buffer) : INHERITED(buffer) { 52 inc_shader_counter(); 53 if (buffer.readBool()) { 54 buffer.readMatrix(&fLocalMatrix); 55 } else { 56 fLocalMatrix.reset(); 57 } 58#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 59 fGenerationID = 0; 60#endif 61} 62 63SkShader::~SkShader() { 64 dec_shader_counter(); 65} 66 67void SkShader::flatten(SkWriteBuffer& buffer) const { 68 this->INHERITED::flatten(buffer); 69 bool hasLocalM = !fLocalMatrix.isIdentity(); 70 buffer.writeBool(hasLocalM); 71 if (hasLocalM) { 72 buffer.writeMatrix(fLocalMatrix); 73 } 74} 75 76bool SkShader::computeTotalInverse(const ContextRec& rec, SkMatrix* totalInverse) const { 77 SkMatrix total; 78 total.setConcat(*rec.fMatrix, fLocalMatrix); 79 80 const SkMatrix* m = &total; 81 if (rec.fLocalMatrix) { 82 total.setConcat(*m, *rec.fLocalMatrix); 83 m = &total; 84 } 85 return m->invert(totalInverse); 86} 87 88SkShader::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 95SkShader::Context* SkShader::onCreateContext(const ContextRec& rec, void*) const { 96 return NULL; 97} 98 99size_t SkShader::contextSize() const { 100 return 0; 101} 102 103SkShader::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 114SkShader::Context::~Context() {} 115 116SkShader::Context::ShadeProc SkShader::Context::asAShadeProc(void** ctx) { 117 return NULL; 118} 119 120#include "SkColorPriv.h" 121 122void 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 140void 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 194SkShader::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 209SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*, TileMode*) const { 210 return kNone_BitmapType; 211} 212 213SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const { 214 return kNone_GradientType; 215} 216 217bool SkShader::asNewEffect(GrContext* context, const SkPaint& paint, 218 const SkMatrix* localMatrixOrNull, GrColor* grColor, 219 GrEffectRef** grEffect) const { 220 return false; 221} 222 223SkShader* SkShader::refAsALocalMatrixShader(SkMatrix*) const { 224 return NULL; 225} 226 227SkShader* SkShader::CreateEmptyShader() { 228 return SkNEW(SkEmptyShader); 229} 230 231SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, 232 const SkMatrix* localMatrix) { 233 return ::CreateBitmapShader(src, tmx, tmy, localMatrix, NULL); 234} 235 236SkShader* SkShader::CreatePictureShader(SkPicture* src, TileMode tmx, TileMode tmy, 237 const SkMatrix* localMatrix) { 238 return SkPictureShader::Create(src, tmx, tmy, localMatrix); 239} 240 241#ifndef SK_IGNORE_TO_STRING 242void SkShader::toString(SkString* str) const { 243 if (!fLocalMatrix.isIdentity()) { 244 str->append(" "); 245 fLocalMatrix.toString(str); 246 } 247} 248#endif 249 250////////////////////////////////////////////////////////////////////////////// 251 252#include "SkColorShader.h" 253#include "SkUtils.h" 254 255SkColorShader::SkColorShader(SkColor c) 256 : fColor(c) { 257} 258 259bool SkColorShader::isOpaque() const { 260 return SkColorGetA(fColor) == 255; 261} 262 263SkColorShader::SkColorShader(SkReadBuffer& b) : INHERITED(b) { 264 // V25_COMPATIBILITY_CODE We had a boolean to make the color shader inherit the paint's 265 // color. We don't support that any more. 266 if (b.isVersionLT(SkReadBuffer::kColorShaderNoBool_Version)) { 267 if (b.readBool()) { 268 SkDEBUGFAIL("We shouldn't have pictures that recorded the inherited case."); 269 fColor = SK_ColorWHITE; 270 return; 271 } 272 } 273 fColor = b.readColor(); 274} 275 276void SkColorShader::flatten(SkWriteBuffer& buffer) const { 277 this->INHERITED::flatten(buffer); 278 buffer.writeColor(fColor); 279} 280 281uint32_t SkColorShader::ColorShaderContext::getFlags() const { 282 return fFlags; 283} 284 285uint8_t SkColorShader::ColorShaderContext::getSpan16Alpha() const { 286 return SkGetPackedA32(fPMColor); 287} 288 289SkShader::Context* SkColorShader::onCreateContext(const ContextRec& rec, void* storage) const { 290 return SkNEW_PLACEMENT_ARGS(storage, ColorShaderContext, (*this, rec)); 291} 292 293SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader, 294 const ContextRec& rec) 295 : INHERITED(shader, rec) 296{ 297 SkColor color = shader.fColor; 298 unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha())); 299 300 unsigned r = SkColorGetR(color); 301 unsigned g = SkColorGetG(color); 302 unsigned b = SkColorGetB(color); 303 304 // we want this before we apply any alpha 305 fColor16 = SkPack888ToRGB16(r, g, b); 306 307 if (a != 255) { 308 r = SkMulDiv255Round(r, a); 309 g = SkMulDiv255Round(g, a); 310 b = SkMulDiv255Round(b, a); 311 } 312 fPMColor = SkPackARGB32(a, r, g, b); 313 314 fFlags = kConstInY32_Flag; 315 if (255 == a) { 316 fFlags |= kOpaqueAlpha_Flag; 317 if (rec.fPaint->isDither() == false) { 318 fFlags |= kHasSpan16_Flag; 319 } 320 } 321} 322 323void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) { 324 sk_memset32(span, fPMColor, count); 325} 326 327void SkColorShader::ColorShaderContext::shadeSpan16(int x, int y, uint16_t span[], int count) { 328 sk_memset16(span, fColor16, count); 329} 330 331void SkColorShader::ColorShaderContext::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { 332 memset(alpha, SkGetPackedA32(fPMColor), count); 333} 334 335// if we had a asAColor method, that would be more efficient... 336SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix, 337 TileMode modes[]) const { 338 return kNone_BitmapType; 339} 340 341SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const { 342 if (info) { 343 if (info->fColors && info->fColorCount >= 1) { 344 info->fColors[0] = fColor; 345 } 346 info->fColorCount = 1; 347 info->fTileMode = SkShader::kRepeat_TileMode; 348 } 349 return kColor_GradientType; 350} 351 352#if SK_SUPPORT_GPU 353 354#include "SkGr.h" 355 356bool SkColorShader::asNewEffect(GrContext* context, const SkPaint& paint, 357 const SkMatrix* localMatrix, GrColor* grColor, 358 GrEffectRef** grEffect) const { 359 *grEffect = NULL; 360 SkColor skColor = fColor; 361 U8CPU newA = SkMulDiv255Round(SkColorGetA(fColor), paint.getAlpha()); 362 *grColor = SkColor2GrColor(SkColorSetA(skColor, newA)); 363 return true; 364} 365 366#else 367 368bool SkColorShader::asNewEffect(GrContext* context, const SkPaint& paint, 369 const SkMatrix* localMatrix, GrColor* grColor, 370 GrEffectRef** grEffect) const { 371 SkDEBUGFAIL("Should not call in GPU-less build"); 372 return false; 373} 374 375#endif 376 377#ifndef SK_IGNORE_TO_STRING 378void SkColorShader::toString(SkString* str) const { 379 str->append("SkColorShader: ("); 380 381 str->append("Color: "); 382 str->appendHex(fColor); 383 384 this->INHERITED::toString(str); 385 386 str->append(")"); 387} 388#endif 389 390/////////////////////////////////////////////////////////////////////////////// 391 392#ifndef SK_IGNORE_TO_STRING 393#include "SkEmptyShader.h" 394 395void SkEmptyShader::toString(SkString* str) const { 396 str->append("SkEmptyShader: ("); 397 398 this->INHERITED::toString(str); 399 400 str->append(")"); 401} 402#endif 403