예제 #1
0
void SkOpSpan::release(const SkOpPtT* kept) {
    SkDEBUGCODE(fDebugDeleted = true);
    SkOPASSERT(kept->span() != this);
    SkASSERT(!final());
    SkOpSpan* prev = this->prev();
    SkASSERT(prev);
    SkOpSpanBase* next = this->next();
    SkASSERT(next);
    prev->setNext(next);
    next->setPrev(prev);
    this->segment()->release(this);
    SkOpCoincidence* coincidence = this->globalState()->coincidence();
    if (coincidence) {
        coincidence->fixUp(this->ptT(), kept);
    }
    this->ptT()->setDeleted();
    SkOpPtT* stopPtT = this->ptT();
    SkOpPtT* testPtT = stopPtT;
    const SkOpSpanBase* keptSpan = kept->span();
    do {
        if (this == testPtT->span()) {
            testPtT->setSpan(keptSpan);
        }
    } while ((testPtT = testPtT->next()) != stopPtT);
}
예제 #2
0
// please keep in sync with debugCheckForCollapsedCoincidence()
void SkOpSpanBase::checkForCollapsedCoincidence() {
    SkOpCoincidence* coins = this->globalState()->coincidence();
    if (coins->isEmpty()) {
        return;
    }
// the insert above may have put both ends of a coincident run in the same span
// for each coincident ptT in loop; see if its opposite in is also in the loop
// this implementation is the motivation for marking that a ptT is referenced by a coincident span
    SkOpPtT* head = this->ptT();
    SkOpPtT* test = head;
    do {
        if (!test->coincident()) {
            continue;
        }
        coins->markCollapsed(test);
    } while ((test = test->next()) != head);
    coins->releaseDeleted();
}
예제 #3
0
bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence,
        SkChunkAlloc* allocator) {
    SkOpGlobalState* globalState = contourList->globalState();
    // combine t values when multiple intersections occur on some segments but not others
    moveMultiples(contourList);
    findCollapsed(contourList);
    // move t values and points together to eliminate small/tiny gaps
    moveNearby(contourList);
    align(contourList);  // give all span members common values
    coincidence->fixAligned();  // aligning may have marked a coincidence pt-t deleted
#if DEBUG_VALIDATE
    globalState->setPhase(SkOpGlobalState::kIntersecting);
#endif
    // look for intersections on line segments formed by moving end points
    addAlignIntersections(contourList, allocator);
    coincidence->addMissing(allocator);
#if DEBUG_VALIDATE
    globalState->setPhase(SkOpGlobalState::kWalking);
#endif
    // check to see if, loosely, coincident ranges may be expanded
    if (coincidence->expand()) {
        coincidence->addExpanded(allocator  PATH_OPS_DEBUG_VALIDATE_PARAMS(globalState));
    }
    // the expanded ranges may not align -- add the missing spans
    coincidence->mark();  // mark spans of coincident segments as coincident
    // look for coincidence missed earlier
    if (missingCoincidence(contourList, coincidence, allocator)) {
        (void) coincidence->expand();
        coincidence->addExpanded(allocator  PATH_OPS_DEBUG_VALIDATE_PARAMS(globalState));
        coincidence->mark();
    }
    SkOpCoincidence overlaps;
    do {
        SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps;
        if (!pairs->apply()) {  // adjust the winding value to account for coincident edges
            return false;
        }
        // For each coincident pair that overlaps another, when the receivers (the 1st of the pair)
        // are different, construct a new pair to resolve their mutual span
        pairs->findOverlaps(&overlaps, allocator);
    } while (!overlaps.isEmpty());
    calcAngles(contourList, allocator);
    sortAngles(contourList);
    if (globalState->angleCoincidence()) {
        (void) missingCoincidence(contourList, coincidence, allocator);
        if (!coincidence->apply()) {
            return false;
        }
    }
#if DEBUG_ACTIVE_SPANS
    coincidence->debugShowCoincidence();
    DebugShowActiveSpans(contourList);
#endif
    return true;
}
예제 #4
0
bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence) {
    SkOpGlobalState* globalState = contourList->globalState();
    DEBUG_COINCIDENCE_HEALTH(contourList, "start");
#if DEBUG_VALIDATE
    globalState->setPhase(SkOpGlobalState::kIntersecting);
#endif

    // match up points within the coincident runs
    if (!coincidence->addExpanded()) {
        return false;
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded");
#if DEBUG_VALIDATE
    globalState->setPhase(SkOpGlobalState::kWalking);
#endif
    // combine t values when multiple intersections occur on some segments but not others
    if (!moveMultiples(contourList)) {
        return false;
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "moveMultiples");
    // move t values and points together to eliminate small/tiny gaps
    (void) moveNearby(contourList);
    DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby");
#if DEBUG_VALIDATE
    globalState->setPhase(SkOpGlobalState::kIntersecting);
#endif
    // add coincidence formed by pairing on curve points and endpoints
    coincidence->correctEnds();
    if (!coincidence->addEndMovedSpans()) {
        return false;
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "addEndMovedSpans");

    const int SAFETY_COUNT = 100;  // FIXME: tune
    int safetyHatch = SAFETY_COUNT;
    // look for coincidence present in A-B and A-C but missing in B-C
    while (coincidence->addMissing()) {
        if (!--safetyHatch) {
            SkASSERT(0);  // FIXME: take this out after verifying std tests don't trigger
            return false;
        }
        DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing");
        moveNearby(contourList);
        DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby");
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing2");
    // FIXME: only call this if addMissing modified something when returning false
    moveNearby(contourList);
    DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby2");
    // check to see if, loosely, coincident ranges may be expanded
    if (coincidence->expand()) {
        DEBUG_COINCIDENCE_HEALTH(contourList, "expand1");
        coincidence->addMissing();
        DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing2");
        if (!coincidence->addExpanded()) {
            return false;
        }
        DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded2");
        if (!moveMultiples(contourList)) {
            return false;
        }
        DEBUG_COINCIDENCE_HEALTH(contourList, "moveMultiples2");
        moveNearby(contourList);
    }
#if DEBUG_VALIDATE
    globalState->setPhase(SkOpGlobalState::kWalking);
#endif
    DEBUG_COINCIDENCE_HEALTH(contourList, "expand2");
    // the expanded ranges may not align -- add the missing spans
    if (!coincidence->addExpanded()) {
        SkASSERT(globalState->debugSkipAssert());
        return false;
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded3");
    coincidence->correctEnds();
    if (!coincidence->mark()) {  // mark spans of coincident segments as coincident
        return false;
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "mark1");
    // look for coincidence lines and curves undetected by intersection
    if (missingCoincidence(contourList)) {
#if DEBUG_VALIDATE
        globalState->setPhase(SkOpGlobalState::kIntersecting);
#endif
        DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence1");
        (void) coincidence->expand();
        DEBUG_COINCIDENCE_HEALTH(contourList, "expand3");
        if (!coincidence->addExpanded()) {
            return false;
        }
#if DEBUG_VALIDATE
        globalState->setPhase(SkOpGlobalState::kWalking);
#endif
        DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded3");
        if (!coincidence->mark()) {
            return false;
        }
    } else {
        DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence2");
        (void) coincidence->expand();
    }
    DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence3");

    (void) coincidence->expand();

#if 0  // under development
    // coincident runs may cross two or more spans, but the opposite spans may be out of order
    if (!coincidence->reorder()) {
      return false;
    }
#endif
    DEBUG_COINCIDENCE_HEALTH(contourList, "coincidence.reorder");
    SkOpCoincidence overlaps(globalState);
    do {
        SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps;
        if (!pairs->apply()) {  // adjust the winding value to account for coincident edges
            return false;
        }
        DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->apply");
        // For each coincident pair that overlaps another, when the receivers (the 1st of the pair)
        // are different, construct a new pair to resolve their mutual span
        if (!pairs->findOverlaps(&overlaps)) {
            return false;
        }
        DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->findOverlaps");
    } while (!overlaps.isEmpty());
    calcAngles(contourList);
    sortAngles(contourList);
    if (globalState->angleCoincidence()) {
        (void) missingCoincidence(contourList);
        if (!coincidence->apply()) {
            return false;
        }
    }
#if DEBUG_COINCIDENCE_VERBOSE
    coincidence->debugShowCoincidence();
#endif
#if DEBUG_COINCIDENCE
    coincidence->debugValidate();
#endif
    SkPathOpsDebug::ShowActiveSpans(contourList);
    return true;
}