summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/parse/properties/utils.c178
-rw-r--r--src/parse/propstrings.c2
-rw-r--r--src/parse/propstrings.h2
-rw-r--r--test/data/parse/INDEX1
-rw-r--r--test/data/parse/properties.dat10
5 files changed, 190 insertions, 3 deletions
diff --git a/src/parse/properties/utils.c b/src/parse/properties/utils.c
index 22fdd31..fa79d04 100644
--- a/src/parse/properties/utils.c
+++ b/src/parse/properties/utils.c
@@ -248,6 +248,65 @@ css__parse_border_side_cleanup:
return error;
}
+
+/* CSS standard definition
+
+ HOW TO RETURN hsl.to.rgb(h, s, l):
+ SELECT:
+ l<=0.5: PUT l*(s+1) IN m2
+ ELSE: PUT l+s-l*s IN m2
+ PUT l*2-m2 IN m1
+ PUT hue.to.rgb(m1, m2, h+1/3) IN r
+ PUT hue.to.rgb(m1, m2, h ) IN g
+ PUT hue.to.rgb(m1, m2, h-1/3) IN b
+ RETURN (r, g, b)
+
+ HOW TO RETURN hue.to.rgb(m1, m2, h):
+ IF h<0: PUT h+1 IN h
+ IF h>1: PUT h-1 IN h
+ IF h*6<1: RETURN m1+(m2-m1)*h*6
+ IF h*2<1: RETURN m2
+ IF h*3<2: RETURN m1+(m2-m1)*(2/3-h)*6
+ RETURN m1
+*/
+static inline int hue_to_RGB(float m1, float m2, float h)
+{
+ h = (h < 0) ? h + 1.0 : h;
+ h = (h > 1.0) ? h - 1.0 : h;
+
+ if (h * 6.0 < 1.0) return (m1 + (m2 - m1) * h * 6.0) * 255.5;
+ if (h * 2.0 < 1.0) return (m2 * 255.5);
+ if (h * 3.0 < 2.0) return (m1 + (m2 - m1) * ((2.0/3.0) - h) * 6.0) * 255.5;
+ return m1 * 255.5;
+}
+
+/**
+ * Convert Hue Sauration Lightness value to RGB float version from CSS standard
+ *
+ * \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(int32_t hue, int32_t sat, int32_t lit, uint8_t *r, uint8_t *g, uint8_t *b)
+{
+ float m1, m2;
+ float h, s, l;
+
+ h = hue/360.0;
+ s = sat/100.0;
+ l = lit/100.0;
+
+ m2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;
+ m1 = l * 2 - m2;
+
+ *r = hue_to_RGB(m1, m2, h + (1.0/3.0));
+ *g = hue_to_RGB(m1, m2, h );
+ *b = hue_to_RGB(m1, m2, h - (1.0/3.0));
+}
+
/**
* Parse a colour specifier
*
@@ -273,9 +332,12 @@ css_error css__parse_colour_specifier(css_language *c,
consumeWhitespace(vector, ctx);
- /* IDENT(<colour name>) | HASH(rgb | rrggbb) |
+ /* 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
@@ -338,6 +400,14 @@ css_error css__parse_colour_specifier(css_language *c,
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) {
@@ -418,8 +488,112 @@ css_error css__parse_colour_specifier(css_language *c,
goto invalid;
}
}
- } else
+ } else if (colour_channels == 5 || colour_channels == 6) {
+ /* hue - saturation - lightness */
+ size_t consumed = 0;
+ css_fixed num;
+ int32_t alpha = 255, hue, sat, lit;
+
+ /* 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;
+
+ num = css__number_from_lwc_string(token->idata, true, &consumed);
+ if (consumed != lwc_string_length(token->idata))
+ goto invalid; /* failed to consume the whole string as a number */
+
+ hue = (((FIXTOINT(num) % 360) + 360) % 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;
+
+ num = css__number_from_lwc_string(token->idata, true, &consumed);
+ if (consumed != lwc_string_length(token->idata))
+ goto invalid; /* failed to consume the whole string as a number */
+ sat = FIXTOINT(num);
+
+ 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;
+
+ num = css__number_from_lwc_string(token->idata, true, &consumed);
+ if (consumed != lwc_string_length(token->idata))
+ goto invalid; /* failed to consume the whole string as a number */
+
+ lit = FIXTOINT(num);
+
+ 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;
+
+ num = css__number_from_lwc_string(token->idata, true, &consumed);
+ if (consumed != lwc_string_length(token->idata))
+ goto invalid; /* failed to consume the whole string as a number */
+
+ alpha = FIXTOINT(FMULI(num, 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;
diff --git a/src/parse/propstrings.c b/src/parse/propstrings.c
index ef71235..354c794 100644
--- a/src/parse/propstrings.c
+++ b/src/parse/propstrings.c
@@ -331,6 +331,8 @@ const stringmap_entry stringmap[LAST_KNOWN] = {
{ "blink", SLEN("blink") },
{ "rgb", SLEN("rgb") },
{ "rgba", SLEN("rgba") },
+ { "hsl", SLEN("hsl") },
+ { "hsla", SLEN("hsla") },
{ "-libcss-left", SLEN("-libcss-left") },
{ "-libcss-center", SLEN("-libcss-center") },
{ "-libcss-right", SLEN("-libcss-right") },
diff --git a/src/parse/propstrings.h b/src/parse/propstrings.h
index 78b7dda..d3b7208 100644
--- a/src/parse/propstrings.h
+++ b/src/parse/propstrings.h
@@ -84,7 +84,7 @@ enum {
NE_RESIZE, NW_RESIZE, N_RESIZE, SE_RESIZE, SW_RESIZE, S_RESIZE,
W_RESIZE, LIBCSS_TEXT, WAIT, HELP, PROGRESS, SERIF, SANS_SERIF, CURSIVE,
FANTASY, MONOSPACE, MALE, FEMALE, CHILD, MIX, UNDERLINE, OVERLINE,
- LINE_THROUGH, BLINK, RGB, RGBA, LIBCSS_LEFT, LIBCSS_CENTER,
+ LINE_THROUGH, BLINK, RGB, RGBA, HSL, HSLA, LIBCSS_LEFT, LIBCSS_CENTER,
LIBCSS_RIGHT,
/* Named colours */
diff --git a/test/data/parse/INDEX b/test/data/parse/INDEX
index da0b41c..6019062 100644
--- a/test/data/parse/INDEX
+++ b/test/data/parse/INDEX
@@ -6,4 +6,5 @@ tests1.dat Basic tests
selectors.dat Selectors
atrules.dat @-rules
colours.dat Colour values
+colours-hsl.dat HSL Colour values
properties.dat Properties
diff --git a/test/data/parse/properties.dat b/test/data/parse/properties.dat
index 8cc4c7d..ac038e5 100644
--- a/test/data/parse/properties.dat
+++ b/test/data/parse/properties.dat
@@ -777,6 +777,16 @@
| 0x02000018 0xffbbbbcc
#reset
+## more fully tested in colours-hsl.dat
+
+#data
+* { color: hsl(240,15%,77%) }
+#errors
+#expected
+| 1 *
+| 0x02000018 0xffbbbbcd
+#reset
+
##
## 19 - content
##