GrTessellator: fix for overlapping outer boundary edges in AA case.

When inflating outer path boundaries for edge AA, two outer boundary
edges may be collinear. In this case, they form part of the overlap
region, but they must not be removed on collapse, since they form
part of the outer boundary of the shape.

Bug: 846655
Change-Id: I4808b570cc4f82d6202862f7a8ecf0f8add771ef
Reviewed-on: https://skia-review.googlesource.com/132084
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Stephen White 2018-06-05 09:15:59 -04:00 committed by Skia Commit-Bot
parent 35f06df995
commit 77169c8fd6
2 changed files with 41 additions and 6 deletions

View File

@ -116,6 +116,21 @@ void draw_pointy_golf_club(SkCanvas* canvas, const SkPaint& paint, SkScalar widt
canvas->drawPath(path, paint);
}
void draw_small_i(SkCanvas* canvas, const SkPaint& paint, SkScalar width) {
SkPath path;
path.moveTo(1.25 - width, 18.75 + width);
path.lineTo(1.25 - width, 12.25 - width);
path.lineTo(2.50 + width, 12.25 - width);
path.lineTo(2.50 + width, 18.75 + width);
path.moveTo(1.25 - width, 11.75 + width);
path.lineTo(1.25 - width, 10.25 - width);
path.lineTo(2.50 + width, 10.25 - width);
path.lineTo(2.50 + width, 11.75 + width);
canvas->drawPath(path, paint);
}
};
DEF_SIMPLE_GM(thinconcavepaths, canvas, 550, 400) {
@ -181,4 +196,11 @@ DEF_SIMPLE_GM(thinconcavepaths, canvas, 550, 400) {
}
canvas->restore();
canvas->translate(100, 0);
canvas->save();
for (SkScalar width = 0.0f; width < 0.5f; width += 0.05f) {
draw_small_i(canvas, paint, width);
canvas->translate(0, 30);
}
canvas->restore();
canvas->translate(100, 0);
}

View File

@ -479,10 +479,12 @@ struct EdgeList {
};
struct Event {
Event(Edge* edge, const SkPoint& point, uint8_t alpha)
: fEdge(edge), fPoint(point), fAlpha(alpha), fPrev(nullptr), fNext(nullptr) {
Event(Edge* edge, bool isOuterBoundary, const SkPoint& point, uint8_t alpha)
: fEdge(edge), fIsOuterBoundary(isOuterBoundary), fPoint(point), fAlpha(alpha)
, fPrev(nullptr), fNext(nullptr) {
}
Edge* fEdge;
bool fIsOuterBoundary;
SkPoint fPoint;
uint8_t fAlpha;
Event* fPrev;
@ -496,7 +498,7 @@ bool compare(Event* const& e1, Event* const& e2) {
struct EventList : public SkTDPQueue<Event*, &compare> {};
void create_event(Edge* e, EventList* events, SkArenaAlloc& alloc) {
void create_event(Edge* e, bool isOuterBoundary, EventList* events, SkArenaAlloc& alloc) {
Edge bisector1(e->fTop, e->fTop->fPartner, 1, Edge::Type::kConnector);
Edge bisector2(e->fBottom, e->fBottom->fPartner, 1, Edge::Type::kConnector);
SkPoint p;
@ -504,7 +506,7 @@ void create_event(Edge* e, EventList* events, SkArenaAlloc& alloc) {
if (bisector1.intersect(bisector2, &p, &alpha)) {
LOG("found overlap edge %g -> %g, will collapse to %g,%g alpha %d\n",
e->fTop->fID, e->fBottom->fID, p.fX, p.fY, alpha);
e->fEvent = alloc.make<Event>(e, p, alpha);
e->fEvent = alloc.make<Event>(e, isOuterBoundary, p, alpha);
events->insert(e->fEvent);
}
}
@ -1691,7 +1693,15 @@ void Event::apply(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
// Since the destination has multiple partners, give it none.
dest->fPartner = nullptr;
disconnect(fEdge);
// Disconnect all collapsed edges except outer boundaries.
// Those are required to preserve shape coverage and winding correctness.
if (!fIsOuterBoundary) {
disconnect(fEdge);
} else {
LOG("edge %g -> %g is outer boundary; not disconnecting.\n",
fEdge->fTop->fID, fEdge->fBottom->fID);
}
// If top still has some connected edges, set its partner to dest.
top->fPartner = top->fFirstEdgeAbove || top->fFirstEdgeBelow ? dest : nullptr;
@ -1738,7 +1748,10 @@ bool collapse_overlap_regions(VertexList* mesh, Comparator& c, SkArenaAlloc& all
}
e->fOverlap = e->fOverlap || is_overlap_edge(e);
if (e->fOverlap) {
create_event(e, &events, alloc);
// If this edge borders a zero-winding area, it's a boundary; don't disconnect it.
bool isOuterBoundary = e->fType == Edge::Type::kOuter &&
(!prev || prev->fWinding == 0 || e->fWinding == 0);
create_event(e, isOuterBoundary, &events, alloc);
}
insert_edge(e, prev, &activeEdges);
prev = e;