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
33namespace blink {
34
35static inline IntSize outsetSizeForBlur(float stdDeviation)
36{
37    IntSize kernelSize = FEGaussianBlur::calculateUnscaledKernelSize(FloatPoint(stdDeviation, stdDeviation));
38
39    IntSize outset;
40    // We take the half kernel size and multiply it with three, because we run box blur three times.
41    outset.setWidth(3 * kernelSize.width() * 0.5f);
42    outset.setHeight(3 * kernelSize.height() * 0.5f);
43
44    return outset;
45}
46
47FilterOperations::FilterOperations()
48{
49}
50
51FilterOperations& FilterOperations::operator=(const FilterOperations& other)
52{
53    m_operations = other.m_operations;
54    return *this;
55}
56
57bool FilterOperations::operator==(const FilterOperations& o) const
58{
59    if (m_operations.size() != o.m_operations.size())
60        return false;
61
62    unsigned s = m_operations.size();
63    for (unsigned i = 0; i < s; i++) {
64        if (*m_operations[i] != *o.m_operations[i])
65            return false;
66    }
67
68    return true;
69}
70
71bool FilterOperations::canInterpolateWith(const FilterOperations& other) const
72{
73    for (size_t i = 0; i < operations().size(); ++i) {
74        if (!FilterOperation::canInterpolate(operations()[i]->type()))
75            return false;
76    }
77
78    for (size_t i = 0; i < other.operations().size(); ++i) {
79        if (!FilterOperation::canInterpolate(other.operations()[i]->type()))
80            return false;
81    }
82
83    size_t commonSize = std::min(operations().size(), other.operations().size());
84    for (size_t i = 0; i < commonSize; ++i) {
85        if (!operations()[i]->isSameType(*other.operations()[i]))
86            return false;
87    }
88    return true;
89}
90
91bool FilterOperations::hasReferenceFilter() const
92{
93    for (size_t i = 0; i < m_operations.size(); ++i) {
94        if (m_operations.at(i)->type() == FilterOperation::REFERENCE)
95            return true;
96    }
97    return false;
98}
99
100bool FilterOperations::hasOutsets() const
101{
102    for (size_t i = 0; i < m_operations.size(); ++i) {
103        FilterOperation::OperationType operationType = m_operations.at(i)->type();
104        if (operationType == FilterOperation::BLUR || operationType == FilterOperation::DROP_SHADOW || operationType == FilterOperation::REFERENCE)
105            return true;
106    }
107    return false;
108}
109
110FilterOutsets FilterOperations::outsets() const
111{
112    FilterOutsets totalOutsets;
113    for (size_t i = 0; i < m_operations.size(); ++i) {
114        FilterOperation* filterOperation = m_operations.at(i).get();
115        switch (filterOperation->type()) {
116        case FilterOperation::BLUR: {
117            BlurFilterOperation* blurOperation = toBlurFilterOperation(filterOperation);
118            float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0);
119            IntSize outsetSize = outsetSizeForBlur(stdDeviation);
120            FilterOutsets outsets(outsetSize.height(), outsetSize.width(), outsetSize.height(), outsetSize.width());
121            totalOutsets += outsets;
122            break;
123        }
124        case FilterOperation::DROP_SHADOW: {
125            DropShadowFilterOperation* dropShadowOperation = toDropShadowFilterOperation(filterOperation);
126            IntSize outsetSize = outsetSizeForBlur(dropShadowOperation->stdDeviation());
127            FilterOutsets outsets(
128                std::max(0, outsetSize.height() - dropShadowOperation->y()),
129                std::max(0, outsetSize.width() + dropShadowOperation->x()),
130                std::max(0, outsetSize.height() + dropShadowOperation->y()),
131                std::max(0, outsetSize.width() - dropShadowOperation->x())
132            );
133            totalOutsets += outsets;
134            break;
135        }
136        case FilterOperation::REFERENCE: {
137            ReferenceFilterOperation* referenceOperation = toReferenceFilterOperation(filterOperation);
138            if (referenceOperation->filter() && referenceOperation->filter()->lastEffect()) {
139                FloatRect outsetRect(0, 0, 1, 1);
140                outsetRect = referenceOperation->filter()->lastEffect()->mapRectRecursive(outsetRect);
141                FilterOutsets outsets(
142                    std::max(0.0f, -outsetRect.y()),
143                    std::max(0.0f, outsetRect.x() + outsetRect.width() - 1),
144                    std::max(0.0f, outsetRect.y() + outsetRect.height() - 1),
145                    std::max(0.0f, -outsetRect.x())
146                );
147                totalOutsets += outsets;
148            }
149            break;
150        }
151        default:
152            break;
153        }
154    }
155    return totalOutsets;
156}
157
158bool FilterOperations::hasFilterThatAffectsOpacity() const
159{
160    for (size_t i = 0; i < m_operations.size(); ++i)
161        if (m_operations[i]->affectsOpacity())
162            return true;
163    return false;
164}
165
166bool FilterOperations::hasFilterThatMovesPixels() const
167{
168    for (size_t i = 0; i < m_operations.size(); ++i)
169        if (m_operations[i]->movesPixels())
170            return true;
171    return false;
172}
173
174} // namespace blink
175
176