summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libcss/fpmath.h122
-rw-r--r--src/parse/properties/azimuth.c6
-rw-r--r--src/parse/properties/elevation.c6
-rw-r--r--src/parse/properties/utils.c30
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 <stdint.h>
+#include <limits.h>
/* 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);