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