From a3b7632e61981a730a8883a13f36f19be75647f1 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Sun, 23 Nov 2008 09:58:48 +0000 Subject: All numerical values are represented in 22:10 fixed point. svn path=/trunk/libcss/; revision=5762 --- docs/Bytecode | 13 +++------- src/parse/css21props.c | 35 +++++++++++++------------- src/utils/fpmath.h | 45 ++++++++++++++++++++++++++++++++++ src/utils/utils.h | 66 ++++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 126 insertions(+), 33 deletions(-) create mode 100644 src/utils/fpmath.h diff --git a/docs/Bytecode b/docs/Bytecode index e7bb2fa..0b5ec74 100644 --- a/docs/Bytecode +++ b/docs/Bytecode @@ -23,21 +23,16 @@ Parameters are opcode-specific. Each parameter must begin on a 4 byte boundary. Datatype storage ---------------- -8 and 16 bit integers are stored as 32bit values. - -32 bit integers are stored in their natural format. - -Floats are stored in their natural format. - -Integers wider than 32 bits are not supported. -Doubles are not supported. +All numeric values are stored in a 32bit wide field. This field contains +a fixed point value with 22 bits assigned to the integer part and 10 bits +assigned to the fractional part. Strings are stored as pairs, as per css_string. Pointer's width is the native width of a pointer on the platform. Length's width is the native width of a size_t on the platform. CSS dimensions are stored as two 32bit values: . -Length is a 32bit integer and unit is as follows: +Length is a 32bit numeric value (as described above) and unit is as follows: bit 8 clear => length unit bits 9-31: MBZ diff --git a/src/parse/css21props.c b/src/parse/css21props.c index 082f063..1e8793e 100644 --- a/src/parse/css21props.c +++ b/src/parse/css21props.c @@ -317,7 +317,7 @@ static inline css_error parse_colour_specifier(css_css21 *c, uint32_t *result); static inline css_error parse_unit_specifier(css_css21 *c, const parserutils_vector *vector, int *ctx, - uint32_t *length, uint32_t *unit); + fixed *length, uint32_t *unit); static inline css_error parse_border_side_color(css_css21 *c, const parserutils_vector *vector, int *ctx, @@ -815,7 +815,7 @@ css_error parse_bottom(css_css21 *c, uint8_t flags = 0; uint16_t value = 0; uint32_t opv; - uint32_t length = 0; + fixed length = 0; uint32_t unit = 0; uint32_t required_size; @@ -1309,7 +1309,7 @@ css_error parse_elevation(css_css21 *c, uint8_t flags = 0; uint16_t value = 0; uint32_t opv; - uint32_t length = 0; + fixed length = 0; uint32_t unit = 0; uint32_t required_size; @@ -1487,7 +1487,7 @@ css_error parse_font_size(css_css21 *c, uint8_t flags = 0; uint16_t value = 0; uint32_t opv; - uint32_t length = 0; + fixed length = 0; uint32_t unit = 0; uint32_t required_size; @@ -1684,10 +1684,12 @@ css_error parse_font_weight(css_css21 *c, flags |= FLAG_INHERIT; } else if (token->type == CSS_TOKEN_NUMBER) { size_t consumed = 0; - int32_t num = integer_from_css_string(&token->lower, &consumed); - if (consumed != token->lower.len) + fixed num = number_from_css_string(&token->lower, &consumed); + int32_t intpart = FIXTOINT(num); + /* Invalid if there are trailing characters or it was a float */ + if (consumed != token->lower.len || num != intpart) return CSS_INVALID; - switch (num) { + switch (intpart) { case 100: value = FONT_WEIGHT_100; break; case 200: value = FONT_WEIGHT_200; break; case 300: value = FONT_WEIGHT_300; break; @@ -1732,7 +1734,7 @@ css_error parse_height(css_css21 *c, uint8_t flags = 0; uint16_t value = 0; uint32_t opv; - uint32_t length = 0; + fixed length = 0; uint32_t unit = 0; uint32_t required_size; @@ -1796,7 +1798,7 @@ css_error parse_left(css_css21 *c, uint8_t flags = 0; uint16_t value = 0; uint32_t opv; - uint32_t length = 0; + fixed length = 0; uint32_t unit = 0; uint32_t required_size; @@ -1860,7 +1862,7 @@ css_error parse_letter_spacing(css_css21 *c, uint8_t flags = 0; uint16_t value = 0; uint32_t opv; - uint32_t length = 0; + fixed length = 0; uint32_t unit = 0; uint32_t required_size; @@ -1925,7 +1927,7 @@ css_error parse_line_height(css_css21 *c, uint8_t flags = 0; uint16_t value = 0; uint32_t opv; - uint32_t length = 0; + fixed length = 0; uint32_t unit = 0; uint32_t required_size; @@ -1943,9 +1945,8 @@ css_error parse_line_height(css_css21 *c, parserutils_vector_iterate(vector, ctx); value = LINE_HEIGHT_NORMAL; } else if (token->type == CSS_TOKEN_NUMBER) { - /** \todo length should be a float */ size_t consumed = 0; - length = integer_from_css_string(&token->lower, &consumed); + length = number_from_css_string(&token->lower, &consumed); if (consumed != token->lower.len) return CSS_INVALID; @@ -2371,7 +2372,7 @@ css_error parse_right(css_css21 *c, uint8_t flags = 0; uint16_t value = 0; uint32_t opv; - uint32_t length = 0; + fixed length = 0; uint32_t unit = 0; uint32_t required_size; @@ -2567,7 +2568,7 @@ css_error parse_top(css_css21 *c, uint8_t flags = 0; uint16_t value = 0; uint32_t opv; - uint32_t length = 0; + fixed length = 0; uint32_t unit = 0; uint32_t required_size; @@ -2788,7 +2789,7 @@ css_error parse_colour_specifier(css_css21 *c, css_error parse_unit_specifier(css_css21 *c, const parserutils_vector *vector, int *ctx, - uint32_t *length, uint32_t *unit) + fixed *length, uint32_t *unit) { const css_token *token; @@ -2936,7 +2937,7 @@ css_error parse_border_side_width(css_css21 *c, uint8_t flags = 0; uint16_t value = 0; uint32_t opv; - uint32_t length = 0; + fixed length = 0; uint32_t unit = 0; uint32_t required_size; diff --git a/src/utils/fpmath.h b/src/utils/fpmath.h new file mode 100644 index 0000000..edf6471 --- /dev/null +++ b/src/utils/fpmath.h @@ -0,0 +1,45 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2008 John-Mark Bell + */ + +#ifndef css_utils_fpmath_h_ +#define css_utils_fpmath_h_ + +#include + +/* 22:10 fixed point math */ +typedef int32_t fixed; + +/* Add two fixed point values */ +#define FADD(a, b) ((a) + (b)) +/* Subtract two fixed point values */ +#define FSUB(a, b) ((a) - (b)) +/* Multiply two fixed point values */ +#define FMUL(a, b) (((a) * (b)) >> 10) +/* Divide two fixed point values */ +#define FDIV(a, b) (((a) << 10) / (b)) + +/* Add an integer to a fixed point value */ +#define FADDI(a, b) ((a) + ((b) << 10)) +/* Subtract an integer from a fixed point value */ +#define FSUBI(a, b) ((a) - ((b) << 10)) +/* Multiply a fixed point value by an integer */ +#define FMULI(a, b) ((a) * (b)) +/* Divide a fixed point value by an integer */ +#define FDIVI(a, b) ((a) / (b)) + +/* Convert a floating point value to fixed point */ +#define FLTTOFIX(a) ((fixed) ((a) * (float) (1 << 10))) +/* Convert a fixed point value to floating point */ +#define FIXTOFLT(a) ((float) (a) / (float) (1 << 10)) + +/* Convert an integer to a fixed point value */ +#define INTTOFIX(a) ((a) << 10) +/* Convert a fixed point value to an integer */ +#define FIXTOINT(a) ((a) >> 10) + +#endif + diff --git a/src/utils/utils.h b/src/utils/utils.h index b165059..eead21d 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -10,6 +10,8 @@ #include +#include "utils/fpmath.h" + #ifndef max #define max(a,b) ((a)>(b)?(a):(b)) #endif @@ -27,13 +29,15 @@ #define UNUSED(x) ((x)=(x)) #endif -static inline int32_t integer_from_css_string(const css_string *string, +static inline fixed number_from_css_string(const css_string *string, size_t *consumed) { size_t len; const uint8_t *ptr; int sign = 1; - int32_t val = 0; + int32_t intpart = 0; + int32_t fracpart = 0; + int32_t pwr = 1; if (string == NULL || string->len == 0 || consumed == NULL) return 0; @@ -41,6 +45,8 @@ static inline int32_t integer_from_css_string(const css_string *string, len = string->len; ptr = string->ptr; + /* number = [+-]? ([0-9]+ | [0-9]* '.' [0-9]+) */ + /* Extract sign, if any */ if (ptr[0] == '-') { sign = -1; @@ -51,23 +57,69 @@ static inline int32_t integer_from_css_string(const css_string *string, ptr++; } - /** \todo check for overflow */ + /* Ensure we have either a digit or a '.' followed by a digit */ + if (len == 0) { + *consumed = 0; + return 0; + } else { + if (ptr[0] == '.') { + if (len == 1 || ptr[1] < '0' || '9' < ptr[1]) { + *consumed = 0; + return 0; + } + } else if (ptr[0] < '0' || '9' < ptr[0]) { + *consumed = 0; + return 0; + } + } - /* Now extract value, assuming base 10 */ + /* Now extract intpart, assuming base 10 */ while (len > 0) { /* Stop on first non-digit */ if (ptr[0] < '0' || '9' < ptr[0]) break; - val *= 10; - val += ptr[0] - '0'; + /* Clamp to a max of 2^22 - 1 */ + if (intpart < (1 << 22)) { + intpart *= 10; + intpart += ptr[0] - '0'; + } ptr++; len--; } + /* And fracpart, again, assuming base 10 */ + if (len > 1 && ptr[0] == '.' && ('0' <= ptr[1] && ptr[1] <= '9')) { + ptr++; + len--; + + while (len > 0) { + if (ptr[0] < '0' || '9' < ptr[0]) + break; + + if (pwr < 1000000) { + pwr *= 10; + fracpart *= 10; + fracpart += ptr[0] - '0'; + } + ptr++; + len--; + } + fracpart = ((1 << 10) * fracpart + pwr/2) / pwr; + if (fracpart >= (1 << 10)) + fracpart = (1 << 10) - 1; + } + + /* If the intpart is larger than we can represent, + * then clamp to the maximum value we can store. */ + if (intpart >= (1 << 21)) { + intpart = (sign == -1) ? (1 << 21) : (1 << 21) - 1; + fracpart = (1 << 10) - 1; + } + *consumed = ptr - string->ptr; - return val * sign; + return FMULI((intpart << 10) | fracpart, sign); } #endif -- cgit v1.2.3