Home | History | Annotate | Download | only in effects
      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