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