WebCore/html/HTMLAreaElement.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
       
     3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
       
     4  * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved.
       
     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 #include "HTMLAreaElement.h"
       
    24 
       
    25 #include "Attribute.h"
       
    26 #include "HTMLImageElement.h"
       
    27 #include "HTMLMapElement.h"
       
    28 #include "HTMLNames.h"
       
    29 #include "HitTestResult.h"
       
    30 #include "Path.h"
       
    31 #include "RenderObject.h"
       
    32 
       
    33 using namespace std;
       
    34 
       
    35 namespace WebCore {
       
    36 
       
    37 using namespace HTMLNames;
       
    38 
       
    39 inline HTMLAreaElement::HTMLAreaElement(const QualifiedName& tagName, Document* document)
       
    40     : HTMLAnchorElement(tagName, document)
       
    41     , m_coordsLen(0)
       
    42     , m_lastSize(-1, -1)
       
    43     , m_shape(Unknown)
       
    44 {
       
    45     ASSERT(hasTagName(areaTag));
       
    46 }
       
    47 
       
    48 PassRefPtr<HTMLAreaElement> HTMLAreaElement::create(const QualifiedName& tagName, Document* document)
       
    49 {
       
    50     return adoptRef(new HTMLAreaElement(tagName, document));
       
    51 }
       
    52 
       
    53 void HTMLAreaElement::parseMappedAttribute(Attribute* attr)
       
    54 {
       
    55     if (attr->name() == shapeAttr) {
       
    56         if (equalIgnoringCase(attr->value(), "default"))
       
    57             m_shape = Default;
       
    58         else if (equalIgnoringCase(attr->value(), "circle"))
       
    59             m_shape = Circle;
       
    60         else if (equalIgnoringCase(attr->value(), "poly"))
       
    61             m_shape = Poly;
       
    62         else if (equalIgnoringCase(attr->value(), "rect"))
       
    63             m_shape = Rect;
       
    64     } else if (attr->name() == coordsAttr) {
       
    65         m_coords.set(newCoordsArray(attr->value().string(), m_coordsLen));
       
    66     } else if (attr->name() == altAttr || attr->name() == accesskeyAttr) {
       
    67         // Do nothing.
       
    68     } else
       
    69         HTMLAnchorElement::parseMappedAttribute(attr);
       
    70 }
       
    71 
       
    72 bool HTMLAreaElement::mapMouseEvent(int x, int y, const IntSize& size, HitTestResult& result)
       
    73 {
       
    74     if (m_lastSize != size) {
       
    75         m_region.set(new Path(getRegion(size)));
       
    76         m_lastSize = size;
       
    77     }
       
    78 
       
    79     if (!m_region->contains(IntPoint(x, y)))
       
    80         return false;
       
    81     
       
    82     result.setInnerNode(this);
       
    83     result.setURLElement(this);
       
    84     return true;
       
    85 }
       
    86 
       
    87 Path HTMLAreaElement::getPath(RenderObject* obj) const
       
    88 {
       
    89     if (!obj)
       
    90         return Path();
       
    91     
       
    92     // FIXME: This doesn't work correctly with transforms.
       
    93     FloatPoint absPos = obj->localToAbsolute();
       
    94 
       
    95     // Default should default to the size of the containing object.
       
    96     IntSize size = m_lastSize;
       
    97     if (m_shape == Default)
       
    98         size = obj->absoluteOutlineBounds().size();
       
    99     
       
   100     Path p = getRegion(size);
       
   101     p.translate(absPos - FloatPoint());
       
   102     return p;
       
   103 }
       
   104     
       
   105 IntRect HTMLAreaElement::getRect(RenderObject* obj) const
       
   106 {
       
   107     return enclosingIntRect(getPath(obj).boundingRect());
       
   108 }
       
   109 
       
   110 Path HTMLAreaElement::getRegion(const IntSize& size) const
       
   111 {
       
   112     if (!m_coords && m_shape != Default)
       
   113         return Path();
       
   114 
       
   115     int width = size.width();
       
   116     int height = size.height();
       
   117 
       
   118     // If element omits the shape attribute, select shape based on number of coordinates.
       
   119     Shape shape = m_shape;
       
   120     if (shape == Unknown) {
       
   121         if (m_coordsLen == 3)
       
   122             shape = Circle;
       
   123         else if (m_coordsLen == 4)
       
   124             shape = Rect;
       
   125         else if (m_coordsLen >= 6)
       
   126             shape = Poly;
       
   127     }
       
   128 
       
   129     Path path;
       
   130     switch (shape) {
       
   131         case Poly:
       
   132             if (m_coordsLen >= 6) {
       
   133                 int numPoints = m_coordsLen / 2;
       
   134                 path.moveTo(FloatPoint(m_coords[0].calcMinValue(width), m_coords[1].calcMinValue(height)));
       
   135                 for (int i = 1; i < numPoints; ++i)
       
   136                     path.addLineTo(FloatPoint(m_coords[i * 2].calcMinValue(width), m_coords[i * 2 + 1].calcMinValue(height)));
       
   137                 path.closeSubpath();
       
   138             }
       
   139             break;
       
   140         case Circle:
       
   141             if (m_coordsLen >= 3) {
       
   142                 Length radius = m_coords[2];
       
   143                 int r = min(radius.calcMinValue(width), radius.calcMinValue(height));
       
   144                 path.addEllipse(FloatRect(m_coords[0].calcMinValue(width) - r, m_coords[1].calcMinValue(height) - r, 2 * r, 2 * r));
       
   145             }
       
   146             break;
       
   147         case Rect:
       
   148             if (m_coordsLen >= 4) {
       
   149                 int x0 = m_coords[0].calcMinValue(width);
       
   150                 int y0 = m_coords[1].calcMinValue(height);
       
   151                 int x1 = m_coords[2].calcMinValue(width);
       
   152                 int y1 = m_coords[3].calcMinValue(height);
       
   153                 path.addRect(FloatRect(x0, y0, x1 - x0, y1 - y0));
       
   154             }
       
   155             break;
       
   156         case Default:
       
   157             path.addRect(FloatRect(0, 0, width, height));
       
   158             break;
       
   159         case Unknown:
       
   160             break;
       
   161     }
       
   162 
       
   163     return path;
       
   164 }
       
   165 
       
   166 HTMLImageElement* HTMLAreaElement::imageElement() const
       
   167 {
       
   168     Node* mapElement = parent();
       
   169     if (!mapElement->hasTagName(mapTag))
       
   170         return 0;
       
   171     
       
   172     return static_cast<HTMLMapElement*>(mapElement)->imageElement();
       
   173 }
       
   174 
       
   175 bool HTMLAreaElement::isKeyboardFocusable(KeyboardEvent*) const
       
   176 {
       
   177     return supportsFocus();
       
   178 }
       
   179 
       
   180 bool HTMLAreaElement::isFocusable() const
       
   181 {
       
   182     return supportsFocus();
       
   183 }
       
   184     
       
   185 void HTMLAreaElement::dispatchBlurEvent()
       
   186 {
       
   187     HTMLAnchorElement::dispatchBlurEvent();
       
   188     
       
   189     // On a blur, we might need to remove our focus rings by repainting.
       
   190     updateFocusAppearance(false);
       
   191 }
       
   192     
       
   193 void HTMLAreaElement::updateFocusAppearance(bool restorePreviousSelection)
       
   194 {
       
   195     Node* parent = parentNode();
       
   196     if (!parent || !parent->hasTagName(mapTag))
       
   197         return;
       
   198     
       
   199     HTMLImageElement* imageElement = static_cast<HTMLMapElement*>(parent)->imageElement();
       
   200     if (!imageElement)
       
   201         return;
       
   202     
       
   203     // This will handle scrolling to the image if necessary.
       
   204     imageElement->updateFocusAppearance(restorePreviousSelection);
       
   205     
       
   206     RenderObject* imageRenderer = imageElement->renderer();
       
   207     if (imageRenderer)
       
   208         imageRenderer->setNeedsLayout(true);
       
   209 }
       
   210     
       
   211 bool HTMLAreaElement::supportsFocus() const
       
   212 {
       
   213     // If the AREA element was a link, it should support focus.
       
   214     // The inherited method is not used because it assumes that a render object must exist 
       
   215     // for the element to support focus. AREA elements do not have render objects.
       
   216     return isLink();
       
   217 }
       
   218 
       
   219 String HTMLAreaElement::target() const
       
   220 {
       
   221     return getAttribute(targetAttr);
       
   222 }
       
   223 
       
   224 }