Upstream version 9.38.198.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 "SkReadBuffer.h"
15 #include "SkWriteBuffer.h"
16
17 namespace {
18
19 void mult_color_matrix(SkScalar a[20], SkScalar b[20], SkScalar out[20]) {
20     for (int j = 0; j < 4; ++j) {
21         for (int i = 0; i < 5; ++i) {
22             out[i+j*5] = 4 == i ? a[4+j*5] : 0;
23             for (int k = 0; k < 4; ++k)
24                 out[i+j*5] += SkScalarMul(a[k+j*5], b[i+k*5]);
25         }
26     }
27 }
28
29 // 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
31 // input components in [0..255].
32 // 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
34 // values of input components (i.e. 0 or 255).
35 // 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
37 // minimum value will be for R=0 if x>0 or R=255 if x<0.
38 // Same goes for all components.
39 bool component_needs_clamping(SkScalar row[5]) {
40     SkScalar maxValue = row[4] / 255;
41     SkScalar minValue = row[4] / 255;
42     for (int i = 0; i < 4; ++i) {
43         if (row[i] > 0)
44             maxValue += row[i];
45         else
46             minValue += row[i];
47     }
48     return (maxValue > 1) || (minValue < 0);
49 }
50
51 bool matrix_needs_clamping(SkScalar matrix[20]) {
52     return component_needs_clamping(matrix)
53         || component_needs_clamping(matrix+5)
54         || component_needs_clamping(matrix+10)
55         || component_needs_clamping(matrix+15);
56 }
57
58 };
59
60 SkColorFilterImageFilter* SkColorFilterImageFilter::Create(SkColorFilter* cf,
61         SkImageFilter* input, const CropRect* cropRect) {
62     SkASSERT(cf);
63     SkScalar colorMatrix[20], inputMatrix[20];
64     SkColorFilter* inputColorFilter;
65     if (input && cf->asColorMatrix(colorMatrix)
66               && input->asColorFilter(&inputColorFilter)
67               && (NULL != inputColorFilter)) {
68         SkAutoUnref autoUnref(inputColorFilter);
69         if (inputColorFilter->asColorMatrix(inputMatrix) && !matrix_needs_clamping(inputMatrix)) {
70             SkScalar combinedMatrix[20];
71             mult_color_matrix(colorMatrix, inputMatrix, combinedMatrix);
72             SkAutoTUnref<SkColorFilter> newCF(SkColorMatrixFilter::Create(combinedMatrix));
73             return SkNEW_ARGS(SkColorFilterImageFilter, (newCF, input->getInput(0), cropRect));
74         }
75     }
76     return SkNEW_ARGS(SkColorFilterImageFilter, (cf, input, cropRect));
77 }
78
79 SkColorFilterImageFilter::SkColorFilterImageFilter(SkColorFilter* cf,
80         SkImageFilter* input, const CropRect* cropRect)
81     : INHERITED(1, &input, cropRect), fColorFilter(cf) {
82     SkASSERT(cf);
83     SkSafeRef(cf);
84 }
85
86 SkColorFilterImageFilter::SkColorFilterImageFilter(SkReadBuffer& buffer)
87   : INHERITED(1, buffer) {
88     fColorFilter = buffer.readColorFilter();
89 }
90
91 void SkColorFilterImageFilter::flatten(SkWriteBuffer& buffer) const {
92     this->INHERITED::flatten(buffer);
93
94     buffer.writeFlattenable(fColorFilter);
95 }
96
97 SkColorFilterImageFilter::~SkColorFilterImageFilter() {
98     SkSafeUnref(fColorFilter);
99 }
100
101 bool SkColorFilterImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source,
102                                              const Context& ctx,
103                                              SkBitmap* result,
104                                              SkIPoint* offset) const {
105     SkBitmap src = source;
106     SkIPoint srcOffset = SkIPoint::Make(0, 0);
107     if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset)) {
108         return false;
109     }
110
111     SkIRect bounds;
112     if (!this->applyCropRect(ctx, src, srcOffset, &bounds)) {
113         return false;
114     }
115
116     SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
117     if (NULL == device.get()) {
118         return false;
119     }
120     SkCanvas canvas(device.get());
121     SkPaint paint;
122
123     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
124     paint.setColorFilter(fColorFilter);
125     canvas.drawSprite(src, srcOffset.fX - bounds.fLeft, srcOffset.fY - bounds.fTop, &paint);
126
127     *result = device.get()->accessBitmap(false);
128     offset->fX = bounds.fLeft;
129     offset->fY = bounds.fTop;
130     return true;
131 }
132
133 bool SkColorFilterImageFilter::asColorFilter(SkColorFilter** filter) const {
134     if (!cropRectIsSet()) {
135         if (filter) {
136             *filter = fColorFilter;
137             fColorFilter->ref();
138         }
139         return true;
140     }
141     return false;
142 }