summaryrefslogtreecommitdiffstats
path: root/skia/corecg/SkFloatBits.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'skia/corecg/SkFloatBits.cpp')
-rw-r--r--skia/corecg/SkFloatBits.cpp205
1 files changed, 205 insertions, 0 deletions
diff --git a/skia/corecg/SkFloatBits.cpp b/skia/corecg/SkFloatBits.cpp
new file mode 100644
index 0000000..1f15df2
--- /dev/null
+++ b/skia/corecg/SkFloatBits.cpp
@@ -0,0 +1,205 @@
+#include "SkFloatBits.h"
+#include "SkMath.h"
+
+/******************************************************************************
+ SkFloatBits_toInt[Floor, Round, Ceil] are identical except for what they
+ do right before they return ... >> exp;
+ Floor - adds nothing
+ Round - adds 1 << (exp - 1)
+ Ceil - adds (1 << exp) - 1
+
+ Floor and Cast are very similar, but Cast applies its sign after all other
+ computations on value. Also, Cast does not need to check for negative zero,
+ as that value (0x80000000) "does the right thing" for Ceil. Note that it
+ doesn't for Floor/Round/Ceil, hence the explicit check.
+******************************************************************************/
+
+#define EXP_BIAS (127+23)
+#define MATISSA_MAGIC_BIG (1 << 23)
+
+static inline int unpack_exp(uint32_t packed) {
+ return (packed << 1 >> 24);
+}
+
+#if 0
+// the ARM compiler generates an extra BIC, so I use the dirty version instead
+static inline int unpack_matissa(uint32_t packed) {
+ // we could mask with 0x7FFFFF, but that is harder for ARM to encode
+ return (packed & ~0xFF000000) | MATISSA_MAGIC_BIG;
+}
+#endif
+
+// returns the low 24-bits, so we need to OR in the magic_bit afterwards
+static inline int unpack_matissa_dirty(uint32_t packed) {
+ return packed & ~0xFF000000;
+}
+
+// same as (int)float
+int32_t SkFloatBits_toIntCast(int32_t packed) {
+ int exp = unpack_exp(packed) - EXP_BIAS;
+ int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG;
+
+ if (exp >= 0) {
+ if (exp > 7) { // overflow
+ value = SK_MaxS32;
+ } else {
+ value <<= exp;
+ }
+ } else {
+ exp = -exp;
+ if (exp > 25) { // underflow
+ exp = 25;
+ }
+ value >>= exp;
+ }
+ return SkApplySign(value, SkExtractSign(packed));
+}
+
+// same as (int)floor(float)
+int32_t SkFloatBits_toIntFloor(int32_t packed) {
+ // curse you negative 0
+ if ((packed << 1) == 0) {
+ return 0;
+ }
+
+ int exp = unpack_exp(packed) - EXP_BIAS;
+ int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG;
+
+ if (exp >= 0) {
+ if (exp > 7) { // overflow
+ value = SK_MaxS32;
+ } else {
+ value <<= exp;
+ }
+ // apply the sign after we check for overflow
+ return SkApplySign(value, SkExtractSign(packed));
+ } else {
+ // apply the sign before we right-shift
+ value = SkApplySign(value, SkExtractSign(packed));
+ exp = -exp;
+ if (exp > 25) { // underflow
+ exp = 25;
+ }
+ // int add = 0;
+ return value >> exp;
+ }
+}
+
+// same as (int)floor(float + 0.5)
+int32_t SkFloatBits_toIntRound(int32_t packed) {
+ // curse you negative 0
+ if ((packed << 1) == 0) {
+ return 0;
+ }
+
+ int exp = unpack_exp(packed) - EXP_BIAS;
+ int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG;
+
+ if (exp >= 0) {
+ if (exp > 7) { // overflow
+ value = SK_MaxS32;
+ } else {
+ value <<= exp;
+ }
+ // apply the sign after we check for overflow
+ return SkApplySign(value, SkExtractSign(packed));
+ } else {
+ // apply the sign before we right-shift
+ value = SkApplySign(value, SkExtractSign(packed));
+ exp = -exp;
+ if (exp > 25) { // underflow
+ exp = 25;
+ }
+ int add = 1 << (exp - 1);
+ return (value + add) >> exp;
+ }
+}
+
+// same as (int)ceil(float)
+int32_t SkFloatBits_toIntCeil(int32_t packed) {
+ // curse you negative 0
+ if ((packed << 1) == 0) {
+ return 0;
+ }
+
+ int exp = unpack_exp(packed) - EXP_BIAS;
+ int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG;
+
+ if (exp >= 0) {
+ if (exp > 7) { // overflow
+ value = SK_MaxS32;
+ } else {
+ value <<= exp;
+ }
+ // apply the sign after we check for overflow
+ return SkApplySign(value, SkExtractSign(packed));
+ } else {
+ // apply the sign before we right-shift
+ value = SkApplySign(value, SkExtractSign(packed));
+ exp = -exp;
+ if (exp > 25) { // underflow
+ exp = 25;
+ }
+ int add = (1 << exp) - 1;
+ return (value + add) >> exp;
+ }
+}
+
+float SkFloatBits_intToFloatNative(int x);
+float SkFloatBits_intToFloatNative(int x) {
+ return x;
+}
+
+float SkIntToFloatCast(int32_t value) {
+ if (0 == value) {
+ return 0;
+ }
+
+ int shift = EXP_BIAS;
+
+ // record the sign and make value positive
+ int sign = SkExtractSign(value);
+ value = SkApplySign(value, sign);
+
+ if (value >> 24) { // value is too big (has more than 24 bits set)
+ int bias = 8 - SkCLZ(value);
+ SkDebugf("value = %d, bias = %d\n", value, bias);
+ SkASSERT(bias > 0 && bias < 8);
+ value >>= bias; // need to round?
+ shift += bias;
+ } else {
+ int zeros = SkCLZ(value << 8);
+ SkASSERT(zeros >= 0 && zeros <= 23);
+ value <<= zeros;
+ shift -= zeros;
+ }
+
+ // now value is left-aligned to 24 bits
+ SkASSERT((value >> 23) == 1);
+ SkASSERT(shift >= 0 && shift <= 255);
+
+ SkFloatIntUnion data;
+ data.fSignBitInt = (sign << 31) | (shift << 23) | (value & ~MATISSA_MAGIC_BIG);
+ return data.fFloat;
+}
+
+float SkIntToFloatCast_NoOverflowCheck(int32_t value) {
+ if (0 == value) {
+ return 0;
+ }
+
+ int shift = EXP_BIAS;
+
+ // record the sign and make value positive
+ int sign = SkExtractSign(value);
+ value = SkApplySign(value, sign);
+
+ int zeros = SkCLZ(value << 8);
+ value <<= zeros;
+ shift -= zeros;
+
+ SkFloatIntUnion data;
+ data.fSignBitInt = (sign << 31) | (shift << 23) | (value & ~MATISSA_MAGIC_BIG);
+ return data.fFloat;
+}
+