skia2/tests/PathOpsOpCircleThreadedTest.cpp
caryclark 2bec26a716 fix security bug
This fix is a tradeoff. It changes intersection to
treat a case where one coincident run is intersected at one point
and the other edge is not as continuing to be a span.

The old code tried to treat this as a single point.
The old code is probably right, but this change alone
made the data structures inconsistent. Later, extending
the coincident runs would fail by incorrectly discarding
the single point intersection.

As a result, this fixes the security test and one other, but
makes a different test fail. Isolating the failure uncovered
a reduced case that fails with and without the change, so
there are more serious problems here. Those problems are
addressed in a separate CL.

Many of the test edits below remove ill-thought out debugging
messaging that fire off global state, which isn't usable
in a multi-threaded test environment.

In the end, with this fix, all existing tests (modulo one
new failure and one new non-failure) pass in debug and
in the extended release test suites.

TBR=reed@google.com
BUG=614248
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2018513003

Review-Url: https://codereview.chromium.org/2018513003
2016-05-26 09:01:47 -07:00

83 lines
3.5 KiB
C++

/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "PathOpsExtendedTest.h"
#include "PathOpsThreadedCommon.h"
static void testOpCirclesMain(PathOpsThreadState* data) {
SkASSERT(data);
PathOpsThreadState& state = *data;
char pathStr[1024];
bool progress = state.fReporter->verbose(); // FIXME: break out into its own parameter?
if (progress) {
sk_bzero(pathStr, sizeof(pathStr));
}
for (int a = 0 ; a < 6; ++a) {
for (int b = a + 1 ; b < 7; ++b) {
for (int c = 0 ; c < 6; ++c) {
for (int d = c + 1 ; d < 7; ++d) {
for (int e = SkPath::kWinding_FillType ; e <= SkPath::kEvenOdd_FillType; ++e) {
for (int f = SkPath::kWinding_FillType ; f <= SkPath::kEvenOdd_FillType; ++f) {
SkPath pathA, pathB;
if (progress) {
char* str = pathStr;
const int loopNo = 4;
str += sprintf(str, "static void circlesOp%d(skiatest::Reporter* reporter,"
" const char* filename) {\n", loopNo);
str += sprintf(str, " SkPath path, pathB;\n");
str += sprintf(str, " path.setFillType(SkPath::k%s_FillType);\n",
e == SkPath::kWinding_FillType ? "Winding" : e == SkPath::kEvenOdd_FillType
? "EvenOdd" : "?UNDEFINED");
str += sprintf(str, " path.addCircle(%d, %d, %d, %s);\n", state.fA, state.fB,
state.fC, state.fD ? "SkPath::kCW_Direction" : "SkPath::kCCW_Direction");
str += sprintf(str, " pathB.setFillType(SkPath::k%s_FillType);\n",
f == SkPath::kWinding_FillType ? "Winding" : f == SkPath::kEvenOdd_FillType
? "EvenOdd" : "?UNDEFINED");
str += sprintf(str, " pathB.addCircle(%d, %d, %d, %s);\n", a, b,
c, d ? "SkPath::kCW_Direction" : "SkPath::kCCW_Direction");
str += sprintf(str, " testPathOp(reporter, path, pathB, kDifference_SkPathOp,"
" filename);\n");
str += sprintf(str, "}\n");
}
pathA.setFillType((SkPath::FillType) e);
pathA.addCircle(SkIntToScalar(state.fA), SkIntToScalar(state.fB), SkIntToScalar(state.fC),
state.fD ? SkPath::kCW_Direction : SkPath::kCCW_Direction);
pathB.setFillType((SkPath::FillType) f);
pathB.addCircle(SkIntToScalar(a), SkIntToScalar(b), SkIntToScalar(c),
d ? SkPath::kCW_Direction : SkPath::kCCW_Direction);
for (int op = 0 ; op <= kXOR_SkPathOp; ++op) {
if (progress) {
outputProgress(state.fPathStr, pathStr, (SkPathOp) op);
}
testPathOp(state.fReporter, pathA, pathB, (SkPathOp) op, "circles");
}
}
}
}
}
}
}
}
DEF_TEST(PathOpsOpCircleThreaded, reporter) {
initializeTests(reporter, "circleOp");
PathOpsThreadedTestRunner testRunner(reporter);
for (int a = 0; a < 6; ++a) { // outermost
for (int b = a + 1; b < 7; ++b) {
for (int c = 0 ; c < 6; ++c) {
for (int d = 0; d < 2; ++d) {
*testRunner.fRunnables.append() = new PathOpsThreadedRunnable(
&testOpCirclesMain, a, b, c, d, &testRunner);
}
}
if (!reporter->allowExtendedTest()) goto finish;
}
}
finish:
testRunner.render();
}