From 5ca8e29dcfc73b13a3c4c32e58619d9c486df57b Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sat, 12 Mar 2011 17:46:11 +0000 Subject: Saturated maths in css fixed point svn path=/trunk/libcss/; revision=11975 --- include/libcss/fpmath.h | 122 +++++++++++++++++++++++++++++++++------ src/parse/properties/azimuth.c | 6 +- src/parse/properties/elevation.c | 6 +- src/parse/properties/utils.c | 30 +++++----- 4 files changed, 126 insertions(+), 38 deletions(-) diff --git a/include/libcss/fpmath.h b/include/libcss/fpmath.h index 3867f3a..36e0ab5 100644 --- a/include/libcss/fpmath.h +++ b/include/libcss/fpmath.h @@ -14,37 +14,120 @@ extern "C" #endif #include +#include /* 22:10 fixed point math */ +#define CSS_RADIX_POINT 10 + +/* type for fixed point numbers */ typedef int32_t css_fixed; +static inline css_fixed +css_add_fixed(const css_fixed x, const css_fixed y) { + int32_t ux = x; + int32_t uy = y; + int32_t res = ux + uy; + + /* Calculate overflowed result. (Don't change the sign bit of ux) */ + ux = (ux >> 31) + INT_MAX; + + /* Force compiler to use cmovns instruction */ + if ((int32_t) ((ux ^ uy) | ~(uy ^ res)) >= 0) { + res = ux; + } + + return res; +} + +static inline css_fixed +css_subtract_fixed(const css_fixed x, const css_fixed y) { + int32_t ux = x; + int32_t uy = y; + int32_t res = ux - uy; + + ux = (ux >> 31) + INT_MAX; + + /* Force compiler to use cmovns instruction */ + if ((int32_t)((ux ^ uy) & (ux ^ res)) < 0) { + res = ux; + } + + return res; +} + +static inline css_fixed +css_divide_fixed(const css_fixed x, const css_fixed y) { + int64_t xx = ((int64_t)x << CSS_RADIX_POINT) / y; + + if (xx < INT_MIN) + xx = INT_MIN; + + if (xx > INT_MAX) + xx = INT_MAX; + + return xx; +} + +static inline css_fixed +css_multiply_fixed(const css_fixed x, const css_fixed y) { + int64_t xx = ((int64_t)x * (int64_t)y) >> CSS_RADIX_POINT; + + if (xx < INT_MIN) + xx = INT_MIN; + + if (xx > INT_MAX) + xx = INT_MAX; + + return xx; +} + +static inline css_fixed +css_int_to_fixed(const int a) { + int64_t xx = ((int64_t) a) << CSS_RADIX_POINT; + + if (xx < INT_MIN) + xx = INT_MIN; + + if (xx > INT_MAX) + xx = INT_MAX; + + return xx; +} + +static inline css_fixed +css_float_to_fixed(const float a) { + float xx = a * (float) (1 << CSS_RADIX_POINT); + + if (xx < INT_MIN) + xx = INT_MIN; + + if (xx > INT_MAX) + xx = INT_MAX; + + return xx; +} + /* Add two fixed point values */ -#define FADD(a, b) ((a) + (b)) +#define FADD(a, b) (css_add_fixed((a), (b))) /* Subtract two fixed point values */ -#define FSUB(a, b) ((a) - (b)) +#define FSUB(a, b) (css_subtract_fixed((a), (b))) /* Multiply two fixed point values */ -#define FMUL(a, b) ((((int64_t) (a)) * ((int64_t) (b))) >> 10) +#define FMUL(a, b) (css_multiply_fixed((a), (b))) /* Divide two fixed point values */ -#define FDIV(a, b) ((((int64_t) (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)) +#define FDIV(a, b) (css_divide_fixed((a), (b))) /* Convert a floating point value to fixed point */ -#define FLTTOFIX(a) ((css_fixed) ((a) * (float) (1 << 10))) +#define FLTTOFIX(a) ((css_fixed) ((a) * (float) (1 << CSS_RADIX_POINT))) /* Convert a fixed point value to floating point */ -#define FIXTOFLT(a) ((float) (a) / (float) (1 << 10)) +#define FIXTOFLT(a) ((float) (a) / (float) (1 << CSS_RADIX_POINT)) /* Convert an integer to a fixed point value */ -#define INTTOFIX(a) ((a) << 10) +#define INTTOFIX(a) (css_int_to_fixed(a)) /* Convert a fixed point value to an integer */ -#define FIXTOINT(a) ((a) >> 10) +#define FIXTOINT(a) ((a) >> CSS_RADIX_POINT) + +/* truncate a fixed point value */ +#define TRUNCATEFIX(a) (a & ~((1 << CSS_RADIX_POINT)- 1 )) /* Useful values */ #define F_PI_2 0x00000648 /* 1.5708 (PI/2) */ @@ -57,8 +140,13 @@ typedef int32_t css_fixed; #define F_270 0x00043800 /* 270 */ #define F_360 0x0005a000 /* 360 */ +#define F_0_5 0x00000200 /* 0.5 */ +#define F_1 0x00000400 /* 1 */ +#define F_10 0x00002800 /* 10 */ +#define F_72 0x00012000 /* 72 */ #define F_100 0x00019000 /* 100 */ #define F_200 0x00032000 /* 200 */ +#define F_255 0x0003FC00 /* 255 */ #define F_300 0x0004b000 /* 300 */ #define F_400 0x00064000 /* 400 */ diff --git a/src/parse/properties/azimuth.c b/src/parse/properties/azimuth.c index 76bc383..7df7298 100644 --- a/src/parse/properties/azimuth.c +++ b/src/parse/properties/azimuth.c @@ -198,17 +198,17 @@ css_error css__parse_azimuth(css_language *c, /* Valid angles lie between -360 and 360 degrees */ if (unit == UNIT_DEG) { - if (length < FMULI(F_360, -1) || length > F_360) { + if ((length < -F_360) || (length > F_360)) { *ctx = orig_ctx; return CSS_INVALID; } } else if (unit == UNIT_GRAD) { - if (length < FMULI(F_400, -1) || length > F_400) { + if ((length < -F_400) || (length > F_400)) { *ctx = orig_ctx; return CSS_INVALID; } } else if (unit == UNIT_RAD) { - if (length < FMULI(F_2PI, -1) || length > F_2PI) { + if ((length < -F_2PI) || (length > F_2PI)) { *ctx = orig_ctx; return CSS_INVALID; } diff --git a/src/parse/properties/elevation.c b/src/parse/properties/elevation.c index f3a48a4..0b5fdc4 100644 --- a/src/parse/properties/elevation.c +++ b/src/parse/properties/elevation.c @@ -98,17 +98,17 @@ css_error css__parse_elevation(css_language *c, /* Valid angles lie between -90 and 90 degrees */ if (unit == UNIT_DEG) { - if (length < FMULI(F_90, -1) || length > F_90) { + if (length < -F_90 || length > F_90) { *ctx = orig_ctx; return CSS_INVALID; } } else if (unit == UNIT_GRAD) { - if (length < FMULI(F_100, -1) || length > F_100) { + if (length < -F_100 || length > F_100) { *ctx = orig_ctx; return CSS_INVALID; } } else if (unit == UNIT_RAD) { - if (length < FMULI(F_PI_2, -1) || length > F_PI_2) { + if (length < -F_PI_2 || length > F_PI_2) { *ctx = orig_ctx; return CSS_INVALID; } diff --git a/src/parse/properties/utils.c b/src/parse/properties/utils.c index 934b3f6..bf7e212 100644 --- a/src/parse/properties/utils.c +++ b/src/parse/properties/utils.c @@ -266,9 +266,9 @@ static void HSL_to_RGB(css_fixed hue, css_fixed sat, css_fixed lit, uint8_t *r, int sextant; #define ORGB(R, G, B) \ - *r = FIXTOINT(FDIVI(FMULI((R), 255), 100)); \ - *g = FIXTOINT(FDIVI(FMULI((G), 255), 100)); \ - *b = FIXTOINT(FDIVI(FMULI((B), 255), 100)) + *r = FIXTOINT(FDIV(FMUL((R), F_255), F_100)); \ + *g = FIXTOINT(FDIV(FMUL((G), F_255), F_100)); \ + *b = FIXTOINT(FDIV(FMUL((B), F_255), F_100)) /* If saturation is zero there is no hue and r = g = b = lit */ if (sat == INTTOFIX(0)) { @@ -278,13 +278,13 @@ static void HSL_to_RGB(css_fixed hue, css_fixed sat, css_fixed lit, uint8_t *r, /* Compute max(r,g,b) */ if (lit <= INTTOFIX(50)) { - max_rgb = FDIVI(FMUL(lit, FADDI(sat, 100)), 100); + max_rgb = FDIV(FMUL(lit, FADD(sat, F_100)), F_100); } else { - max_rgb = FDIVI(FSUB(FMULI(FADD(lit, sat), 100), FMUL(lit, sat)), 100); + max_rgb = FDIV(FSUB(FMUL(FADD(lit, sat), F_100), FMUL(lit, sat)), F_100); } /* Compute min(r,g,b) */ - min_rgb = FSUB(FMULI(lit, 2), max_rgb); + min_rgb = FSUB(FMUL(lit, INTTOFIX(2)), max_rgb); /* We know that the value of at least one of the components is * max(r,g,b) and that the value of at least one of the other @@ -310,11 +310,11 @@ static void HSL_to_RGB(css_fixed hue, css_fixed sat, css_fixed lit, uint8_t *r, chroma = FSUB(max_rgb, min_rgb); /* Compute which sextant the hue lies in (truncates result) */ - hue = FDIVI(FMULI(hue, 6), 360); + hue = FDIV(FMUL(hue, INTTOFIX(6)), F_360); sextant = FIXTOINT(hue); /* Compute offset of hue from start of sextant */ - relative_hue = FSUBI(hue, sextant); + relative_hue = FSUB(hue, INTTOFIX(sextant)); /* Scale offset by chroma */ scaled_hue = FMUL(relative_hue, chroma); @@ -489,14 +489,14 @@ css_error css__parse_colour_specifier(css_language *c, if (i == 3) { /* alpha channel */ intval = FIXTOINT( - FMULI(num, 255)); + FMUL(num, F_255)); } else { /* colour channels */ intval = FIXTOINT(num); } } else { intval = FIXTOINT( - FDIVI(FMULI(num, 255), 100)); + FDIV(FMUL(num, F_255), F_100)); } if (intval > 255) @@ -544,10 +544,10 @@ css_error css__parse_colour_specifier(css_language *c, goto invalid; /* failed to consume the whole string as a number */ /* Normalise hue to the range [0, 360) */ - while (hue < INTTOFIX(0)) - hue += INTTOFIX(360); - while (hue >= INTTOFIX(360)) - hue -= INTTOFIX(360); + while (hue < 0) + hue += F_360; + while (hue >= F_360) + hue -= F_360; consumeWhitespace(vector, ctx); @@ -617,7 +617,7 @@ css_error css__parse_colour_specifier(css_language *c, if (consumed != lwc_string_length(token->idata)) goto invalid; /* failed to consume the whole string as a number */ - alpha = FIXTOINT(FMULI(alpha, 255)); + alpha = FIXTOINT(FMUL(alpha, F_255)); consumeWhitespace(vector, ctx); -- cgit v1.2.3