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 #include "core/svg/SVGTextPathElement.h" 23 24 #include "core/XLinkNames.h" 25 #include "core/rendering/svg/RenderSVGResource.h" 26 #include "core/rendering/svg/RenderSVGTextPath.h" 27 #include "core/svg/SVGDocumentExtensions.h" 28 29 namespace blink { 30 31 template<> const SVGEnumerationStringEntries& getStaticStringEntries<SVGTextPathMethodType>() 32 { 33 DEFINE_STATIC_LOCAL(SVGEnumerationStringEntries, entries, ()); 34 if (entries.isEmpty()) { 35 entries.append(std::make_pair(SVGTextPathMethodAlign, "align")); 36 entries.append(std::make_pair(SVGTextPathMethodStretch, "stretch")); 37 } 38 return entries; 39 } 40 41 template<> const SVGEnumerationStringEntries& getStaticStringEntries<SVGTextPathSpacingType>() 42 { 43 DEFINE_STATIC_LOCAL(SVGEnumerationStringEntries, entries, ()); 44 if (entries.isEmpty()) { 45 entries.append(std::make_pair(SVGTextPathSpacingAuto, "auto")); 46 entries.append(std::make_pair(SVGTextPathSpacingExact, "exact")); 47 } 48 return entries; 49 } 50 51 inline SVGTextPathElement::SVGTextPathElement(Document& document) 52 : SVGTextContentElement(SVGNames::textPathTag, document) 53 , SVGURIReference(this) 54 , m_startOffset(SVGAnimatedLength::create(this, SVGNames::startOffsetAttr, SVGLength::create(LengthModeOther), AllowNegativeLengths)) 55 , m_method(SVGAnimatedEnumeration<SVGTextPathMethodType>::create(this, SVGNames::methodAttr, SVGTextPathMethodAlign)) 56 , m_spacing(SVGAnimatedEnumeration<SVGTextPathSpacingType>::create(this, SVGNames::spacingAttr, SVGTextPathSpacingExact)) 57 { 58 addToPropertyMap(m_startOffset); 59 addToPropertyMap(m_method); 60 addToPropertyMap(m_spacing); 61 } 62 63 DEFINE_NODE_FACTORY(SVGTextPathElement) 64 65 SVGTextPathElement::~SVGTextPathElement() 66 { 67 #if !ENABLE(OILPAN) 68 clearResourceReferences(); 69 #endif 70 } 71 72 void SVGTextPathElement::clearResourceReferences() 73 { 74 removeAllOutgoingReferences(); 75 } 76 77 bool SVGTextPathElement::isSupportedAttribute(const QualifiedName& attrName) 78 { 79 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 80 if (supportedAttributes.isEmpty()) { 81 SVGURIReference::addSupportedAttributes(supportedAttributes); 82 supportedAttributes.add(SVGNames::startOffsetAttr); 83 supportedAttributes.add(SVGNames::methodAttr); 84 supportedAttributes.add(SVGNames::spacingAttr); 85 } 86 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); 87 } 88 89 void SVGTextPathElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 90 { 91 SVGParsingError parseError = NoError; 92 93 if (!isSupportedAttribute(name)) 94 SVGTextContentElement::parseAttribute(name, value); 95 else if (name == SVGNames::startOffsetAttr) 96 m_startOffset->setBaseValueAsString(value, parseError); 97 else if (name == SVGNames::methodAttr) 98 m_method->setBaseValueAsString(value, parseError); 99 else if (name == SVGNames::spacingAttr) 100 m_spacing->setBaseValueAsString(value, parseError); 101 else if (SVGURIReference::parseAttribute(name, value, parseError)) { 102 } else 103 ASSERT_NOT_REACHED(); 104 105 reportAttributeParsingError(parseError, name, value); 106 } 107 108 void SVGTextPathElement::svgAttributeChanged(const QualifiedName& attrName) 109 { 110 if (!isSupportedAttribute(attrName)) { 111 SVGTextContentElement::svgAttributeChanged(attrName); 112 return; 113 } 114 115 SVGElement::InvalidationGuard invalidationGuard(this); 116 117 if (SVGURIReference::isKnownAttribute(attrName)) { 118 buildPendingResource(); 119 return; 120 } 121 122 if (attrName == SVGNames::startOffsetAttr) 123 updateRelativeLengthsInformation(); 124 125 if (RenderObject* object = renderer()) 126 RenderSVGResource::markForLayoutAndParentResourceInvalidation(object); 127 } 128 129 RenderObject* SVGTextPathElement::createRenderer(RenderStyle*) 130 { 131 return new RenderSVGTextPath(this); 132 } 133 134 bool SVGTextPathElement::rendererIsNeeded(const RenderStyle& style) 135 { 136 if (parentNode() && (isSVGAElement(*parentNode()) || isSVGTextElement(*parentNode()))) 137 return Element::rendererIsNeeded(style); 138 139 return false; 140 } 141 142 void SVGTextPathElement::buildPendingResource() 143 { 144 clearResourceReferences(); 145 if (!inDocument()) 146 return; 147 148 AtomicString id; 149 Element* target = SVGURIReference::targetElementFromIRIString(hrefString(), treeScope(), &id); 150 if (!target) { 151 // Do not register as pending if we are already pending this resource. 152 if (document().accessSVGExtensions().isElementPendingResource(this, id)) 153 return; 154 155 if (!id.isEmpty()) { 156 document().accessSVGExtensions().addPendingResource(id, this); 157 ASSERT(hasPendingResources()); 158 } 159 } else if (isSVGPathElement(*target)) { 160 // Register us with the target in the dependencies map. Any change of hrefElement 161 // that leads to relayout/repainting now informs us, so we can react to it. 162 addReferenceTo(toSVGElement((target))); 163 } 164 } 165 166 Node::InsertionNotificationRequest SVGTextPathElement::insertedInto(ContainerNode* rootParent) 167 { 168 SVGTextContentElement::insertedInto(rootParent); 169 buildPendingResource(); 170 return InsertionDone; 171 } 172 173 void SVGTextPathElement::removedFrom(ContainerNode* rootParent) 174 { 175 SVGTextContentElement::removedFrom(rootParent); 176 if (rootParent->inDocument()) 177 clearResourceReferences(); 178 } 179 180 bool SVGTextPathElement::selfHasRelativeLengths() const 181 { 182 return m_startOffset->currentValue()->isRelative() 183 || SVGTextContentElement::selfHasRelativeLengths(); 184 } 185 186 } // namespace blink 187