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