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