Home | History | Annotate | Download | only in svg
      1 /*
      2     Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3                   2004, 2005, 2007 Rob Buis <buis (at) kde.org>
      4                   2007 Eric Seidel <eric (at) webkit.org>
      5 
      6     This library is free software; you can redistribute it and/or
      7     modify it under the terms of the GNU Library General Public
      8     License as published by the Free Software Foundation; either
      9     version 2 of the License, or (at your option) any later version.
     10 
     11     This library is distributed in the hope that it will be useful,
     12     but WITHOUT ANY WARRANTY; without even the implied warranty of
     13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14     Library General Public License for more details.
     15 
     16     You should have received a copy of the GNU Library General Public License
     17     along with this library; see the file COPYING.LIB.  If not, write to
     18     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     19     Boston, MA 02110-1301, USA.
     20 */
     21 
     22 #include "config.h"
     23 
     24 #if ENABLE(SVG)
     25 #include "SVGAElement.h"
     26 
     27 #include "Attr.h"
     28 #include "CSSHelper.h"
     29 #include "Document.h"
     30 #include "EventHandler.h"
     31 #include "EventNames.h"
     32 #include "Frame.h"
     33 #include "FrameLoader.h"
     34 #include "FrameLoaderTypes.h"
     35 #include "KeyboardEvent.h"
     36 #include "MappedAttribute.h"
     37 #include "MouseEvent.h"
     38 #include "PlatformMouseEvent.h"
     39 #include "RenderSVGInline.h"
     40 #include "RenderSVGTransformableContainer.h"
     41 #include "ResourceRequest.h"
     42 #include "SVGNames.h"
     43 #include "SVGSMILElement.h"
     44 #include "XLinkNames.h"
     45 
     46 namespace WebCore {
     47 
     48 SVGAElement::SVGAElement(const QualifiedName& tagName, Document *doc)
     49     : SVGStyledTransformableElement(tagName, doc)
     50     , SVGURIReference()
     51     , SVGTests()
     52     , SVGLangSpace()
     53     , SVGExternalResourcesRequired()
     54 {
     55 }
     56 
     57 SVGAElement::~SVGAElement()
     58 {
     59 }
     60 
     61 String SVGAElement::title() const
     62 {
     63     return getAttribute(XLinkNames::titleAttr);
     64 }
     65 
     66 void SVGAElement::parseMappedAttribute(MappedAttribute* attr)
     67 {
     68     if (attr->name() == SVGNames::targetAttr)
     69         setTargetBaseValue(attr->value());
     70     else {
     71         if (SVGURIReference::parseMappedAttribute(attr))
     72             return;
     73         if (SVGTests::parseMappedAttribute(attr))
     74             return;
     75         if (SVGLangSpace::parseMappedAttribute(attr))
     76             return;
     77         if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
     78             return;
     79         SVGStyledTransformableElement::parseMappedAttribute(attr);
     80     }
     81 }
     82 
     83 void SVGAElement::svgAttributeChanged(const QualifiedName& attrName)
     84 {
     85     SVGStyledTransformableElement::svgAttributeChanged(attrName);
     86 
     87     // Unlike other SVG*Element classes, SVGAElement only listens to SVGURIReference changes
     88     // as none of the other properties changes the linking behaviour for our <a> element.
     89     if (SVGURIReference::isKnownAttribute(attrName)) {
     90         bool wasLink = isLink();
     91         setIsLink(!href().isNull());
     92 
     93         if (wasLink != isLink())
     94             setNeedsStyleRecalc();
     95     }
     96 }
     97 
     98 void SVGAElement::synchronizeProperty(const QualifiedName& attrName)
     99 {
    100     SVGStyledTransformableElement::synchronizeProperty(attrName);
    101 
    102     if (attrName == anyQName()) {
    103         synchronizeTarget();
    104         synchronizeHref();
    105         synchronizeExternalResourcesRequired();
    106         return;
    107     }
    108 
    109     if (attrName == SVGNames::targetAttr)
    110         synchronizeTarget();
    111     else if (SVGURIReference::isKnownAttribute(attrName))
    112         synchronizeHref();
    113     else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
    114         synchronizeExternalResourcesRequired();
    115 }
    116 
    117 RenderObject* SVGAElement::createRenderer(RenderArena* arena, RenderStyle*)
    118 {
    119     if (static_cast<SVGElement*>(parent())->isTextContent())
    120         return new (arena) RenderSVGInline(this);
    121 
    122     return new (arena) RenderSVGTransformableContainer(this);
    123 }
    124 
    125 void SVGAElement::defaultEventHandler(Event* evt)
    126 {
    127     if (isLink() && (evt->type() == eventNames().clickEvent || (evt->type() == eventNames().keydownEvent && focused()))) {
    128         MouseEvent* e = 0;
    129         if (evt->type() == eventNames().clickEvent && evt->isMouseEvent())
    130             e = static_cast<MouseEvent*>(evt);
    131 
    132         KeyboardEvent* k = 0;
    133         if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent())
    134             k = static_cast<KeyboardEvent*>(evt);
    135 
    136         if (e && e->button() == RightButton) {
    137             SVGStyledTransformableElement::defaultEventHandler(evt);
    138             return;
    139         }
    140 
    141         if (k) {
    142             if (k->keyIdentifier() != "Enter") {
    143                 SVGStyledTransformableElement::defaultEventHandler(evt);
    144                 return;
    145             }
    146             evt->setDefaultHandled();
    147             dispatchSimulatedClick(evt);
    148             return;
    149         }
    150 
    151         String target = this->target();
    152         if (e && e->button() == MiddleButton)
    153             target = "_blank";
    154         else if (target.isEmpty()) // if target is empty, default to "_self" or use xlink:target if set
    155             target = (getAttribute(XLinkNames::showAttr) == "new") ? "_blank" : "_self";
    156 
    157         if (!evt->defaultPrevented()) {
    158             String url = deprecatedParseURL(href());
    159 #if ENABLE(SVG_ANIMATION)
    160             if (url.startsWith("#")) {
    161                 Element* targetElement = document()->getElementById(url.substring(1));
    162                 if (SVGSMILElement::isSMILElement(targetElement)) {
    163                     SVGSMILElement* timed = static_cast<SVGSMILElement*>(targetElement);
    164                     timed->beginByLinkActivation();
    165                     evt->setDefaultHandled();
    166                     SVGStyledTransformableElement::defaultEventHandler(evt);
    167                     return;
    168                 }
    169             }
    170 #endif
    171             if (document()->frame())
    172                 document()->frame()->loader()->urlSelected(document()->completeURL(url), target, evt, false, false, true, SendReferrer);
    173         }
    174 
    175         evt->setDefaultHandled();
    176     }
    177 
    178     SVGStyledTransformableElement::defaultEventHandler(evt);
    179 }
    180 
    181 bool SVGAElement::supportsFocus() const
    182 {
    183     if (isContentEditable())
    184         return SVGStyledTransformableElement::supportsFocus();
    185     return true;
    186 }
    187 
    188 bool SVGAElement::isFocusable() const
    189 {
    190     if (renderer() && renderer()->absoluteClippedOverflowRect().isEmpty())
    191         return false;
    192 
    193     return SVGElement::isFocusable();
    194 }
    195 
    196 bool SVGAElement::isMouseFocusable() const
    197 {
    198     return false;
    199 }
    200 
    201 bool SVGAElement::isKeyboardFocusable(KeyboardEvent* event) const
    202 {
    203     if (!isFocusable())
    204         return false;
    205 
    206     if (!document()->frame())
    207         return false;
    208 
    209     return document()->frame()->eventHandler()->tabsToLinks(event);
    210 }
    211 
    212 bool SVGAElement::childShouldCreateRenderer(Node* child) const
    213 {
    214     // http://www.w3.org/2003/01/REC-SVG11-20030114-errata#linking-text-environment
    215     // The 'a' element may contain any element that its parent may contain, except itself.
    216     if (child->hasTagName(SVGNames::aTag))
    217         return false;
    218     if (parent() && parent()->isSVGElement())
    219         return static_cast<SVGElement*>(parent())->childShouldCreateRenderer(child);
    220 
    221     return SVGElement::childShouldCreateRenderer(child);
    222 }
    223 
    224 } // namespace WebCore
    225 
    226 #endif // ENABLE(SVG)
    227