Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 98 additions & 33 deletions src/parse/properties/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,34 +487,75 @@ static bool parse_rgb(
*
* \param vector Vector of tokens to process
* \param ctx Pointer to vector iteration context
* \param colour_channels Number of colour channels to expect
* \param result Pointer to location to receive result (AARRGGBB)
* \return true on success, false on error.
*/
static bool parse_hsl(
const parserutils_vector *vector,
int32_t *ctx,
int colour_channels,
uint32_t *result)
{
const css_token *token;
size_t consumed = 0;
css_fixed hue, sat, lit;
int32_t alpha = 255;
bool legacy = false;
css_error error;
uint8_t r = 0, g = 0, b = 0, a = 0xff;

/* hue is a number without a unit representing an
* angle (0-360) degrees
* angle (0-360) degrees, or it can be an angle dimension.
*/
consumeWhitespace(vector, ctx);

token = parserutils_vector_iterate(vector, ctx);
if ((token == NULL) || (token->type != CSS_TOKEN_NUMBER))
if ((token == NULL) ||
(token->type != CSS_TOKEN_NUMBER &&
token->type != CSS_TOKEN_DIMENSION)) {
return false;
}

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

switch (token->type) {
case CSS_TOKEN_NUMBER:
if (consumed != lwc_string_length(token->idata)) {
return false; /* failed to consume the whole string as a number */
}
break;
case CSS_TOKEN_DIMENSION: {
size_t len = lwc_string_length(token->idata);
const char *data = lwc_string_data(token->idata);
uint32_t unit = UNIT_DEG;

error = css__parse_unit_keyword(
data + consumed,
len - consumed,
&unit);
if (error != CSS_OK) {
return false;
}

switch (unit) {
case UNIT_DEG:
break;
case UNIT_RAD:
hue = FDIV(FMUL(hue, F_180), F_PI);
break;
case UNIT_GRAD:
hue = FMUL(hue, FLTTOFIX(0.9));
break;
case UNIT_TURN:
hue = FMUL(hue, F_360);
break;
default:
return false;
}
}
break;
default:
return false; /* unexpected token type */
}

/* Normalise hue to the range [0, 360) */
while (hue < 0)
Expand All @@ -524,21 +565,32 @@ static bool parse_hsl(

consumeWhitespace(vector, ctx);

token = parserutils_vector_iterate(vector, ctx);
if (!tokenIsChar(token, ','))
token = parserutils_vector_peek(vector, *ctx);
if (token == NULL) {
return false;
}

if (tokenIsChar(token, ',')) {
parserutils_vector_iterate(vector, ctx);
consumeWhitespace(vector, ctx);
legacy = true;
}

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

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

if ((token->type != CSS_TOKEN_PERCENTAGE) &&
(token->type != CSS_TOKEN_NUMBER || legacy)) {
return false;
}

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

/* Normalise saturation to the range [0, 100] */
if (sat < INTTOFIX(0))
Expand All @@ -548,21 +600,30 @@ static bool parse_hsl(

consumeWhitespace(vector, ctx);

token = parserutils_vector_iterate(vector, ctx);
if (!tokenIsChar(token, ','))
return false;
if (legacy) {
token = parserutils_vector_iterate(vector, ctx);
if (token == NULL || !tokenIsChar(token, ',')) {
return false;
}

consumeWhitespace(vector, ctx);
}

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

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

if ((token->type != CSS_TOKEN_PERCENTAGE) &&
(token->type != CSS_TOKEN_NUMBER || legacy)) {
return false;
}

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

/* Normalise lightness to the range [0, 100] */
if (lit < INTTOFIX(0))
Expand All @@ -574,28 +635,32 @@ static bool parse_hsl(

token = parserutils_vector_iterate(vector, ctx);

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

if (!tokenIsChar(token, ','))
return false;

if (( legacy && tokenIsChar(token, ',')) ||
(!legacy && tokenIsChar(token, '/'))) {
consumeWhitespace(vector, ctx);

token = parserutils_vector_iterate(vector, ctx);
if ((token == NULL) || (token->type != CSS_TOKEN_NUMBER))
if ((token == NULL) ||
(token->type != CSS_TOKEN_NUMBER &&
token->type != CSS_TOKEN_PERCENTAGE)) {
return false;
}

alpha = css__number_from_lwc_string(token->idata, false, &consumed);
if (consumed != lwc_string_length(token->idata))
return false; /* failed to consume the whole string as a number */
if (consumed != lwc_string_length(token->idata)) {
/* failed to consume the whole string as a number */
return false;
}

alpha = FIXTOINT(FMUL(alpha, F_255));
if (token->type != CSS_TOKEN_NUMBER) {
alpha = FIXTOINT(FMUL(alpha, F_255));
} else {
alpha = FIXTOINT(FDIV(FMUL(alpha, F_255), F_100));
}

consumeWhitespace(vector, ctx);

token = parserutils_vector_iterate(vector, ctx);

}

if (!tokenIsChar(token, ')'))
Expand Down Expand Up @@ -731,7 +796,7 @@ css_error css__parse_colour_specifier(css_language *c,
goto invalid;
}
} else if (colour_channels == 5 || colour_channels == 6) {
if (!parse_hsl(vector, ctx, colour_channels, result)) {
if (!parse_hsl(vector, ctx, result)) {
goto invalid;
}
} else {
Expand Down
Loading