summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Mark Bell <jmb@netsurf-browser.org>2008-11-23 09:58:48 +0000
committerJohn Mark Bell <jmb@netsurf-browser.org>2008-11-23 09:58:48 +0000
commita3b7632e61981a730a8883a13f36f19be75647f1 (patch)
tree07ec4da268fb7e7f9aa2ddc20c5379e7f5982003
parent1f0c609def5cff6b7bc16ddeefafb1654b11cb71 (diff)
downloadlibcss-a3b7632e61981a730a8883a13f36f19be75647f1.tar.gz
libcss-a3b7632e61981a730a8883a13f36f19be75647f1.tar.bz2
All numerical values are represented in 22:10 fixed point.
svn path=/trunk/libcss/; revision=5762
-rw-r--r--docs/Bytecode13
-rw-r--r--src/parse/css21props.c35
-rw-r--r--src/utils/fpmath.h45
-rw-r--r--src/utils/utils.h66
4 files changed, 126 insertions, 33 deletions
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 <pointer,length> 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, units>.
-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 <jmb@netsurf-browser.org>
+ */
+
+#ifndef css_utils_fpmath_h_
+#define css_utils_fpmath_h_
+
+#include <stdint.h>
+
+/* 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 <libcss/types.h>
+#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