aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-10-26 15:03:48 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-10-26 15:03:48 +0000
commit209c41511eb0d06f8c19f8fb1fc0393c502a1b18 (patch)
treebd83511d61c0005c91b6f5a25be221fa6183c5ce
parent67cdbf5c63cfd77523d2a3070a44a200fabf0739 (diff)
add initial unittests for aaclip. Fix case where BuilderBlitter skipped the top
few scanlines (of its bounds) and therefore didn't know to trim its bounds back down. This can happen when the path's bounds are larger than the curve's bounds (i.e. the control points are outside of the tight-bounds of the shape.) git-svn-id: http://skia.googlecode.com/svn/trunk@2534 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--gyp/tests.gyp1
-rw-r--r--src/core/SkAAClip.cpp38
-rw-r--r--tests/AAClipTest.cpp43
3 files changed, 81 insertions, 1 deletions
diff --git a/gyp/tests.gyp b/gyp/tests.gyp
index ede5885864..d1904876f0 100644
--- a/gyp/tests.gyp
+++ b/gyp/tests.gyp
@@ -13,6 +13,7 @@
'../src/gpu',
],
'sources': [
+ '../tests/AAClipTest.cpp',
'../tests/BitmapCopyTest.cpp',
'../tests/BitmapGetColorTest.cpp',
'../tests/BitSetTest.cpp',
diff --git a/src/core/SkAAClip.cpp b/src/core/SkAAClip.cpp
index dd388950a9..d9cc181f74 100644
--- a/src/core/SkAAClip.cpp
+++ b/src/core/SkAAClip.cpp
@@ -478,12 +478,14 @@ class SkAAClip::Builder {
Row* fCurrRow;
int fPrevY;
int fWidth;
+ int fMinY;
public:
Builder(const SkIRect& bounds) : fBounds(bounds) {
fPrevY = -1;
fWidth = bounds.width();
fCurrRow = NULL;
+ fMinY = bounds.fTop;
}
~Builder() {
@@ -550,6 +552,11 @@ public:
return target->setEmpty();
}
+ SkASSERT(fMinY >= fBounds.fTop);
+ SkASSERT(fMinY < fBounds.fBottom);
+ int adjustY = fMinY - fBounds.fTop;
+ fBounds.fTop = fMinY;
+
RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
YOffset* yoffset = head->yoffsets();
uint8_t* data = head->data();
@@ -557,7 +564,7 @@ public:
row = fRows.begin();
while (row < stop) {
- yoffset->fY = row->fY;
+ yoffset->fY = row->fY - adjustY;
yoffset->fOffset = data - baseData;
yoffset += 1;
@@ -614,7 +621,13 @@ public:
#endif
}
+ // only called by BuilderBlitter
+ void setMinY(int y) {
+ fMinY = y;
+ }
+
private:
+
Row* flushRow(bool readyForAnother) {
Row* next = NULL;
int count = fRows.count();
@@ -676,6 +689,13 @@ public:
fBuilder = builder;
fLeft = builder->getBounds().fLeft;
fRight = builder->getBounds().fRight;
+ fMinY = SK_MaxS32;
+ }
+
+ void finish() {
+ if (fMinY < SK_MaxS32) {
+ fBuilder->setMinY(fMinY);
+ }
}
virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE
@@ -692,11 +712,13 @@ public:
}
virtual void blitH(int x, int y, int width) SK_OVERRIDE {
+ this->recordMinY(y);
fBuilder->addRun(x, y, 0xFF, width);
}
virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
const int16_t runs[]) SK_OVERRIDE {
+ this->recordMinY(y);
for (;;) {
int count = *runs;
if (count <= 0) {
@@ -736,6 +758,19 @@ private:
Builder* fBuilder;
int fLeft; // cache of builder's bounds' left edge
int fRight;
+ int fMinY;
+
+ /*
+ * We track this, in case the scan converter skipped some number of
+ * scanlines at the (relative to the bounds it was given). This allows
+ * the builder, during its finish, to trip its bounds down to the "real"
+ * top.
+ */
+ void recordMinY(int y) {
+ if (y < fMinY) {
+ fMinY = y;
+ }
+ }
void unexpected() {
SkDebugf("---- did not expect to get called here");
@@ -776,6 +811,7 @@ bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
SkScan::FillPath(path, *clip, &blitter);
}
+ blitter.finish();
return builder.finish(this);
}
diff --git a/tests/AAClipTest.cpp b/tests/AAClipTest.cpp
new file mode 100644
index 0000000000..a66e69a5be
--- /dev/null
+++ b/tests/AAClipTest.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "SkAAClip.h"
+#include "SkPath.h"
+
+static void test_trim_bounds(skiatest::Reporter* reporter) {
+ SkPath path;
+ SkAAClip clip;
+ const int height = 40;
+ const SkScalar sheight = SkIntToScalar(height);
+
+ path.addOval(SkRect::MakeWH(sheight, sheight));
+ REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
+ clip.setPath(path, NULL, true);
+ REPORTER_ASSERT(reporter, height == clip.getBounds().height());
+
+ // this is the trimmed height of this cubic (with aa). The critical thing
+ // for this test is that it is less than height, which represents just
+ // the bounds of the path's control-points.
+ //
+ // This used to fail until we tracked the MinY in the BuilderBlitter.
+ //
+ const int teardrop_height = 12;
+ path.reset();
+ path.moveTo(0, 20);
+ path.cubicTo(40, 40, 40, 0, 0, 20);
+ REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
+ clip.setPath(path, NULL, true);
+ REPORTER_ASSERT(reporter, teardrop_height == clip.getBounds().height());
+}
+
+static void TestAAClip(skiatest::Reporter* reporter) {
+ test_trim_bounds(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("AAClip", AAClipTestClass, TestAAClip)