void html_mouse_action(struct content *c, struct browser_window *bw,
		browser_mouse_state mouse, int x, int y)
{
	html_content *html = (html_content *) c;
	enum { ACTION_NONE, ACTION_SUBMIT, ACTION_GO } action = ACTION_NONE;
	const char *title = 0;
	nsurl *url = 0;
	const char *target = 0;
	char status_buffer[200];
	const char *status = 0;
	browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT;
	bool imagemap = false;
	int box_x = 0, box_y = 0;
	int gadget_box_x = 0, gadget_box_y = 0;
	int html_object_pos_x = 0, html_object_pos_y = 0;
	int text_box_x = 0;
	struct box *url_box = 0;
	struct box *gadget_box = 0;
	struct box *text_box = 0;
	struct box *box;
	struct form_control *gadget = 0;
	hlcache_handle *object = NULL;
	struct box *html_object_box = NULL;
	struct browser_window *iframe = NULL;
	struct box *next_box;
	struct box *drag_candidate = NULL;
	struct scrollbar *scrollbar = NULL;
	plot_font_style_t fstyle;
	int scroll_mouse_x = 0, scroll_mouse_y = 0;
	int padding_left, padding_right, padding_top, padding_bottom;
	browser_drag_type drag_type = browser_window_get_drag_type(bw);
	union content_msg_data msg_data;
	struct dom_node *node = NULL;

	if (drag_type != DRAGGING_NONE && !mouse &&
			html->visible_select_menu != NULL) {
		/* drag end: select menu */
		form_select_mouse_drag_end(html->visible_select_menu,
				mouse, x, y);
	}

	if (html->visible_select_menu != NULL) {
		box = html->visible_select_menu->box;
		box_coords(box, &box_x, &box_y);

		box_x -= box->border[LEFT].width;
		box_y += box->height + box->border[BOTTOM].width +
				box->padding[BOTTOM] + box->padding[TOP];
		status = form_select_mouse_action(html->visible_select_menu,
				mouse, x - box_x, y - box_y);
		if (status != NULL) {
			msg_data.explicit_status_text = status;
			content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
		} else {
			int width, height;
			form_select_get_dimensions(html->visible_select_menu,
					&width, &height);
			html->visible_select_menu = NULL;
			browser_window_redraw_rect(bw, box_x, box_y,
					width, height);					
		}
		return;
	}

	if (!mouse && html->scrollbar != NULL) {
		/* drag end: scrollbar */
		html_overflow_scroll_drag_end(html->scrollbar, mouse, x, y);
	}

	if (html->scrollbar != NULL) {
		struct html_scrollbar_data *data =
				scrollbar_get_data(html->scrollbar);
		box = data->box;
		box_coords(box, &box_x, &box_y);
		if (scrollbar_is_horizontal(html->scrollbar)) {
			scroll_mouse_x = x - box_x ;
			scroll_mouse_y = y - (box_y + box->padding[TOP] +
					box->height + box->padding[BOTTOM] -
					SCROLLBAR_WIDTH);
			status = scrollbar_mouse_action(html->scrollbar, mouse,
					scroll_mouse_x, scroll_mouse_y);
		} else {
			scroll_mouse_x = x - (box_x + box->padding[LEFT] +
					box->width + box->padding[RIGHT] -
					SCROLLBAR_WIDTH);
			scroll_mouse_y = y - box_y;
			status = scrollbar_mouse_action(html->scrollbar, mouse, 
					scroll_mouse_x, scroll_mouse_y);
		}

		msg_data.explicit_status_text = status;
		content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
		return;
	}

	/* Content related drags handled by now */
	browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);

	/* search the box tree for a link, imagemap, form control, or
	 * box with scrollbars 
	 */

	box = html->layout;

	/* Consider the margins of the html page now */
	box_x = box->margin[LEFT];
	box_y = box->margin[TOP];

	/* descend through visible boxes setting more specific values for:
	 * box - deepest box at point 
	 * html_object_box - html object
	 * html_object_pos_x - html object
	 * html_object_pos_y - html object
	 * object - non html object
	 * iframe - iframe
	 * url - href or imagemap
	 * target - href or imagemap or gadget
	 * url_box - href or imagemap
	 * imagemap - imagemap
	 * gadget - gadget
	 * gadget_box - gadget
	 * gadget_box_x - gadget
	 * gadget_box_y - gadget
	 * title - title
	 * pointer
	 *
	 * drag_candidate - first box with scroll
	 * padding_left - box with scroll
	 * padding_right
	 * padding_top
	 * padding_bottom
	 * scrollbar - inside padding box stops decent
	 * scroll_mouse_x - inside padding box stops decent
	 * scroll_mouse_y - inside padding box stops decent
	 * 
	 * text_box - text box
	 * text_box_x - text_box
	 */
	while ((next_box = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
		box = next_box;

		if ((box->style != NULL) && 
		    (css_computed_visibility(box->style) == 
		     CSS_VISIBILITY_HIDDEN)) {
			continue;
		}

		if (box->node != NULL) {
			node = box->node;
		}

		if (box->object) {
			if (content_get_type(box->object) == CONTENT_HTML) {
				html_object_box = box;
				html_object_pos_x = box_x;
				html_object_pos_y = box_y;
			} else {
				object = box->object;
			}
		}

		if (box->iframe) {
			iframe = box->iframe;
		}

		if (box->href) {
			url = box->href;
			target = box->target;
			url_box = box;
		}

		if (box->usemap) {
			url = imagemap_get(html, box->usemap,
					box_x, box_y, x, y, &target);
			if (url) {
				imagemap = true;
				url_box = box;
			}
		}

		if (box->gadget) {
			gadget = box->gadget;
			gadget_box = box;
			gadget_box_x = box_x;
			gadget_box_y = box_y;
			if (gadget->form)
				target = gadget->form->target;
		}

		if (box->title) {
			title = box->title;
		}

		pointer = get_pointer_shape(box, false);
		
		if ((box->scroll_x != NULL) || 
		    (box->scroll_y != NULL)) {

			if (drag_candidate == NULL) {
				drag_candidate = box;
			}

			padding_left = box_x +
					scrollbar_get_offset(box->scroll_x);
			padding_right = padding_left + box->padding[LEFT] +
					box->width + box->padding[RIGHT];
			padding_top = box_y +
					scrollbar_get_offset(box->scroll_y);
			padding_bottom = padding_top + box->padding[TOP] +
					box->height + box->padding[BOTTOM];
			
			if ((x > padding_left) && 
			    (x < padding_right) &&
			    (y > padding_top) && 
			    (y < padding_bottom)) {
				/* mouse inside padding box */
				
				if ((box->scroll_y != NULL) && 
				    (x > (padding_right - SCROLLBAR_WIDTH))) {
					/* mouse above vertical box scroll */
					
					scrollbar = box->scroll_y;
					scroll_mouse_x = x - (padding_right -
							     SCROLLBAR_WIDTH);
					scroll_mouse_y = y - padding_top;
					break;
				
				} else if ((box->scroll_x != NULL) &&
					   (y > (padding_bottom - SCROLLBAR_WIDTH))) {
					/* mouse above horizontal box scroll */
							
					scrollbar = box->scroll_x;
					scroll_mouse_x = x - padding_left;
					scroll_mouse_y = y - (padding_bottom -
							SCROLLBAR_WIDTH);
					break;
				}
			}
		}

		if (box->text && !box->object) {
			text_box = box;
			text_box_x = box_x;
		}
	}

	/* use of box_x, box_y, or content below this point is probably a
	 * mistake; they will refer to the last box returned by box_at_point */

	if (scrollbar) {
		status = scrollbar_mouse_action(scrollbar, mouse,
				scroll_mouse_x, scroll_mouse_y);
		pointer = BROWSER_POINTER_DEFAULT;
	} else if (gadget) {
		switch (gadget->type) {
		case GADGET_SELECT:
			status = messages_get("FormSelect");
			pointer = BROWSER_POINTER_MENU;
			if (mouse & BROWSER_MOUSE_CLICK_1 &&
			    nsoption_bool(core_select_menu)) {
				html->visible_select_menu = gadget;
				form_open_select_menu(c, gadget,
						form_select_menu_callback,
						c);
				pointer =  BROWSER_POINTER_DEFAULT;
			} else if (mouse & BROWSER_MOUSE_CLICK_1)
				gui_create_form_select_menu(bw, gadget);
			break;
		case GADGET_CHECKBOX:
			status = messages_get("FormCheckbox");
			if (mouse & BROWSER_MOUSE_CLICK_1) {
				gadget->selected = !gadget->selected;
				html__redraw_a_box(html, gadget_box);
			}
			break;
		case GADGET_RADIO:
			status = messages_get("FormRadio");
			if (mouse & BROWSER_MOUSE_CLICK_1)
				form_radio_set(html, gadget);
			break;
		case GADGET_IMAGE:
			if (mouse & BROWSER_MOUSE_CLICK_1) {
				gadget->data.image.mx = x - gadget_box_x;
				gadget->data.image.my = y - gadget_box_y;
			}
			/* drop through */
		case GADGET_SUBMIT:
			if (gadget->form) {
				snprintf(status_buffer, sizeof status_buffer,
						messages_get("FormSubmit"),
						gadget->form->action);
				status = status_buffer;
				pointer = get_pointer_shape(gadget_box, false);
				if (mouse & (BROWSER_MOUSE_CLICK_1 |
						BROWSER_MOUSE_CLICK_2))
					action = ACTION_SUBMIT;
			} else {
				status = messages_get("FormBadSubmit");
			}
			break;
		case GADGET_TEXTAREA:
			status = messages_get("FormTextarea");
			pointer = get_pointer_shape(gadget_box, false);

			if (mouse & (BROWSER_MOUSE_PRESS_1 |
					BROWSER_MOUSE_PRESS_2)) {
				if (text_box && selection_root(&html->sel) !=
						gadget_box)
					selection_init(&html->sel, gadget_box);

				textinput_textarea_click(c, mouse,
						gadget_box,
						gadget_box_x,
						gadget_box_y,
						x - gadget_box_x,
						y - gadget_box_y);
			}

			if (text_box) {
				int pixel_offset;
				size_t idx;

				font_plot_style_from_css(text_box->style, 
						&fstyle);

				nsfont.font_position_in_string(&fstyle,
					text_box->text,
					text_box->length,
					x - gadget_box_x - text_box->x,
					&idx,
					&pixel_offset);

				selection_click(&html->sel, mouse,
						text_box->byte_offset + idx);

				if (selection_dragging(&html->sel)) {
					browser_window_set_drag_type(bw,
							DRAGGING_SELECTION,
							NULL);
					status = messages_get("Selecting");
				}
			}
			else if (mouse & BROWSER_MOUSE_PRESS_1)
				selection_clear(&html->sel, true);
			break;
		case GADGET_TEXTBOX:
		case GADGET_PASSWORD:
			status = messages_get("FormTextbox");
			pointer = get_pointer_shape(gadget_box, false);

			if ((mouse & BROWSER_MOUSE_PRESS_1) &&
					!(mouse & (BROWSER_MOUSE_MOD_1 |
					BROWSER_MOUSE_MOD_2))) {
				textinput_input_click(c,
						gadget_box,
						gadget_box_x,
						gadget_box_y,
						x - gadget_box_x,
						y - gadget_box_y);
			}
			if (text_box) {
				int pixel_offset;
				size_t idx;

				if (mouse & (BROWSER_MOUSE_DRAG_1 |
						BROWSER_MOUSE_DRAG_2))
					selection_init(&html->sel, gadget_box);

				font_plot_style_from_css(text_box->style,
						&fstyle);

				nsfont.font_position_in_string(&fstyle,
					text_box->text,
					text_box->length,
					x - gadget_box_x - text_box->x,
					&idx,
					&pixel_offset);

				selection_click(&html->sel, mouse,
						text_box->byte_offset + idx);

				if (selection_dragging(&html->sel))
					browser_window_set_drag_type(bw,
							DRAGGING_SELECTION,
							NULL);
			}
			else if (mouse & BROWSER_MOUSE_PRESS_1)
				selection_clear(&html->sel, true);
			break;
		case GADGET_HIDDEN:
			/* not possible: no box generated */
			break;
		case GADGET_RESET:
			status = messages_get("FormReset");
			break;
		case GADGET_FILE:
			status = messages_get("FormFile");
			break;
		case GADGET_BUTTON:
			/* This gadget cannot be activated */
			status = messages_get("FormButton");
			break;
		}

	} else if (object && (mouse & BROWSER_MOUSE_MOD_2)) {

		if (mouse & BROWSER_MOUSE_DRAG_2) {
			msg_data.dragsave.type = CONTENT_SAVE_NATIVE;
			msg_data.dragsave.content = object;
			content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data);

		} else if (mouse & BROWSER_MOUSE_DRAG_1) {
			msg_data.dragsave.type = CONTENT_SAVE_ORIG;
			msg_data.dragsave.content = object;
			content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data);
		}

		/* \todo should have a drag-saving object msg */

	} else if (iframe) {
		int pos_x, pos_y;
		float scale = browser_window_get_scale(bw);

		browser_window_get_position(iframe, false, &pos_x, &pos_y);

		pos_x /= scale;
		pos_y /= scale;

		if (mouse & BROWSER_MOUSE_CLICK_1 ||
				mouse & BROWSER_MOUSE_CLICK_2) {
			browser_window_mouse_click(iframe, mouse,
					x - pos_x, y - pos_y);
		} else {
			browser_window_mouse_track(iframe, mouse,
					x - pos_x, y - pos_y);
		}
	} else if (html_object_box) {
		if (mouse & BROWSER_MOUSE_CLICK_1 ||
				mouse & BROWSER_MOUSE_CLICK_2) {
			content_mouse_action(html_object_box->object,
					bw, mouse,
					x - html_object_pos_x,
					y - html_object_pos_y);
		} else {
			content_mouse_track(html_object_box->object,
					bw, mouse,
					x - html_object_pos_x,
					y - html_object_pos_y);
		}
	} else if (url) {
		if (title) {
			snprintf(status_buffer, sizeof status_buffer, "%s: %s",
					nsurl_access(url), title);
			status = status_buffer;
		} else
			status = nsurl_access(url);

		pointer = get_pointer_shape(url_box, imagemap);

		if (mouse & BROWSER_MOUSE_CLICK_1 &&
				mouse & BROWSER_MOUSE_MOD_1) {
			/* force download of link */
			browser_window_go_post(bw, nsurl_access(url), 0, 0,
					false,
					nsurl_access(content_get_url(c)),
					true, true, 0);

		} else if (mouse & BROWSER_MOUSE_CLICK_2 &&
				mouse & BROWSER_MOUSE_MOD_1) {
			msg_data.savelink.url = nsurl_access(url);
			msg_data.savelink.title = title;
			content_broadcast(c, CONTENT_MSG_SAVELINK, msg_data);

		} else if (mouse & (BROWSER_MOUSE_CLICK_1 |
				BROWSER_MOUSE_CLICK_2))
			action = ACTION_GO;
	} else {
		bool done = false;

		/* frame resizing */
		if (browser_window_frame_resize_start(bw, mouse, x, y,
				&pointer)) {
			if (mouse & (BROWSER_MOUSE_DRAG_1 |
					BROWSER_MOUSE_DRAG_2)) {
				status = messages_get("FrameDrag");
			}
			done = true;
		}

		/* if clicking in the main page, remove the selection from any
		 * text areas */
		if (!done) {
			struct box *layout = html->layout;

			if (mouse && (mouse < BROWSER_MOUSE_MOD_1) &&
					selection_root(&html->sel) != layout) {
				selection_init(&html->sel, layout);
			}

			if (text_box) {
				int pixel_offset;
				size_t idx;

				font_plot_style_from_css(text_box->style,
						&fstyle);

				nsfont.font_position_in_string(&fstyle,
					text_box->text,
					text_box->length,
					x - text_box_x,
					&idx,
					&pixel_offset);

				if (selection_click(&html->sel, mouse,
						text_box->byte_offset + idx)) {
					/* key presses must be directed at the
					 * main browser window, paste text
					 * operations ignored */

					if (selection_dragging(&html->sel)) {
						browser_window_set_drag_type(bw,
							DRAGGING_SELECTION,
							NULL);
						status = messages_get(
								"Selecting");
					}

					done = true;
				}

			} else if (mouse & BROWSER_MOUSE_PRESS_1)
				selection_clear(&html->sel, true);
		}

		if (!done) {
			if (title)
				status = title;

			if (mouse & BROWSER_MOUSE_DRAG_1) {
				if (mouse & BROWSER_MOUSE_MOD_2) {
					msg_data.dragsave.type =
							CONTENT_SAVE_COMPLETE;
					msg_data.dragsave.content = NULL;
					content_broadcast(c,
							CONTENT_MSG_DRAGSAVE,
							msg_data);
				} else {
					if (drag_candidate == NULL) {
						browser_window_page_drag_start(
								bw, x, y);
					} else {
						html_box_drag_start(
								drag_candidate,
								x, y);
					}
					pointer = BROWSER_POINTER_MOVE;
				}
			}
			else if (mouse & BROWSER_MOUSE_DRAG_2) {
				if (mouse & BROWSER_MOUSE_MOD_2) {
					msg_data.dragsave.type =
							CONTENT_SAVE_SOURCE;
					msg_data.dragsave.content = NULL;
					content_broadcast(c,
							CONTENT_MSG_DRAGSAVE,
							msg_data);
				} else {
					if (drag_candidate == NULL) {
						browser_window_page_drag_start(
								bw, x, y);
					} else {
						html_box_drag_start(
								drag_candidate,
								x, y);
					}
					pointer = BROWSER_POINTER_MOVE;
				}
			}
		}
		if (mouse && mouse < BROWSER_MOUSE_MOD_1) {
			/* ensure key presses still act on the browser window */
			browser_window_remove_caret(bw);
		}
	}

	if (!iframe && !html_object_box) {
		msg_data.explicit_status_text = status;
		content_broadcast(c, CONTENT_MSG_STATUS, msg_data);

		msg_data.pointer = pointer;
		content_broadcast(c, CONTENT_MSG_POINTER, msg_data);
	}

	/* fire dom click event */
	if ((mouse & BROWSER_MOUSE_CLICK_1) ||
	    (mouse & BROWSER_MOUSE_CLICK_2)) {
		js_fire_event(html->jscontext, "click", html->document, node);
	}

	/* deferred actions that can cause this browser_window to be destroyed
	 * and must therefore be done after set_status/pointer
	 */
	switch (action) {
	case ACTION_SUBMIT:
		form_submit(content_get_url(c),
				browser_window_find_target(bw, target, mouse),
				gadget->form, gadget);
		break;
	case ACTION_GO:
		browser_window_go(browser_window_find_target(bw, target, mouse),
				nsurl_access(url),
				nsurl_access(content_get_url(c)), true);
		break;
	case ACTION_NONE:
		break;
	}
}
Beispiel #2
0
/**
 * Dump a computed style \a style to the give file handle \a stream.
 *
 * \param stream  Stream to write to
 * \param style   Computed style to dump
 */
void nscss_dump_computed_style(FILE *stream, const css_computed_style *style)
{
	uint8_t val;
	css_color color = 0;
	lwc_string *url = NULL;
	css_fixed len1 = 0, len2 = 0;
	css_unit unit1 = CSS_UNIT_PX, unit2 = CSS_UNIT_PX;
	css_computed_clip_rect rect = { 0, 0, 0, 0, CSS_UNIT_PX, CSS_UNIT_PX,
					CSS_UNIT_PX, CSS_UNIT_PX, true, true,
					true, true };
	const css_computed_content_item *content = NULL;
	const css_computed_counter *counter = NULL;
	lwc_string **string_list = NULL;
	int32_t zindex = 0;

	fprintf(stream, "{ ");

	/* background-attachment */
	val = css_computed_background_attachment(style);
	switch (val) {
	case CSS_BACKGROUND_ATTACHMENT_FIXED:
		fprintf(stream, "background-attachment: fixed ");
		break;
	case CSS_BACKGROUND_ATTACHMENT_SCROLL:
		fprintf(stream, "background-attachment: scroll ");
		break;
	default:
		break;
	}

	/* background-color */
	val = css_computed_background_color(style, &color);
	switch (val) {
	case CSS_BACKGROUND_COLOR_COLOR:
		fprintf(stream, "background-color: #%08x ", color);
		break;
	default:
		break;
	}

	/* background-image */
	val = css_computed_background_image(style, &url);
	if (val == CSS_BACKGROUND_IMAGE_IMAGE && url != NULL) {
		fprintf(stream, "background-image: url('%.*s') ",
				(int) lwc_string_length(url), 
				lwc_string_data(url));
	} else if (val == CSS_BACKGROUND_IMAGE_NONE) {
		fprintf(stream, "background-image: none ");
	}

	/* background-position */
	val = css_computed_background_position(style, &len1, &unit1,
			&len2, &unit2);
	if (val == CSS_BACKGROUND_POSITION_SET) {
		fprintf(stream, "background-position: ");
		dump_css_unit(stream, len1, unit1);
		fprintf(stream, " ");
		dump_css_unit(stream, len2, unit2);
		fprintf(stream, " ");
	}

	/* background-repeat */
	val = css_computed_background_repeat(style);
	switch (val) {
	case CSS_BACKGROUND_REPEAT_REPEAT_X:
		fprintf(stream, "background-repeat: repeat-x ");
		break;
	case CSS_BACKGROUND_REPEAT_REPEAT_Y:
		fprintf(stream, "background-repeat: repeat-y ");
		break;
	case CSS_BACKGROUND_REPEAT_REPEAT:
		fprintf(stream, "background-repeat: repeat ");
		break;
	case CSS_BACKGROUND_REPEAT_NO_REPEAT:
		fprintf(stream, "background-repeat: no-repeat ");
		break;
	default:
		break;
	}

	/* border-collapse */
	val = css_computed_border_collapse(style);
	switch (val) {
	case CSS_BORDER_COLLAPSE_SEPARATE:
		fprintf(stream, "border-collapse: separate ");
		break;
	case CSS_BORDER_COLLAPSE_COLLAPSE:
		fprintf(stream, "border-collapse: collapse ");
		break;
	default:

		break;
	}

	/* border-spacing */
	val = css_computed_border_spacing(style, &len1, &unit1, &len2, &unit2);
	if (val == CSS_BORDER_SPACING_SET) {
		fprintf(stream, "border-spacing: ");
		dump_css_unit(stream, len1, unit1);
		fprintf(stream, " ");
		dump_css_unit(stream, len2, unit2);
		fprintf(stream, " ");
	}

	/* border-top-color */
	val = css_computed_border_top_color(style, &color);
	switch (val) {
	case CSS_BORDER_COLOR_COLOR:
		fprintf(stream, "border-top-color: #%08x ", color);
		break;
	default:
		break;
	}

	/* border-right-color */
	val = css_computed_border_right_color(style, &color);
	switch (val) {
	case CSS_BORDER_COLOR_COLOR:
		fprintf(stream, "border-right-color: #%08x ", color);
		break;
	default:
		break;
	}

	/* border-bottom-color */
	val = css_computed_border_bottom_color(style, &color);
	switch (val) {
	case CSS_BORDER_COLOR_COLOR:
		fprintf(stream, "border-bottom-color: #%08x ", color);
		break;
	default:
		break;
	}

	/* border-left-color */
	val = css_computed_border_left_color(style, &color);
	switch (val) {
	case CSS_BORDER_COLOR_COLOR:
		fprintf(stream, "border-left-color: #%08x ", color);
		break;
	default:
		break;
	}

	/* border-top-style */
	val = css_computed_border_top_style(style);
	switch (val) {
	case CSS_BORDER_STYLE_NONE:
		fprintf(stream, "border-top-style: none ");
		break;
	case CSS_BORDER_STYLE_HIDDEN:
		fprintf(stream, "border-top-style: hidden ");
		break;
	case CSS_BORDER_STYLE_DOTTED:
		fprintf(stream, "border-top-style: dotted ");
		break;
	case CSS_BORDER_STYLE_DASHED:
		fprintf(stream, "border-top-style: dashed ");
		break;
	case CSS_BORDER_STYLE_SOLID:
		fprintf(stream, "border-top-style: solid ");
		break;
	case CSS_BORDER_STYLE_DOUBLE:
		fprintf(stream, "border-top-style: double ");
		break;
	case CSS_BORDER_STYLE_GROOVE:
		fprintf(stream, "border-top-style: groove ");
		break;
	case CSS_BORDER_STYLE_RIDGE:
		fprintf(stream, "border-top-style: ridge ");
		break;
	case CSS_BORDER_STYLE_INSET:
		fprintf(stream, "border-top-style: inset ");
		break;
	case CSS_BORDER_STYLE_OUTSET:
		fprintf(stream, "border-top-style: outset ");
		break;
	default:
		break;
	}

	/* border-right-style */
	val = css_computed_border_right_style(style);
	switch (val) {
	case CSS_BORDER_STYLE_NONE:
		fprintf(stream, "border-right-style: none ");
		break;
	case CSS_BORDER_STYLE_HIDDEN:
		fprintf(stream, "border-right-style: hidden ");
		break;
	case CSS_BORDER_STYLE_DOTTED:
		fprintf(stream, "border-right-style: dotted ");
		break;
	case CSS_BORDER_STYLE_DASHED:
		fprintf(stream, "border-right-style: dashed ");
		break;
	case CSS_BORDER_STYLE_SOLID:
		fprintf(stream, "border-right-style: solid ");
		break;
	case CSS_BORDER_STYLE_DOUBLE:
		fprintf(stream, "border-right-style: double ");
		break;
	case CSS_BORDER_STYLE_GROOVE:
		fprintf(stream, "border-right-style: groove ");
		break;
	case CSS_BORDER_STYLE_RIDGE:
		fprintf(stream, "border-right-style: ridge ");
		break;
	case CSS_BORDER_STYLE_INSET:
		fprintf(stream, "border-right-style: inset ");
		break;
	case CSS_BORDER_STYLE_OUTSET:
		fprintf(stream, "border-right-style: outset ");
		break;
	default:
		break;
	}

	/* border-bottom-style */
	val = css_computed_border_bottom_style(style);
	switch (val) {
	case CSS_BORDER_STYLE_NONE:
		fprintf(stream, "border-bottom-style: none ");
		break;
	case CSS_BORDER_STYLE_HIDDEN:
		fprintf(stream, "border-bottom-style: hidden ");
		break;
	case CSS_BORDER_STYLE_DOTTED:
		fprintf(stream, "border-bottom-style: dotted ");
		break;
	case CSS_BORDER_STYLE_DASHED:
		fprintf(stream, "border-bottom-style: dashed ");
		break;
	case CSS_BORDER_STYLE_SOLID:
		fprintf(stream, "border-bottom-style: solid ");
		break;
	case CSS_BORDER_STYLE_DOUBLE:
		fprintf(stream, "border-bottom-style: double ");
		break;
	case CSS_BORDER_STYLE_GROOVE:
		fprintf(stream, "border-bottom-style: groove ");
		break;
	case CSS_BORDER_STYLE_RIDGE:
		fprintf(stream, "border-bottom-style: ridge ");
		break;
	case CSS_BORDER_STYLE_INSET:
		fprintf(stream, "border-bottom-style: inset ");
		break;
	case CSS_BORDER_STYLE_OUTSET:
		fprintf(stream, "border-bottom-style: outset ");
		break;
	default:
		break;
	}

	/* border-left-style */
	val = css_computed_border_left_style(style);
	switch (val) {
	case CSS_BORDER_STYLE_NONE:
		fprintf(stream, "border-left-style: none ");
		break;
	case CSS_BORDER_STYLE_HIDDEN:
		fprintf(stream, "border-left-style: hidden ");
		break;
	case CSS_BORDER_STYLE_DOTTED:
		fprintf(stream, "border-left-style: dotted ");
		break;
	case CSS_BORDER_STYLE_DASHED:
		fprintf(stream, "border-left-style: dashed ");
		break;
	case CSS_BORDER_STYLE_SOLID:
		fprintf(stream, "border-left-style: solid ");
		break;
	case CSS_BORDER_STYLE_DOUBLE:
		fprintf(stream, "border-left-style: double ");
		break;
	case CSS_BORDER_STYLE_GROOVE:
		fprintf(stream, "border-left-style: groove ");
		break;
	case CSS_BORDER_STYLE_RIDGE:
		fprintf(stream, "border-left-style: ridge ");
		break;
	case CSS_BORDER_STYLE_INSET:
		fprintf(stream, "border-left-style: inset ");
		break;
	case CSS_BORDER_STYLE_OUTSET:
		fprintf(stream, "border-left-style: outset ");
		break;
	default:
		break;
	}

	/* border-top-width */
	val = css_computed_border_top_width(style, &len1, &unit1);
	switch (val) {
	case CSS_BORDER_WIDTH_THIN:
		fprintf(stream, "border-top-width: thin ");
		break;
	case CSS_BORDER_WIDTH_MEDIUM:
		fprintf(stream, "border-top-width: medium ");
		break;
	case CSS_BORDER_WIDTH_THICK:
		fprintf(stream, "border-top-width: thick ");
		break;
	case CSS_BORDER_WIDTH_WIDTH:
		fprintf(stream, "border-top-width: ");
		dump_css_unit(stream, len1, unit1);
		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* border-right-width */
	val = css_computed_border_right_width(style, &len1, &unit1);
	switch (val) {
	case CSS_BORDER_WIDTH_THIN:
		fprintf(stream, "border-right-width: thin ");
		break;
	case CSS_BORDER_WIDTH_MEDIUM:
		fprintf(stream, "border-right-width: medium ");
		break;
	case CSS_BORDER_WIDTH_THICK:
		fprintf(stream, "border-right-width: thick ");
		break;
	case CSS_BORDER_WIDTH_WIDTH:
		fprintf(stream, "border-right-width: ");
		dump_css_unit(stream, len1, unit1);
		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* border-bottom-width */
	val = css_computed_border_bottom_width(style, &len1, &unit1);
	switch (val) {
	case CSS_BORDER_WIDTH_THIN:
		fprintf(stream, "border-bottom-width: thin ");
		break;
	case CSS_BORDER_WIDTH_MEDIUM:
		fprintf(stream, "border-bottom-width: medium ");
		break;
	case CSS_BORDER_WIDTH_THICK:
		fprintf(stream, "border-bottom-width: thick ");
		break;
	case CSS_BORDER_WIDTH_WIDTH:
		fprintf(stream, "border-bottom-width: ");
		dump_css_unit(stream, len1, unit1);
		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* border-left-width */
	val = css_computed_border_left_width(style, &len1, &unit1);
	switch (val) {
	case CSS_BORDER_WIDTH_THIN:
		fprintf(stream, "border-left-width: thin ");
		break;
	case CSS_BORDER_WIDTH_MEDIUM:
		fprintf(stream, "border-left-width: medium ");
		break;
	case CSS_BORDER_WIDTH_THICK:
		fprintf(stream, "border-left-width: thick ");
		break;
	case CSS_BORDER_WIDTH_WIDTH:
		fprintf(stream, "border-left-width: ");
		dump_css_unit(stream, len1, unit1);
		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* bottom */
	val = css_computed_bottom(style, &len1, &unit1);
	switch (val) {
	case CSS_BOTTOM_AUTO:
		fprintf(stream, "bottom: auto ");
		break;
	case CSS_BOTTOM_SET:
		fprintf(stream, "bottom: ");
		dump_css_unit(stream, len1, unit1);
		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* caption-side */
	val = css_computed_caption_side(style);
	switch (val) {
	case CSS_CAPTION_SIDE_TOP:
		fprintf(stream, "caption_side: top ");
		break;
	case CSS_CAPTION_SIDE_BOTTOM:
		fprintf(stream, "caption_side: bottom ");
		break;
	default:
		break;
	}

	/* clear */
	val = css_computed_clear(style);
	switch (val) {
	case CSS_CLEAR_NONE:
		fprintf(stream, "clear: none ");
		break;
	case CSS_CLEAR_LEFT:
		fprintf(stream, "clear: left ");
		break;
	case CSS_CLEAR_RIGHT:
		fprintf(stream, "clear: right ");
		break;
	case CSS_CLEAR_BOTH:
		fprintf(stream, "clear: both ");
		break;
	default:
		break;
	}

	/* clip */
	val = css_computed_clip(style, &rect);
	switch (val) {
	case CSS_CLIP_AUTO:
		fprintf(stream, "clip: auto ");
		break;
	case CSS_CLIP_RECT:
		fprintf(stream, "clip: rect( ");

		if (rect.top_auto)
			fprintf(stream, "auto");
		else
			dump_css_unit(stream, rect.top, rect.tunit);
		fprintf(stream, ", ");

		if (rect.right_auto)
			fprintf(stream, "auto");
		else
			dump_css_unit(stream, rect.right, rect.runit);
		fprintf(stream, ", ");

		if (rect.bottom_auto)
			fprintf(stream, "auto");
		else
			dump_css_unit(stream, rect.bottom, rect.bunit);
		fprintf(stream, ", ");

		if (rect.left_auto)
			fprintf(stream, "auto");
		else
			dump_css_unit(stream, rect.left, rect.lunit);
		fprintf(stream, ") ");
		break;
	default:
		break;
	}

	/* color */
	val = css_computed_color(style, &color);
	if (val == CSS_COLOR_COLOR) {
		fprintf(stream, "color: #%08x ", color);
	}

	/* content */
	val = css_computed_content(style, &content);
	switch (val) {
	case CSS_CONTENT_NONE:
		fprintf(stream, "content: none ");
		break;
	case CSS_CONTENT_NORMAL:
		fprintf(stream, "content: normal ");
		break;
	case CSS_CONTENT_SET:
		fprintf(stream, "content:");

		while (content->type != CSS_COMPUTED_CONTENT_NONE) {
			fprintf(stream, " ");

			switch (content->type) {
			case CSS_COMPUTED_CONTENT_STRING:
				fprintf(stream,	"\"%.*s\"",
						(int) lwc_string_length(
						content->data.string),
						lwc_string_data(
						content->data.string));
				break;
			case CSS_COMPUTED_CONTENT_URI:
				fprintf(stream,	"uri(\"%.*s\")",
						(int) lwc_string_length(
						content->data.uri),
						lwc_string_data(
						content->data.uri));
				break;
			case CSS_COMPUTED_CONTENT_COUNTER:
				fprintf(stream, "counter(%.*s)",
						(int) lwc_string_length(
						content->data.counter.name),
						lwc_string_data(
						content->data.counter.name));
				break;
			case CSS_COMPUTED_CONTENT_COUNTERS:
				fprintf(stream, "counters(%.*s, \"%.*s\")",
						(int) lwc_string_length(
						content->data.counters.name),
						lwc_string_data(
						content->data.counters.name),
						(int) lwc_string_length(
						content->data.counters.sep),
						lwc_string_data(
						content->data.counters.sep));
				break;
			case CSS_COMPUTED_CONTENT_ATTR:
				fprintf(stream, "attr(%.*s)",
						(int) lwc_string_length(
						content->data.attr),
						lwc_string_data(
						content->data.attr));
				break;
			case CSS_COMPUTED_CONTENT_OPEN_QUOTE:
				fprintf(stream, "open-quote");
				break;
			case CSS_COMPUTED_CONTENT_CLOSE_QUOTE:
				fprintf(stream, "close-quote");
				break;
			case CSS_COMPUTED_CONTENT_NO_OPEN_QUOTE:
				fprintf(stream, "no-open-quote");
				break;
			case CSS_COMPUTED_CONTENT_NO_CLOSE_QUOTE:
				fprintf(stream, "no-close-quote");
				break;
			}

			content++;
		}

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* counter-increment */
	val = css_computed_counter_increment(style, &counter);
	if ((val == CSS_COUNTER_INCREMENT_NONE) || (counter == NULL)) {
		fprintf(stream, "counter-increment: none ");
	} else {
		fprintf(stream, "counter-increment:");

		while (counter->name != NULL) {
			fprintf(stream, " %.*s ",
					(int) lwc_string_length(counter->name),
					lwc_string_data(counter->name));

			dump_css_fixed(stream, counter->value);

			counter++;
		}

		fprintf(stream, " ");
	}

	/* counter-reset */
	val = css_computed_counter_reset(style, &counter);
	if ((val == CSS_COUNTER_RESET_NONE) || (counter == NULL)) {
		fprintf(stream, "counter-reset: none ");
	} else {
		fprintf(stream, "counter-reset:");

		while (counter->name != NULL) {
			fprintf(stream, " %.*s ",
					(int) lwc_string_length(counter->name),
					lwc_string_data(counter->name));

			dump_css_fixed(stream, counter->value);

			counter++;
		}

		fprintf(stream, " ");
	}

	/* cursor */
	val = css_computed_cursor(style, &string_list);
	fprintf(stream, "cursor:");

	if (string_list != NULL) {
		while (*string_list != NULL) {
			fprintf(stream, " url\"%.*s\")",
					(int) lwc_string_length(*string_list),
					lwc_string_data(*string_list));

			string_list++;
		}
	}
	switch (val) {
	case CSS_CURSOR_AUTO:
		fprintf(stream, " auto ");
		break;
	case CSS_CURSOR_CROSSHAIR:
		fprintf(stream, " crosshair ");
		break;
	case CSS_CURSOR_DEFAULT:
		fprintf(stream, " default ");
		break;
	case CSS_CURSOR_POINTER:
		fprintf(stream, " pointer ");
		break;
	case CSS_CURSOR_MOVE:
		fprintf(stream, " move ");
		break;
	case CSS_CURSOR_E_RESIZE:
		fprintf(stream, " e-resize ");
		break;
	case CSS_CURSOR_NE_RESIZE:
		fprintf(stream, " ne-resize ");
		break;
	case CSS_CURSOR_NW_RESIZE:
		fprintf(stream, " nw-resize ");
		break;
	case CSS_CURSOR_N_RESIZE:
		fprintf(stream, " n-resize ");
		break;
	case CSS_CURSOR_SE_RESIZE:
		fprintf(stream, " se-resize ");
		break;
	case CSS_CURSOR_SW_RESIZE:
		fprintf(stream, " sw-resize ");
		break;
	case CSS_CURSOR_S_RESIZE:
		fprintf(stream, " s-resize ");
		break;
	case CSS_CURSOR_W_RESIZE:
		fprintf(stream, " w-resize ");
		break;
	case CSS_CURSOR_TEXT:
		fprintf(stream, " text ");
		break;
	case CSS_CURSOR_WAIT:
		fprintf(stream, " wait ");
		break;
	case CSS_CURSOR_HELP:
		fprintf(stream, " help ");
		break;
	case CSS_CURSOR_PROGRESS:
		fprintf(stream, " progress ");
		break;
	default:
		break;
	}

	/* direction */
	val = css_computed_direction(style);
	switch (val) {
	case CSS_DIRECTION_LTR:
		fprintf(stream, "direction: ltr ");
		break;
	case CSS_DIRECTION_RTL:
		fprintf(stream, "direction: rtl ");
		break;
	default:
		break;
	}

	/* display */
	val = css_computed_display_static(style);
	switch (val) {
	case CSS_DISPLAY_INLINE:
		fprintf(stream, "display: inline ");
		break;
	case CSS_DISPLAY_BLOCK:
		fprintf(stream, "display: block ");
		break;
	case CSS_DISPLAY_LIST_ITEM:
		fprintf(stream, "display: list-item ");
		break;
	case CSS_DISPLAY_RUN_IN:
		fprintf(stream, "display: run-in ");
		break;
	case CSS_DISPLAY_INLINE_BLOCK:
		fprintf(stream, "display: inline-block ");
		break;
	case CSS_DISPLAY_TABLE:
		fprintf(stream, "display: table ");
		break;
	case CSS_DISPLAY_INLINE_TABLE:
		fprintf(stream, "display: inline-table ");
		break;
	case CSS_DISPLAY_TABLE_ROW_GROUP:
		fprintf(stream, "display: table-row-group ");
		break;
	case CSS_DISPLAY_TABLE_HEADER_GROUP:
		fprintf(stream, "display: table-header-group ");
		break;
	case CSS_DISPLAY_TABLE_FOOTER_GROUP:
		fprintf(stream, "display: table-footer-group ");
		break;
	case CSS_DISPLAY_TABLE_ROW:
		fprintf(stream, "display: table-row ");
		break;
	case CSS_DISPLAY_TABLE_COLUMN_GROUP:
		fprintf(stream, "display: table-column-group ");
		break;
	case CSS_DISPLAY_TABLE_COLUMN:
		fprintf(stream, "display: table-column ");
		break;
	case CSS_DISPLAY_TABLE_CELL:
		fprintf(stream, "display: table-cell ");
		break;
	case CSS_DISPLAY_TABLE_CAPTION:
		fprintf(stream, "display: table-caption ");
		break;
	case CSS_DISPLAY_NONE:
		fprintf(stream, "display: none ");
		break;
	default:
		break;
	}

	/* empty-cells */
	val = css_computed_empty_cells(style);
	switch (val) {
	case CSS_EMPTY_CELLS_SHOW:
		fprintf(stream, "empty-cells: show ");
		break;
	case CSS_EMPTY_CELLS_HIDE:
		fprintf(stream, "empty-cells: hide ");
		break;
	default:
		break;
	}

	/* float */
	val = css_computed_float(style);
	switch (val) {
	case CSS_FLOAT_LEFT:
		fprintf(stream, "float: left ");
		break;
	case CSS_FLOAT_RIGHT:
		fprintf(stream, "float: right ");
		break;
	case CSS_FLOAT_NONE:
		fprintf(stream, "float: none ");
		break;
	default:
		break;
	}

	/* font-family */
	val = css_computed_font_family(style, &string_list);
	if (val != CSS_FONT_FAMILY_INHERIT) {
		fprintf(stream, "font-family:");

		if (string_list != NULL) {
			while (*string_list != NULL) {
				fprintf(stream, " \"%.*s\"",
					(int) lwc_string_length(*string_list),
					lwc_string_data(*string_list));

				string_list++;
			}
		}
		switch (val) {
		case CSS_FONT_FAMILY_SERIF:
			fprintf(stream, " serif ");
			break;
		case CSS_FONT_FAMILY_SANS_SERIF:
			fprintf(stream, " sans-serif ");
			break;
		case CSS_FONT_FAMILY_CURSIVE:
			fprintf(stream, " cursive ");
			break;
		case CSS_FONT_FAMILY_FANTASY:
			fprintf(stream, " fantasy ");
			break;
		case CSS_FONT_FAMILY_MONOSPACE:
			fprintf(stream, " monospace ");
			break;
		}
	}

	/* font-size */
	val = css_computed_font_size(style, &len1, &unit1);
	switch (val) {
	case CSS_FONT_SIZE_XX_SMALL:
		fprintf(stream, "font-size: xx-small ");
		break;
	case CSS_FONT_SIZE_X_SMALL:
		fprintf(stream, "font-size: x-small ");
		break;
	case CSS_FONT_SIZE_SMALL:
		fprintf(stream, "font-size: small ");
		break;
	case CSS_FONT_SIZE_MEDIUM:
		fprintf(stream, "font-size: medium ");
		break;
	case CSS_FONT_SIZE_LARGE:
		fprintf(stream, "font-size: large ");
		break;
	case CSS_FONT_SIZE_X_LARGE:
		fprintf(stream, "font-size: x-large ");
		break;
	case CSS_FONT_SIZE_XX_LARGE:
		fprintf(stream, "font-size: xx-large ");
		break;
	case CSS_FONT_SIZE_LARGER:
		fprintf(stream, "font-size: larger ");
		break;
	case CSS_FONT_SIZE_SMALLER:
		fprintf(stream, "font-size: smaller ");
		break;
	case CSS_FONT_SIZE_DIMENSION:
		fprintf(stream, "font-size: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* font-style */
	val = css_computed_font_style(style);
	switch (val) {
	case CSS_FONT_STYLE_NORMAL:
		fprintf(stream, "font-style: normal ");
		break;
	case CSS_FONT_STYLE_ITALIC:
		fprintf(stream, "font-style: italic ");
		break;
	case CSS_FONT_STYLE_OBLIQUE:
		fprintf(stream, "font-style: oblique ");
		break;
	default:
		break;
	}

	/* font-variant */
	val = css_computed_font_variant(style);
	switch (val) {
	case CSS_FONT_VARIANT_NORMAL:
		fprintf(stream, "font-variant: normal ");
		break;
	case CSS_FONT_VARIANT_SMALL_CAPS:
		fprintf(stream, "font-variant: small-caps ");
		break;
	default:
		break;
	}

	/* font-weight */
	val = css_computed_font_weight(style);
	switch (val) {
	case CSS_FONT_WEIGHT_NORMAL:
		fprintf(stream, "font-weight: normal ");
		break;
	case CSS_FONT_WEIGHT_BOLD:
		fprintf(stream, "font-weight: bold ");
		break;
	case CSS_FONT_WEIGHT_BOLDER:
		fprintf(stream, "font-weight: bolder ");
		break;
	case CSS_FONT_WEIGHT_LIGHTER:
		fprintf(stream, "font-weight: lighter ");
		break;
	case CSS_FONT_WEIGHT_100:
		fprintf(stream, "font-weight: 100 ");
		break;
	case CSS_FONT_WEIGHT_200:
		fprintf(stream, "font-weight: 200 ");
		break;
	case CSS_FONT_WEIGHT_300:
		fprintf(stream, "font-weight: 300 ");
		break;
	case CSS_FONT_WEIGHT_400:
		fprintf(stream, "font-weight: 400 ");
		break;
	case CSS_FONT_WEIGHT_500:
		fprintf(stream, "font-weight: 500 ");
		break;
	case CSS_FONT_WEIGHT_600:
		fprintf(stream, "font-weight: 600 ");
		break;
	case CSS_FONT_WEIGHT_700:
		fprintf(stream, "font-weight: 700 ");
		break;
	case CSS_FONT_WEIGHT_800:
		fprintf(stream, "font-weight: 800 ");
		break;
	case CSS_FONT_WEIGHT_900:
		fprintf(stream, "font-weight: 900 ");
		break;
	default:
		break;
	}

	/* height */
	val = css_computed_height(style, &len1, &unit1);
	switch (val) {
	case CSS_HEIGHT_AUTO:
		fprintf(stream, "height: auto ");
		break;
	case CSS_HEIGHT_SET:
		fprintf(stream, "height: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* left */
	val = css_computed_left(style, &len1, &unit1);
	switch (val) {
	case CSS_LEFT_AUTO:
		fprintf(stream, "left: auto ");
		break;
	case CSS_LEFT_SET:
		fprintf(stream, "left: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* letter-spacing */
	val = css_computed_letter_spacing(style, &len1, &unit1);
	switch (val) {
	case CSS_LETTER_SPACING_NORMAL:
		fprintf(stream, "letter-spacing: normal ");
		break;
	case CSS_LETTER_SPACING_SET:
		fprintf(stream, "letter-spacing: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* line-height */
	val = css_computed_line_height(style, &len1, &unit1);
	switch (val) {
	case CSS_LINE_HEIGHT_NORMAL:
		fprintf(stream, "line-height: normal ");
		break;
	case CSS_LINE_HEIGHT_NUMBER:
		fprintf(stream, "line-height: ");

		dump_css_fixed(stream, len1);

		fprintf(stream, " ");
		break;
	case CSS_LINE_HEIGHT_DIMENSION:
		fprintf(stream, "line-height: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* list-style-image */
	val = css_computed_list_style_image(style, &url);
	if (url != NULL) {
		fprintf(stream, "list-style-image: url('%.*s') ",
				(int) lwc_string_length(url), 
				lwc_string_data(url));
	} else if (val == CSS_LIST_STYLE_IMAGE_NONE) {
		fprintf(stream, "list-style-image: none ");
	}

	/* list-style-position */
	val = css_computed_list_style_position(style);
	switch (val) {
	case CSS_LIST_STYLE_POSITION_INSIDE:
		fprintf(stream, "list-style-position: inside ");
		break;
	case CSS_LIST_STYLE_POSITION_OUTSIDE:
		fprintf(stream, "list-style-position: outside ");
		break;
	default:
		break;
	}

	/* list-style-type */
	val = css_computed_list_style_type(style);
	switch (val) {
	case CSS_LIST_STYLE_TYPE_DISC:
		fprintf(stream, "list-style-type: disc ");
		break;
	case CSS_LIST_STYLE_TYPE_CIRCLE:
		fprintf(stream, "list-style-type: circle ");
		break;
	case CSS_LIST_STYLE_TYPE_SQUARE:
		fprintf(stream, "list-style-type: square ");
		break;
	case CSS_LIST_STYLE_TYPE_DECIMAL:
		fprintf(stream, "list-style-type: decimal ");
		break;
	case CSS_LIST_STYLE_TYPE_DECIMAL_LEADING_ZERO:
		fprintf(stream, "list-style-type: decimal-leading-zero ");
		break;
	case CSS_LIST_STYLE_TYPE_LOWER_ROMAN:
		fprintf(stream, "list-style-type: lower-roman ");
		break;
	case CSS_LIST_STYLE_TYPE_UPPER_ROMAN:
		fprintf(stream, "list-style-type: upper-roman ");
		break;
	case CSS_LIST_STYLE_TYPE_LOWER_GREEK:
		fprintf(stream, "list-style-type: lower-greek ");
		break;
	case CSS_LIST_STYLE_TYPE_LOWER_LATIN:
		fprintf(stream, "list-style-type: lower-latin ");
		break;
	case CSS_LIST_STYLE_TYPE_UPPER_LATIN:
		fprintf(stream, "list-style-type: upper-latin ");
		break;
	case CSS_LIST_STYLE_TYPE_ARMENIAN:
		fprintf(stream, "list-style-type: armenian ");
		break;
	case CSS_LIST_STYLE_TYPE_GEORGIAN:
		fprintf(stream, "list-style-type: georgian ");
		break;
	case CSS_LIST_STYLE_TYPE_LOWER_ALPHA:
		fprintf(stream, "list-style-type: lower-alpha ");
		break;
	case CSS_LIST_STYLE_TYPE_UPPER_ALPHA:
		fprintf(stream, "list-style-type: upper-alpha ");
		break;
	case CSS_LIST_STYLE_TYPE_NONE:
		fprintf(stream, "list-style-type: none ");
		break;
	default:
		break;
	}

	/* margin-top */
	val = css_computed_margin_top(style, &len1, &unit1);
	switch (val) {
	case CSS_MARGIN_AUTO:
		fprintf(stream, "margin-top: auto ");
		break;
	case CSS_MARGIN_SET:
		fprintf(stream, "margin-top: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* margin-right */
	val = css_computed_margin_right(style, &len1, &unit1);
	switch (val) {
	case CSS_MARGIN_AUTO:
		fprintf(stream, "margin-right: auto ");
		break;
	case CSS_MARGIN_SET:
		fprintf(stream, "margin-right: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* margin-bottom */
	val = css_computed_margin_bottom(style, &len1, &unit1);
	switch (val) {
	case CSS_MARGIN_AUTO:
		fprintf(stream, "margin-bottom: auto ");
		break;
	case CSS_MARGIN_SET:
		fprintf(stream, "margin-bottom: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* margin-left */
	val = css_computed_margin_left(style, &len1, &unit1);
	switch (val) {
	case CSS_MARGIN_AUTO:
		fprintf(stream, "margin-left: auto ");
		break;
	case CSS_MARGIN_SET:
		fprintf(stream, "margin-left: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* max-height */
	val = css_computed_max_height(style, &len1, &unit1);
	switch (val) {
	case CSS_MAX_HEIGHT_NONE:
		fprintf(stream, "max-height: none ");
		break;
	case CSS_MAX_HEIGHT_SET:
		fprintf(stream, "max-height: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* max-width */
	val = css_computed_max_width(style, &len1, &unit1);
	switch (val) {
	case CSS_MAX_WIDTH_NONE:
		fprintf(stream, "max-width: none ");
		break;
	case CSS_MAX_WIDTH_SET:
		fprintf(stream, "max-width: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* min-height */
	val = css_computed_min_height(style, &len1, &unit1);
	switch (val) {
	case CSS_MIN_HEIGHT_SET:
		fprintf(stream, "min-height: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* min-width */
	val = css_computed_min_width(style, &len1, &unit1);
	switch (val) {
	case CSS_MIN_WIDTH_SET:
		fprintf(stream, "min-width: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* opacity */
	val = css_computed_opacity(style, &len1);
	switch (val) {
	case CSS_OPACITY_SET:
		fprintf(stream, "opacity: ");

		dump_css_fixed(stream, len1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* outline-color */
	val = css_computed_outline_color(style, &color);
	switch (val) {
	case CSS_OUTLINE_COLOR_INVERT:
		fprintf(stream, "outline-color: invert ");
		break;
	case CSS_OUTLINE_COLOR_COLOR:
		fprintf(stream, "outline-color: #%08x ", color);
		break;
	default:
		break;
	}

	/* outline-style */
	val = css_computed_outline_style(style);
	switch (val) {
	case CSS_OUTLINE_STYLE_NONE:
		fprintf(stream, "outline-style: none ");
		break;
	case CSS_OUTLINE_STYLE_DOTTED:
		fprintf(stream, "outline-style: dotted ");
		break;
	case CSS_OUTLINE_STYLE_DASHED:
		fprintf(stream, "outline-style: dashed ");
		break;
	case CSS_OUTLINE_STYLE_SOLID:
		fprintf(stream, "outline-style: solid ");
		break;
	case CSS_OUTLINE_STYLE_DOUBLE:
		fprintf(stream, "outline-style: double ");
		break;
	case CSS_OUTLINE_STYLE_GROOVE:
		fprintf(stream, "outline-style: groove ");
		break;
	case CSS_OUTLINE_STYLE_RIDGE:
		fprintf(stream, "outline-style: ridge ");
		break;
	case CSS_OUTLINE_STYLE_INSET:
		fprintf(stream, "outline-style: inset ");
		break;
	case CSS_OUTLINE_STYLE_OUTSET:
		fprintf(stream, "outline-style: outset ");
		break;
	default:
		break;
	}

	/* outline-width */
	val = css_computed_outline_width(style, &len1, &unit1);
	switch (val) {
	case CSS_OUTLINE_WIDTH_THIN:
		fprintf(stream, "outline-width: thin ");
		break;
	case CSS_OUTLINE_WIDTH_MEDIUM:
		fprintf(stream, "outline-width: medium ");
		break;
	case CSS_OUTLINE_WIDTH_THICK:
		fprintf(stream, "outline-width: thick ");
		break;
	case CSS_OUTLINE_WIDTH_WIDTH:
		fprintf(stream, "outline-width: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* overflow */
	val = css_computed_overflow(style);
	switch (val) {
	case CSS_OVERFLOW_VISIBLE:
		fprintf(stream, "overflow: visible ");
		break;
	case CSS_OVERFLOW_HIDDEN:
		fprintf(stream, "overflow: hidden ");
		break;
	case CSS_OVERFLOW_SCROLL:
		fprintf(stream, "overflow: scroll ");
		break;
	case CSS_OVERFLOW_AUTO:
		fprintf(stream, "overflow: auto ");
		break;
	default:
		break;
	}

	/* padding-top */
	val = css_computed_padding_top(style, &len1, &unit1);
	switch (val) {
	case CSS_PADDING_SET:
		fprintf(stream, "padding-top: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* padding-right */
	val = css_computed_padding_right(style, &len1, &unit1);
	switch (val) {
	case CSS_PADDING_SET:
		fprintf(stream, "padding-right: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* padding-bottom */
	val = css_computed_padding_bottom(style, &len1, &unit1);
	switch (val) {
	case CSS_PADDING_SET:
		fprintf(stream, "padding-bottom: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* padding-left */
	val = css_computed_padding_left(style, &len1, &unit1);
	switch (val) {
	case CSS_PADDING_SET:
		fprintf(stream, "padding-left: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* position */
	val = css_computed_position(style);
	switch (val) {
	case CSS_POSITION_STATIC:
		fprintf(stream, "position: static ");
		break;
	case CSS_POSITION_RELATIVE:
		fprintf(stream, "position: relative ");
		break;
	case CSS_POSITION_ABSOLUTE:
		fprintf(stream, "position: absolute ");
		break;
	case CSS_POSITION_FIXED:
		fprintf(stream, "position: fixed ");
		break;
	default:
		break;
	}

	/* quotes */
	val = css_computed_quotes(style, &string_list);
	if (val == CSS_QUOTES_STRING && string_list != NULL) {
		fprintf(stream, "quotes:");

		while (*string_list != NULL) {
			fprintf(stream, " \"%.*s\"",
				(int) lwc_string_length(*string_list),
				lwc_string_data(*string_list));

			string_list++;
		}

		fprintf(stream, " ");
	} else {
		switch (val) {
		case CSS_QUOTES_NONE:
			fprintf(stream, "quotes: none ");
			break;
		default:
			break;
		}
	}

	/* right */
	val = css_computed_right(style, &len1, &unit1);
	switch (val) {
	case CSS_RIGHT_AUTO:
		fprintf(stream, "right: auto ");
		break;
	case CSS_RIGHT_SET:
		fprintf(stream, "right: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* table-layout */
	val = css_computed_table_layout(style);
	switch (val) {
	case CSS_TABLE_LAYOUT_AUTO:
		fprintf(stream, "table-layout: auto ");
		break;
	case CSS_TABLE_LAYOUT_FIXED:
		fprintf(stream, "table-layout: fixed ");
		break;
	default:
		break;
	}

	/* text-align */
	val = css_computed_text_align(style);
	switch (val) {
	case CSS_TEXT_ALIGN_LEFT:
		fprintf(stream, "text-align: left ");
		break;
	case CSS_TEXT_ALIGN_RIGHT:
		fprintf(stream, "text-align: right ");
		break;
	case CSS_TEXT_ALIGN_CENTER:
		fprintf(stream, "text-align: center ");
		break;
	case CSS_TEXT_ALIGN_JUSTIFY:
		fprintf(stream, "text-align: justify ");
		break;
	case CSS_TEXT_ALIGN_DEFAULT:
		fprintf(stream, "text-align: default ");
		break;
	case CSS_TEXT_ALIGN_LIBCSS_LEFT:
		fprintf(stream, "text-align: -libcss-left ");
		break;
	case CSS_TEXT_ALIGN_LIBCSS_CENTER:
		fprintf(stream, "text-align: -libcss-center ");
		break;
	case CSS_TEXT_ALIGN_LIBCSS_RIGHT:
		fprintf(stream, "text-align: -libcss-right ");
		break;
	default:
		break;
	}

	/* text-decoration */
	val = css_computed_text_decoration(style);
	if (val == CSS_TEXT_DECORATION_NONE) {
		fprintf(stream, "text-decoration: none ");
	} else {
		fprintf(stream, "text-decoration:");

		if (val & CSS_TEXT_DECORATION_BLINK) {
			fprintf(stream, " blink");
		}
		if (val & CSS_TEXT_DECORATION_LINE_THROUGH) {
			fprintf(stream, " line-through");
		}
		if (val & CSS_TEXT_DECORATION_OVERLINE) {
			fprintf(stream, " overline");
		}
		if (val & CSS_TEXT_DECORATION_UNDERLINE) {
			fprintf(stream, " underline");
		}

		fprintf(stream, " ");
	}

	/* text-indent */
	val = css_computed_text_indent(style, &len1, &unit1);
	switch (val) {
	case CSS_TEXT_INDENT_SET:
		fprintf(stream, "text-indent: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* text-transform */
	val = css_computed_text_transform(style);
	switch (val) {
	case CSS_TEXT_TRANSFORM_CAPITALIZE:
		fprintf(stream, "text-transform: capitalize ");
		break;
	case CSS_TEXT_TRANSFORM_UPPERCASE:
		fprintf(stream, "text-transform: uppercase ");
		break;
	case CSS_TEXT_TRANSFORM_LOWERCASE:
		fprintf(stream, "text-transform: lowercase ");
		break;
	case CSS_TEXT_TRANSFORM_NONE:
		fprintf(stream, "text-transform: none ");
		break;
	default:
		break;
	}

	/* top */
	val = css_computed_top(style, &len1, &unit1);
	switch (val) {
	case CSS_TOP_AUTO:
		fprintf(stream, "top: auto ");
		break;
	case CSS_TOP_SET:
		fprintf(stream, "top: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* unicode-bidi */
	val = css_computed_unicode_bidi(style);
	switch (val) {
	case CSS_UNICODE_BIDI_NORMAL:
		fprintf(stream, "unicode-bidi: normal ");
		break;
	case CSS_UNICODE_BIDI_EMBED:
		fprintf(stream, "unicode-bidi: embed ");
		break;
	case CSS_UNICODE_BIDI_BIDI_OVERRIDE:
		fprintf(stream, "unicode-bidi: bidi-override ");
		break;
	default:
		break;
	}

	/* vertical-align */
	val = css_computed_vertical_align(style, &len1, &unit1);
	switch (val) {
	case CSS_VERTICAL_ALIGN_BASELINE:
		fprintf(stream, "vertical-align: baseline ");
		break;
	case CSS_VERTICAL_ALIGN_SUB:
		fprintf(stream, "vertical-align: sub ");
		break;
	case CSS_VERTICAL_ALIGN_SUPER:
		fprintf(stream, "vertical-align: super ");
		break;
	case CSS_VERTICAL_ALIGN_TOP:
		fprintf(stream, "vertical-align: top ");
		break;
	case CSS_VERTICAL_ALIGN_TEXT_TOP:
		fprintf(stream, "vertical-align: text-top ");
		break;
	case CSS_VERTICAL_ALIGN_MIDDLE:
		fprintf(stream, "vertical-align: middle ");
		break;
	case CSS_VERTICAL_ALIGN_BOTTOM:
		fprintf(stream, "vertical-align: bottom ");
		break;
	case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
		fprintf(stream, "vertical-align: text-bottom ");
		break;
	case CSS_VERTICAL_ALIGN_SET:
		fprintf(stream, "vertical-align: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* visibility */
	val = css_computed_visibility(style);
	switch (val) {
	case CSS_VISIBILITY_VISIBLE:
		fprintf(stream, "visibility: visible ");
		break;
	case CSS_VISIBILITY_HIDDEN:
		fprintf(stream, "visibility: hidden ");
		break;
	case CSS_VISIBILITY_COLLAPSE:
		fprintf(stream, "visibility: collapse ");
		break;
	default:
		break;
	}

	/* white-space */
	val = css_computed_white_space(style);
	switch (val) {
	case CSS_WHITE_SPACE_NORMAL:
		fprintf(stream, "white-space: normal ");
		break;
	case CSS_WHITE_SPACE_PRE:
		fprintf(stream, "white-space: pre ");
		break;
	case CSS_WHITE_SPACE_NOWRAP:
		fprintf(stream, "white-space: nowrap ");
		break;
	case CSS_WHITE_SPACE_PRE_WRAP:
		fprintf(stream, "white-space: pre-wrap ");
		break;
	case CSS_WHITE_SPACE_PRE_LINE:
		fprintf(stream, "white-space: pre-line ");
		break;
	default:
		break;
	}

	/* width */
	val = css_computed_width(style, &len1, &unit1);
	switch (val) {
	case CSS_WIDTH_AUTO:
		fprintf(stream, "width: auto ");
		break;
	case CSS_WIDTH_SET:
		fprintf(stream, "width: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* word-spacing */
	val = css_computed_word_spacing(style, &len1, &unit1);
	switch (val) {
	case CSS_WORD_SPACING_NORMAL:
		fprintf(stream, "word-spacing: normal ");
		break;
	case CSS_WORD_SPACING_SET:
		fprintf(stream, "word-spacing: ");

		dump_css_unit(stream, len1, unit1);

		fprintf(stream, " ");
		break;
	default:
		break;
	}

	/* z-index */
	val = css_computed_z_index(style, &zindex);
	switch (val) {
	case CSS_Z_INDEX_AUTO:
		fprintf(stream, "z-index: auto ");
		break;
	case CSS_Z_INDEX_SET:
		fprintf(stream, "z-index: %d ", zindex);
		break;
	default:
		break;
	}

	fprintf(stream, "}");
}
Beispiel #3
0
void ro_gui_save_drag_end(wimp_dragged *drag)
{
	const char *name;
	wimp_pointer pointer;
	wimp_message message;
	os_error *error;
	char *dp, *ep;
	char *local_name = NULL;
	utf8_convert_ret err;

	if (dragbox_active)
		ro_gui_drag_box_cancel();

	error = xwimp_get_pointer_info(&pointer);
	if (error) {
		LOG(("xwimp_get_pointer_info: 0x%x: %s",
				error->errnum, error->errmess));
		warn_user("WimpError", error->errmess);
		return;
	}

	/* perform hit-test if the destination is the same as the source window;
		we want to allow drag-saving from a page into the input fields within
		the page, but avoid accidental replacements of the current page */
	if (gui_save_sourcew != (wimp_w)-1 && pointer.w == gui_save_sourcew) {
		int dx = (drag->final.x1 + drag->final.x0)/2;
		int dy = (drag->final.y1 + drag->final.y0)/2;
		struct gui_window *g;
		bool dest_ok = false;
		os_coord pos;

		g = ro_gui_window_lookup(gui_save_sourcew);

		if (g && ro_gui_window_to_window_pos(g, dx, dy, &pos)) {
			hlcache_handle *h = g->bw->current_content;

			if (h && content_get_type(h) == CONTENT_HTML) {
				struct box *box = html_get_box_tree(h);
				int box_x, box_y;

				/* Consider the margins of the html page now */
				box_x = box->margin[LEFT];
				box_y = box->margin[TOP];

				while (!dest_ok && (box = box_at_point(box,
						pos.x, pos.y, &box_x, &box_y,
						&h))) {
					if (box->style && 
							css_computed_visibility(
								box->style) == 
							CSS_VISIBILITY_HIDDEN)
						continue;

					if (box->gadget) {
						switch (box->gadget->type) {
							case GADGET_FILE:
							case GADGET_TEXTBOX:
							case GADGET_TEXTAREA:
							case GADGET_PASSWORD:
								dest_ok = true;
								break;

							default:	/* appease compiler */
								break;
						}
					}
				}
			}
		}
		if (!dest_ok) {
			/* cancel the drag operation */
			gui_current_drag_type = GUI_DRAG_NONE;
			return;
		}
	}
Beispiel #4
0
void html_mouse_action(struct content *c, struct browser_window *bw,
                       browser_mouse_state mouse, int x, int y)
{
    html_content *html = (html_content *) c;
    enum { ACTION_NONE, ACTION_SUBMIT, ACTION_GO } action = ACTION_NONE;
    const char *title = 0;
    nsurl *url = 0;
    const char *target = 0;
    char status_buffer[200];
    const char *status = 0;
    browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT;
    bool imagemap = false;
    int box_x = 0, box_y = 0;
    int gadget_box_x = 0, gadget_box_y = 0;
    int html_object_pos_x = 0, html_object_pos_y = 0;
    int text_box_x = 0;
    struct box *url_box = 0;
    struct box *gadget_box = 0;
    struct box *text_box = 0;
    struct box *box;
    struct form_control *gadget = 0;
    hlcache_handle *object = NULL;
    struct box *html_object_box = NULL;
    struct browser_window *iframe = NULL;
    struct box *next_box;
    struct box *drag_candidate = NULL;
    struct scrollbar *scrollbar = NULL;
    plot_font_style_t fstyle;
    int scroll_mouse_x = 0, scroll_mouse_y = 0;
    int padding_left, padding_right, padding_top, padding_bottom;
    browser_drag_type drag_type = browser_window_get_drag_type(bw);
    union content_msg_data msg_data;
    struct dom_node *node = NULL;
    union html_drag_owner drag_owner;
    union html_selection_owner sel_owner;
    bool click = mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2 |
                          BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2 |
                          BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2);

    if (drag_type != DRAGGING_NONE && !mouse &&
            html->visible_select_menu != NULL) {
        /* drag end: select menu */
        form_select_mouse_drag_end(html->visible_select_menu,
                                   mouse, x, y);
    }

    if (html->visible_select_menu != NULL) {
        box = html->visible_select_menu->box;
        box_coords(box, &box_x, &box_y);

        box_x -= box->border[LEFT].width;
        box_y += box->height + box->border[BOTTOM].width +
                 box->padding[BOTTOM] + box->padding[TOP];
        status = form_select_mouse_action(html->visible_select_menu,
                                          mouse, x - box_x, y - box_y);
        if (status != NULL) {
            msg_data.explicit_status_text = status;
            content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
        } else {
            int width, height;
            form_select_get_dimensions(html->visible_select_menu,
                                       &width, &height);
            html->visible_select_menu = NULL;
            browser_window_redraw_rect(bw, box_x, box_y,
                                       width, height);
        }
        return;
    }

    if (html->drag_type == HTML_DRAG_SELECTION) {
        /* Selection drag */
        struct box *box;
        int dir = -1;
        int dx, dy;

        if (!mouse) {
            /* End of selection drag */
            int dir = -1;
            size_t idx;

            if (selection_dragging_start(&html->sel))
                dir = 1;

            idx = html_selection_drag_end(html, mouse, x, y, dir);

            if (idx != 0)
                selection_track(&html->sel, mouse, idx);

            drag_owner.no_owner = true;
            html_set_drag_type(html, HTML_DRAG_NONE,
                               drag_owner, NULL);
            return;
        }

        if (selection_dragging_start(&html->sel))
            dir = 1;

        box = box_pick_text_box(html, x, y, dir, &dx, &dy);

        if (box != NULL) {
            int pixel_offset;
            size_t idx;
            plot_font_style_t fstyle;

            font_plot_style_from_css(box->style, &fstyle);

            nsfont.font_position_in_string(&fstyle,
                                           box->text, box->length,
                                           dx, &idx, &pixel_offset);

            selection_track(&html->sel, mouse,
                            box->byte_offset + idx);
        }
        return;
    }

    if (html->drag_type == HTML_DRAG_SCROLLBAR) {
        struct scrollbar *scr = html->drag_owner.scrollbar;
        struct html_scrollbar_data *data = scrollbar_get_data(scr);

        if (!mouse) {
            /* drag end: scrollbar */
            html_overflow_scroll_drag_end(scr, mouse, x, y);
        }

        box = data->box;
        box_coords(box, &box_x, &box_y);
        if (scrollbar_is_horizontal(scr)) {
            scroll_mouse_x = x - box_x ;
            scroll_mouse_y = y - (box_y + box->padding[TOP] +
                                  box->height + box->padding[BOTTOM] -
                                  SCROLLBAR_WIDTH);
            status = scrollbar_mouse_status_to_message(
                         scrollbar_mouse_action(scr, mouse,
                                                scroll_mouse_x,
                                                scroll_mouse_y));
        } else {
            scroll_mouse_x = x - (box_x + box->padding[LEFT] +
                                  box->width + box->padding[RIGHT] -
                                  SCROLLBAR_WIDTH);
            scroll_mouse_y = y - box_y;
            status = scrollbar_mouse_status_to_message(
                         scrollbar_mouse_action(scr, mouse,
                                                scroll_mouse_x,
                                                scroll_mouse_y));
        }

        msg_data.explicit_status_text = status;
        content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
        return;
    }

    if (html->drag_type == HTML_DRAG_TEXTAREA_SELECTION ||
            html->drag_type == HTML_DRAG_TEXTAREA_SCROLLBAR) {
        box = html->drag_owner.textarea;
        assert(box->gadget != NULL);
        assert(box->gadget->type == GADGET_TEXTAREA ||
               box->gadget->type == GADGET_PASSWORD ||
               box->gadget->type == GADGET_TEXTBOX);

        box_coords(box, &box_x, &box_y);
        textarea_mouse_action(box->gadget->data.text.ta, mouse,
                              x - box_x, y - box_y);

        /* TODO: Set appropriate statusbar message */
        return;
    }

    if (html->drag_type == HTML_DRAG_CONTENT_SELECTION ||
            html->drag_type == HTML_DRAG_CONTENT_SCROLL) {
        box = html->drag_owner.content;
        assert(box->object != NULL);

        box_coords(box, &box_x, &box_y);
        content_mouse_track(box->object, bw, mouse,
                            x - box_x, y - box_y);
        return;
    }

    if (html->drag_type == HTML_DRAG_CONTENT_SELECTION) {
        box = html->drag_owner.content;
        assert(box->object != NULL);

        box_coords(box, &box_x, &box_y);
        content_mouse_track(box->object, bw, mouse,
                            x - box_x, y - box_y);
        return;
    }

    /* Content related drags handled by now */
    assert(html->drag_type == HTML_DRAG_NONE);

    /* search the box tree for a link, imagemap, form control, or
     * box with scrollbars
     */

    box = html->layout;

    /* Consider the margins of the html page now */
    box_x = box->margin[LEFT];
    box_y = box->margin[TOP];

    /* descend through visible boxes setting more specific values for:
     * box - deepest box at point
     * html_object_box - html object
     * html_object_pos_x - html object
     * html_object_pos_y - html object
     * object - non html object
     * iframe - iframe
     * url - href or imagemap
     * target - href or imagemap or gadget
     * url_box - href or imagemap
     * imagemap - imagemap
     * gadget - gadget
     * gadget_box - gadget
     * gadget_box_x - gadget
     * gadget_box_y - gadget
     * title - title
     * pointer
     *
     * drag_candidate - first box with scroll
     * padding_left - box with scroll
     * padding_right
     * padding_top
     * padding_bottom
     * scrollbar - inside padding box stops decent
     * scroll_mouse_x - inside padding box stops decent
     * scroll_mouse_y - inside padding box stops decent
     *
     * text_box - text box
     * text_box_x - text_box
     */
    while ((next_box = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
        box = next_box;

        if ((box->style != NULL) &&
                (css_computed_visibility(box->style) ==
                 CSS_VISIBILITY_HIDDEN)) {
            continue;
        }

        if (box->node != NULL) {
            node = box->node;
        }

        if (box->object) {
            if (content_get_type(box->object) == CONTENT_HTML) {
                html_object_box = box;
                html_object_pos_x = box_x;
                html_object_pos_y = box_y;
            } else {
                object = box->object;
            }
        }

        if (box->iframe) {
            iframe = box->iframe;
        }

        if (box->href) {
            url = box->href;
            target = box->target;
            url_box = box;
        }

        if (box->usemap) {
            url = imagemap_get(html, box->usemap,
                               box_x, box_y, x, y, &target);
            if (url) {
                imagemap = true;
                url_box = box;
            }
        }

        if (box->gadget) {
            gadget = box->gadget;
            gadget_box = box;
            gadget_box_x = box_x;
            gadget_box_y = box_y;
            if (gadget->form)
                target = gadget->form->target;
        }

        if (box->title) {
            title = box->title;
        }

        pointer = get_pointer_shape(box, false);

        if ((box->scroll_x != NULL) ||
                (box->scroll_y != NULL)) {

            if (drag_candidate == NULL) {
                drag_candidate = box;
            }

            padding_left = box_x +
                           scrollbar_get_offset(box->scroll_x);
            padding_right = padding_left + box->padding[LEFT] +
                            box->width + box->padding[RIGHT];
            padding_top = box_y +
                          scrollbar_get_offset(box->scroll_y);
            padding_bottom = padding_top + box->padding[TOP] +
                             box->height + box->padding[BOTTOM];

            if ((x > padding_left) &&
                    (x < padding_right) &&
                    (y > padding_top) &&
                    (y < padding_bottom)) {
                /* mouse inside padding box */

                if ((box->scroll_y != NULL) &&
                        (x > (padding_right -
                              SCROLLBAR_WIDTH))) {
                    /* mouse above vertical box scroll */

                    scrollbar = box->scroll_y;
                    scroll_mouse_x = x - (padding_right -
                                          SCROLLBAR_WIDTH);
                    scroll_mouse_y = y - padding_top;
                    break;

                } else if ((box->scroll_x != NULL) &&
                           (y > (padding_bottom -
                                 SCROLLBAR_WIDTH))) {
                    /* mouse above horizontal box scroll */

                    scrollbar = box->scroll_x;
                    scroll_mouse_x = x - padding_left;
                    scroll_mouse_y = y - (padding_bottom -
                                          SCROLLBAR_WIDTH);
                    break;
                }
            }
        }

        if (box->text && !box->object) {
            text_box = box;
            text_box_x = box_x;
        }
    }

    /* use of box_x, box_y, or content below this point is probably a
     * mistake; they will refer to the last box returned by box_at_point */

    if (scrollbar) {
        status = scrollbar_mouse_status_to_message(
                     scrollbar_mouse_action(scrollbar, mouse,
                                            scroll_mouse_x,
                                            scroll_mouse_y));
        pointer = BROWSER_POINTER_DEFAULT;
    } else if (gadget) {
        textarea_mouse_status ta_status;

        switch (gadget->type) {
        case GADGET_SELECT:
            status = messages_get("FormSelect");
            pointer = BROWSER_POINTER_MENU;
            if (mouse & BROWSER_MOUSE_CLICK_1 &&
                    nsoption_bool(core_select_menu)) {
                html->visible_select_menu = gadget;
                form_open_select_menu(c, gadget,
                                      form_select_menu_callback,
                                      c);
                pointer = BROWSER_POINTER_DEFAULT;
            } else if (mouse & BROWSER_MOUSE_CLICK_1)
                gui_create_form_select_menu(bw, gadget);
            break;
        case GADGET_CHECKBOX:
            status = messages_get("FormCheckbox");
            if (mouse & BROWSER_MOUSE_CLICK_1) {
                gadget->selected = !gadget->selected;
                html__redraw_a_box(html, gadget_box);
            }
            break;
        case GADGET_RADIO:
            status = messages_get("FormRadio");
            if (mouse & BROWSER_MOUSE_CLICK_1)
                form_radio_set(html, gadget);
            break;
        case GADGET_IMAGE:
            if (mouse & BROWSER_MOUSE_CLICK_1) {
                gadget->data.image.mx = x - gadget_box_x;
                gadget->data.image.my = y - gadget_box_y;
            }
        /* drop through */
        case GADGET_SUBMIT:
            if (gadget->form) {
                snprintf(status_buffer, sizeof status_buffer,
                         messages_get("FormSubmit"),
                         gadget->form->action);
                status = status_buffer;
                pointer = get_pointer_shape(gadget_box, false);
                if (mouse & (BROWSER_MOUSE_CLICK_1 |
                             BROWSER_MOUSE_CLICK_2))
                    action = ACTION_SUBMIT;
            } else {
                status = messages_get("FormBadSubmit");
            }
            break;
        case GADGET_TEXTBOX:
        case GADGET_PASSWORD:
        case GADGET_TEXTAREA:
            if (gadget->type == GADGET_TEXTAREA)
                status = messages_get("FormTextarea");
            else
                status = messages_get("FormTextbox");

            if (click && (html->selection_type !=
                          HTML_SELECTION_TEXTAREA ||
                          html->selection_owner.textarea !=
                          gadget_box)) {
                sel_owner.none = true;
                html_set_selection(html, HTML_SELECTION_NONE,
                                   sel_owner, true);
            }

            ta_status = textarea_mouse_action(gadget->data.text.ta,
                                              mouse, x - gadget_box_x,
                                              y - gadget_box_y);

            if (ta_status & TEXTAREA_MOUSE_EDITOR) {
                pointer = get_pointer_shape(gadget_box, false);
            } else {
                pointer = BROWSER_POINTER_DEFAULT;
                status = scrollbar_mouse_status_to_message(
                             ta_status >> 3);
            }
            break;
        case GADGET_HIDDEN:
            /* not possible: no box generated */
            break;
        case GADGET_RESET:
            status = messages_get("FormReset");
            break;
        case GADGET_FILE:
            status = messages_get("FormFile");
            break;
        case GADGET_BUTTON:
            /* This gadget cannot be activated */
            status = messages_get("FormButton");
            break;
        }

    } else if (object && (mouse & BROWSER_MOUSE_MOD_2)) {