handle clipping large triangles

originally found by fuzzer.

Bug: skia:
Change-Id: I45007a619f13936153c0db8a60b3631a2c9db20c
Reviewed-on: https://skia-review.googlesource.com/101741
Reviewed-by: Cary Clark <caryclark@google.com>
Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2018-01-30 10:12:22 -05:00 committed by Skia Commit-Bot
parent ab2621d3e2
commit 63227ca63b
3 changed files with 103 additions and 2 deletions

View File

@ -759,9 +759,19 @@ void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip,
}
SkRect r;
SkIRect ir;
r.set(pts, 3);
r.round(&ir);
// If r is too large (larger than can easily fit in SkFixed) then we need perform geometric
// clipping. This is a bit of work, so we just call the general FillPath() to handle it.
// Use FixedMax/2 as the limit so we can subtract two edges and still store that in Fixed.
const SkScalar limit = SK_MaxS16 >> 1;
if (!SkRect::MakeLTRB(-limit, -limit, limit, limit).contains(r)) {
SkPath path;
path.addPoly(pts, 3, false);
FillPath(path, clip, blitter);
return;
}
SkIRect ir = r.round();
if (ir.isEmpty() || !SkIRect::Intersects(ir, clip.getBounds())) {
return;
}

View File

@ -5,7 +5,10 @@
* found in the LICENSE file.
*/
#include "SkCanvas.h"
#include "SkSurface.h"
#include "SkVertices.h"
#include "sk_pixel_iter.h"
#include "Test.h"
static bool equal(const SkVertices* v0, const SkVertices* v1) {
@ -86,3 +89,30 @@ DEF_TEST(Vertices, reporter) {
}
}
}
static void fill_triangle(SkCanvas* canvas, const SkPoint pts[], SkColor c) {
SkColor colors[] = { c, c, c };
auto verts = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, 3, pts, nullptr, colors);
canvas->drawVertices(verts, SkBlendMode::kSrc, SkPaint());
}
DEF_TEST(Vertices_clipping, reporter) {
// A very large triangle has to be geometrically clipped (since its "fast" clipping is
// normally done in after building SkFixed coordinates). Check that we handle this.
// (and don't assert).
auto surf = SkSurface::MakeRasterN32Premul(3, 3);
SkPoint pts[] = { { -10, 1 }, { -10, 2 }, { 1e9f, 1.5f } };
fill_triangle(surf->getCanvas(), pts, SK_ColorBLACK);
sk_tool_utils::PixelIter iter(surf.get());
SkIPoint loc;
while (void* addr = iter.next(&loc)) {
SkPMColor c = *(SkPMColor*)addr;
if (loc.fY == 1) {
REPORTER_ASSERT(reporter, c == 0xFF000000);
} else {
REPORTER_ASSERT(reporter, c == 0);
}
}
}

61
tools/sk_pixel_iter.h Normal file
View File

@ -0,0 +1,61 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef sk_pixel_iter_DEFINED
#define sk_pixel_iter_DEFINED
#include "SkPixmap.h"
#include "SkSurface.h"
namespace sk_tool_utils {
class PixelIter {
public:
PixelIter();
PixelIter(SkSurface* surf) {
SkPixmap pm;
if (!surf->peekPixels(&pm)) {
pm.reset();
}
this->reset(pm);
}
void reset(const SkPixmap& pm) {
fPM = pm;
fLoc = { -1, 0 };
}
void* next(SkIPoint* loc = nullptr) {
if (!fPM.addr()) {
return nullptr;
}
fLoc.fX += 1;
if (fLoc.fX >= fPM.width()) {
fLoc.fX = 0;
if (++fLoc.fY >= fPM.height()) {
this->setDone();
return nullptr;
}
}
if (loc) {
*loc = fLoc;
}
return fPM.writable_addr(fLoc.fX, fLoc.fY);
}
void setDone() {
fPM.reset();
}
private:
SkPixmap fPM;
SkIPoint fLoc;
};
} // namespace sk_tool_utils
#endif // sk_tool_utils_DEFINED