aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/SkScan_AntiPath.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/SkScan_AntiPath.cpp')
-rw-r--r--src/core/SkScan_AntiPath.cpp293
1 files changed, 241 insertions, 52 deletions
diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp
index 4dc2cd3..97843ef 100644
--- a/src/core/SkScan_AntiPath.cpp
+++ b/src/core/SkScan_AntiPath.cpp
@@ -1,19 +1,11 @@
-/* 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.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkScanPriv.h"
#include "SkPath.h"
@@ -26,13 +18,18 @@
#define SCALE (1 << SHIFT)
#define MASK (SCALE - 1)
-/*
+/** @file
We have two techniques for capturing the output of the supersampler:
- SUPERMASK, which records a large mask-bitmap
this is often faster for small, complex objects
- RLE, which records a rle-encoded scanline
this is often faster for large objects with big spans
+ These blitters use two coordinate systems:
+ - destination coordinates, scale equal to the output - often
+ abbreviated with 'i' or 'I' in variable names
+ - supersampled coordinates, scale equal to the output * SCALE
+
NEW_AA is a set of code-changes to try to make both paths produce identical
results. Its not quite there yet, though the remaining differences may be
in the subsequent blits, and not in the different masks/runs...
@@ -43,29 +40,38 @@
///////////////////////////////////////////////////////////////////////////////
+/// Base class for a single-pass supersampled blitter.
class BaseSuperBlitter : public SkBlitter {
public:
BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
const SkRegion& clip);
+ /// Must be explicitly defined on subclasses.
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?");
+ const int16_t runs[]) SK_OVERRIDE {
+ SkDEBUGFAIL("How did I get here?");
}
- virtual void blitRect(int x, int y, int width, int height) {
- SkASSERT(!"How did I get here?");
+ /// May not be called on BaseSuperBlitter because it blits out of order.
+ virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE {
+ SkDEBUGFAIL("How did I get here?");
}
protected:
SkBlitter* fRealBlitter;
+ /// Current y coordinate, in destination coordinates.
int fCurrIY;
- int fWidth, fLeft, fSuperLeft;
+ /// Widest row of region to be blitted, in destination coordinates.
+ int fWidth;
+ /// Leftmost x coordinate in any row, in destination coordinates.
+ int fLeft;
+ /// Leftmost x coordinate in any row, in supersampled coordinates.
+ int fSuperLeft;
SkDEBUGCODE(int fCurrX;)
+ /// Current y coordinate in supersampled coordinates.
int fCurrY;
+ /// Initial y coordinate (top of bounds).
+ int fTop;
};
BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
@@ -80,11 +86,18 @@ BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
fLeft = left;
fSuperLeft = left << SHIFT;
fWidth = right - left;
+#if 0
fCurrIY = -1;
fCurrY = -1;
+#else
+ fTop = ir.fTop;
+ fCurrIY = ir.fTop - 1;
+ fCurrY = (ir.fTop << SHIFT) - 1;
+#endif
SkDEBUGCODE(fCurrX = -1;)
}
+/// Run-length-encoded supersampling antialiased blitter.
class SuperBlitter : public BaseSuperBlitter {
public:
SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
@@ -95,10 +108,16 @@ public:
sk_free(fRuns.fRuns);
}
+ /// Once fRuns contains a complete supersampled row, flush() blits
+ /// it out through the wrapped blitter.
void flush();
- virtual void blitH(int x, int y, int width);
- virtual void blitRect(int x, int y, int width, int height);
+ /// Blits a row of pixels, with location and width specified
+ /// in supersampled coordinates.
+ virtual void blitH(int x, int y, int width) SK_OVERRIDE;
+ /// Blits a rectangle of pixels, with location and size specified
+ /// in supersampled coordinates.
+ virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
private:
SkAlphaRuns fRuns;
@@ -119,14 +138,14 @@ SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
}
void SuperBlitter::flush() {
- if (fCurrIY >= 0) {
+ if (fCurrIY >= fTop) {
if (!fRuns.empty()) {
// SkDEBUGCODE(fRuns.dump();)
fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
fRuns.reset(fWidth);
fOffsetX = 0;
}
- fCurrIY = -1;
+ fCurrIY = fTop - 1;
SkDEBUGCODE(fCurrX = -1;)
}
}
@@ -137,9 +156,15 @@ static inline int coverage_to_alpha(int aa) {
return aa;
}
-#define SUPER_Mask ((1 << SHIFT) - 1)
+static inline int coverage_to_exact_alpha(int aa) {
+ int alpha = (256 >> SHIFT) * aa;
+ // clamp 256->255
+ return alpha - (alpha >> 8);
+}
void SuperBlitter::blitH(int x, int y, int width) {
+ SkASSERT(width > 0);
+
int iy = y >> SHIFT;
SkASSERT(iy >= fCurrIY);
@@ -164,16 +189,13 @@ void SuperBlitter::blitH(int x, int y, int width) {
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);
-
int start = x;
int stop = x + width;
SkASSERT(start >= 0 && stop > start);
- int fb = start & SUPER_Mask;
- int fe = stop & SUPER_Mask;
+ // integer-pixel-aligned ends of blit, rounded out
+ int fb = start & MASK;
+ int fe = stop & MASK;
int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
if (n < 0) {
@@ -184,11 +206,13 @@ void SuperBlitter::blitH(int x, int y, int width) {
if (fb == 0) {
n += 1;
} else {
- fb = (1 << SHIFT) - fb;
+ fb = SCALE - fb;
}
}
- fOffsetX = fRuns.add(x >> SHIFT, coverage_to_alpha(fb), n, coverage_to_alpha(fe),
+ // TODO - should this be using coverage_to_exact_alpha?
+ fOffsetX = fRuns.add(x >> SHIFT, coverage_to_alpha(fb),
+ n, coverage_to_alpha(fe),
(1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT),
fOffsetX);
@@ -198,16 +222,141 @@ void SuperBlitter::blitH(int x, int y, int width) {
#endif
}
+static void set_left_rite_runs(SkAlphaRuns& runs, int ileft, U8CPU leftA,
+ int n, U8CPU riteA) {
+ SkASSERT(leftA <= 0xFF);
+ SkASSERT(riteA <= 0xFF);
+
+ int16_t* run = runs.fRuns;
+ uint8_t* aa = runs.fAlpha;
+
+ if (ileft > 0) {
+ run[0] = ileft;
+ aa[0] = 0;
+ run += ileft;
+ aa += ileft;
+ }
+
+ SkASSERT(leftA < 0xFF);
+ if (leftA > 0) {
+ *run++ = 1;
+ *aa++ = leftA;
+ }
+
+ if (n > 0) {
+ run[0] = n;
+ aa[0] = 0xFF;
+ run += n;
+ aa += n;
+ }
+
+ SkASSERT(riteA < 0xFF);
+ if (riteA > 0) {
+ *run++ = 1;
+ *aa++ = riteA;
+ }
+ run[0] = 0;
+}
+
void SuperBlitter::blitRect(int x, int y, int width, int height) {
- for (int i = 0; i < height; ++i) {
- blitH(x, y + i, width);
+ SkASSERT(width > 0);
+ SkASSERT(height > 0);
+
+ // blit leading rows
+ while ((y & MASK)) {
+ this->blitH(x, y++, width);
+ if (--height <= 0) {
+ return;
+ }
+ }
+ SkASSERT(height > 0);
+
+ // Since this is a rect, instead of blitting supersampled rows one at a
+ // time and then resolving to the destination canvas, we can blit
+ // directly to the destintion canvas one row per SCALE supersampled rows.
+ int start_y = y >> SHIFT;
+ int stop_y = (y + height) >> SHIFT;
+ int count = stop_y - start_y;
+ if (count > 0) {
+ y += count << SHIFT;
+ height -= count << SHIFT;
+
+ // save original X for our tail blitH() loop at the bottom
+ int origX = x;
+
+ x -= fSuperLeft;
+ // hack, until I figure out why my cubics (I think) go beyond the bounds
+ if (x < 0) {
+ width += x;
+ x = 0;
+ }
+
+ // There is always a left column, a middle, and a right column.
+ // ileft is the destination x of the first pixel of the entire rect.
+ // xleft is (SCALE - # of covered supersampled pixels) in that
+ // destination pixel.
+ int ileft = x >> SHIFT;
+ int xleft = x & MASK;
+ // irite is the destination x of the last pixel of the OPAQUE section.
+ // xrite is the number of supersampled pixels extending beyond irite;
+ // xrite/SCALE should give us alpha.
+ int irite = (x + width) >> SHIFT;
+ int xrite = (x + width) & MASK;
+ if (!xrite) {
+ xrite = SCALE;
+ irite--;
+ }
+
+ // Need to call flush() to clean up pending draws before we
+ // even consider blitV(), since otherwise it can look nonmonotonic.
+ SkASSERT(start_y > fCurrIY);
+ this->flush();
+
+ int n = irite - ileft - 1;
+ if (n < 0) {
+ // If n < 0, we'll only have a single partially-transparent column
+ // of pixels to render.
+ xleft = xrite - xleft;
+ SkASSERT(xleft <= SCALE);
+ SkASSERT(xleft > 0);
+ xrite = 0;
+ fRealBlitter->blitV(ileft + fLeft, start_y, count,
+ coverage_to_exact_alpha(xleft));
+ } else {
+ // With n = 0, we have two possibly-transparent columns of pixels
+ // to render; with n > 0, we have opaque columns between them.
+
+ xleft = SCALE - xleft;
+
+ // Using coverage_to_exact_alpha is not consistent with blitH()
+ const int coverageL = coverage_to_exact_alpha(xleft);
+ const int coverageR = coverage_to_exact_alpha(xrite);
+
+ SkASSERT(coverageL > 0 || n > 0 || coverageR > 0);
+ SkASSERT((coverageL != 0) + n + (coverageR != 0) <= fWidth);
+
+ fRealBlitter->blitAntiRect(ileft + fLeft, start_y, n, count,
+ coverageL, coverageR);
+ }
+
+ // preamble for our next call to blitH()
+ fCurrIY = stop_y - 1;
+ fOffsetX = 0;
+ fCurrY = y - 1;
+ fRuns.reset(fWidth);
+ x = origX;
}
- flush();
+ // catch any remaining few rows
+ SkASSERT(height <= MASK);
+ while (--height >= 0) {
+ this->blitH(x, y++, width);
+ }
}
///////////////////////////////////////////////////////////////////////////////
+/// Masked supersampling antialiased blitter.
class MaskSuperBlitter : public BaseSuperBlitter {
public:
MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
@@ -216,7 +365,7 @@ public:
fRealBlitter->blitMask(fMask, fClipRect);
}
- virtual void blitH(int x, int y, int width);
+ virtual void blitH(int x, int y, int width) SK_OVERRIDE;
static bool CanHandleRect(const SkIRect& bounds) {
#ifdef FORCE_RLE
@@ -365,18 +514,14 @@ void MaskSuperBlitter::blitH(int x, int y, int width) {
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 fb = start & MASK;
+ int fe = stop & MASK;
int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
@@ -389,10 +534,10 @@ void MaskSuperBlitter::blitH(int x, int y, int width) {
if (0 == fb) {
n += 1;
} else {
- fb = (1 << SHIFT) - fb;
+ fb = SCALE - fb;
}
#else
- fb = (1 << SHIFT) - fb;
+ fb = SCALE - fb;
#endif
SkASSERT(row >= fMask.fImage);
SkASSERT(row + n + 1 < fMask.fImage + kMAX_STORAGE + 1);
@@ -417,7 +562,7 @@ static int overflows_short_shift(int value, int shift) {
}
void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
- SkBlitter* blitter) {
+ SkBlitter* blitter, bool forceRLE) {
if (clip.isEmpty()) {
return;
}
@@ -425,6 +570,9 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
SkIRect ir;
path.getBounds().roundOut(&ir);
if (ir.isEmpty()) {
+ if (path.isInverseFillType()) {
+ blitter->blitRegion(clip);
+ }
return;
}
@@ -468,7 +616,7 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
// 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)) {
+ if (!path.isInverseFillType() && MaskSuperBlitter::CanHandleRect(ir) && !forceRLE) {
MaskSuperBlitter superBlit(blitter, ir, clip);
SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip);
@@ -481,3 +629,44 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
sk_blit_below(blitter, ir, clip);
}
}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkRasterClip.h"
+
+void SkScan::FillPath(const SkPath& path, const SkRasterClip& clip,
+ SkBlitter* blitter) {
+ if (clip.isEmpty()) {
+ return;
+ }
+
+ if (clip.isBW()) {
+ FillPath(path, clip.bwRgn(), blitter);
+ } else {
+ SkRegion tmp;
+ SkAAClipBlitter aaBlitter;
+
+ tmp.setRect(clip.getBounds());
+ aaBlitter.init(blitter, &clip.aaRgn());
+ SkScan::FillPath(path, tmp, &aaBlitter);
+ }
+}
+
+void SkScan::AntiFillPath(const SkPath& path, const SkRasterClip& clip,
+ SkBlitter* blitter) {
+ if (clip.isEmpty()) {
+ return;
+ }
+
+ if (clip.isBW()) {
+ AntiFillPath(path, clip.bwRgn(), blitter);
+ } else {
+ SkRegion tmp;
+ SkAAClipBlitter aaBlitter;
+
+ tmp.setRect(clip.getBounds());
+ aaBlitter.init(blitter, &clip.aaRgn());
+ SkScan::AntiFillPath(path, tmp, &aaBlitter, true);
+ }
+}
+