aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkScan_AntiPath.cpp
diff options
context:
space:
mode:
authorGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2008-12-17 15:59:43 +0000
committerGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2008-12-17 15:59:43 +0000
commit8a1c16ff38322f0210116fa7293eb8817c7e477e (patch)
treefe40e07f6c8983318a2f79032b9a706ede1090c1 /src/core/SkScan_AntiPath.cpp
parent2559c629078f738ac37095d896d580b681ac6a30 (diff)
grab from latest android
git-svn-id: http://skia.googlecode.com/svn/trunk@27 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core/SkScan_AntiPath.cpp')
-rw-r--r--src/core/SkScan_AntiPath.cpp406
1 files changed, 406 insertions, 0 deletions
diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp
new file mode 100644
index 0000000000..9cdeeaa56e
--- /dev/null
+++ b/src/core/SkScan_AntiPath.cpp
@@ -0,0 +1,406 @@
+/* libs/graphics/sgl/SkScan_AntiPath.cpp
+**
+** 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.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "SkScanPriv.h"
+#include "SkPath.h"
+#include "SkMatrix.h"
+#include "SkBlitter.h"
+#include "SkRegion.h"
+#include "SkAntiRun.h"
+
+#define SHIFT 2
+#define SCALE (1 << SHIFT)
+#define MASK (SCALE - 1)
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+class BaseSuperBlitter : public SkBlitter {
+public:
+ BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
+ const SkRegion& clip);
+
+ virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
+ const int16_t runs[]) {
+ SkASSERT(!"How did I get here?");
+ }
+ virtual void blitV(int x, int y, int height, SkAlpha alpha) {
+ SkASSERT(!"How did I get here?");
+ }
+ virtual void blitRect(int x, int y, int width, int height) {
+ SkASSERT(!"How did I get here?");
+ }
+
+protected:
+ SkBlitter* fRealBlitter;
+ int fCurrIY;
+ int fWidth, fLeft, fSuperLeft;
+
+ SkDEBUGCODE(int fCurrX;)
+ SkDEBUGCODE(int fCurrY;)
+};
+
+BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
+ const SkRegion& clip) {
+ fRealBlitter = realBlitter;
+
+ // take the union of the ir bounds and clip, since we may be called with an
+ // inverse filltype
+ const int left = SkMin32(ir.fLeft, clip.getBounds().fLeft);
+ const int right = SkMax32(ir.fRight, clip.getBounds().fRight);
+
+ fLeft = left;
+ fSuperLeft = left << SHIFT;
+ fWidth = right - left;
+ fCurrIY = -1;
+ SkDEBUGCODE(fCurrX = -1; fCurrY = -1;)
+}
+
+class SuperBlitter : public BaseSuperBlitter {
+public:
+ SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
+ const SkRegion& clip);
+
+ virtual ~SuperBlitter() {
+ this->flush();
+ sk_free(fRuns.fRuns);
+ }
+
+ void flush();
+
+ virtual void blitH(int x, int y, int width);
+
+private:
+ SkAlphaRuns fRuns;
+};
+
+SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
+ const SkRegion& clip)
+ : BaseSuperBlitter(realBlitter, ir, clip) {
+ const int width = fWidth;
+
+ // extra one to store the zero at the end
+ fRuns.fRuns = (int16_t*)sk_malloc_throw((width + 1 + (width + 2)/2) * sizeof(int16_t));
+ fRuns.fAlpha = (uint8_t*)(fRuns.fRuns + width + 1);
+ fRuns.reset(width);
+}
+
+void SuperBlitter::flush()
+{
+ if (fCurrIY >= 0)
+ {
+ if (!fRuns.empty())
+ {
+ // SkDEBUGCODE(fRuns.dump();)
+ fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
+ fRuns.reset(fWidth);
+ }
+ fCurrIY = -1;
+ SkDEBUGCODE(fCurrX = -1;)
+ }
+}
+
+static inline int coverage_to_alpha(int aa)
+{
+ aa <<= 8 - 2*SHIFT;
+ aa -= aa >> (8 - SHIFT - 1);
+ return aa;
+}
+
+#define SUPER_Mask ((1 << SHIFT) - 1)
+
+void SuperBlitter::blitH(int x, int y, int width)
+{
+ int iy = y >> SHIFT;
+ SkASSERT(iy >= fCurrIY);
+
+ x -= fSuperLeft;
+ // hack, until I figure out why my cubics (I think) go beyond the bounds
+ if (x < 0)
+ {
+ width += x;
+ x = 0;
+ }
+
+#ifdef SK_DEBUG
+ SkASSERT(y >= fCurrY);
+ SkASSERT(y != fCurrY || x >= fCurrX);
+ fCurrY = y;
+#endif
+
+ if (iy != fCurrIY) // new scanline
+ {
+ this->flush();
+ fCurrIY = iy;
+ }
+
+ // we sub 1 from maxValue 1 time for each block, so that we don't
+ // hit 256 as a summed max, but 255.
+// int maxValue = (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT);
+
+#if 0
+ SkAntiRun<SHIFT> arun;
+ arun.set(x, x + width);
+ fRuns.add(x >> SHIFT, arun.getStartAlpha(), arun.getMiddleCount(), arun.getStopAlpha(), maxValue);
+#else
+ {
+ int start = x;
+ int stop = x + width;
+
+ SkASSERT(start >= 0 && stop > start);
+ int fb = start & SUPER_Mask;
+ int fe = stop & SUPER_Mask;
+ int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
+
+ if (n < 0)
+ {
+ fb = fe - fb;
+ n = 0;
+ fe = 0;
+ }
+ else
+ {
+ if (fb == 0)
+ n += 1;
+ else
+ fb = (1 << SHIFT) - fb;
+ }
+ fRuns.add(x >> SHIFT, coverage_to_alpha(fb), n, coverage_to_alpha(fe),
+ (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT));
+ }
+#endif
+
+#ifdef SK_DEBUG
+ fRuns.assertValid(y & MASK, (1 << (8 - SHIFT)));
+ fCurrX = x + width;
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class MaskSuperBlitter : public BaseSuperBlitter {
+public:
+ MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
+ const SkRegion& clip);
+ virtual ~MaskSuperBlitter() {
+ fRealBlitter->blitMask(fMask, fClipRect);
+ }
+
+ virtual void blitH(int x, int y, int width);
+
+ static bool CanHandleRect(const SkIRect& bounds)
+ {
+ int width = bounds.width();
+ int rb = SkAlign4(width);
+
+ return (width <= MaskSuperBlitter::kMAX_WIDTH) &&
+ (rb * bounds.height() <= MaskSuperBlitter::kMAX_STORAGE);
+ }
+
+private:
+ enum {
+ kMAX_WIDTH = 32, // so we don't try to do very wide things, where the RLE blitter would be faster
+ kMAX_STORAGE = 1024
+ };
+
+ SkMask fMask;
+ SkIRect fClipRect;
+ // we add 1 because add_aa_span can write (unchanged) 1 extra byte at the end, rather than
+ // perform a test to see if stopAlpha != 0
+ uint32_t fStorage[(kMAX_STORAGE >> 2) + 1];
+};
+
+MaskSuperBlitter::MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
+ const SkRegion& clip)
+ : BaseSuperBlitter(realBlitter, ir, clip) {
+ SkASSERT(CanHandleRect(ir));
+
+ fMask.fImage = (uint8_t*)fStorage;
+ fMask.fBounds = ir;
+ fMask.fRowBytes = ir.width();
+ fMask.fFormat = SkMask::kA8_Format;
+
+ fClipRect = ir;
+ fClipRect.intersect(clip.getBounds());
+
+ // For valgrind, write 1 extra byte at the end so we don't read
+ // uninitialized memory. See comment in add_aa_span and fStorage[].
+ memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1);
+}
+
+static void add_aa_span(uint8_t* alpha, U8CPU startAlpha)
+{
+ /* I should be able to just add alpha[x] + startAlpha.
+ However, if the trailing edge of the previous span and the leading
+ edge of the current span round to the same super-sampled x value,
+ I might overflow to 256 with this add, hence the funny subtract.
+ */
+ unsigned tmp = *alpha + startAlpha;
+ SkASSERT(tmp <= 256);
+ *alpha = SkToU8(tmp - (tmp >> 8));
+}
+
+static void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount, U8CPU stopAlpha, U8CPU maxValue)
+{
+ SkASSERT(middleCount >= 0);
+
+ /* I should be able to just add alpha[x] + startAlpha.
+ However, if the trailing edge of the previous span and the leading
+ edge of the current span round to the same super-sampled x value,
+ I might overflow to 256 with this add, hence the funny subtract.
+ */
+ unsigned tmp = *alpha + startAlpha;
+ SkASSERT(tmp <= 256);
+ *alpha++ = SkToU8(tmp - (tmp >> 8));
+
+ while (--middleCount >= 0)
+ {
+ alpha[0] = SkToU8(alpha[0] + maxValue);
+ alpha += 1;
+ }
+
+ // potentially this can be off the end of our "legal" alpha values, but that
+ // only happens if stopAlpha is also 0. Rather than test for stopAlpha != 0
+ // every time (slow), we just do it, and ensure that we've allocated extra space
+ // (see the + 1 comment in fStorage[]
+ *alpha = SkToU8(*alpha + stopAlpha);
+}
+
+void MaskSuperBlitter::blitH(int x, int y, int width)
+{
+ int iy = (y >> SHIFT);
+
+ SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom);
+ iy -= fMask.fBounds.fTop; // make it relative to 0
+
+#ifdef SK_DEBUG
+ {
+ int ix = x >> SHIFT;
+ SkASSERT(ix >= fMask.fBounds.fLeft && ix < fMask.fBounds.fRight);
+ }
+#endif
+
+ x -= (fMask.fBounds.fLeft << SHIFT);
+
+ // hack, until I figure out why my cubics (I think) go beyond the bounds
+ if (x < 0)
+ {
+ width += x;
+ x = 0;
+ }
+
+ // we sub 1 from maxValue 1 time for each block, so that we don't
+ // hit 256 as a summed max, but 255.
+// int maxValue = (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT);
+
+ uint8_t* row = fMask.fImage + iy * fMask.fRowBytes + (x >> SHIFT);
+
+ int start = x;
+ int stop = x + width;
+
+ SkASSERT(start >= 0 && stop > start);
+ int fb = start & SUPER_Mask;
+ int fe = stop & SUPER_Mask;
+ int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
+
+
+ if (n < 0)
+ {
+ add_aa_span(row, coverage_to_alpha(fe - fb));
+ }
+ else
+ {
+ fb = (1 << SHIFT) - fb;
+ add_aa_span(row, coverage_to_alpha(fb), n, coverage_to_alpha(fe),
+ (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT));
+ }
+
+#ifdef SK_DEBUG
+ fCurrX = x + width;
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int overflows_short(int value) {
+ return value - (short)value;
+}
+
+void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
+ SkBlitter* blitter) {
+ if (clip.isEmpty()) {
+ return;
+ }
+
+ SkRect r;
+ SkIRect ir;
+
+ path.computeBounds(&r, SkPath::kFast_BoundsType);
+ r.roundOut(&ir);
+ if (ir.isEmpty()) {
+ return;
+ }
+
+ if (overflows_short(ir.fLeft << SHIFT) ||
+ overflows_short(ir.fRight << SHIFT) ||
+ overflows_short(ir.width() << SHIFT) ||
+ overflows_short(ir.fTop << SHIFT) ||
+ overflows_short(ir.fBottom << SHIFT) ||
+ overflows_short(ir.height() << SHIFT)) {
+ // can't supersample, try drawing w/o antialiasing
+ SkScan::FillPath(path, clip, blitter);
+ return;
+ }
+
+ SkScanClipper clipper(blitter, &clip, ir);
+ const SkIRect* clipRect = clipper.getClipRect();
+
+ if (clipper.getBlitter() == NULL) { // clipped out
+ if (path.isInverseFillType()) {
+ blitter->blitRegion(clip);
+ }
+ return;
+ }
+
+ // now use the (possibly wrapped) blitter
+ blitter = clipper.getBlitter();
+
+ if (path.isInverseFillType()) {
+ sk_blit_above_and_below(blitter, ir, clip);
+ }
+
+ SkIRect superRect, *superClipRect = NULL;
+
+ if (clipRect)
+ {
+ superRect.set( clipRect->fLeft << SHIFT, clipRect->fTop << SHIFT,
+ clipRect->fRight << SHIFT, clipRect->fBottom << SHIFT);
+ superClipRect = &superRect;
+ }
+
+ // MaskSuperBlitter can't handle drawing outside of ir, so we can't use it
+ // if we're an inverse filltype
+ if (!path.isInverseFillType() && MaskSuperBlitter::CanHandleRect(ir))
+ {
+ MaskSuperBlitter superBlit(blitter, ir, clip);
+ sk_fill_path(path, superClipRect, &superBlit, ir.fBottom, SHIFT, clip);
+ }
+ else
+ {
+ SuperBlitter superBlit(blitter, ir, clip);
+ sk_fill_path(path, superClipRect, &superBlit, ir.fBottom, SHIFT, clip);
+ }
+}