• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 2011 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 "core/html/HTMLAreaElement.h"
24 
25 #include "core/HTMLNames.h"
26 #include "core/html/HTMLImageElement.h"
27 #include "core/html/HTMLMapElement.h"
28 #include "core/rendering/HitTestResult.h"
29 #include "core/rendering/RenderImage.h"
30 #include "core/rendering/RenderView.h"
31 #include "platform/LengthFunctions.h"
32 #include "platform/graphics/Path.h"
33 #include "platform/transforms/AffineTransform.h"
34 
35 namespace WebCore {
36 
37 using namespace HTMLNames;
38 
HTMLAreaElement(Document & document)39 inline HTMLAreaElement::HTMLAreaElement(Document& document)
40     : HTMLAnchorElement(areaTag, document)
41     , m_lastSize(-1, -1)
42     , m_shape(Unknown)
43 {
44     ScriptWrappable::init(this);
45 }
46 
DEFINE_NODE_FACTORY(HTMLAreaElement)47 DEFINE_NODE_FACTORY(HTMLAreaElement)
48 
49 void HTMLAreaElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
50 {
51     if (name == shapeAttr) {
52         if (equalIgnoringCase(value, "default"))
53             m_shape = Default;
54         else if (equalIgnoringCase(value, "circle"))
55             m_shape = Circle;
56         else if (equalIgnoringCase(value, "poly"))
57             m_shape = Poly;
58         else if (equalIgnoringCase(value, "rect"))
59             m_shape = Rect;
60         invalidateCachedRegion();
61     } else if (name == coordsAttr) {
62         m_coords = parseHTMLAreaElementCoords(value.string());
63         invalidateCachedRegion();
64     } else if (name == altAttr || name == accesskeyAttr) {
65         // Do nothing.
66     } else
67         HTMLAnchorElement::parseAttribute(name, value);
68 }
69 
invalidateCachedRegion()70 void HTMLAreaElement::invalidateCachedRegion()
71 {
72     m_lastSize = LayoutSize(-1, -1);
73 }
74 
mapMouseEvent(LayoutPoint location,const LayoutSize & size,HitTestResult & result)75 bool HTMLAreaElement::mapMouseEvent(LayoutPoint location, const LayoutSize& size, HitTestResult& result)
76 {
77     if (m_lastSize != size) {
78         m_region = adoptPtr(new Path(getRegion(size)));
79         m_lastSize = size;
80     }
81 
82     if (!m_region->contains(location))
83         return false;
84 
85     result.setInnerNode(this);
86     result.setURLElement(this);
87     return true;
88 }
89 
computePath(RenderObject * obj) const90 Path HTMLAreaElement::computePath(RenderObject* obj) const
91 {
92     if (!obj)
93         return Path();
94 
95     // FIXME: This doesn't work correctly with transforms.
96     FloatPoint absPos = obj->localToAbsolute();
97 
98     // Default should default to the size of the containing object.
99     LayoutSize size = m_lastSize;
100     if (m_shape == Default)
101         size = obj->absoluteClippedOverflowRect().size();
102 
103     Path p = getRegion(size);
104     float zoomFactor = obj->style()->effectiveZoom();
105     if (zoomFactor != 1.0f) {
106         AffineTransform zoomTransform;
107         zoomTransform.scale(zoomFactor);
108         p.transform(zoomTransform);
109     }
110 
111     p.translate(toFloatSize(absPos));
112     return p;
113 }
114 
computeRect(RenderObject * obj) const115 LayoutRect HTMLAreaElement::computeRect(RenderObject* obj) const
116 {
117     return enclosingLayoutRect(computePath(obj).boundingRect());
118 }
119 
getRegion(const LayoutSize & size) const120 Path HTMLAreaElement::getRegion(const LayoutSize& size) const
121 {
122     if (m_coords.isEmpty() && m_shape != Default)
123         return Path();
124 
125     LayoutUnit width = size.width();
126     LayoutUnit height = size.height();
127 
128     // If element omits the shape attribute, select shape based on number of coordinates.
129     Shape shape = m_shape;
130     if (shape == Unknown) {
131         if (m_coords.size() == 3)
132             shape = Circle;
133         else if (m_coords.size() == 4)
134             shape = Rect;
135         else if (m_coords.size() >= 6)
136             shape = Poly;
137     }
138 
139     Path path;
140     switch (shape) {
141         case Poly:
142             if (m_coords.size() >= 6) {
143                 int numPoints = m_coords.size() / 2;
144                 path.moveTo(FloatPoint(minimumValueForLength(m_coords[0], width).toFloat(), minimumValueForLength(m_coords[1], height).toFloat()));
145                 for (int i = 1; i < numPoints; ++i)
146                     path.addLineTo(FloatPoint(minimumValueForLength(m_coords[i * 2], width).toFloat(), minimumValueForLength(m_coords[i * 2 + 1], height).toFloat()));
147                 path.closeSubpath();
148             }
149             break;
150         case Circle:
151             if (m_coords.size() >= 3) {
152                 Length radius = m_coords[2];
153                 float r = std::min(minimumValueForLength(radius, width).toFloat(), minimumValueForLength(radius, height).toFloat());
154                 path.addEllipse(FloatRect(minimumValueForLength(m_coords[0], width).toFloat() - r, minimumValueForLength(m_coords[1], height).toFloat() - r, 2 * r, 2 * r));
155             }
156             break;
157         case Rect:
158             if (m_coords.size() >= 4) {
159                 float x0 = minimumValueForLength(m_coords[0], width).toFloat();
160                 float y0 = minimumValueForLength(m_coords[1], height).toFloat();
161                 float x1 = minimumValueForLength(m_coords[2], width).toFloat();
162                 float y1 = minimumValueForLength(m_coords[3], height).toFloat();
163                 path.addRect(FloatRect(x0, y0, x1 - x0, y1 - y0));
164             }
165             break;
166         case Default:
167             path.addRect(FloatRect(0, 0, width.toFloat(), height.toFloat()));
168             break;
169         case Unknown:
170             break;
171     }
172 
173     return path;
174 }
175 
imageElement() const176 HTMLImageElement* HTMLAreaElement::imageElement() const
177 {
178     Element* mapElement = parentElement();
179     while (mapElement && !isHTMLMapElement(*mapElement))
180         mapElement = mapElement->parentElement();
181 
182     if (!mapElement)
183         return 0;
184 
185     return toHTMLMapElement(*mapElement).imageElement();
186 }
187 
isKeyboardFocusable() const188 bool HTMLAreaElement::isKeyboardFocusable() const
189 {
190     return isFocusable();
191 }
192 
isMouseFocusable() const193 bool HTMLAreaElement::isMouseFocusable() const
194 {
195     return isFocusable();
196 }
197 
rendererIsFocusable() const198 bool HTMLAreaElement::rendererIsFocusable() const
199 {
200     HTMLImageElement* image = imageElement();
201     if (!image || !image->renderer() || image->renderer()->style()->visibility() != VISIBLE)
202         return false;
203 
204     return supportsFocus() && Element::tabIndex() >= 0;
205 }
206 
setFocus(bool shouldBeFocused)207 void HTMLAreaElement::setFocus(bool shouldBeFocused)
208 {
209     if (focused() == shouldBeFocused)
210         return;
211 
212     HTMLAnchorElement::setFocus(shouldBeFocused);
213 
214     HTMLImageElement* imageElement = this->imageElement();
215     if (!imageElement)
216         return;
217 
218     RenderObject* renderer = imageElement->renderer();
219     if (!renderer || !renderer->isImage())
220         return;
221 
222     toRenderImage(renderer)->areaElementFocusChanged(this);
223 }
224 
updateFocusAppearance(bool restorePreviousSelection)225 void HTMLAreaElement::updateFocusAppearance(bool restorePreviousSelection)
226 {
227     if (!isFocusable())
228         return;
229 
230     HTMLImageElement* imageElement = this->imageElement();
231     if (!imageElement)
232         return;
233 
234     imageElement->updateFocusAppearance(restorePreviousSelection);
235 }
236 
237 }
238