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 <cmath>
      6 
      7 #include "cc/output/filter_operations.h"
      8 
      9 #include "base/values.h"
     10 #include "cc/output/filter_operation.h"
     11 
     12 namespace cc {
     13 
     14 FilterOperations::FilterOperations() {}
     15 
     16 FilterOperations::FilterOperations(const FilterOperations& other)
     17     : operations_(other.operations_) {}
     18 
     19 FilterOperations::~FilterOperations() {}
     20 
     21 FilterOperations& FilterOperations::operator=(const FilterOperations& other) {
     22   operations_ = other.operations_;
     23   return *this;
     24 }
     25 
     26 bool FilterOperations::operator==(const FilterOperations& other) const {
     27   if (other.size() != size())
     28     return false;
     29   for (size_t i = 0; i < size(); ++i) {
     30     if (other.at(i) != at(i))
     31       return false;
     32   }
     33   return true;
     34 }
     35 
     36 void FilterOperations::Append(const FilterOperation& filter) {
     37   operations_.push_back(filter);
     38 }
     39 
     40 void FilterOperations::Clear() {
     41   operations_.clear();
     42 }
     43 
     44 bool FilterOperations::IsEmpty() const {
     45   return operations_.empty();
     46 }
     47 
     48 static int SpreadForStdDeviation(float std_deviation) {
     49   // https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#feGaussianBlurElement
     50   // provides this approximation for evaluating a gaussian blur by a triple box
     51   // filter.
     52   float d = floorf(std_deviation * 3.f * sqrt(8.f * atan(1.f)) / 4.f + 0.5f);
     53   return static_cast<int>(ceilf(d * 3.f / 2.f));
     54 }
     55 
     56 void FilterOperations::GetOutsets(int* top,
     57                                   int* right,
     58                                   int* bottom,
     59                                   int* left) const {
     60   *top = *right = *bottom = *left = 0;
     61   for (size_t i = 0; i < operations_.size(); ++i) {
     62     const FilterOperation& op = operations_[i];
     63     // TODO(ajuma): Add support for reference filters once SkImageFilter
     64     // reports its outsets.
     65     DCHECK(op.type() != FilterOperation::REFERENCE);
     66     if (op.type() == FilterOperation::BLUR ||
     67         op.type() == FilterOperation::DROP_SHADOW) {
     68       int spread = SpreadForStdDeviation(op.amount());
     69       if (op.type() == FilterOperation::BLUR) {
     70         *top += spread;
     71         *right += spread;
     72         *bottom += spread;
     73         *left += spread;
     74       } else {
     75         *top += spread - op.drop_shadow_offset().y();
     76         *right += spread + op.drop_shadow_offset().x();
     77         *bottom += spread + op.drop_shadow_offset().y();
     78         *left += spread - op.drop_shadow_offset().x();
     79       }
     80     }
     81   }
     82 }
     83 
     84 bool FilterOperations::HasFilterThatMovesPixels() const {
     85   for (size_t i = 0; i < operations_.size(); ++i) {
     86     const FilterOperation& op = operations_[i];
     87     // TODO(ajuma): Once SkImageFilter reports its outsets, use those here to
     88     // determine whether a reference filter really moves pixels.
     89     switch (op.type()) {
     90       case FilterOperation::BLUR:
     91       case FilterOperation::DROP_SHADOW:
     92       case FilterOperation::ZOOM:
     93       case FilterOperation::REFERENCE:
     94         return true;
     95       case FilterOperation::OPACITY:
     96       case FilterOperation::COLOR_MATRIX:
     97       case FilterOperation::GRAYSCALE:
     98       case FilterOperation::SEPIA:
     99       case FilterOperation::SATURATE:
    100       case FilterOperation::HUE_ROTATE:
    101       case FilterOperation::INVERT:
    102       case FilterOperation::BRIGHTNESS:
    103       case FilterOperation::CONTRAST:
    104       case FilterOperation::SATURATING_BRIGHTNESS:
    105         break;
    106     }
    107   }
    108   return false;
    109 }
    110 
    111 bool FilterOperations::HasFilterThatAffectsOpacity() const {
    112   for (size_t i = 0; i < operations_.size(); ++i) {
    113     const FilterOperation& op = operations_[i];
    114     // TODO(ajuma): Make this smarter for reference filters. Once SkImageFilter
    115     // can report affectsOpacity(), call that.
    116     switch (op.type()) {
    117       case FilterOperation::OPACITY:
    118       case FilterOperation::BLUR:
    119       case FilterOperation::DROP_SHADOW:
    120       case FilterOperation::ZOOM:
    121       case FilterOperation::REFERENCE:
    122         return true;
    123       case FilterOperation::COLOR_MATRIX: {
    124         const SkScalar* matrix = op.matrix();
    125         if (matrix[15] ||
    126             matrix[16] ||
    127             matrix[17] ||
    128             matrix[18] != 1 ||
    129             matrix[19])
    130           return true;
    131         break;
    132       }
    133       case FilterOperation::GRAYSCALE:
    134       case FilterOperation::SEPIA:
    135       case FilterOperation::SATURATE:
    136       case FilterOperation::HUE_ROTATE:
    137       case FilterOperation::INVERT:
    138       case FilterOperation::BRIGHTNESS:
    139       case FilterOperation::CONTRAST:
    140       case FilterOperation::SATURATING_BRIGHTNESS:
    141         break;
    142     }
    143   }
    144   return false;
    145 }
    146 
    147 bool FilterOperations::HasReferenceFilter() const {
    148   for (size_t i = 0; i < operations_.size(); ++i) {
    149     if (operations_[i].type() == FilterOperation::REFERENCE)
    150       return true;
    151   }
    152   return false;
    153 }
    154 
    155 FilterOperations FilterOperations::Blend(const FilterOperations& from,
    156                                          double progress) const {
    157   if (HasReferenceFilter() || from.HasReferenceFilter())
    158     return *this;
    159 
    160   bool from_is_longer = from.size() > size();
    161 
    162   size_t shorter_size, longer_size;
    163   if (size() == from.size()) {
    164     shorter_size = longer_size = size();
    165   } else if  (from_is_longer) {
    166     longer_size = from.size();
    167     shorter_size = size();
    168   } else {
    169     longer_size = size();
    170     shorter_size = from.size();
    171   }
    172 
    173   for (size_t i = 0; i < shorter_size; i++) {
    174     if (from.at(i).type() != at(i).type())
    175       return *this;
    176   }
    177 
    178   FilterOperations blended_filters;
    179   for (size_t i = 0; i < shorter_size; i++) {
    180     blended_filters.Append(
    181         FilterOperation::Blend(&from.at(i), &at(i), progress));
    182   }
    183 
    184   if (from_is_longer) {
    185     for (size_t i = shorter_size; i < longer_size; i++) {
    186       blended_filters.Append(
    187           FilterOperation::Blend(&from.at(i), NULL, progress));
    188     }
    189   } else {
    190     for (size_t i = shorter_size; i < longer_size; i++)
    191       blended_filters.Append(FilterOperation::Blend(NULL, &at(i), progress));
    192   }
    193 
    194   return blended_filters;
    195 }
    196 
    197 scoped_ptr<base::Value> FilterOperations::AsValue() const {
    198   scoped_ptr<base::ListValue> value(new ListValue);
    199   for (size_t i = 0; i < operations_.size(); ++i)
    200     value->Append(operations_[i].AsValue().release());
    201   return value.PassAs<base::Value>();
    202 }
    203 
    204 }  // namespace cc
    205