blob: 5eeb31e46f851f74b7385dcc0bfac99c75914217 [file] [log] [blame]
darin@apple.com640fa302008-02-15 05:03:55 +00001/*
eseidel84943622006-05-15 23:23:42 +00002 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
darin@apple.com88b13e62011-02-01 22:49:01 +00004 * Copyright (C) 2004, 2005, 2006, 2009, 2011 Apple Inc. All rights reserved.
eseidel84943622006-05-15 23:23:42 +00005 *
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
ddkilzerc8eccec2007-09-26 02:29:57 +000018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
eseidel84943622006-05-15 23:23:42 +000020 */
darin@apple.com640fa302008-02-15 05:03:55 +000021
eseidel84943622006-05-15 23:23:42 +000022#include "config.h"
23#include "HTMLAreaElement.h"
24
tonyg@chromium.org9c384212011-01-19 23:13:26 +000025#include "AffineTransform.h"
weinig@apple.comc3608932010-05-19 17:48:06 +000026#include "Attribute.h"
yael.aharon@nokia.com8c59fca2010-11-19 16:05:13 +000027#include "Frame.h"
cfleizach@apple.combc088902010-01-26 18:06:41 +000028#include "HTMLImageElement.h"
29#include "HTMLMapElement.h"
bdakinc1a5a832006-10-28 18:28:00 +000030#include "HitTestResult.h"
treat@webkit.org0d381b42009-07-15 23:02:01 +000031#include "Path.h"
darin@apple.com88b13e62011-02-01 22:49:01 +000032#include "RenderImage.h"
commit-queue@webkit.orgc558b512012-03-27 19:19:59 +000033#include "RenderView.h"
eseidel84943622006-05-15 23:23:42 +000034
eseidel84943622006-05-15 23:23:42 +000035namespace WebCore {
36
37using namespace HTMLNames;
38
weinig@apple.comc1d18d02013-09-14 19:51:53 +000039inline HTMLAreaElement::HTMLAreaElement(const QualifiedName& tagName, Document& document)
darin@apple.come8c3a2a2009-02-02 17:29:54 +000040 : HTMLAnchorElement(tagName, document)
eseidel84943622006-05-15 23:23:42 +000041 , m_coordsLen(0)
42 , m_lastSize(-1, -1)
43 , m_shape(Unknown)
44{
jchaffraix@webkit.org94d95b02008-12-04 22:39:05 +000045 ASSERT(hasTagName(areaTag));
eseidel84943622006-05-15 23:23:42 +000046}
47
weinig@apple.comc1d18d02013-09-14 19:51:53 +000048PassRefPtr<HTMLAreaElement> HTMLAreaElement::create(const QualifiedName& tagName, Document& document)
eseidel84943622006-05-15 23:23:42 +000049{
darin@apple.comcf9dd0f2009-08-23 06:55:57 +000050 return adoptRef(new HTMLAreaElement(tagName, document));
eseidel84943622006-05-15 23:23:42 +000051}
52
akling@apple.com43e9d042012-11-18 16:55:06 +000053void HTMLAreaElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
eseidel84943622006-05-15 23:23:42 +000054{
akling@apple.com43e9d042012-11-18 16:55:06 +000055 if (name == shapeAttr) {
56 if (equalIgnoringCase(value, "default"))
eseidel84943622006-05-15 23:23:42 +000057 m_shape = Default;
akling@apple.com43e9d042012-11-18 16:55:06 +000058 else if (equalIgnoringCase(value, "circle"))
eseidel84943622006-05-15 23:23:42 +000059 m_shape = Circle;
akling@apple.com43e9d042012-11-18 16:55:06 +000060 else if (equalIgnoringCase(value, "poly"))
eseidel84943622006-05-15 23:23:42 +000061 m_shape = Poly;
akling@apple.com43e9d042012-11-18 16:55:06 +000062 else if (equalIgnoringCase(value, "rect"))
eseidel84943622006-05-15 23:23:42 +000063 m_shape = Rect;
andreas.kling@nokia.com7b570a52011-05-17 19:26:11 +000064 invalidateCachedRegion();
akling@apple.com43e9d042012-11-18 16:55:06 +000065 } else if (name == coordsAttr) {
66 m_coords = newCoordsArray(value.string(), m_coordsLen);
andreas.kling@nokia.com7b570a52011-05-17 19:26:11 +000067 invalidateCachedRegion();
akling@apple.com43e9d042012-11-18 16:55:06 +000068 } else if (name == altAttr || name == accesskeyAttr) {
eseidel84943622006-05-15 23:23:42 +000069 // Do nothing.
70 } else
akling@apple.com43e9d042012-11-18 16:55:06 +000071 HTMLAnchorElement::parseAttribute(name, value);
eseidel84943622006-05-15 23:23:42 +000072}
73
andreas.kling@nokia.com7b570a52011-05-17 19:26:11 +000074void HTMLAreaElement::invalidateCachedRegion()
75{
eae@chromium.org020f5872011-08-18 03:38:05 +000076 m_lastSize = LayoutSize(-1, -1);
andreas.kling@nokia.com7b570a52011-05-17 19:26:11 +000077}
78
eae@chromium.org020f5872011-08-18 03:38:05 +000079bool HTMLAreaElement::mapMouseEvent(LayoutPoint location, const LayoutSize& size, HitTestResult& result)
eseidel84943622006-05-15 23:23:42 +000080{
81 if (m_lastSize != size) {
abarth@webkit.orge5a57d82010-08-24 18:31:25 +000082 m_region = adoptPtr(new Path(getRegion(size)));
eseidel84943622006-05-15 23:23:42 +000083 m_lastSize = size;
84 }
85
eae@chromium.org020f5872011-08-18 03:38:05 +000086 if (!m_region->contains(location))
eseidel84943622006-05-15 23:23:42 +000087 return false;
88
bdakin1c628c02006-10-29 22:07:47 +000089 result.setInnerNode(this);
90 result.setURLElement(this);
eseidel84943622006-05-15 23:23:42 +000091 return true;
92}
93
dbates@webkit.org1edd81d2013-12-18 00:15:02 +000094// FIXME: We should use RenderElement* instead of RenderObject* once we upstream iOS's DOMUIKitExtensions.{h, mm}.
95Path HTMLAreaElement::computePath(RenderObject* obj) const
eseidel84943622006-05-15 23:23:42 +000096{
cfleizach@apple.combc088902010-01-26 18:06:41 +000097 if (!obj)
98 return Path();
99
simon.fraser@apple.comc65d3282008-11-04 18:54:50 +0000100 // FIXME: This doesn't work correctly with transforms.
101 FloatPoint absPos = obj->localToAbsolute();
cfleizach@apple.combc088902010-01-26 18:06:41 +0000102
103 // Default should default to the size of the containing object.
eae@chromium.org020f5872011-08-18 03:38:05 +0000104 LayoutSize size = m_lastSize;
cfleizach@apple.combc088902010-01-26 18:06:41 +0000105 if (m_shape == Default)
106 size = obj->absoluteOutlineBounds().size();
107
108 Path p = getRegion(size);
akling@apple.com827be9c2013-10-29 02:58:43 +0000109 float zoomFactor = obj->style().effectiveZoom();
yael.aharon@nokia.com8c59fca2010-11-19 16:05:13 +0000110 if (zoomFactor != 1.0f) {
111 AffineTransform zoomTransform;
112 zoomTransform.scale(zoomFactor);
113 p.transform(zoomTransform);
114 }
115
commit-queue@webkit.org00e1f2f2013-01-08 07:46:58 +0000116 p.translate(toFloatSize(absPos));
cfleizach@apple.combc088902010-01-26 18:06:41 +0000117 return p;
118}
dbates@webkit.org1edd81d2013-12-18 00:15:02 +0000119
120// FIXME: Use RenderElement* instead of RenderObject* once we upstream iOS's DOMUIKitExtensions.{h, mm}.
121LayoutRect HTMLAreaElement::computeRect(RenderObject* obj) const
cfleizach@apple.combc088902010-01-26 18:06:41 +0000122{
timothy_horton@apple.com581c8392011-11-07 20:40:24 +0000123 return enclosingLayoutRect(computePath(obj).fastBoundingRect());
eseidel84943622006-05-15 23:23:42 +0000124}
125
eae@chromium.org020f5872011-08-18 03:38:05 +0000126Path HTMLAreaElement::getRegion(const LayoutSize& size) const
eseidel84943622006-05-15 23:23:42 +0000127{
hyatt00af680d2006-09-19 21:31:59 +0000128 if (!m_coords && m_shape != Default)
eseidel84943622006-05-15 23:23:42 +0000129 return Path();
hyatt00af680d2006-09-19 21:31:59 +0000130
eae@chromium.org020f5872011-08-18 03:38:05 +0000131 LayoutUnit width = size.width();
132 LayoutUnit height = size.height();
eseidel84943622006-05-15 23:23:42 +0000133
134 // If element omits the shape attribute, select shape based on number of coordinates.
135 Shape shape = m_shape;
136 if (shape == Unknown) {
137 if (m_coordsLen == 3)
138 shape = Circle;
139 else if (m_coordsLen == 4)
140 shape = Rect;
141 else if (m_coordsLen >= 6)
142 shape = Poly;
143 }
144
145 Path path;
akling@apple.com622b1a42013-08-30 14:30:12 +0000146 RenderView* renderView = document().renderView();
eseidel84943622006-05-15 23:23:42 +0000147 switch (shape) {
148 case Poly:
149 if (m_coordsLen >= 6) {
150 int numPoints = m_coordsLen / 2;
commit-queue@webkit.orgc558b512012-03-27 19:19:59 +0000151 path.moveTo(FloatPoint(minimumValueForLength(m_coords[0], width, renderView), minimumValueForLength(m_coords[1], height, renderView)));
eseidel84943622006-05-15 23:23:42 +0000152 for (int i = 1; i < numPoints; ++i)
commit-queue@webkit.orgc558b512012-03-27 19:19:59 +0000153 path.addLineTo(FloatPoint(minimumValueForLength(m_coords[i * 2], width, renderView), minimumValueForLength(m_coords[i * 2 + 1], height, renderView)));
eseidel84943622006-05-15 23:23:42 +0000154 path.closeSubpath();
155 }
156 break;
157 case Circle:
158 if (m_coordsLen >= 3) {
159 Length radius = m_coords[2];
andersca@apple.comff9adb82013-10-25 01:15:36 +0000160 int r = std::min(minimumValueForLength(radius, width, renderView), minimumValueForLength(radius, height, renderView));
commit-queue@webkit.orgc558b512012-03-27 19:19:59 +0000161 path.addEllipse(FloatRect(minimumValueForLength(m_coords[0], width, renderView) - r, minimumValueForLength(m_coords[1], height, renderView) - r, 2 * r, 2 * r));
eseidel84943622006-05-15 23:23:42 +0000162 }
163 break;
164 case Rect:
165 if (m_coordsLen >= 4) {
commit-queue@webkit.orgc558b512012-03-27 19:19:59 +0000166 int x0 = minimumValueForLength(m_coords[0], width, renderView);
167 int y0 = minimumValueForLength(m_coords[1], height, renderView);
168 int x1 = minimumValueForLength(m_coords[2], width, renderView);
169 int y1 = minimumValueForLength(m_coords[3], height, renderView);
eseidel84943622006-05-15 23:23:42 +0000170 path.addRect(FloatRect(x0, y0, x1 - x0, y1 - y0));
171 }
172 break;
173 case Default:
174 path.addRect(FloatRect(0, 0, width, height));
175 break;
176 case Unknown:
177 break;
178 }
179
180 return path;
181}
182
commit-queue@webkit.orgc1beaa02012-03-26 18:51:52 +0000183HTMLImageElement* HTMLAreaElement::imageElement() const
cfleizach@apple.combc088902010-01-26 18:06:41 +0000184{
dglazkov@chromium.orge43caa72010-11-18 00:20:10 +0000185 Node* mapElement = parentNode();
kangil.han@samsung.combe99eac2013-07-04 04:31:30 +0000186 if (!mapElement || !isHTMLMapElement(mapElement))
cfleizach@apple.combc088902010-01-26 18:06:41 +0000187 return 0;
188
kangil.han@samsung.combe99eac2013-07-04 04:31:30 +0000189 return toHTMLMapElement(mapElement)->imageElement();
cfleizach@apple.combc088902010-01-26 18:06:41 +0000190}
eseidel84943622006-05-15 23:23:42 +0000191
cfleizach@apple.combc088902010-01-26 18:06:41 +0000192bool HTMLAreaElement::isKeyboardFocusable(KeyboardEvent*) const
193{
cfleizach@apple.com77be71c2010-10-06 22:09:04 +0000194 return isFocusable();
195}
196
197bool HTMLAreaElement::isMouseFocusable() const
198{
199 return isFocusable();
cfleizach@apple.combc088902010-01-26 18:06:41 +0000200}
201
202bool HTMLAreaElement::isFocusable() const
203{
commit-queue@webkit.orgc1beaa02012-03-26 18:51:52 +0000204 HTMLImageElement* image = imageElement();
akling@apple.com827be9c2013-10-29 02:58:43 +0000205 if (!image || !image->renderer() || image->renderer()->style().visibility() != VISIBLE)
commit-queue@webkit.orgc1beaa02012-03-26 18:51:52 +0000206 return false;
207
cfleizach@apple.com77be71c2010-10-06 22:09:04 +0000208 return supportsFocus() && Element::tabIndex() >= 0;
cfleizach@apple.combc088902010-01-26 18:06:41 +0000209}
210
darin@apple.com88b13e62011-02-01 22:49:01 +0000211void HTMLAreaElement::setFocus(bool shouldBeFocused)
cfleizach@apple.combc088902010-01-26 18:06:41 +0000212{
darin@apple.com88b13e62011-02-01 22:49:01 +0000213 if (focused() == shouldBeFocused)
214 return;
215
216 HTMLAnchorElement::setFocus(shouldBeFocused);
217
218 HTMLImageElement* imageElement = this->imageElement();
219 if (!imageElement)
220 return;
221
darin@apple.com8cdf7122013-09-30 02:40:50 +0000222 auto renderer = imageElement->renderer();
jhoneycutt@apple.com59248b42014-01-24 02:55:15 +0000223 if (!renderer || !renderer->isRenderImage())
darin@apple.com88b13e62011-02-01 22:49:01 +0000224 return;
225
226 toRenderImage(renderer)->areaElementFocusChanged(this);
cfleizach@apple.combc088902010-01-26 18:06:41 +0000227}
228
229void HTMLAreaElement::updateFocusAppearance(bool restorePreviousSelection)
230{
cfleizach@apple.com77be71c2010-10-06 22:09:04 +0000231 if (!isFocusable())
232 return;
darin@apple.com88b13e62011-02-01 22:49:01 +0000233
234 HTMLImageElement* imageElement = this->imageElement();
cfleizach@apple.combc088902010-01-26 18:06:41 +0000235 if (!imageElement)
236 return;
darin@apple.com88b13e62011-02-01 22:49:01 +0000237
cfleizach@apple.combc088902010-01-26 18:06:41 +0000238 imageElement->updateFocusAppearance(restorePreviousSelection);
cfleizach@apple.combc088902010-01-26 18:06:41 +0000239}
240
abarth@webkit.org40933792009-09-07 05:10:12 +0000241bool HTMLAreaElement::supportsFocus() const
alice.liu@apple.com86484822008-04-29 01:18:52 +0000242{
cfleizach@apple.combc088902010-01-26 18:06:41 +0000243 // If the AREA element was a link, it should support focus.
244 // The inherited method is not used because it assumes that a render object must exist
245 // for the element to support focus. AREA elements do not have render objects.
246 return isLink();
alice.liu@apple.com86484822008-04-29 01:18:52 +0000247}
248
eseidel84943622006-05-15 23:23:42 +0000249String HTMLAreaElement::target() const
250{
commit-queue@webkit.org03477c82011-09-02 17:07:51 +0000251 return getAttribute(targetAttr);
eseidel84943622006-05-15 23:23:42 +0000252}
253
eseidel84943622006-05-15 23:23:42 +0000254}