SkShader.cpp revision 5970f625e96cdc007c563ae72f343ae0d71719a1
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} 47 48SkShader::SkShader(SkReadBuffer& buffer) : INHERITED(buffer) { 49 inc_shader_counter(); 50 if (buffer.readBool()) { 51 buffer.readMatrix(&fLocalMatrix); 52 } else { 53 fLocalMatrix.reset(); 54 } 55} 56 57SkShader::~SkShader() { 58 dec_shader_counter(); 59} 60 61void SkShader::flatten(SkWriteBuffer& buffer) const { 62 this->INHERITED::flatten(buffer); 63 bool hasLocalM = !fLocalMatrix.isIdentity(); 64 buffer.writeBool(hasLocalM); 65 if (hasLocalM) { 66 buffer.writeMatrix(fLocalMatrix); 67 } 68} 69 70bool SkShader::computeTotalInverse(const ContextRec& rec, SkMatrix* totalInverse) const { 71 SkMatrix total; 72 total.setConcat(*rec.fMatrix, fLocalMatrix); 73 74 const SkMatrix* m = &total; 75 if (rec.fLocalMatrix) { 76 total.setConcat(*m, *rec.fLocalMatrix); 77 m = &total; 78 } 79 return m->invert(totalInverse); 80} 81 82SkShader::Context* SkShader::createContext(const ContextRec& rec, void* storage) const { 83 if (!this->computeTotalInverse(rec, NULL)) { 84 return NULL; 85 } 86 return this->onCreateContext(rec, storage); 87} 88 89SkShader::Context* SkShader::onCreateContext(const ContextRec& rec, void*) const { 90 return NULL; 91} 92 93size_t SkShader::contextSize() const { 94 return 0; 95} 96 97SkShader::Context::Context(const SkShader& shader, const ContextRec& rec) 98 : fShader(shader), fCTM(*rec.fMatrix) 99{ 100 // Because the context parameters must be valid at this point, we know that the matrix is 101 // invertible. 102 SkAssertResult(fShader.computeTotalInverse(rec, &fTotalInverse)); 103 fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse); 104 105 fPaintAlpha = rec.fPaint->getAlpha(); 106} 107 108SkShader::Context::~Context() {} 109 110SkShader::Context::ShadeProc SkShader::Context::asAShadeProc(void** ctx) { 111 return NULL; 112} 113 114#include "SkColorPriv.h" 115 116void SkShader::Context::shadeSpan16(int x, int y, uint16_t span16[], int count) { 117 SkASSERT(span16); 118 SkASSERT(count > 0); 119 SkASSERT(this->canCallShadeSpan16()); 120 121 // basically, if we get here, the subclass screwed up 122 SkDEBUGFAIL("kHasSpan16 flag is set, but shadeSpan16() not implemented"); 123} 124 125#define kTempColorQuadCount 6 // balance between speed (larger) and saving stack-space 126#define kTempColorCount (kTempColorQuadCount << 2) 127 128#ifdef SK_CPU_BENDIAN 129 #define SkU32BitShiftToByteOffset(shift) (3 - ((shift) >> 3)) 130#else 131 #define SkU32BitShiftToByteOffset(shift) ((shift) >> 3) 132#endif 133 134void SkShader::Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { 135 SkASSERT(count > 0); 136 137 SkPMColor colors[kTempColorCount]; 138 139 while ((count -= kTempColorCount) >= 0) { 140 this->shadeSpan(x, y, colors, kTempColorCount); 141 x += kTempColorCount; 142 143 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 144 int quads = kTempColorQuadCount; 145 do { 146 U8CPU a0 = srcA[0]; 147 U8CPU a1 = srcA[4]; 148 U8CPU a2 = srcA[8]; 149 U8CPU a3 = srcA[12]; 150 srcA += 4*4; 151 *alpha++ = SkToU8(a0); 152 *alpha++ = SkToU8(a1); 153 *alpha++ = SkToU8(a2); 154 *alpha++ = SkToU8(a3); 155 } while (--quads != 0); 156 } 157 SkASSERT(count < 0); 158 SkASSERT(count + kTempColorCount >= 0); 159 if (count += kTempColorCount) { 160 this->shadeSpan(x, y, colors, count); 161 162 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 163 do { 164 *alpha++ = *srcA; 165 srcA += 4; 166 } while (--count != 0); 167 } 168#if 0 169 do { 170 int n = count; 171 if (n > kTempColorCount) 172 n = kTempColorCount; 173 SkASSERT(n > 0); 174 175 this->shadeSpan(x, y, colors, n); 176 x += n; 177 count -= n; 178 179 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 180 do { 181 *alpha++ = *srcA; 182 srcA += 4; 183 } while (--n != 0); 184 } while (count > 0); 185#endif 186} 187 188SkShader::Context::MatrixClass SkShader::Context::ComputeMatrixClass(const SkMatrix& mat) { 189 MatrixClass mc = kLinear_MatrixClass; 190 191 if (mat.hasPerspective()) { 192 if (mat.fixedStepInX(0, NULL, NULL)) { 193 mc = kFixedStepInX_MatrixClass; 194 } else { 195 mc = kPerspective_MatrixClass; 196 } 197 } 198 return mc; 199} 200 201////////////////////////////////////////////////////////////////////////////// 202 203SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*, TileMode*) const { 204 return kNone_BitmapType; 205} 206 207SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const { 208 return kNone_GradientType; 209} 210 211GrEffectRef* SkShader::asNewEffect(GrContext*, const SkPaint&, const SkMatrix*) const { 212 return NULL; 213} 214 215SkShader* SkShader::refAsALocalMatrixShader(SkMatrix*) const { 216 return NULL; 217} 218 219SkShader* SkShader::CreateEmptyShader() { 220 return SkNEW(SkEmptyShader); 221} 222 223SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, 224 const SkMatrix* localMatrix) { 225 return ::CreateBitmapShader(src, tmx, tmy, localMatrix, NULL); 226} 227 228SkShader* SkShader::CreatePictureShader(SkPicture* src, TileMode tmx, TileMode tmy, 229 const SkMatrix* localMatrix) { 230 return SkPictureShader::Create(src, tmx, tmy, localMatrix); 231} 232 233#ifndef SK_IGNORE_TO_STRING 234void SkShader::toString(SkString* str) const { 235 if (!fLocalMatrix.isIdentity()) { 236 str->append(" "); 237 fLocalMatrix.toString(str); 238 } 239} 240#endif 241 242////////////////////////////////////////////////////////////////////////////// 243 244#include "SkColorShader.h" 245#include "SkUtils.h" 246 247SkColorShader::SkColorShader(SkColor c) 248 : fColor(c) { 249} 250 251bool SkColorShader::isOpaque() const { 252 return SkColorGetA(fColor) == 255; 253} 254 255SkColorShader::SkColorShader(SkReadBuffer& b) : INHERITED(b) { 256 // V25_COMPATIBILITY_CODE We had a boolean to make the color shader inherit the paint's 257 // color. We don't support that any more. 258 if (b.pictureVersion() < 26 && 0 != b.pictureVersion()) { 259 if (b.readBool()) { 260 SkDEBUGFAIL("We shouldn't have pictures that recorded the inherited case."); 261 fColor = SK_ColorWHITE; 262 return; 263 } 264 } 265 fColor = b.readColor(); 266} 267 268void SkColorShader::flatten(SkWriteBuffer& buffer) const { 269 this->INHERITED::flatten(buffer); 270 buffer.writeColor(fColor); 271} 272 273uint32_t SkColorShader::ColorShaderContext::getFlags() const { 274 return fFlags; 275} 276 277uint8_t SkColorShader::ColorShaderContext::getSpan16Alpha() const { 278 return SkGetPackedA32(fPMColor); 279} 280 281SkShader::Context* SkColorShader::onCreateContext(const ContextRec& rec, void* storage) const { 282 return SkNEW_PLACEMENT_ARGS(storage, ColorShaderContext, (*this, rec)); 283} 284 285SkColorShader::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 315void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) { 316 sk_memset32(span, fPMColor, count); 317} 318 319void SkColorShader::ColorShaderContext::shadeSpan16(int x, int y, uint16_t span[], int count) { 320 sk_memset16(span, fColor16, count); 321} 322 323void 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... 328SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix, 329 TileMode modes[]) const { 330 return kNone_BitmapType; 331} 332 333SkShader::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#ifndef SK_IGNORE_TO_STRING 345void SkColorShader::toString(SkString* str) const { 346 str->append("SkColorShader: ("); 347 348 str->append("Color: "); 349 str->appendHex(fColor); 350 351 this->INHERITED::toString(str); 352 353 str->append(")"); 354} 355#endif 356 357/////////////////////////////////////////////////////////////////////////////// 358 359#ifndef SK_IGNORE_TO_STRING 360#include "SkEmptyShader.h" 361 362void SkEmptyShader::toString(SkString* str) const { 363 str->append("SkEmptyShader: ("); 364 365 this->INHERITED::toString(str); 366 367 str->append(")"); 368} 369#endif 370