/* * 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. Load more
/* * 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)); }