/** * Convert a voice-family token into a bytecode value * * \param c Parsing context * \param token Token to consider * \return Bytecode value */ static css_code_t voice_family_value(css_language *c, const css_token *token, bool first) { uint16_t value; bool match; if (token->type == CSS_TOKEN_IDENT) { if ((lwc_string_caseless_isequal( token->idata, c->strings[MALE], &match) == lwc_error_ok && match)) value = VOICE_FAMILY_MALE; else if ((lwc_string_caseless_isequal( token->idata, c->strings[FEMALE], &match) == lwc_error_ok && match)) value = VOICE_FAMILY_FEMALE; else if ((lwc_string_caseless_isequal( token->idata, c->strings[CHILD], &match) == lwc_error_ok && match)) value = VOICE_FAMILY_CHILD; else value = VOICE_FAMILY_IDENT_LIST; } else { value = VOICE_FAMILY_STRING; } return first ? buildOPV(CSS_PROP_VOICE_FAMILY, 0, value) : value; }
/** * Parse overflow * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \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 parse_overflow(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) { int orig_ctx = *ctx; css_error error; const css_token *ident; uint8_t flags = 0; uint16_t value = 0; uint32_t opv; bool match; /* IDENT (visible, hidden, scroll, auto, inherit) */ ident = parserutils_vector_iterate(vector, ctx); if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { *ctx = orig_ctx; return CSS_INVALID; } if ((lwc_string_caseless_isequal( ident->idata, c->strings[INHERIT], &match) == lwc_error_ok && match)) { flags |= FLAG_INHERIT; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[VISIBLE], &match) == lwc_error_ok && match)) { value = OVERFLOW_VISIBLE; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[HIDDEN], &match) == lwc_error_ok && match)) { value = OVERFLOW_HIDDEN; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[SCROLL], &match) == lwc_error_ok && match)) { value = OVERFLOW_SCROLL; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[AUTO], &match) == lwc_error_ok && match)) { value = OVERFLOW_AUTO; } else { *ctx = orig_ctx; return CSS_INVALID; } opv = buildOPV(CSS_PROP_OVERFLOW, flags, value); /* Allocate result */ error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); if (error != CSS_OK) { *ctx = orig_ctx; return error; } /* Copy the bytecode to it */ memcpy((*result)->bytecode, &opv, sizeof(opv)); return CSS_OK; }
/** * Parse width * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \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 parse_width(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) { int orig_ctx = *ctx; css_error error; const css_token *token; uint8_t flags = 0; uint16_t value = 0; uint32_t opv; css_fixed length = 0; uint32_t unit = 0; uint32_t required_size; bool match; /* length | percentage | IDENT(auto, inherit) */ token = parserutils_vector_peek(vector, *ctx); if (token == NULL) { *ctx = orig_ctx; return CSS_INVALID; } if (token->type == CSS_TOKEN_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[INHERIT], &match) == lwc_error_ok && match)) { parserutils_vector_iterate(vector, ctx); flags = FLAG_INHERIT; } else if (token->type == CSS_TOKEN_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[AUTO], &match) == lwc_error_ok && match)) { parserutils_vector_iterate(vector, ctx); value = WIDTH_AUTO; } else { error = parse_unit_specifier(c, vector, ctx, UNIT_PX, &length, &unit); if (error != CSS_OK) { *ctx = orig_ctx; return error; } if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { *ctx = orig_ctx; return CSS_INVALID; } /* Must be positive */ if (length < 0) { *ctx = orig_ctx; return CSS_INVALID; } value = WIDTH_SET; } opv = buildOPV(CSS_PROP_WIDTH, flags, value); required_size = sizeof(opv); if ((flags & FLAG_INHERIT) == false && value == WIDTH_SET) required_size += sizeof(length) + sizeof(unit); /* Allocate result */ error = css_stylesheet_style_create(c->sheet, required_size, result); if (error != CSS_OK) { *ctx = orig_ctx; return error; } /* Copy the bytecode to it */ memcpy((*result)->bytecode, &opv, sizeof(opv)); if ((flags & FLAG_INHERIT) == false && value == WIDTH_SET) { memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), &length, sizeof(length)); memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + sizeof(length), &unit, sizeof(unit)); } return CSS_OK; }
/** * Parse display * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \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 parse_display(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) { int orig_ctx = *ctx; css_error error; const css_token *ident; uint8_t flags = 0; uint16_t value = 0; uint32_t opv; bool match; /* IDENT (inline, block, list-item, run-in, inline-block, table, * inline-table, table-row-group, table-header-group, * table-footer-group, table-row, table-column-group, table-column, * table-cell, table-caption, none, inherit) */ ident = parserutils_vector_iterate(vector, ctx); if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { *ctx = orig_ctx; return CSS_INVALID; } if ((lwc_string_caseless_isequal( ident->idata, c->strings[INHERIT], &match) == lwc_error_ok && match)) { flags |= FLAG_INHERIT; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[INLINE], &match) == lwc_error_ok && match)) { value = DISPLAY_INLINE; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[BLOCK], &match) == lwc_error_ok && match)) { value = DISPLAY_BLOCK; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[LIST_ITEM], &match) == lwc_error_ok && match)) { value = DISPLAY_LIST_ITEM; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[RUN_IN], &match) == lwc_error_ok && match)) { value = DISPLAY_RUN_IN; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[INLINE_BLOCK], &match) == lwc_error_ok && match)) { value = DISPLAY_INLINE_BLOCK; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[TABLE], &match) == lwc_error_ok && match)) { value = DISPLAY_TABLE; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[INLINE_TABLE], &match) == lwc_error_ok && match)) { value = DISPLAY_INLINE_TABLE; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[TABLE_ROW_GROUP], &match) == lwc_error_ok && match)) { value = DISPLAY_TABLE_ROW_GROUP; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[TABLE_HEADER_GROUP], &match) == lwc_error_ok && match)) { value = DISPLAY_TABLE_HEADER_GROUP; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[TABLE_FOOTER_GROUP], &match) == lwc_error_ok && match)) { value = DISPLAY_TABLE_FOOTER_GROUP; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[TABLE_ROW], &match) == lwc_error_ok && match)) { value = DISPLAY_TABLE_ROW; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[TABLE_COLUMN_GROUP], &match) == lwc_error_ok && match)) { value = DISPLAY_TABLE_COLUMN_GROUP; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[TABLE_COLUMN], &match) == lwc_error_ok && match)) { value = DISPLAY_TABLE_COLUMN; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[TABLE_CELL], &match) == lwc_error_ok && match)) { value = DISPLAY_TABLE_CELL; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[TABLE_CAPTION], &match) == lwc_error_ok && match)) { value = DISPLAY_TABLE_CAPTION; } else if ((lwc_string_caseless_isequal( ident->idata, c->strings[NONE], &match) == lwc_error_ok && match)) { value = DISPLAY_NONE; } else { *ctx = orig_ctx; return CSS_INVALID; } opv = buildOPV(CSS_PROP_DISPLAY, flags, value); /* Allocate result */ error = css_stylesheet_style_create(c->sheet, sizeof(opv), result); if (error != CSS_OK) { *ctx = orig_ctx; return error; } /* Copy the bytecode to it */ memcpy((*result)->bytecode, &opv, sizeof(opv)); return CSS_OK; }
/** * Parse line-height * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \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 parse_line_height(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) { int orig_ctx = *ctx; css_error error; const css_token *token; uint8_t flags = 0; uint16_t value = 0; uint32_t opv; css_fixed length = 0; uint32_t unit = 0; uint32_t required_size; bool match; /* number | length | percentage | IDENT(normal, inherit) */ token = parserutils_vector_peek(vector, *ctx); if (token == NULL) { *ctx = orig_ctx; return CSS_INVALID; } if (token->type == CSS_TOKEN_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[INHERIT], &match) == lwc_error_ok && match)) { parserutils_vector_iterate(vector, ctx); flags = FLAG_INHERIT; } else if (token->type == CSS_TOKEN_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[NORMAL], &match) == lwc_error_ok && match)) { parserutils_vector_iterate(vector, ctx); value = LINE_HEIGHT_NORMAL; } else if (token->type == CSS_TOKEN_NUMBER) { size_t consumed = 0; length = number_from_lwc_string(token->idata, false, &consumed); if (consumed != lwc_string_length(token->idata)) { *ctx = orig_ctx; return CSS_INVALID; } /* Negative values are illegal */ if (length < 0) { *ctx = orig_ctx; return CSS_INVALID; } parserutils_vector_iterate(vector, ctx); value = LINE_HEIGHT_NUMBER; } else { error = parse_unit_specifier(c, vector, ctx, UNIT_PX, &length, &unit); if (error != CSS_OK) { *ctx = orig_ctx; return error; } if (unit & UNIT_ANGLE || unit & UNIT_TIME || unit & UNIT_FREQ) { *ctx = orig_ctx; return CSS_INVALID; } /* Negative values are illegal */ if (length < 0) { *ctx = orig_ctx; return CSS_INVALID; } value = LINE_HEIGHT_DIMENSION; } opv = buildOPV(CSS_PROP_LINE_HEIGHT, flags, value); required_size = sizeof(opv); if ((flags & FLAG_INHERIT) == false && value == LINE_HEIGHT_NUMBER) required_size += sizeof(length); else if ((flags & FLAG_INHERIT) == false && value == LINE_HEIGHT_DIMENSION) required_size += sizeof(length) + sizeof(unit); /* Allocate result */ error = css_stylesheet_style_create(c->sheet, required_size, result); if (error != CSS_OK) { *ctx = orig_ctx; return error; } /* Copy the bytecode to it */ memcpy((*result)->bytecode, &opv, sizeof(opv)); if ((flags & FLAG_INHERIT) == false && (value == LINE_HEIGHT_NUMBER || value == LINE_HEIGHT_DIMENSION)) memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), &length, sizeof(length)); if ((flags & FLAG_INHERIT) == false && value == LINE_HEIGHT_DIMENSION) memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) + sizeof(length), &unit, sizeof(unit)); return CSS_OK; }
/** * Make a style important * * \param style The style to modify */ void css__make_style_important(css_style *style) { css_code_t *bytecode = style->bytecode; uint32_t length = style->used; uint32_t offset = 0; while (offset < length) { opcode_t op; uint8_t flags; uint32_t value; css_code_t opv = bytecode[offset]; /* Extract opv components, setting important flag */ op = getOpcode(opv); flags = getFlags(opv) | FLAG_IMPORTANT; value = getValue(opv); /* Write OPV back to bytecode */ bytecode[offset] = buildOPV(op, flags, value); offset++; /* Advance past any property-specific data */ if (isInherit(opv) == false) { switch (op) { case CSS_PROP_AZIMUTH: if ((value & ~AZIMUTH_BEHIND) == AZIMUTH_ANGLE) offset += 2; /* length + units */ break; case CSS_PROP_BORDER_TOP_COLOR: case CSS_PROP_BORDER_RIGHT_COLOR: case CSS_PROP_BORDER_BOTTOM_COLOR: case CSS_PROP_BORDER_LEFT_COLOR: case CSS_PROP_BACKGROUND_COLOR: case CSS_PROP_COLUMN_RULE_COLOR: assert(BACKGROUND_COLOR_SET == (enum op_background_color)BORDER_COLOR_SET); assert(BACKGROUND_COLOR_SET == (enum op_background_color)COLUMN_RULE_COLOR_SET); if (value == BACKGROUND_COLOR_SET) offset++; /* colour */ break; case CSS_PROP_BACKGROUND_IMAGE: case CSS_PROP_CUE_AFTER: case CSS_PROP_CUE_BEFORE: case CSS_PROP_LIST_STYLE_IMAGE: assert(BACKGROUND_IMAGE_URI == (enum op_background_image)CUE_AFTER_URI); assert(BACKGROUND_IMAGE_URI == (enum op_background_image)CUE_BEFORE_URI); assert(BACKGROUND_IMAGE_URI == (enum op_background_image)LIST_STYLE_IMAGE_URI); if (value == BACKGROUND_IMAGE_URI) offset++; /* string table entry */ break; case CSS_PROP_BACKGROUND_POSITION: if ((value & 0xf0) == BACKGROUND_POSITION_HORZ_SET) offset += 2; /* length + units */ if ((value & 0x0f) == BACKGROUND_POSITION_VERT_SET) offset += 2; /* length + units */ break; case CSS_PROP_BORDER_SPACING: if (value == BORDER_SPACING_SET) offset += 4; /* two length + units */ break; case CSS_PROP_BORDER_TOP_WIDTH: case CSS_PROP_BORDER_RIGHT_WIDTH: case CSS_PROP_BORDER_BOTTOM_WIDTH: case CSS_PROP_BORDER_LEFT_WIDTH: case CSS_PROP_OUTLINE_WIDTH: case CSS_PROP_COLUMN_RULE_WIDTH: assert(BORDER_WIDTH_SET == (enum op_border_width)OUTLINE_WIDTH_SET); assert(BORDER_WIDTH_SET == (enum op_border_width)COLUMN_RULE_WIDTH_SET); if (value == BORDER_WIDTH_SET) offset += 2; /* length + units */ break; case CSS_PROP_MARGIN_TOP: case CSS_PROP_MARGIN_RIGHT: case CSS_PROP_MARGIN_BOTTOM: case CSS_PROP_MARGIN_LEFT: case CSS_PROP_BOTTOM: case CSS_PROP_LEFT: case CSS_PROP_RIGHT: case CSS_PROP_TOP: case CSS_PROP_HEIGHT: case CSS_PROP_WIDTH: case CSS_PROP_COLUMN_WIDTH: case CSS_PROP_COLUMN_GAP: assert(BOTTOM_SET == (enum op_bottom)LEFT_SET); assert(BOTTOM_SET == (enum op_bottom)RIGHT_SET); assert(BOTTOM_SET == (enum op_bottom)TOP_SET); assert(BOTTOM_SET == (enum op_bottom)HEIGHT_SET); assert(BOTTOM_SET == (enum op_bottom)MARGIN_SET); assert(BOTTOM_SET == (enum op_bottom)WIDTH_SET); assert(BOTTOM_SET == (enum op_bottom)COLUMN_WIDTH_SET); assert(BOTTOM_SET == (enum op_bottom)COLUMN_GAP_SET); if (value == BOTTOM_SET) offset += 2; /* length + units */ break; case CSS_PROP_CLIP: if ((value & CLIP_SHAPE_MASK) == CLIP_SHAPE_RECT) { if ((value & CLIP_RECT_TOP_AUTO) == 0) offset += 2; /* length + units */ if ((value & CLIP_RECT_RIGHT_AUTO) == 0) offset += 2; /* length + units */ if ((value & CLIP_RECT_BOTTOM_AUTO) == 0) offset += 2; /* length + units */ if ((value & CLIP_RECT_LEFT_AUTO) == 0) offset += 2; /* length + units */ } break; case CSS_PROP_COLOR: if (value == COLOR_SET) offset++; /* colour */ break; case CSS_PROP_COLUMN_COUNT: if (value == COLUMN_COUNT_SET) offset++; /* colour */ break; case CSS_PROP_CONTENT: while (value != CONTENT_NORMAL && value != CONTENT_NONE) { switch (value & 0xff) { case CONTENT_COUNTER: case CONTENT_URI: case CONTENT_ATTR: case CONTENT_STRING: offset++; /* string table entry */ break; case CONTENT_COUNTERS: offset+=2; /* two string entries */ break; case CONTENT_OPEN_QUOTE: case CONTENT_CLOSE_QUOTE: case CONTENT_NO_OPEN_QUOTE: case CONTENT_NO_CLOSE_QUOTE: break; } value = bytecode[offset]; offset++; } break; case CSS_PROP_COUNTER_INCREMENT: case CSS_PROP_COUNTER_RESET: assert(COUNTER_INCREMENT_NONE == (enum op_counter_increment)COUNTER_RESET_NONE); while (value != COUNTER_INCREMENT_NONE) { offset+=2; /* string + integer */ value = bytecode[offset]; offset++; } break; case CSS_PROP_CURSOR: while (value == CURSOR_URI) { offset++; /* string table entry */ value = bytecode[offset]; offset++; } break; case CSS_PROP_ELEVATION: if (value == ELEVATION_ANGLE) offset += 2; /* length + units */ break; case CSS_PROP_FONT_FAMILY: while (value != FONT_FAMILY_END) { switch (value) { case FONT_FAMILY_STRING: case FONT_FAMILY_IDENT_LIST: offset++; /* string table entry */ break; } value = bytecode[offset]; offset++; } break; case CSS_PROP_FONT_SIZE: if (value == FONT_SIZE_DIMENSION) offset += 2; /* length + units */ break; case CSS_PROP_LETTER_SPACING: case CSS_PROP_WORD_SPACING: assert(LETTER_SPACING_SET == (enum op_letter_spacing)WORD_SPACING_SET); if (value == LETTER_SPACING_SET) offset += 2; /* length + units */ break; case CSS_PROP_LINE_HEIGHT: switch (value) { case LINE_HEIGHT_NUMBER: offset++; /* value */ break; case LINE_HEIGHT_DIMENSION: offset += 2; /* length + units */ break; } break; case CSS_PROP_MAX_HEIGHT: case CSS_PROP_MAX_WIDTH: assert(MAX_HEIGHT_SET == (enum op_max_height)MAX_WIDTH_SET); if (value == MAX_HEIGHT_SET) offset += 2; /* length + units */ break; case CSS_PROP_PADDING_TOP: case CSS_PROP_PADDING_RIGHT: case CSS_PROP_PADDING_BOTTOM: case CSS_PROP_PADDING_LEFT: case CSS_PROP_MIN_HEIGHT: case CSS_PROP_MIN_WIDTH: case CSS_PROP_PAUSE_AFTER: case CSS_PROP_PAUSE_BEFORE: case CSS_PROP_TEXT_INDENT: assert(MIN_HEIGHT_SET == (enum op_min_height)MIN_WIDTH_SET); assert(MIN_HEIGHT_SET == (enum op_min_height)PADDING_SET); assert(MIN_HEIGHT_SET == (enum op_min_height)PAUSE_AFTER_SET); assert(MIN_HEIGHT_SET == (enum op_min_height)PAUSE_BEFORE_SET); assert(MIN_HEIGHT_SET == (enum op_min_height)TEXT_INDENT_SET); if (value == MIN_HEIGHT_SET) offset += 2; /* length + units */ break; case CSS_PROP_OPACITY: if (value == OPACITY_SET) offset++; /* value */ break; case CSS_PROP_ORPHANS: case CSS_PROP_PITCH_RANGE: case CSS_PROP_RICHNESS: case CSS_PROP_STRESS: case CSS_PROP_WIDOWS: case CSS_PROP_FLEX_GROW: case CSS_PROP_FLEX_SHRINK: case CSS_PROP_FLEX_BASIS: assert(ORPHANS_SET == (enum op_orphans)PITCH_RANGE_SET); assert(ORPHANS_SET == (enum op_orphans)RICHNESS_SET); assert(ORPHANS_SET == (enum op_orphans)STRESS_SET); assert(ORPHANS_SET == (enum op_orphans)WIDOWS_SET); assert(ORPHANS_SET == (enum op_orphans)FLEX_GROW_SET); assert(ORPHANS_SET == (enum op_orphans)FLEX_SHRINK_SET); assert(ORPHANS_SET == (enum op_orphans)FLEX_BASIS_SET); if (value == ORPHANS_SET) offset++; /* value */ break; case CSS_PROP_OUTLINE_COLOR: if (value == OUTLINE_COLOR_SET) offset++; /* color */ break; case CSS_PROP_PITCH: if (value == PITCH_FREQUENCY) offset += 2; /* length + units */ break; case CSS_PROP_PLAY_DURING: if (value & PLAY_DURING_URI) offset++; /* string table entry */ break; case CSS_PROP_QUOTES: while (value != QUOTES_NONE) { offset += 2; /* two string table entries */ value = bytecode[offset]; offset++; } break; case CSS_PROP_SPEECH_RATE: if (value == SPEECH_RATE_SET) offset++; /* rate */ break; case CSS_PROP_VERTICAL_ALIGN: if (value == VERTICAL_ALIGN_SET) offset += 2; /* length + units */ break; case CSS_PROP_VOICE_FAMILY: while (value != VOICE_FAMILY_END) { switch (value) { case VOICE_FAMILY_STRING: case VOICE_FAMILY_IDENT_LIST: offset++; /* string table entry */ break; } value = bytecode[offset]; offset++; } break; case CSS_PROP_VOLUME: switch (value) { case VOLUME_NUMBER: offset++; /* value */ break; case VOLUME_DIMENSION: offset += 2; /* value + units */ break; } break; case CSS_PROP_Z_INDEX: if (value == Z_INDEX_SET) offset++; /* z index */ break; default: break; } } } }
/** * Parse z-index * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \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 parse_z_index(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) { int orig_ctx = *ctx; css_error error; const css_token *token; uint8_t flags = 0; uint16_t value = 0; uint32_t opv; css_fixed num = 0; uint32_t required_size; bool match; /* <integer> | IDENT (auto, inherit) */ 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_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[INHERIT], &match) == lwc_error_ok && match)) { flags |= FLAG_INHERIT; } else if (token->type == CSS_TOKEN_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[AUTO], &match) == lwc_error_ok && match)) { value = Z_INDEX_AUTO; } else if (token->type == CSS_TOKEN_NUMBER) { size_t consumed = 0; num = 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; } value = Z_INDEX_SET; } else { *ctx = orig_ctx; return CSS_INVALID; } opv = buildOPV(CSS_PROP_Z_INDEX, flags, value); required_size = sizeof(opv); if ((flags & FLAG_INHERIT) == false && value == Z_INDEX_SET) required_size += sizeof(num); /* Allocate result */ error = css_stylesheet_style_create(c->sheet, required_size, result); if (error != CSS_OK) { *ctx = orig_ctx; return error; } /* Copy the bytecode to it */ memcpy((*result)->bytecode, &opv, sizeof(opv)); if ((flags & FLAG_INHERIT) == false && value == Z_INDEX_SET) { memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv), &num, sizeof(num)); } return CSS_OK; }
/** * Parse clip * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \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 parse_clip(css_language *c, const parserutils_vector *vector, int *ctx, css_style **result) { int orig_ctx = *ctx; css_error error; const css_token *token; uint8_t flags = 0; uint16_t value = 0; uint32_t opv; int num_lengths = 0; css_fixed length[4] = { 0 }; uint32_t unit[4] = { 0 }; uint32_t required_size; bool match; /* FUNCTION(rect) [ [ IDENT(auto) | length ] CHAR(,)? ]{3} * [ IDENT(auto) | length ] CHAR{)} | * IDENT(auto, inherit) */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL) { *ctx = orig_ctx; return CSS_INVALID; } if (token->type == CSS_TOKEN_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[INHERIT], &match) == lwc_error_ok && match)) { flags = FLAG_INHERIT; } else if (token->type == CSS_TOKEN_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[AUTO], &match) == lwc_error_ok && match)) { value = CLIP_AUTO; } else if (token->type == CSS_TOKEN_FUNCTION && (lwc_string_caseless_isequal( token->idata, c->strings[RECT], &match) == lwc_error_ok && match)) { int i; value = CLIP_SHAPE_RECT; for (i = 0; i < 4; i++) { consumeWhitespace(vector, ctx); token = parserutils_vector_peek(vector, *ctx); if (token == NULL) { *ctx = orig_ctx; return CSS_INVALID; } if (token->type == CSS_TOKEN_IDENT) { /* Slightly magical way of generating the auto * values. These are bits 3-6 of the value. */ if ((lwc_string_caseless_isequal( token->idata, c->strings[AUTO], &match) == lwc_error_ok && match)) value |= 1 << (i + 3); else { *ctx = orig_ctx; return CSS_INVALID; } parserutils_vector_iterate(vector, ctx); } else { error = parse_unit_specifier(c, vector, ctx, UNIT_PX, &length[num_lengths], &unit[num_lengths]); if (error != CSS_OK) { *ctx = orig_ctx; return error; } if (unit[num_lengths] & UNIT_ANGLE || unit[num_lengths] & UNIT_TIME || unit[num_lengths] & UNIT_FREQ || unit[num_lengths] & UNIT_PCT) { *ctx = orig_ctx; return CSS_INVALID; } num_lengths++; } consumeWhitespace(vector, ctx); /* Consume optional comma after first 3 parameters */ if (i < 3) { token = parserutils_vector_peek(vector, *ctx); if (token == NULL) { *ctx = orig_ctx; return CSS_INVALID; } if (tokenIsChar(token, ',')) parserutils_vector_iterate(vector, ctx); } } consumeWhitespace(vector, ctx); /* Finally, consume closing parenthesis */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL || tokenIsChar(token, ')') == false) { *ctx = orig_ctx; return CSS_INVALID; } } else { *ctx = orig_ctx; return CSS_INVALID; } opv = buildOPV(CSS_PROP_CLIP, flags, value); required_size = sizeof(opv); if ((flags & FLAG_INHERIT) == false && (value & CLIP_SHAPE_MASK) == CLIP_SHAPE_RECT) { required_size += num_lengths * (sizeof(length[0]) + sizeof(unit[0])); } /* Allocate result */ error = css_stylesheet_style_create(c->sheet, required_size, result); if (error != CSS_OK) { *ctx = orig_ctx; return error; } /* Copy the bytecode to it */ memcpy((*result)->bytecode, &opv, sizeof(opv)); if ((flags & FLAG_INHERIT) == false && (value & CLIP_SHAPE_MASK) == CLIP_SHAPE_RECT) { int i; uint8_t *ptr = ((uint8_t *) (*result)->bytecode) + sizeof(opv); for (i = 0; i < num_lengths; i++) { memcpy(ptr, &length[i], sizeof(length[i])); ptr += sizeof(length[i]); memcpy(ptr, &unit[i], sizeof(unit[i])); ptr += sizeof(unit[i]); } } return CSS_OK; }