Home | History | Annotate | Download | only in filters
      1 /*
      2  * Copyright (C) 2011 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "platform/graphics/filters/FilterOperations.h"
     28 
     29 #include "platform/LengthFunctions.h"
     30 #include "platform/geometry/IntSize.h"
     31 #include "platform/graphics/filters/FEGaussianBlur.h"
     32 
     33 namespace WebCore {
     34 
     35 static inline IntSize outsetSizeForBlur(float stdDeviation)
     36 {
     37     unsigned kernelSizeX = 0;
     38     unsigned kernelSizeY = 0;
     39     FEGaussianBlur::calculateUnscaledKernelSize(kernelSizeX, kernelSizeY, stdDeviation, stdDeviation);
     40 
     41     IntSize outset;
     42     // We take the half kernel size and multiply it with three, because we run box blur three times.
     43     outset.setWidth(3 * kernelSizeX * 0.5f);
     44     outset.setHeight(3 * kernelSizeY * 0.5f);
     45 
     46     return outset;
     47 }
     48 
     49 FilterOperations::FilterOperations()
     50 {
     51 }
     52 
     53 FilterOperations& FilterOperations::operator=(const FilterOperations& other)
     54 {
     55     m_operations = other.m_operations;
     56     return *this;
     57 }
     58 
     59 bool FilterOperations::operator==(const FilterOperations& o) const
     60 {
     61     if (m_operations.size() != o.m_operations.size())
     62         return false;
     63 
     64     unsigned s = m_operations.size();
     65     for (unsigned i = 0; i < s; i++) {
     66         if (*m_operations[i] != *o.m_operations[i])
     67             return false;
     68     }
     69 
     70     return true;
     71 }
     72 
     73 bool FilterOperations::canInterpolateWith(const FilterOperations& other) const
     74 {
     75     for (size_t i = 0; i < operations().size(); ++i) {
     76         if (!FilterOperation::canInterpolate(operations()[i]->type()))
     77             return false;
     78     }
     79 
     80     for (size_t i = 0; i < other.operations().size(); ++i) {
     81         if (!FilterOperation::canInterpolate(other.operations()[i]->type()))
     82             return false;
     83     }
     84 
     85     size_t commonSize = std::min(operations().size(), other.operations().size());
     86     for (size_t i = 0; i < commonSize; ++i) {
     87         if (!operations()[i]->isSameType(*other.operations()[i]))
     88             return false;
     89     }
     90     return true;
     91 }
     92 
     93 bool FilterOperations::hasCustomFilter() const
     94 {
     95     for (size_t i = 0; i < m_operations.size(); ++i) {
     96         FilterOperation::OperationType type = m_operations.at(i)->type();
     97         if (type == FilterOperation::CUSTOM || type == FilterOperation::VALIDATED_CUSTOM)
     98             return true;
     99     }
    100     return false;
    101 }
    102 
    103 bool FilterOperations::hasReferenceFilter() const
    104 {
    105     for (size_t i = 0; i < m_operations.size(); ++i) {
    106         if (m_operations.at(i)->type() == FilterOperation::REFERENCE)
    107             return true;
    108     }
    109     return false;
    110 }
    111 
    112 bool FilterOperations::hasOutsets() const
    113 {
    114     for (size_t i = 0; i < m_operations.size(); ++i) {
    115         FilterOperation::OperationType operationType = m_operations.at(i)->type();
    116         if (operationType == FilterOperation::BLUR || operationType == FilterOperation::DROP_SHADOW || operationType == FilterOperation::REFERENCE)
    117             return true;
    118     }
    119     return false;
    120 }
    121 
    122 FilterOutsets FilterOperations::outsets() const
    123 {
    124     FilterOutsets totalOutsets;
    125     for (size_t i = 0; i < m_operations.size(); ++i) {
    126         FilterOperation* filterOperation = m_operations.at(i).get();
    127         switch (filterOperation->type()) {
    128         case FilterOperation::BLUR: {
    129             BlurFilterOperation* blurOperation = toBlurFilterOperation(filterOperation);
    130             float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0);
    131             IntSize outsetSize = outsetSizeForBlur(stdDeviation);
    132             FilterOutsets outsets(outsetSize.height(), outsetSize.width(), outsetSize.height(), outsetSize.width());
    133             totalOutsets += outsets;
    134             break;
    135         }
    136         case FilterOperation::DROP_SHADOW: {
    137             DropShadowFilterOperation* dropShadowOperation = toDropShadowFilterOperation(filterOperation);
    138             IntSize outsetSize = outsetSizeForBlur(dropShadowOperation->stdDeviation());
    139             FilterOutsets outsets(
    140                 std::max(0, outsetSize.height() - dropShadowOperation->y()),
    141                 std::max(0, outsetSize.width() + dropShadowOperation->x()),
    142                 std::max(0, outsetSize.height() + dropShadowOperation->y()),
    143                 std::max(0, outsetSize.width() - dropShadowOperation->x())
    144             );
    145             totalOutsets += outsets;
    146             break;
    147         }
    148         case FilterOperation::REFERENCE: {
    149             ReferenceFilterOperation* referenceOperation = toReferenceFilterOperation(filterOperation);
    150             if (referenceOperation->filter() && referenceOperation->filter()->lastEffect()) {
    151                 FloatRect outsetRect(0, 0, 1, 1);
    152                 outsetRect = referenceOperation->filter()->lastEffect()->mapRectRecursive(outsetRect);
    153                 FilterOutsets outsets(
    154                     std::max(0.0f, -outsetRect.y()),
    155                     std::max(0.0f, outsetRect.x() + outsetRect.width() - 1),
    156                     std::max(0.0f, outsetRect.y() + outsetRect.height() - 1),
    157                     std::max(0.0f, -outsetRect.x())
    158                 );
    159                 totalOutsets += outsets;
    160             }
    161             break;
    162         }
    163         case FilterOperation::CUSTOM:
    164         case FilterOperation::VALIDATED_CUSTOM: {
    165             // FIXME: Need to include the filter margins here.
    166             // https://bugs.webkit.org/show_bug.cgi?id=71400
    167             break;
    168         }
    169         default:
    170             break;
    171         }
    172     }
    173     return totalOutsets;
    174 }
    175 
    176 bool FilterOperations::hasFilterThatAffectsOpacity() const
    177 {
    178     for (size_t i = 0; i < m_operations.size(); ++i)
    179         if (m_operations[i]->affectsOpacity())
    180             return true;
    181     return false;
    182 }
    183 
    184 bool FilterOperations::hasFilterThatMovesPixels() const
    185 {
    186     for (size_t i = 0; i < m_operations.size(); ++i)
    187         if (m_operations[i]->movesPixels())
    188             return true;
    189     return false;
    190 }
    191 
    192 } // namespace WebCore
    193 
    194