Home | History | Annotate | Download | only in svg
      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