1 /* 2 * Copyright 2012 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkColorFilterImageFilter.h" 9 #include "SkBitmap.h" 10 #include "SkCanvas.h" 11 #include "SkColorMatrixFilter.h" 12 #include "SkDevice.h" 13 #include "SkColorFilter.h" 14 #include "SkFlattenableBuffers.h" 15 16 namespace { 17 18 void mult_color_matrix(SkScalar a[20], SkScalar b[20], SkScalar out[20]) { 19 for (int j = 0; j < 4; ++j) { 20 for (int i = 0; i < 5; ++i) { 21 out[i+j*5] = 4 == i ? a[4+j*5] : 0; 22 for (int k = 0; k < 4; ++k) 23 out[i+j*5] += SkScalarMul(a[k+j*5], b[i+k*5]); 24 } 25 } 26 } 27 28 // To detect if we need to apply clamping after applying a matrix, we check if 29 // any output component might go outside of [0, 255] for any combination of 30 // input components in [0..255]. 31 // Each output component is an affine transformation of the input component, so 32 // the minimum and maximum values are for any combination of minimum or maximum 33 // values of input components (i.e. 0 or 255). 34 // E.g. if R' = x*R + y*G + z*B + w*A + t 35 // Then the maximum value will be for R=255 if x>0 or R=0 if x<0, and the 36 // minimum value will be for R=0 if x>0 or R=255 if x<0. 37 // Same goes for all components. 38 bool component_needs_clamping(SkScalar row[5]) { 39 SkScalar maxValue = row[4] / 255; 40 SkScalar minValue = row[4] / 255; 41 for (int i = 0; i < 4; ++i) { 42 if (row[i] > 0) 43 maxValue += row[i]; 44 else 45 minValue += row[i]; 46 } 47 return (maxValue > 1) || (minValue < 0); 48 } 49 50 bool matrix_needs_clamping(SkScalar matrix[20]) { 51 return component_needs_clamping(matrix) 52 || component_needs_clamping(matrix+5) 53 || component_needs_clamping(matrix+10) 54 || component_needs_clamping(matrix+15); 55 } 56 57 }; 58 59 SkColorFilterImageFilter* SkColorFilterImageFilter::Create(SkColorFilter* cf, 60 SkImageFilter* input, const SkIRect* cropRect) { 61 SkASSERT(cf); 62 SkScalar colorMatrix[20], inputMatrix[20]; 63 SkColorFilter* inputColorFilter; 64 if (input && cf->asColorMatrix(colorMatrix) 65 && input->asColorFilter(&inputColorFilter) 66 && (NULL != inputColorFilter)) { 67 SkAutoUnref autoUnref(inputColorFilter); 68 if (inputColorFilter->asColorMatrix(inputMatrix) && !matrix_needs_clamping(inputMatrix)) { 69 SkScalar combinedMatrix[20]; 70 mult_color_matrix(inputMatrix, colorMatrix, combinedMatrix); 71 SkAutoTUnref<SkColorFilter> newCF(SkNEW_ARGS(SkColorMatrixFilter, (combinedMatrix))); 72 return SkNEW_ARGS(SkColorFilterImageFilter, (newCF, input->getInput(0), cropRect)); 73 } 74 } 75 return SkNEW_ARGS(SkColorFilterImageFilter, (cf, input, cropRect)); 76 } 77 78 SkColorFilterImageFilter::SkColorFilterImageFilter(SkColorFilter* cf, 79 SkImageFilter* input, const SkIRect* cropRect) 80 : INHERITED(input, cropRect), fColorFilter(cf) { 81 SkASSERT(cf); 82 SkSafeRef(cf); 83 } 84 85 SkColorFilterImageFilter::SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { 86 fColorFilter = buffer.readFlattenableT<SkColorFilter>(); 87 } 88 89 void SkColorFilterImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { 90 this->INHERITED::flatten(buffer); 91 92 buffer.writeFlattenable(fColorFilter); 93 } 94 95 SkColorFilterImageFilter::~SkColorFilterImageFilter() { 96 SkSafeUnref(fColorFilter); 97 } 98 99 bool SkColorFilterImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, 100 const SkMatrix& matrix, 101 SkBitmap* result, 102 SkIPoint* loc) { 103 SkBitmap src = source; 104 if (getInput(0) && !getInput(0)->filterImage(proxy, source, matrix, &src, loc)) { 105 return false; 106 } 107 108 SkIRect bounds; 109 src.getBounds(&bounds); 110 if (!this->applyCropRect(&bounds)) { 111 return false; 112 } 113 114 SkAutoTUnref<SkDevice> device(proxy->createDevice(bounds.width(), bounds.height())); 115 SkCanvas canvas(device.get()); 116 SkPaint paint; 117 118 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 119 paint.setColorFilter(fColorFilter); 120 canvas.drawSprite(src, -bounds.fLeft, -bounds.fTop, &paint); 121 122 *result = device.get()->accessBitmap(false); 123 loc->fX += bounds.fLeft; 124 loc->fY += bounds.fTop; 125 return true; 126 } 127 128 bool SkColorFilterImageFilter::asColorFilter(SkColorFilter** filter) const { 129 if (cropRect().isLargest()) { 130 if (filter) { 131 *filter = fColorFilter; 132 fColorFilter->ref(); 133 } 134 return true; 135 } 136 return false; 137 } 138