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 "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(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 }
    143