Home | History | Annotate | Download | only in output
      1 // Copyright 2013 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 <algorithm>
      6 
      7 #include "base/values.h"
      8 #include "cc/base/math_util.h"
      9 #include "cc/output/filter_operation.h"
     10 #include "third_party/skia/include/core/SkMath.h"
     11 #include "ui/gfx/animation/tween.h"
     12 
     13 namespace cc {
     14 
     15 bool FilterOperation::operator==(const FilterOperation& other) const {
     16   if (type_ != other.type_)
     17     return false;
     18   if (type_ == COLOR_MATRIX)
     19     return !memcmp(matrix_, other.matrix_, sizeof(matrix_));
     20   if (type_ == DROP_SHADOW) {
     21     return amount_ == other.amount_ &&
     22            drop_shadow_offset_ == other.drop_shadow_offset_ &&
     23            drop_shadow_color_ == other.drop_shadow_color_;
     24   }
     25   if (type_ == REFERENCE)
     26     return image_filter_.get() == other.image_filter_.get();
     27   if (type_ == ALPHA_THRESHOLD) {
     28     return region_ == other.region_ &&
     29         amount_ == other.amount_ &&
     30         outer_threshold_ == other.outer_threshold_;
     31   }
     32   return amount_ == other.amount_;
     33 }
     34 
     35 FilterOperation::FilterOperation(FilterType type, float amount)
     36     : type_(type),
     37       amount_(amount),
     38       outer_threshold_(0),
     39       drop_shadow_offset_(0, 0),
     40       drop_shadow_color_(0),
     41       zoom_inset_(0) {
     42   DCHECK_NE(type_, DROP_SHADOW);
     43   DCHECK_NE(type_, COLOR_MATRIX);
     44   DCHECK_NE(type_, REFERENCE);
     45   memset(matrix_, 0, sizeof(matrix_));
     46 }
     47 
     48 FilterOperation::FilterOperation(FilterType type,
     49                                  const gfx::Point& offset,
     50                                  float stdDeviation,
     51                                  SkColor color)
     52     : type_(type),
     53       amount_(stdDeviation),
     54       outer_threshold_(0),
     55       drop_shadow_offset_(offset),
     56       drop_shadow_color_(color),
     57       zoom_inset_(0) {
     58   DCHECK_EQ(type_, DROP_SHADOW);
     59   memset(matrix_, 0, sizeof(matrix_));
     60 }
     61 
     62 FilterOperation::FilterOperation(FilterType type, SkScalar matrix[20])
     63     : type_(type),
     64       amount_(0),
     65       outer_threshold_(0),
     66       drop_shadow_offset_(0, 0),
     67       drop_shadow_color_(0),
     68       zoom_inset_(0) {
     69   DCHECK_EQ(type_, COLOR_MATRIX);
     70   memcpy(matrix_, matrix, sizeof(matrix_));
     71 }
     72 
     73 FilterOperation::FilterOperation(FilterType type, float amount, int inset)
     74     : type_(type),
     75       amount_(amount),
     76       outer_threshold_(0),
     77       drop_shadow_offset_(0, 0),
     78       drop_shadow_color_(0),
     79       zoom_inset_(inset) {
     80   DCHECK_EQ(type_, ZOOM);
     81   memset(matrix_, 0, sizeof(matrix_));
     82 }
     83 
     84 FilterOperation::FilterOperation(
     85     FilterType type,
     86     const skia::RefPtr<SkImageFilter>& image_filter)
     87     : type_(type),
     88       amount_(0),
     89       outer_threshold_(0),
     90       drop_shadow_offset_(0, 0),
     91       drop_shadow_color_(0),
     92       image_filter_(image_filter),
     93       zoom_inset_(0) {
     94   DCHECK_EQ(type_, REFERENCE);
     95   memset(matrix_, 0, sizeof(matrix_));
     96 }
     97 
     98 FilterOperation::FilterOperation(FilterType type,
     99                                  const SkRegion& region,
    100                                  float inner_threshold,
    101                                  float outer_threshold)
    102     : type_(type),
    103       amount_(inner_threshold),
    104       outer_threshold_(outer_threshold),
    105       drop_shadow_offset_(0, 0),
    106       drop_shadow_color_(0),
    107       zoom_inset_(0),
    108       region_(region) {
    109   DCHECK_EQ(type_, ALPHA_THRESHOLD);
    110   memset(matrix_, 0, sizeof(matrix_));
    111 }
    112 
    113 FilterOperation::FilterOperation(const FilterOperation& other)
    114     : type_(other.type_),
    115       amount_(other.amount_),
    116       outer_threshold_(other.outer_threshold_),
    117       drop_shadow_offset_(other.drop_shadow_offset_),
    118       drop_shadow_color_(other.drop_shadow_color_),
    119       image_filter_(other.image_filter_),
    120       zoom_inset_(other.zoom_inset_),
    121       region_(other.region_) {
    122   memcpy(matrix_, other.matrix_, sizeof(matrix_));
    123 }
    124 
    125 FilterOperation::~FilterOperation() {
    126 }
    127 
    128 static FilterOperation CreateNoOpFilter(FilterOperation::FilterType type) {
    129   switch (type) {
    130     case FilterOperation::GRAYSCALE:
    131       return FilterOperation::CreateGrayscaleFilter(0.f);
    132     case FilterOperation::SEPIA:
    133       return FilterOperation::CreateSepiaFilter(0.f);
    134     case FilterOperation::SATURATE:
    135       return FilterOperation::CreateSaturateFilter(1.f);
    136     case FilterOperation::HUE_ROTATE:
    137       return FilterOperation::CreateHueRotateFilter(0.f);
    138     case FilterOperation::INVERT:
    139       return FilterOperation::CreateInvertFilter(0.f);
    140     case FilterOperation::BRIGHTNESS:
    141       return FilterOperation::CreateBrightnessFilter(1.f);
    142     case FilterOperation::CONTRAST:
    143       return FilterOperation::CreateContrastFilter(1.f);
    144     case FilterOperation::OPACITY:
    145       return FilterOperation::CreateOpacityFilter(1.f);
    146     case FilterOperation::BLUR:
    147       return FilterOperation::CreateBlurFilter(0.f);
    148     case FilterOperation::DROP_SHADOW:
    149       return FilterOperation::CreateDropShadowFilter(
    150           gfx::Point(0, 0), 0.f, SK_ColorTRANSPARENT);
    151     case FilterOperation::COLOR_MATRIX: {
    152       SkScalar matrix[20];
    153       memset(matrix, 0, 20 * sizeof(SkScalar));
    154       matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f;
    155       return FilterOperation::CreateColorMatrixFilter(matrix);
    156     }
    157     case FilterOperation::ZOOM:
    158       return FilterOperation::CreateZoomFilter(1.f, 0);
    159     case FilterOperation::SATURATING_BRIGHTNESS:
    160       return FilterOperation::CreateSaturatingBrightnessFilter(0.f);
    161     case FilterOperation::REFERENCE:
    162       return FilterOperation::CreateReferenceFilter(
    163           skia::RefPtr<SkImageFilter>());
    164     case FilterOperation::ALPHA_THRESHOLD:
    165       return FilterOperation::CreateAlphaThresholdFilter(SkRegion(), 1.f, 0.f);
    166   }
    167   NOTREACHED();
    168   return FilterOperation::CreateEmptyFilter();
    169 }
    170 
    171 static float ClampAmountForFilterType(float amount,
    172                                       FilterOperation::FilterType type) {
    173   switch (type) {
    174     case FilterOperation::GRAYSCALE:
    175     case FilterOperation::SEPIA:
    176     case FilterOperation::INVERT:
    177     case FilterOperation::OPACITY:
    178     case FilterOperation::ALPHA_THRESHOLD:
    179       return MathUtil::ClampToRange(amount, 0.f, 1.f);
    180     case FilterOperation::SATURATE:
    181     case FilterOperation::BRIGHTNESS:
    182     case FilterOperation::CONTRAST:
    183     case FilterOperation::BLUR:
    184     case FilterOperation::DROP_SHADOW:
    185       return std::max(amount, 0.f);
    186     case FilterOperation::ZOOM:
    187       return std::max(amount, 1.f);
    188     case FilterOperation::HUE_ROTATE:
    189     case FilterOperation::SATURATING_BRIGHTNESS:
    190       return amount;
    191     case FilterOperation::COLOR_MATRIX:
    192     case FilterOperation::REFERENCE:
    193       NOTREACHED();
    194       return amount;
    195   }
    196   NOTREACHED();
    197   return amount;
    198 }
    199 
    200 // static
    201 FilterOperation FilterOperation::Blend(const FilterOperation* from,
    202                                        const FilterOperation* to,
    203                                        double progress) {
    204   FilterOperation blended_filter = FilterOperation::CreateEmptyFilter();
    205 
    206   if (!from && !to)
    207     return blended_filter;
    208 
    209   const FilterOperation& from_op = from ? *from : CreateNoOpFilter(to->type());
    210   const FilterOperation& to_op = to ? *to : CreateNoOpFilter(from->type());
    211 
    212   if (from_op.type() != to_op.type())
    213     return blended_filter;
    214 
    215   DCHECK(to_op.type() != FilterOperation::COLOR_MATRIX);
    216   blended_filter.set_type(to_op.type());
    217 
    218   if (to_op.type() == FilterOperation::REFERENCE) {
    219     if (progress > 0.5)
    220       blended_filter.set_image_filter(to_op.image_filter());
    221     else
    222       blended_filter.set_image_filter(from_op.image_filter());
    223     return blended_filter;
    224   }
    225 
    226   blended_filter.set_amount(ClampAmountForFilterType(
    227       gfx::Tween::FloatValueBetween(progress, from_op.amount(), to_op.amount()),
    228       to_op.type()));
    229 
    230   if (to_op.type() == FilterOperation::DROP_SHADOW) {
    231     gfx::Point blended_offset(
    232         gfx::Tween::LinearIntValueBetween(progress,
    233                                           from_op.drop_shadow_offset().x(),
    234                                           to_op.drop_shadow_offset().x()),
    235         gfx::Tween::LinearIntValueBetween(progress,
    236                                           from_op.drop_shadow_offset().y(),
    237                                           to_op.drop_shadow_offset().y()));
    238     blended_filter.set_drop_shadow_offset(blended_offset);
    239     blended_filter.set_drop_shadow_color(gfx::Tween::ColorValueBetween(
    240         progress, from_op.drop_shadow_color(), to_op.drop_shadow_color()));
    241   } else if (to_op.type() == FilterOperation::ZOOM) {
    242     blended_filter.set_zoom_inset(
    243         std::max(gfx::Tween::LinearIntValueBetween(
    244                      from_op.zoom_inset(), to_op.zoom_inset(), progress),
    245                  0));
    246   } else if (to_op.type() == FilterOperation::ALPHA_THRESHOLD) {
    247     blended_filter.set_outer_threshold(ClampAmountForFilterType(
    248             gfx::Tween::FloatValueBetween(progress,
    249                                           from_op.outer_threshold(),
    250                                           to_op.outer_threshold()),
    251             to_op.type()));
    252     blended_filter.set_region(to_op.region());
    253   }
    254 
    255   return blended_filter;
    256 }
    257 
    258 scoped_ptr<base::Value> FilterOperation::AsValue() const {
    259   scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue);
    260   value->SetInteger("type", type_);
    261   switch (type_) {
    262     case FilterOperation::GRAYSCALE:
    263     case FilterOperation::SEPIA:
    264     case FilterOperation::SATURATE:
    265     case FilterOperation::HUE_ROTATE:
    266     case FilterOperation::INVERT:
    267     case FilterOperation::BRIGHTNESS:
    268     case FilterOperation::CONTRAST:
    269     case FilterOperation::OPACITY:
    270     case FilterOperation::BLUR:
    271     case FilterOperation::SATURATING_BRIGHTNESS:
    272       value->SetDouble("amount", amount_);
    273       break;
    274     case FilterOperation::DROP_SHADOW:
    275       value->SetDouble("std_deviation", amount_);
    276       value->Set("offset", MathUtil::AsValue(drop_shadow_offset_).release());
    277       value->SetInteger("color", drop_shadow_color_);
    278       break;
    279     case FilterOperation::COLOR_MATRIX: {
    280       scoped_ptr<base::ListValue> matrix(new base::ListValue);
    281       for (size_t i = 0; i < arraysize(matrix_); ++i)
    282         matrix->AppendDouble(matrix_[i]);
    283       value->Set("matrix", matrix.release());
    284       break;
    285     }
    286     case FilterOperation::ZOOM:
    287       value->SetDouble("amount", amount_);
    288       value->SetDouble("inset", zoom_inset_);
    289       break;
    290     case FilterOperation::REFERENCE: {
    291       int count_inputs = 0;
    292       bool can_filter_image_gpu = false;
    293       if (image_filter_) {
    294         count_inputs = image_filter_->countInputs();
    295         can_filter_image_gpu = image_filter_->canFilterImageGPU();
    296       }
    297       value->SetBoolean("is_null", !image_filter_);
    298       value->SetInteger("count_inputs", count_inputs);
    299       value->SetBoolean("can_filter_image_gpu", can_filter_image_gpu);
    300       break;
    301     }
    302     case FilterOperation::ALPHA_THRESHOLD: {
    303         value->SetDouble("inner_threshold", amount_);
    304         value->SetDouble("outer_threshold", outer_threshold_);
    305         scoped_ptr<base::ListValue> region_value(new base::ListValue());
    306         for (SkRegion::Iterator it(region_); !it.done(); it.next()) {
    307           region_value->AppendInteger(it.rect().x());
    308           region_value->AppendInteger(it.rect().y());
    309           region_value->AppendInteger(it.rect().width());
    310           region_value->AppendInteger(it.rect().height());
    311         }
    312         value->Set("region", region_value.release());
    313       }
    314       break;
    315   }
    316   return value.PassAs<base::Value>();
    317 }
    318 
    319 }  // namespace cc
    320