61c21cdcc3
Add support for tight bounds to detect and return moveTo followed by close or zero-length lineTo. Also short circuit so that hard work is avoided when the path bounds is also the tight bounds. Avoid doing work if the bounds can be trivially computed. Include naked moveTo coordinates in the tight bounds. R=fmalita@chromium.org BUG=skia:5555, skia:5553 GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2394443004 Review-Url: https://codereview.chromium.org/2394443004
191 lines
6.5 KiB
C++
191 lines
6.5 KiB
C++
/*
|
|
* Copyright 2013 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"
|
|
#include "SkCanvas.h"
|
|
#include "SkRandom.h"
|
|
#include "SkTSort.h"
|
|
#include "Test.h"
|
|
|
|
static void testTightBoundsLines(PathOpsThreadState* data) {
|
|
SkRandom ran;
|
|
for (int index = 0; index < 1000; ++index) {
|
|
SkPath path;
|
|
int contourCount = ran.nextRangeU(1, 10);
|
|
for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
|
|
int lineCount = ran.nextRangeU(1, 10);
|
|
path.moveTo(ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000));
|
|
for (int lIndex = 0; lIndex < lineCount; ++lIndex) {
|
|
path.lineTo(ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000));
|
|
}
|
|
if (ran.nextBool()) {
|
|
path.close();
|
|
}
|
|
}
|
|
SkRect classicBounds = path.getBounds();
|
|
SkRect tightBounds;
|
|
REPORTER_ASSERT(data->fReporter, TightBounds(path, &tightBounds));
|
|
REPORTER_ASSERT(data->fReporter, classicBounds == tightBounds);
|
|
}
|
|
}
|
|
|
|
DEF_TEST(PathOpsTightBoundsLines, reporter) {
|
|
initializeTests(reporter, "tightBoundsLines");
|
|
PathOpsThreadedTestRunner testRunner(reporter);
|
|
int outerCount = reporter->allowExtendedTest() ? 100 : 1;
|
|
for (int index = 0; index < outerCount; ++index) {
|
|
for (int idx2 = 0; idx2 < 10; ++idx2) {
|
|
*testRunner.fRunnables.append() =
|
|
new PathOpsThreadedRunnable(&testTightBoundsLines, 0, 0, 0, 0, &testRunner);
|
|
}
|
|
}
|
|
testRunner.render();
|
|
}
|
|
|
|
static void testTightBoundsQuads(PathOpsThreadState* data) {
|
|
SkRandom ran;
|
|
const int bitWidth = 32;
|
|
const int bitHeight = 32;
|
|
const float pathMin = 1;
|
|
const float pathMax = (float) (bitHeight - 2);
|
|
SkBitmap& bits = *data->fBitmap;
|
|
if (bits.width() == 0) {
|
|
bits.allocN32Pixels(bitWidth, bitHeight);
|
|
}
|
|
SkCanvas canvas(bits);
|
|
SkPaint paint;
|
|
for (int index = 0; index < 100; ++index) {
|
|
SkPath path;
|
|
int contourCount = ran.nextRangeU(1, 10);
|
|
for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
|
|
int lineCount = ran.nextRangeU(1, 10);
|
|
path.moveTo(ran.nextRangeF(1, pathMax), ran.nextRangeF(pathMin, pathMax));
|
|
for (int lIndex = 0; lIndex < lineCount; ++lIndex) {
|
|
if (ran.nextBool()) {
|
|
path.lineTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax));
|
|
} else {
|
|
path.quadTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax),
|
|
ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax));
|
|
}
|
|
}
|
|
if (ran.nextBool()) {
|
|
path.close();
|
|
}
|
|
}
|
|
SkRect classicBounds = path.getBounds();
|
|
SkRect tightBounds;
|
|
REPORTER_ASSERT(data->fReporter, TightBounds(path, &tightBounds));
|
|
REPORTER_ASSERT(data->fReporter, classicBounds.contains(tightBounds));
|
|
canvas.drawColor(SK_ColorWHITE);
|
|
canvas.drawPath(path, paint);
|
|
SkIRect bitsWritten = {31, 31, 0, 0};
|
|
for (int y = 0; y < bitHeight; ++y) {
|
|
uint32_t* addr1 = data->fBitmap->getAddr32(0, y);
|
|
bool lineWritten = false;
|
|
for (int x = 0; x < bitWidth; ++x) {
|
|
if (addr1[x] == (uint32_t) -1) {
|
|
continue;
|
|
}
|
|
lineWritten = true;
|
|
bitsWritten.fLeft = SkTMin(bitsWritten.fLeft, x);
|
|
bitsWritten.fRight = SkTMax(bitsWritten.fRight, x);
|
|
}
|
|
if (!lineWritten) {
|
|
continue;
|
|
}
|
|
bitsWritten.fTop = SkTMin(bitsWritten.fTop, y);
|
|
bitsWritten.fBottom = SkTMax(bitsWritten.fBottom, y);
|
|
}
|
|
if (!bitsWritten.isEmpty()) {
|
|
SkIRect tightOut;
|
|
tightBounds.roundOut(&tightOut);
|
|
REPORTER_ASSERT(data->fReporter, tightOut.contains(bitsWritten));
|
|
}
|
|
}
|
|
}
|
|
|
|
DEF_TEST(PathOpsTightBoundsQuads, reporter) {
|
|
initializeTests(reporter, "tightBoundsQuads");
|
|
PathOpsThreadedTestRunner testRunner(reporter);
|
|
int outerCount = reporter->allowExtendedTest() ? 100 : 1;
|
|
for (int index = 0; index < outerCount; ++index) {
|
|
for (int idx2 = 0; idx2 < 10; ++idx2) {
|
|
*testRunner.fRunnables.append() =
|
|
new PathOpsThreadedRunnable(&testTightBoundsQuads, 0, 0, 0, 0, &testRunner);
|
|
}
|
|
}
|
|
testRunner.render();
|
|
}
|
|
|
|
DEF_TEST(PathOpsTightBoundsMove, reporter) {
|
|
SkPath path;
|
|
path.moveTo(10, 10);
|
|
path.close();
|
|
path.moveTo(20, 20);
|
|
path.lineTo(20, 20);
|
|
path.close();
|
|
path.moveTo(15, 15);
|
|
path.lineTo(15, 15);
|
|
path.close();
|
|
const SkRect& bounds = path.getBounds();
|
|
SkRect tight;
|
|
REPORTER_ASSERT(reporter, TightBounds(path, &tight));
|
|
REPORTER_ASSERT(reporter, bounds == tight);
|
|
}
|
|
|
|
DEF_TEST(PathOpsTightBoundsMoveOne, reporter) {
|
|
SkPath path;
|
|
path.moveTo(20, 20);
|
|
const SkRect& bounds = path.getBounds();
|
|
SkRect tight;
|
|
REPORTER_ASSERT(reporter, TightBounds(path, &tight));
|
|
REPORTER_ASSERT(reporter, bounds == tight);
|
|
}
|
|
|
|
DEF_TEST(PathOpsTightBoundsMoveTwo, reporter) {
|
|
SkPath path;
|
|
path.moveTo(20, 20);
|
|
path.moveTo(40, 40);
|
|
const SkRect& bounds = path.getBounds();
|
|
SkRect tight;
|
|
REPORTER_ASSERT(reporter, TightBounds(path, &tight));
|
|
REPORTER_ASSERT(reporter, bounds == tight);
|
|
}
|
|
|
|
DEF_TEST(PathOpsTightBoundsTiny, reporter) {
|
|
SkPath path;
|
|
path.moveTo(1, 1);
|
|
path.quadTo(1.000001f, 1, 1, 1);
|
|
const SkRect& bounds = path.getBounds();
|
|
SkRect tight;
|
|
REPORTER_ASSERT(reporter, TightBounds(path, &tight));
|
|
SkRect moveBounds = {1, 1, 1, 1};
|
|
REPORTER_ASSERT(reporter, bounds != tight);
|
|
REPORTER_ASSERT(reporter, moveBounds == tight);
|
|
}
|
|
|
|
DEF_TEST(PathOpsTightBoundsWellBehaved, reporter) {
|
|
SkPath path;
|
|
path.moveTo(1, 1);
|
|
path.quadTo(2, 3, 4, 5);
|
|
const SkRect& bounds = path.getBounds();
|
|
SkRect tight;
|
|
REPORTER_ASSERT(reporter, TightBounds(path, &tight));
|
|
REPORTER_ASSERT(reporter, bounds == tight);
|
|
}
|
|
|
|
DEF_TEST(PathOpsTightBoundsIllBehaved, reporter) {
|
|
SkPath path;
|
|
path.moveTo(1, 1);
|
|
path.quadTo(4, 3, 2, 2);
|
|
const SkRect& bounds = path.getBounds();
|
|
SkRect tight;
|
|
REPORTER_ASSERT(reporter, TightBounds(path, &tight));
|
|
REPORTER_ASSERT(reporter, bounds != tight);
|
|
}
|
|
|