gfx/skia/trunk/src/pathops/SkPathOpsSimplify.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/pathops/SkPathOpsSimplify.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,199 @@
     1.4 +/*
     1.5 + * Copyright 2012 Google Inc.
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +#include "SkAddIntersections.h"
    1.11 +#include "SkOpEdgeBuilder.h"
    1.12 +#include "SkPathOpsCommon.h"
    1.13 +#include "SkPathWriter.h"
    1.14 +
    1.15 +static bool bridgeWinding(SkTArray<SkOpContour*, true>& contourList, SkPathWriter* simple) {
    1.16 +    bool firstContour = true;
    1.17 +    bool unsortable = false;
    1.18 +    bool topUnsortable = false;
    1.19 +    SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
    1.20 +    do {
    1.21 +        int index, endIndex;
    1.22 +        bool topDone;
    1.23 +        SkOpSegment* current = FindSortableTop(contourList, SkOpAngle::kUnaryWinding, &firstContour,
    1.24 +                &index, &endIndex, &topLeft, &topUnsortable, &topDone);
    1.25 +        if (!current) {
    1.26 +            if (topUnsortable || !topDone) {
    1.27 +                topUnsortable = false;
    1.28 +                SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
    1.29 +                topLeft.fX = topLeft.fY = SK_ScalarMin;
    1.30 +                continue;
    1.31 +            }
    1.32 +            break;
    1.33 +        }
    1.34 +        SkTDArray<SkOpSpan*> chaseArray;
    1.35 +        do {
    1.36 +            if (current->activeWinding(index, endIndex)) {
    1.37 +                do {
    1.38 +                    if (!unsortable && current->done()) {
    1.39 +            #if DEBUG_ACTIVE_SPANS
    1.40 +                        DebugShowActiveSpans(contourList);
    1.41 +            #endif
    1.42 +                        if (simple->isEmpty()) {
    1.43 +                            simple->init();
    1.44 +                            break;
    1.45 +                        }
    1.46 +                    }
    1.47 +                    SkASSERT(unsortable || !current->done());
    1.48 +                    int nextStart = index;
    1.49 +                    int nextEnd = endIndex;
    1.50 +                    SkOpSegment* next = current->findNextWinding(&chaseArray, &nextStart, &nextEnd,
    1.51 +                            &unsortable);
    1.52 +                    if (!next) {
    1.53 +                        if (!unsortable && simple->hasMove()
    1.54 +                                && current->verb() != SkPath::kLine_Verb
    1.55 +                                && !simple->isClosed()) {
    1.56 +                            current->addCurveTo(index, endIndex, simple, true);
    1.57 +                            SkASSERT(simple->isClosed());
    1.58 +                        }
    1.59 +                        break;
    1.60 +                    }
    1.61 +        #if DEBUG_FLOW
    1.62 +            SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
    1.63 +                    current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
    1.64 +                    current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
    1.65 +        #endif
    1.66 +                    current->addCurveTo(index, endIndex, simple, true);
    1.67 +                    current = next;
    1.68 +                    index = nextStart;
    1.69 +                    endIndex = nextEnd;
    1.70 +                } while (!simple->isClosed() && (!unsortable
    1.71 +                        || !current->done(SkMin32(index, endIndex))));
    1.72 +                if (current->activeWinding(index, endIndex) && !simple->isClosed()) {
    1.73 +                    SkASSERT(unsortable || simple->isEmpty());
    1.74 +                    int min = SkMin32(index, endIndex);
    1.75 +                    if (!current->done(min)) {
    1.76 +                        current->addCurveTo(index, endIndex, simple, true);
    1.77 +                        current->markDoneUnary(min);
    1.78 +                    }
    1.79 +                }
    1.80 +                simple->close();
    1.81 +            } else {
    1.82 +                SkOpSpan* last = current->markAndChaseDoneUnary(index, endIndex);
    1.83 +                if (last && !last->fLoop) {
    1.84 +                    *chaseArray.append() = last;
    1.85 +                }
    1.86 +            }
    1.87 +            current = FindChase(chaseArray, index, endIndex);
    1.88 +        #if DEBUG_ACTIVE_SPANS
    1.89 +            DebugShowActiveSpans(contourList);
    1.90 +        #endif
    1.91 +            if (!current) {
    1.92 +                break;
    1.93 +            }
    1.94 +        } while (true);
    1.95 +    } while (true);
    1.96 +    return simple->someAssemblyRequired();
    1.97 +}
    1.98 +
    1.99 +// returns true if all edges were processed
   1.100 +static bool bridgeXor(SkTArray<SkOpContour*, true>& contourList, SkPathWriter* simple) {
   1.101 +    SkOpSegment* current;
   1.102 +    int start, end;
   1.103 +    bool unsortable = false;
   1.104 +    bool closable = true;
   1.105 +    while ((current = FindUndone(contourList, &start, &end))) {
   1.106 +        do {
   1.107 +    #if DEBUG_ACTIVE_SPANS
   1.108 +            if (!unsortable && current->done()) {
   1.109 +                DebugShowActiveSpans(contourList);
   1.110 +            }
   1.111 +    #endif
   1.112 +            SkASSERT(unsortable || !current->done());
   1.113 +            int nextStart = start;
   1.114 +            int nextEnd = end;
   1.115 +            SkOpSegment* next = current->findNextXor(&nextStart, &nextEnd, &unsortable);
   1.116 +            if (!next) {
   1.117 +                if (!unsortable && simple->hasMove()
   1.118 +                        && current->verb() != SkPath::kLine_Verb
   1.119 +                        && !simple->isClosed()) {
   1.120 +                    current->addCurveTo(start, end, simple, true);
   1.121 +                    SkASSERT(simple->isClosed());
   1.122 +                }
   1.123 +                break;
   1.124 +            }
   1.125 +        #if DEBUG_FLOW
   1.126 +            SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
   1.127 +                    current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
   1.128 +                    current->xyAtT(end).fX, current->xyAtT(end).fY);
   1.129 +        #endif
   1.130 +            current->addCurveTo(start, end, simple, true);
   1.131 +            current = next;
   1.132 +            start = nextStart;
   1.133 +            end = nextEnd;
   1.134 +        } while (!simple->isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
   1.135 +        if (!simple->isClosed()) {
   1.136 +            SkASSERT(unsortable);
   1.137 +            int min = SkMin32(start, end);
   1.138 +            if (!current->done(min)) {
   1.139 +                current->addCurveTo(start, end, simple, true);
   1.140 +                current->markDone(min, 1);
   1.141 +            }
   1.142 +            closable = false;
   1.143 +        }
   1.144 +        simple->close();
   1.145 +    #if DEBUG_ACTIVE_SPANS
   1.146 +        DebugShowActiveSpans(contourList);
   1.147 +    #endif
   1.148 +    }
   1.149 +    return closable;
   1.150 +}
   1.151 +
   1.152 +// FIXME : add this as a member of SkPath
   1.153 +bool Simplify(const SkPath& path, SkPath* result) {
   1.154 +#if DEBUG_SORT || DEBUG_SWAP_TOP
   1.155 +    SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault;
   1.156 +#endif
   1.157 +    // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
   1.158 +    SkPath::FillType fillType = path.isInverseFillType() ? SkPath::kInverseEvenOdd_FillType
   1.159 +            : SkPath::kEvenOdd_FillType;
   1.160 +
   1.161 +    // turn path into list of segments
   1.162 +    SkTArray<SkOpContour> contours;
   1.163 +    SkOpEdgeBuilder builder(path, contours);
   1.164 +    if (!builder.finish()) {
   1.165 +        return false;
   1.166 +    }
   1.167 +    SkTArray<SkOpContour*, true> contourList;
   1.168 +    MakeContourList(contours, contourList, false, false);
   1.169 +    SkOpContour** currentPtr = contourList.begin();
   1.170 +    result->reset();
   1.171 +    result->setFillType(fillType);
   1.172 +    if (!currentPtr) {
   1.173 +        return true;
   1.174 +    }
   1.175 +    SkOpContour** listEnd = contourList.end();
   1.176 +    // find all intersections between segments
   1.177 +    do {
   1.178 +        SkOpContour** nextPtr = currentPtr;
   1.179 +        SkOpContour* current = *currentPtr++;
   1.180 +        if (current->containsCubics()) {
   1.181 +            AddSelfIntersectTs(current);
   1.182 +        }
   1.183 +        SkOpContour* next;
   1.184 +        do {
   1.185 +            next = *nextPtr++;
   1.186 +        } while (AddIntersectTs(current, next) && nextPtr != listEnd);
   1.187 +    } while (currentPtr != listEnd);
   1.188 +    HandleCoincidence(&contourList, 0);
   1.189 +    // construct closed contours
   1.190 +    SkPathWriter simple(*result);
   1.191 +    if (builder.xorMask() == kWinding_PathOpsMask ? bridgeWinding(contourList, &simple)
   1.192 +                : !bridgeXor(contourList, &simple))
   1.193 +    {  // if some edges could not be resolved, assemble remaining fragments
   1.194 +        SkPath temp;
   1.195 +        temp.setFillType(fillType);
   1.196 +        SkPathWriter assembled(temp);
   1.197 +        Assemble(simple, &assembled);
   1.198 +        *result = *assembled.nativePath();
   1.199 +        result->setFillType(fillType);
   1.200 +    }
   1.201 +    return true;
   1.202 +}

mercurial