2010-04-20 Dirk Schulze <krit@webkit.org>
[WebKit-https.git] / WebCore / svg / SVGStyledElement.cpp
1 /*
2     Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3                   2004, 2005, 2007, 2008 Rob Buis <buis@kde.org>
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Library General Public
7     License as published by the Free Software Foundation; either
8     version 2 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Library General Public License for more details.
14
15     You should have received a copy of the GNU Library General Public License
16     along with this library; see the file COPYING.LIB.  If not, write to
17     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18     Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22
23 #if ENABLE(SVG)
24 #include "SVGStyledElement.h"
25
26 #include "Attr.h"
27 #include "CSSParser.h"
28 #include "CSSStyleSelector.h"
29 #include "Document.h"
30 #include "HTMLNames.h"
31 #include "MappedAttribute.h"
32 #include "PlatformString.h"
33 #include "RenderObject.h"
34 #include "RenderSVGResource.h"
35 #include "RenderSVGResourceClipper.h"
36 #include "RenderSVGResourceFilter.h"
37 #include "RenderSVGResourceMasker.h"
38 #include "SVGElement.h"
39 #include "SVGElementInstance.h"
40 #include "SVGElementRareData.h"
41 #include "SVGNames.h"
42 #include "SVGRenderStyle.h"
43 #include "SVGRenderSupport.h"
44 #include "SVGResource.h"
45 #include "SVGSVGElement.h"
46 #include <wtf/Assertions.h>
47
48 namespace WebCore {
49
50 using namespace SVGNames;
51
52 void mapAttributeToCSSProperty(HashMap<AtomicStringImpl*, int>* propertyNameToIdMap, const QualifiedName& attrName)
53 {
54     int propertyId = cssPropertyID(attrName.localName());
55     ASSERT(propertyId > 0);
56     propertyNameToIdMap->set(attrName.localName().impl(), propertyId);
57 }
58
59 SVGStyledElement::SVGStyledElement(const QualifiedName& tagName, Document* doc)
60     : SVGElement(tagName, doc)
61 {
62 }
63
64 SVGStyledElement::~SVGStyledElement()
65 {
66     SVGResource::removeClient(this);
67 }
68
69 bool SVGStyledElement::rendererIsNeeded(RenderStyle* style)
70 {
71     // http://www.w3.org/TR/SVG/extend.html#PrivateData
72     // Prevent anything other than SVG renderers from appearing in our render tree
73     // Spec: SVG allows inclusion of elements from foreign namespaces anywhere
74     // with the SVG content. In general, the SVG user agent will include the unknown
75     // elements in the DOM but will otherwise ignore unknown elements. 
76     if (!parentNode() || parentNode()->isSVGElement())
77         return StyledElement::rendererIsNeeded(style);
78
79     return false;
80 }
81
82 int SVGStyledElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
83 {
84     if (!attrName.namespaceURI().isNull())
85         return 0;
86     
87     static HashMap<AtomicStringImpl*, int>* propertyNameToIdMap = 0;
88     if (!propertyNameToIdMap) {
89         propertyNameToIdMap = new HashMap<AtomicStringImpl*, int>;
90         // This is a list of all base CSS and SVG CSS properties which are exposed as SVG XML attributes
91         mapAttributeToCSSProperty(propertyNameToIdMap, alignment_baselineAttr);
92         mapAttributeToCSSProperty(propertyNameToIdMap, baseline_shiftAttr);
93         mapAttributeToCSSProperty(propertyNameToIdMap, clipAttr);
94         mapAttributeToCSSProperty(propertyNameToIdMap, clip_pathAttr);
95         mapAttributeToCSSProperty(propertyNameToIdMap, clip_ruleAttr);
96         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::colorAttr);
97         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolationAttr);
98         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolation_filtersAttr);
99         mapAttributeToCSSProperty(propertyNameToIdMap, color_profileAttr);
100         mapAttributeToCSSProperty(propertyNameToIdMap, color_renderingAttr); 
101         mapAttributeToCSSProperty(propertyNameToIdMap, cursorAttr);
102         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::directionAttr);
103         mapAttributeToCSSProperty(propertyNameToIdMap, displayAttr);
104         mapAttributeToCSSProperty(propertyNameToIdMap, dominant_baselineAttr);
105         mapAttributeToCSSProperty(propertyNameToIdMap, enable_backgroundAttr);
106         mapAttributeToCSSProperty(propertyNameToIdMap, fillAttr);
107         mapAttributeToCSSProperty(propertyNameToIdMap, fill_opacityAttr);
108         mapAttributeToCSSProperty(propertyNameToIdMap, fill_ruleAttr);
109         mapAttributeToCSSProperty(propertyNameToIdMap, filterAttr);
110         mapAttributeToCSSProperty(propertyNameToIdMap, flood_colorAttr);
111         mapAttributeToCSSProperty(propertyNameToIdMap, flood_opacityAttr);
112         mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
113         mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
114         mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
115         mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
116         mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
117         mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
118         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_horizontalAttr);
119         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_verticalAttr);
120         mapAttributeToCSSProperty(propertyNameToIdMap, image_renderingAttr);
121         mapAttributeToCSSProperty(propertyNameToIdMap, kerningAttr);
122         mapAttributeToCSSProperty(propertyNameToIdMap, letter_spacingAttr);
123         mapAttributeToCSSProperty(propertyNameToIdMap, lighting_colorAttr);
124         mapAttributeToCSSProperty(propertyNameToIdMap, marker_endAttr);
125         mapAttributeToCSSProperty(propertyNameToIdMap, marker_midAttr);
126         mapAttributeToCSSProperty(propertyNameToIdMap, marker_startAttr);
127         mapAttributeToCSSProperty(propertyNameToIdMap, maskAttr);
128         mapAttributeToCSSProperty(propertyNameToIdMap, opacityAttr);
129         mapAttributeToCSSProperty(propertyNameToIdMap, overflowAttr);
130         mapAttributeToCSSProperty(propertyNameToIdMap, pointer_eventsAttr);
131         mapAttributeToCSSProperty(propertyNameToIdMap, shape_renderingAttr);
132         mapAttributeToCSSProperty(propertyNameToIdMap, stop_colorAttr);
133         mapAttributeToCSSProperty(propertyNameToIdMap, stop_opacityAttr);
134         mapAttributeToCSSProperty(propertyNameToIdMap, strokeAttr);
135         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dasharrayAttr);
136         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dashoffsetAttr);
137         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linecapAttr);
138         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linejoinAttr);
139         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_miterlimitAttr);
140         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_opacityAttr);
141         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_widthAttr);
142         mapAttributeToCSSProperty(propertyNameToIdMap, text_anchorAttr);
143         mapAttributeToCSSProperty(propertyNameToIdMap, text_decorationAttr);
144         mapAttributeToCSSProperty(propertyNameToIdMap, text_renderingAttr);
145         mapAttributeToCSSProperty(propertyNameToIdMap, unicode_bidiAttr);
146         mapAttributeToCSSProperty(propertyNameToIdMap, visibilityAttr);
147         mapAttributeToCSSProperty(propertyNameToIdMap, word_spacingAttr);
148         mapAttributeToCSSProperty(propertyNameToIdMap, writing_modeAttr);
149     }
150     
151     return propertyNameToIdMap->get(attrName.localName().impl());
152 }
153
154 bool SVGStyledElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
155 {
156     if (SVGStyledElement::cssPropertyIdForSVGAttributeName(attrName) > 0) {
157         result = eSVG;
158         return false;
159     }
160     return SVGElement::mapToEntry(attrName, result);
161 }
162
163 void SVGStyledElement::parseMappedAttribute(MappedAttribute* attr)
164 {
165     const QualifiedName& attrName = attr->name();
166     // NOTE: Any subclass which overrides parseMappedAttribute for a property handled by
167     // cssPropertyIdForSVGAttributeName will also have to override mapToEntry to disable the default eSVG mapping
168     int propId = SVGStyledElement::cssPropertyIdForSVGAttributeName(attrName);
169     if (propId > 0) {
170         addCSSProperty(attr, propId, attr->value());
171         setNeedsStyleRecalc();
172         return;
173     }
174     
175     // SVG animation has currently requires special storage of values so we set
176     // the className here.  svgAttributeChanged actually causes the resulting
177     // style updates (instead of StyledElement::parseMappedAttribute). We don't
178     // tell StyledElement about the change to avoid parsing the class list twice
179     if (attrName.matches(HTMLNames::classAttr))
180         setClassNameBaseValue(attr->value());
181     else
182         // id is handled by StyledElement which SVGElement inherits from
183         SVGElement::parseMappedAttribute(attr);
184 }
185
186 bool SVGStyledElement::isKnownAttribute(const QualifiedName& attrName)
187 {
188     // Recognize all style related SVG CSS properties
189     int propId = SVGStyledElement::cssPropertyIdForSVGAttributeName(attrName);
190     if (propId > 0)
191         return true;
192
193     return (attrName == idAttributeName() || attrName == HTMLNames::styleAttr); 
194 }
195
196 void SVGStyledElement::svgAttributeChanged(const QualifiedName& attrName)
197 {
198     SVGElement::svgAttributeChanged(attrName);
199
200     if (attrName.matches(HTMLNames::classAttr))
201         classAttributeChanged(className());
202
203     if (attrName == idAttributeName()) {
204         // Notify resources about id changes, this is important as we cache resources by id in SVGDocumentExtensions
205         if (renderer() && renderer()->isSVGResource()) {
206             RenderSVGResource* resource = renderer()->toRenderSVGResource();
207             resource->idChanged();
208         }
209     }
210
211     // If we're the child of a resource element, be sure to invalidate it.
212     invalidateResourcesInAncestorChain();
213
214     // If the element is using resources, invalidate them.
215     invalidateResources();
216
217     // Invalidate all SVGElementInstances associated with us
218     SVGElementInstance::invalidateAllInstancesOfElement(this);
219 }
220
221 void SVGStyledElement::synchronizeProperty(const QualifiedName& attrName)
222 {
223     SVGElement::synchronizeProperty(attrName);
224
225     if (attrName == anyQName() || attrName.matches(HTMLNames::classAttr))
226         synchronizeClassName();
227 }
228
229 void SVGStyledElement::invalidateResources()
230 {
231     RenderObject* object = renderer();
232     if (!object)
233         return;
234
235     Document* document = this->document();
236
237     if (document->parsing())
238         return;
239
240     deregisterFromResources(object);
241 }
242
243 void SVGStyledElement::invalidateResourcesInAncestorChain() const
244 {
245     Node* node = parentNode();
246     while (node) {
247         if (!node->isSVGElement())
248             break;
249
250         SVGElement* element = static_cast<SVGElement*>(node);
251         if (SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(element->isStyled() ? element : 0))
252             styledElement->invalidateCanvasResources();
253
254         node = node->parentNode();
255     }
256 }
257
258 void SVGStyledElement::invalidateCanvasResources()
259 {
260     RenderObject* object = renderer();
261     if (!object)
262         return;
263
264     if (object->isSVGResource())
265         object->toRenderSVGResource()->invalidateClients();
266
267     // The following lines will be removed soon, once all resources are handled by renderers.
268     if (SVGResource* resource = canvasResource(object))
269         resource->invalidate();
270 }
271
272 void SVGStyledElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
273 {
274     SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
275
276     // Invalidate all SVGElementInstances associated with us
277     SVGElementInstance::invalidateAllInstancesOfElement(this);
278 }
279
280 PassRefPtr<RenderStyle> SVGStyledElement::resolveStyle(RenderStyle* parentStyle)
281 {
282     if (renderer())
283         return renderer()->style();
284     return document()->styleSelector()->styleForElement(this, parentStyle);
285 }
286
287 PassRefPtr<CSSValue> SVGStyledElement::getPresentationAttribute(const String& name)
288 {
289     if (!mappedAttributes())
290         return 0;
291
292     QualifiedName attributeName(nullAtom, name, nullAtom);
293     Attribute* attr = mappedAttributes()->getAttributeItem(attributeName);
294     if (!attr || !attr->isMappedAttribute() || !attr->style())
295         return 0;
296
297     MappedAttribute* cssSVGAttr = static_cast<MappedAttribute*>(attr);
298     // This function returns a pointer to a CSSValue which can be mutated from JavaScript.
299     // If the associated MappedAttribute uses the same CSSMappedAttributeDeclaration
300     // as StyledElement's mappedAttributeDecls cache, create a new CSSMappedAttributeDeclaration
301     // before returning so that any modifications to the CSSValue will not affect other attributes.
302     MappedAttributeEntry entry;
303     mapToEntry(attributeName, entry);
304     if (getMappedAttributeDecl(entry, cssSVGAttr) == cssSVGAttr->decl()) {
305         cssSVGAttr->setDecl(0);
306         int propId = SVGStyledElement::cssPropertyIdForSVGAttributeName(cssSVGAttr->name());
307         addCSSProperty(cssSVGAttr, propId, cssSVGAttr->value());
308     }
309     return cssSVGAttr->style()->getPropertyCSSValue(name);
310 }
311
312 void SVGStyledElement::detach()
313 {
314     SVGResource::removeClient(this);
315     SVGElement::detach();
316 }
317
318 bool SVGStyledElement::instanceUpdatesBlocked() const
319 {
320     return hasRareSVGData() && rareSVGData()->instanceUpdatesBlocked();
321 }
322
323 void SVGStyledElement::setInstanceUpdatesBlocked(bool value)
324 {
325     if (hasRareSVGData())
326         rareSVGData()->setInstanceUpdatesBlocked(value);
327 }
328
329 AffineTransform SVGStyledElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope) const
330 {
331     // To be overriden by SVGStyledLocatableElement/SVGStyledTransformableElement (or as special case SVGTextElement)
332     ASSERT_NOT_REACHED();
333     return AffineTransform();
334 }
335
336 }
337
338 #endif // ENABLE(SVG)