1 /* 2 * Copyright (C) 2007 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2010 Rob Buis <rwlbuis (at) gmail.com> 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 "SVGTextPathElement.h" 25 26 #include "Attribute.h" 27 #include "RenderSVGResource.h" 28 #include "RenderSVGTextPath.h" 29 #include "SVGNames.h" 30 31 namespace WebCore { 32 33 // Animated property definitions 34 DEFINE_ANIMATED_LENGTH(SVGTextPathElement, SVGNames::startOffsetAttr, StartOffset, startOffset) 35 DEFINE_ANIMATED_ENUMERATION(SVGTextPathElement, SVGNames::methodAttr, Method, method) 36 DEFINE_ANIMATED_ENUMERATION(SVGTextPathElement, SVGNames::spacingAttr, Spacing, spacing) 37 DEFINE_ANIMATED_STRING(SVGTextPathElement, XLinkNames::hrefAttr, Href, href) 38 39 inline SVGTextPathElement::SVGTextPathElement(const QualifiedName& tagName, Document* document) 40 : SVGTextContentElement(tagName, document) 41 , m_startOffset(LengthModeOther) 42 , m_method(SVG_TEXTPATH_METHODTYPE_ALIGN) 43 , m_spacing(SVG_TEXTPATH_SPACINGTYPE_EXACT) 44 { 45 } 46 47 PassRefPtr<SVGTextPathElement> SVGTextPathElement::create(const QualifiedName& tagName, Document* document) 48 { 49 return adoptRef(new SVGTextPathElement(tagName, document)); 50 } 51 52 void SVGTextPathElement::parseMappedAttribute(Attribute* attr) 53 { 54 const String& value = attr->value(); 55 56 if (attr->name() == SVGNames::startOffsetAttr) 57 setStartOffsetBaseValue(SVGLength(LengthModeOther, value)); 58 else if (attr->name() == SVGNames::methodAttr) { 59 if (value == "align") 60 setSpacingBaseValue(SVG_TEXTPATH_METHODTYPE_ALIGN); 61 else if (value == "stretch") 62 setSpacingBaseValue(SVG_TEXTPATH_METHODTYPE_STRETCH); 63 } else if (attr->name() == SVGNames::spacingAttr) { 64 if (value == "auto") 65 setMethodBaseValue(SVG_TEXTPATH_SPACINGTYPE_AUTO); 66 else if (value == "exact") 67 setMethodBaseValue(SVG_TEXTPATH_SPACINGTYPE_EXACT); 68 } else { 69 if (SVGURIReference::parseMappedAttribute(attr)) 70 return; 71 SVGTextContentElement::parseMappedAttribute(attr); 72 } 73 } 74 75 void SVGTextPathElement::svgAttributeChanged(const QualifiedName& attrName) 76 { 77 SVGTextContentElement::svgAttributeChanged(attrName); 78 79 if (attrName == SVGNames::startOffsetAttr) 80 updateRelativeLengthsInformation(); 81 82 if (!renderer()) 83 return; 84 85 if (attrName == SVGNames::startOffsetAttr 86 || SVGURIReference::isKnownAttribute(attrName)) 87 RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer()); 88 } 89 90 void SVGTextPathElement::synchronizeProperty(const QualifiedName& attrName) 91 { 92 SVGTextContentElement::synchronizeProperty(attrName); 93 94 if (attrName == anyQName()) { 95 synchronizeStartOffset(); 96 synchronizeMethod(); 97 synchronizeSpacing(); 98 synchronizeHref(); 99 return; 100 } 101 102 if (attrName == SVGNames::startOffsetAttr) 103 synchronizeStartOffset(); 104 else if (attrName == SVGNames::methodAttr) 105 synchronizeMethod(); 106 else if (attrName == SVGNames::spacingAttr) 107 synchronizeSpacing(); 108 else if (SVGURIReference::isKnownAttribute(attrName)) 109 synchronizeHref(); 110 } 111 112 AttributeToPropertyTypeMap& SVGTextPathElement::attributeToPropertyTypeMap() 113 { 114 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ()); 115 return s_attributeToPropertyTypeMap; 116 } 117 118 void SVGTextPathElement::fillAttributeToPropertyTypeMap() 119 { 120 AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap(); 121 122 SVGTextContentElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap); 123 attributeToPropertyTypeMap.set(SVGNames::startOffsetAttr, AnimatedLength); 124 attributeToPropertyTypeMap.set(SVGNames::methodAttr, AnimatedEnumeration); 125 attributeToPropertyTypeMap.set(SVGNames::spacingAttr, AnimatedEnumeration); 126 attributeToPropertyTypeMap.set(XLinkNames::hrefAttr, AnimatedString); 127 } 128 129 RenderObject* SVGTextPathElement::createRenderer(RenderArena* arena, RenderStyle*) 130 { 131 return new (arena) RenderSVGTextPath(this); 132 } 133 134 bool SVGTextPathElement::childShouldCreateRenderer(Node* child) const 135 { 136 if (child->isTextNode() 137 || child->hasTagName(SVGNames::aTag) 138 || child->hasTagName(SVGNames::trefTag) 139 || child->hasTagName(SVGNames::tspanTag)) 140 return true; 141 142 return false; 143 } 144 145 bool SVGTextPathElement::rendererIsNeeded(RenderStyle* style) 146 { 147 if (parentNode() 148 && (parentNode()->hasTagName(SVGNames::aTag) 149 || parentNode()->hasTagName(SVGNames::textTag))) 150 return StyledElement::rendererIsNeeded(style); 151 152 return false; 153 } 154 155 void SVGTextPathElement::insertedIntoDocument() 156 { 157 SVGTextContentElement::insertedIntoDocument(); 158 159 String id = SVGURIReference::getTarget(href()); 160 Element* targetElement = ownerDocument()->getElementById(id); 161 if (!targetElement) { 162 document()->accessSVGExtensions()->addPendingResource(id, this); 163 return; 164 } 165 } 166 167 bool SVGTextPathElement::selfHasRelativeLengths() const 168 { 169 return startOffset().isRelative() 170 || SVGTextContentElement::selfHasRelativeLengths(); 171 } 172 173 } 174 175 #endif // ENABLE(SVG) 176