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