aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar tomhudson@google.com <tomhudson@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-12-28 17:58:07 +0000
committerGravatar tomhudson@google.com <tomhudson@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-12-28 17:58:07 +0000
commit4714359ec091b34a4f88eb9708868a58a22177d3 (patch)
tree540246da2514658a244eed3bf6c7d53fd2a628b5
parent6fc7cc23a9c33960b879f69d92d6fb0e1373e556 (diff)
Bugfixes to antialiased blitting.
More details of blitter contracts in function headers. New precautionary assert in one high-level default blitter. git-svn-id: http://skia.googlecode.com/svn/trunk@2928 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--include/core/SkBlitter.h9
-rw-r--r--src/core/SkBlitter.cpp10
-rw-r--r--src/core/SkScan_AntiPath.cpp33
3 files changed, 30 insertions, 22 deletions
diff --git a/include/core/SkBlitter.h b/include/core/SkBlitter.h
index beaebfeccd..e784ef5e23 100644
--- a/include/core/SkBlitter.h
+++ b/include/core/SkBlitter.h
@@ -24,7 +24,7 @@ class SkBlitter {
public:
virtual ~SkBlitter();
- /// Blit a horizontal run of pixels.
+ /// Blit a horizontal run of zero or more pixels.
virtual void blitH(int x, int y, int width);
/// Blit a horizontal run of antialiased pixels; runs[] is a *sparse*
/// zero-terminated run-length encoding of spans of constant alpha values.
@@ -32,11 +32,12 @@ public:
const int16_t runs[]);
/// Blit a vertical run of pixels with a constant alpha value.
virtual void blitV(int x, int y, int height, SkAlpha alpha);
- /// Blit a solid rectangle.
+ /// Blit a solid rectangle zero or more pixels wide.
virtual void blitRect(int x, int y, int width, int height);
/** Blit a rectangle with one alpha-blended column on the left,
- width opaque pixels, and one alpha-blended column on the right.
- Note that the result will always be at least two pixels wide.
+ width (zero or more) opaque pixels, and one alpha-blended column
+ on the right.
+ The result will always be at least two pixels wide.
*/
virtual void blitAntiRect(int x, int y, int width, int height,
SkAlpha leftAlpha, SkAlpha rightAlpha);
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp
index 6d2d51201c..265ae6b6ef 100644
--- a/src/core/SkBlitter.cpp
+++ b/src/core/SkBlitter.cpp
@@ -47,6 +47,7 @@ void SkBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
}
void SkBlitter::blitRect(int x, int y, int width, int height) {
+ SkASSERT(width >= 0);
while (--height >= 0) {
this->blitH(x, y++, width);
}
@@ -57,9 +58,12 @@ void SkBlitter::blitRect(int x, int y, int width, int height) {
/// may not support.
void SkBlitter::blitAntiRect(int x, int y, int width, int height,
SkAlpha leftAlpha, SkAlpha rightAlpha) {
- this->blitV(x, y, height, leftAlpha);
- this->blitRect(x + 1, y, width, height);
- this->blitV(x + width + 1, y, height, rightAlpha);
+ this->blitV(x++, y, height, leftAlpha);
+ if (width >= 0) {
+ this->blitRect(x, y, width, height);
+ x += width;
+ }
+ this->blitV(x, y, height, rightAlpha);
}
//////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp
index 4136636a66..fc7f737e13 100644
--- a/src/core/SkScan_AntiPath.cpp
+++ b/src/core/SkScan_AntiPath.cpp
@@ -307,8 +307,15 @@ void SuperBlitter::blitRect(int x, int y, int width, int height) {
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);
@@ -316,25 +323,21 @@ void SuperBlitter::blitRect(int x, int y, int width, int height) {
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);
- // here we go
- SkASSERT(start_y > fCurrIY);
- this->flush();
+ SkASSERT(coverageL > 0 || n > 0 || coverageR > 0);
+ SkASSERT((coverageL != 0) + n + (coverageR != 0) <= fWidth);
- // to be compatible with the blitH() version, we just shift these
- // values up. If we didn't care about that, we could be more precise
- // and compute these exactly (e.g. 2->128 instead of 2->124)
- //
- const int coverageL = coverage_to_exact_alpha(xleft);
- const int coverageR = coverage_to_exact_alpha(xrite);
- SkASSERT(n + (coverageR != 0) <= fWidth);
-
- SkASSERT(coverageL > 0 || n > 0 || coverageR > 0);
- fRealBlitter->blitAntiRect(ileft + fLeft, start_y, n, count,
- coverageL, coverageR);
+ fRealBlitter->blitAntiRect(ileft + fLeft, start_y, n, count,
+ coverageL, coverageR);
+ }
// preamble for our next call to blitH()
fCurrIY = stop_y - 1;