SkColorFilterImageFilter.cpp revision 8d21f6c7a9d0cf4f87d77c235c6da7203620c7e5
144888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org/* 244888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org * Copyright 2012 The Android Open Source Project 344888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org * 444888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org * Use of this source code is governed by a BSD-style license that can be 544888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org * found in the LICENSE file. 644888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org */ 744888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org 844888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org#include "SkColorFilterImageFilter.h" 944888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org#include "SkBitmap.h" 1044888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org#include "SkCanvas.h" 118d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org#include "SkColorMatrixFilter.h" 1244888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org#include "SkDevice.h" 1344888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org#include "SkColorFilter.h" 1444888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org#include "SkFlattenableBuffers.h" 1544888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org 168d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.orgnamespace { 178d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org 188d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.orgvoid mult_color_matrix(SkScalar a[20], SkScalar b[20], SkScalar out[20]) { 198d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org for (int j = 0; j < 4; ++j) { 208d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org for (int i = 0; i < 5; ++i) { 218d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org out[i+j*5] = 4 == i ? a[4+j*5] : 0; 228d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org for (int k = 0; k < 4; ++k) 238d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org out[i+j*5] += SkScalarMul(a[k+j*5], b[i+k*5]); 248d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org } 258d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org } 268d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org} 278d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org 288d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org// To detect if we need to apply clamping after applying a matrix, we check if 298d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org// any output component might go outside of [0, 255] for any combination of 308d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org// input components in [0..255]. 318d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org// Each output component is an affine transformation of the input component, so 328d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org// the minimum and maximum values are for any combination of minimum or maximum 338d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org// values of input components (i.e. 0 or 255). 348d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org// E.g. if R' = x*R + y*G + z*B + w*A + t 358d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org// Then the maximum value will be for R=255 if x>0 or R=0 if x<0, and the 368d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org// minimum value will be for R=0 if x>0 or R=255 if x<0. 378d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org// Same goes for all components. 388d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.orgbool component_needs_clamping(SkScalar row[5]) { 398d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org SkScalar maxValue = row[4] / 255; 408d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org SkScalar minValue = row[4] / 255; 418d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org for (int i = 0; i < 4; ++i) { 428d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org if (row[i] > 0) 438d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org maxValue += row[i]; 448d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org else 458d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org minValue += row[i]; 468d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org } 478d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org return (maxValue > 1) || (minValue < 0); 488d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org} 498d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org 508d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.orgbool matrix_needs_clamping(SkScalar matrix[20]) { 518d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org return component_needs_clamping(matrix) 528d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org || component_needs_clamping(matrix+5) 538d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org || component_needs_clamping(matrix+10) 548d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org || component_needs_clamping(matrix+15); 558d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org} 568d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org 578d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org}; 588d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org 5944888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.orgSkColorFilterImageFilter::SkColorFilterImageFilter(SkColorFilter* cf, SkImageFilter* input) : INHERITED(input), fColorFilter(cf) { 608d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org SkASSERT(cf); 6144888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org SkSafeRef(cf); 6244888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org} 6344888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org 6444888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.orgSkColorFilterImageFilter::SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { 6544888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org fColorFilter = buffer.readFlattenableT<SkColorFilter>(); 6644888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org} 6744888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org 6844888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.orgvoid SkColorFilterImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { 6944888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org this->INHERITED::flatten(buffer); 70fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 7144888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org buffer.writeFlattenable(fColorFilter); 7244888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org} 7344888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org 7444888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.orgSkColorFilterImageFilter::~SkColorFilterImageFilter() { 7544888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org SkSafeUnref(fColorFilter); 7644888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org} 7744888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org 7844888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.orgbool SkColorFilterImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, 7944888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org const SkMatrix& matrix, 8044888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org SkBitmap* result, 8144888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org SkIPoint* loc) { 828d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org SkImageFilter* parent = getInput(0); 838d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org SkScalar colorMatrix[20]; 848d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org SkBitmap src; 858d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org SkColorFilter* cf; 868d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org if (parent && fColorFilter->asColorMatrix(colorMatrix)) { 878d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org SkColorFilter* parentColorFilter; 888d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org SkScalar parentMatrix[20]; 898d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org while (parent && (parentColorFilter = parent->asColorFilter()) 908d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org && parentColorFilter->asColorMatrix(parentMatrix) 918d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org && !matrix_needs_clamping(parentMatrix)) { 928d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org SkScalar combinedMatrix[20]; 938d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org mult_color_matrix(parentMatrix, colorMatrix, combinedMatrix); 948d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org memcpy(colorMatrix, combinedMatrix, 20 * sizeof(SkScalar)); 958d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org parent = parent->getInput(0); 968d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org } 978d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org if (!parent || !parent->filterImage(proxy, source, matrix, &src, loc)) { 988d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org src = source; 998d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org } 1008d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org cf = SkNEW_ARGS(SkColorMatrixFilter, (colorMatrix)); 1018d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org } else { 1028d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org src = this->getInputResult(proxy, source, matrix, loc); 1038d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org cf = fColorFilter; 1048d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org cf->ref(); 10544888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org } 10644888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org 10744888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org SkAutoTUnref<SkDevice> device(proxy->createDevice(src.width(), src.height())); 10844888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org SkCanvas canvas(device.get()); 10944888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org SkPaint paint; 11044888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org 11144888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org paint.setXfermodeMode(SkXfermode::kSrc_Mode); 1128d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org paint.setColorFilter(cf)->unref(); 11344888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org canvas.drawSprite(src, 0, 0, &paint); 11444888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org 11544888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org *result = device.get()->accessBitmap(false); 11644888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org return true; 11744888c66d4bf03da58eb9fbd3db92eb477141aabsenorblanco@chromium.org} 1188d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org 1198d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.orgSkColorFilter* SkColorFilterImageFilter::asColorFilter() const { 1208d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org return fColorFilter; 1218d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org} 122