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 --- src/utils/fpmath.h | 45 +++++++++++++++++++++++++++++++++++++ src/utils/utils.h | 66 ++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 src/utils/fpmath.h (limited to 'src/utils') 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