| /* | 
 |  * 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; | 
 | } |