Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005, 2007 Rob Buis <buis (at) kde.org>
      4  * Copyright (C) 2007 Eric Seidel <eric (at) webkit.org>
      5  * Copyright (C) 2010 Apple Inc. All rights reserved.
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Library General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Library General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Library General Public License
     18  * along with this library; see the file COPYING.LIB.  If not, write to
     19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20  * Boston, MA 02110-1301, USA.
     21  */
     22 
     23 #include "config.h"
     24 
     25 #include "core/svg/SVGAElement.h"
     26 
     27 #include "SVGNames.h"
     28 #include "XLinkNames.h"
     29 #include "core/dom/Attr.h"
     30 #include "core/dom/Attribute.h"
     31 #include "core/dom/Document.h"
     32 #include "core/dom/EventNames.h"
     33 #include "core/dom/KeyboardEvent.h"
     34 #include "core/dom/MouseEvent.h"
     35 #include "core/dom/NodeRenderingContext.h"
     36 #include "core/html/HTMLAnchorElement.h"
     37 #include "core/html/HTMLFormElement.h"
     38 #include "core/html/parser/HTMLParserIdioms.h"
     39 #include "core/loader/FrameLoadRequest.h"
     40 #include "core/loader/FrameLoader.h"
     41 #include "core/loader/FrameLoaderTypes.h"
     42 #include "core/page/Chrome.h"
     43 #include "core/page/ChromeClient.h"
     44 #include "core/page/Frame.h"
     45 #include "core/page/Page.h"
     46 #include "core/platform/PlatformMouseEvent.h"
     47 #include "core/platform/network/ResourceRequest.h"
     48 #include "core/rendering/svg/RenderSVGInline.h"
     49 #include "core/rendering/svg/RenderSVGText.h"
     50 #include "core/rendering/svg/RenderSVGTransformableContainer.h"
     51 #include "core/svg/SVGElementInstance.h"
     52 #include "core/svg/animation/SVGSMILElement.h"
     53 
     54 namespace WebCore {
     55 
     56 using namespace HTMLNames;
     57 
     58 // Animated property definitions
     59 DEFINE_ANIMATED_STRING(SVGAElement, SVGNames::targetAttr, SVGTarget, svgTarget)
     60 DEFINE_ANIMATED_STRING(SVGAElement, XLinkNames::hrefAttr, Href, href)
     61 DEFINE_ANIMATED_BOOLEAN(SVGAElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
     62 
     63 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGAElement)
     64     REGISTER_LOCAL_ANIMATED_PROPERTY(svgTarget)
     65     REGISTER_LOCAL_ANIMATED_PROPERTY(href)
     66     REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
     67     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement)
     68 END_REGISTER_ANIMATED_PROPERTIES
     69 
     70 inline SVGAElement::SVGAElement(const QualifiedName& tagName, Document* document)
     71     : SVGGraphicsElement(tagName, document)
     72 {
     73     ASSERT(hasTagName(SVGNames::aTag));
     74     ScriptWrappable::init(this);
     75     registerAnimatedPropertiesForSVGAElement();
     76 }
     77 
     78 PassRefPtr<SVGAElement> SVGAElement::create(const QualifiedName& tagName, Document* document)
     79 {
     80     return adoptRef(new SVGAElement(tagName, document));
     81 }
     82 
     83 String SVGAElement::title() const
     84 {
     85     // If the xlink:title is set (non-empty string), use it.
     86     const AtomicString& title = fastGetAttribute(XLinkNames::titleAttr);
     87     if (!title.isEmpty())
     88         return title;
     89 
     90     // Otherwise, use the title of this element.
     91     return SVGElement::title();
     92 }
     93 
     94 bool SVGAElement::isSupportedAttribute(const QualifiedName& attrName)
     95 {
     96     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
     97     if (supportedAttributes.isEmpty()) {
     98         SVGURIReference::addSupportedAttributes(supportedAttributes);
     99         SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
    100         supportedAttributes.add(SVGNames::targetAttr);
    101     }
    102     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
    103 }
    104 
    105 void SVGAElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    106 {
    107     if (!isSupportedAttribute(name)) {
    108         SVGGraphicsElement::parseAttribute(name, value);
    109         return;
    110     }
    111 
    112     if (name == SVGNames::targetAttr) {
    113         setSVGTargetBaseValue(value);
    114         return;
    115     }
    116 
    117     if (SVGURIReference::parseAttribute(name, value))
    118         return;
    119     if (SVGExternalResourcesRequired::parseAttribute(name, value))
    120         return;
    121 
    122     ASSERT_NOT_REACHED();
    123 }
    124 
    125 void SVGAElement::svgAttributeChanged(const QualifiedName& attrName)
    126 {
    127     if (!isSupportedAttribute(attrName)) {
    128         SVGGraphicsElement::svgAttributeChanged(attrName);
    129         return;
    130     }
    131 
    132     SVGElementInstance::InvalidationGuard invalidationGuard(this);
    133 
    134     // Unlike other SVG*Element classes, SVGAElement only listens to SVGURIReference changes
    135     // as none of the other properties changes the linking behaviour for our <a> element.
    136     if (SVGURIReference::isKnownAttribute(attrName)) {
    137         bool wasLink = isLink();
    138         setIsLink(!hrefCurrentValue().isNull());
    139 
    140         if (wasLink != isLink())
    141             setNeedsStyleRecalc();
    142     }
    143 }
    144 
    145 RenderObject* SVGAElement::createRenderer(RenderStyle*)
    146 {
    147     if (parentNode() && parentNode()->isSVGElement() && toSVGElement(parentNode())->isTextContent())
    148         return new RenderSVGInline(this);
    149 
    150     return new RenderSVGTransformableContainer(this);
    151 }
    152 
    153 void SVGAElement::defaultEventHandler(Event* event)
    154 {
    155     if (isLink()) {
    156         if (focused() && isEnterKeyKeydownEvent(event)) {
    157             event->setDefaultHandled();
    158             dispatchSimulatedClick(event);
    159             return;
    160         }
    161 
    162         if (isLinkClick(event)) {
    163             String url = stripLeadingAndTrailingHTMLSpaces(hrefCurrentValue());
    164 
    165             if (url[0] == '#') {
    166                 Element* targetElement = treeScope()->getElementById(url.substring(1));
    167                 if (SVGSMILElement::isSMILElement(targetElement)) {
    168                     toSVGSMILElement(targetElement)->beginByLinkActivation();
    169                     event->setDefaultHandled();
    170                     return;
    171                 }
    172                 // Only allow navigation to internal <view> anchors.
    173                 if (targetElement && !targetElement->hasTagName(SVGNames::viewTag))
    174                     return;
    175             }
    176 
    177             String target = this->target();
    178             if (target.isEmpty() && fastGetAttribute(XLinkNames::showAttr) == "new")
    179                 target = "_blank";
    180             event->setDefaultHandled();
    181 
    182             Frame* frame = document()->frame();
    183             if (!frame)
    184                 return;
    185             FrameLoadRequest frameRequest(document()->securityOrigin(), ResourceRequest(document()->completeURL(url)), target);
    186             frameRequest.setTriggeringEvent(event);
    187             frame->loader()->load(frameRequest);
    188             return;
    189         }
    190     }
    191 
    192     SVGGraphicsElement::defaultEventHandler(event);
    193 }
    194 
    195 bool SVGAElement::supportsFocus() const
    196 {
    197     if (rendererIsEditable())
    198         return SVGGraphicsElement::supportsFocus();
    199     return true;
    200 }
    201 
    202 bool SVGAElement::rendererIsFocusable() const
    203 {
    204     if (renderer() && renderer()->absoluteClippedOverflowRect().isEmpty())
    205         return false;
    206 
    207     return SVGElement::rendererIsFocusable();
    208 }
    209 
    210 bool SVGAElement::isURLAttribute(const Attribute& attribute) const
    211 {
    212     return attribute.name().localName() == hrefAttr || SVGGraphicsElement::isURLAttribute(attribute);
    213 }
    214 
    215 bool SVGAElement::isMouseFocusable() const
    216 {
    217     return false;
    218 }
    219 
    220 bool SVGAElement::isKeyboardFocusable() const
    221 {
    222     if (!isFocusable())
    223         return false;
    224 
    225     Page* page = document()->page();
    226     if (!page)
    227         return false;
    228 
    229     return page->chrome().client()->tabsToLinks();
    230 }
    231 
    232 bool SVGAElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
    233 {
    234     // http://www.w3.org/2003/01/REC-SVG11-20030114-errata#linking-text-environment
    235     // The 'a' element may contain any element that its parent may contain, except itself.
    236     if (childContext.node()->hasTagName(SVGNames::aTag))
    237         return false;
    238     if (parentNode() && parentNode()->isSVGElement())
    239         return parentNode()->childShouldCreateRenderer(childContext);
    240 
    241     return SVGElement::childShouldCreateRenderer(childContext);
    242 }
    243 
    244 } // namespace WebCore
    245