Home | History | Annotate | Download | only in output
      1 // Copyright 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "cc/output/render_surface_filters.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "cc/output/filter_operation.h"
     10 #include "cc/output/filter_operations.h"
     11 #include "skia/ext/refptr.h"
     12 #include "third_party/skia/include/core/SkImageFilter.h"
     13 #include "third_party/skia/include/effects/SkAlphaThresholdFilter.h"
     14 #include "third_party/skia/include/effects/SkBlurImageFilter.h"
     15 #include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
     16 #include "third_party/skia/include/effects/SkColorMatrixFilter.h"
     17 #include "third_party/skia/include/effects/SkComposeImageFilter.h"
     18 #include "third_party/skia/include/effects/SkDropShadowImageFilter.h"
     19 #include "third_party/skia/include/effects/SkMagnifierImageFilter.h"
     20 #include "third_party/skia/include/effects/SkRectShaderImageFilter.h"
     21 #include "ui/gfx/geometry/size_f.h"
     22 
     23 namespace cc {
     24 
     25 namespace {
     26 
     27 void GetBrightnessMatrix(float amount, SkScalar matrix[20]) {
     28   // Spec implementation
     29   // (http://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#brightnessEquivalent)
     30   // <feFunc[R|G|B] type="linear" slope="[amount]">
     31   memset(matrix, 0, 20 * sizeof(SkScalar));
     32   matrix[0] = matrix[6] = matrix[12] = amount;
     33   matrix[18] = 1.f;
     34 }
     35 
     36 void GetSaturatingBrightnessMatrix(float amount, SkScalar matrix[20]) {
     37   // Legacy implementation used by internal clients.
     38   // <feFunc[R|G|B] type="linear" intercept="[amount]"/>
     39   memset(matrix, 0, 20 * sizeof(SkScalar));
     40   matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f;
     41   matrix[4] = matrix[9] = matrix[14] = amount * 255.f;
     42 }
     43 
     44 void GetContrastMatrix(float amount, SkScalar matrix[20]) {
     45   memset(matrix, 0, 20 * sizeof(SkScalar));
     46   matrix[0] = matrix[6] = matrix[12] = amount;
     47   matrix[4] = matrix[9] = matrix[14] = (-0.5f * amount + 0.5f) * 255.f;
     48   matrix[18] = 1.f;
     49 }
     50 
     51 void GetSaturateMatrix(float amount, SkScalar matrix[20]) {
     52   // Note, these values are computed to ensure MatrixNeedsClamping is false
     53   // for amount in [0..1]
     54   matrix[0] = 0.213f + 0.787f * amount;
     55   matrix[1] = 0.715f - 0.715f * amount;
     56   matrix[2] = 1.f - (matrix[0] + matrix[1]);
     57   matrix[3] = matrix[4] = 0.f;
     58   matrix[5] = 0.213f - 0.213f * amount;
     59   matrix[6] = 0.715f + 0.285f * amount;
     60   matrix[7] = 1.f - (matrix[5] + matrix[6]);
     61   matrix[8] = matrix[9] = 0.f;
     62   matrix[10] = 0.213f - 0.213f * amount;
     63   matrix[11] = 0.715f - 0.715f * amount;
     64   matrix[12] = 1.f - (matrix[10] + matrix[11]);
     65   matrix[13] = matrix[14] = 0.f;
     66   matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f;
     67   matrix[18] = 1.f;
     68 }
     69 
     70 void GetHueRotateMatrix(float hue, SkScalar matrix[20]) {
     71   const float kPi = 3.1415926535897932384626433832795f;
     72 
     73   float cos_hue = cosf(hue * kPi / 180.f);
     74   float sin_hue = sinf(hue * kPi / 180.f);
     75   matrix[0] = 0.213f + cos_hue * 0.787f - sin_hue * 0.213f;
     76   matrix[1] = 0.715f - cos_hue * 0.715f - sin_hue * 0.715f;
     77   matrix[2] = 0.072f - cos_hue * 0.072f + sin_hue * 0.928f;
     78   matrix[3] = matrix[4] = 0.f;
     79   matrix[5] = 0.213f - cos_hue * 0.213f + sin_hue * 0.143f;
     80   matrix[6] = 0.715f + cos_hue * 0.285f + sin_hue * 0.140f;
     81   matrix[7] = 0.072f - cos_hue * 0.072f - sin_hue * 0.283f;
     82   matrix[8] = matrix[9] = 0.f;
     83   matrix[10] = 0.213f - cos_hue * 0.213f - sin_hue * 0.787f;
     84   matrix[11] = 0.715f - cos_hue * 0.715f + sin_hue * 0.715f;
     85   matrix[12] = 0.072f + cos_hue * 0.928f + sin_hue * 0.072f;
     86   matrix[13] = matrix[14] = 0.f;
     87   matrix[15] = matrix[16] = matrix[17] = 0.f;
     88   matrix[18] = 1.f;
     89   matrix[19] = 0.f;
     90 }
     91 
     92 void GetInvertMatrix(float amount, SkScalar matrix[20]) {
     93   memset(matrix, 0, 20 * sizeof(SkScalar));
     94   matrix[0] = matrix[6] = matrix[12] = 1.f - 2.f * amount;
     95   matrix[4] = matrix[9] = matrix[14] = amount * 255.f;
     96   matrix[18] = 1.f;
     97 }
     98 
     99 void GetOpacityMatrix(float amount, SkScalar matrix[20]) {
    100   memset(matrix, 0, 20 * sizeof(SkScalar));
    101   matrix[0] = matrix[6] = matrix[12] = 1.f;
    102   matrix[18] = amount;
    103 }
    104 
    105 void GetGrayscaleMatrix(float amount, SkScalar matrix[20]) {
    106   // Note, these values are computed to ensure MatrixNeedsClamping is false
    107   // for amount in [0..1]
    108   matrix[0] = 0.2126f + 0.7874f * amount;
    109   matrix[1] = 0.7152f - 0.7152f * amount;
    110   matrix[2] = 1.f - (matrix[0] + matrix[1]);
    111   matrix[3] = matrix[4] = 0.f;
    112 
    113   matrix[5] = 0.2126f - 0.2126f * amount;
    114   matrix[6] = 0.7152f + 0.2848f * amount;
    115   matrix[7] = 1.f - (matrix[5] + matrix[6]);
    116   matrix[8] = matrix[9] = 0.f;
    117 
    118   matrix[10] = 0.2126f - 0.2126f * amount;
    119   matrix[11] = 0.7152f - 0.7152f * amount;
    120   matrix[12] = 1.f - (matrix[10] + matrix[11]);
    121   matrix[13] = matrix[14] = 0.f;
    122 
    123   matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f;
    124   matrix[18] = 1.f;
    125 }
    126 
    127 void GetSepiaMatrix(float amount, SkScalar matrix[20]) {
    128   matrix[0] = 0.393f + 0.607f * amount;
    129   matrix[1] = 0.769f - 0.769f * amount;
    130   matrix[2] = 0.189f - 0.189f * amount;
    131   matrix[3] = matrix[4] = 0.f;
    132 
    133   matrix[5] = 0.349f - 0.349f * amount;
    134   matrix[6] = 0.686f + 0.314f * amount;
    135   matrix[7] = 0.168f - 0.168f * amount;
    136   matrix[8] = matrix[9] = 0.f;
    137 
    138   matrix[10] = 0.272f - 0.272f * amount;
    139   matrix[11] = 0.534f - 0.534f * amount;
    140   matrix[12] = 0.131f + 0.869f * amount;
    141   matrix[13] = matrix[14] = 0.f;
    142 
    143   matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f;
    144   matrix[18] = 1.f;
    145 }
    146 
    147 skia::RefPtr<SkImageFilter> CreateMatrixImageFilter(
    148     const SkScalar matrix[20],
    149     const skia::RefPtr<SkImageFilter>& input) {
    150   skia::RefPtr<SkColorFilter> color_filter =
    151       skia::AdoptRef(SkColorMatrixFilter::Create(matrix));
    152   return skia::AdoptRef(
    153       SkColorFilterImageFilter::Create(color_filter.get(), input.get()));
    154 }
    155 
    156 }  // namespace
    157 
    158 skia::RefPtr<SkImageFilter> RenderSurfaceFilters::BuildImageFilter(
    159     const FilterOperations& filters,
    160     const gfx::SizeF& size) {
    161   skia::RefPtr<SkImageFilter> image_filter;
    162   SkScalar matrix[20];
    163   for (size_t i = 0; i < filters.size(); ++i) {
    164     const FilterOperation& op = filters.at(i);
    165     switch (op.type()) {
    166       case FilterOperation::GRAYSCALE:
    167         GetGrayscaleMatrix(1.f - op.amount(), matrix);
    168         image_filter = CreateMatrixImageFilter(matrix, image_filter);
    169         break;
    170       case FilterOperation::SEPIA:
    171         GetSepiaMatrix(1.f - op.amount(), matrix);
    172         image_filter = CreateMatrixImageFilter(matrix, image_filter);
    173         break;
    174       case FilterOperation::SATURATE:
    175         GetSaturateMatrix(op.amount(), matrix);
    176         image_filter = CreateMatrixImageFilter(matrix, image_filter);
    177         break;
    178       case FilterOperation::HUE_ROTATE:
    179         GetHueRotateMatrix(op.amount(), matrix);
    180         image_filter = CreateMatrixImageFilter(matrix, image_filter);
    181         break;
    182       case FilterOperation::INVERT:
    183         GetInvertMatrix(op.amount(), matrix);
    184         image_filter = CreateMatrixImageFilter(matrix, image_filter);
    185         break;
    186       case FilterOperation::OPACITY:
    187         GetOpacityMatrix(op.amount(), matrix);
    188         image_filter = CreateMatrixImageFilter(matrix, image_filter);
    189         break;
    190       case FilterOperation::BRIGHTNESS:
    191         GetBrightnessMatrix(op.amount(), matrix);
    192         image_filter = CreateMatrixImageFilter(matrix, image_filter);
    193         break;
    194       case FilterOperation::CONTRAST:
    195         GetContrastMatrix(op.amount(), matrix);
    196         image_filter = CreateMatrixImageFilter(matrix, image_filter);
    197         break;
    198       case FilterOperation::BLUR:
    199         image_filter = skia::AdoptRef(SkBlurImageFilter::Create(
    200             op.amount(), op.amount(), image_filter.get()));
    201         break;
    202       case FilterOperation::DROP_SHADOW:
    203         image_filter = skia::AdoptRef(SkDropShadowImageFilter::Create(
    204             SkIntToScalar(op.drop_shadow_offset().x()),
    205             SkIntToScalar(op.drop_shadow_offset().y()),
    206             SkIntToScalar(op.amount()),
    207             SkIntToScalar(op.amount()),
    208             op.drop_shadow_color(),
    209             image_filter.get()));
    210         break;
    211       case FilterOperation::COLOR_MATRIX:
    212         image_filter = CreateMatrixImageFilter(op.matrix(), image_filter);
    213         break;
    214       case FilterOperation::ZOOM: {
    215         skia::RefPtr<SkImageFilter> zoom_filter =
    216             skia::AdoptRef(SkMagnifierImageFilter::Create(
    217                 SkRect::MakeXYWH(
    218                     (size.width() - (size.width() / op.amount())) / 2.f,
    219                     (size.height() - (size.height() / op.amount())) / 2.f,
    220                     size.width() / op.amount(),
    221                     size.height() / op.amount()),
    222                 op.zoom_inset()));
    223         if (image_filter.get()) {
    224           // TODO(ajuma): When there's a 1-input version of
    225           // SkMagnifierImageFilter, use that to handle the input filter
    226           // instead of using an SkComposeImageFilter.
    227           image_filter = skia::AdoptRef(SkComposeImageFilter::Create(
    228               zoom_filter.get(), image_filter.get()));
    229         } else {
    230           image_filter = zoom_filter;
    231         }
    232         break;
    233       }
    234       case FilterOperation::SATURATING_BRIGHTNESS:
    235         GetSaturatingBrightnessMatrix(op.amount(), matrix);
    236         image_filter = CreateMatrixImageFilter(matrix, image_filter);
    237         break;
    238       case FilterOperation::REFERENCE: {
    239         if (!op.image_filter())
    240           break;
    241 
    242         skia::RefPtr<SkColorFilter> cf;
    243 
    244         {
    245           SkColorFilter* colorfilter_rawptr = NULL;
    246           op.image_filter()->asColorFilter(&colorfilter_rawptr);
    247           cf = skia::AdoptRef(colorfilter_rawptr);
    248         }
    249 
    250         if (cf && cf->asColorMatrix(matrix) &&
    251             !op.image_filter()->getInput(0)) {
    252           image_filter = CreateMatrixImageFilter(matrix, image_filter);
    253         } else if (image_filter) {
    254           image_filter = skia::AdoptRef(SkComposeImageFilter::Create(
    255               op.image_filter().get(), image_filter.get()));
    256         } else {
    257           image_filter = op.image_filter();
    258         }
    259         break;
    260       }
    261       case FilterOperation::ALPHA_THRESHOLD: {
    262         skia::RefPtr<SkImageFilter> alpha_filter = skia::AdoptRef(
    263             SkAlphaThresholdFilter::Create(
    264                 op.region(), op.amount(), op.outer_threshold()));
    265         if (image_filter.get()) {
    266           image_filter = skia::AdoptRef(SkComposeImageFilter::Create(
    267               alpha_filter.get(), image_filter.get()));
    268         } else {
    269           image_filter = alpha_filter;
    270         }
    271         break;
    272       }
    273     }
    274   }
    275   return image_filter;
    276 }
    277 
    278 }  // namespace cc
    279