/* * 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 "src/core/SkMathPriv.h" #include "src/core/SkPathPriv.h" #include "tests/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) { bool foundCurve = false; int contourCount = 0; for (auto [verb, pts, w] : SkPathPriv::Iterate(fPath)) { switch (verb) { case SkPathVerb::kMove: break; case SkPathVerb::kLine: case SkPathVerb::kQuad: case SkPathVerb::kConic: case SkPathVerb::kCubic: foundCurve = true; break; case SkPathVerb::kClose: ++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; } int contourCount = 0; bool enabled = fSelected[0]; bool addMoveTo = true; for (auto [verb, pts, w] : SkPathPriv::Iterate(fPath)) { if (enabled && addMoveTo) { result.moveTo(pts[0]); addMoveTo = false; } switch (verb) { case SkPathVerb::kMove: break; case SkPathVerb::kLine: if (enabled) { result.lineTo(pts[1]); } break; case SkPathVerb::kQuad: if (enabled) { result.quadTo(pts[1], pts[2]); } break; case SkPathVerb::kConic: if (enabled) { result.conicTo(pts[1], pts[2], *w); } break; case SkPathVerb::kCubic: if (enabled) { result.cubicTo(pts[1], pts[2], pts[3]); } break; case SkPathVerb::kClose: 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) { int verbCount = 0; for (auto [verb, pts, w] : SkPathPriv::Iterate(fPath)) { switch (verb) { case SkPathVerb::kMove: break; case SkPathVerb::kLine: case SkPathVerb::kQuad: case SkPathVerb::kConic: case SkPathVerb::kCubic: ++verbCount; break; case SkPathVerb::kClose: 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; } int verbIndex = 0; bool addMoveTo = true; bool addLineTo = false; for (auto [verb, pts, w] : SkPathPriv::Iterate(fPath)) { bool enabled = SkPathVerb::kLine <= verb && verb <= SkPathVerb::kCubic ? 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 SkPathVerb::kMove: break; case SkPathVerb::kLine: if (enabled) { result.lineTo(pts[1]); } break; case SkPathVerb::kQuad: if (enabled) { result.quadTo(pts[1], pts[2]); } break; case SkPathVerb::kConic: if (enabled) { result.conicTo(pts[1], pts[2], *w); } break; case SkPathVerb::kCubic: if (enabled) { result.cubicTo(pts[1], pts[2], pts[3]); } break; case SkPathVerb::kClose: result.close(); addMoveTo = true; addLineTo = false; continue; default: SkDEBUGFAIL("bad verb"); return result; } addLineTo = !enabled; } return result; }