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