Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3584 sourcerer 1
/*
2
 * Copyright 2006 James Bursa 
3
 * Copyright 2006 Richard Wilson 
4
 * Copyright 2008 Michael Drake 
5
 * Copyright 2009 Paul Blokus 
6
 *
7
 * This file is part of NetSurf, http://www.netsurf-browser.org/
8
 *
9
 * NetSurf is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; version 2 of the License.
12
 *
13
 * NetSurf is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program.  If not, see .
20
 */
21
 
22
/** \file
23
 * User interaction with a CONTENT_HTML (implementation).
24
 */
25
 
26
#include 
27
#include 
28
 
29
#include 
30
 
31
#include "content/content.h"
32
#include "desktop/browser.h"
33
#include "desktop/frames.h"
34
#include "desktop/mouse.h"
35
#include "desktop/options.h"
36
#include "desktop/scrollbar.h"
37
#include "desktop/selection.h"
38
#include "desktop/textinput.h"
39
#include "render/box.h"
40
#include "render/font.h"
41
#include "render/form.h"
42
#include "render/html_internal.h"
43
#include "render/imagemap.h"
44
#include "render/textinput.h"
45
#include "javascript/js.h"
46
#include "utils/messages.h"
47
#include "utils/utils.h"
48
 
49
 
50
/**
51
 * Get pointer shape for given box
52
 *
53
 * \param box       box in question
54
 * \param imagemap  whether an imagemap applies to the box
55
 */
56
 
57
static browser_pointer_shape get_pointer_shape(struct box *box, bool imagemap)
58
{
59
	browser_pointer_shape pointer;
60
	css_computed_style *style;
61
	enum css_cursor_e cursor;
62
	lwc_string **cursor_uris;
63
 
64
	if (box->type == BOX_FLOAT_LEFT || box->type == BOX_FLOAT_RIGHT)
65
		style = box->children->style;
66
	else
67
		style = box->style;
68
 
69
	if (style == NULL)
70
		return BROWSER_POINTER_DEFAULT;
71
 
72
	cursor = css_computed_cursor(style, &cursor_uris);
73
 
74
	switch (cursor) {
75
	case CSS_CURSOR_AUTO:
76
		if (box->href || (box->gadget &&
77
				(box->gadget->type == GADGET_IMAGE ||
78
				box->gadget->type == GADGET_SUBMIT)) ||
79
				imagemap) {
80
			/* link */
81
			pointer = BROWSER_POINTER_POINT;
82
		} else if (box->gadget &&
83
				(box->gadget->type == GADGET_TEXTBOX ||
84
				box->gadget->type == GADGET_PASSWORD ||
85
				box->gadget->type == GADGET_TEXTAREA)) {
86
			/* text input */
87
			pointer = BROWSER_POINTER_CARET;
88
		} else {
89
			/* html content doesn't mind */
90
			pointer = BROWSER_POINTER_AUTO;
91
		}
92
		break;
93
	case CSS_CURSOR_CROSSHAIR:
94
		pointer = BROWSER_POINTER_CROSS;
95
		break;
96
	case CSS_CURSOR_POINTER:
97
		pointer = BROWSER_POINTER_POINT;
98
		break;
99
	case CSS_CURSOR_MOVE:
100
		pointer = BROWSER_POINTER_MOVE;
101
		break;
102
	case CSS_CURSOR_E_RESIZE:
103
		pointer = BROWSER_POINTER_RIGHT;
104
		break;
105
	case CSS_CURSOR_W_RESIZE:
106
		pointer = BROWSER_POINTER_LEFT;
107
		break;
108
	case CSS_CURSOR_N_RESIZE:
109
		pointer = BROWSER_POINTER_UP;
110
		break;
111
	case CSS_CURSOR_S_RESIZE:
112
		pointer = BROWSER_POINTER_DOWN;
113
		break;
114
	case CSS_CURSOR_NE_RESIZE:
115
		pointer = BROWSER_POINTER_RU;
116
		break;
117
	case CSS_CURSOR_SW_RESIZE:
118
		pointer = BROWSER_POINTER_LD;
119
		break;
120
	case CSS_CURSOR_SE_RESIZE:
121
		pointer = BROWSER_POINTER_RD;
122
		break;
123
	case CSS_CURSOR_NW_RESIZE:
124
		pointer = BROWSER_POINTER_LU;
125
		break;
126
	case CSS_CURSOR_TEXT:
127
		pointer = BROWSER_POINTER_CARET;
128
		break;
129
	case CSS_CURSOR_WAIT:
130
		pointer = BROWSER_POINTER_WAIT;
131
		break;
132
	case CSS_CURSOR_PROGRESS:
133
		pointer = BROWSER_POINTER_PROGRESS;
134
		break;
135
	case CSS_CURSOR_HELP:
136
		pointer = BROWSER_POINTER_HELP;
137
		break;
138
	default:
139
		pointer = BROWSER_POINTER_DEFAULT;
140
		break;
141
	}
142
 
143
	return pointer;
144
}
145
 
146
 
147
/**
148
 * Start drag scrolling the contents of a box
149
 *
150
 * \param box	the box to be scrolled
151
 * \param x	x ordinate of initial mouse position
152
 * \param y	y ordinate
153
 */
154
 
155
static void html_box_drag_start(struct box *box, int x, int y)
156
{
157
	int box_x, box_y;
158
	int scroll_mouse_x, scroll_mouse_y;
159
 
160
	box_coords(box, &box_x, &box_y);
161
 
162
	if (box->scroll_x != NULL) {
163
		scroll_mouse_x = x - box_x ;
164
		scroll_mouse_y = y - (box_y + box->padding[TOP] +
165
				box->height + box->padding[BOTTOM] -
166
				SCROLLBAR_WIDTH);
167
		scrollbar_start_content_drag(box->scroll_x,
168
				scroll_mouse_x, scroll_mouse_y);
169
	} else if (box->scroll_y != NULL) {
170
		scroll_mouse_x = x - (box_x + box->padding[LEFT] +
171
				box->width + box->padding[RIGHT] -
172
				SCROLLBAR_WIDTH);
173
		scroll_mouse_y = y - box_y;
174
 
175
		scrollbar_start_content_drag(box->scroll_y,
176
				scroll_mouse_x, scroll_mouse_y);
177
	}
178
}
179
 
180
 
181
/**
182
 * End overflow scroll scrollbar drags
183
 *
184
 * \param  h      html content's high level cache entry
185
 * \param  mouse  state of mouse buttons and modifier keys
186
 * \param  x	  coordinate of mouse
187
 * \param  y	  coordinate of mouse
188
 */
189
static size_t html_selection_drag_end(struct html_content *html,
190
		browser_mouse_state mouse, int x, int y, int dir)
191
{
192
	int pixel_offset;
193
	struct box *box;
194
	int dx, dy;
195
	size_t idx = 0;
196
 
197
	box = box_pick_text_box(html, x, y, dir, &dx, &dy);
198
	if (box) {
199
		plot_font_style_t fstyle;
200
 
201
		font_plot_style_from_css(box->style, &fstyle);
202
 
203
		nsfont.font_position_in_string(&fstyle, box->text, box->length,
204
				dx, &idx, &pixel_offset);
205
 
206
		idx += box->byte_offset;
207
	}
208
 
209
	return idx;
210
}
211
 
212
 
213
/**
214
 * Handle mouse tracking (including drags) in an HTML content window.
215
 *
216
 * \param  c	  content of type html
217
 * \param  bw	  browser window
218
 * \param  mouse  state of mouse buttons and modifier keys
219
 * \param  x	  coordinate of mouse
220
 * \param  y	  coordinate of mouse
221
 */
222
 
223
void html_mouse_track(struct content *c, struct browser_window *bw,
224
		browser_mouse_state mouse, int x, int y)
225
{
226
	html_content *html = (html_content*) c;
227
	browser_drag_type drag_type = browser_window_get_drag_type(bw);
228
 
229
	if (drag_type == DRAGGING_SELECTION && !mouse) {
230
		int dir = -1;
231
		size_t idx;
232
 
233
		if (selection_dragging_start(&html->sel))
234
			dir = 1;
235
 
236
		idx = html_selection_drag_end(html, mouse, x, y, dir);
237
 
238
		if (idx != 0)
239
			selection_track(&html->sel, mouse, idx);
240
 
241
		browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);
242
	}
243
 
244
	switch (drag_type) {
245
		case DRAGGING_SELECTION: {
246
			struct box *box;
247
			int dir = -1;
248
			int dx, dy;
249
 
250
			if (selection_dragging_start(&html->sel))
251
				dir = 1;
252
 
253
			box = box_pick_text_box(html, x, y, dir, &dx, &dy);
254
 
255
			if (box) {
256
				int pixel_offset;
257
				size_t idx;
258
				plot_font_style_t fstyle;
259
 
260
				font_plot_style_from_css(box->style, &fstyle);
261
 
262
				nsfont.font_position_in_string(&fstyle,
263
						box->text, box->length,
264
						dx, &idx, &pixel_offset);
265
 
266
				selection_track(&html->sel, mouse,
267
						box->byte_offset + idx);
268
			}
269
		}
270
		break;
271
 
272
		default:
273
			html_mouse_action(c, bw, mouse, x, y);
274
			break;
275
	}
276
}
277
 
278
 
279
/**
280
 * Handle mouse clicks and movements in an HTML content window.
281
 *
282
 * \param  c	  content of type html
283
 * \param  bw	  browser window
284
 * \param  mouse  state of mouse buttons and modifier keys
285
 * \param  x	  coordinate of mouse
286
 * \param  y	  coordinate of mouse
287
 *
288
 * This function handles both hovering and clicking. It is important that the
289
 * code path is identical (except that hovering doesn't carry out the action),
290
 * so that the status bar reflects exactly what will happen. Having separate
291
 * code paths opens the possibility that an attacker will make the status bar
292
 * show some harmless action where clicking will be harmful.
293
 */
294
 
295
void html_mouse_action(struct content *c, struct browser_window *bw,
296
		browser_mouse_state mouse, int x, int y)
297
{
298
	html_content *html = (html_content *) c;
299
	enum { ACTION_NONE, ACTION_SUBMIT, ACTION_GO } action = ACTION_NONE;
300
	const char *title = 0;
301
	nsurl *url = 0;
302
	const char *target = 0;
303
	char status_buffer[200];
304
	const char *status = 0;
305
	browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT;
306
	bool imagemap = false;
307
	int box_x = 0, box_y = 0;
308
	int gadget_box_x = 0, gadget_box_y = 0;
309
	int html_object_pos_x = 0, html_object_pos_y = 0;
310
	int text_box_x = 0;
311
	struct box *url_box = 0;
312
	struct box *gadget_box = 0;
313
	struct box *text_box = 0;
314
	struct box *box;
315
	struct form_control *gadget = 0;
316
	hlcache_handle *object = NULL;
317
	struct box *html_object_box = NULL;
318
	struct browser_window *iframe = NULL;
319
	struct box *next_box;
320
	struct box *drag_candidate = NULL;
321
	struct scrollbar *scrollbar = NULL;
322
	plot_font_style_t fstyle;
323
	int scroll_mouse_x = 0, scroll_mouse_y = 0;
324
	int padding_left, padding_right, padding_top, padding_bottom;
325
	browser_drag_type drag_type = browser_window_get_drag_type(bw);
326
	union content_msg_data msg_data;
327
	struct dom_node *node = NULL;
328
 
329
	if (drag_type != DRAGGING_NONE && !mouse &&
330
			html->visible_select_menu != NULL) {
331
		/* drag end: select menu */
332
		form_select_mouse_drag_end(html->visible_select_menu,
333
				mouse, x, y);
334
	}
335
 
336
	if (html->visible_select_menu != NULL) {
337
		box = html->visible_select_menu->box;
338
		box_coords(box, &box_x, &box_y);
339
 
340
		box_x -= box->border[LEFT].width;
341
		box_y += box->height + box->border[BOTTOM].width +
342
				box->padding[BOTTOM] + box->padding[TOP];
343
		status = form_select_mouse_action(html->visible_select_menu,
344
				mouse, x - box_x, y - box_y);
345
		if (status != NULL) {
346
			msg_data.explicit_status_text = status;
347
			content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
348
		} else {
349
			int width, height;
350
			form_select_get_dimensions(html->visible_select_menu,
351
					&width, &height);
352
			html->visible_select_menu = NULL;
353
			browser_window_redraw_rect(bw, box_x, box_y,
354
					width, height);
355
		}
356
		return;
357
	}
358
 
359
	if (!mouse && html->scrollbar != NULL) {
360
		/* drag end: scrollbar */
361
		html_overflow_scroll_drag_end(html->scrollbar, mouse, x, y);
362
	}
363
 
364
	if (html->scrollbar != NULL) {
365
		struct html_scrollbar_data *data =
366
				scrollbar_get_data(html->scrollbar);
367
		box = data->box;
368
		box_coords(box, &box_x, &box_y);
369
		if (scrollbar_is_horizontal(html->scrollbar)) {
370
			scroll_mouse_x = x - box_x ;
371
			scroll_mouse_y = y - (box_y + box->padding[TOP] +
372
					box->height + box->padding[BOTTOM] -
373
					SCROLLBAR_WIDTH);
374
			status = scrollbar_mouse_action(html->scrollbar, mouse,
375
					scroll_mouse_x, scroll_mouse_y);
376
		} else {
377
			scroll_mouse_x = x - (box_x + box->padding[LEFT] +
378
					box->width + box->padding[RIGHT] -
379
					SCROLLBAR_WIDTH);
380
			scroll_mouse_y = y - box_y;
381
			status = scrollbar_mouse_action(html->scrollbar, mouse,
382
					scroll_mouse_x, scroll_mouse_y);
383
		}
384
 
385
		msg_data.explicit_status_text = status;
386
		content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
387
		return;
388
	}
389
 
390
	/* Content related drags handled by now */
391
	browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);
392
 
393
	/* search the box tree for a link, imagemap, form control, or
394
	 * box with scrollbars
395
	 */
396
 
397
	box = html->layout;
398
 
399
	/* Consider the margins of the html page now */
400
	box_x = box->margin[LEFT];
401
	box_y = box->margin[TOP];
402
 
403
	/* descend through visible boxes setting more specific values for:
404
	 * box - deepest box at point
405
	 * html_object_box - html object
406
	 * html_object_pos_x - html object
407
	 * html_object_pos_y - html object
408
	 * object - non html object
409
	 * iframe - iframe
410
	 * url - href or imagemap
411
	 * target - href or imagemap or gadget
412
	 * url_box - href or imagemap
413
	 * imagemap - imagemap
414
	 * gadget - gadget
415
	 * gadget_box - gadget
416
	 * gadget_box_x - gadget
417
	 * gadget_box_y - gadget
418
	 * title - title
419
	 * pointer
420
	 *
421
	 * drag_candidate - first box with scroll
422
	 * padding_left - box with scroll
423
	 * padding_right
424
	 * padding_top
425
	 * padding_bottom
426
	 * scrollbar - inside padding box stops decent
427
	 * scroll_mouse_x - inside padding box stops decent
428
	 * scroll_mouse_y - inside padding box stops decent
429
	 *
430
	 * text_box - text box
431
	 * text_box_x - text_box
432
	 */
433
	while ((next_box = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
434
		box = next_box;
435
 
436
		if ((box->style != NULL) &&
437
		    (css_computed_visibility(box->style) ==
438
		     CSS_VISIBILITY_HIDDEN)) {
439
			continue;
440
		}
441
 
442
		if (box->node != NULL) {
443
			node = box->node;
444
		}
445
 
446
		if (box->object) {
447
			if (content_get_type(box->object) == CONTENT_HTML) {
448
				html_object_box = box;
449
				html_object_pos_x = box_x;
450
				html_object_pos_y = box_y;
451
			} else {
452
				object = box->object;
453
			}
454
		}
455
 
456
		if (box->iframe) {
457
			iframe = box->iframe;
458
		}
459
 
460
		if (box->href) {
461
			url = box->href;
462
			target = box->target;
463
			url_box = box;
464
		}
465
 
466
		if (box->usemap) {
467
			url = imagemap_get(html, box->usemap,
468
					box_x, box_y, x, y, &target);
469
			if (url) {
470
				imagemap = true;
471
				url_box = box;
472
			}
473
		}
474
 
475
		if (box->gadget) {
476
			gadget = box->gadget;
477
			gadget_box = box;
478
			gadget_box_x = box_x;
479
			gadget_box_y = box_y;
480
			if (gadget->form)
481
				target = gadget->form->target;
482
		}
483
 
484
		if (box->title) {
485
			title = box->title;
486
		}
487
 
488
		pointer = get_pointer_shape(box, false);
489
 
490
		if ((box->scroll_x != NULL) ||
491
		    (box->scroll_y != NULL)) {
492
 
493
			if (drag_candidate == NULL) {
494
				drag_candidate = box;
495
			}
496
 
497
			padding_left = box_x +
498
					scrollbar_get_offset(box->scroll_x);
499
			padding_right = padding_left + box->padding[LEFT] +
500
					box->width + box->padding[RIGHT];
501
			padding_top = box_y +
502
					scrollbar_get_offset(box->scroll_y);
503
			padding_bottom = padding_top + box->padding[TOP] +
504
					box->height + box->padding[BOTTOM];
505
 
506
			if ((x > padding_left) &&
507
			    (x < padding_right) &&
508
			    (y > padding_top) &&
509
			    (y < padding_bottom)) {
510
				/* mouse inside padding box */
511
 
512
				if ((box->scroll_y != NULL) &&
513
				    (x > (padding_right - SCROLLBAR_WIDTH))) {
514
					/* mouse above vertical box scroll */
515
 
516
					scrollbar = box->scroll_y;
517
					scroll_mouse_x = x - (padding_right -
518
							     SCROLLBAR_WIDTH);
519
					scroll_mouse_y = y - padding_top;
520
					break;
521
 
522
				} else if ((box->scroll_x != NULL) &&
523
					   (y > (padding_bottom - SCROLLBAR_WIDTH))) {
524
					/* mouse above horizontal box scroll */
525
 
526
					scrollbar = box->scroll_x;
527
					scroll_mouse_x = x - padding_left;
528
					scroll_mouse_y = y - (padding_bottom -
529
							SCROLLBAR_WIDTH);
530
					break;
531
				}
532
			}
533
		}
534
 
535
		if (box->text && !box->object) {
536
			text_box = box;
537
			text_box_x = box_x;
538
		}
539
	}
540
 
541
	/* use of box_x, box_y, or content below this point is probably a
542
	 * mistake; they will refer to the last box returned by box_at_point */
543
 
544
	if (scrollbar) {
545
		status = scrollbar_mouse_action(scrollbar, mouse,
546
				scroll_mouse_x, scroll_mouse_y);
547
		pointer = BROWSER_POINTER_DEFAULT;
548
	} else if (gadget) {
549
		switch (gadget->type) {
550
		case GADGET_SELECT:
551
			status = messages_get("FormSelect");
552
			pointer = BROWSER_POINTER_MENU;
553
			if (mouse & BROWSER_MOUSE_CLICK_1 &&
554
			    nsoption_bool(core_select_menu)) {
555
				html->visible_select_menu = gadget;
556
				form_open_select_menu(c, gadget,
557
						form_select_menu_callback,
558
						c);
559
				pointer =  BROWSER_POINTER_DEFAULT;
560
			} else if (mouse & BROWSER_MOUSE_CLICK_1)
561
				gui_create_form_select_menu(bw, gadget);
562
			break;
563
		case GADGET_CHECKBOX:
564
			status = messages_get("FormCheckbox");
565
			if (mouse & BROWSER_MOUSE_CLICK_1) {
566
				gadget->selected = !gadget->selected;
567
				html__redraw_a_box(html, gadget_box);
568
			}
569
			break;
570
		case GADGET_RADIO:
571
			status = messages_get("FormRadio");
572
			if (mouse & BROWSER_MOUSE_CLICK_1)
573
				form_radio_set(html, gadget);
574
			break;
575
		case GADGET_IMAGE:
576
			if (mouse & BROWSER_MOUSE_CLICK_1) {
577
				gadget->data.image.mx = x - gadget_box_x;
578
				gadget->data.image.my = y - gadget_box_y;
579
			}
580
			/* drop through */
581
		case GADGET_SUBMIT:
582
			if (gadget->form) {
583
				snprintf(status_buffer, sizeof status_buffer,
584
						messages_get("FormSubmit"),
585
						gadget->form->action);
586
				status = status_buffer;
587
				pointer = get_pointer_shape(gadget_box, false);
588
				if (mouse & (BROWSER_MOUSE_CLICK_1 |
589
						BROWSER_MOUSE_CLICK_2))
590
					action = ACTION_SUBMIT;
591
			} else {
592
				status = messages_get("FormBadSubmit");
593
			}
594
			break;
595
		case GADGET_TEXTAREA:
596
			status = messages_get("FormTextarea");
597
			pointer = get_pointer_shape(gadget_box, false);
598
 
599
			if (mouse & (BROWSER_MOUSE_PRESS_1 |
600
					BROWSER_MOUSE_PRESS_2)) {
601
				if (text_box && selection_root(&html->sel) !=
602
						gadget_box)
603
					selection_init(&html->sel, gadget_box);
604
 
605
				textinput_textarea_click(c, mouse,
606
						gadget_box,
607
						gadget_box_x,
608
						gadget_box_y,
609
						x - gadget_box_x,
610
						y - gadget_box_y);
611
			}
612
 
613
			if (text_box) {
614
				int pixel_offset;
615
				size_t idx;
616
 
617
				font_plot_style_from_css(text_box->style,
618
						&fstyle);
619
 
620
				nsfont.font_position_in_string(&fstyle,
621
					text_box->text,
622
					text_box->length,
623
					x - gadget_box_x - text_box->x,
624
					&idx,
625
					&pixel_offset);
626
 
627
				selection_click(&html->sel, mouse,
628
						text_box->byte_offset + idx);
629
 
630
				if (selection_dragging(&html->sel)) {
631
					browser_window_set_drag_type(bw,
632
							DRAGGING_SELECTION,
633
							NULL);
634
					status = messages_get("Selecting");
635
				}
636
			}
637
			else if (mouse & BROWSER_MOUSE_PRESS_1)
638
				selection_clear(&html->sel, true);
639
			break;
640
		case GADGET_TEXTBOX:
641
		case GADGET_PASSWORD:
642
			status = messages_get("FormTextbox");
643
			pointer = get_pointer_shape(gadget_box, false);
644
 
645
			if ((mouse & BROWSER_MOUSE_PRESS_1) &&
646
					!(mouse & (BROWSER_MOUSE_MOD_1 |
647
					BROWSER_MOUSE_MOD_2))) {
648
				textinput_input_click(c,
649
						gadget_box,
650
						gadget_box_x,
651
						gadget_box_y,
652
						x - gadget_box_x,
653
						y - gadget_box_y);
654
			}
655
			if (text_box) {
656
				int pixel_offset;
657
				size_t idx;
658
 
659
				if (mouse & (BROWSER_MOUSE_DRAG_1 |
660
						BROWSER_MOUSE_DRAG_2))
661
					selection_init(&html->sel, gadget_box);
662
 
663
				font_plot_style_from_css(text_box->style,
664
						&fstyle);
665
 
666
				nsfont.font_position_in_string(&fstyle,
667
					text_box->text,
668
					text_box->length,
669
					x - gadget_box_x - text_box->x,
670
					&idx,
671
					&pixel_offset);
672
 
673
				selection_click(&html->sel, mouse,
674
						text_box->byte_offset + idx);
675
 
676
				if (selection_dragging(&html->sel))
677
					browser_window_set_drag_type(bw,
678
							DRAGGING_SELECTION,
679
							NULL);
680
			}
681
			else if (mouse & BROWSER_MOUSE_PRESS_1)
682
				selection_clear(&html->sel, true);
683
			break;
684
		case GADGET_HIDDEN:
685
			/* not possible: no box generated */
686
			break;
687
		case GADGET_RESET:
688
			status = messages_get("FormReset");
689
			break;
690
		case GADGET_FILE:
691
			status = messages_get("FormFile");
692
			break;
693
		case GADGET_BUTTON:
694
			/* This gadget cannot be activated */
695
			status = messages_get("FormButton");
696
			break;
697
		}
698
 
699
	} else if (object && (mouse & BROWSER_MOUSE_MOD_2)) {
700
 
701
		if (mouse & BROWSER_MOUSE_DRAG_2) {
702
			msg_data.dragsave.type = CONTENT_SAVE_NATIVE;
703
			msg_data.dragsave.content = object;
704
			content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data);
705
 
706
		} else if (mouse & BROWSER_MOUSE_DRAG_1) {
707
			msg_data.dragsave.type = CONTENT_SAVE_ORIG;
708
			msg_data.dragsave.content = object;
709
			content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data);
710
		}
711
 
712
		/* \todo should have a drag-saving object msg */
713
 
714
	} else if (iframe) {
715
		int pos_x, pos_y;
716
		float scale = browser_window_get_scale(bw);
717
 
718
		browser_window_get_position(iframe, false, &pos_x, &pos_y);
719
 
720
		pos_x /= scale;
721
		pos_y /= scale;
722
 
723
		if (mouse & BROWSER_MOUSE_CLICK_1 ||
724
				mouse & BROWSER_MOUSE_CLICK_2) {
725
			browser_window_mouse_click(iframe, mouse,
726
					x - pos_x, y - pos_y);
727
		} else {
728
			browser_window_mouse_track(iframe, mouse,
729
					x - pos_x, y - pos_y);
730
		}
731
	} else if (html_object_box) {
732
		if (mouse & BROWSER_MOUSE_CLICK_1 ||
733
				mouse & BROWSER_MOUSE_CLICK_2) {
734
			content_mouse_action(html_object_box->object,
735
					bw, mouse,
736
					x - html_object_pos_x,
737
					y - html_object_pos_y);
738
		} else {
739
			content_mouse_track(html_object_box->object,
740
					bw, mouse,
741
					x - html_object_pos_x,
742
					y - html_object_pos_y);
743
		}
744
	} else if (url) {
745
		if (title) {
746
			snprintf(status_buffer, sizeof status_buffer, "%s: %s",
747
					nsurl_access(url), title);
748
			status = status_buffer;
749
		} else
750
			status = nsurl_access(url);
751
 
752
		pointer = get_pointer_shape(url_box, imagemap);
753
 
754
		if (mouse & BROWSER_MOUSE_CLICK_1 &&
755
				mouse & BROWSER_MOUSE_MOD_1) {
756
			/* force download of link */
757
			browser_window_go_post(bw, nsurl_access(url), 0, 0,
758
					false,
759
					nsurl_access(content_get_url(c)),
760
					true, true, 0);
761
 
762
		} else if (mouse & BROWSER_MOUSE_CLICK_2 &&
763
				mouse & BROWSER_MOUSE_MOD_1) {
764
			msg_data.savelink.url = nsurl_access(url);
765
			msg_data.savelink.title = title;
766
			content_broadcast(c, CONTENT_MSG_SAVELINK, msg_data);
767
 
768
		} else if (mouse & (BROWSER_MOUSE_CLICK_1 |
769
				BROWSER_MOUSE_CLICK_2))
770
			action = ACTION_GO;
771
	} else {
772
		bool done = false;
773
 
774
		/* frame resizing */
775
		if (browser_window_frame_resize_start(bw, mouse, x, y,
776
				&pointer)) {
777
			if (mouse & (BROWSER_MOUSE_DRAG_1 |
778
					BROWSER_MOUSE_DRAG_2)) {
779
				status = messages_get("FrameDrag");
780
			}
781
			done = true;
782
		}
783
 
784
		/* if clicking in the main page, remove the selection from any
785
		 * text areas */
786
		if (!done) {
787
			struct box *layout = html->layout;
788
 
789
			if (mouse && (mouse < BROWSER_MOUSE_MOD_1) &&
790
					selection_root(&html->sel) != layout) {
791
				selection_init(&html->sel, layout);
792
			}
793
 
794
			if (text_box) {
795
				int pixel_offset;
796
				size_t idx;
797
 
798
				font_plot_style_from_css(text_box->style,
799
						&fstyle);
800
 
801
				nsfont.font_position_in_string(&fstyle,
802
					text_box->text,
803
					text_box->length,
804
					x - text_box_x,
805
					&idx,
806
					&pixel_offset);
807
 
808
				if (selection_click(&html->sel, mouse,
809
						text_box->byte_offset + idx)) {
810
					/* key presses must be directed at the
811
					 * main browser window, paste text
812
					 * operations ignored */
813
 
814
					if (selection_dragging(&html->sel)) {
815
						browser_window_set_drag_type(bw,
816
							DRAGGING_SELECTION,
817
							NULL);
818
						status = messages_get(
819
								"Selecting");
820
					}
821
 
822
					done = true;
823
				}
824
 
825
			} else if (mouse & BROWSER_MOUSE_PRESS_1)
826
				selection_clear(&html->sel, true);
827
		}
828
 
829
		if (!done) {
830
			if (title)
831
				status = title;
832
 
833
			if (mouse & BROWSER_MOUSE_DRAG_1) {
834
				if (mouse & BROWSER_MOUSE_MOD_2) {
835
					msg_data.dragsave.type =
836
							CONTENT_SAVE_COMPLETE;
837
					msg_data.dragsave.content = NULL;
838
					content_broadcast(c,
839
							CONTENT_MSG_DRAGSAVE,
840
							msg_data);
841
				} else {
842
					if (drag_candidate == NULL) {
843
						browser_window_page_drag_start(
844
								bw, x, y);
845
					} else {
846
						html_box_drag_start(
847
								drag_candidate,
848
								x, y);
849
					}
850
					pointer = BROWSER_POINTER_MOVE;
851
				}
852
			}
853
			else if (mouse & BROWSER_MOUSE_DRAG_2) {
854
				if (mouse & BROWSER_MOUSE_MOD_2) {
855
					msg_data.dragsave.type =
856
							CONTENT_SAVE_SOURCE;
857
					msg_data.dragsave.content = NULL;
858
					content_broadcast(c,
859
							CONTENT_MSG_DRAGSAVE,
860
							msg_data);
861
				} else {
862
					if (drag_candidate == NULL) {
863
						browser_window_page_drag_start(
864
								bw, x, y);
865
					} else {
866
						html_box_drag_start(
867
								drag_candidate,
868
								x, y);
869
					}
870
					pointer = BROWSER_POINTER_MOVE;
871
				}
872
			}
873
		}
874
		if (mouse && mouse < BROWSER_MOUSE_MOD_1) {
875
			/* ensure key presses still act on the browser window */
876
			browser_window_remove_caret(bw);
877
		}
878
	}
879
 
880
	if (!iframe && !html_object_box) {
881
		msg_data.explicit_status_text = status;
882
		content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
883
 
884
		msg_data.pointer = pointer;
885
		content_broadcast(c, CONTENT_MSG_POINTER, msg_data);
886
	}
887
 
888
	/* fire dom click event */
889
	if ((mouse & BROWSER_MOUSE_CLICK_1) ||
890
	    (mouse & BROWSER_MOUSE_CLICK_2)) {
891
		js_fire_event(html->jscontext, "click", html->document, node);
892
	}
893
 
894
	/* deferred actions that can cause this browser_window to be destroyed
895
	 * and must therefore be done after set_status/pointer
896
	 */
897
	switch (action) {
898
	case ACTION_SUBMIT:
899
		form_submit(content_get_url(c),
900
				browser_window_find_target(bw, target, mouse),
901
				gadget->form, gadget);
902
		break;
903
	case ACTION_GO:
904
		browser_window_go(browser_window_find_target(bw, target, mouse),
905
				nsurl_access(url),
906
				nsurl_access(content_get_url(c)), true);
907
		break;
908
	case ACTION_NONE:
909
		break;
910
	}
911
}
912
 
913
 
914
/**
915
 * Callback for in-page scrollbars.
916
 */
917
void html_overflow_scroll_callback(void *client_data,
918
		struct scrollbar_msg_data *scrollbar_data)
919
{
920
	struct html_scrollbar_data *data = client_data;
921
	html_content *html = (html_content *)data->c;
922
	struct box *box = data->box;
923
	union content_msg_data msg_data;
924
 
925
	switch(scrollbar_data->msg) {
926
		case SCROLLBAR_MSG_MOVED:
927
			html__redraw_a_box(html, box);
928
			break;
929
		case SCROLLBAR_MSG_SCROLL_START:
930
		{
931
			struct rect rect = {
932
				.x0 = scrollbar_data->x0,
933
				.y0 = scrollbar_data->y0,
934
				.x1 = scrollbar_data->x1,
935
				.y1 = scrollbar_data->y1
936
			};
937
			browser_window_set_drag_type(html->bw,
938
					DRAGGING_CONTENT_SCROLLBAR, &rect);
939
 
940
			html->scrollbar = scrollbar_data->scrollbar;
941
		}
942
			break;
943
		case SCROLLBAR_MSG_SCROLL_FINISHED:
944
			html->scrollbar = NULL;
945
 
946
			browser_window_set_drag_type(html->bw,
947
					DRAGGING_NONE, NULL);
948
 
949
			msg_data.pointer = BROWSER_POINTER_AUTO;
950
			content_broadcast(data->c, CONTENT_MSG_POINTER,
951
					msg_data);
952
			break;
953
	}
954
}
955
 
956
 
957
/**
958
 * End overflow scroll scrollbar drags
959
 *
960
 * \param  scroll  scrollbar widget
961
 * \param  mouse   state of mouse buttons and modifier keys
962
 * \param  x	   coordinate of mouse
963
 * \param  y	   coordinate of mouse
964
 */
965
void html_overflow_scroll_drag_end(struct scrollbar *scrollbar,
966
		browser_mouse_state mouse, int x, int y)
967
{
968
	int scroll_mouse_x, scroll_mouse_y, box_x, box_y;
969
	struct html_scrollbar_data *data = scrollbar_get_data(scrollbar);
970
	struct box *box;
971
 
972
	box = data->box;
973
	box_coords(box, &box_x, &box_y);
974
 
975
	if (scrollbar_is_horizontal(scrollbar)) {
976
		scroll_mouse_x = x - box_x;
977
		scroll_mouse_y = y - (box_y + box->padding[TOP] +
978
				box->height + box->padding[BOTTOM] -
979
				SCROLLBAR_WIDTH);
980
		scrollbar_mouse_drag_end(scrollbar, mouse,
981
				scroll_mouse_x, scroll_mouse_y);
982
	} else {
983
		scroll_mouse_x = x - (box_x + box->padding[LEFT] +
984
				box->width + box->padding[RIGHT] -
985
				SCROLLBAR_WIDTH);
986
		scroll_mouse_y = y - box_y;
987
		scrollbar_mouse_drag_end(scrollbar, mouse,
988
				scroll_mouse_x, scroll_mouse_y);
989
	}
990
}