Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / effects / SkColorFilterImageFilter.cpp
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 CropRect* 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 CropRect* cropRect)
80     : INHERITED(input, cropRect), fColorFilter(cf) {
81     SkASSERT(cf);
82     SkSafeRef(cf);
83 }
84
85 SkColorFilterImageFilter::SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer)
86   : INHERITED(1, buffer) {
87     fColorFilter = buffer.readColorFilter();
88 }
89
90 void SkColorFilterImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
91     this->INHERITED::flatten(buffer);
92
93     buffer.writeFlattenable(fColorFilter);
94 }
95
96 SkColorFilterImageFilter::~SkColorFilterImageFilter() {
97     SkSafeUnref(fColorFilter);
98 }
99
100 bool SkColorFilterImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source,
101                                              const SkMatrix& matrix,
102                                              SkBitmap* result,
103                                              SkIPoint* offset) {
104     SkBitmap src = source;
105     SkIPoint srcOffset = SkIPoint::Make(0, 0);
106     if (getInput(0) && !getInput(0)->filterImage(proxy, source, matrix, &src, &srcOffset)) {
107         return false;
108     }
109
110     SkIRect bounds;
111     src.getBounds(&bounds);
112     bounds.offset(srcOffset);
113     if (!this->applyCropRect(&bounds, matrix)) {
114         return false;
115     }
116
117     SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
118     if (NULL == device.get()) {
119         return false;
120     }
121     SkCanvas canvas(device.get());
122     SkPaint paint;
123
124     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
125     paint.setColorFilter(fColorFilter);
126     canvas.drawSprite(src, srcOffset.fX - bounds.fLeft, srcOffset.fY - bounds.fTop, &paint);
127
128     *result = device.get()->accessBitmap(false);
129     offset->fX = bounds.fLeft;
130     offset->fY = bounds.fTop;
131     return true;
132 }
133
134 bool SkColorFilterImageFilter::asColorFilter(SkColorFilter** filter) const {
135     if (!cropRectIsSet()) {
136         if (filter) {
137             *filter = fColorFilter;
138             fColorFilter->ref();
139         }
140         return true;
141     }
142     return false;
143 }