aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2010-03-19 14:42:28 +0000
committerGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2010-03-19 14:42:28 +0000
commite88f551b38c2893566b7016d906b1455e43542f5 (patch)
tree6aa3ff633a27a6c2087df1ccdb5facee526da869
parent9f8f48e9e4a75f2b15bd5d6f8cac728f5e0af0ce (diff)
use 64bit intermediate to accumulate 16.16 widths, to avoid overflow
git-svn-id: http://skia.googlecode.com/svn/trunk@531 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--src/core/SkPaint.cpp33
1 files changed, 26 insertions, 7 deletions
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index a0134123db..3d85b8c839 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -711,9 +711,24 @@ static void set_bounds(const SkGlyph& g, SkRect* bounds)
SkIntToScalar(g.fTop + g.fHeight));
}
-static void join_bounds(const SkGlyph& g, SkRect* bounds, SkFixed dx)
+// 64bits wide, with a 16bit bias. Useful when accumulating lots of 16.16 so
+// we don't overflow along the way
+typedef int64_t Sk48Dot16;
+
+#ifdef SK_SCALAR_IS_FLOAT
+ static inline float Sk48Dot16ToScalar(Sk48Dot16 x) {
+ return x * 1.5258789e-5f; // x * (1 / 65536.0f)
+ }
+#else
+ static inline SkFixed Sk48Dot16ToScalar(Sk48Dot16 x) {
+ // just return the low 32bits
+ return static_cast<SkFixed>(x);
+ }
+#endif
+
+static void join_bounds(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dx)
{
- SkScalar sx = SkFixedToScalar(dx);
+ SkScalar sx = Sk48Dot16ToScalar(dx);
bounds->join(SkIntToScalar(g.fLeft) + sx,
SkIntToScalar(g.fTop),
SkIntToScalar(g.fLeft + g.fWidth) + sx,
@@ -740,7 +755,10 @@ SkScalar SkPaint::measure_text(SkGlyphCache* cache,
int n = 1;
const char* stop = (const char*)text + byteLength;
const SkGlyph* g = &glyphCacheProc(cache, &text);
- SkFixed x = g->fAdvanceX;
+ // our accumulated fixed-point advances might overflow 16.16, so we use
+ // a 48.16 (64bit) accumulator, and then convert that to scalar at the
+ // very end.
+ Sk48Dot16 x = g->fAdvanceX;
SkAutoKern autokern;
@@ -788,7 +806,7 @@ SkScalar SkPaint::measure_text(SkGlyphCache* cache,
SkASSERT(text == stop);
*count = n;
- return SkFixedToScalar(x);
+ return Sk48Dot16ToScalar(x);
}
SkScalar SkPaint::measureText(const void* textData, size_t length,
@@ -898,8 +916,9 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
SkMeasureCacheProc glyphCacheProc = this->getMeasureCacheProc(tbd, false);
const char* stop;
SkTextBufferPred pred = chooseTextBufferPred(tbd, &text, length, &stop);
- SkFixed max = SkScalarToFixed(maxWidth);
- SkFixed width = 0;
+ // use 64bits for our accumulator, to avoid overflowing 16.16
+ Sk48Dot16 max = SkScalarToFixed(maxWidth);
+ Sk48Dot16 width = 0;
SkAutoKern autokern;
@@ -938,7 +957,7 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
if (measuredWidth)
{
- SkScalar scalarWidth = SkFixedToScalar(width);
+ SkScalar scalarWidth = Sk48Dot16ToScalar(width);
if (scale)
scalarWidth = SkScalarMul(scalarWidth, scale);
*measuredWidth = scalarWidth;