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, uint32_t uniqueID) {
     62     SkASSERT(cf);
     63     SkScalar colorMatrix[20], inputMatrix[20];
     64     SkColorFilter* inputColorFilter;
     65     if (input && cf->asColorMatrix(colorMatrix)
     66               && input->asColorFilter(&inputColorFilter)
     67               && (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, 0));
     74         }
     75     }
     76     return SkNEW_ARGS(SkColorFilterImageFilter, (cf, input, cropRect, uniqueID));
     77 }
     78 
     79 SkColorFilterImageFilter::SkColorFilterImageFilter(SkColorFilter* cf,
     80         SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID)
     81     : INHERITED(1, &input, cropRect, uniqueID), fColorFilter(cf) {
     82     SkASSERT(cf);
     83     SkSafeRef(cf);
     84 }
     85 
     86 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
     87 SkColorFilterImageFilter::SkColorFilterImageFilter(SkReadBuffer& buffer)
     88   : INHERITED(1, buffer) {
     89     fColorFilter = buffer.readColorFilter();
     90 }
     91 #endif
     92 
     93 SkFlattenable* SkColorFilterImageFilter::CreateProc(SkReadBuffer& buffer) {
     94     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
     95     SkAutoTUnref<SkColorFilter> cf(buffer.readColorFilter());
     96     return Create(cf, common.getInput(0), &common.cropRect(), common.uniqueID());
     97 }
     98 
     99 void SkColorFilterImageFilter::flatten(SkWriteBuffer& buffer) const {
    100     this->INHERITED::flatten(buffer);
    101     buffer.writeFlattenable(fColorFilter);
    102 }
    103 
    104 SkColorFilterImageFilter::~SkColorFilterImageFilter() {
    105     SkSafeUnref(fColorFilter);
    106 }
    107 
    108 bool SkColorFilterImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source,
    109                                              const Context& ctx,
    110                                              SkBitmap* result,
    111                                              SkIPoint* offset) const {
    112     SkBitmap src = source;
    113     SkIPoint srcOffset = SkIPoint::Make(0, 0);
    114     if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset)) {
    115         return false;
    116     }
    117 
    118     SkIRect bounds;
    119     if (!this->applyCropRect(ctx, src, srcOffset, &bounds)) {
    120         return false;
    121     }
    122 
    123     SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
    124     if (NULL == device.get()) {
    125         return false;
    126     }
    127     SkCanvas canvas(device.get());
    128     SkPaint paint;
    129 
    130     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
    131     paint.setColorFilter(fColorFilter);
    132     canvas.drawSprite(src, srcOffset.fX - bounds.fLeft, srcOffset.fY - bounds.fTop, &paint);
    133 
    134     *result = device.get()->accessBitmap(false);
    135     offset->fX = bounds.fLeft;
    136     offset->fY = bounds.fTop;
    137     return true;
    138 }
    139 
    140 bool SkColorFilterImageFilter::asColorFilter(SkColorFilter** filter) const {
    141     if (!cropRectIsSet()) {
    142         if (filter) {
    143             *filter = fColorFilter;
    144             fColorFilter->ref();
    145         }
    146         return true;
    147     }
    148     return false;
    149 }
    150