Example #1
0
/**
 * Dump a numeric value to the stream in a textual form.
 *
 * \param stream  Stream to write to
 * \param val     Value to write
 */
void dump_css_number(FILE *stream, css_fixed val)
{
	if (INTTOFIX(FIXTOINT(val)) == val)
		fprintf(stream, "%d", FIXTOINT(val));
	else
		dump_css_fixed(stream, val);
}
Example #2
0
/* exported function documented in render/font_internal.h */
void font_plot_style_from_css(const css_computed_style *css,
		plot_font_style_t *fstyle)
{
	lwc_string **families;
	css_fixed length = 0;
	css_unit unit = CSS_UNIT_PX;
	css_color col;

	fstyle->family = plot_font_generic_family(
			css_computed_font_family(css, &families));

	css_computed_font_size(css, &length, &unit);
	fstyle->size = FIXTOINT(FMUL(nscss_len2pt(length, unit),
				      INTTOFIX(FONT_SIZE_SCALE)));

	/* Clamp font size to configured minimum */
	if (fstyle->size < (nsoption_int(font_min_size) * FONT_SIZE_SCALE) / 10)
		fstyle->size = (nsoption_int(font_min_size) * FONT_SIZE_SCALE) / 10;

	fstyle->weight = plot_font_weight(css_computed_font_weight(css));
	fstyle->flags = plot_font_flags(css_computed_font_style(css),
			css_computed_font_variant(css));

	css_computed_color(css, &col);
	fstyle->foreground = nscss_color_to_ns(col);
	fstyle->background = 0;
}
Example #3
0
/**
 * Dump a fixed point value to the stream in a textual form.
 *
 * \param stream  Stream to write to
 * \param f       Value to write
 */
void dump_css_fixed(FILE *stream, css_fixed f)
{
#define NSCSS_ABS(x) (uint32_t)((x) < 0 ? -(x) : (x))
	uint32_t uintpart = FIXTOINT(NSCSS_ABS(f));
	/* + 500 to ensure round to nearest (division will truncate) */
	uint32_t fracpart = ((NSCSS_ABS(f) & 0x3ff) * 1000 + 500) / (1 << 10);
#undef NSCSS_ABS

	fprintf(stream, "%s%d.%03d", f < 0 ? "-" : "", uintpart, fracpart);
}
static void fb_fill_scalar(const plot_font_style_t *fstyle, FTC_Scaler srec)
{
        int selected_face = FB_FACE_DEFAULT;

	switch (fstyle->family) {
                                
	case PLOT_FONT_FAMILY_SERIF:
		if (fstyle->weight >= BOLD_WEIGHT) {
                        selected_face = FB_FACE_SERIF_BOLD;
		} else {
                        selected_face = FB_FACE_SERIF;
                }
		break;

	case PLOT_FONT_FAMILY_MONOSPACE:
		if (fstyle->weight >= BOLD_WEIGHT) {
			selected_face = FB_FACE_MONOSPACE_BOLD;
		} else {
			selected_face = FB_FACE_MONOSPACE;
                }
		break;

	case PLOT_FONT_FAMILY_CURSIVE:
                selected_face = FB_FACE_CURSIVE;
		break;

	case PLOT_FONT_FAMILY_FANTASY:
                selected_face = FB_FACE_FANTASY;
		break;

	case PLOT_FONT_FAMILY_SANS_SERIF:
	default:
		if ((fstyle->flags & FONTF_ITALIC) || 
		    (fstyle->flags & FONTF_OBLIQUE)) {
			if (fstyle->weight >= BOLD_WEIGHT) {
                                selected_face = FB_FACE_SANS_SERIF_ITALIC_BOLD;
			} else {
                                selected_face = FB_FACE_SANS_SERIF_ITALIC;
			}
		} else {
			if (fstyle->weight >= BOLD_WEIGHT) {
                                selected_face = FB_FACE_SANS_SERIF_BOLD;
                        } else {
                                selected_face = FB_FACE_SANS_SERIF;
			}
                }
	}

        srec->face_id = (FTC_FaceID)fb_faces[selected_face];

	srec->width = srec->height = (fstyle->size * 64) / FONT_SIZE_SCALE;
	srec->pixel = 0;

	srec->x_res = srec->y_res = FIXTOINT(nscss_screen_dpi);
}
Example #5
0
/**
 * Parse a colour specifier
 *
 * \param c       Parsing context
 * \param vector  Vector of tokens to process
 * \param ctx     Pointer to vector iteration context
 * \param value   Pointer to location to receive value
 * \param result  Pointer to location to receive result (AARRGGBB)
 * \return CSS_OK      on success,
 *         CSS_INVALID if the input is invalid
 *
 * Post condition: \a *ctx is updated with the next token to process
 *                 If the input is invalid, then \a *ctx remains unchanged.
 */
css_error css__parse_colour_specifier(css_language *c,
		const parserutils_vector *vector, int *ctx,
		uint16_t *value, uint32_t *result)
{
	int orig_ctx = *ctx;
	const css_token *token;
	bool match;
	css_error error;

	consumeWhitespace(vector, ctx);

	/* IDENT(<colour name>) | 
	 * HASH(rgb | rrggbb) |
	 * FUNCTION(rgb) [ [ NUMBER | PERCENTAGE ] ',' ] {3} ')'
	 * FUNCTION(rgba) [ [ NUMBER | PERCENTAGE ] ',' ] {4} ')'
	 * FUNCTION(hsl) ANGLE ',' PERCENTAGE ',' PERCENTAGE  ')'
	 * FUNCTION(hsla) ANGLE ',' PERCENTAGE ',' PERCENTAGE ',' NUMBER ')'
	 *
	 * For quirks, NUMBER | DIMENSION | IDENT, too
	 * I.E. "123456" -> NUMBER, "1234f0" -> DIMENSION, "f00000" -> IDENT
	 */
	token = parserutils_vector_iterate(vector, ctx);
	if (token == NULL || (token->type != CSS_TOKEN_IDENT &&
			token->type != CSS_TOKEN_HASH &&
			token->type != CSS_TOKEN_FUNCTION)) {
		if (c->sheet->quirks_allowed == false ||
				token == NULL ||
				(token->type != CSS_TOKEN_NUMBER &&
				token->type != CSS_TOKEN_DIMENSION))
			goto invalid;
	}

	if (token->type == CSS_TOKEN_IDENT) {
		if ((lwc_string_caseless_isequal(
				token->idata, c->strings[TRANSPARENT],
				&match) == lwc_error_ok && match)) {
			*value = COLOR_TRANSPARENT;
			*result = 0; /* black transparent */
			return CSS_OK;
		} else if ((lwc_string_caseless_isequal(
				token->idata, c->strings[CURRENTCOLOR],
				&match) == lwc_error_ok && match)) {
			*value = COLOR_CURRENT_COLOR;
			*result = 0;
			return CSS_OK;
		}

		error = css__parse_named_colour(c, token->idata, result);
		if (error != CSS_OK && c->sheet->quirks_allowed) {
			error = css__parse_hash_colour(token->idata, result);
			if (error == CSS_OK)
				c->sheet->quirks_used = true;
		}

		if (error != CSS_OK)
			goto invalid;
	} else if (token->type == CSS_TOKEN_HASH) {
		error = css__parse_hash_colour(token->idata, result);
		if (error != CSS_OK)
			goto invalid;
	} else if (c->sheet->quirks_allowed &&
			token->type == CSS_TOKEN_NUMBER) {
		error = css__parse_hash_colour(token->idata, result);
		if (error == CSS_OK)
			c->sheet->quirks_used = true;
		else
			goto invalid;
	} else if (c->sheet->quirks_allowed &&
			token->type == CSS_TOKEN_DIMENSION) {
		error = css__parse_hash_colour(token->idata, result);
		if (error == CSS_OK)
			c->sheet->quirks_used = true;
		else
			goto invalid;
	} else if (token->type == CSS_TOKEN_FUNCTION) {
		uint8_t r = 0, g = 0, b = 0, a = 0xff;
		int colour_channels = 0;

		if ((lwc_string_caseless_isequal(
				token->idata, c->strings[RGB],
				&match) == lwc_error_ok && match)) {
			colour_channels = 3;
		} else if ((lwc_string_caseless_isequal(
				token->idata, c->strings[RGBA],
				&match) == lwc_error_ok && match)) {
			colour_channels = 4;
		} if ((lwc_string_caseless_isequal(
				token->idata, c->strings[HSL],
				&match) == lwc_error_ok && match)) {
			colour_channels = 5;
		} else if ((lwc_string_caseless_isequal(
				token->idata, c->strings[HSLA],
				&match) == lwc_error_ok && match)) {
			colour_channels = 6;
		}

		if (colour_channels == 3 || colour_channels == 4) {
			int i;
			css_token_type valid = CSS_TOKEN_NUMBER;
			uint8_t *components[4] = { &r, &g, &b, &a };

			for (i = 0; i < colour_channels; i++) {
				uint8_t *component;
				css_fixed num;
				size_t consumed = 0;
				int32_t intval;
				bool int_only;

				component = components[i];

				consumeWhitespace(vector, ctx);

				token = parserutils_vector_peek(vector, *ctx);
				if (token == NULL || (token->type !=
						CSS_TOKEN_NUMBER &&
						token->type !=
						CSS_TOKEN_PERCENTAGE))
					goto invalid;

				if (i == 0)
					valid = token->type;
				else if (i < 3 && token->type != valid)
					goto invalid;

				/* The alpha channel may be a float */
				if (i < 3)
					int_only = (valid == CSS_TOKEN_NUMBER);
				else
					int_only = false;

				num = css__number_from_lwc_string(token->idata,
						int_only, &consumed);
				if (consumed != lwc_string_length(token->idata))
					goto invalid;

				if (valid == CSS_TOKEN_NUMBER) {
					if (i == 3) {
						/* alpha channel */
						intval = FIXTOINT(
							FMUL(num, F_255));
					} else {
						/* colour channels */
						intval = FIXTOINT(num);
					}
				} else {
					intval = FIXTOINT(
						FDIV(FMUL(num, F_255), F_100));
				}

				if (intval > 255)
					*component = 255;
				else if (intval < 0)
					*component = 0;
				else
					*component = intval;

				parserutils_vector_iterate(vector, ctx);

				consumeWhitespace(vector, ctx);

				token = parserutils_vector_peek(vector, *ctx);
				if (token == NULL)
					goto invalid;

				if (i != (colour_channels - 1) &&
						tokenIsChar(token, ',')) {
					parserutils_vector_iterate(vector, ctx);
				} else if (i == (colour_channels - 1) &&
						tokenIsChar(token, ')')) {
					parserutils_vector_iterate(vector, ctx);
				} else {
					goto invalid;
				}
			}
		} else if (colour_channels == 5 || colour_channels == 6) {
			/* hue - saturation - lightness */
			size_t consumed = 0;
			css_fixed hue, sat, lit;
			int32_t alpha = 255;

			/* hue is a number without a unit representing an 
			 * angle (0-360) degrees  
			 */
			consumeWhitespace(vector, ctx);

			token = parserutils_vector_iterate(vector, ctx);
			if ((token == NULL) || (token->type != CSS_TOKEN_NUMBER))
				goto invalid;

			hue = css__number_from_lwc_string(token->idata, false, &consumed);
			if (consumed != lwc_string_length(token->idata))
				goto invalid; /* failed to consume the whole string as a number */

			/* Normalise hue to the range [0, 360) */
			while (hue < 0)
				hue += F_360;
			while (hue >= F_360)
				hue -= F_360;

			consumeWhitespace(vector, ctx);

			token = parserutils_vector_iterate(vector, ctx);
			if (!tokenIsChar(token, ','))
				goto invalid;


			/* saturation */
			consumeWhitespace(vector, ctx);

			token = parserutils_vector_iterate(vector, ctx);
			if ((token == NULL) || (token->type != CSS_TOKEN_PERCENTAGE))
				goto invalid;

			sat = css__number_from_lwc_string(token->idata, false, &consumed);
			if (consumed != lwc_string_length(token->idata))
				goto invalid; /* failed to consume the whole string as a number */

			/* Normalise saturation to the range [0, 100] */
			if (sat < INTTOFIX(0))
				sat = INTTOFIX(0);
			else if (sat > INTTOFIX(100))
				sat = INTTOFIX(100);

			consumeWhitespace(vector, ctx);

			token = parserutils_vector_iterate(vector, ctx);
			if (!tokenIsChar(token, ','))
				goto invalid;


			/* lightness */
			consumeWhitespace(vector, ctx);

			token = parserutils_vector_iterate(vector, ctx);
			if ((token == NULL) || (token->type != CSS_TOKEN_PERCENTAGE))
				goto invalid;

			lit = css__number_from_lwc_string(token->idata, false, &consumed);
			if (consumed != lwc_string_length(token->idata))
				goto invalid; /* failed to consume the whole string as a number */

			/* Normalise lightness to the range [0, 100] */
			if (lit < INTTOFIX(0))
				lit = INTTOFIX(0);
			else if (lit > INTTOFIX(100))
				lit = INTTOFIX(100);

			consumeWhitespace(vector, ctx);

			token = parserutils_vector_iterate(vector, ctx);

			if (colour_channels == 6) {
				/* alpha */

				if (!tokenIsChar(token, ','))
					goto invalid;
			
				consumeWhitespace(vector, ctx);

				token = parserutils_vector_iterate(vector, ctx);
				if ((token == NULL) || (token->type != CSS_TOKEN_NUMBER))
					goto invalid;

				alpha = css__number_from_lwc_string(token->idata, false, &consumed);
				if (consumed != lwc_string_length(token->idata))
					goto invalid; /* failed to consume the whole string as a number */
				
				alpha = FIXTOINT(FMUL(alpha, F_255));

				consumeWhitespace(vector, ctx);

				token = parserutils_vector_iterate(vector, ctx);

			}

			if (!tokenIsChar(token, ')'))
				goto invalid;

			/* have a valid HSV entry, convert to RGB */
			HSL_to_RGB(hue, sat, lit, &r, &g, &b);

			/* apply alpha */
			if (alpha > 255)
				a = 255;
			else if (alpha < 0)
				a = 0;
			else
				a = alpha;

		} else {
			goto invalid;
		}

		*result = (a << 24) | (r << 16) | (g << 8) | b;
	}

	*value = COLOR_SET;

	return CSS_OK;

invalid:
	*ctx = orig_ctx;
	return CSS_INVALID;
}
Example #6
0
/**
 * Convert Hue Saturation Lightness value to RGB.
 *
 * \param hue Hue in degrees 0..360
 * \param sat Saturation value in percent 0..100
 * \param lit Lightness value in percent 0..100
 * \param r red component
 * \param g green component
 * \param b blue component
 */
static void HSL_to_RGB(css_fixed hue, css_fixed sat, css_fixed lit, uint8_t *r, uint8_t *g, uint8_t *b)
{
	css_fixed min_rgb, max_rgb, chroma;
	css_fixed relative_hue, scaled_hue, mid1, mid2;
	int sextant;

#define ORGB(R, G, B) \
	*r = FIXTOINT(FDIV(FMUL((R), F_255), F_100)); \
	*g = FIXTOINT(FDIV(FMUL((G), F_255), F_100)); \
	*b = FIXTOINT(FDIV(FMUL((B), F_255), F_100))

	/* If saturation is zero there is no hue and r = g = b = lit */
	if (sat == INTTOFIX(0)) {
		ORGB(lit, lit, lit);
		return;
	}

	/* Compute max(r,g,b) */
	if (lit <= INTTOFIX(50)) {
		max_rgb = FDIV(FMUL(lit, FADD(sat, F_100)), F_100);
	} else {
		max_rgb = FDIV(FSUB(FMUL(FADD(lit, sat), F_100), FMUL(lit, sat)), F_100);
	}

	/* Compute min(r,g,b) */
	min_rgb = FSUB(FMUL(lit, INTTOFIX(2)), max_rgb);

	/* We know that the value of at least one of the components is 
	 * max(r,g,b) and that the value of at least one of the other
	 * components is min(r,g,b).
	 *
	 * We can determine which components have these values by
	 * considering which the sextant of the hexcone the hue lies
	 * in:
	 *
	 * Sextant:	max(r,g,b):	min(r,g,b):
	 *
	 * 0		r		b
	 * 1		g		b
	 * 2		g		r
	 * 3		b		r
	 * 4		b		g
	 * 5		r		g
	 *
	 * Thus, we need only compute the value of the third component
	 */

	/* Chroma is the difference between min and max */
	chroma = FSUB(max_rgb, min_rgb);

	/* Compute which sextant the hue lies in (truncates result) */
	hue = FDIV(FMUL(hue, INTTOFIX(6)), F_360);
	sextant = FIXTOINT(hue);

	/* Compute offset of hue from start of sextant */
	relative_hue = FSUB(hue, INTTOFIX(sextant));

	/* Scale offset by chroma */
        scaled_hue = FMUL(relative_hue, chroma);

	/* Compute potential values of the third colour component */
        mid1 = FADD(min_rgb, scaled_hue);
        mid2 = FSUB(max_rgb, scaled_hue);

	/* Populate result */
        switch (sextant) {
	case 0: ORGB(max_rgb,   mid1,      min_rgb); break;
	case 1: ORGB(mid2,      max_rgb,   min_rgb); break;
	case 2: ORGB(min_rgb,   max_rgb,   mid1); break;
	case 3: ORGB(min_rgb,   mid2,      max_rgb); break;
	case 4: ORGB(mid1,      min_rgb,   max_rgb); break;
	case 5: ORGB(max_rgb,   min_rgb,   mid2); break;
        }

#undef ORGB
}
Example #7
0
static nserror
html_object_callback(hlcache_handle *object,
		     const hlcache_event *event,
		     void *pw)
{
	struct content_html_object *o = pw;
	html_content *c = (html_content *) o->parent;
	int x, y;
	struct box *box;

	assert(c->base.status != CONTENT_STATUS_ERROR);

	box = o->box;
	if (box == NULL && event->type != CONTENT_MSG_ERROR) {
		return NSERROR_OK;
	}

	switch (event->type) {
	case CONTENT_MSG_LOADING:
		if (c->base.status != CONTENT_STATUS_LOADING && c->bw != NULL)
			content_open(object,
					c->bw, &c->base,
					box->object_params);
		break;

	case CONTENT_MSG_READY:
		if (content_can_reformat(object)) {
			/* TODO: avoid knowledge of box internals here */
			content_reformat(object, false,
					box->max_width != UNKNOWN_MAX_WIDTH ?
							box->width : 0,
					box->max_width != UNKNOWN_MAX_WIDTH ?
							box->height : 0);

			/* Adjust parent content for new object size */
			html_object_done(box, object, o->background);
			if (c->base.status == CONTENT_STATUS_READY ||
					c->base.status == CONTENT_STATUS_DONE)
				content__reformat(&c->base, false,
						c->base.available_width,
						c->base.height);
		}
		break;

	case CONTENT_MSG_DONE:
		c->base.active--;
		LOG("%d fetches active", c->base.active);

		html_object_done(box, object, o->background);

		if (c->base.status != CONTENT_STATUS_LOADING &&
				box->flags & REPLACE_DIM) {
			union content_msg_data data;

			if (!box_visible(box))
				break;

			box_coords(box, &x, &y);

			data.redraw.x = x + box->padding[LEFT];
			data.redraw.y = y + box->padding[TOP];
			data.redraw.width = box->width;
			data.redraw.height = box->height;
			data.redraw.full_redraw = true;

			content_broadcast(&c->base, CONTENT_MSG_REDRAW, data);
		}
		break;

	case CONTENT_MSG_ERROR:
		hlcache_handle_release(object);

		o->content = NULL;

		if (box != NULL) {
			c->base.active--;
			LOG("%d fetches active", c->base.active);

			content_add_error(&c->base, "?", 0);
			html_object_failed(box, c, o->background);
		}
		break;

	case CONTENT_MSG_REDRAW:
		if (c->base.status != CONTENT_STATUS_LOADING) {
			union content_msg_data data = event->data;

			if (!box_visible(box))
				break;

			box_coords(box, &x, &y);

			if (object == box->background) {
				/* Redraw request is for background */
				css_fixed hpos = 0, vpos = 0;
				css_unit hunit = CSS_UNIT_PX;
				css_unit vunit = CSS_UNIT_PX;
				int width = box->padding[LEFT] + box->width +
						box->padding[RIGHT];
				int height = box->padding[TOP] + box->height +
						box->padding[BOTTOM];
				int t, h, l, w;

				/* Need to know background-position */
				css_computed_background_position(box->style,
						&hpos, &hunit, &vpos, &vunit);

				w = content_get_width(box->background);
				if (hunit == CSS_UNIT_PCT) {
					l = (width - w) * hpos / INTTOFIX(100);
				} else {
					l = FIXTOINT(nscss_len2px(hpos, hunit,
							box->style));
				}

				h = content_get_height(box->background);
				if (vunit == CSS_UNIT_PCT) {
					t = (height - h) * vpos / INTTOFIX(100);
				} else {
					t = FIXTOINT(nscss_len2px(vpos, vunit,
							box->style));
				}

				/* Redraw area depends on background-repeat */
				switch (css_computed_background_repeat(
						box->style)) {
				case CSS_BACKGROUND_REPEAT_REPEAT:
					data.redraw.x = 0;
					data.redraw.y = 0;
					data.redraw.width = box->width;
					data.redraw.height = box->height;
					break;

				case CSS_BACKGROUND_REPEAT_REPEAT_X:
					data.redraw.x = 0;
					data.redraw.y += t;
					data.redraw.width = box->width;
					break;

				case CSS_BACKGROUND_REPEAT_REPEAT_Y:
					data.redraw.x += l;
					data.redraw.y = 0;
					data.redraw.height = box->height;
					break;

				case CSS_BACKGROUND_REPEAT_NO_REPEAT:
					data.redraw.x += l;
					data.redraw.y += t;
					break;

				default:
					break;
				}

				data.redraw.object_width = box->width;
				data.redraw.object_height = box->height;

				/* Add offset to box */
				data.redraw.x += x;
				data.redraw.y += y;
				data.redraw.object_x += x;
				data.redraw.object_y += y;

				content_broadcast(&c->base,
						CONTENT_MSG_REDRAW, data);
				break;

			} else {
				/* Non-background case */
				if (hlcache_handle_get_content(object) ==
						event->data.redraw.object) {

					int w = content_get_width(object);
					int h = content_get_height(object);

					if (w != 0) {
						data.redraw.x =
							data.redraw.x *
							box->width / w;
						data.redraw.width =
							data.redraw.width *
							box->width / w;
					}

					if (h != 0) {
						data.redraw.y =
							data.redraw.y *
							box->height / h;
						data.redraw.height =
							data.redraw.height *
							box->height / h;
					}

					data.redraw.object_width = box->width;
					data.redraw.object_height = box->height;
				}

				data.redraw.x += x + box->padding[LEFT];
				data.redraw.y += y + box->padding[TOP];
				data.redraw.object_x += x + box->padding[LEFT];
				data.redraw.object_y += y + box->padding[TOP];
			}

			content_broadcast(&c->base, CONTENT_MSG_REDRAW, data);
		}
		break;

	case CONTENT_MSG_REFRESH:
		if (content_get_type(object) == CONTENT_HTML) {
			/* only for HTML objects */
			guit->misc->schedule(event->data.delay * 1000,
					html_object_refresh, o);
		}

		break;

	case CONTENT_MSG_LINK:
		/* Don't care about favicons that aren't on top level content */
		break;

	case CONTENT_MSG_GETCTX:
		*(event->data.jscontext) = NULL;
		break;

	case CONTENT_MSG_SCROLL:
		if (box->scroll_x != NULL)
			scrollbar_set(box->scroll_x, event->data.scroll.x0,
					false);
		if (box->scroll_y != NULL)
			scrollbar_set(box->scroll_y, event->data.scroll.y0,
					false);
		break;

	case CONTENT_MSG_DRAGSAVE:
	{
		union content_msg_data msg_data;
		if (event->data.dragsave.content == NULL)
			msg_data.dragsave.content = object;
		else
			msg_data.dragsave.content =
					event->data.dragsave.content;

		content_broadcast(&c->base, CONTENT_MSG_DRAGSAVE, msg_data);
	}
		break;

	case CONTENT_MSG_SAVELINK:
	case CONTENT_MSG_POINTER:
	case CONTENT_MSG_SELECTMENU:
	case CONTENT_MSG_GADGETCLICK:
		/* These messages are for browser window layer.
		 * we're not interested, so pass them on. */
		content_broadcast(&c->base, event->type, event->data);
		break;

	case CONTENT_MSG_CARET:
	{
		union html_focus_owner focus_owner;
		focus_owner.content = box;

		switch (event->data.caret.type) {
		case CONTENT_CARET_REMOVE:
		case CONTENT_CARET_HIDE:
			html_set_focus(c, HTML_FOCUS_CONTENT, focus_owner,
					true, 0, 0, 0, NULL);
			break;
		case CONTENT_CARET_SET_POS:
			html_set_focus(c, HTML_FOCUS_CONTENT, focus_owner,
					false, event->data.caret.pos.x,
					event->data.caret.pos.y,
					event->data.caret.pos.height,
					event->data.caret.pos.clip);
			break;
		}
	}
		break;

	case CONTENT_MSG_DRAG:
	{
		html_drag_type drag_type = HTML_DRAG_NONE;
		union html_drag_owner drag_owner;
		drag_owner.content = box;

		switch (event->data.drag.type) {
		case CONTENT_DRAG_NONE:
			drag_type = HTML_DRAG_NONE;
			drag_owner.no_owner = true;
			break;
		case CONTENT_DRAG_SCROLL:
			drag_type = HTML_DRAG_CONTENT_SCROLL;
			break;
		case CONTENT_DRAG_SELECTION:
			drag_type = HTML_DRAG_CONTENT_SELECTION;
			break;
		}
		html_set_drag_type(c, drag_type, drag_owner,
				event->data.drag.rect);
	}
		break;

	case CONTENT_MSG_SELECTION:
	{
		html_selection_type sel_type;
		union html_selection_owner sel_owner;

		if (event->data.selection.selection) {
			sel_type = HTML_SELECTION_CONTENT;
			sel_owner.content = box;
		} else {
			sel_type = HTML_SELECTION_NONE;
			sel_owner.none = true;
		}
		html_set_selection(c, sel_type, sel_owner,
				event->data.selection.read_only);
	}
		break;

	default:
		break;
	}

	if (c->base.status == CONTENT_STATUS_READY && c->base.active == 0 &&
			(event->type == CONTENT_MSG_LOADING ||
			event->type == CONTENT_MSG_DONE ||
			event->type == CONTENT_MSG_ERROR)) {
		/* all objects have arrived */
		content__reformat(&c->base, false, c->base.available_width,
				c->base.height);
		content_set_done(&c->base);
	}

	/* If  1) the configuration option to reflow pages while objects are
	 *        fetched is set
	 *     2) an object is newly fetched & converted,
	 *     3) the box's dimensions need to change due to being replaced
	 *     4) the object's parent HTML is ready for reformat,
	 *     5) the time since the previous reformat is more than the
	 *        configured minimum time between reformats
	 * then reformat the page to display newly fetched objects */
	else if (nsoption_bool(incremental_reflow) &&
			event->type == CONTENT_MSG_DONE &&
			box != NULL && !(box->flags & REPLACE_DIM) &&
			(c->base.status == CONTENT_STATUS_READY ||
			 c->base.status == CONTENT_STATUS_DONE) &&
			(wallclock() > c->base.reformat_time)) {
		content__reformat(&c->base, false, c->base.available_width,
				c->base.height);
	}

	return NSERROR_OK;
}