1255 lines · 34.2 KB · C
RawDownload
/* * This file is part of LibCSS. * Licensed under the MIT License, *		  http://www.opensource.org/licenses/mit-license.php * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org> */ #include <assert.h>#include <string.h> #include "stylesheet.h"#include "bytecode/bytecode.h"#include "bytecode/opcodes.h"#include "parse/properties/properties.h"#include "parse/properties/utils.h"#include "utils/parserutilserror.h"  /** * Parse list-style-type value * * \param c	 Parsing context * \param ident	 Identifier to consider * \param value	 Pointer to location to receive value * \return CSS_OK on success, *	   CSS_INVALID if the input is not valid */css_error css__parse_list_style_type_value(css_language *c, const css_token *ident,		uint16_t *value){	bool match; 	/* IDENT (disc, circle, square, decimal, decimal-leading-zero,	 *	  lower-roman, upper-roman, lower-greek, lower-latin,	 *	  upper-latin, armenian, georgian, lower-alpha, upper-alpha,	 *	  none)	 */	if ((lwc_string_caseless_isequal(			ident->idata, c->strings[DISC],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_DISC;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[CIRCLE],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_CIRCLE;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[SQUARE],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_SQUARE;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[DECIMAL],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_DECIMAL;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[DECIMAL_LEADING_ZERO],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_DECIMAL_LEADING_ZERO;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[LOWER_ROMAN],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_LOWER_ROMAN;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[UPPER_ROMAN],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_UPPER_ROMAN;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[LOWER_GREEK],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_LOWER_GREEK;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[LOWER_LATIN],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_LOWER_LATIN;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[UPPER_LATIN],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_UPPER_LATIN;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[ARMENIAN],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_ARMENIAN;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[GEORGIAN],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_GEORGIAN;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[LOWER_ALPHA],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_LOWER_ALPHA;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[UPPER_ALPHA],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_UPPER_ALPHA;	} else if ((lwc_string_caseless_isequal(			ident->idata, c->strings[NONE],			&match) == lwc_error_ok && match)) {		*value = LIST_STYLE_TYPE_NONE;	} else		return CSS_INVALID; 	return CSS_OK;}   /** * Parse border-{top,right,bottom,left} shorthand * * \param c	  Parsing context * \param vector  Vector of tokens to process * \param ctx	  Pointer to vector iteration context * \param side	  The side we're parsing for * \param result  Pointer to location to receive resulting style * \return CSS_OK on success, *	   CSS_NOMEM on memory exhaustion, *	   CSS_INVALID if the input is not valid * * 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_border_side(css_language *c,		const parserutils_vector *vector, int *ctx,		css_style *result, enum border_side_e side){	int orig_ctx = *ctx;	int prev_ctx;	const css_token *token;	css_error error = CSS_OK;	bool color = true;	bool style = true;	bool width = true;	css_style *color_style;	css_style *style_style;	css_style *width_style; 	/* Firstly, handle inherit */	token = parserutils_vector_peek(vector, *ctx);	if (token == NULL) 		return CSS_INVALID;			if (is_css_inherit(c, token)) {		error = css_stylesheet_style_inherit(result, CSS_PROP_BORDER_TOP_COLOR + side);		if (error != CSS_OK) 			return error; 		error = css_stylesheet_style_inherit(result, CSS_PROP_BORDER_TOP_STYLE + side);		if (error != CSS_OK) 			return error;		 		error = css_stylesheet_style_inherit(result, CSS_PROP_BORDER_TOP_WIDTH + side);		if (error == CSS_OK) 			parserutils_vector_iterate(vector, ctx); 		return error;	}  	/* allocate styles */	error = css__stylesheet_style_create(c->sheet, &color_style);	if (error != CSS_OK) 		return error; 	error = css__stylesheet_style_create(c->sheet, &style_style);	if (error != CSS_OK) {		css__stylesheet_style_destroy(color_style);		return error;	} 	error = css__stylesheet_style_create(c->sheet, &width_style);	if (error != CSS_OK) {		css__stylesheet_style_destroy(color_style);		css__stylesheet_style_destroy(width_style);		return error;	} 	/* Attempt to parse the various longhand properties */	do {		prev_ctx = *ctx;		error = CSS_OK; 		/* Ensure that we're not about to parse another inherit */		token = parserutils_vector_peek(vector, *ctx);		if (token != NULL && is_css_inherit(c, token)) {			error = CSS_INVALID;			goto css__parse_border_side_cleanup;		} 		/* Try each property parser in turn, but only if we		 * haven't already got a value for this property.		 */		if ((color) && 		    (error = css__parse_border_side_color(c, vector, ctx, 			     color_style, CSS_PROP_BORDER_TOP_COLOR + side)) == CSS_OK) {			color = false;		} else if ((style) && 			   (error = css__parse_border_side_style(c, vector, ctx,				    style_style, CSS_PROP_BORDER_TOP_STYLE + side)) == CSS_OK) {			style = false;		} else if ((width) && 			   (error = css__parse_border_side_width(c, vector, ctx,				    width_style, CSS_PROP_BORDER_TOP_WIDTH + side)) == CSS_OK) {			width = false;		}  		if (error == CSS_OK) {			consumeWhitespace(vector, ctx); 			token = parserutils_vector_peek(vector, *ctx);		} else {			/* Forcibly cause loop to exit */			token = NULL;		}	} while (*ctx != prev_ctx && token != NULL); 	if (style) {		error = css__stylesheet_style_appendOPV(style_style, 				CSS_PROP_BORDER_TOP_STYLE + side, 0, 				BORDER_STYLE_NONE);		if (error != CSS_OK)			goto css__parse_border_side_cleanup;	} 	if (width) {		error = css__stylesheet_style_appendOPV(width_style, 				CSS_PROP_BORDER_TOP_WIDTH + side,				0, BORDER_WIDTH_MEDIUM);		if (error != CSS_OK)			goto css__parse_border_side_cleanup;	} 	error = css__stylesheet_merge_style(result, color_style);	if (error != CSS_OK)		goto css__parse_border_side_cleanup; 	error = css__stylesheet_merge_style(result, style_style);	if (error != CSS_OK)		goto css__parse_border_side_cleanup; 	error = css__stylesheet_merge_style(result, width_style); css__parse_border_side_cleanup:	css__stylesheet_style_destroy(color_style);	css__stylesheet_style_destroy(style_style);	css__stylesheet_style_destroy(width_style); 	if (error != CSS_OK)		*ctx = orig_ctx; 	return error;}  /** * 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} /** * 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));				}

Lines 1–500 of 1255.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t