Use clippedIR instead of clipBounds to filter coverage deltas

Due to precision limit, some cubics may generate lines exceeding
the path's IR. Since we created delta list or delta mask using
clippedIR, it's important that we use the stricter clippedIR
instead of clipBounds to filter the coverage deltas.

Bug: oss-fuzz:6189
Change-Id: I775408282fb45ada41968426c2f32d28bb567af1
Reviewed-on: https://skia-review.googlesource.com/113160
Commit-Queue: Yuqian Li <liyuqian@google.com>
Reviewed-by: Cary Clark <caryclark@google.com>
This commit is contained in:
Yuqian Li 2018-03-08 13:39:27 -05:00 committed by Skia Commit-Bot
parent 2091fe26fe
commit 8b0ef635fd

View File

@ -150,21 +150,23 @@ public:
};
template<class Deltas> static SK_ALWAYS_INLINE
void gen_alpha_deltas(const SkPath& path, const SkIRect& clipBounds, Deltas& result,
SkBlitter* blitter, bool skipRect, bool pathContainedInClip) {
void gen_alpha_deltas(const SkPath& path, const SkIRect& clippedIR, const SkIRect& clipBounds,
Deltas& result, SkBlitter* blitter, bool skipRect, bool pathContainedInClip) {
// 1. Build edges
SkEdgeBuilder builder;
SkIRect ir = path.getBounds().roundOut();
int count = builder.build_edges(path, &clipBounds, 0, pathContainedInClip,
SkEdgeBuilder::kBezier);
// We have to use clipBounds instead of clippedIR to build edges because of "canCullToTheRight":
// if the builder finds a right edge past the right clip, it won't build that right edge.
int count = builder.build_edges(path, &clipBounds, 0, pathContainedInClip,
SkEdgeBuilder::kBezier);
if (count == 0) {
return;
}
SkBezier** list = builder.bezierList();
// 2. Try to find the rect part because blitAntiRect is so much faster than blitCoverageDeltas
int rectTop = ir.fBottom; // the rect is initialized to be empty as top = bot
int rectBot = ir.fBottom;
int rectTop = clippedIR.fBottom; // the rect is initialized to be empty as top = bot
int rectBot = clippedIR.fBottom;
if (skipRect) { // only find that rect is skipRect == true
YLessThan lessThan; // sort edges in YX order
SkTQSort(list, list + count - 1, lessThan);
@ -196,7 +198,7 @@ void gen_alpha_deltas(const SkPath& path, const SkIRect& clipBounds, Deltas& res
SkAlpha ra = (r.fUpperX - SkIntToFixed(R)) >> 8;
result.setAntiRect(L - 1, rectTop, R - L, rectBot - rectTop, la, ra);
} else { // too thin to use blitAntiRect; reset the rect region to be emtpy
rectTop = rectBot = ir.fBottom;
rectTop = rectBot = clippedIR.fBottom;
}
}
break;
@ -265,7 +267,7 @@ void gen_alpha_deltas(const SkPath& path, const SkIRect& clipBounds, Deltas& res
if (lowerCeil <= upperFloor + SK_Fixed1) { // only one row is affected by the currE
SkFixed rowHeight = currE->fLowerY - currE->fUpperY;
SkFixed nextX = currE->fX + SkFixedMul(currE->fDX, rowHeight);
if (iy >= clipBounds.fTop && iy < clipBounds.fBottom) {
if (iy >= clippedIR.fTop && iy < clippedIR.fBottom) {
add_coverage_delta_segment<true>(iy, rowHeight, currE, nextX, &result);
}
continue;
@ -305,7 +307,7 @@ void gen_alpha_deltas(const SkPath& path, const SkIRect& clipBounds, Deltas& res
// last partial row
if (SkIntToFixed(iy) < currE->fLowerY &&
iy >= clipBounds.fTop && iy < clipBounds.fBottom) {
iy >= clippedIR.fTop && iy < clippedIR.fBottom) {
rowHeight = currE->fLowerY - SkIntToFixed(iy);
nextX = currE->fX + SkFixedMul(currE->fDX, rowHeight);
add_coverage_delta_segment<true>(iy, rowHeight, currE, nextX, &result);
@ -358,14 +360,16 @@ void SkScan::DAAFillPath(const SkPath& path, SkBlitter* blitter, const SkIRect&
if (!forceRLE && !isInverse && SkCoverageDeltaMask::Suitable(clippedIR)) {
record->fType = SkDAARecord::Type::kMask;
SkCoverageDeltaMask deltaMask(alloc, clippedIR);
gen_alpha_deltas(path, clipBounds, deltaMask, blitter, skipRect, containedInClip);
gen_alpha_deltas(path, clippedIR, clipBounds, deltaMask, blitter, skipRect,
containedInClip);
deltaMask.convertCoverageToAlpha(isEvenOdd, isInverse, isConvex);
record->fMask = deltaMask.prepareSkMask();
} else {
record->fType = SkDAARecord::Type::kList;
SkCoverageDeltaList* deltaList = alloc->make<SkCoverageDeltaList>(
alloc, clippedIR.fTop, clippedIR.fBottom, forceRLE);
gen_alpha_deltas(path, clipBounds, *deltaList, blitter, skipRect, containedInClip);
gen_alpha_deltas(path, clippedIR, clipBounds, *deltaList, blitter, skipRect,
containedInClip);
record->fList = deltaList;
}
}