Filters need to affect visual overflow
[WebKit-https.git] / Source / WebCore / platform / graphics / filters / FilterOperations.cpp
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 "FilterOperations.h"
28
29 #include "FEGaussianBlur.h"
30 #include "IntSize.h"
31
32 #if ENABLE(CSS_FILTERS)
33
34 namespace WebCore {
35
36 static inline IntSize outsetSizeForBlur(float stdX, float stdY)
37 {
38     unsigned kernelSizeX = 0;
39     unsigned kernelSizeY = 0;
40     FEGaussianBlur::calculateUnscaledKernelSize(kernelSizeX, kernelSizeY, stdX, stdY);
41
42     IntSize outset;
43     // We take the half kernel size and multiply it with three, because we run box blur three times.
44     outset.setWidth(3 * kernelSizeX * 0.5f);
45     outset.setHeight(3 * kernelSizeY * 0.5f);
46
47     return outset;
48 }
49
50 FilterOperations::FilterOperations()
51 {
52 }
53
54 bool FilterOperations::operator==(const FilterOperations& o) const
55 {
56     if (m_operations.size() != o.m_operations.size())
57         return false;
58         
59     unsigned s = m_operations.size();
60     for (unsigned i = 0; i < s; i++) {
61         if (*m_operations[i] != *o.m_operations[i])
62             return false;
63     }
64     
65     return true;
66 }
67
68 bool FilterOperations::operationsMatch(const FilterOperations& other) const
69 {
70     size_t numOperations = operations().size();
71     // If the sizes of the function lists don't match, the lists don't match
72     if (numOperations != other.operations().size())
73         return false;
74     
75     // If the types of each function are not the same, the lists don't match
76     for (size_t i = 0; i < numOperations; ++i) {
77         if (!operations()[i]->isSameType(*other.operations()[i]))
78             return false;
79     }
80     return true;
81 }
82
83 bool FilterOperations::hasOutsets() const
84 {
85     for (size_t i = 0; i < m_operations.size(); ++i) {
86         FilterOperation::OperationType operationType = m_operations.at(i).get()->getOperationType();
87         if (operationType == FilterOperation::BLUR || operationType == FilterOperation::DROP_SHADOW)
88             return true;
89     }
90     return false;
91 }
92
93 void FilterOperations::getOutsets(LayoutUnit& top, LayoutUnit& right, LayoutUnit& bottom, LayoutUnit& left, const LayoutSize& borderBoxSize) const
94 {
95     top = 0;
96     right = 0;
97     bottom = 0;
98     left = 0;
99     for (size_t i = 0; i < m_operations.size(); ++i) {
100         FilterOperation* filterOperation = m_operations.at(i).get();
101         switch (filterOperation->getOperationType()) {
102         case FilterOperation::BLUR: {
103             BlurFilterOperation* blurOperation = static_cast<BlurFilterOperation*>(filterOperation);
104             float stdDeviationX = blurOperation->stdDeviationX().calcFloatValue(borderBoxSize.width());
105             float stdDeviationY = blurOperation->stdDeviationY().calcFloatValue(borderBoxSize.height());
106             IntSize outset = outsetSizeForBlur(stdDeviationX, stdDeviationY);
107             top += outset.height();
108             right += outset.width();
109             bottom += outset.height();
110             left += outset.width();
111             break;
112         }
113         case FilterOperation::DROP_SHADOW: {
114             DropShadowFilterOperation* dropShadowOperation = static_cast<DropShadowFilterOperation*>(filterOperation);
115             IntSize outset = outsetSizeForBlur(dropShadowOperation->stdDeviation(), dropShadowOperation->stdDeviation());
116             top += outset.height() - dropShadowOperation->y();
117             right += outset.width() + dropShadowOperation->x();
118             bottom += outset.height() + dropShadowOperation->y();
119             left += outset.width() - dropShadowOperation->x();
120             break;
121         }
122 #if ENABLE(CSS_SHADERS)
123         case FilterOperation::CUSTOM: {
124             // Need to include the filter margins here.
125             break;
126         }
127 #endif
128         default:
129             break;
130         }
131     }
132 }
133
134 } // namespace WebCore
135
136 #endif // ENABLE(CSS_FILTERS)