/*
* 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 "SubsetPath.h"
SubsetPath::SubsetPath(const SkPath& path)
: fPath(path)
, fSubset(1) {
}
int SubsetPath::range(int* end) const {
int leadingZero = SkCLZ(fSubset);
int parts = 1 << (31 - leadingZero);
int partIndex = fSubset - parts;
SkASSERT(partIndex >= 0);
int count = fSelected.count();
int start = count * partIndex / parts;
*end = count * (partIndex + 1) / parts;
return start;
}
bool SubsetPath::subset(bool testFailed, SkPath* sub) {
int start, end;
if (!testFailed) {
start = range(&end);
for (; start < end; ++start) {
fSelected[start] = true;
}
}
do {
do {
++fSubset;
start = range(&end);
// SkDebugf("%d s=%d e=%d t=%d\n", fSubset, start, end, fTries);
if (end - start > 1) {
fTries = fSelected.count();
} else if (end - start == 1) {
if (--fTries <= 0) {
return false;
}
}
} while (start == end);
} while (!fSelected[start]);
for (; start < end; ++start) {
fSelected[start] = false;
}
#if 1
SkDebugf("selected: ");
for (int index = 0; index < fSelected.count(); ++index) {
SkDebugf("%c", fSelected[index] ? 'x' : '-');
}
#endif
*sub = getSubsetPath();
return true;
}
SubsetContours::SubsetContours(const SkPath& path)
: SubsetPath(path) {
SkPath::RawIter iter(fPath);
uint8_t verb;
SkPoint pts[4];
bool foundCurve = false;
int contourCount = 0;
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
switch (verb) {
case SkPath::kMove_Verb:
break;
case SkPath::kLine_Verb:
case SkPath::kQuad_Verb:
case SkPath::kConic_Verb:
case SkPath::kCubic_Verb:
foundCurve = true;
break;
case SkPath::kClose_Verb:
++contourCount;
foundCurve = false;
break;
default:
SkDEBUGFAIL("bad verb");
return;
}
}
contourCount += foundCurve;
for (int index = 0; index < contourCount; ++index) {
*fSelected.append() = true;
}
fTries = contourCount;
}
SkPath SubsetContours::getSubsetPath() const {
SkPath result;
result.setFillType(fPath.getFillType());
if (!fSelected.count()) {
return result;
}
SkPath::RawIter iter(fPath);
uint8_t verb;
SkPoint pts[4];
int contourCount = 0;
bool enabled = fSelected[0];
bool addMoveTo = true;
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
if (enabled && addMoveTo) {
result.moveTo(pts[0]);
addMoveTo = false;
}
switch (verb) {
case SkPath::kMove_Verb:
break;
case SkPath::kLine_Verb:
if (enabled) {
result.lineTo(pts[1]);
}
break;
case SkPath::kQuad_Verb:
if (enabled) {
result.quadTo(pts[1], pts[2]);
}
break;
case SkPath::kConic_Verb:
if (enabled) {
result.conicTo(pts[1], pts[2], iter.conicWeight());
}
break;
case SkPath::kCubic_Verb:
if (enabled) {
result.cubicTo(pts[1], pts[2], pts[3]);
}
break;
case SkPath::kClose_Verb:
if (enabled) {
result.close();
}
if (++contourCount >= fSelected.count()) {
break;
}
enabled = fSelected[contourCount];
addMoveTo = true;
continue;
default:
SkDEBUGFAIL("bad verb");
return result;
}
}
return result;
}
SubsetVerbs::SubsetVerbs(const SkPath& path)
: SubsetPath(path) {
SkPath::RawIter iter(fPath);
uint8_t verb;
SkPoint pts[4];
int verbCount = 0;
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
switch (verb) {
case SkPath::kMove_Verb:
break;
case SkPath::kLine_Verb:
case SkPath::kQuad_Verb:
case SkPath::kConic_Verb:
case SkPath::kCubic_Verb:
++verbCount;
break;
case SkPath::kClose_Verb:
break;
default:
SkDEBUGFAIL("bad verb");
return;
}
}
for (int index = 0; index < verbCount; ++index) {
*fSelected.append() = true;
}
fTries = verbCount;
}
SkPath SubsetVerbs::getSubsetPath() const {
SkPath result;
result.setFillType(fPath.getFillType());
if (!fSelected.count()) {
return result;
}
SkPath::RawIter iter(fPath);
uint8_t verb;
SkPoint pts[4];
int verbIndex = 0;
bool addMoveTo = true;
bool addLineTo = false;
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
bool enabled = SkPath::kLine_Verb <= verb && verb <= SkPath::kCubic_Verb
? fSelected[verbIndex++] : false;
if (enabled) {
if (addMoveTo) {
result.moveTo(pts[0]);
addMoveTo = false;
} else if (addLineTo) {
result.lineTo(pts[0]);
addLineTo = false;
}
}
switch (verb) {
case SkPath::kMove_Verb:
break;
case SkPath::kLine_Verb:
if (enabled) {
result.lineTo(pts[1]);
}
break;
case SkPath::kQuad_Verb:
if (enabled) {
result.quadTo(pts[1], pts[2]);
}
break;
case SkPath::kConic_Verb:
if (enabled) {
result.conicTo(pts[1], pts[2], iter.conicWeight());
}
break;
case SkPath::kCubic_Verb:
if (enabled) {
result.cubicTo(pts[1], pts[2], pts[3]);
}
break;
case SkPath::kClose_Verb:
result.close();
addMoveTo = true;
addLineTo = false;
continue;
default:
SkDEBUGFAIL("bad verb");
return result;
}
addLineTo = !enabled;
}
return result;
}