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