1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) 4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@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@webkit.org> 7 * Copyright (C) 2007, 2008 Eric Seidel <eric@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/CSSPrimitiveValueMappings.h" 34#include "core/css/CSSShadowValue.h" 35#include "core/css/resolver/TransformBuilder.h" 36#include "core/rendering/svg/ReferenceFilterBuilder.h" 37#include "core/svg/SVGURIReference.h" 38 39namespace blink { 40 41static FilterOperation::OperationType filterOperationForType(CSSFilterValue::FilterOperationType type) 42{ 43 switch (type) { 44 case CSSFilterValue::ReferenceFilterOperation: 45 return FilterOperation::REFERENCE; 46 case CSSFilterValue::GrayscaleFilterOperation: 47 return FilterOperation::GRAYSCALE; 48 case CSSFilterValue::SepiaFilterOperation: 49 return FilterOperation::SEPIA; 50 case CSSFilterValue::SaturateFilterOperation: 51 return FilterOperation::SATURATE; 52 case CSSFilterValue::HueRotateFilterOperation: 53 return FilterOperation::HUE_ROTATE; 54 case CSSFilterValue::InvertFilterOperation: 55 return FilterOperation::INVERT; 56 case CSSFilterValue::OpacityFilterOperation: 57 return FilterOperation::OPACITY; 58 case CSSFilterValue::BrightnessFilterOperation: 59 return FilterOperation::BRIGHTNESS; 60 case CSSFilterValue::ContrastFilterOperation: 61 return FilterOperation::CONTRAST; 62 case CSSFilterValue::BlurFilterOperation: 63 return FilterOperation::BLUR; 64 case CSSFilterValue::DropShadowFilterOperation: 65 return FilterOperation::DROP_SHADOW; 66 case CSSFilterValue::UnknownFilterOperation: 67 return FilterOperation::NONE; 68 } 69 return FilterOperation::NONE; 70} 71 72bool FilterOperationResolver::createFilterOperations(CSSValue* inValue, const CSSToLengthConversionData& unadjustedConversionData, FilterOperations& outOperations, StyleResolverState& state) 73{ 74 ASSERT(outOperations.isEmpty()); 75 76 if (!inValue) 77 return false; 78 79 if (inValue->isPrimitiveValue()) { 80 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(inValue); 81 if (primitiveValue->getValueID() == CSSValueNone) 82 return true; 83 } 84 85 if (!inValue->isValueList()) 86 return false; 87 88 float zoomFactor = unadjustedConversionData.zoom(); 89 const CSSToLengthConversionData& conversionData = unadjustedConversionData.copyWithAdjustedZoom(zoomFactor); 90 FilterOperations operations; 91 for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) { 92 CSSValue* currValue = i.value(); 93 if (!currValue->isFilterValue()) 94 continue; 95 96 CSSFilterValue* filterValue = toCSSFilterValue(i.value()); 97 FilterOperation::OperationType operationType = filterOperationForType(filterValue->operationType()); 98 99 if (operationType == FilterOperation::REFERENCE) { 100 if (filterValue->length() != 1) 101 continue; 102 CSSValue* argument = filterValue->item(0); 103 104 if (!argument->isSVGDocumentValue()) 105 continue; 106 107 CSSSVGDocumentValue* svgDocumentValue = toCSSSVGDocumentValue(argument); 108 KURL url = state.document().completeURL(svgDocumentValue->url()); 109 110 RefPtr<ReferenceFilterOperation> operation = ReferenceFilterOperation::create(svgDocumentValue->url(), AtomicString(url.fragmentIdentifier())); 111 if (SVGURIReference::isExternalURIReference(svgDocumentValue->url(), state.document())) { 112 if (!svgDocumentValue->loadRequested()) 113 state.elementStyleResources().addPendingSVGDocument(operation.get(), svgDocumentValue); 114 else if (svgDocumentValue->cachedSVGDocument()) 115 ReferenceFilterBuilder::setDocumentResourceReference(operation.get(), adoptPtr(new DocumentResourceReference(svgDocumentValue->cachedSVGDocument()))); 116 } 117 operations.operations().append(operation); 118 continue; 119 } 120 121 // Check that all parameters are primitive values, with the 122 // exception of drop shadow which has a CSSShadowValue parameter. 123 if (operationType != FilterOperation::DROP_SHADOW) { 124 bool haveNonPrimitiveValue = false; 125 for (unsigned j = 0; j < filterValue->length(); ++j) { 126 if (!filterValue->item(j)->isPrimitiveValue()) { 127 haveNonPrimitiveValue = true; 128 break; 129 } 130 } 131 if (haveNonPrimitiveValue) 132 continue; 133 } 134 135 CSSPrimitiveValue* firstValue = filterValue->length() && filterValue->item(0)->isPrimitiveValue() ? toCSSPrimitiveValue(filterValue->item(0)) : 0; 136 switch (filterValue->operationType()) { 137 case CSSFilterValue::GrayscaleFilterOperation: 138 case CSSFilterValue::SepiaFilterOperation: 139 case CSSFilterValue::SaturateFilterOperation: { 140 double amount = 1; 141 if (filterValue->length() == 1) { 142 amount = firstValue->getDoubleValue(); 143 if (firstValue->isPercentage()) 144 amount /= 100; 145 } 146 147 operations.operations().append(BasicColorMatrixFilterOperation::create(amount, operationType)); 148 break; 149 } 150 case CSSFilterValue::HueRotateFilterOperation: { 151 double angle = 0; 152 if (filterValue->length() == 1) 153 angle = firstValue->computeDegrees(); 154 155 operations.operations().append(BasicColorMatrixFilterOperation::create(angle, operationType)); 156 break; 157 } 158 case CSSFilterValue::InvertFilterOperation: 159 case CSSFilterValue::BrightnessFilterOperation: 160 case CSSFilterValue::ContrastFilterOperation: 161 case CSSFilterValue::OpacityFilterOperation: { 162 double amount = (filterValue->operationType() == CSSFilterValue::BrightnessFilterOperation) ? 0 : 1; 163 if (filterValue->length() == 1) { 164 amount = firstValue->getDoubleValue(); 165 if (firstValue->isPercentage()) 166 amount /= 100; 167 } 168 169 operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType)); 170 break; 171 } 172 case CSSFilterValue::BlurFilterOperation: { 173 Length stdDeviation = Length(0, Fixed); 174 if (filterValue->length() >= 1) 175 stdDeviation = firstValue->convertToLength<FixedConversion | PercentConversion>(conversionData); 176 operations.operations().append(BlurFilterOperation::create(stdDeviation)); 177 break; 178 } 179 case CSSFilterValue::DropShadowFilterOperation: { 180 if (filterValue->length() != 1) 181 return false; 182 183 CSSValue* cssValue = filterValue->item(0); 184 if (!cssValue->isShadowValue()) 185 continue; 186 187 CSSShadowValue* item = toCSSShadowValue(cssValue); 188 IntPoint location(item->x->computeLength<int>(conversionData), item->y->computeLength<int>(conversionData)); 189 int blur = item->blur ? item->blur->computeLength<int>(conversionData) : 0; 190 Color shadowColor = Color::transparent; 191 if (item->color) 192 shadowColor = state.document().textLinkColors().colorFromPrimitiveValue(item->color.get(), state.style()->color()); 193 194 operations.operations().append(DropShadowFilterOperation::create(location, blur, shadowColor)); 195 break; 196 } 197 case CSSFilterValue::UnknownFilterOperation: 198 default: 199 ASSERT_NOT_REACHED(); 200 break; 201 } 202 } 203 204 outOperations = operations; 205 return true; 206} 207 208} // namespace blink 209