aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/aaclip.cpp29
-rw-r--r--include/core/SkGeometry.h47
-rw-r--r--include/core/SkTemplates.h3
-rw-r--r--src/core/SkScan_Hairline.cpp93
4 files changed, 125 insertions, 47 deletions
diff --git a/gm/aaclip.cpp b/gm/aaclip.cpp
index f59f6aa2b3..6ebb88c0dc 100644
--- a/gm/aaclip.cpp
+++ b/gm/aaclip.cpp
@@ -9,6 +9,34 @@
#include "SkCanvas.h"
#include "SkPath.h"
+static void draw_conic(SkCanvas* canvas, SkScalar weight, const SkPaint& paint) {
+ SkPath path;
+ path.moveTo(100, 100);
+ path.conicTo(300, 100, 300, 300, weight);
+ canvas->drawPath(path, paint);
+}
+
+static void test_conic(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ static const struct {
+ SkScalar fWeight;
+ SkColor fColor;
+ } gRec[] = {
+ { 2 , SK_ColorRED },
+ { 1 , SK_ColorGREEN },
+ { 0.5f, SK_ColorBLUE },
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
+ paint.setColor(gRec[i].fColor);
+ draw_conic(canvas, gRec[i].fWeight, paint);
+ canvas->translate(-30, 30);
+ }
+}
+
#include "SkGradientShader.h"
static void test_shallow_gradient(SkCanvas* canvas, SkScalar width, SkScalar height) {
SkColor colors[] = { 0xFF7F7F7F, 0xFF7F7F7F, 0xFF000000 };
@@ -219,6 +247,7 @@ protected:
}
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+ if (false) { test_conic(canvas); return; }
if (false) {
SkRect bounds;
canvas->getClipBounds(&bounds);
diff --git a/include/core/SkGeometry.h b/include/core/SkGeometry.h
index 2c37fff3e4..38cdf6e9b3 100644
--- a/include/core/SkGeometry.h
+++ b/include/core/SkGeometry.h
@@ -251,4 +251,51 @@ struct SkConic {
void computeFastBounds(SkRect* bounds) const;
};
+#include "SkTemplates.h"
+
+/**
+ * Help class to allocate storage for approximating a conic with N quads.
+ */
+class SkAutoConicToQuads {
+public:
+ SkAutoConicToQuads() : fQuadCount(0) {}
+
+ /**
+ * Given a conic and a tolerance, return the array of points for the
+ * approximating quad(s). Call countQuads() to know the number of quads
+ * represented in these points.
+ *
+ * The quads are allocated to share end-points. e.g. if there are 4 quads,
+ * there will be 9 points allocated as follows
+ * quad[0] == pts[0..2]
+ * quad[1] == pts[2..4]
+ * quad[2] == pts[4..6]
+ * quad[3] == pts[6..8]
+ */
+ const SkPoint* computeQuads(const SkConic& conic, SkScalar tol) {
+ int pow2 = conic.computeQuadPOW2(tol);
+ fQuadCount = 1 << pow2;
+ SkPoint* pts = fStorage.reset(1 + 2 * fQuadCount);
+ conic.chopIntoQuadsPOW2(pts, pow2);
+ return pts;
+ }
+
+ const SkPoint* computeQuads(const SkPoint pts[3], SkScalar weight,
+ SkScalar tol) {
+ SkConic conic;
+ conic.set(pts, weight);
+ return computeQuads(conic, tol);
+ }
+
+ int countQuads() const { return fQuadCount; }
+
+private:
+ enum {
+ kQuadCount = 8, // should handle most conics
+ kPointCount = 1 + 2 * kQuadCount,
+ };
+ SkAutoSTMalloc<kPointCount, SkPoint> fStorage;
+ int fQuadCount; // #quads for current usage
+};
+
#endif
diff --git a/include/core/SkTemplates.h b/include/core/SkTemplates.h
index bbbed48cea..e8a8b61ec8 100644
--- a/include/core/SkTemplates.h
+++ b/include/core/SkTemplates.h
@@ -366,7 +366,7 @@ public:
}
// doesn't preserve contents
- void reset(size_t count) {
+ T* reset(size_t count) {
if (fPtr != fTStorage) {
sk_free(fPtr);
}
@@ -377,6 +377,7 @@ public:
} else {
fPtr = NULL;
}
+ return fPtr;
}
T* get() const { return fPtr; }
diff --git a/src/core/SkScan_Hairline.cpp b/src/core/SkScan_Hairline.cpp
index 3245355a5d..f440d32613 100644
--- a/src/core/SkScan_Hairline.cpp
+++ b/src/core/SkScan_Hairline.cpp
@@ -212,58 +212,55 @@ static int compute_int_quad_dist(const SkPoint pts[3]) {
}
}
-static void hairquad(const SkPoint pts[3], const SkRegion* clip, SkBlitter* blitter, int level,
- void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion* clip, SkBlitter*))
-{
-#if 1
- if (level > 0)
- {
+typedef void (*LineProc)(const SkPoint&, const SkPoint&, const SkRegion*,
+ SkBlitter*);
+
+static void hairquad(const SkPoint pts[3], const SkRegion* clip,
+ SkBlitter* blitter, int level, LineProc lineproc) {
+ if (level > 0) {
SkPoint tmp[5];
SkChopQuadAtHalf(pts, tmp);
hairquad(tmp, clip, blitter, level - 1, lineproc);
hairquad(&tmp[2], clip, blitter, level - 1, lineproc);
- }
- else
+ } else {
lineproc(pts[0], pts[2], clip, blitter);
-#else
- int count = 1 << level;
- const SkScalar dt = SkFixedToScalar(SK_Fixed1 >> level);
- SkScalar t = dt;
- SkPoint prevPt = pts[0];
- for (int i = 1; i < count; i++) {
- SkPoint nextPt;
- SkEvalQuadAt(pts, t, &nextPt);
- lineproc(prevPt, nextPt, clip, blitter);
- t += dt;
- prevPt = nextPt;
}
- // draw the last line explicitly to 1.0, in case t didn't match that exactly
- lineproc(prevPt, pts[2], clip, blitter);
-#endif
}
-static void haircubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* blitter, int level,
- void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion*, SkBlitter*))
-{
- if (level > 0)
- {
+static void haircubic(const SkPoint pts[4], const SkRegion* clip,
+ SkBlitter* blitter, int level, LineProc lineproc) {
+ if (level > 0) {
SkPoint tmp[7];
SkChopCubicAt(pts, tmp, SK_Scalar1/2);
haircubic(tmp, clip, blitter, level - 1, lineproc);
haircubic(&tmp[3], clip, blitter, level - 1, lineproc);
- }
- else
+ } else {
lineproc(pts[0], pts[3], clip, blitter);
+ }
}
#define kMaxCubicSubdivideLevel 6
#define kMaxQuadSubdivideLevel 5
-static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter,
- void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion*, SkBlitter*))
-{
+static int compute_quad_level(const SkPoint pts[3]) {
+ int d = compute_int_quad_dist(pts);
+ /* quadratics approach the line connecting their start and end points
+ 4x closer with each subdivision, so we compute the number of
+ subdivisions to be the minimum need to get that distance to be less
+ than a pixel.
+ */
+ int level = (33 - SkCLZ(d)) >> 1;
+ // sanity check on level (from the previous version)
+ if (level > kMaxQuadSubdivideLevel) {
+ level = kMaxQuadSubdivideLevel;
+ }
+ return level;
+}
+
+static void hair_path(const SkPath& path, const SkRasterClip& rclip,
+ SkBlitter* blitter, LineProc lineproc) {
if (path.isEmpty()) {
return;
}
@@ -293,32 +290,36 @@ static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter*
SkPath::Iter iter(path, false);
SkPoint pts[4];
SkPath::Verb verb;
+ SkAutoConicToQuads converter;
while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
switch (verb) {
+ case SkPath::kMove_Verb:
+ break;
case SkPath::kLine_Verb:
lineproc(pts[0], pts[1], clip, blitter);
break;
- case SkPath::kQuad_Verb: {
- int d = compute_int_quad_dist(pts);
- /* quadratics approach the line connecting their start and end points
- 4x closer with each subdivision, so we compute the number of
- subdivisions to be the minimum need to get that distance to be less
- than a pixel.
- */
- int level = (33 - SkCLZ(d)) >> 1;
- // SkDebugf("----- distance %d computedLevel %d\n", d, computedLevel);
- // sanity check on level (from the previous version)
- if (level > kMaxQuadSubdivideLevel) {
- level = kMaxQuadSubdivideLevel;
+ case SkPath::kQuad_Verb:
+ hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc);
+ break;
+ case SkPath::kConic_Verb: {
+ // how close should the quads be to the original conic?
+ const SkScalar tol = SK_Scalar1 / 4;
+ const SkPoint* quadPts = converter.computeQuads(pts,
+ iter.conicWeight(), tol);
+ for (int i = 0; i < converter.countQuads(); ++i) {
+ int level = compute_quad_level(quadPts);
+ hairquad(quadPts, clip, blitter, level, lineproc);
+ quadPts += 2;
}
- hairquad(pts, clip, blitter, level, lineproc);
break;
}
case SkPath::kCubic_Verb:
haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc);
break;
- default:
+ case SkPath::kClose_Verb:
+ break;
+ case SkPath::kDone_Verb:
break;
}
}