| Index: src/core/SkScan_Path.cpp
|
| diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp
|
| index fc79fc8537d08fdbff306ee801a2fa66a5a9a6a2..dbe61e13d207e55376140c69fae7e300125dcea3 100644
|
| --- a/src/core/SkScan_Path.cpp
|
| +++ b/src/core/SkScan_Path.cpp
|
| @@ -14,9 +14,14 @@
|
| #include "SkQuadClipper.h"
|
| #include "SkRasterClip.h"
|
| #include "SkRegion.h"
|
| +#include "SkStroke.h"
|
| #include "SkTemplates.h"
|
| #include "SkTSort.h"
|
|
|
| +#include <stdio.h> // FIXME
|
| +
|
| +static bool dumping;
|
| +
|
| #define kEDGE_HEAD_Y SK_MinS32
|
| #define kEDGE_TAIL_Y SK_MaxS32
|
|
|
| @@ -48,6 +53,105 @@ static inline void insert_edge_after(SkEdge* edge, SkEdge* afterMe) {
|
| afterMe->fNext = edge;
|
| }
|
|
|
| +static void emit_wireframe_triangle(SkPoint t[3], SkTDArray<SkPoint>* points) {
|
| + SkPoint *p = points->append(6);
|
| + p[0] = t[0];
|
| + p[1] = t[1];
|
| + p[2] = t[1];
|
| + p[3] = t[2];
|
| + p[4] = t[2];
|
| + p[5] = t[0];
|
| +}
|
| +
|
| +static void emit_trapezoid(SkEdge* left, SkEdge* right, float top, float bottom, SkTDArray<SkPoint>* points)
|
| +{
|
| + // If this edge was already neutered by its partner, don't emit.
|
| + if (top > bottom) {
|
| + return;
|
| + }
|
| +
|
| + if (!left || !right) {
|
| + return;
|
| + }
|
| +
|
| + float top_left = left->fFirstXf;
|
| + float top_right = right->fFirstXf;
|
| + float bottom_left = left->fFirstXf + SkFixedToFloat(left->fDX * (bottom - top));
|
| + float bottom_right = right->fFirstXf + SkFixedToFloat(right->fDX * (bottom - top));
|
| + if (dumping) {
|
| + printf("top %g bot %g tl %g tr %g bl %g br %g\n",
|
| + top, bottom, left->fFirstXf, right->fFirstXf, bottom_left, bottom_right);
|
| + }
|
| + if (SkScan::gWireframe) {
|
| + if (top_left == top_right) {
|
| + SkPoint p[3];
|
| + p[0] = SkPoint::Make(top_right, top);
|
| + p[1] = SkPoint::Make(bottom_right, bottom);
|
| + p[2] = SkPoint::Make(bottom_left , bottom);
|
| + emit_wireframe_triangle(p, points);
|
| + } else if (bottom_left == bottom_right) {
|
| + SkPoint p[3];
|
| + p[0] = SkPoint::Make(top_left, top);
|
| + p[1] = SkPoint::Make(top_right, top);
|
| + p[2] = SkPoint::Make(bottom_left, bottom);
|
| + emit_wireframe_triangle(p, points);
|
| + } else {
|
| + SkPoint p[3];
|
| + p[0] = SkPoint::Make(top_left, top);
|
| + p[1] = SkPoint::Make(top_right, top);
|
| + p[2] = SkPoint::Make(bottom_left , bottom);
|
| + emit_wireframe_triangle(p, points);
|
| + p[0] = SkPoint::Make(top_right, top);
|
| + p[1] = SkPoint::Make(bottom_right, bottom);
|
| + p[2] = SkPoint::Make(bottom_left , bottom);
|
| + emit_wireframe_triangle(p, points);
|
| + }
|
| + } else {
|
| + if (top_left == top_right) {
|
| + SkPoint *p = points->append(3);
|
| + p[0] = SkPoint::Make(top_right, top);
|
| + p[1] = SkPoint::Make(bottom_right, bottom);
|
| + p[2] = SkPoint::Make(bottom_left , bottom);
|
| + } else if (bottom_left == bottom_right) {
|
| + SkPoint *p = points->append(3);
|
| + p[0] = SkPoint::Make(top_left, top);
|
| + p[1] = SkPoint::Make(top_right, top);
|
| + p[2] = SkPoint::Make(bottom_left, bottom);
|
| + } else {
|
| + SkPoint *p = points->append(6);
|
| + p[0] = SkPoint::Make(top_left, top);
|
| + p[1] = SkPoint::Make(top_right, top);
|
| + p[2] = SkPoint::Make(bottom_left , bottom);
|
| + p[3] = SkPoint::Make(top_right, top);
|
| + p[4] = SkPoint::Make(bottom_right, bottom);
|
| + p[5] = SkPoint::Make(bottom_left , bottom);
|
| + }
|
| + }
|
| + left->fFirstXf = bottom_left;
|
| + left->fFirstYf = bottom;
|
| + right->fFirstXf = bottom_right;
|
| + right->fFirstYf = bottom;
|
| +}
|
| +
|
| +static void emit_all_trapezoids(SkEdge* start, int windingMask, int curr_y, SkTDArray<SkPoint>* points)
|
| +{
|
| + int w = 0;
|
| + SkEdge* left = NULL;
|
| + for (SkEdge* edge = start; edge != NULL && edge->fFirstY < curr_y && edge->fFirstYf < curr_y; edge = edge->fNext) {
|
| + w += edge->fWinding;
|
| + if ((w & windingMask) == 0) {
|
| + SkASSERT(left);
|
| + emit_trapezoid(left, edge, left->fFirstYf, curr_y, points);
|
| + left = NULL;
|
| + } else if (!left) {
|
| + left = edge;
|
| + } else {
|
| + edge->fFirstXf += SkFixedToFloat(edge->fDX * (curr_y - edge->fFirstYf));
|
| + edge->fFirstYf = (float) curr_y;
|
| + }
|
| + }
|
| +}
|
| +
|
| static void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, curr_y)) {
|
| SkFixed x = edge->fX;
|
|
|
| @@ -97,8 +201,8 @@ typedef void (*PrePostProc)(SkBlitter* blitter, int y, bool isStartOfScanline);
|
| #define PREPOST_END false
|
|
|
| static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
|
| - SkBlitter* blitter, int start_y, int stop_y,
|
| - PrePostProc proc, int rightClip) {
|
| + SkBlitter* blitter, SkTDArray<SkPoint>* points,
|
| + int start_y, int stop_y, PrePostProc proc, int rightClip) {
|
| validate_sort(prevHead->fNext);
|
|
|
| int curr_y = start_y;
|
| @@ -114,7 +218,7 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
|
|
|
| validate_edges_for_y(currE, curr_y);
|
|
|
| - if (proc) {
|
| + if (proc && blitter) {
|
| proc(blitter, curr_y, PREPOST_START); // pre-proc
|
| }
|
|
|
| @@ -127,8 +231,11 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
|
| SkASSERT(in_interval);
|
| int width = x - left;
|
| SkASSERT(width >= 0);
|
| - if (width)
|
| - blitter->blitH(left, curr_y, width);
|
| + if (width) {
|
| + if (blitter) {
|
| + blitter->blitH(left, curr_y, width);
|
| + }
|
| + }
|
| in_interval = false;
|
| } else if (!in_interval) {
|
| left = x;
|
| @@ -139,6 +246,7 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
|
| SkFixed newX;
|
|
|
| if (currE->fLastY == curr_y) { // are we done with this edge?
|
| + if (points) emit_all_trapezoids(prevHead->fNext, windingMask, curr_y + 1, points);
|
| if (currE->fCurveCount < 0) {
|
| if (((SkCubicEdge*)currE)->updateCubic()) {
|
| SkASSERT(currE->fFirstY == curr_y + 1);
|
| @@ -159,6 +267,7 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
|
| currE->fX = newX;
|
| NEXT_X:
|
| if (newX < prevX) { // ripple currE backwards until it is x-sorted
|
| + if (points) emit_all_trapezoids(prevHead->fNext, windingMask, curr_y + 1, points);
|
| backward_insert_edge_based_on_x(currE SkPARAM(curr_y));
|
| } else {
|
| prevX = newX;
|
| @@ -169,14 +278,14 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
|
| }
|
|
|
| // was our right-edge culled away?
|
| - if (in_interval) {
|
| + if (in_interval && blitter) {
|
| int width = rightClip - left;
|
| if (width > 0) {
|
| blitter->blitH(left, curr_y, width);
|
| }
|
| }
|
|
|
| - if (proc) {
|
| + if (proc && blitter) {
|
| proc(blitter, curr_y, PREPOST_END); // post-proc
|
| }
|
|
|
| @@ -184,6 +293,9 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
|
| if (curr_y >= stop_y) {
|
| break;
|
| }
|
| + if (points && currE->fFirstY == curr_y) {
|
| + emit_all_trapezoids(prevHead->fNext, windingMask, curr_y, points);
|
| + }
|
| // now currE points to the first edge with a Yint larger than curr_y
|
| insert_new_edges(currE, curr_y);
|
| }
|
| @@ -210,7 +322,8 @@ static bool update_edge(SkEdge* edge, int last_y) {
|
| }
|
|
|
| static void walk_convex_edges(SkEdge* prevHead, SkPath::FillType,
|
| - SkBlitter* blitter, int start_y, int stop_y,
|
| + SkBlitter* blitter, SkTDArray<SkPoint>* points,
|
| + int start_y, int stop_y,
|
| PrePostProc proc) {
|
| validate_sort(prevHead->fNext);
|
|
|
| @@ -247,12 +360,22 @@ static void walk_convex_edges(SkEdge* prevHead, SkPath::FillType,
|
| SkFixed dRite = riteE->fDX;
|
| int count = local_bot - local_top;
|
| SkASSERT(count >= 0);
|
| - if (0 == (dLeft | dRite)) {
|
| + if (points) {
|
| + emit_trapezoid(leftE, riteE, (float) local_top, (float) (local_bot + 1), points);
|
| + if (left < rite) {
|
| + count += 1;
|
| + left += count * dLeft;
|
| + rite += count * dRite;
|
| + }
|
| + local_top = local_bot + 1;
|
| + } else if (0 == (dLeft | dRite)) {
|
| int L = SkFixedRoundToInt(left);
|
| int R = SkFixedRoundToInt(rite);
|
| if (L < R) {
|
| count += 1;
|
| blitter->blitRect(L, local_top, R - L, count);
|
| + left += count * dLeft;
|
| + rite += count * dRite;
|
| }
|
| local_top = local_bot + 1;
|
| } else {
|
| @@ -394,14 +517,16 @@ static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) {
|
| //
|
| // clipRect (if no null) has already been shifted up
|
| //
|
| -void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitter,
|
| - int start_y, int stop_y, int shiftEdgesUp, const SkRegion& clipRgn) {
|
| - SkASSERT(blitter);
|
| +void sk_fill_path(const SkPath& path, const SkIRect* clipRect,
|
| + SkBlitter* blitter, SkTDArray<SkPoint>* points,
|
| + int start_y, int stop_y, int shiftEdgesUp,
|
| + const SkRegion& clipRgn) {
|
| + SkASSERT(blitter || points);
|
|
|
| SkEdgeBuilder builder;
|
|
|
| // If we're convex, then we need both edges, even the right edge is past the clip
|
| - const bool canCullToTheRight = !path.isConvex();
|
| + const bool canCullToTheRight = !path.isConvex() && !points;
|
|
|
| int count = builder.build(path, clipRect, shiftEdgesUp, canCullToTheRight);
|
| SkASSERT(count >= 0);
|
| @@ -424,18 +549,32 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
|
| rect.fBottom = stop_y;
|
| }
|
| if (!rect.isEmpty()) {
|
| - blitter->blitRect(rect.fLeft << shiftEdgesUp,
|
| - rect.fTop << shiftEdgesUp,
|
| - rect.width() << shiftEdgesUp,
|
| - rect.height() << shiftEdgesUp);
|
| + if (blitter) {
|
| + blitter->blitRect(rect.fLeft << shiftEdgesUp,
|
| + rect.fTop << shiftEdgesUp,
|
| + rect.width() << shiftEdgesUp,
|
| + rect.height() << shiftEdgesUp);
|
| + } else {
|
| + SkRect r = SkRect::Make(rect);
|
| + r.toQuad(points->append(4));
|
| + }
|
| }
|
| }
|
| +
|
| return;
|
| }
|
|
|
| SkEdge headEdge, tailEdge, *last;
|
| // this returns the first and last edge after they're sorted into a dlink list
|
| SkEdge* edge = sort_edges(list, count, &last);
|
| + if (dumping) {
|
| + printf("sorted into %d edges:\n", count);
|
| + SkEdge* e = edge;
|
| + for (int i = 0; i < count; i++) {
|
| + printf("edge %p fFirstXf %g fFirstYf %g fLastY %d fDX %g\n", e, e->fFirstXf, e->fFirstYf, e->fLastY, e->fDX / 65536.0);
|
| + e = e->fNext;
|
| + }
|
| + }
|
|
|
| headEdge.fPrev = nullptr;
|
| headEdge.fNext = edge;
|
| @@ -462,15 +601,15 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
|
| InverseBlitter ib;
|
| PrePostProc proc = nullptr;
|
|
|
| - if (path.isInverseFillType()) {
|
| + if (path.isInverseFillType() && blitter) {
|
| ib.setBlitter(blitter, clipRgn.getBounds(), shiftEdgesUp);
|
| blitter = &ib;
|
| proc = PrePostInverseBlitterProc;
|
| }
|
|
|
| - if (path.isConvex() && (nullptr == proc)) {
|
| + if (path.isConvex() && (nullptr == proc) && blitter) {
|
| SkASSERT(count >= 2); // convex walker does not handle missing right edges
|
| - walk_convex_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, nullptr);
|
| + walk_convex_edges(&headEdge, path.getFillType(), blitter, points, start_y, stop_y, NULL);
|
| } else {
|
| int rightEdge;
|
| if (clipRect) {
|
| @@ -478,8 +617,8 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
|
| } else {
|
| rightEdge = SkScalarRoundToInt(path.getBounds().right()) << shiftEdgesUp;
|
| }
|
| -
|
| - walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc, rightEdge);
|
| +
|
| + walk_edges(&headEdge, path.getFillType(), blitter, points, start_y, stop_y, proc, rightEdge);
|
| }
|
| }
|
|
|
| @@ -599,7 +738,7 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& origClip,
|
| if (path.isInverseFillType()) {
|
| sk_blit_above(blitter, ir, *clipPtr);
|
| }
|
| - sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom,
|
| + sk_fill_path(path, clipper.getClipRect(), blitter, NULL, ir.fTop, ir.fBottom,
|
| 0, *clipPtr);
|
| if (path.isInverseFillType()) {
|
| sk_blit_below(blitter, ir, *clipPtr);
|
| @@ -673,8 +812,8 @@ static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect,
|
| if (clipRect && start_y < clipRect->fTop) {
|
| start_y = clipRect->fTop;
|
| }
|
| - walk_convex_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, nullptr);
|
| -// walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, nullptr);
|
| + walk_convex_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, nullptr, start_y, stop_y, nullptr);
|
| +// walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, NULL);
|
| }
|
|
|
| void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip,
|
| @@ -707,3 +846,39 @@ void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip,
|
| sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir);
|
| }
|
| }
|
| +
|
| +void SkScan::PathToTriangles(const SkPath& path, const SkIRect& clipBounds,
|
| + bool antiAlias, SkTDArray<SkPoint>* points) {
|
| +// dumping = true;
|
| +// printf("*** SkScan::PathToTriangles start\n");
|
| + points->setReserve(path.countPoints());
|
| + SkPath localPath = path;
|
| + SkIRect localClipBounds = clipBounds;
|
| + if (antiAlias) {
|
| + // Stroke 1-pix wide around path.
|
| + SkStroke stroker;
|
| + stroker.setJoin(SkPaint::kMiter_Join);
|
| + stroker.setWidth(5);
|
| + SkPath strokedPath;
|
| + // We want even open paths to become closed, so we can fill them.
|
| + stroker.setAutoClose(true);
|
| + // Don't reverse the inner path direction, since want the interior to be filled.
|
| + stroker.setReverseInner(false);
|
| + stroker.strokePath(localPath, &strokedPath);
|
| + localPath = strokedPath;
|
| + }
|
| + SkRect pathBounds = localPath.getBounds();
|
| + SkRegion clipRgn(localClipBounds);
|
| + if (localPath.isInverseFillType()) {
|
| + localPath.addRect(SkRect::Make(localClipBounds), SkPath::kCCW_Direction);
|
| + sk_fill_path(localPath, &localClipBounds, NULL, points,
|
| + localClipBounds.top(), localClipBounds.bottom(), 0,
|
| + clipRgn);
|
| + } else {
|
| + sk_fill_path(localPath, &localClipBounds, NULL, points,
|
| + pathBounds.top() - 1, pathBounds.bottom() + 1, 0,
|
| + clipRgn);
|
| + }
|
| +// printf("*** SkScan::PathToTriangles end\n");
|
| +// dumping = false;
|
| +}
|
|
|