| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 The Android Open Source Project | 2 * Copyright 2012 The Android Open Source Project |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkColorFilterImageFilter.h" | 8 #include "SkColorFilterImageFilter.h" |
| 9 #include "SkBitmap.h" | 9 #include "SkBitmap.h" |
| 10 #include "SkCanvas.h" | 10 #include "SkCanvas.h" |
| 11 #include "SkColorMatrixFilter.h" | 11 #include "SkColorMatrixFilter.h" |
| 12 #include "SkDevice.h" | 12 #include "SkDevice.h" |
| 13 #include "SkColorFilter.h" | 13 #include "SkColorFilter.h" |
| 14 #include "SkReadBuffer.h" | 14 #include "SkReadBuffer.h" |
| 15 #include "SkTableColorFilter.h" | 15 #include "SkTableColorFilter.h" |
| 16 #include "SkWriteBuffer.h" | 16 #include "SkWriteBuffer.h" |
| 17 | 17 |
| 18 namespace { | |
| 19 | |
| 20 void mult_color_matrix(SkScalar a[20], SkScalar b[20], SkScalar out[20]) { | |
| 21 for (int j = 0; j < 4; ++j) { | |
| 22 for (int i = 0; i < 5; ++i) { | |
| 23 out[i+j*5] = 4 == i ? a[4+j*5] : 0; | |
| 24 for (int k = 0; k < 4; ++k) | |
| 25 out[i+j*5] += a[k+j*5] * b[i+k*5]; | |
| 26 } | |
| 27 } | |
| 28 } | |
| 29 | |
| 30 // Combines the two lookup tables so that making a lookup using OUT has | |
| 31 // the same effect as making a lookup through B then A. | |
| 32 void combine_color_tables(const uint8_t a[4 * 256], | |
| 33 const uint8_t b[4 * 256], | |
| 34 uint8_t out[4 * 256]) { | |
| 35 for (int i = 0; i < 4; i++) { | |
| 36 for (int j = 0; j < 256; j++) { | |
| 37 out[i * 256 + j] = a[i * 256 + b[i * 256 + j]]; | |
| 38 } | |
| 39 } | |
| 40 } | |
| 41 | |
| 42 // To detect if we need to apply clamping after applying a matrix, we check if | |
| 43 // any output component might go outside of [0, 255] for any combination of | |
| 44 // input components in [0..255]. | |
| 45 // Each output component is an affine transformation of the input component, so | |
| 46 // the minimum and maximum values are for any combination of minimum or maximum | |
| 47 // values of input components (i.e. 0 or 255). | |
| 48 // E.g. if R' = x*R + y*G + z*B + w*A + t | |
| 49 // Then the maximum value will be for R=255 if x>0 or R=0 if x<0, and the | |
| 50 // minimum value will be for R=0 if x>0 or R=255 if x<0. | |
| 51 // Same goes for all components. | |
| 52 bool component_needs_clamping(SkScalar row[5]) { | |
| 53 SkScalar maxValue = row[4] / 255; | |
| 54 SkScalar minValue = row[4] / 255; | |
| 55 for (int i = 0; i < 4; ++i) { | |
| 56 if (row[i] > 0) | |
| 57 maxValue += row[i]; | |
| 58 else | |
| 59 minValue += row[i]; | |
| 60 } | |
| 61 return (maxValue > 1) || (minValue < 0); | |
| 62 } | |
| 63 | |
| 64 bool matrix_needs_clamping(SkScalar matrix[20]) { | |
| 65 return component_needs_clamping(matrix) | |
| 66 || component_needs_clamping(matrix+5) | |
| 67 || component_needs_clamping(matrix+10) | |
| 68 || component_needs_clamping(matrix+15); | |
| 69 } | |
| 70 | |
| 71 }; | |
| 72 | |
| 73 SkColorFilterImageFilter* SkColorFilterImageFilter::Create(SkColorFilter* cf, | 18 SkColorFilterImageFilter* SkColorFilterImageFilter::Create(SkColorFilter* cf, |
| 74 SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) { | 19 SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) { |
| 75 if (NULL == cf) { | 20 if (NULL == cf) { |
| 76 return NULL; | 21 return NULL; |
| 77 } | 22 } |
| 78 | 23 |
| 79 SkColorFilter* inputColorFilter; | 24 SkColorFilter* inputColorFilter; |
| 80 if (input && input->asColorFilter(&inputColorFilter) && inputColorFilter) { | 25 if (input && input->asColorFilter(&inputColorFilter)) { |
| 81 SkAutoUnref autoUnref(inputColorFilter); | 26 SkAutoUnref autoUnref(inputColorFilter); |
| 82 | 27 SkAutoTUnref<SkColorFilter> newCF(cf->newComposed(inputColorFilter)); |
| 83 // Try to collapse two consecutive matrix filters | 28 if (newCF) { |
| 84 SkScalar colorMatrix[20], inputMatrix[20]; | |
| 85 if (cf->asColorMatrix(colorMatrix) && inputColorFilter->asColorMatrix(in
putMatrix) | |
| 86 && !matrix_needs_clamping(inputMatrix
)) { | |
| 87 SkScalar combinedMatrix[20]; | |
| 88 mult_color_matrix(colorMatrix, inputMatrix, combinedMatrix); | |
| 89 SkAutoTUnref<SkColorFilter> newCF(SkColorMatrixFilter::Create(combin
edMatrix)); | |
| 90 return SkNEW_ARGS(SkColorFilterImageFilter, (newCF, input->getInput(
0), cropRect, 0)); | |
| 91 } | |
| 92 | |
| 93 // Try to collapse two consecutive table filters | |
| 94 SkBitmap colorTable, inputTable; | |
| 95 if (cf->asComponentTable(&colorTable) && inputColorFilter->asComponentTa
ble(&inputTable)) { | |
| 96 uint8_t combinedTable[4 * 256]; | |
| 97 SkAutoLockPixels colorLock(colorTable); | |
| 98 SkAutoLockPixels inputLock(inputTable); | |
| 99 | |
| 100 combine_color_tables(colorTable.getAddr8(0, 0), inputTable.getAddr8(
0, 0), | |
| 101 combinedTable); | |
| 102 SkAutoTUnref<SkColorFilter> newCF(SkTableColorFilter::CreateARGB( | |
| 103 &combinedTable[256 * 0], | |
| 104 &combinedTable[256 * 1], | |
| 105 &combinedTable[256 * 2], | |
| 106 &combinedTable[256 * 3]) | |
| 107 ); | |
| 108 | |
| 109 return SkNEW_ARGS(SkColorFilterImageFilter, (newCF, input->getInput(
0), cropRect, 0)); | 29 return SkNEW_ARGS(SkColorFilterImageFilter, (newCF, input->getInput(
0), cropRect, 0)); |
| 110 } | 30 } |
| 111 } | 31 } |
| 112 | 32 |
| 113 return SkNEW_ARGS(SkColorFilterImageFilter, (cf, input, cropRect, uniqueID))
; | 33 return SkNEW_ARGS(SkColorFilterImageFilter, (cf, input, cropRect, uniqueID))
; |
| 114 } | 34 } |
| 115 | 35 |
| 116 SkColorFilterImageFilter::SkColorFilterImageFilter(SkColorFilter* cf, | 36 SkColorFilterImageFilter::SkColorFilterImageFilter(SkColorFilter* cf, |
| 117 SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) | 37 SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) |
| 118 : INHERITED(1, &input, cropRect, uniqueID), fColorFilter(SkRef(cf)) { | 38 : INHERITED(1, &input, cropRect, uniqueID), fColorFilter(SkRef(cf)) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 if (this->getInput(0)) { | 105 if (this->getInput(0)) { |
| 186 this->getInput(0)->toString(str); | 106 this->getInput(0)->toString(str); |
| 187 } | 107 } |
| 188 | 108 |
| 189 str->appendf(") color filter: "); | 109 str->appendf(") color filter: "); |
| 190 fColorFilter->toString(str); | 110 fColorFilter->toString(str); |
| 191 | 111 |
| 192 str->append(")"); | 112 str->append(")"); |
| 193 } | 113 } |
| 194 #endif | 114 #endif |
| OLD | NEW |