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 "SkWriteBuffer.h" | 16 #include "SkWriteBuffer.h" |
16 | 17 |
17 namespace { | 18 namespace { |
18 | 19 |
19 void mult_color_matrix(SkScalar a[20], SkScalar b[20], SkScalar out[20]) { | 20 void mult_color_matrix(SkScalar a[20], SkScalar b[20], SkScalar out[20]) { |
20 for (int j = 0; j < 4; ++j) { | 21 for (int j = 0; j < 4; ++j) { |
21 for (int i = 0; i < 5; ++i) { | 22 for (int i = 0; i < 5; ++i) { |
22 out[i+j*5] = 4 == i ? a[4+j*5] : 0; | 23 out[i+j*5] = 4 == i ? a[4+j*5] : 0; |
23 for (int k = 0; k < 4; ++k) | 24 for (int k = 0; k < 4; ++k) |
24 out[i+j*5] += SkScalarMul(a[k+j*5], b[i+k*5]); | 25 out[i+j*5] += a[k+j*5] * b[i+k*5]; |
25 } | 26 } |
26 } | 27 } |
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 } |
28 | 41 |
29 // To detect if we need to apply clamping after applying a matrix, we check if | 42 // To detect if we need to apply clamping after applying a matrix, we check if |
30 // any output component might go outside of [0, 255] for any combination of | 43 // any output component might go outside of [0, 255] for any combination of |
31 // input components in [0..255]. | 44 // input components in [0..255]. |
32 // Each output component is an affine transformation of the input component, so | 45 // Each output component is an affine transformation of the input component, so |
33 // the minimum and maximum values are for any combination of minimum or maximum | 46 // the minimum and maximum values are for any combination of minimum or maximum |
34 // values of input components (i.e. 0 or 255). | 47 // values of input components (i.e. 0 or 255). |
35 // E.g. if R' = x*R + y*G + z*B + w*A + t | 48 // E.g. if R' = x*R + y*G + z*B + w*A + t |
36 // Then the maximum value will be for R=255 if x>0 or R=0 if x<0, and the | 49 // Then the maximum value will be for R=255 if x>0 or R=0 if x<0, and the |
37 // minimum value will be for R=0 if x>0 or R=255 if x<0. | 50 // minimum value will be for R=0 if x>0 or R=255 if x<0. |
(...skipping 14 matching lines...) Expand all Loading... |
52 return component_needs_clamping(matrix) | 65 return component_needs_clamping(matrix) |
53 || component_needs_clamping(matrix+5) | 66 || component_needs_clamping(matrix+5) |
54 || component_needs_clamping(matrix+10) | 67 || component_needs_clamping(matrix+10) |
55 || component_needs_clamping(matrix+15); | 68 || component_needs_clamping(matrix+15); |
56 } | 69 } |
57 | 70 |
58 }; | 71 }; |
59 | 72 |
60 SkColorFilterImageFilter* SkColorFilterImageFilter::Create(SkColorFilter* cf, | 73 SkColorFilterImageFilter* SkColorFilterImageFilter::Create(SkColorFilter* cf, |
61 SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) { | 74 SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) { |
62 SkASSERT(cf); | |
63 if (NULL == cf) { | 75 if (NULL == cf) { |
64 return NULL; | 76 return NULL; |
65 } | 77 } |
66 SkScalar colorMatrix[20], inputMatrix[20]; | 78 |
67 SkColorFilter* inputColorFilter; | 79 SkColorFilter* inputColorFilter; |
68 if (input && cf->asColorMatrix(colorMatrix) | 80 if (input && input->asColorFilter(&inputColorFilter) && inputColorFilter) { |
69 && input->asColorFilter(&inputColorFilter) | |
70 && (inputColorFilter)) { | |
71 SkAutoUnref autoUnref(inputColorFilter); | 81 SkAutoUnref autoUnref(inputColorFilter); |
72 if (inputColorFilter->asColorMatrix(inputMatrix) && !matrix_needs_clampi
ng(inputMatrix)) { | 82 |
| 83 // Try to collapse two consecutive matrix filters |
| 84 SkScalar colorMatrix[20], inputMatrix[20]; |
| 85 if (cf->asColorMatrix(colorMatrix) && inputColorFilter->asColorMatrix(in
putMatrix) |
| 86 && !matrix_needs_clamping(inputMatrix
)) { |
73 SkScalar combinedMatrix[20]; | 87 SkScalar combinedMatrix[20]; |
74 mult_color_matrix(colorMatrix, inputMatrix, combinedMatrix); | 88 mult_color_matrix(colorMatrix, inputMatrix, combinedMatrix); |
75 SkAutoTUnref<SkColorFilter> newCF(SkColorMatrixFilter::Create(combin
edMatrix)); | 89 SkAutoTUnref<SkColorFilter> newCF(SkColorMatrixFilter::Create(combin
edMatrix)); |
76 return SkNEW_ARGS(SkColorFilterImageFilter, (newCF, input->getInput(
0), cropRect, 0)); | 90 return SkNEW_ARGS(SkColorFilterImageFilter, (newCF, input->getInput(
0), cropRect, 0)); |
77 } | 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)); |
| 110 } |
78 } | 111 } |
| 112 |
79 return SkNEW_ARGS(SkColorFilterImageFilter, (cf, input, cropRect, uniqueID))
; | 113 return SkNEW_ARGS(SkColorFilterImageFilter, (cf, input, cropRect, uniqueID))
; |
80 } | 114 } |
81 | 115 |
82 SkColorFilterImageFilter::SkColorFilterImageFilter(SkColorFilter* cf, | 116 SkColorFilterImageFilter::SkColorFilterImageFilter(SkColorFilter* cf, |
83 SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) | 117 SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) |
84 : INHERITED(1, &input, cropRect, uniqueID), fColorFilter(SkRef(cf)) { | 118 : INHERITED(1, &input, cropRect, uniqueID), fColorFilter(SkRef(cf)) { |
85 } | 119 } |
86 | 120 |
87 SkFlattenable* SkColorFilterImageFilter::CreateProc(SkReadBuffer& buffer) { | 121 SkFlattenable* SkColorFilterImageFilter::CreateProc(SkReadBuffer& buffer) { |
88 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); | 122 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 if (this->getInput(0)) { | 185 if (this->getInput(0)) { |
152 this->getInput(0)->toString(str); | 186 this->getInput(0)->toString(str); |
153 } | 187 } |
154 | 188 |
155 str->appendf(") color filter: "); | 189 str->appendf(") color filter: "); |
156 fColorFilter->toString(str); | 190 fColorFilter->toString(str); |
157 | 191 |
158 str->append(")"); | 192 str->append(")"); |
159 } | 193 } |
160 #endif | 194 #endif |
OLD | NEW |