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 "HTMLNames.h"
26 #include "HitTestResult.h"
27 #include "MappedAttribute.h"
28 #include "Path.h"
29 #include "RenderObject.h"
30
31 using namespace std;
32
33 namespace WebCore {
34
35 using namespace HTMLNames;
36
HTMLAreaElement(const QualifiedName & tagName,Document * document)37 HTMLAreaElement::HTMLAreaElement(const QualifiedName& tagName, Document* document)
38 : HTMLAnchorElement(tagName, document)
39 , m_coords(0)
40 , m_coordsLen(0)
41 , m_lastSize(-1, -1)
42 , m_shape(Unknown)
43 {
44 ASSERT(hasTagName(areaTag));
45 }
46
~HTMLAreaElement()47 HTMLAreaElement::~HTMLAreaElement()
48 {
49 delete [] m_coords;
50 }
51
parseMappedAttribute(MappedAttribute * attr)52 void HTMLAreaElement::parseMappedAttribute(MappedAttribute* attr)
53 {
54 if (attr->name() == shapeAttr) {
55 if (equalIgnoringCase(attr->value(), "default"))
56 m_shape = Default;
57 else if (equalIgnoringCase(attr->value(), "circle"))
58 m_shape = Circle;
59 else if (equalIgnoringCase(attr->value(), "poly"))
60 m_shape = Poly;
61 else if (equalIgnoringCase(attr->value(), "rect"))
62 m_shape = Rect;
63 } else if (attr->name() == coordsAttr) {
64 delete [] m_coords;
65 m_coords = 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
mapMouseEvent(int x,int y,const IntSize & size,HitTestResult & result)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
getRect(RenderObject * obj) const87 IntRect HTMLAreaElement::getRect(RenderObject* obj) const
88 {
89 // FIXME: This doesn't work correctly with transforms.
90 FloatPoint absPos = obj->localToAbsolute();
91 Path p = getRegion(m_lastSize);
92 p.translate(absPos - FloatPoint());
93 return enclosingIntRect(p.boundingRect());
94 }
95
getRegion(const IntSize & size) const96 Path HTMLAreaElement::getRegion(const IntSize& size) const
97 {
98 if (!m_coords && m_shape != Default)
99 return Path();
100
101 int width = size.width();
102 int height = size.height();
103
104 // If element omits the shape attribute, select shape based on number of coordinates.
105 Shape shape = m_shape;
106 if (shape == Unknown) {
107 if (m_coordsLen == 3)
108 shape = Circle;
109 else if (m_coordsLen == 4)
110 shape = Rect;
111 else if (m_coordsLen >= 6)
112 shape = Poly;
113 }
114
115 Path path;
116 switch (shape) {
117 case Poly:
118 if (m_coordsLen >= 6) {
119 int numPoints = m_coordsLen / 2;
120 path.moveTo(FloatPoint(m_coords[0].calcMinValue(width), m_coords[1].calcMinValue(height)));
121 for (int i = 1; i < numPoints; ++i)
122 path.addLineTo(FloatPoint(m_coords[i * 2].calcMinValue(width), m_coords[i * 2 + 1].calcMinValue(height)));
123 path.closeSubpath();
124 }
125 break;
126 case Circle:
127 if (m_coordsLen >= 3) {
128 Length radius = m_coords[2];
129 int r = min(radius.calcMinValue(width), radius.calcMinValue(height));
130 path.addEllipse(FloatRect(m_coords[0].calcMinValue(width) - r, m_coords[1].calcMinValue(height) - r, 2 * r, 2 * r));
131 }
132 break;
133 case Rect:
134 if (m_coordsLen >= 4) {
135 int x0 = m_coords[0].calcMinValue(width);
136 int y0 = m_coords[1].calcMinValue(height);
137 int x1 = m_coords[2].calcMinValue(width);
138 int y1 = m_coords[3].calcMinValue(height);
139 path.addRect(FloatRect(x0, y0, x1 - x0, y1 - y0));
140 }
141 break;
142 case Default:
143 path.addRect(FloatRect(0, 0, width, height));
144 break;
145 case Unknown:
146 break;
147 }
148
149 return path;
150 }
151
href() const152 KURL HTMLAreaElement::href() const
153 {
154 return document()->completeURL(getAttribute(hrefAttr));
155 }
156
noHref() const157 bool HTMLAreaElement::noHref() const
158 {
159 return !getAttribute(nohrefAttr).isNull();
160 }
161
setNoHref(bool noHref)162 void HTMLAreaElement::setNoHref(bool noHref)
163 {
164 setAttribute(nohrefAttr, noHref ? "" : 0);
165 }
166
isFocusable() const167 bool HTMLAreaElement::isFocusable() const
168 {
169 return HTMLElement::isFocusable();
170 }
171
target() const172 String HTMLAreaElement::target() const
173 {
174 return getAttribute(targetAttr);
175 }
176
177 }
178