1 /* libs/graphics/sgl/SkShader.cpp 2 ** 3 ** Copyright 2006, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #include "SkScalar.h" 19 #include "SkShader.h" 20 #include "SkPaint.h" 21 #include "SkMallocPixelRef.h" 22 23 SkShader::SkShader() : fLocalMatrix(NULL) { 24 SkDEBUGCODE(fInSession = false;) 25 } 26 27 SkShader::SkShader(SkFlattenableReadBuffer& buffer) 28 : INHERITED(buffer), fLocalMatrix(NULL) { 29 if (buffer.readBool()) { 30 SkMatrix matrix; 31 SkReadMatrix(&buffer, &matrix); 32 setLocalMatrix(matrix); 33 } 34 SkDEBUGCODE(fInSession = false;) 35 } 36 37 SkShader::~SkShader() { 38 SkASSERT(!fInSession); 39 sk_free(fLocalMatrix); 40 } 41 42 void SkShader::beginSession() { 43 SkASSERT(!fInSession); 44 SkDEBUGCODE(fInSession = true;) 45 } 46 47 void SkShader::endSession() { 48 SkASSERT(fInSession); 49 SkDEBUGCODE(fInSession = false;) 50 } 51 52 void SkShader::flatten(SkFlattenableWriteBuffer& buffer) { 53 this->INHERITED::flatten(buffer); 54 buffer.writeBool(fLocalMatrix != NULL); 55 if (fLocalMatrix) { 56 SkWriteMatrix(&buffer, *fLocalMatrix); 57 } 58 } 59 60 bool SkShader::getLocalMatrix(SkMatrix* localM) const { 61 if (fLocalMatrix) { 62 if (localM) { 63 *localM = *fLocalMatrix; 64 } 65 return true; 66 } else { 67 if (localM) { 68 localM->reset(); 69 } 70 return false; 71 } 72 } 73 74 void SkShader::setLocalMatrix(const SkMatrix& localM) { 75 if (localM.isIdentity()) { 76 this->resetLocalMatrix(); 77 } else { 78 if (fLocalMatrix == NULL) { 79 fLocalMatrix = (SkMatrix*)sk_malloc_throw(sizeof(SkMatrix)); 80 } 81 *fLocalMatrix = localM; 82 } 83 } 84 85 void SkShader::resetLocalMatrix() { 86 if (fLocalMatrix) { 87 sk_free(fLocalMatrix); 88 fLocalMatrix = NULL; 89 } 90 } 91 92 bool SkShader::setContext(const SkBitmap& device, 93 const SkPaint& paint, 94 const SkMatrix& matrix) { 95 const SkMatrix* m = &matrix; 96 SkMatrix total; 97 98 fDeviceConfig = SkToU8(device.getConfig()); 99 fPaintAlpha = paint.getAlpha(); 100 if (fLocalMatrix) { 101 total.setConcat(matrix, *fLocalMatrix); 102 m = &total; 103 } 104 if (m->invert(&fTotalInverse)) { 105 fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse); 106 return true; 107 } 108 return false; 109 } 110 111 #include "SkColorPriv.h" 112 113 void SkShader::shadeSpan16(int x, int y, uint16_t span16[], int count) { 114 SkASSERT(span16); 115 SkASSERT(count > 0); 116 SkASSERT(this->canCallShadeSpan16()); 117 118 // basically, if we get here, the subclass screwed up 119 SkASSERT(!"kHasSpan16 flag is set, but shadeSpan16() not implemented"); 120 } 121 122 #define kTempColorQuadCount 6 // balance between speed (larger) and saving stack-space 123 #define kTempColorCount (kTempColorQuadCount << 2) 124 125 #ifdef SK_CPU_BENDIAN 126 #define SkU32BitShiftToByteOffset(shift) (3 - ((shift) >> 3)) 127 #else 128 #define SkU32BitShiftToByteOffset(shift) ((shift) >> 3) 129 #endif 130 131 void SkShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { 132 SkASSERT(count > 0); 133 134 SkPMColor colors[kTempColorCount]; 135 136 while ((count -= kTempColorCount) >= 0) { 137 this->shadeSpan(x, y, colors, kTempColorCount); 138 x += kTempColorCount; 139 140 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 141 int quads = kTempColorQuadCount; 142 do { 143 U8CPU a0 = srcA[0]; 144 U8CPU a1 = srcA[4]; 145 U8CPU a2 = srcA[8]; 146 U8CPU a3 = srcA[12]; 147 srcA += 4*4; 148 *alpha++ = SkToU8(a0); 149 *alpha++ = SkToU8(a1); 150 *alpha++ = SkToU8(a2); 151 *alpha++ = SkToU8(a3); 152 } while (--quads != 0); 153 } 154 SkASSERT(count < 0); 155 SkASSERT(count + kTempColorCount >= 0); 156 if (count += kTempColorCount) { 157 this->shadeSpan(x, y, colors, count); 158 159 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 160 do { 161 *alpha++ = *srcA; 162 srcA += 4; 163 } while (--count != 0); 164 } 165 #if 0 166 do { 167 int n = count; 168 if (n > kTempColorCount) 169 n = kTempColorCount; 170 SkASSERT(n > 0); 171 172 this->shadeSpan(x, y, colors, n); 173 x += n; 174 count -= n; 175 176 const uint8_t* srcA = (const uint8_t*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT); 177 do { 178 *alpha++ = *srcA; 179 srcA += 4; 180 } while (--n != 0); 181 } while (count > 0); 182 #endif 183 } 184 185 SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) { 186 MatrixClass mc = kLinear_MatrixClass; 187 188 if (mat.hasPerspective()) { 189 if (mat.fixedStepInX(0, NULL, NULL)) { 190 mc = kFixedStepInX_MatrixClass; 191 } else { 192 mc = kPerspective_MatrixClass; 193 } 194 } 195 return mc; 196 } 197 198 ////////////////////////////////////////////////////////////////////////////// 199 200 SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*, 201 TileMode*, SkScalar*) const { 202 return kNone_BitmapType; 203 } 204 205 SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const { 206 return kNone_GradientType; 207 } 208 209 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, 210 TileMode tmx, TileMode tmy) { 211 return SkShader::CreateBitmapShader(src, tmx, tmy, NULL, 0); 212 } 213 214 ////////////////////////////////////////////////////////////////////////////// 215 216 #include "SkColorShader.h" 217 #include "SkUtils.h" 218 219 SkColorShader::SkColorShader() { 220 fFlags = 0; 221 fInheritColor = true; 222 fAsABitmapPixelRef = NULL; 223 } 224 225 SkColorShader::SkColorShader(SkColor c) { 226 fFlags = 0; 227 fColor = c; 228 fInheritColor = false; 229 fAsABitmapPixelRef = NULL; 230 } 231 232 SkColorShader::~SkColorShader() { 233 SkSafeUnref(fAsABitmapPixelRef); 234 } 235 236 SkColorShader::SkColorShader(SkFlattenableReadBuffer& b) : INHERITED(b) { 237 fFlags = 0; // computed in setContext 238 fAsABitmapPixelRef = NULL; 239 240 fInheritColor = b.readU8(); 241 if (fInheritColor) { 242 return; 243 } 244 fColor = b.readU32(); 245 } 246 247 void SkColorShader::flatten(SkFlattenableWriteBuffer& buffer) { 248 this->INHERITED::flatten(buffer); 249 buffer.write8(fInheritColor); 250 if (fInheritColor) { 251 return; 252 } 253 buffer.write32(fColor); 254 } 255 256 uint8_t SkColorShader::getSpan16Alpha() const { 257 return SkGetPackedA32(fPMColor); 258 } 259 260 bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint, 261 const SkMatrix& matrix) { 262 if (!this->INHERITED::setContext(device, paint, matrix)) { 263 return false; 264 } 265 266 unsigned a; 267 268 if (fInheritColor) { 269 fColor = paint.getColor(); 270 a = SkColorGetA(fColor); 271 } else { 272 a = SkAlphaMul(SkColorGetA(fColor), SkAlpha255To256(paint.getAlpha())); 273 } 274 275 unsigned r = SkColorGetR(fColor); 276 unsigned g = SkColorGetG(fColor); 277 unsigned b = SkColorGetB(fColor); 278 279 // we want this before we apply any alpha 280 fColor16 = SkPack888ToRGB16(r, g, b); 281 282 if (a != 255) { 283 r = SkMulDiv255Round(r, a); 284 g = SkMulDiv255Round(g, a); 285 b = SkMulDiv255Round(b, a); 286 } 287 fPMColor = SkPackARGB32(a, r, g, b); 288 289 fFlags = kConstInY32_Flag; 290 if (255 == a) { 291 fFlags |= kOpaqueAlpha_Flag; 292 if (paint.isDither() == false) { 293 fFlags |= kHasSpan16_Flag; 294 } 295 } 296 297 return true; 298 } 299 300 void SkColorShader::shadeSpan(int x, int y, SkPMColor span[], int count) { 301 sk_memset32(span, fPMColor, count); 302 } 303 304 void SkColorShader::shadeSpan16(int x, int y, uint16_t span[], int count) { 305 sk_memset16(span, fColor16, count); 306 } 307 308 void SkColorShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { 309 memset(alpha, SkGetPackedA32(fPMColor), count); 310 } 311 312 // if we had a asAColor method, that would be more efficient... 313 SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix, 314 TileMode modes[], 315 SkScalar* twoPointRadialParams) const { 316 // we cache the pixelref, since its generateID is used in the texture cache 317 if (NULL == fAsABitmapPixelRef) { 318 SkPMColor* storage = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor)); 319 *storage = fPMColor; 320 fAsABitmapPixelRef = new SkMallocPixelRef(storage, sizeof(SkPMColor), 321 NULL); 322 } 323 324 if (bitmap) { 325 bitmap->setConfig(SkBitmap::kARGB_8888_Config, 1, 1); 326 bitmap->setPixelRef(fAsABitmapPixelRef); 327 } 328 if (matrix) { 329 matrix->reset(); 330 } 331 if (modes) { 332 modes[0] = modes[1] = SkShader::kRepeat_TileMode; 333 } 334 return kDefault_BitmapType; 335 } 336 337 SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const { 338 if (info) { 339 if (info->fColors && info->fColorCount >= 1) { 340 info->fColors[0] = fColor; 341 } 342 info->fColorCount = 1; 343 info->fTileMode = SkShader::kRepeat_TileMode; 344 } 345 return kColor_GradientType; 346 } 347