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 "core/platform/graphics/filters/FilterOperations.h" 28 29 #include "core/css/LengthFunctions.h" 30 #include "core/platform/graphics/IntSize.h" 31 #include "core/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::operationsMatch(const FilterOperations& other) const 74 { 75 size_t numOperations = operations().size(); 76 // If the sizes of the function lists don't match, the lists don't match 77 if (numOperations != other.operations().size()) 78 return false; 79 80 // If the types of each function are not the same, the lists don't match 81 for (size_t i = 0; i < numOperations; ++i) { 82 if (!operations()[i]->isSameType(*other.operations()[i])) 83 return false; 84 } 85 return true; 86 } 87 88 bool FilterOperations::hasCustomFilter() const 89 { 90 for (size_t i = 0; i < m_operations.size(); ++i) { 91 FilterOperation::OperationType type = m_operations.at(i)->getOperationType(); 92 if (type == FilterOperation::CUSTOM || type == FilterOperation::VALIDATED_CUSTOM) 93 return true; 94 } 95 return false; 96 } 97 98 bool FilterOperations::hasReferenceFilter() const 99 { 100 for (size_t i = 0; i < m_operations.size(); ++i) { 101 if (m_operations.at(i)->getOperationType() == FilterOperation::REFERENCE) 102 return true; 103 } 104 return false; 105 } 106 107 bool FilterOperations::hasOutsets() const 108 { 109 for (size_t i = 0; i < m_operations.size(); ++i) { 110 FilterOperation::OperationType operationType = m_operations.at(i).get()->getOperationType(); 111 if (operationType == FilterOperation::BLUR || operationType == FilterOperation::DROP_SHADOW || operationType == FilterOperation::REFERENCE) 112 return true; 113 } 114 return false; 115 } 116 117 FilterOutsets FilterOperations::outsets() const 118 { 119 FilterOutsets totalOutsets; 120 for (size_t i = 0; i < m_operations.size(); ++i) { 121 FilterOperation* filterOperation = m_operations.at(i).get(); 122 switch (filterOperation->getOperationType()) { 123 case FilterOperation::BLUR: { 124 BlurFilterOperation* blurOperation = static_cast<BlurFilterOperation*>(filterOperation); 125 float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0); 126 IntSize outsetSize = outsetSizeForBlur(stdDeviation); 127 FilterOutsets outsets(outsetSize.height(), outsetSize.width(), outsetSize.height(), outsetSize.width()); 128 totalOutsets += outsets; 129 break; 130 } 131 case FilterOperation::DROP_SHADOW: { 132 DropShadowFilterOperation* dropShadowOperation = static_cast<DropShadowFilterOperation*>(filterOperation); 133 IntSize outsetSize = outsetSizeForBlur(dropShadowOperation->stdDeviation()); 134 FilterOutsets outsets( 135 std::max(0, outsetSize.height() - dropShadowOperation->y()), 136 std::max(0, outsetSize.width() + dropShadowOperation->x()), 137 std::max(0, outsetSize.height() + dropShadowOperation->y()), 138 std::max(0, outsetSize.width() - dropShadowOperation->x()) 139 ); 140 totalOutsets += outsets; 141 break; 142 } 143 case FilterOperation::REFERENCE: { 144 ReferenceFilterOperation* referenceOperation = static_cast<ReferenceFilterOperation*>(filterOperation); 145 if (referenceOperation->filter() && referenceOperation->filter()->lastEffect()) { 146 FloatRect outsetRect(0, 0, 1, 1); 147 outsetRect = referenceOperation->filter()->lastEffect()->mapRectRecursive(outsetRect); 148 FilterOutsets outsets( 149 std::max(0.0f, -outsetRect.y()), 150 std::max(0.0f, outsetRect.x() + outsetRect.width() - 1), 151 std::max(0.0f, outsetRect.y() + outsetRect.height() - 1), 152 std::max(0.0f, -outsetRect.x()) 153 ); 154 totalOutsets += outsets; 155 } 156 break; 157 } 158 case FilterOperation::CUSTOM: 159 case FilterOperation::VALIDATED_CUSTOM: { 160 // FIXME: Need to include the filter margins here. 161 // https://bugs.webkit.org/show_bug.cgi?id=71400 162 break; 163 } 164 default: 165 break; 166 } 167 } 168 return totalOutsets; 169 } 170 171 bool FilterOperations::hasFilterThatAffectsOpacity() const 172 { 173 for (size_t i = 0; i < m_operations.size(); ++i) 174 if (m_operations[i]->affectsOpacity()) 175 return true; 176 return false; 177 } 178 179 bool FilterOperations::hasFilterThatMovesPixels() const 180 { 181 for (size_t i = 0; i < m_operations.size(); ++i) 182 if (m_operations[i]->movesPixels()) 183 return true; 184 return false; 185 } 186 187 } // namespace WebCore 188 189