summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucas Neves <lcneves@gmail.com>2017-08-30 05:55:33 (GMT)
committer Lucas Neves <lcneves@gmail.com>2017-09-26 02:00:25 (GMT)
commit9ce51bc289a5c02b11b9bb7f3d45c1233058bc36 (patch)
treeaa77b8e91c2446b38ca890fec5e304aaf49df381
parent369e6532cbc6e0332eecb97c3106fee7a29ae100 (diff)
downloadlibcss-9ce51bc289a5c02b11b9bb7f3d45c1233058bc36.tar.gz
libcss-9ce51bc289a5c02b11b9bb7f3d45c1233058bc36.tar.bz2
Parse: Implementing shorthands flex and flex-flow
-rw-r--r--src/parse/properties/flex.c313
-rw-r--r--src/parse/properties/flex_flow.c265
-rw-r--r--src/select/computed.c24
3 files changed, 594 insertions, 8 deletions
diff --git a/src/parse/properties/flex.c b/src/parse/properties/flex.c
new file mode 100644
index 0000000..54c4560
--- a/dev/null
+++ b/src/parse/properties/flex.c
@@ -0,0 +1,313 @@
+/*
+ * This file is part of LibCSS.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2017 Lucas Neves <lcneves@gmail.com>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "bytecode/bytecode.h"
+#include "bytecode/opcodes.h"
+#include "parse/properties/properties.h"
+#include "parse/properties/utils.h"
+
+/**
+ * Parse list-style
+ *
+ * \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 css__parse_flex_basis(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ css_fixed *basis_length, css_fixed *basis_unit,
+ opcode_t *basis_op)
+{
+ css_error error;
+ error = css__parse_unit_specifier(c, vector, ctx,
+ UNIT_PX, basis_length, basis_unit);
+
+ if (error == CSS_OK) {
+ if (*basis_unit & UNIT_ANGLE ||
+ *basis_unit & UNIT_TIME ||
+ *basis_unit & UNIT_FREQ) {
+ return CSS_INVALID;
+ }
+ *basis_op = FLEX_BASIS_SET;
+ }
+
+ return error;
+}
+
+css_error css__parse_flex_grow(const css_token *token, css_fixed *number)
+{
+ if (token->type != CSS_TOKEN_NUMBER)
+ return CSS_INVALID;
+
+ size_t consumed = 0;
+ css_fixed num = css__number_from_lwc_string(
+ token->idata, false, &consumed);
+
+ /* Invalid if there are trailing characters */
+ if (consumed != lwc_string_length(token->idata))
+ return CSS_INVALID;
+
+ /* Invalid if number is negative */
+ if (num < 0)
+ return CSS_INVALID;
+
+ *number = num;
+ return CSS_OK;
+}
+
+css_error css__parse_flex(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ css_style *result)
+{
+ int orig_ctx = *ctx;
+ const css_token *token;
+ css_error error;
+
+ /* 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_FLEX_GROW);
+ if (error != CSS_OK)
+ return error;
+
+ error = css_stylesheet_style_inherit(result,
+ CSS_PROP_FLEX_SHRINK);
+ if (error != CSS_OK)
+ return error;
+
+
+ error = css_stylesheet_style_inherit(result,
+ CSS_PROP_FLEX_BASIS);
+
+ if (error == CSS_OK)
+ parserutils_vector_iterate(vector, ctx);
+
+ return error;
+ }
+
+ /* Default values */
+ opcode_t grow_op = FLEX_GROW_SET;
+ css_fixed grow_number = 0;
+ opcode_t shrink_op = FLEX_SHRINK_SET;
+ css_fixed shrink_number = INTTOFIX(1);
+ opcode_t basis_op = FLEX_BASIS_AUTO;
+ css_fixed basis_length = 0;
+ uint32_t basis_unit = UNIT_PX;
+
+ /* Attempt to parse the various longhand properties */
+ *ctx = orig_ctx;
+ size_t length;
+ parserutils_vector_get_length(vector, &length);
+
+ switch (length) {
+ case 1:
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token == NULL || token->type != CSS_TOKEN_IDENT) {
+ *ctx = orig_ctx;
+ return CSS_INVALID;
+ }
+
+ /*
+ * Handle auto and none
+ * auto = flex: 1 1 auto;
+ * none = flex: 0 0 auto;
+ */
+ bool match;
+ if ((lwc_string_caseless_isequal(
+ token->idata, c->strings[AUTO],
+ &match) == lwc_error_ok && match) ||
+ (lwc_string_caseless_isequal(
+ token->idata, c->strings[NONE],
+ &match) == lwc_error_ok && match)) {
+ if ((lwc_string_caseless_isequal(
+ token->idata, c->strings[AUTO],
+ &match) == lwc_error_ok && match)) {
+ grow_number = INTTOFIX(1);
+ }
+ else {
+ shrink_number = 0;
+ }
+
+ }
+
+ /* Token must be either flex-basis or flex-grow */
+ else {
+ *ctx = orig_ctx;
+ error = css__parse_flex_basis(c, vector, ctx,
+ &basis_length, &basis_unit,
+ &basis_op);
+
+ if (error != CSS_OK) {
+ /* Positive number: equivalent of
+ * flex: <positive number> 1 0; */
+ *ctx = orig_ctx;
+ token = parserutils_vector_iterate(vector, ctx);
+ error = css__parse_flex_grow(
+ token, &grow_number);
+ if (error != CSS_OK) {
+ *ctx = orig_ctx;
+ return CSS_INVALID;
+ }
+ basis_op = FLEX_BASIS_SET;
+ }
+ }
+ break;
+
+ case 2:
+ /* First value must be flex-grow */
+ token = parserutils_vector_iterate(vector, ctx);
+ error = css__parse_flex_grow(
+ token, &grow_number);
+ if (error != CSS_OK) {
+ *ctx = orig_ctx;
+ return CSS_INVALID;
+ }
+
+ /* Second value must be either flex-basis or flex-shrink */
+ int prev_ctx = *ctx;
+ error = css__parse_flex_basis(c, vector, ctx,
+ &basis_length, &basis_unit, &basis_op);
+
+ if (error != CSS_OK) {
+ /* Two positive numbers: equivalent of
+ * flex: <number_1> <number_2> 0; */
+ *ctx = prev_ctx;
+ token = parserutils_vector_iterate(vector, ctx);
+ error = css__parse_flex_grow(
+ token, &shrink_number);
+ if (error != CSS_OK) {
+ *ctx = orig_ctx;
+ return CSS_INVALID;
+ }
+ basis_op = FLEX_BASIS_SET;
+ }
+ break;
+
+ case 3:
+ /* First value must be flex-grow */
+ token = parserutils_vector_iterate(vector, ctx);
+ error = css__parse_flex_grow(
+ token, &grow_number);
+ if (error != CSS_OK) {
+ *ctx = orig_ctx;
+ return CSS_INVALID;
+ }
+
+ /* Second value must be flex-shrink */
+ token = parserutils_vector_iterate(vector, ctx);
+ error = css__parse_flex_grow(
+ token, &shrink_number);
+ if (error != CSS_OK) {
+ *ctx = orig_ctx;
+ return CSS_INVALID;
+ }
+
+ /* Third value must be flex-basis */
+ error = css__parse_flex_basis(c, vector, ctx,
+ &basis_length, &basis_unit, &basis_op);
+ if (error != CSS_OK) {
+ *ctx = orig_ctx;
+ return CSS_INVALID;
+ }
+ break;
+
+ default:
+ return CSS_INVALID;
+ }
+
+ /* allocate styles */
+ css_style *grow_style;
+ css_style *shrink_style;
+ css_style *basis_style;
+
+ error = css__stylesheet_style_create(c->sheet, &grow_style);
+ if (error != CSS_OK)
+ return error;
+
+ error = css__stylesheet_style_create(c->sheet, &shrink_style);
+ if (error != CSS_OK) {
+ css__stylesheet_style_destroy(grow_style);
+ return error;
+ }
+
+ error = css__stylesheet_style_create(c->sheet, &basis_style);
+ if (error != CSS_OK) {
+ css__stylesheet_style_destroy(shrink_style);
+ css__stylesheet_style_destroy(grow_style);
+ return error;
+ }
+
+ error = css__stylesheet_style_appendOPV(grow_style,
+ CSS_PROP_FLEX_GROW, 0, grow_op);
+ if (error != CSS_OK)
+ goto css__parse_flex_flow_cleanup;
+
+ error = css__stylesheet_style_append(grow_style, grow_number);
+ if (error != CSS_OK)
+ goto css__parse_flex_flow_cleanup;
+
+ error = css__stylesheet_style_appendOPV(shrink_style,
+ CSS_PROP_FLEX_SHRINK, 0, shrink_op);
+ if (error != CSS_OK)
+ goto css__parse_flex_flow_cleanup;
+
+ error = css__stylesheet_style_append(shrink_style, shrink_number);
+ if (error != CSS_OK)
+ goto css__parse_flex_flow_cleanup;
+
+ error = css__stylesheet_style_appendOPV(basis_style,
+ CSS_PROP_FLEX_BASIS, 0, basis_op);
+ if (error != CSS_OK)
+ goto css__parse_flex_flow_cleanup;
+
+ if (basis_op == FLEX_BASIS_SET) {
+ error = css__stylesheet_style_append(basis_style, basis_length);
+ if (error != CSS_OK)
+ goto css__parse_flex_flow_cleanup;
+
+ error = css__stylesheet_style_append(basis_style, basis_unit);
+ if (error != CSS_OK)
+ goto css__parse_flex_flow_cleanup;
+ }
+
+ error = css__stylesheet_merge_style(result, grow_style);
+ if (error != CSS_OK)
+ goto css__parse_flex_flow_cleanup;
+
+ error = css__stylesheet_merge_style(result, shrink_style);
+ if (error != CSS_OK)
+ goto css__parse_flex_flow_cleanup;
+
+ error = css__stylesheet_merge_style(result, basis_style);
+
+css__parse_flex_flow_cleanup:
+
+ css__stylesheet_style_destroy(basis_style);
+ css__stylesheet_style_destroy(shrink_style);
+ css__stylesheet_style_destroy(grow_style);
+
+ if (error != CSS_OK)
+ *ctx = orig_ctx;
+
+ return error;
+}
+
diff --git a/src/parse/properties/flex_flow.c b/src/parse/properties/flex_flow.c
new file mode 100644
index 0000000..843b186
--- a/dev/null
+++ b/src/parse/properties/flex_flow.c
@@ -0,0 +1,265 @@
+/*
+ * This file is part of LibCSS.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2017 Lucas Neves <lcneves@gmail.com>
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "bytecode/bytecode.h"
+#include "bytecode/opcodes.h"
+#include "parse/properties/properties.h"
+#include "parse/properties/utils.h"
+
+/**
+ * Parse list-style
+ *
+ * \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 css__parse_flex_flow_direction_value(
+ css_language *c, const css_token *ident, uint16_t *value)
+{
+ bool match;
+
+ /* IDENT (row, column, row-reverse, column-reverse) */
+ if ((lwc_string_caseless_isequal(
+ ident->idata, c->strings[ROW],
+ &match) == lwc_error_ok && match)) {
+ *value = FLEX_DIRECTION_ROW;
+ } else if ((lwc_string_caseless_isequal(
+ ident->idata, c->strings[COLUMN],
+ &match) == lwc_error_ok && match)) {
+ *value = FLEX_DIRECTION_COLUMN;
+ } else if ((lwc_string_caseless_isequal(
+ ident->idata, c->strings[ROW_REVERSE],
+ &match) == lwc_error_ok && match)) {
+ *value = FLEX_DIRECTION_ROW_REVERSE;
+ } else if ((lwc_string_caseless_isequal(
+ ident->idata, c->strings[COLUMN_REVERSE],
+ &match) == lwc_error_ok && match)) {
+ *value = FLEX_DIRECTION_COLUMN_REVERSE;
+ } else
+ return CSS_INVALID;
+
+ return CSS_OK;
+}
+
+css_error css__parse_flex_flow_wrap_value(
+ css_language *c, const css_token *ident, uint16_t *value)
+{
+ bool match;
+
+ /* IDENT (nowrap, wrap, wrap-reverse) */
+ if ((lwc_string_caseless_isequal(
+ ident->idata, c->strings[NOWRAP],
+ &match) == lwc_error_ok && match)) {
+ *value = FLEX_WRAP_NOWRAP;
+ } else if ((lwc_string_caseless_isequal(
+ ident->idata, c->strings[WRAP],
+ &match) == lwc_error_ok && match)) {
+ *value = FLEX_WRAP_WRAP;
+ } else if ((lwc_string_caseless_isequal(
+ ident->idata, c->strings[WRAP_REVERSE],
+ &match) == lwc_error_ok && match)) {
+ *value = FLEX_DIRECTION_WRAP_REVERSE;
+ } else
+ return CSS_INVALID;
+
+ return CSS_OK;
+}
+
+css_error css__parse_flex_flow_direction(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;
+ bool match;
+
+ 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->[INHERIT],
+ &match) == lwc_error_ok && match)) {
+ flags |= FLAG_INHERIT
+ } else {
+ error = css__parse_flex_flow_direction_value(c, ident, &value);
+ if (error != CSS_OK) {
+ *ctx = orig_ctx;
+ return error;
+ }
+ }
+
+ error = css__stylesheet_style_appendOPV(result, CSS_PROP_FLEX_DIRECTION,
+ flags, value);
+
+ if (error != CSS_OK)
+ *ctx = orig_ctx;
+
+ return error;
+}
+
+css_error css__parse_flex_flow_wrap(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;
+ bool match;
+
+ 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->[INHERIT],
+ &match) == lwc_error_ok && match)) {
+ flags |= FLAG_INHERIT
+ } else {
+ error = css__parse_flex_flow_wrap_value(c, ident, &value);
+ if (error != CSS_OK) {
+ *ctx = orig_ctx;
+ return error;
+ }
+ }
+
+ error = css__stylesheet_style_appendOPV(result, CSS_PROP_FLEX_WRAP,
+ flags, value);
+
+ if (error != CSS_OK)
+ *ctx = orig_ctx;
+
+ return error;
+}
+
+css_error css__parse_flex_flow(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ css_style *result)
+{
+ int orig_ctx = *ctx;
+ int prev_ctx;
+ const css_token *token;
+ css_error error;
+ bool direction = true;
+ bool wrap = true;
+ css_style *direction_style;
+ css_style *wrap_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_FLEX_DIRECTION);
+ if (error != CSS_OK)
+ return error;
+
+ error = css_stylesheet_style_inherit(result,
+ CSS_PROP_FLEX_WRAP);
+
+ if (error == CSS_OK)
+ parserutils_vector_iterate(vector, ctx);
+
+ return error;
+ }
+
+ /* allocate styles */
+ error = css__stylesheet_style_create(c->sheet, &direction_style);
+ if (error != CSS_OK)
+ return error;
+
+ error = css__stylesheet_style_create(c->sheet, &wrap_style);
+ if (error != CSS_OK) {
+ css__stylesheet_style_destroy(direction_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_flex_flow_cleanup;
+ }
+
+ if ((wrap) &&
+ (error = css__parse_flex_flow_wrap(c, vector,
+ ctx, wrap_style)) == CSS_OK) {
+ wrap = false;
+ } else if ((direction) &&
+ (error = css__parse_flex_flow_direction(c, vector,
+ ctx, direction_style)) == CSS_OK) {
+ direction = 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);
+
+
+ /* defaults */
+ if (direction) {
+ error = css__stylesheet_style_appendOPV(direction_style,
+ CSS_PROP_FLEX_DIRECTION,
+ 0, FLEX_DIRECTION_ROW);
+ }
+
+ if (wrap) {
+ error = css__stylesheet_style_appendOPV(wrap_style,
+ CSS_PROP_FLEX_WRAP,
+ 0, FLEX_WRAP_NOWRAP);
+ }
+
+ error = css__stylesheet_merge_style(result, direction_style);
+ if (error != CSS_OK)
+ goto css__parse_flex_flow_cleanup;
+
+ error = css__stylesheet_merge_style(result, wrap_style);
+
+css__parse_flex_flow_cleanup:
+
+ css__stylesheet_style_destroy(wrap_style);
+ css__stylesheet_style_destroy(direction_style);
+
+ if (error != CSS_OK)
+ *ctx = orig_ctx;
+
+ return error;
+}
+
diff --git a/src/select/computed.c b/src/select/computed.c
index ede52a1..131735b 100644
--- a/src/select/computed.c
+++ b/src/select/computed.c
@@ -749,23 +749,31 @@ uint8_t css_computed_font_style(const css_computed_style *style)
uint8_t css_computed_min_height(const css_computed_style *style,
css_fixed *length, css_unit *unit)
{
- return get_min_height(style, length, unit);
+ uint8_t min_height = get_min_height(style, length, unit);
+ uint8_t display = get_display(style);
+
+ if (display != CSS_DISPLAY_FLEX && display != CSS_DISPLAY_INLINE_FLEX &&
+ min_height == CSS_MIN_HEIGHT_AUTO)
+ {
+ min_height = CSS_MIN_HEIGHT_SET;
+ }
+
+ return min_height;
}
uint8_t css_computed_min_width(const css_computed_style *style,
css_fixed *length, css_unit *unit)
{
- css_fixed *a_length;
- css_fixed *a_unit;
- uint8_t min_width = get_min_width(style, a_length, a_unit);
+ uint8_t min_width = get_min_width(style, length, unit);
uint8_t display = get_display(style);
-
if (display != CSS_DISPLAY_FLEX && display != CSS_DISPLAY_INLINE_FLEX &&
min_width == CSS_MIN_WIDTH_AUTO)
- /* TODO: Continue here. return CSS_MIN_WIDTH_AUTO; */
- else
- return get_min_width(style, length, unit);
+ {
+ min_width = CSS_MIN_WIDTH_SET;
+ }
+
+ return min_width;
}
uint8_t css_computed_background_repeat(const css_computed_style *style)