1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.html;
16
17 import static org.htmlunit.BrowserVersionFeatures.CSS_DISPLAY_BLOCK;
18
19 import java.io.IOException;
20 import java.net.MalformedURLException;
21 import java.net.URL;
22 import java.util.Arrays;
23 import java.util.Map;
24
25 import org.apache.commons.lang3.StringUtils;
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.htmlunit.SgmlPage;
29 import org.htmlunit.WebClient;
30 import org.htmlunit.WebRequest;
31 import org.htmlunit.WebWindow;
32 import org.htmlunit.javascript.host.event.Event;
33 import org.htmlunit.protocol.javascript.JavaScriptURLConnection;
34 import org.htmlunit.util.geometry.Circle2D;
35 import org.htmlunit.util.geometry.Polygon2D;
36 import org.htmlunit.util.geometry.Rectangle2D;
37 import org.htmlunit.util.geometry.Shape2D;
38
39
40
41
42
43
44
45
46
47
48
49
50 public class HtmlArea extends HtmlElement {
51 private static final Log LOG = LogFactory.getLog(HtmlArea.class);
52
53
54 public static final String TAG_NAME = "area";
55
56 private static final String SHAPE_RECT = "rect";
57 private static final String SHAPE_CIRCLE = "circle";
58 private static final String SHAPE_POLY = "poly";
59
60
61
62
63
64
65
66
67 HtmlArea(final String qualifiedName, final SgmlPage page,
68 final Map<String, DomAttr> attributes) {
69 super(qualifiedName, page, attributes);
70 }
71
72
73
74
75 @Override
76 protected boolean doClickStateUpdate(final boolean shiftKey, final boolean ctrlKey) throws IOException {
77 final HtmlPage enclosingPage = (HtmlPage) getPage();
78 final WebClient webClient = enclosingPage.getWebClient();
79
80 final String href = getHrefAttribute().trim();
81 if (!href.isEmpty()) {
82 final HtmlPage page = (HtmlPage) getPage();
83 if (StringUtils.startsWithIgnoreCase(href, JavaScriptURLConnection.JAVASCRIPT_PREFIX)) {
84 page.executeJavaScript(
85 href, "javascript url", getStartLineNumber());
86 return false;
87 }
88 final URL url;
89 try {
90 url = enclosingPage.getFullyQualifiedUrl(getHrefAttribute());
91 }
92 catch (final MalformedURLException e) {
93 throw new IllegalStateException(
94 "Not a valid url: " + getHrefAttribute(), e);
95 }
96 final WebRequest request = new WebRequest(url, page.getCharset(), page.getUrl());
97 final WebWindow webWindow = enclosingPage.getEnclosingWindow();
98 final String target = enclosingPage.getResolvedTarget(getTargetAttribute());
99 webClient.getPage(webClient.openTargetWindow(webWindow, target, WebClient.TARGET_SELF), request);
100 }
101 return false;
102 }
103
104
105
106
107
108
109
110
111 public final String getShapeAttribute() {
112 return getAttributeDirect("shape");
113 }
114
115
116
117
118
119
120
121
122 public final String getCoordsAttribute() {
123 return getAttributeDirect("coords");
124 }
125
126
127
128
129
130
131
132
133 public final String getHrefAttribute() {
134 return getAttributeDirect("href");
135 }
136
137
138
139
140
141
142
143
144 public final String getNoHrefAttribute() {
145 return getAttributeDirect("nohref");
146 }
147
148
149
150
151
152
153
154
155 public final String getAltAttribute() {
156 return getAttributeDirect("alt");
157 }
158
159
160
161
162
163
164
165
166 public final String getTabIndexAttribute() {
167 return getAttributeDirect("tabindex");
168 }
169
170
171
172
173
174
175
176
177 public final String getAccessKeyAttribute() {
178 return getAttributeDirect("accesskey");
179 }
180
181
182
183
184
185
186
187
188 public final String getOnFocusAttribute() {
189 return getAttributeDirect("onfocus");
190 }
191
192
193
194
195
196
197
198
199 public final String getOnBlurAttribute() {
200 return getAttributeDirect("onblur");
201 }
202
203
204
205
206
207
208
209
210 public final String getTargetAttribute() {
211 return getAttributeDirect("target");
212 }
213
214
215
216
217
218
219
220 boolean containsPoint(final int x, final int y) {
221 final String shape = StringUtils.defaultIfEmpty(getShapeAttribute(), SHAPE_RECT);
222
223 if ("default".equalsIgnoreCase(shape) && getCoordsAttribute() != null) {
224 return true;
225 }
226
227 if (SHAPE_RECT.equalsIgnoreCase(shape) && getCoordsAttribute() != null) {
228 final Shape2D rectangle = parseRect();
229 return rectangle.contains(x, y);
230 }
231
232 if (SHAPE_CIRCLE.equalsIgnoreCase(shape) && getCoordsAttribute() != null) {
233 final Shape2D circle = parseCircle();
234 return circle.contains(x, y);
235 }
236
237 if (SHAPE_POLY.equalsIgnoreCase(shape) && getCoordsAttribute() != null) {
238 final Shape2D path = parsePoly();
239 return path.contains(x, y);
240 }
241
242 return false;
243 }
244
245
246
247
248 @Override
249 public DisplayStyle getDefaultStyleDisplay() {
250 if (hasFeature(CSS_DISPLAY_BLOCK)) {
251 return DisplayStyle.NONE;
252 }
253 return DisplayStyle.INLINE;
254 }
255
256
257
258
259 @Override
260 public boolean isDisplayed() {
261 final DomNode parent = getParentNode();
262 if (parent instanceof HtmlMap && parent.isDisplayed()) {
263 return !isEmpty();
264 }
265 return false;
266 }
267
268 private Rectangle2D parseRect() {
269
270 final String[] coords = org.htmlunit.util.StringUtils.splitAtCommaOrBlank(getCoordsAttribute());
271
272 double leftX = 0;
273 double topY = 0;
274 double rightX = 0;
275 double bottomY = 0;
276
277 try {
278 if (coords.length > 0) {
279 leftX = Double.parseDouble(coords[0].trim());
280 }
281 if (coords.length > 1) {
282 topY = Double.parseDouble(coords[1].trim());
283 }
284 if (coords.length > 2) {
285 rightX = Double.parseDouble(coords[2].trim());
286 }
287 if (coords.length > 3) {
288 bottomY = Double.parseDouble(coords[3].trim());
289 }
290 }
291 catch (final NumberFormatException e) {
292 if (LOG.isWarnEnabled()) {
293 LOG.warn("Invalid rect coords '" + Arrays.toString(coords) + "'", e);
294 }
295 }
296
297 return new Rectangle2D(leftX, topY, rightX, bottomY);
298 }
299
300 private Circle2D parseCircle() {
301
302 final String[] coords = org.htmlunit.util.StringUtils.splitAtCommaOrBlank(getCoordsAttribute());
303
304 double centerX = 0;
305 double centerY = 0;
306 double radius = 0;
307
308 try {
309 if (coords.length > 0) {
310 centerX = Double.parseDouble(coords[0].trim());
311 }
312 if (coords.length > 1) {
313 centerY = Double.parseDouble(coords[1].trim());
314 }
315 if (coords.length > 2) {
316 radius = Double.parseDouble(coords[2].trim());
317 }
318
319 }
320 catch (final NumberFormatException e) {
321 if (LOG.isWarnEnabled()) {
322 LOG.warn("Invalid circle coords '" + Arrays.toString(coords) + "'", e);
323 }
324 }
325
326 return new Circle2D(centerX, centerY, radius);
327 }
328
329 private Shape2D parsePoly() {
330
331 final String[] coords = org.htmlunit.util.StringUtils.splitAtCommaOrBlank(getCoordsAttribute());
332
333 try {
334 if (coords.length > 1) {
335 final Polygon2D path = new Polygon2D(Double.parseDouble(coords[0]), Double.parseDouble(coords[1]));
336
337 for (int i = 2; i + 1 < coords.length; i += 2) {
338 path.lineTo(Double.parseDouble(coords[i]), Double.parseDouble(coords[i + 1]));
339 }
340 return path;
341 }
342 }
343 catch (final NumberFormatException e) {
344 if (LOG.isWarnEnabled()) {
345 LOG.warn("Invalid poly coords '" + Arrays.toString(coords) + "'", e);
346 }
347 }
348
349 return new Rectangle2D(0, 0, 0, 0);
350 }
351
352
353
354
355 @Override
356 public boolean handles(final Event event) {
357 if (Event.TYPE_BLUR.equals(event.getType()) || Event.TYPE_FOCUS.equals(event.getType())) {
358 return true;
359 }
360 return super.handles(event);
361 }
362
363 private boolean isEmpty() {
364 final String shape = StringUtils.defaultIfEmpty(getShapeAttribute(), SHAPE_RECT);
365
366 if ("default".equalsIgnoreCase(shape) && getCoordsAttribute() != null) {
367 return false;
368 }
369
370 if (SHAPE_RECT.equalsIgnoreCase(shape) && getCoordsAttribute() != null) {
371 final Shape2D rectangle = parseRect();
372 return rectangle.isEmpty();
373 }
374
375 if (SHAPE_CIRCLE.equalsIgnoreCase(shape) && getCoordsAttribute() != null) {
376 final Shape2D circle = parseCircle();
377 return circle.isEmpty();
378 }
379
380 if (SHAPE_POLY.equalsIgnoreCase(shape) && getCoordsAttribute() != null) {
381 final Shape2D path = parsePoly();
382 return path.isEmpty();
383 }
384
385 return false;
386 }
387 }