1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 2004-2005 Allan Sandfeld Jensen (kde (at) carewolf.com) 4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit (at) nickshanks.com) 5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. 6 * Copyright (C) 2007 Alexey Proskuryakov <ap (at) webkit.org> 7 * Copyright (C) 2007, 2008 Eric Seidel <eric (at) webkit.org> 8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. 10 * Copyright (C) Research In Motion Limited 2011. All rights reserved. 11 * Copyright (C) 2012 Google Inc. All rights reserved. 12 * 13 * This library is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU Library General Public 15 * License as published by the Free Software Foundation; either 16 * version 2 of the License, or (at your option) any later version. 17 * 18 * This library is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 * Library General Public License for more details. 22 * 23 * You should have received a copy of the GNU Library General Public License 24 * along with this library; see the file COPYING.LIB. If not, write to 25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 26 * Boston, MA 02110-1301, USA. 27 */ 28 29 #include "config.h" 30 #include "core/css/resolver/FilterOperationResolver.h" 31 32 #include "core/css/CSSFilterValue.h" 33 #include "core/css/parser/BisonCSSParser.h" 34 #include "core/css/CSSPrimitiveValueMappings.h" 35 #include "core/css/CSSShadowValue.h" 36 #include "core/css/resolver/TransformBuilder.h" 37 #include "core/rendering/svg/ReferenceFilterBuilder.h" 38 #include "core/svg/SVGURIReference.h" 39 40 namespace WebCore { 41 42 static FilterOperation::OperationType filterOperationForType(CSSFilterValue::FilterOperationType type) 43 { 44 switch (type) { 45 case CSSFilterValue::ReferenceFilterOperation: 46 return FilterOperation::REFERENCE; 47 case CSSFilterValue::GrayscaleFilterOperation: 48 return FilterOperation::GRAYSCALE; 49 case CSSFilterValue::SepiaFilterOperation: 50 return FilterOperation::SEPIA; 51 case CSSFilterValue::SaturateFilterOperation: 52 return FilterOperation::SATURATE; 53 case CSSFilterValue::HueRotateFilterOperation: 54 return FilterOperation::HUE_ROTATE; 55 case CSSFilterValue::InvertFilterOperation: 56 return FilterOperation::INVERT; 57 case CSSFilterValue::OpacityFilterOperation: 58 return FilterOperation::OPACITY; 59 case CSSFilterValue::BrightnessFilterOperation: 60 return FilterOperation::BRIGHTNESS; 61 case CSSFilterValue::ContrastFilterOperation: 62 return FilterOperation::CONTRAST; 63 case CSSFilterValue::BlurFilterOperation: 64 return FilterOperation::BLUR; 65 case CSSFilterValue::DropShadowFilterOperation: 66 return FilterOperation::DROP_SHADOW; 67 case CSSFilterValue::UnknownFilterOperation: 68 return FilterOperation::NONE; 69 } 70 return FilterOperation::NONE; 71 } 72 73 bool FilterOperationResolver::createFilterOperations(CSSValue* inValue, const CSSToLengthConversionData& unadjustedConversionData, FilterOperations& outOperations, StyleResolverState& state) 74 { 75 ASSERT(outOperations.isEmpty()); 76 77 if (!inValue) 78 return false; 79 80 if (inValue->isPrimitiveValue()) { 81 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(inValue); 82 if (primitiveValue->getValueID() == CSSValueNone) 83 return true; 84 } 85 86 if (!inValue->isValueList()) 87 return false; 88 89 #ifdef BLINK_SCALE_FILTERS_AT_RECORD_TIME 90 float zoomFactor = unadjustedConversionData.zoom() * state.elementStyleResources().deviceScaleFactor(); 91 #else 92 float zoomFactor = unadjustedConversionData.zoom(); 93 #endif 94 const CSSToLengthConversionData& conversionData = unadjustedConversionData.copyWithAdjustedZoom(zoomFactor); 95 FilterOperations operations; 96 for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) { 97 CSSValue* currValue = i.value(); 98 if (!currValue->isFilterValue()) 99 continue; 100 101 CSSFilterValue* filterValue = toCSSFilterValue(i.value()); 102 FilterOperation::OperationType operationType = filterOperationForType(filterValue->operationType()); 103 104 if (operationType == FilterOperation::REFERENCE) { 105 if (filterValue->length() != 1) 106 continue; 107 CSSValue* argument = filterValue->itemWithoutBoundsCheck(0); 108 109 if (!argument->isSVGDocumentValue()) 110 continue; 111 112 CSSSVGDocumentValue* svgDocumentValue = toCSSSVGDocumentValue(argument); 113 KURL url = state.document().completeURL(svgDocumentValue->url()); 114 115 RefPtr<ReferenceFilterOperation> operation = ReferenceFilterOperation::create(svgDocumentValue->url(), AtomicString(url.fragmentIdentifier())); 116 if (SVGURIReference::isExternalURIReference(svgDocumentValue->url(), state.document())) { 117 if (!svgDocumentValue->loadRequested()) 118 state.elementStyleResources().addPendingSVGDocument(operation.get(), svgDocumentValue); 119 else if (svgDocumentValue->cachedSVGDocument()) 120 ReferenceFilterBuilder::setDocumentResourceReference(operation.get(), adoptPtr(new DocumentResourceReference(svgDocumentValue->cachedSVGDocument()))); 121 } 122 operations.operations().append(operation); 123 continue; 124 } 125 126 // Check that all parameters are primitive values, with the 127 // exception of drop shadow which has a CSSShadowValue parameter. 128 if (operationType != FilterOperation::DROP_SHADOW) { 129 bool haveNonPrimitiveValue = false; 130 for (unsigned j = 0; j < filterValue->length(); ++j) { 131 if (!filterValue->itemWithoutBoundsCheck(j)->isPrimitiveValue()) { 132 haveNonPrimitiveValue = true; 133 break; 134 } 135 } 136 if (haveNonPrimitiveValue) 137 continue; 138 } 139 140 CSSPrimitiveValue* firstValue = filterValue->length() && filterValue->itemWithoutBoundsCheck(0)->isPrimitiveValue() ? toCSSPrimitiveValue(filterValue->itemWithoutBoundsCheck(0)) : 0; 141 switch (filterValue->operationType()) { 142 case CSSFilterValue::GrayscaleFilterOperation: 143 case CSSFilterValue::SepiaFilterOperation: 144 case CSSFilterValue::SaturateFilterOperation: { 145 double amount = 1; 146 if (filterValue->length() == 1) { 147 amount = firstValue->getDoubleValue(); 148 if (firstValue->isPercentage()) 149 amount /= 100; 150 } 151 152 operations.operations().append(BasicColorMatrixFilterOperation::create(amount, operationType)); 153 break; 154 } 155 case CSSFilterValue::HueRotateFilterOperation: { 156 double angle = 0; 157 if (filterValue->length() == 1) 158 angle = firstValue->computeDegrees(); 159 160 operations.operations().append(BasicColorMatrixFilterOperation::create(angle, operationType)); 161 break; 162 } 163 case CSSFilterValue::InvertFilterOperation: 164 case CSSFilterValue::BrightnessFilterOperation: 165 case CSSFilterValue::ContrastFilterOperation: 166 case CSSFilterValue::OpacityFilterOperation: { 167 double amount = (filterValue->operationType() == CSSFilterValue::BrightnessFilterOperation) ? 0 : 1; 168 if (filterValue->length() == 1) { 169 amount = firstValue->getDoubleValue(); 170 if (firstValue->isPercentage()) 171 amount /= 100; 172 } 173 174 operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType)); 175 break; 176 } 177 case CSSFilterValue::BlurFilterOperation: { 178 Length stdDeviation = Length(0, Fixed); 179 if (filterValue->length() >= 1) 180 stdDeviation = firstValue->convertToLength<FixedConversion | PercentConversion>(conversionData); 181 operations.operations().append(BlurFilterOperation::create(stdDeviation)); 182 break; 183 } 184 case CSSFilterValue::DropShadowFilterOperation: { 185 if (filterValue->length() != 1) 186 return false; 187 188 CSSValue* cssValue = filterValue->itemWithoutBoundsCheck(0); 189 if (!cssValue->isShadowValue()) 190 continue; 191 192 CSSShadowValue* item = toCSSShadowValue(cssValue); 193 IntPoint location(item->x->computeLength<int>(conversionData), item->y->computeLength<int>(conversionData)); 194 int blur = item->blur ? item->blur->computeLength<int>(conversionData) : 0; 195 Color shadowColor = Color::transparent; 196 if (item->color) 197 shadowColor = state.document().textLinkColors().colorFromPrimitiveValue(item->color.get(), state.style()->color()); 198 199 operations.operations().append(DropShadowFilterOperation::create(location, blur, shadowColor)); 200 break; 201 } 202 case CSSFilterValue::UnknownFilterOperation: 203 default: 204 ASSERT_NOT_REACHED(); 205 break; 206 } 207 } 208 209 outOperations = operations; 210 return true; 211 } 212 213 } // namespace WebCore 214