diff options
Diffstat (limited to 'src/parse')
-rw-r--r-- | src/parse/Makefile | 2 | ||||
-rw-r--r-- | src/parse/font_face.c | 413 | ||||
-rw-r--r-- | src/parse/font_face.h | 22 | ||||
-rw-r--r-- | src/parse/language.c | 42 | ||||
-rw-r--r-- | src/parse/properties/utils.c | 45 | ||||
-rw-r--r-- | src/parse/properties/utils.h | 14 | ||||
-rw-r--r-- | src/parse/propstrings.c | 10 | ||||
-rw-r--r-- | src/parse/propstrings.h | 5 |
8 files changed, 540 insertions, 13 deletions
diff --git a/src/parse/Makefile b/src/parse/Makefile index a7548a8..3d1df42 100644 --- a/src/parse/Makefile +++ b/src/parse/Makefile @@ -1,4 +1,4 @@ # Sources -DIR_SOURCES := parse.c language.c important.c propstrings.c +DIR_SOURCES := parse.c language.c important.c propstrings.c font_face.c include build/makefiles/Makefile.subdir diff --git a/src/parse/font_face.c b/src/parse/font_face.c new file mode 100644 index 0000000..14a715d --- /dev/null +++ b/src/parse/font_face.c @@ -0,0 +1,413 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2011 Things Made Out Of Other Things Ltd. + * Written by James Montgomerie <jamie@th.ingsmadeoutofotherthin.gs> + */ + +#include "parse/font_face.h" + +#include <assert.h> +#include <string.h> + +#include "parse/propstrings.h" +#include "parse/properties/utils.h" +#include "select/font_face.h" + +static bool font_rule_font_family_reserved(css_language *c, + const css_token *ident) +{ + bool match; + + return (lwc_string_caseless_isequal(ident->idata, c->strings[SERIF], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal(ident->idata, + c->strings[SANS_SERIF], &match) == lwc_error_ok && + match) || + (lwc_string_caseless_isequal(ident->idata, c->strings[CURSIVE], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal(ident->idata, c->strings[FANTASY], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal(ident->idata, + c->strings[MONOSPACE], &match) == lwc_error_ok && + match) || + (lwc_string_caseless_isequal(ident->idata, c->strings[INHERIT], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal(ident->idata, c->strings[INITIAL], + &match) == lwc_error_ok && match) || + (lwc_string_caseless_isequal(ident->idata, c->strings[DEFAULT], + &match) == lwc_error_ok && match); +} + +static css_error font_face_parse_font_family(css_language *c, + const parserutils_vector *vector, int *ctx, + css_font_face *font_face) +{ + css_error error; + lwc_string *string; + + error = css__ident_list_or_string_to_string(c, vector, ctx, + font_rule_font_family_reserved, &string); + if (error != CSS_OK) + return error; + + css__font_face_set_font_family(font_face, string); + + lwc_string_unref(string); + + return CSS_OK; +} + +static css_error font_face_src_parse_format(css_language *c, + const parserutils_vector *vector, int *ctx, + css_font_face_format *format) +{ + bool match; + const css_token *token; + + *format = CSS_FONT_FACE_FORMAT_UNSPECIFIED; + + /* 'format(' STRING [ ',' STRING ]* ')' + * + * 'format(' already consumed + */ + + do { + consumeWhitespace(vector, ctx); + + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || token->type != CSS_TOKEN_STRING) + return CSS_INVALID; + + if (lwc_string_isequal(token->idata, + c->strings[WOFF], &match) == lwc_error_ok && + match) { + *format |= CSS_FONT_FACE_FORMAT_WOFF; + } else if ((lwc_string_isequal(token->idata, + c->strings[TRUETYPE], &match) == lwc_error_ok && + match) || + (lwc_string_isequal(token->idata, + c->strings[OPENTYPE], &match) == lwc_error_ok && + match)) { + *format |= CSS_FONT_FACE_FORMAT_OPENTYPE; + } else if (lwc_string_isequal(token->idata, + c->strings[EMBEDDED_OPENTYPE], + &match) == lwc_error_ok && match) { + *format |= CSS_FONT_FACE_FORMAT_EMBEDDED_OPENTYPE; + } else if (lwc_string_isequal(token->idata, + c->strings[SVG], &match) == lwc_error_ok && + match) { + *format |= CSS_FONT_FACE_FORMAT_SVG; + } else { + /* The spec gives a list of possible strings, which + * hints that unknown strings should be parse errors, + * but it also talks about "unknown font formats", + * so we treat any string we don't know not as a parse + * error, but as indicating an "unknown font format". + */ + *format |= CSS_FONT_FACE_FORMAT_UNKNOWN; + } + + consumeWhitespace(vector, ctx); + token = parserutils_vector_iterate(vector, ctx); + } while (token != NULL && tokenIsChar(token, ',')); + + if (token == NULL || tokenIsChar(token, ')') == false) + return CSS_INVALID; + + return CSS_OK; +} + +static css_error font_face_src_parse_spec_or_name(css_language *c, + const parserutils_vector *vector, int *ctx, + lwc_string **location, + css_font_face_location_type *location_type, + css_font_face_format *format) +{ + const css_token *token; + css_error error; + bool match; + + /* spec-or-name ::= font-face-spec | font-face-name + * font-face-spec ::= URI [ 'format(' STRING [ ',' STRING ]* ')' ]? + * font-face-name ::= 'local(' ident-list-or-string ')' + * ident-list-or-string ::= IDENT IDENT* | STRING + */ + + consumeWhitespace(vector, ctx); + + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL) + return CSS_INVALID; + + if (token->type == CSS_TOKEN_URI) { + error = c->sheet->resolve(c->sheet->resolve_pw, + c->sheet->url, token->idata, + location); + if (error != CSS_OK) + return error; + + *location_type = CSS_FONT_FACE_LOCATION_TYPE_URI; + + consumeWhitespace(vector, ctx); + + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && token->type == CSS_TOKEN_FUNCTION && + lwc_string_caseless_isequal(token->idata, + c->strings[FORMAT], &match) == lwc_error_ok && + match) { + parserutils_vector_iterate(vector, ctx); + + error = font_face_src_parse_format(c, vector, ctx, + format); + if (error != CSS_OK) { + lwc_string_unref(*location); + return error; + } + } + } else if (token->type == CSS_TOKEN_FUNCTION && + lwc_string_caseless_isequal(token->idata, + c->strings[LOCAL], + &match) == lwc_error_ok && match) { + consumeWhitespace(vector, ctx); + + error = css__ident_list_or_string_to_string( + c, vector, ctx, NULL, location); + if (error != CSS_OK) + return error; + + consumeWhitespace(vector, ctx); + + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || tokenIsChar(token, ')') == false) { + lwc_string_unref(*location); + return CSS_INVALID; + } + + *location_type = CSS_FONT_FACE_LOCATION_TYPE_LOCAL; + } else { + return CSS_INVALID; + } + + return CSS_OK; +} + +static css_error font_face_parse_src(css_language *c, + const parserutils_vector *vector, int *ctx, + css_font_face *font_face) +{ + int orig_ctx = *ctx; + css_error error = CSS_OK; + const css_token *token; + css_font_face_src *srcs = NULL, *new_srcs = NULL; + uint32_t n_srcs = 0; + + /* src ::= spec-or-name [ ',' spec-or-name ]* + * spec-or-name ::= font-face-spec | font-face-name + * font-face-spec ::= URI [ 'format(' STRING [ ',' STRING ]* ')' ]? + * font-face-name ::= 'local(' ident-list-or-string ')' + * ident-list-or-string ::= IDENT IDENT* | STRING + */ + + /* Create one css_font_face_src for each consecutive location and + * [potentially] type pair in the comma-separated list + */ + do { + lwc_string *location; + css_font_face_location_type location_type = + CSS_FONT_FACE_LOCATION_TYPE_UNSPECIFIED; + css_font_face_format format = + CSS_FONT_FACE_FORMAT_UNSPECIFIED; + + error = font_face_src_parse_spec_or_name(c, vector, ctx, + &location, &location_type, &format); + if (error != CSS_OK) + goto cleanup; + + /* This will be inefficient if there are a lot of locations - + * probably not a problem in practice. + */ + new_srcs = c->alloc(srcs, + (n_srcs + 1) * sizeof(css_font_face_src), + c->pw); + if (new_srcs == NULL) { + error = CSS_NOMEM; + goto cleanup; + } + srcs = new_srcs; + + srcs[n_srcs].location = location; + srcs[n_srcs].bits[0] = format << 2 | location_type; + + ++n_srcs; + + consumeWhitespace(vector, ctx); + token = parserutils_vector_iterate(vector, ctx); + } while (token != NULL && tokenIsChar(token, ',')); + + error = css__font_face_set_srcs(font_face, srcs, n_srcs); + +cleanup: + if (error != CSS_OK) { + *ctx = orig_ctx; + if (srcs != NULL) + c->alloc(srcs, 0, c->pw); + } + + return error; +} + +static css_error font_face_parse_font_style(css_language *c, + const parserutils_vector *vector, int *ctx, + css_font_face *font_face) +{ + int orig_ctx = *ctx; + css_error error = CSS_OK; + const css_token *token; + enum css_font_style_e style = 0; + bool match; + + /* IDENT(normal, italic, oblique) */ + + token = parserutils_vector_iterate(vector, ctx); + if ((token == NULL) || ((token->type != CSS_TOKEN_IDENT))) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if ((lwc_string_caseless_isequal(token->idata, + c->strings[NORMAL], &match) == lwc_error_ok && match)) { + style = CSS_FONT_STYLE_NORMAL; + } else if ((lwc_string_caseless_isequal(token->idata, + c->strings[ITALIC], &match) == lwc_error_ok && match)) { + style = CSS_FONT_STYLE_ITALIC; + } else if ((lwc_string_caseless_isequal(token->idata, + c->strings[OBLIQUE], &match) == lwc_error_ok && + match)) { + style = CSS_FONT_STYLE_OBLIQUE; + } else { + error = CSS_INVALID; + } + + if (error == CSS_OK) { + font_face->bits[0] = (font_face->bits[0] & 0xfc) | style; + } else { + *ctx = orig_ctx; + } + + return error; +} + +static css_error font_face_parse_font_weight(css_language *c, + const parserutils_vector *vector, int *ctx, + css_font_face *font_face) +{ + int orig_ctx = *ctx; + css_error error = CSS_OK; + const css_token *token; + enum css_font_weight_e weight = 0; + bool match; + + /* NUMBER (100, 200, 300, 400, 500, 600, 700, 800, 900) | + * IDENT (normal, bold) */ + token = parserutils_vector_iterate(vector, ctx); + if (token == NULL || (token->type != CSS_TOKEN_IDENT && + token->type != CSS_TOKEN_NUMBER)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + if (token->type == CSS_TOKEN_NUMBER) { + size_t consumed = 0; + css_fixed num = css__number_from_lwc_string(token->idata, + true, &consumed); + /* Invalid if there are trailing characters */ + if (consumed != lwc_string_length(token->idata)) { + *ctx = orig_ctx; + return CSS_INVALID; + } + + switch (FIXTOINT(num)) { + case 100: weight = CSS_FONT_WEIGHT_100; break; + case 200: weight = CSS_FONT_WEIGHT_200; break; + case 300: weight = CSS_FONT_WEIGHT_300; break; + case 400: weight = CSS_FONT_WEIGHT_400; break; + case 500: weight = CSS_FONT_WEIGHT_500; break; + case 600: weight = CSS_FONT_WEIGHT_600; break; + case 700: weight = CSS_FONT_WEIGHT_700; break; + case 800: weight = CSS_FONT_WEIGHT_800; break; + case 900: weight = CSS_FONT_WEIGHT_900; break; + default: error = CSS_INVALID; + } + } else if ((lwc_string_caseless_isequal(token->idata, + c->strings[NORMAL], &match) == lwc_error_ok && match)) { + weight = CSS_FONT_WEIGHT_NORMAL; + } else if ((lwc_string_caseless_isequal(token->idata, + c->strings[BOLD], &match) == lwc_error_ok && match)) { + weight = CSS_FONT_WEIGHT_BOLD; + } else { + error = CSS_INVALID; + } + + if (error == CSS_OK) { + font_face->bits[0] = (font_face->bits[0] & 0xc3) | + (weight << 2); + } else { + *ctx = orig_ctx; + } + + return error; +} + +/** + * Parse a descriptor in an @font-face rule + * + * \param c Parsing context + * \param descriptor Token for this descriptor + * \param vector Vector of tokens to process + * \param ctx Pointer to vector iteration context + * \param rule Rule to process descriptor into + * \return CSS_OK on success, + * CSS_BADPARM on bad parameters, + * CSS_INVALID on invalid syntax, + * CSS_NOMEM on memory exhaustion + */ +css_error css__parse_font_descriptor(css_language *c, + const css_token *descriptor, const parserutils_vector *vector, + int *ctx, css_rule_font_face *rule) +{ + css_font_face *font_face = rule->font_face; + css_error error; + bool match; + + if (font_face == NULL) { + error = css__font_face_create(c->sheet->alloc, + c->sheet->pw, &font_face); + if (error != CSS_OK) { + return error; + } + + rule->font_face = font_face; + } + + if (lwc_string_caseless_isequal(descriptor->idata, + c->strings[FONT_FAMILY], &match) == lwc_error_ok && + match) { + return font_face_parse_font_family(c, vector, ctx, font_face); + } else if (lwc_string_caseless_isequal(descriptor->idata, + c->strings[SRC], &match) == lwc_error_ok && match) { + return font_face_parse_src(c, vector, ctx, font_face); + } else if (lwc_string_caseless_isequal(descriptor->idata, + c->strings[FONT_STYLE], &match) == lwc_error_ok && + match) { + return font_face_parse_font_style(c, vector, ctx, font_face); + } else if (lwc_string_caseless_isequal(descriptor->idata, + c->strings[FONT_WEIGHT], &match) == lwc_error_ok && + match) { + return font_face_parse_font_weight(c, vector, ctx, font_face); + } + + return CSS_INVALID; +} + diff --git a/src/parse/font_face.h b/src/parse/font_face.h new file mode 100644 index 0000000..435380e --- /dev/null +++ b/src/parse/font_face.h @@ -0,0 +1,22 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2011 Things Made Out Of Other Things Ltd. + * Written by James Montgomerie <jamie@th.ingsmadeoutofotherthin.gs> + */ + +#ifndef css_parse_font_face_h_ +#define css_parse_font_face_h_ + +#include <parserutils/utils/vector.h> + +#include "stylesheet.h" +#include "lex/lex.h" +#include "parse/language.h" + +css_error css__parse_font_descriptor(css_language *c, + const css_token *descriptor, const parserutils_vector *vector, + int *ctx, struct css_rule_font_face *rule); + +#endif diff --git a/src/parse/language.c b/src/parse/language.c index 0436c22..a5fce0e 100644 --- a/src/parse/language.c +++ b/src/parse/language.c @@ -12,6 +12,7 @@ #include "stylesheet.h" #include "lex/lex.h" +#include "parse/font_face.h" #include "parse/important.h" #include "parse/language.h" #include "parse/parse.h" @@ -558,6 +559,26 @@ css_error handleStartAtRule(css_language *c, const parserutils_vector *vector) * so no need to destroy it */ c->state = HAD_RULE; + } else if (lwc_string_caseless_isequal(atkeyword->idata, + c->strings[FONT_FACE], &match) == lwc_error_ok && + match) { + error = css__stylesheet_rule_create(c->sheet, + CSS_RULE_FONT_FACE, &rule); + if (error != CSS_OK) + return error; + + consumeWhitespace(vector, &ctx); + + error = css__stylesheet_add_rule(c->sheet, rule, NULL); + if (error != CSS_OK) { + css__stylesheet_rule_destroy(c->sheet, rule); + return error; + } + + /* Rule is now owned by the sheet, + * so no need to destroy it */ + + c->state = HAD_RULE; } else if (lwc_string_caseless_isequal(atkeyword->idata, c->strings[PAGE], &match) == lwc_error_ok && match) { const css_token *token; @@ -693,9 +714,9 @@ css_error handleBlockContent(css_language *c, const parserutils_vector *vector) context_entry *entry; css_rule *rule; - /* In CSS 2.1, block content comprises either declarations (if the - * current block is associated with @page or a selector), or rulesets - * (if the current block is associated with @media). */ + /* Block content comprises either declarations (if the current block is + * associated with @page, @font-face or a selector), or rulesets (if the + * current block is associated with @media). */ entry = parserutils_stack_get_current(c->context); if (entry == NULL || entry->data == NULL) @@ -704,7 +725,8 @@ css_error handleBlockContent(css_language *c, const parserutils_vector *vector) rule = entry->data; if (rule == NULL || (rule->type != CSS_RULE_SELECTOR && rule->type != CSS_RULE_PAGE && - rule->type != CSS_RULE_MEDIA)) + rule->type != CSS_RULE_MEDIA && + rule->type != CSS_RULE_FONT_FACE)) return CSS_INVALID; if (rule->type == CSS_RULE_MEDIA) { @@ -729,6 +751,7 @@ css_error handleDeclaration(css_language *c, const parserutils_vector *vector) /* Locations where declarations are permitted: * * + In @page + * + In @font-face * + In ruleset */ entry = parserutils_stack_get_current(c->context); @@ -737,7 +760,8 @@ css_error handleDeclaration(css_language *c, const parserutils_vector *vector) rule = entry->data; if (rule == NULL || (rule->type != CSS_RULE_SELECTOR && - rule->type != CSS_RULE_PAGE)) + rule->type != CSS_RULE_PAGE && + rule->type != CSS_RULE_FONT_FACE)) return CSS_INVALID; /* Strip any leading whitespace (can happen if in nested block) */ @@ -759,7 +783,13 @@ css_error handleDeclaration(css_language *c, const parserutils_vector *vector) consumeWhitespace(vector, &ctx); - error = parseProperty(c, ident, vector, &ctx, rule); + if (rule->type == CSS_RULE_FONT_FACE) { + css_rule_font_face * ff_rule = (css_rule_font_face *) rule; + error = css__parse_font_descriptor( + c, ident, vector, &ctx, ff_rule); + } else { + error = parseProperty(c, ident, vector, &ctx, rule); + } if (error != CSS_OK) return error; diff --git a/src/parse/properties/utils.c b/src/parse/properties/utils.c index bf7e212..4eca6fc 100644 --- a/src/parse/properties/utils.c +++ b/src/parse/properties/utils.c @@ -1044,6 +1044,45 @@ css_error css__parse_unit_keyword(const char *ptr, size_t len, css_unit *unit) } /** + * Create a string from a list of IDENT/S tokens if the next token is IDENT + * or references the next token's string if it is a STRING + * + * \param c Parsing context + * \param vector Vector containing tokens + * \param ctx Vector iteration context + * \param reserved Callback to determine if an identifier is reserved + * \param result Pointer to location to receive resulting string + * \return CSS_OK on success, appropriate error otherwise. + * + * Post condition: \a *ctx is updated with the next token to process + * If the input is invalid, then \a *ctx remains unchanged. + * + * The resulting string's reference is passed to the caller + */ +css_error css__ident_list_or_string_to_string(css_language *c, + const parserutils_vector *vector, int *ctx, + bool (*reserved)(css_language *c, const css_token *ident), + lwc_string **result) +{ + const css_token *token; + + token = parserutils_vector_peek(vector, *ctx); + if (token == NULL) + return CSS_INVALID; + + if (token->type == CSS_TOKEN_STRING) { + token = parserutils_vector_iterate(vector, ctx); + *result = lwc_string_ref(token->idata); + return CSS_OK; + } else if(token->type == CSS_TOKEN_IDENT) { + return css__ident_list_to_string(c, vector, ctx, reserved, + result); + } + + return CSS_INVALID; +} + +/** * Create a string from a list of IDENT/S tokens * * \param c Parsing context @@ -1058,7 +1097,7 @@ css_error css__parse_unit_keyword(const char *ptr, size_t len, css_unit *unit) * * The resulting string's reference is passed to the caller */ -static css_error ident_list_to_string(css_language *c, +css_error css__ident_list_to_string(css_language *c, const parserutils_vector *vector, int *ctx, bool (*reserved)(css_language *c, const css_token *ident), lwc_string **result) @@ -1084,7 +1123,7 @@ static css_error ident_list_to_string(css_language *c, token->type == CSS_TOKEN_S)) { if (token->type == CSS_TOKEN_IDENT) { /* IDENT -- if reserved, reject style */ - if (reserved(c, token)) { + if (reserved != NULL && reserved(c, token)) { error = CSS_INVALID; goto cleanup; } @@ -1175,7 +1214,7 @@ css_error css__comma_list_to_style(css_language *c, *ctx = prev_ctx; - error = ident_list_to_string(c, vector, ctx, + error = css__ident_list_to_string(c, vector, ctx, reserved, &str); if (error != CSS_OK) goto cleanup; diff --git a/src/parse/properties/utils.h b/src/parse/properties/utils.h index ab045bd..be903ee 100644 --- a/src/parse/properties/utils.h +++ b/src/parse/properties/utils.h @@ -181,10 +181,22 @@ css_error css__parse_unit_specifier(css_language *c, css_error css__parse_unit_keyword(const char *ptr, size_t len, css_unit *unit); +css_error css__ident_list_or_string_to_string(css_language *c, + const parserutils_vector *vector, int *ctx, + bool (*reserved)(css_language *c, const css_token *ident), + lwc_string **result); + +css_error css__ident_list_to_string(css_language *c, + const parserutils_vector *vector, int *ctx, + bool (*reserved)(css_language *c, const css_token *ident), + lwc_string **result); + css_error css__comma_list_to_style(css_language *c, const parserutils_vector *vector, int *ctx, bool (*reserved)(css_language *c, const css_token *ident), - css_code_t (*get_value)(css_language *c, const css_token *token, bool first), + css_code_t (*get_value)(css_language *c, + const css_token *token, + bool first), css_style *result); #endif diff --git a/src/parse/propstrings.c b/src/parse/propstrings.c index bf1fcd0..dea8816 100644 --- a/src/parse/propstrings.c +++ b/src/parse/propstrings.c @@ -30,6 +30,7 @@ const stringmap_entry stringmap[LAST_KNOWN] = { { "import", SLEN("import") }, { "media", SLEN("media") }, { "namespace", SLEN("namespace") }, + { "font-face", SLEN("font-face") }, { "page", SLEN("page") }, { "aural", SLEN("aural") }, @@ -372,6 +373,15 @@ const stringmap_entry stringmap[LAST_KNOWN] = { { "currentColor", SLEN("currentColor") }, { "odd", SLEN("odd") }, { "even", SLEN("even") }, + { "src", SLEN("src") }, + { "local", SLEN("local") }, + { "initial", SLEN("initial") }, + { "format", SLEN("format") }, + { "woff", SLEN("woff") }, + { "truetype", SLEN("truetype") }, + { "opentype", SLEN("opentype") }, + { "embedded-opentype", SLEN("embedded-opentype") }, + { "svg", SLEN("svg") }, { "aliceblue", SLEN("aliceblue") }, { "antiquewhite", SLEN("antiquewhite") }, diff --git a/src/parse/propstrings.h b/src/parse/propstrings.h index 7c7b693..16affcd 100644 --- a/src/parse/propstrings.h +++ b/src/parse/propstrings.h @@ -15,7 +15,7 @@ enum { UNIVERSAL, /* At-rules */ - CHARSET, LIBCSS_IMPORT, MEDIA, NAMESPACE, PAGE, + CHARSET, LIBCSS_IMPORT, MEDIA, NAMESPACE, FONT_FACE, PAGE, /* Media types */ AURAL, BRAILLE, EMBOSSED, HANDHELD, PRINT, PROJECTION, @@ -88,7 +88,8 @@ enum { W_RESIZE, LIBCSS_TEXT, WAIT, HELP, PROGRESS, SERIF, SANS_SERIF, CURSIVE, FANTASY, MONOSPACE, MALE, FEMALE, CHILD, MIX, UNDERLINE, OVERLINE, LINE_THROUGH, BLINK, RGB, RGBA, HSL, HSLA, LIBCSS_LEFT, LIBCSS_CENTER, - LIBCSS_RIGHT, CURRENTCOLOR, ODD, EVEN, + LIBCSS_RIGHT, CURRENTCOLOR, ODD, EVEN, SRC, LOCAL, INITIAL, + FORMAT, WOFF, TRUETYPE, OPENTYPE, EMBEDDED_OPENTYPE, SVG, /* Named colours */ FIRST_COLOUR, |