Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / resolver / FilterOperationResolver.cpp
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/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 blink {
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     float zoomFactor = unadjustedConversionData.zoom();
90     const CSSToLengthConversionData& conversionData = unadjustedConversionData.copyWithAdjustedZoom(zoomFactor);
91     FilterOperations operations;
92     for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) {
93         CSSValue* currValue = i.value();
94         if (!currValue->isFilterValue())
95             continue;
96
97         CSSFilterValue* filterValue = toCSSFilterValue(i.value());
98         FilterOperation::OperationType operationType = filterOperationForType(filterValue->operationType());
99
100         if (operationType == FilterOperation::REFERENCE) {
101             if (filterValue->length() != 1)
102                 continue;
103             CSSValue* argument = filterValue->item(0);
104
105             if (!argument->isSVGDocumentValue())
106                 continue;
107
108             CSSSVGDocumentValue* svgDocumentValue = toCSSSVGDocumentValue(argument);
109             KURL url = state.document().completeURL(svgDocumentValue->url());
110
111             RefPtr<ReferenceFilterOperation> operation = ReferenceFilterOperation::create(svgDocumentValue->url(), AtomicString(url.fragmentIdentifier()));
112             if (SVGURIReference::isExternalURIReference(svgDocumentValue->url(), state.document())) {
113                 if (!svgDocumentValue->loadRequested())
114                     state.elementStyleResources().addPendingSVGDocument(operation.get(), svgDocumentValue);
115                 else if (svgDocumentValue->cachedSVGDocument())
116                     ReferenceFilterBuilder::setDocumentResourceReference(operation.get(), adoptPtr(new DocumentResourceReference(svgDocumentValue->cachedSVGDocument())));
117             }
118             operations.operations().append(operation);
119             continue;
120         }
121
122         // Check that all parameters are primitive values, with the
123         // exception of drop shadow which has a CSSShadowValue parameter.
124         if (operationType != FilterOperation::DROP_SHADOW) {
125             bool haveNonPrimitiveValue = false;
126             for (unsigned j = 0; j < filterValue->length(); ++j) {
127                 if (!filterValue->item(j)->isPrimitiveValue()) {
128                     haveNonPrimitiveValue = true;
129                     break;
130                 }
131             }
132             if (haveNonPrimitiveValue)
133                 continue;
134         }
135
136         CSSPrimitiveValue* firstValue = filterValue->length() && filterValue->item(0)->isPrimitiveValue() ? toCSSPrimitiveValue(filterValue->item(0)) : 0;
137         switch (filterValue->operationType()) {
138         case CSSFilterValue::GrayscaleFilterOperation:
139         case CSSFilterValue::SepiaFilterOperation:
140         case CSSFilterValue::SaturateFilterOperation: {
141             double amount = 1;
142             if (filterValue->length() == 1) {
143                 amount = firstValue->getDoubleValue();
144                 if (firstValue->isPercentage())
145                     amount /= 100;
146             }
147
148             operations.operations().append(BasicColorMatrixFilterOperation::create(amount, operationType));
149             break;
150         }
151         case CSSFilterValue::HueRotateFilterOperation: {
152             double angle = 0;
153             if (filterValue->length() == 1)
154                 angle = firstValue->computeDegrees();
155
156             operations.operations().append(BasicColorMatrixFilterOperation::create(angle, operationType));
157             break;
158         }
159         case CSSFilterValue::InvertFilterOperation:
160         case CSSFilterValue::BrightnessFilterOperation:
161         case CSSFilterValue::ContrastFilterOperation:
162         case CSSFilterValue::OpacityFilterOperation: {
163             double amount = (filterValue->operationType() == CSSFilterValue::BrightnessFilterOperation) ? 0 : 1;
164             if (filterValue->length() == 1) {
165                 amount = firstValue->getDoubleValue();
166                 if (firstValue->isPercentage())
167                     amount /= 100;
168             }
169
170             operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType));
171             break;
172         }
173         case CSSFilterValue::BlurFilterOperation: {
174             Length stdDeviation = Length(0, Fixed);
175             if (filterValue->length() >= 1)
176                 stdDeviation = firstValue->convertToLength<FixedConversion | PercentConversion>(conversionData);
177             operations.operations().append(BlurFilterOperation::create(stdDeviation));
178             break;
179         }
180         case CSSFilterValue::DropShadowFilterOperation: {
181             if (filterValue->length() != 1)
182                 return false;
183
184             CSSValue* cssValue = filterValue->item(0);
185             if (!cssValue->isShadowValue())
186                 continue;
187
188             CSSShadowValue* item = toCSSShadowValue(cssValue);
189             IntPoint location(item->x->computeLength<int>(conversionData), item->y->computeLength<int>(conversionData));
190             int blur = item->blur ? item->blur->computeLength<int>(conversionData) : 0;
191             Color shadowColor = Color::transparent;
192             if (item->color)
193                 shadowColor = state.document().textLinkColors().colorFromPrimitiveValue(item->color.get(), state.style()->color());
194
195             operations.operations().append(DropShadowFilterOperation::create(location, blur, shadowColor));
196             break;
197         }
198         case CSSFilterValue::UnknownFilterOperation:
199         default:
200             ASSERT_NOT_REACHED();
201             break;
202         }
203     }
204
205     outOperations = operations;
206     return true;
207 }
208
209 } // namespace blink