コード例 #1
0
// A tiny interval may indicate an undiscovered coincidence. Find and fix.
static void checkTiny(SkTArray<SkOpContour*, true>* contourList) {
    int contourCount = (*contourList).count();
    for (int cTest = 0; cTest < contourCount; ++cTest) {
        SkOpContour* contour = (*contourList)[cTest];
        contour->checkTiny();
    }
}
コード例 #2
0
static void joinCoincidence(SkTArray<SkOpContour*, true>* contourList) {
    int contourCount = (*contourList).count();
    for (int cTest = 0; cTest < contourCount; ++cTest) {
        SkOpContour* contour = (*contourList)[cTest];
        contour->joinCoincidence();
    }
}
コード例 #3
0
static void fixOtherTIndex(SkTArray<SkOpContour*, true>* contourList) {
    int contourCount = (*contourList).count();
    for (int cTest = 0; cTest < contourCount; ++cTest) {
        SkOpContour* contour = (*contourList)[cTest];
        contour->fixOtherTIndex();
    }
}
コード例 #4
0
bool TightBounds(const SkPath& path, SkRect* result) {
    SkChunkAlloc allocator(4096);  // FIXME: constant-ize, tune
    SkOpContour contour;
    SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour);
    SkOpGlobalState globalState(contourList, &allocator  SkDEBUGPARAMS(false)
            SkDEBUGPARAMS(nullptr));
    // turn path into list of segments
    SkScalar scaleFactor = ScaleFactor(path);
    SkPath scaledPath;
    const SkPath* workingPath;
    if (scaleFactor > SK_Scalar1) {
        ScalePath(path, 1.f / scaleFactor, &scaledPath);
        workingPath = &scaledPath;
    } else {
        workingPath = &path;
    }
    SkOpEdgeBuilder builder(*workingPath, &contour, &globalState);
    if (!builder.finish()) {
        return false;
    }
    if (!SortContourList(&contourList, false, false)) {
        result->setEmpty();
        return true;
    }
    SkOpContour* current = contourList;
    SkPathOpsBounds bounds = current->bounds();
    while ((current = current->next())) {
        bounds.add(current->bounds());
    }
    *result = bounds;
    return true;
}
コード例 #5
0
static void sortSegments(SkTArray<SkOpContour*, true>* contourList) {
    int contourCount = (*contourList).count();
    for (int cTest = 0; cTest < contourCount; ++cTest) {
        SkOpContour* contour = (*contourList)[cTest];
        contour->sortSegments();
    }
}
コード例 #6
0
ファイル: SkPathOpsCommon.cpp プロジェクト: sylvestre/skia
static bool missingCoincidence(SkOpContourHead* contourList) {
    SkOpContour* contour = contourList;
    bool result = false;
    do {
        result |= contour->missingCoincidence();
    } while ((contour = contour->next()));
    return result;
}
コード例 #7
0
static void checkEnds(SkTArray<SkOpContour*, true>* contourList) {
    // it's hard to determine if the end of a cubic or conic nearly intersects another curve.
    // instead, look to see if the connecting curve intersected at that same end.
    int contourCount = (*contourList).count();
    for (int cTest = 0; cTest < contourCount; ++cTest) {
        SkOpContour* contour = (*contourList)[cTest];
        contour->checkEnds();
    }
}
コード例 #8
0
ファイル: SkPathOpsCommon.cpp プロジェクト: Just-D/skia
static bool missingCoincidence(SkOpContourHead* contourList,
        SkOpCoincidence* coincidence, SkChunkAlloc* allocator) {
    SkOpContour* contour = contourList;
    bool result = false;
    do {
        result |= contour->missingCoincidence(coincidence, allocator);
    } while ((contour = contour->next()));
    return result;
}
コード例 #9
0
ファイル: SkPathOpsCommon.cpp プロジェクト: sylvestre/skia
static bool moveMultiples(SkOpContourHead* contourList) {
    SkOpContour* contour = contourList;
    do {
        if (!contour->moveMultiples()) {
            return false;
        }
    } while ((contour = contour->next()));
    return true;
}
コード例 #10
0
static void alignMultiples(SkTArray<SkOpContour*, true>* contourList,
        SkTDArray<SkOpSegment::AlignedSpan>* aligned) {
    int contourCount = (*contourList).count();
    for (int cTest = 0; cTest < contourCount; ++cTest) {
        SkOpContour* contour = (*contourList)[cTest];
        if (contour->hasMultiples()) {
            contour->alignMultiples(aligned);
        }
    }
}
コード例 #11
0
static bool calcAngles(SkTArray<SkOpContour*, true>* contourList) {
    int contourCount = (*contourList).count();
    for (int cTest = 0; cTest < contourCount; ++cTest) {
        SkOpContour* contour = (*contourList)[cTest];
        if (!contour->calcAngles()) {
            return false;
        }
    }
    return true;
}
コード例 #12
0
static bool checkMultiples(SkTArray<SkOpContour*, true>* contourList) {
    bool hasMultiples = false;
    int contourCount = (*contourList).count();
    for (int cTest = 0; cTest < contourCount; ++cTest) {
        SkOpContour* contour = (*contourList)[cTest];
        contour->checkMultiples();
        hasMultiples |= contour->hasMultiples();
    }
    return hasMultiples;
}
コード例 #13
0
static void alignCoincidence(SkTArray<SkOpContour*, true>* contourList,
        const SkTDArray<SkOpSegment::AlignedSpan>& aligned) {
    int contourCount = (*contourList).count();
    for (int cTest = 0; cTest < contourCount; ++cTest) {
        SkOpContour* contour = (*contourList)[cTest];
        int count = aligned.count();
        for (int index = 0; index < count; ++index) {
            contour->alignCoincidence(aligned[index]);
        }
    }    
}
コード例 #14
0
ファイル: SkPathOpsCommon.cpp プロジェクト: Just-D/skia
SkOpSegment* FindUndone(SkOpContourHead* contourList, SkOpSpanBase** startPtr,
         SkOpSpanBase** endPtr) {
    SkOpSegment* result;
    SkOpContour* contour = contourList;
    do {
        result = contour->undoneSegment(startPtr, endPtr);
        if (result) {
            return result;
        }
    } while ((contour = contour->next()));
    return nullptr;
}
コード例 #15
0
ファイル: SkOpEdgeBuilder.cpp プロジェクト: molikto/Skia
bool SkOpEdgeBuilder::finish() {
    fOperand = false;
    if (fUnparseable || !walk()) {
        return false;
    }
    complete();
    SkOpContour* contour = fContourBuilder.contour();
    if (contour && !contour->count()) {
        fContoursHead->remove(contour);
    }
    return true;
}
コード例 #16
0
SkOpSegment* FindUndone(SkTArray<SkOpContour*, true>& contourList, int* start, int* end) {
    int contourCount = contourList.count();
    SkOpSegment* result;
    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
        SkOpContour* contour = contourList[cIndex];
        result = contour->undoneSegment(start, end);
        if (result) {
            return result;
        }
    }
    return NULL;
}
コード例 #17
0
ファイル: SkPathOpsCommon.cpp プロジェクト: Just-D/skia
bool SortContourList(SkOpContourHead** contourList, bool evenOdd, bool oppEvenOdd) {
    SkTDArray<SkOpContour* > list;
    SkOpContour* contour = *contourList;
    do {
        if (contour->count()) {
            contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd);
            *list.append() = contour;
        }
    } while ((contour = contour->next()));
    int count = list.count();
    if (!count) {
        return false;
    }
    if (count > 1) {
        SkTQSort<SkOpContour>(list.begin(), list.end() - 1);
    }
    contour = list[0];
    SkOpContourHead* contourHead = static_cast<SkOpContourHead*>(contour);
    contour->globalState()->setContourHead(contourHead);
    *contourList = contourHead;
    for (int index = 1; index < count; ++index) {
        SkOpContour* next = list[index];
        contour->setNext(next);
        contour = next;
    }
    contour->setNext(nullptr);
    return true;
}
コード例 #18
0
ファイル: SkPathOpsSimplify.cpp プロジェクト: SimonSapin/skia
// FIXME : add this as a member of SkPath
void Simplify(const SkPath& path, SkPath* result) {
#if DEBUG_SORT || DEBUG_SWAP_TOP
    gDebugSortCount = gDebugSortCountDefault;
#endif
    // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
    result->reset();
    result->setFillType(SkPath::kEvenOdd_FillType);
    SkPathWriter simple(*result);

    // turn path into list of segments
    SkTArray<SkOpContour> contours;
    SkOpEdgeBuilder builder(path, contours);
    builder.finish();
    SkTDArray<SkOpContour*> contourList;
    MakeContourList(contours, contourList, false, false);
    SkOpContour** currentPtr = contourList.begin();
    if (!currentPtr) {
        return;
    }
    SkOpContour** listEnd = contourList.end();
    // find all intersections between segments
    do {
        SkOpContour** nextPtr = currentPtr;
        SkOpContour* current = *currentPtr++;
        if (current->containsCubics()) {
            AddSelfIntersectTs(current);
        }
        SkOpContour* next;
        do {
            next = *nextPtr++;
        } while (AddIntersectTs(current, next) && nextPtr != listEnd);
    } while (currentPtr != listEnd);
    // eat through coincident edges
    CoincidenceCheck(&contourList, 0);
    FixOtherTIndex(&contourList);
    SortSegments(&contourList);
#if DEBUG_ACTIVE_SPANS
    DebugShowActiveSpans(contourList);
#endif
    // construct closed contours
    if (builder.xorMask() == kWinding_PathOpsMask ? bridgeWinding(contourList, &simple)
                : !bridgeXor(contourList, &simple))
    {  // if some edges could not be resolved, assemble remaining fragments
        SkPath temp;
        temp.setFillType(SkPath::kEvenOdd_FillType);
        SkPathWriter assembled(temp);
        Assemble(simple, &assembled);
        *result = *assembled.nativePath();
    }
}
コード例 #19
0
ファイル: SkPathOpsCommon.cpp プロジェクト: windyuuy/opera
static void skipVertical(const SkTArray<SkOpContour*, true>& contourList,
        SkOpSegment** current, int* index, int* endIndex) {
    if (!(*current)->isVertical(*index, *endIndex)) {
        return;
    }
    int contourCount = contourList.count();
    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
        SkOpContour* contour = contourList[cIndex];
        if (contour->done()) {
            continue;
        }
        *current = contour->nonVerticalSegment(index, endIndex);
        if (*current) {
            return;
        }
    }
}
コード例 #20
0
static SkOpSegment* findTopSegment(const SkTArray<SkOpContour*, true>& contourList, int* index,
        int* endIndex, SkPoint* topLeft, bool* unsortable, bool* done, bool firstPass) {
    SkOpSegment* result;
    const SkOpSegment* lastTopStart = NULL;
    int lastIndex = -1, lastEndIndex = -1;
    do {
        SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
        int contourCount = contourList.count();
        SkOpSegment* topStart = NULL;
        *done = true;
        for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
            SkOpContour* contour = contourList[cIndex];
            if (contour->done()) {
                continue;
            }
            const SkPathOpsBounds& bounds = contour->bounds();
            if (bounds.fBottom < topLeft->fY) {
                *done = false;
                continue;
            }
            if (bounds.fBottom == topLeft->fY && bounds.fRight < topLeft->fX) {
                *done = false;
                continue;
            }
            contour->topSortableSegment(*topLeft, &bestXY, &topStart);
            if (!contour->done()) {
                *done = false;
            }
        }
        if (!topStart) {
            return NULL;
        }
        *topLeft = bestXY;
        result = topStart->findTop(index, endIndex, unsortable, firstPass);
        if (!result) {
            if (lastTopStart == topStart && lastIndex == *index && lastEndIndex == *endIndex) {
                *done = true;
                return NULL;
            }
            lastTopStart = topStart;
            lastIndex = *index;
            lastEndIndex = *endIndex;
        }
    } while (!result);
    return result;
}
コード例 #21
0
DEF_TEST(PathOpsAngleCircle, reporter) {
    SkChunkAlloc allocator(4096);
    SkOpContour contour;
    SkOpGlobalState state(NULL  PATH_OPS_DEBUG_PARAMS(&contour));
    contour.init(&state, false, false);
    for (int index = 0; index < circleDataSetSize; ++index) {
        CircleData& data = circleDataSet[index];
        for (int idx2 = 0; idx2 < data.fPtCount; ++idx2) {
            data.fShortPts[idx2] = data.fPts.fPts[idx2].asSkPoint();
        }
        switch (data.fPtCount) {
            case 2:
                contour.addLine(data.fShortPts, &allocator);
                break;
            case 3:
                contour.addQuad(data.fShortPts, &allocator);
                break;
            case 4:
                contour.addCubic(data.fShortPts, &allocator);
                break;
        }
    }
    SkOpSegment* first = contour.first();
    first->debugAddAngle(0, 1, &allocator);
    SkOpSegment* next = first->next();
    next->debugAddAngle(0, 1, &allocator);
    PathOpsAngleTester::Orderable(*first->debugLastAngle(), *next->debugLastAngle());
}
コード例 #22
0
bool TightBounds(const SkPath& path, SkRect* result) {
    SkChunkAlloc allocator(4096);  // FIXME: constant-ize, tune
    SkOpContour contour;
    SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour);
    SkOpGlobalState globalState(nullptr, contourList  SkDEBUGPARAMS(nullptr));
    // turn path into list of segments
    SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState);
    if (!builder.finish(&allocator)) {
        return false;
    }
    if (!SortContourList(&contourList, false, false)) {
        result->setEmpty();
        return true;
    }
    SkOpContour* current = contourList;
    SkPathOpsBounds bounds = current->bounds();
    while ((current = current->next())) {
        bounds.add(current->bounds());
    }
    *result = bounds;
    return true;
}
コード例 #23
0
// resolve any coincident pairs found while intersecting, and
// see if coincidence is formed by clipping non-concident segments
void CoincidenceCheck(SkTArray<SkOpContour*, true>* contourList, int total) {
    int contourCount = (*contourList).count();
    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
        SkOpContour* contour = (*contourList)[cIndex];
        contour->addCoincidentPoints();
    }
    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
        SkOpContour* contour = (*contourList)[cIndex];
        contour->calcCoincidentWinding();
    }
    for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
        SkOpContour* contour = (*contourList)[cIndex];
        contour->calcPartialCoincidentWinding();
    }
}
コード例 #24
0
ファイル: SkPathOpsCommon.cpp プロジェクト: Just-D/skia
static void moveMultiples(SkOpContourHead* contourList) {
    SkOpContour* contour = contourList;
    do {
        contour->moveMultiples();
    } while ((contour = contour->next()));
}
コード例 #25
0
ファイル: SkPathOpsCommon.cpp プロジェクト: Just-D/skia
static void moveNearby(SkOpContourHead* contourList) {
    SkOpContour* contour = contourList;
    do {
        contour->moveNearby();
    } while ((contour = contour->next()));
}
コード例 #26
0
ファイル: SkPathOpsCommon.cpp プロジェクト: Just-D/skia
static void sortAngles(SkOpContourHead* contourList) {
    SkOpContour* contour = contourList;
    do {
        contour->sortAngles();
    } while ((contour = contour->next()));
}
コード例 #27
0
ファイル: SkOpBuilder.cpp プロジェクト: OwenTan/skia
bool FixWinding(SkPath* path) {
    SkPath::FillType fillType = path->getFillType();
    if (fillType == SkPath::kInverseEvenOdd_FillType) {
        fillType = SkPath::kInverseWinding_FillType;
    } else if (fillType == SkPath::kEvenOdd_FillType) {
        fillType = SkPath::kWinding_FillType;
    }
    SkPathPriv::FirstDirection dir;
    if (one_contour(*path) && SkPathPriv::CheapComputeFirstDirection(*path, &dir)) {
        if (dir != SkPathPriv::kCCW_FirstDirection) {
            SkPath temp;
            temp.reverseAddPath(*path);
            *path = temp;
        }
        path->setFillType(fillType);
        return true;
    }
    SkChunkAlloc allocator(4096);
    SkOpContourHead contourHead;
    SkOpGlobalState globalState(nullptr, &contourHead  SkDEBUGPARAMS(false)
            SkDEBUGPARAMS(nullptr));
    SkOpEdgeBuilder builder(*path, &contourHead, &allocator, &globalState);
    builder.finish(&allocator);
    if (!contourHead.next()) {
        return false;
    }
    contourHead.resetReverse();
    bool writePath = false;
    SkOpSpan* topSpan;
    globalState.setPhase(SkOpGlobalState::kFixWinding);
    while ((topSpan = FindSortableTop(&contourHead))) {
        SkOpSegment* topSegment = topSpan->segment();
        SkOpContour* topContour = topSegment->contour();
        SkASSERT(topContour->isCcw() >= 0);
#if DEBUG_WINDING
        SkDebugf("%s id=%d nested=%d ccw=%d\n",  __FUNCTION__,
                topSegment->debugID(), globalState.nested(), topContour->isCcw());
#endif
        if ((globalState.nested() & 1) != SkToBool(topContour->isCcw())) {
            topContour->setReverse();
            writePath = true;
        }
        topContour->markDone();
        globalState.clearNested();
    }
    if (!writePath) {
        path->setFillType(fillType);
        return true;
    }
    SkPath empty;
    SkPathWriter woundPath(empty);
    SkOpContour* test = &contourHead;
    do {
        if (test->reversed()) {
            test->toReversePath(&woundPath);
        } else {
            test->toPath(&woundPath);
        }
    } while ((test = test->next()));
    *path = *woundPath.nativePath();
    path->setFillType(fillType);
    return true;
}
コード例 #28
0
static int contourRangeCheckY(const SkTArray<SkOpContour*, true>& contourList, SkOpSegment** currentPtr,
                              int* indexPtr, int* endIndexPtr, double* bestHit, SkScalar* bestDx,
                              bool* tryAgain, double* midPtr, bool opp) {
    const int index = *indexPtr;
    const int endIndex = *endIndexPtr;
    const double mid = *midPtr;
    const SkOpSegment* current = *currentPtr;
    double tAtMid = current->tAtMid(index, endIndex, mid);
    SkPoint basePt = current->ptAtT(tAtMid);
    int contourCount = contourList.count();
    SkScalar bestY = SK_ScalarMin;
    SkOpSegment* bestSeg = NULL;
    int bestTIndex = 0;
    bool bestOpp;
    bool hitSomething = false;
    for (int cTest = 0; cTest < contourCount; ++cTest) {
        SkOpContour* contour = contourList[cTest];
        bool testOpp = contour->operand() ^ current->operand() ^ opp;
        if (basePt.fY < contour->bounds().fTop) {
            continue;
        }
        if (bestY > contour->bounds().fBottom) {
            continue;
        }
        int segmentCount = contour->segments().count();
        for (int test = 0; test < segmentCount; ++test) {
            SkOpSegment* testSeg = &contour->segments()[test];
            SkScalar testY = bestY;
            double testHit;
            int testTIndex = testSeg->crossedSpanY(basePt, &testY, &testHit, &hitSomething, tAtMid,
                    testOpp, testSeg == current);
            if (testTIndex < 0) {
                if (testTIndex == SK_MinS32) {
                    hitSomething = true;
                    bestSeg = NULL;
                    goto abortContours;  // vertical encountered, return and try different point
                }
                continue;
            }
            if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
                double baseT = current->t(index);
                double endT = current->t(endIndex);
                double newMid = (testHit - baseT) / (endT - baseT);
#if DEBUG_WINDING
                double midT = current->tAtMid(index, endIndex, mid);
                SkPoint midXY = current->xyAtT(midT);
                double newMidT = current->tAtMid(index, endIndex, newMid);
                SkPoint newXY = current->xyAtT(newMidT);
                SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
                        " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
                        current->debugID(), mid, newMid,
                        baseT, current->xAtT(index), current->yAtT(index),
                        baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
                        baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
                        endT, current->xAtT(endIndex), current->yAtT(endIndex));
#endif
                *midPtr = newMid * 2;  // calling loop with divide by 2 before continuing
                return SK_MinS32;
            }
            bestSeg = testSeg;
            *bestHit = testHit;
            bestOpp = testOpp;
            bestTIndex = testTIndex;
            bestY = testY;
        }
    }
abortContours:
    int result;
    if (!bestSeg) {
        result = hitSomething ? SK_MinS32 : 0;
    } else {
        if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
            *currentPtr = bestSeg;
            *indexPtr = bestTIndex;
            *endIndexPtr = bestSeg->nextSpan(bestTIndex, 1);
            SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
            *tryAgain = true;
            return 0;
        }
        result = bestSeg->windingAtT(*bestHit, bestTIndex, bestOpp, bestDx);
        SkASSERT(result == SK_MinS32 || *bestDx);
    }
    double baseT = current->t(index);
    double endT = current->t(endIndex);
    *bestHit = baseT + mid * (endT - baseT);
    return result;
}
コード例 #29
0
ファイル: SkPathOpsOp.cpp プロジェクト: CodeSpeaker/gecko-dev
bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) {
#if DEBUG_SHOW_TEST_NAME
    char* debugName = DEBUG_FILENAME_STRING;
    if (debugName && debugName[0]) {
        SkPathOpsDebug::BumpTestName(debugName);
        SkPathOpsDebug::ShowPath(one, two, op, debugName);
    }
#endif
    op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()];
    SkPath::FillType fillType = gOutInverse[op][one.isInverseFillType()][two.isInverseFillType()]
            ? SkPath::kInverseEvenOdd_FillType : SkPath::kEvenOdd_FillType;
    const SkPath* minuend = &one;
    const SkPath* subtrahend = &two;
    if (op == kReverseDifference_PathOp) {
        minuend = &two;
        subtrahend = &one;
        op = kDifference_PathOp;
    }
#if DEBUG_SORT || DEBUG_SWAP_TOP
    SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault;
#endif
    // turn path into list of segments
    SkTArray<SkOpContour> contours;
    // FIXME: add self-intersecting cubics' T values to segment
    SkOpEdgeBuilder builder(*minuend, contours);
    const int xorMask = builder.xorMask();
    builder.addOperand(*subtrahend);
    if (!builder.finish()) {
        return false;
    }
    result->reset();
    result->setFillType(fillType);
    const int xorOpMask = builder.xorMask();
    SkTArray<SkOpContour*, true> contourList;
    MakeContourList(contours, contourList, xorMask == kEvenOdd_PathOpsMask,
            xorOpMask == kEvenOdd_PathOpsMask);
    SkOpContour** currentPtr = contourList.begin();
    if (!currentPtr) {
        return true;
    }
    SkOpContour** listEnd = contourList.end();
    // find all intersections between segments
    do {
        SkOpContour** nextPtr = currentPtr;
        SkOpContour* current = *currentPtr++;
        if (current->containsCubics()) {
            AddSelfIntersectTs(current);
        }
        SkOpContour* next;
        do {
            next = *nextPtr++;
        } while (AddIntersectTs(current, next) && nextPtr != listEnd);
    } while (currentPtr != listEnd);
    // eat through coincident edges

    int total = 0;
    int index;
    for (index = 0; index < contourList.count(); ++index) {
        total += contourList[index]->segments().count();
    }
    HandleCoincidence(&contourList, total);
    // construct closed contours
    SkPathWriter wrapper(*result);
    bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper);
    {  // if some edges could not be resolved, assemble remaining fragments
        SkPath temp;
        temp.setFillType(fillType);
        SkPathWriter assembled(temp);
        Assemble(wrapper, &assembled);
        *result = *assembled.nativePath();
        result->setFillType(fillType);
    }
    return true;
}
コード例 #30
0
static void testQuadAngles(skiatest::Reporter* reporter, const SkDQuad& quad1, const SkDQuad& quad2,
        int testNo, SkChunkAlloc* allocator) {
    SkPoint shortQuads[2][3];

    SkOpContour contour;
    SkOpGlobalState state(NULL  PATH_OPS_DEBUG_PARAMS(&contour));
    contour.init(&state, false, false);
    makeSegment(&contour, quad1, shortQuads[0], allocator);
    makeSegment(&contour, quad1, shortQuads[1], allocator);
    SkOpSegment* seg1 = contour.first();
    seg1->debugAddAngle(0, 1, allocator);
    SkOpSegment* seg2 = seg1->next();
    seg2->debugAddAngle(0, 1, allocator);
    int realOverlap = PathOpsAngleTester::ConvexHullOverlaps(*seg1->debugLastAngle(),
            *seg2->debugLastAngle());
    const SkDPoint& origin = quad1[0];
    REPORTER_ASSERT(reporter, origin == quad2[0]);
    double a1s = atan2(origin.fY - quad1[1].fY, quad1[1].fX - origin.fX);
    double a1e = atan2(origin.fY - quad1[2].fY, quad1[2].fX - origin.fX);
    double a2s = atan2(origin.fY - quad2[1].fY, quad2[1].fX - origin.fX);
    double a2e = atan2(origin.fY - quad2[2].fY, quad2[2].fX - origin.fX);
    bool oldSchoolOverlap = radianBetween(a1s, a2s, a1e)
        || radianBetween(a1s, a2e, a1e) || radianBetween(a2s, a1s, a2e)
        || radianBetween(a2s, a1e, a2e);
    int overlap = quadHullsOverlap(reporter, quad1, quad2);
    bool realMatchesOverlap = realOverlap == overlap || SK_ScalarPI - fabs(a2s - a1s) < 0.002;
    if (realOverlap != overlap) {
        SkDebugf("\nSK_ScalarPI - fabs(a2s - a1s) = %1.9g\n", SK_ScalarPI - fabs(a2s - a1s));
    }
    if (!realMatchesOverlap) {
        DumpQ(quad1, quad2, testNo);
    }
    REPORTER_ASSERT(reporter, realMatchesOverlap);
    if (oldSchoolOverlap != (overlap < 0)) {
        overlap = quadHullsOverlap(reporter, quad1, quad2);  // set a breakpoint and debug if assert fires
        REPORTER_ASSERT(reporter, oldSchoolOverlap == (overlap < 0));
    }
    SkDVector v1s = quad1[1] - quad1[0];
    SkDVector v1e = quad1[2] - quad1[0];
    SkDVector v2s = quad2[1] - quad2[0];
    SkDVector v2e = quad2[2] - quad2[0];
    double vDir[2] = { v1s.cross(v1e), v2s.cross(v2e) };
    bool ray1In2 = v1s.cross(v2s) * vDir[1] <= 0 && v1s.cross(v2e) * vDir[1] >= 0;
    bool ray2In1 = v2s.cross(v1s) * vDir[0] <= 0 && v2s.cross(v1e) * vDir[0] >= 0;
    if (overlap >= 0) {
        // verify that hulls really don't overlap
        REPORTER_ASSERT(reporter, !ray1In2);
        REPORTER_ASSERT(reporter, !ray2In1);
        bool ctrl1In2 = v1e.cross(v2s) * vDir[1] <= 0 && v1e.cross(v2e) * vDir[1] >= 0;
        REPORTER_ASSERT(reporter, !ctrl1In2);
        bool ctrl2In1 = v2e.cross(v1s) * vDir[0] <= 0 && v2e.cross(v1e) * vDir[0] >= 0;
        REPORTER_ASSERT(reporter, !ctrl2In1);
        // check answer against reference
        bruteForce(reporter, quad1, quad2, overlap > 0);
    }
    // continue end point rays and see if they intersect the opposite curve
    SkDLine rays[] = {{{origin, quad2[2]}}, {{origin, quad1[2]}}};
    const SkDQuad* quads[] = {&quad1, &quad2};
    SkDVector midSpokes[2];
    SkIntersections intersect[2];
    double minX, minY, maxX, maxY;
    minX = minY = SK_ScalarInfinity;
    maxX = maxY = -SK_ScalarInfinity;
    double maxWidth = 0;
    bool useIntersect = false;
    double smallestTs[] = {1, 1};
    for (unsigned index = 0; index < SK_ARRAY_COUNT(quads); ++index) {
        const SkDQuad& q = *quads[index];
        midSpokes[index] = q.ptAtT(0.5) - origin;
        minX = SkTMin(SkTMin(SkTMin(minX, origin.fX), q[1].fX), q[2].fX);
        minY = SkTMin(SkTMin(SkTMin(minY, origin.fY), q[1].fY), q[2].fY);
        maxX = SkTMax(SkTMax(SkTMax(maxX, origin.fX), q[1].fX), q[2].fX);
        maxY = SkTMax(SkTMax(SkTMax(maxY, origin.fY), q[1].fY), q[2].fY);
        maxWidth = SkTMax(maxWidth, SkTMax(maxX - minX, maxY - minY));
        intersect[index].intersectRay(q, rays[index]);
        const SkIntersections& i = intersect[index];
        REPORTER_ASSERT(reporter, i.used() >= 1);
        bool foundZero = false;
        double smallT = 1;
        for (int idx2 = 0; idx2 < i.used(); ++idx2) {
            double t = i[0][idx2];
            if (t == 0) {
                foundZero = true;
                continue;
            }
            if (smallT > t) {
                smallT = t;
            }
        }
        REPORTER_ASSERT(reporter, foundZero == true);
        if (smallT == 1) {
            continue;
        }
        SkDVector ray = q.ptAtT(smallT) - origin;
        SkDVector end = rays[index][1] - origin;
        if (ray.fX * end.fX < 0 || ray.fY * end.fY < 0) {
            continue;
        }
        double rayDist = ray.length();
        double endDist = end.length();
        double delta = fabs(rayDist - endDist) / maxWidth;
        if (delta > 1e-4) {
            useIntersect ^= true;
        }
        smallestTs[index] = smallT;
    }
    bool firstInside;
    if (useIntersect) {
        int sIndex = (int) (smallestTs[1] < 1);
        REPORTER_ASSERT(reporter, smallestTs[sIndex ^ 1] == 1);
        double t = smallestTs[sIndex];
        const SkDQuad& q = *quads[sIndex];
        SkDVector ray = q.ptAtT(t) - origin;
        SkDVector end = rays[sIndex][1] - origin;
        double rayDist = ray.length();
        double endDist = end.length();
        SkDVector mid = q.ptAtT(t / 2) - origin;
        double midXray = mid.crossCheck(ray);
        if (gPathOpsAngleIdeasVerbose) {
            SkDebugf("rayDist>endDist:%d sIndex==0:%d vDir[sIndex]<0:%d midXray<0:%d\n",
                    rayDist > endDist, sIndex == 0, vDir[sIndex] < 0, midXray < 0);
        }
        SkASSERT(SkScalarSignAsInt(SkDoubleToScalar(midXray))
            == SkScalarSignAsInt(SkDoubleToScalar(vDir[sIndex])));
        firstInside = (rayDist > endDist) ^ (sIndex == 0) ^ (vDir[sIndex] < 0);
    } else if (overlap >= 0) {
        return;  // answer has already been determined
    } else {
        firstInside = checkParallel(reporter, quad1, quad2);
    }
    if (overlap < 0) {
        SkDEBUGCODE(int realEnds =)
                PathOpsAngleTester::EndsIntersect(*seg1->debugLastAngle(),
                *seg2->debugLastAngle());
        SkASSERT(realEnds == (firstInside ? 1 : 0));
    }