diff options
Diffstat (limited to 'skia/sgl/SkScan_Antihair.cpp')
-rw-r--r-- | skia/sgl/SkScan_Antihair.cpp | 214 |
1 files changed, 155 insertions, 59 deletions
diff --git a/skia/sgl/SkScan_Antihair.cpp b/skia/sgl/SkScan_Antihair.cpp index ca36739..04e4690 100644 --- a/skia/sgl/SkScan_Antihair.cpp +++ b/skia/sgl/SkScan_Antihair.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkScan_Antihair.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -23,6 +23,12 @@ #define HLINE_STACK_BUFFER 100 +static inline int SmallDot6Scale(int value, int dot6) { + SkASSERT((int16_t)value == value); + SkASSERT((unsigned)dot6 <= 64); + return SkMulS16(value, dot6) >> 6; +} + //#define TEST_GAMMA #ifdef TEST_GAMMA @@ -52,8 +58,9 @@ #define ApplyGamma(table, alpha) SkToU8(alpha) #endif +/////////////////////////////////////////////////////////////////////////////// -static void call_hline_blitter(SkBlitter* blitter, int x, int y, int count, uint8_t alpha) +static void call_hline_blitter(SkBlitter* blitter, int x, int y, int count, U8CPU alpha) { SkASSERT(count > 0); @@ -74,7 +81,7 @@ static void call_hline_blitter(SkBlitter* blitter, int x, int y, int count, uint } while (count > 0); } -static void hline(int x, int stopx, SkFixed fy, SkFixed /*slope*/, SkBlitter* blitter) +static SkFixed hline(int x, int stopx, SkFixed fy, SkFixed /*slope*/, SkBlitter* blitter, int mod64) { SkASSERT(x < stopx); int count = stopx - x; @@ -84,16 +91,21 @@ static void hline(int x, int stopx, SkFixed fy, SkFixed /*slope*/, SkBlitter* bl uint8_t a = (uint8_t)(fy >> 8); // lower line - if (a) - call_hline_blitter(blitter, x, y, count, a); + unsigned ma = SmallDot6Scale(a, mod64); + if (ma) { + call_hline_blitter(blitter, x, y, count, ma); + } // upper line - a = (uint8_t)(255 - a); - if (a) - call_hline_blitter(blitter, x, y - 1, count, a); + ma = SmallDot6Scale(255 - a, mod64); + if (ma) { + call_hline_blitter(blitter, x, y - 1, count, ma); + } + + return fy - SK_Fixed1/2; } -static void horish(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitter) +static SkFixed horish(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitter, int mod64) { SkASSERT(x < stopx); @@ -110,19 +122,19 @@ static void horish(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitter) do { int lower_y = fy >> 16; uint8_t a = (uint8_t)(fy >> 8); - - if (a) + unsigned ma = SmallDot6Scale(a, mod64); + if (ma) { - aa[0] = ApplyGamma(gamma, a); + aa[0] = ApplyGamma(gamma, ma); blitter->blitAntiH(x, lower_y, aa, runs); // the clipping blitters might edit runs, but should not affect us SkASSERT(runs[0] == 1); SkASSERT(runs[1] == 0); } - a = (uint8_t)(255 - a); - if (a) + ma = SmallDot6Scale(255 - a, mod64); + if (ma) { - aa[0] = ApplyGamma(gamma, a); + aa[0] = ApplyGamma(gamma, ma); blitter->blitAntiH(x, lower_y - 1, aa, runs); // the clipping blitters might edit runs, but should not affect us SkASSERT(runs[0] == 1); @@ -130,9 +142,11 @@ static void horish(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitter) } fy += dy; } while (++x < stopx); + + return fy - SK_Fixed1/2; } -static void vline(int y, int stopy, SkFixed fx, SkFixed /*slope*/, SkBlitter* blitter) +static SkFixed vline(int y, int stopy, SkFixed fx, SkFixed /*slope*/, SkBlitter* blitter, int mod64) { SkASSERT(y < stopy); fx += SK_Fixed1/2; @@ -140,14 +154,17 @@ static void vline(int y, int stopy, SkFixed fx, SkFixed /*slope*/, SkBlitter* bl int x = fx >> 16; int a = (uint8_t)(fx >> 8); - if (a) - blitter->blitV(x, y, stopy - y, ApplyGamma(gGammaTable, a)); - a = 255 - a; - if (a) - blitter->blitV(x - 1, y, stopy - y, ApplyGamma(gGammaTable, a)); + unsigned ma = SmallDot6Scale(a, mod64); + if (ma) + blitter->blitV(x, y, stopy - y, ApplyGamma(gGammaTable, ma)); + ma = SmallDot6Scale(255 - a, mod64); + if (ma) + blitter->blitV(x - 1, y, stopy - y, ApplyGamma(gGammaTable, ma)); + + return fx - SK_Fixed1/2; } -static void vertish(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitter) +static SkFixed vertish(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitter, int mod64) { SkASSERT(y < stopy); #ifdef TEST_GAMMA @@ -164,8 +181,8 @@ static void vertish(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitter int x = fx >> 16; uint8_t a = (uint8_t)(fx >> 8); - aa[0] = ApplyGamma(gamma, 255 - a); - aa[1] = ApplyGamma(gamma, a); + aa[0] = ApplyGamma(gamma, SmallDot6Scale(255 - a, mod64)); + aa[1] = ApplyGamma(gamma, SmallDot6Scale(a, mod64)); // the clippng blitters might overwrite this guy, so we have to reset it each time runs[1] = 1; blitter->blitAntiH(x - 1, y, aa, runs); @@ -174,9 +191,11 @@ static void vertish(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitter SkASSERT(runs[2] == 0); fx += dx; } while (++y < stopy); + + return fx - SK_Fixed1/2; } -typedef void (*LineProc)(int istart, int istop, SkFixed fstart, SkFixed slope, SkBlitter*); +typedef SkFixed (*LineProc)(int istart, int istop, SkFixed fstart, SkFixed slope, SkBlitter*, int); static inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) { @@ -184,11 +203,6 @@ static inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) SkASSERT(b != 0); return (a << 16) / b; } -static inline SkFDot6 fastfixmul(SkFixed fixed, SkFDot6 b) -{ - SkASSERT(SkAbs32(fixed) <= SK_Fixed1 && SkAbs32(b) <= SkIntToFDot6(511)); - return (fixed * b + 0x8000) >> 16; -} static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, const SkIRect* clip, SkBlitter* blitter) @@ -205,35 +219,40 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, return; } + int scaleStart, scaleStop; int istart, istop; SkFixed fstart, slope; LineProc proc; if (SkAbs32(x1 - x0) > SkAbs32(y1 - y0)) // mostly horizontal { - if (x0 > x1) // we want to go left-to-right - { + if (x0 > x1) { // we want to go left-to-right SkTSwap<SkFDot6>(x0, x1); SkTSwap<SkFDot6>(y0, y1); } - istart = SkFDot6Round(x0); - istop = SkFDot6Round(x1); - if (istart == istop) // too short to draw - return; - if (y0 == y1) // completely horizontal, take fast case - { + istart = SkFDot6Floor(x0); + istop = SkFDot6Ceil(x1); + fstart = SkFDot6ToFixed(y0); + if (y0 == y1) { // completely horizontal, take fast case slope = 0; - fstart = SkFDot6ToFixed(y0); proc = hline; - } - else - { + } else { slope = fastfixdiv(y1 - y0, x1 - x0); SkASSERT(slope >= -SK_Fixed1 && slope <= SK_Fixed1); - fstart = SkFDot6ToFixed(y0 + fastfixmul(slope, (32 - x0) & 63)); + fstart += (slope * (32 - (x0 & 63)) + 32) >> 6; proc = horish; } + + SkASSERT(istop > istart); + if (istop - istart == 1) { + scaleStart = x1 - x0; + SkASSERT(scaleStart >= 0 && scaleStart <= 64); + scaleStop = 0; + } else { + scaleStart = 64 - (x0 & 63); + scaleStop = x1 & 63; + } if (clip) { @@ -243,12 +262,16 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, { fstart += slope * (clip->fLeft - istart); istart = clip->fLeft; + scaleStart = 64; } - if (istop > clip->fRight) + if (istop > clip->fRight) { istop = clip->fRight; + scaleStop = 64; + } SkASSERT(istart <= istop); if (istart == istop) return; + // now test if our Y values are completely inside the clip int top, bottom; if (slope >= 0) // T2B @@ -274,25 +297,36 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, SkTSwap<SkFDot6>(x0, x1); SkTSwap<SkFDot6>(y0, y1); } - istart = SkFDot6Round(y0); - istop = SkFDot6Round(y1); - if (istart == istop) // too short to draw - return; + istart = SkFDot6Floor(y0); + istop = SkFDot6Ceil(y1); + fstart = SkFDot6ToFixed(x0); if (x0 == x1) { + if (y0 == y1) { // are we zero length? + return; // nothing to do + } slope = 0; - fstart = SkFDot6ToFixed(x0); proc = vline; } else { slope = fastfixdiv(x1 - x0, y1 - y0); SkASSERT(slope <= SK_Fixed1 && slope >= -SK_Fixed1); - fstart = SkFDot6ToFixed(x0 + fastfixmul(slope, (32 - y0) & 63)); + fstart += (slope * (32 - (y0 & 63)) + 32) >> 6; proc = vertish; } + SkASSERT(istop > istart); + if (istop - istart == 1) { + scaleStart = y1 - y0; + SkASSERT(scaleStart >= 0 && scaleStart <= 64); + scaleStop = 0; + } else { + scaleStart = 64 - (y0 & 63); + scaleStop = y1 & 63; + } + if (clip) { if (istart >= clip->fBottom || istop <= clip->fTop) @@ -301,12 +335,16 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, { fstart += slope * (clip->fTop - istart); istart = clip->fTop; + scaleStart = 64; } - if (istop > clip->fBottom) + if (istop > clip->fBottom) { istop = clip->fBottom; + scaleStop = 64; + } SkASSERT(istart <= istop); if (istart == istop) return; + // now test if our X values are completely inside the clip int left, right; if (slope >= 0) // L2R @@ -332,7 +370,16 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, rectClipper.init(blitter, *clip); blitter = &rectClipper; } - proc(istart, istop, fstart, slope, blitter); + + fstart = proc(istart, istart + 1, fstart, slope, blitter, scaleStart); + istart += 1; + int fullSpans = istop - istart - 1; + if (fullSpans > 0) { + fstart = proc(istart, istart + fullSpans, fstart, slope, blitter, 64); + } + if (scaleStop > 0) { + proc(istop - 1, istop, fstart, slope, blitter, scaleStop); + } } void SkScan::AntiHairLine(const SkPoint& pt0, const SkPoint& pt1, @@ -360,10 +407,10 @@ void SkScan::AntiHairLine(const SkPoint& pt0, const SkPoint& pt1, SkFDot6 bottom = SkMax32(y0, y1); SkIRect ir; - ir.set( SkFDot6Round(left) - 1, - SkFDot6Round(top) - 1, - SkFDot6Round(right) + 1, - SkFDot6Round(bottom) + 1); + ir.set( SkFDot6Floor(left) - 1, + SkFDot6Floor(top) - 1, + SkFDot6Ceil(right) + 1, + SkFDot6Ceil(bottom) + 1); if (clip->quickReject(ir)) return; @@ -536,12 +583,61 @@ void SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip, #ifdef SK_SCALAR_IS_FLOAT -void SkScan::AntiFillRect(const SkRect& r, const SkRegion* clip, - SkBlitter* blitter) { +/* This guy takes a float-rect, but with the key improvement that it has + already been clipped, so we know that it is safe to convert it into a + XRect (fixedpoint), as it won't overflow. +*/ +static void antifillrect(const SkRect& r, SkBlitter* blitter) { SkXRect xr; XRect_set(&xr, r); - SkScan::AntiFillXRect(xr, clip, blitter); + antifillrect(xr, blitter); +} + +/* We repeat the clipping logic of AntiFillXRect because the float rect might + overflow if we blindly converted it to an XRect. This sucks that we have to + repeat the clipping logic, but I don't see how to share the code/logic. + + We clip r (as needed) into one or more (smaller) float rects, and then pass + those to our version of antifillrect, which converts it into an XRect and + then calls the blit. +*/ +void SkScan::AntiFillRect(const SkRect& r, const SkRegion* clip, + SkBlitter* blitter) { + if (clip) { + SkIRect outerBounds; + r.roundOut(&outerBounds); + + if (clip->isRect()) { + const SkIRect& clipBounds = clip->getBounds(); + + if (clipBounds.contains(outerBounds)) { + antifillrect(r, blitter); + } else { + SkRect tmpR; + // this keeps our original edges fractional + tmpR.set(clipBounds); + if (tmpR.intersect(r)) { + antifillrect(tmpR, blitter); + } + } + } else { + SkRegion::Cliperator clipper(*clip, outerBounds); + const SkIRect& rr = clipper.rect(); + + while (!clipper.done()) { + SkRect tmpR; + // this keeps our original edges fractional + tmpR.set(rr); + if (tmpR.intersect(r)) { + antifillrect(tmpR, blitter); + } + clipper.next(); + } + } + } else { + antifillrect(r, blitter); + } } #endif |