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