1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "SkColorMatrixFilter.h" 9 #include "SkColorMatrix.h" 10 #include "SkColorPriv.h" 11 #include "SkUnPreMultiply.h" 12 13 static int32_t rowmul4(const int32_t array[], unsigned r, unsigned g, 14 unsigned b, unsigned a) { 15 return array[0] * r + array[1] * g + array[2] * b + array[3] * a + array[4]; 16 } 17 18 static int32_t rowmul3(const int32_t array[], unsigned r, unsigned g, 19 unsigned b) { 20 return array[0] * r + array[1] * g + array[2] * b + array[4]; 21 } 22 23 static void General(SkColorMatrixFilter::State* state, 24 unsigned r, unsigned g, unsigned b, unsigned a) { 25 const int32_t* SK_RESTRICT array = state->fArray; 26 const int shift = state->fShift; 27 int32_t* SK_RESTRICT result = state->fResult; 28 29 result[0] = rowmul4(&array[0], r, g, b, a) >> shift; 30 result[1] = rowmul4(&array[5], r, g, b, a) >> shift; 31 result[2] = rowmul4(&array[10], r, g, b, a) >> shift; 32 result[3] = rowmul4(&array[15], r, g, b, a) >> shift; 33 } 34 35 static void General16(SkColorMatrixFilter::State* state, 36 unsigned r, unsigned g, unsigned b, unsigned a) { 37 const int32_t* SK_RESTRICT array = state->fArray; 38 int32_t* SK_RESTRICT result = state->fResult; 39 40 result[0] = rowmul4(&array[0], r, g, b, a) >> 16; 41 result[1] = rowmul4(&array[5], r, g, b, a) >> 16; 42 result[2] = rowmul4(&array[10], r, g, b, a) >> 16; 43 result[3] = rowmul4(&array[15], r, g, b, a) >> 16; 44 } 45 46 static void AffineAdd(SkColorMatrixFilter::State* state, 47 unsigned r, unsigned g, unsigned b, unsigned a) { 48 const int32_t* SK_RESTRICT array = state->fArray; 49 const int shift = state->fShift; 50 int32_t* SK_RESTRICT result = state->fResult; 51 52 result[0] = rowmul3(&array[0], r, g, b) >> shift; 53 result[1] = rowmul3(&array[5], r, g, b) >> shift; 54 result[2] = rowmul3(&array[10], r, g, b) >> shift; 55 result[3] = a; 56 } 57 58 static void AffineAdd16(SkColorMatrixFilter::State* state, 59 unsigned r, unsigned g, unsigned b, unsigned a) { 60 const int32_t* SK_RESTRICT array = state->fArray; 61 int32_t* SK_RESTRICT result = state->fResult; 62 63 result[0] = rowmul3(&array[0], r, g, b) >> 16; 64 result[1] = rowmul3(&array[5], r, g, b) >> 16; 65 result[2] = rowmul3(&array[10], r, g, b) >> 16; 66 result[3] = a; 67 } 68 69 static void ScaleAdd(SkColorMatrixFilter::State* state, 70 unsigned r, unsigned g, unsigned b, unsigned a) { 71 const int32_t* SK_RESTRICT array = state->fArray; 72 const int shift = state->fShift; 73 int32_t* SK_RESTRICT result = state->fResult; 74 75 // cast to (int) to keep the expression signed for the shift 76 result[0] = (array[0] * (int)r + array[4]) >> shift; 77 result[1] = (array[6] * (int)g + array[9]) >> shift; 78 result[2] = (array[12] * (int)b + array[14]) >> shift; 79 result[3] = a; 80 } 81 82 static void ScaleAdd16(SkColorMatrixFilter::State* state, 83 unsigned r, unsigned g, unsigned b, unsigned a) { 84 const int32_t* SK_RESTRICT array = state->fArray; 85 int32_t* SK_RESTRICT result = state->fResult; 86 87 // cast to (int) to keep the expression signed for the shift 88 result[0] = (array[0] * (int)r + array[4]) >> 16; 89 result[1] = (array[6] * (int)g + array[9]) >> 16; 90 result[2] = (array[12] * (int)b + array[14]) >> 16; 91 result[3] = a; 92 } 93 94 static void Add(SkColorMatrixFilter::State* state, 95 unsigned r, unsigned g, unsigned b, unsigned a) { 96 const int32_t* SK_RESTRICT array = state->fArray; 97 const int shift = state->fShift; 98 int32_t* SK_RESTRICT result = state->fResult; 99 100 result[0] = r + (array[4] >> shift); 101 result[1] = g + (array[9] >> shift); 102 result[2] = b + (array[14] >> shift); 103 result[3] = a; 104 } 105 106 static void Add16(SkColorMatrixFilter::State* state, 107 unsigned r, unsigned g, unsigned b, unsigned a) { 108 const int32_t* SK_RESTRICT array = state->fArray; 109 int32_t* SK_RESTRICT result = state->fResult; 110 111 result[0] = r + (array[4] >> 16); 112 result[1] = g + (array[9] >> 16); 113 result[2] = b + (array[14] >> 16); 114 result[3] = a; 115 } 116 117 #define kNO_ALPHA_FLAGS (SkColorFilter::kAlphaUnchanged_Flag | \ 118 SkColorFilter::kHasFilter16_Flag) 119 120 // src is [20] but some compilers won't accept __restrict__ on anything 121 // but an raw pointer or reference 122 void SkColorMatrixFilter::setup(const SkScalar* SK_RESTRICT src) { 123 if (NULL == src) { 124 fProc = NULL; // signals identity 125 fFlags = kNO_ALPHA_FLAGS; 126 // fState is undefined, but that is OK, since we shouldn't look at it 127 return; 128 } 129 130 int32_t* array = fState.fArray; 131 132 int i; 133 SkFixed max = 0; 134 135 for (int i = 0; i < 20; i++) { 136 SkFixed value = SkScalarToFixed(src[i]); 137 array[i] = value; 138 value = SkAbs32(value); 139 max = SkMax32(max, value); 140 } 141 142 /* All of fArray[] values must fit in 23 bits, to safely allow me to 143 multiply them by 8bit unsigned values, and get a signed answer without 144 overflow. This means clz needs to be 9 or bigger 145 */ 146 int bits = SkCLZ(max); 147 int32_t one = SK_Fixed1; 148 149 fState.fShift = 16; // we are starting out as fixed 16.16 150 if (bits < 9) { 151 bits = 9 - bits; 152 fState.fShift -= bits; 153 for (i = 0; i < 20; i++) { 154 array[i] >>= bits; 155 } 156 one >>= bits; 157 } 158 159 // check if we have to munge Alpha 160 int32_t changesAlpha = (array[15] | array[16] | array[17] | 161 (array[18] - one) | array[19]); 162 int32_t usesAlpha = (array[3] | array[8] | array[13]); 163 bool shiftIs16 = (16 == fState.fShift); 164 165 if (changesAlpha | usesAlpha) { 166 fProc = shiftIs16 ? General16 : General; 167 fFlags = changesAlpha ? 0 : SkColorFilter::kAlphaUnchanged_Flag; 168 } else { 169 fFlags = kNO_ALPHA_FLAGS; 170 171 int32_t needsScale = (array[0] - one) | // red axis 172 (array[6] - one) | // green axis 173 (array[12] - one); // blue axis 174 175 int32_t needs3x3 = array[1] | array[2] | // red off-axis 176 array[5] | array[7] | // green off-axis 177 array[10] | array[11]; // blue off-axis 178 179 if (needs3x3) { 180 fProc = shiftIs16 ? AffineAdd16 : AffineAdd; 181 } else if (needsScale) { 182 fProc = shiftIs16 ? ScaleAdd16 : ScaleAdd; 183 } else if (array[4] | array[9] | array[14]) { // needs add 184 fProc = shiftIs16 ? Add16 : Add; 185 } else { 186 fProc = NULL; // identity 187 } 188 } 189 190 /* preround our add values so we get a rounded shift. We do this after we 191 analyze the array, so we don't miss the case where the caller has zeros 192 which could make us accidentally take the General or Add case. 193 */ 194 if (NULL != fProc) { 195 int32_t add = 1 << (fState.fShift - 1); 196 array[4] += add; 197 array[9] += add; 198 array[14] += add; 199 array[19] += add; 200 } 201 } 202 203 /////////////////////////////////////////////////////////////////////////////// 204 205 static int32_t pin(int32_t value, int32_t max) { 206 if (value < 0) { 207 value = 0; 208 } 209 if (value > max) { 210 value = max; 211 } 212 return value; 213 } 214 215 SkColorMatrixFilter::SkColorMatrixFilter() { 216 this->setup(NULL); 217 } 218 219 SkColorMatrixFilter::SkColorMatrixFilter(const SkColorMatrix& cm) { 220 this->setup(cm.fMat); 221 } 222 223 SkColorMatrixFilter::SkColorMatrixFilter(const SkScalar array[20]) { 224 this->setup(array); 225 } 226 227 uint32_t SkColorMatrixFilter::getFlags() { 228 return this->INHERITED::getFlags() | fFlags; 229 } 230 231 void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count, 232 SkPMColor dst[]) { 233 Proc proc = fProc; 234 State* state = &fState; 235 int32_t* result = state->fResult; 236 237 if (NULL == proc) { 238 if (src != dst) { 239 memcpy(dst, src, count * sizeof(SkPMColor)); 240 } 241 return; 242 } 243 244 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); 245 246 for (int i = 0; i < count; i++) { 247 SkPMColor c = src[i]; 248 249 unsigned r = SkGetPackedR32(c); 250 unsigned g = SkGetPackedG32(c); 251 unsigned b = SkGetPackedB32(c); 252 unsigned a = SkGetPackedA32(c); 253 254 // need our components to be un-premultiplied 255 if (255 != a) { 256 SkUnPreMultiply::Scale scale = table[a]; 257 r = SkUnPreMultiply::ApplyScale(scale, r); 258 g = SkUnPreMultiply::ApplyScale(scale, g); 259 b = SkUnPreMultiply::ApplyScale(scale, b); 260 261 SkASSERT(r <= 255); 262 SkASSERT(g <= 255); 263 SkASSERT(b <= 255); 264 } 265 266 proc(state, r, g, b, a); 267 268 r = pin(result[0], SK_R32_MASK); 269 g = pin(result[1], SK_G32_MASK); 270 b = pin(result[2], SK_B32_MASK); 271 a = pin(result[3], SK_A32_MASK); 272 // re-prepremultiply if needed 273 dst[i] = SkPremultiplyARGBInline(a, r, g, b); 274 } 275 } 276 277 void SkColorMatrixFilter::filterSpan16(const uint16_t src[], int count, 278 uint16_t dst[]) { 279 SkASSERT(fFlags & SkColorFilter::kHasFilter16_Flag); 280 281 Proc proc = fProc; 282 State* state = &fState; 283 int32_t* result = state->fResult; 284 285 if (NULL == proc) { 286 if (src != dst) { 287 memcpy(dst, src, count * sizeof(uint16_t)); 288 } 289 return; 290 } 291 292 for (int i = 0; i < count; i++) { 293 uint16_t c = src[i]; 294 295 // expand to 8bit components (since our matrix translate is 8bit biased 296 unsigned r = SkPacked16ToR32(c); 297 unsigned g = SkPacked16ToG32(c); 298 unsigned b = SkPacked16ToB32(c); 299 300 proc(state, r, g, b, 0); 301 302 r = pin(result[0], SK_R32_MASK); 303 g = pin(result[1], SK_G32_MASK); 304 b = pin(result[2], SK_B32_MASK); 305 306 // now packed it back down to 16bits (hmmm, could dither...) 307 dst[i] = SkPack888ToRGB16(r, g, b); 308 } 309 } 310 311 /////////////////////////////////////////////////////////////////////////////// 312 313 void SkColorMatrixFilter::flatten(SkFlattenableWriteBuffer& buffer) { 314 this->INHERITED::flatten(buffer); 315 316 buffer.writeFunctionPtr((void*)fProc); 317 buffer.writeMul4(&fState, sizeof(fState)); 318 buffer.write32(fFlags); 319 } 320 321 SkFlattenable::Factory SkColorMatrixFilter::getFactory() { return CreateProc; } 322 323 SkColorMatrixFilter::SkColorMatrixFilter(SkFlattenableReadBuffer& buffer) 324 : INHERITED(buffer) { 325 fProc = (Proc)buffer.readFunctionPtr(); 326 buffer.read(&fState, sizeof(fState)); 327 fFlags = buffer.readU32(); 328 } 329 330 bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) { 331 int32_t* array = fState.fArray; 332 int unshift = 16 - fState.fShift; 333 for (int i = 0; i < 20; i++) { 334 matrix[i] = SkFixedToScalar(array[i] << unshift); 335 } 336 if (NULL != fProc) { 337 // Undo the offset applied to the constant column in setup(). 338 SkFixed offset = 1 << (fState.fShift - 1); 339 matrix[4] = SkFixedToScalar((array[4] - offset) << unshift); 340 matrix[9] = SkFixedToScalar((array[9] - offset) << unshift); 341 matrix[14] = SkFixedToScalar((array[14] - offset) << unshift); 342 matrix[19] = SkFixedToScalar((array[19] - offset) << unshift); 343 } 344 return true; 345 } 346 347 SkFlattenable* SkColorMatrixFilter::CreateProc(SkFlattenableReadBuffer& buf) { 348 return SkNEW_ARGS(SkColorMatrixFilter, (buf)); 349 } 350 351 void SkColorMatrixFilter::setMatrix(const SkColorMatrix& matrix) { 352 setup(matrix.fMat); 353 } 354 355 void SkColorMatrixFilter::setArray(const SkScalar array[20]) { 356 setup(array); 357 } 358 359 SK_DEFINE_FLATTENABLE_REGISTRAR(SkColorMatrixFilter) 360