2011-05-01 Nikolas Zimmermann <nzimmermann@rim.com>
[WebKit-https.git] / Source / WebCore / svg / SVGStyledElement.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 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 "PlatformString.h"
32 #include "RenderObject.h"
33 #include "RenderSVGResource.h"
34 #include "RenderSVGResourceClipper.h"
35 #include "RenderSVGResourceFilter.h"
36 #include "RenderSVGResourceMasker.h"
37 #include "SVGElement.h"
38 #include "SVGElementInstance.h"
39 #include "SVGElementRareData.h"
40 #include "SVGNames.h"
41 #include "SVGRenderStyle.h"
42 #include "SVGRenderSupport.h"
43 #include "SVGSVGElement.h"
44 #include "SVGUseElement.h"
45 #include <wtf/Assertions.h>
46 #include <wtf/HashMap.h>
47
48 namespace WebCore {
49
50 // Animated property definitions
51 DEFINE_ANIMATED_STRING(SVGStyledElement, HTMLNames::classAttr, ClassName, className)
52
53 using namespace SVGNames;
54
55 void mapAttributeToCSSProperty(HashMap<AtomicStringImpl*, int>* propertyNameToIdMap, const QualifiedName& attrName)
56 {
57     int propertyId = cssPropertyID(attrName.localName());
58     ASSERT(propertyId > 0);
59     propertyNameToIdMap->set(attrName.localName().impl(), propertyId);
60 }
61
62 SVGStyledElement::SVGStyledElement(const QualifiedName& tagName, Document* document)
63     : SVGElement(tagName, document)
64 {
65 }
66
67 SVGStyledElement::~SVGStyledElement()
68 {
69     if (needsPendingResourceHandling() && hasPendingResources() && document())
70         document()->accessSVGExtensions()->removeElementFromPendingResources(this);
71
72     ASSERT(!hasPendingResources());
73 }
74
75 String SVGStyledElement::title() const
76 {
77     // According to spec, we should not return titles when hovering over root <svg> elements (those
78     // <title> elements are the title of the document, not a tooltip) so we instantly return.
79     if (hasTagName(SVGNames::svgTag)) {
80         const SVGSVGElement* svg = static_cast<const SVGSVGElement*>(this);
81         if (svg->isOutermostSVG())
82             return String();
83     }
84     
85     // Walk up the tree, to find out whether we're inside a <use> shadow tree, to find the right title.
86     Node* parent = const_cast<SVGStyledElement*>(this);
87     while (parent) {
88         if (!parent->isSVGShadowRoot()) {
89             parent = parent->parentNodeGuaranteedHostFree();
90             continue;
91         }
92         
93         // Get the <use> element.
94         Element* shadowParent = parent->svgShadowHost();
95         if (shadowParent && shadowParent->isSVGElement() && shadowParent->hasTagName(SVGNames::useTag)) {
96             SVGUseElement* useElement = static_cast<SVGUseElement*>(shadowParent);
97             // If the <use> title is not empty we found the title to use.
98             String useTitle(useElement->title());
99             if (useTitle.isEmpty())
100                 break;
101             return useTitle;
102         }
103         parent = parent->parentNode();
104     }
105     
106     // If we aren't an instance in a <use> or the <use> title was not found, then find the first
107     // <title> child of this element.
108     Element* titleElement = firstElementChild();
109     for (; titleElement; titleElement = titleElement->nextElementSibling()) {
110         if (titleElement->hasTagName(SVGNames::titleTag) && titleElement->isSVGElement())
111             break;
112     }
113
114     // If a title child was found, return the text contents.
115     if (titleElement)
116         return titleElement->innerText();
117     
118     // Otherwise return a null/empty string.
119     return String();
120 }
121
122 bool SVGStyledElement::rendererIsNeeded(RenderStyle* style)
123 {
124     // http://www.w3.org/TR/SVG/extend.html#PrivateData
125     // Prevent anything other than SVG renderers from appearing in our render tree
126     // Spec: SVG allows inclusion of elements from foreign namespaces anywhere
127     // with the SVG content. In general, the SVG user agent will include the unknown
128     // elements in the DOM but will otherwise ignore unknown elements. 
129     if (!parentNode() || parentNode()->isSVGElement())
130         return StyledElement::rendererIsNeeded(style);
131
132     return false;
133 }
134
135 int SVGStyledElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
136 {
137     if (!attrName.namespaceURI().isNull())
138         return 0;
139     
140     static HashMap<AtomicStringImpl*, int>* propertyNameToIdMap = 0;
141     if (!propertyNameToIdMap) {
142         propertyNameToIdMap = new HashMap<AtomicStringImpl*, int>;
143         // This is a list of all base CSS and SVG CSS properties which are exposed as SVG XML attributes
144         mapAttributeToCSSProperty(propertyNameToIdMap, alignment_baselineAttr);
145         mapAttributeToCSSProperty(propertyNameToIdMap, baseline_shiftAttr);
146         mapAttributeToCSSProperty(propertyNameToIdMap, clipAttr);
147         mapAttributeToCSSProperty(propertyNameToIdMap, clip_pathAttr);
148         mapAttributeToCSSProperty(propertyNameToIdMap, clip_ruleAttr);
149         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::colorAttr);
150         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolationAttr);
151         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolation_filtersAttr);
152         mapAttributeToCSSProperty(propertyNameToIdMap, color_profileAttr);
153         mapAttributeToCSSProperty(propertyNameToIdMap, color_renderingAttr); 
154         mapAttributeToCSSProperty(propertyNameToIdMap, cursorAttr);
155         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::directionAttr);
156         mapAttributeToCSSProperty(propertyNameToIdMap, displayAttr);
157         mapAttributeToCSSProperty(propertyNameToIdMap, dominant_baselineAttr);
158         mapAttributeToCSSProperty(propertyNameToIdMap, enable_backgroundAttr);
159         mapAttributeToCSSProperty(propertyNameToIdMap, fillAttr);
160         mapAttributeToCSSProperty(propertyNameToIdMap, fill_opacityAttr);
161         mapAttributeToCSSProperty(propertyNameToIdMap, fill_ruleAttr);
162         mapAttributeToCSSProperty(propertyNameToIdMap, filterAttr);
163         mapAttributeToCSSProperty(propertyNameToIdMap, flood_colorAttr);
164         mapAttributeToCSSProperty(propertyNameToIdMap, flood_opacityAttr);
165         mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
166         mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
167         mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
168         mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
169         mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
170         mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
171         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_horizontalAttr);
172         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_verticalAttr);
173         mapAttributeToCSSProperty(propertyNameToIdMap, image_renderingAttr);
174         mapAttributeToCSSProperty(propertyNameToIdMap, kerningAttr);
175         mapAttributeToCSSProperty(propertyNameToIdMap, letter_spacingAttr);
176         mapAttributeToCSSProperty(propertyNameToIdMap, lighting_colorAttr);
177         mapAttributeToCSSProperty(propertyNameToIdMap, marker_endAttr);
178         mapAttributeToCSSProperty(propertyNameToIdMap, marker_midAttr);
179         mapAttributeToCSSProperty(propertyNameToIdMap, marker_startAttr);
180         mapAttributeToCSSProperty(propertyNameToIdMap, maskAttr);
181         mapAttributeToCSSProperty(propertyNameToIdMap, opacityAttr);
182         mapAttributeToCSSProperty(propertyNameToIdMap, overflowAttr);
183         mapAttributeToCSSProperty(propertyNameToIdMap, pointer_eventsAttr);
184         mapAttributeToCSSProperty(propertyNameToIdMap, shape_renderingAttr);
185         mapAttributeToCSSProperty(propertyNameToIdMap, stop_colorAttr);
186         mapAttributeToCSSProperty(propertyNameToIdMap, stop_opacityAttr);
187         mapAttributeToCSSProperty(propertyNameToIdMap, strokeAttr);
188         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dasharrayAttr);
189         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dashoffsetAttr);
190         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linecapAttr);
191         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linejoinAttr);
192         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_miterlimitAttr);
193         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_opacityAttr);
194         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_widthAttr);
195         mapAttributeToCSSProperty(propertyNameToIdMap, text_anchorAttr);
196         mapAttributeToCSSProperty(propertyNameToIdMap, text_decorationAttr);
197         mapAttributeToCSSProperty(propertyNameToIdMap, text_renderingAttr);
198         mapAttributeToCSSProperty(propertyNameToIdMap, unicode_bidiAttr);
199         mapAttributeToCSSProperty(propertyNameToIdMap, vector_effectAttr);
200         mapAttributeToCSSProperty(propertyNameToIdMap, visibilityAttr);
201         mapAttributeToCSSProperty(propertyNameToIdMap, word_spacingAttr);
202         mapAttributeToCSSProperty(propertyNameToIdMap, writing_modeAttr);
203     }
204     
205     return propertyNameToIdMap->get(attrName.localName().impl());
206 }
207
208 static inline AttributeToPropertyTypeMap& cssPropertyToTypeMap()
209 {
210     DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_cssPropertyMap, ());
211     
212     if (!s_cssPropertyMap.isEmpty())
213         return s_cssPropertyMap;
214
215     // Fill the map for the first use.
216     s_cssPropertyMap.set(alignment_baselineAttr, AnimatedString);
217     s_cssPropertyMap.set(baseline_shiftAttr, AnimatedString);
218     s_cssPropertyMap.set(clipAttr, AnimatedRect);
219     s_cssPropertyMap.set(clip_pathAttr, AnimatedString);
220     s_cssPropertyMap.set(clip_ruleAttr, AnimatedString);
221     s_cssPropertyMap.set(SVGNames::colorAttr, AnimatedColor);
222     s_cssPropertyMap.set(color_interpolationAttr, AnimatedString);
223     s_cssPropertyMap.set(color_interpolation_filtersAttr, AnimatedString);
224     s_cssPropertyMap.set(color_profileAttr, AnimatedString);
225     s_cssPropertyMap.set(color_renderingAttr, AnimatedString); 
226     s_cssPropertyMap.set(cursorAttr, AnimatedString);
227     s_cssPropertyMap.set(displayAttr, AnimatedString);
228     s_cssPropertyMap.set(dominant_baselineAttr, AnimatedString);
229     s_cssPropertyMap.set(fillAttr, AnimatedColor);
230     s_cssPropertyMap.set(fill_opacityAttr, AnimatedNumber);
231     s_cssPropertyMap.set(fill_ruleAttr, AnimatedString);
232     s_cssPropertyMap.set(filterAttr, AnimatedString);
233     s_cssPropertyMap.set(flood_colorAttr, AnimatedColor);
234     s_cssPropertyMap.set(flood_opacityAttr, AnimatedNumber);
235     s_cssPropertyMap.set(font_familyAttr, AnimatedString);
236     s_cssPropertyMap.set(font_sizeAttr, AnimatedLength);
237     s_cssPropertyMap.set(font_stretchAttr, AnimatedString);
238     s_cssPropertyMap.set(font_styleAttr, AnimatedString);
239     s_cssPropertyMap.set(font_variantAttr, AnimatedString);
240     s_cssPropertyMap.set(font_weightAttr, AnimatedString);
241     s_cssPropertyMap.set(image_renderingAttr, AnimatedString);
242     s_cssPropertyMap.set(kerningAttr, AnimatedLength);
243     s_cssPropertyMap.set(letter_spacingAttr, AnimatedLength);
244     s_cssPropertyMap.set(lighting_colorAttr, AnimatedColor);
245     s_cssPropertyMap.set(marker_endAttr, AnimatedString);
246     s_cssPropertyMap.set(marker_midAttr, AnimatedString);
247     s_cssPropertyMap.set(marker_startAttr, AnimatedString);
248     s_cssPropertyMap.set(maskAttr, AnimatedString);
249     s_cssPropertyMap.set(opacityAttr, AnimatedNumber);
250     s_cssPropertyMap.set(overflowAttr, AnimatedString);
251     s_cssPropertyMap.set(pointer_eventsAttr, AnimatedString);
252     s_cssPropertyMap.set(shape_renderingAttr, AnimatedString);
253     s_cssPropertyMap.set(stop_colorAttr, AnimatedColor);
254     s_cssPropertyMap.set(stop_opacityAttr, AnimatedNumber);
255     s_cssPropertyMap.set(strokeAttr, AnimatedColor);
256     s_cssPropertyMap.set(stroke_dasharrayAttr, AnimatedLengthList);
257     s_cssPropertyMap.set(stroke_dashoffsetAttr, AnimatedLength);
258     s_cssPropertyMap.set(stroke_linecapAttr, AnimatedString);
259     s_cssPropertyMap.set(stroke_linejoinAttr, AnimatedString);
260     s_cssPropertyMap.set(stroke_miterlimitAttr, AnimatedNumber);
261     s_cssPropertyMap.set(stroke_opacityAttr, AnimatedNumber);
262     s_cssPropertyMap.set(stroke_widthAttr, AnimatedLength);
263     s_cssPropertyMap.set(text_anchorAttr, AnimatedString);
264     s_cssPropertyMap.set(text_decorationAttr, AnimatedString);
265     s_cssPropertyMap.set(text_renderingAttr, AnimatedString);
266     s_cssPropertyMap.set(vector_effectAttr, AnimatedString);
267     s_cssPropertyMap.set(visibilityAttr, AnimatedString);
268     s_cssPropertyMap.set(word_spacingAttr, AnimatedLength);
269     return s_cssPropertyMap;
270 }
271
272 AnimatedAttributeType SVGStyledElement::animatedPropertyTypeForCSSProperty(const QualifiedName& attrName)
273 {
274     AttributeToPropertyTypeMap& cssPropertyTypeMap = cssPropertyToTypeMap();
275     if (cssPropertyTypeMap.contains(attrName))
276         return cssPropertyTypeMap.get(attrName);
277     return AnimatedUnknown;
278 }
279
280 bool SVGStyledElement::isAnimatableCSSProperty(const QualifiedName& attrName)
281 {
282     return cssPropertyToTypeMap().contains(attrName);
283 }
284
285 void SVGStyledElement::fillPassedAttributeToPropertyTypeMap(AttributeToPropertyTypeMap& attributeToPropertyTypeMap)
286 {
287     attributeToPropertyTypeMap.set(HTMLNames::classAttr, AnimatedString);
288 }
289
290 bool SVGStyledElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
291 {
292     if (SVGStyledElement::cssPropertyIdForSVGAttributeName(attrName) > 0) {
293         result = eSVG;
294         return false;
295     }
296     return SVGElement::mapToEntry(attrName, result);
297 }
298
299 void SVGStyledElement::parseMappedAttribute(Attribute* attr)
300 {
301     const QualifiedName& attrName = attr->name();
302     // NOTE: Any subclass which overrides parseMappedAttribute for a property handled by
303     // cssPropertyIdForSVGAttributeName will also have to override mapToEntry to disable the default eSVG mapping
304     int propId = SVGStyledElement::cssPropertyIdForSVGAttributeName(attrName);
305     if (propId > 0) {
306         addCSSProperty(attr, propId, attr->value());
307         setNeedsStyleRecalc();
308         return;
309     }
310     
311     // SVG animation has currently requires special storage of values so we set
312     // the className here.  svgAttributeChanged actually causes the resulting
313     // style updates (instead of StyledElement::parseMappedAttribute). We don't
314     // tell StyledElement about the change to avoid parsing the class list twice
315     if (attrName.matches(HTMLNames::classAttr))
316         setClassNameBaseValue(attr->value());
317     else
318         // id is handled by StyledElement which SVGElement inherits from
319         SVGElement::parseMappedAttribute(attr);
320 }
321
322 bool SVGStyledElement::isKnownAttribute(const QualifiedName& attrName)
323 {
324     return isIdAttributeName(attrName);
325 }
326
327 void SVGStyledElement::svgAttributeChanged(const QualifiedName& attrName)
328 {
329     SVGElement::svgAttributeChanged(attrName);
330
331     if (attrName.matches(HTMLNames::classAttr))
332         classAttributeChanged(className());
333
334     RenderObject* object = renderer();
335
336     if (isIdAttributeName(attrName)) {
337         // Notify resources about id changes, this is important as we cache resources by id in SVGDocumentExtensions
338         if (object && object->isSVGResourceContainer())
339             object->toRenderSVGResourceContainer()->idChanged();
340     }
341
342     // Invalidate all SVGElementInstances associated with us
343     SVGElementInstance::invalidateAllInstancesOfElement(this);
344 }
345
346 void SVGStyledElement::synchronizeProperty(const QualifiedName& attrName)
347 {
348     SVGElement::synchronizeProperty(attrName);
349
350     if (attrName == anyQName() || attrName.matches(HTMLNames::classAttr))
351         synchronizeClassName();
352 }
353
354 void SVGStyledElement::attach()
355 {
356     SVGElement::attach();
357
358     if (RenderObject* object = renderer())
359         object->updateFromElement();
360 }
361
362 void SVGStyledElement::insertedIntoDocument()
363 {
364     SVGElement::insertedIntoDocument();
365     updateRelativeLengthsInformation();
366
367     Document* document = this->document();
368     if (!needsPendingResourceHandling() || !document)
369         return;
370
371     SVGDocumentExtensions* extensions = document->accessSVGExtensions();
372     String resourceId = getIdAttribute();
373     if (!extensions->hasPendingResources(resourceId))
374         return;
375
376     OwnPtr<SVGDocumentExtensions::SVGPendingElements> clients(extensions->removePendingResource(resourceId));
377     ASSERT(!clients->isEmpty());
378
379     const SVGDocumentExtensions::SVGPendingElements::const_iterator end = clients->end();
380     for (SVGDocumentExtensions::SVGPendingElements::const_iterator it = clients->begin(); it != end; ++it) {
381         ASSERT((*it)->hasPendingResources());
382         (*it)->buildPendingResource();
383         (*it)->setHasPendingResources(false);
384     }
385 }
386
387 void SVGStyledElement::removedFromDocument()
388 {
389     updateRelativeLengthsInformation(false, this);
390     SVGElement::removedFromDocument();
391
392     Document* document = this->document();
393     if (!needsPendingResourceHandling() || !document)
394         return;
395
396     document->accessSVGExtensions()->removeElementFromPendingResources(this);
397 }
398
399 void SVGStyledElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
400 {
401     SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
402
403     // Invalidate all SVGElementInstances associated with us
404     if (!changedByParser)
405         SVGElementInstance::invalidateAllInstancesOfElement(this);
406 }
407
408 PassRefPtr<RenderStyle> SVGStyledElement::resolveStyle(RenderStyle* parentStyle)
409 {
410     if (renderer())
411         return renderer()->style();
412     return document()->styleSelector()->styleForElement(this, parentStyle);
413 }
414
415 PassRefPtr<CSSValue> SVGStyledElement::getPresentationAttribute(const String& name)
416 {
417     if (!attributeMap())
418         return 0;
419
420     QualifiedName attributeName(nullAtom, name, nullAtom);
421     Attribute* attr = attributeMap()->getAttributeItem(attributeName);
422     if (!attr || !attr->isMappedAttribute() || !attr->style())
423         return 0;
424
425     Attribute* cssSVGAttr = attr;
426     // This function returns a pointer to a CSSValue which can be mutated from JavaScript.
427     // If the associated MappedAttribute uses the same CSSMappedAttributeDeclaration
428     // as StyledElement's mappedAttributeDecls cache, create a new CSSMappedAttributeDeclaration
429     // before returning so that any modifications to the CSSValue will not affect other attributes.
430     MappedAttributeEntry entry;
431     mapToEntry(attributeName, entry);
432     if (getMappedAttributeDecl(entry, cssSVGAttr) == cssSVGAttr->decl()) {
433         cssSVGAttr->setDecl(0);
434         int propId = SVGStyledElement::cssPropertyIdForSVGAttributeName(cssSVGAttr->name());
435         addCSSProperty(cssSVGAttr, propId, cssSVGAttr->value());
436     }
437     return cssSVGAttr->style()->getPropertyCSSValue(name);
438 }
439
440 bool SVGStyledElement::instanceUpdatesBlocked() const
441 {
442     return hasRareSVGData() && rareSVGData()->instanceUpdatesBlocked();
443 }
444
445 void SVGStyledElement::setInstanceUpdatesBlocked(bool value)
446 {
447     if (hasRareSVGData())
448         rareSVGData()->setInstanceUpdatesBlocked(value);
449 }
450
451 bool SVGStyledElement::hasPendingResources() const
452 {
453     return hasRareSVGData() && rareSVGData()->hasPendingResources();
454 }
455
456 void SVGStyledElement::setHasPendingResources(bool value)
457 {
458     ensureRareSVGData()->setHasPendingResources(value);
459 }
460
461 AffineTransform SVGStyledElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope) const
462 {
463     // To be overriden by SVGStyledLocatableElement/SVGStyledTransformableElement (or as special case SVGTextElement)
464     ASSERT_NOT_REACHED();
465     return AffineTransform();
466 }
467
468 void SVGStyledElement::updateRelativeLengthsInformation(bool hasRelativeLengths, SVGStyledElement* element)
469 {
470     // If we're not yet in a document, this function will be called again from insertedIntoDocument(). Do nothing now.
471     if (!inDocument())
472         return;
473
474     // An element wants to notify us that its own relative lengths state changed.
475     // Register it in the relative length map, and register us in the parent relative length map.
476     // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree.
477
478     if (hasRelativeLengths)
479         m_elementsWithRelativeLengths.add(element);
480     else {
481         if (!m_elementsWithRelativeLengths.contains(element)) {
482             // We were never registered. Do nothing.
483             return;
484         }
485
486         m_elementsWithRelativeLengths.remove(element);
487     }
488
489     // Find first styled parent node, and notify it that we've changed our relative length state.
490     ContainerNode* node = parentNode();
491     while (node) {
492         if (!node->isSVGElement())
493             break;
494
495         SVGElement* element = static_cast<SVGElement*>(node);
496         if (!element->isStyled()) {
497             node = node->parentNode();
498             continue;
499         }
500
501         // Register us in the parent element map.
502         static_cast<SVGStyledElement*>(element)->updateRelativeLengthsInformation(hasRelativeLengths, this);
503         break;
504     }
505 }
506
507 }
508
509 #endif // ENABLE(SVG)