diff options
-rw-r--r-- | gm/aaclip.cpp | 29 | ||||
-rw-r--r-- | include/core/SkGeometry.h | 47 | ||||
-rw-r--r-- | include/core/SkTemplates.h | 3 | ||||
-rw-r--r-- | src/core/SkScan_Hairline.cpp | 93 |
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; } } |