1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h"
9cb93a386Sopenharmony_ci#include "include/pathops/SkPathOps.h"
10cb93a386Sopenharmony_ci#include "src/core/SkArenaAlloc.h"
11cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h"
12cb93a386Sopenharmony_ci#include "src/pathops/SkOpEdgeBuilder.h"
13cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCommon.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_cistatic bool one_contour(const SkPath& path) {
16cb93a386Sopenharmony_ci    SkSTArenaAlloc<256> allocator;
17cb93a386Sopenharmony_ci    int verbCount = path.countVerbs();
18cb93a386Sopenharmony_ci    uint8_t* verbs = (uint8_t*) allocator.makeArrayDefault<uint8_t>(verbCount);
19cb93a386Sopenharmony_ci    (void) path.getVerbs(verbs, verbCount);
20cb93a386Sopenharmony_ci    for (int index = 1; index < verbCount; ++index) {
21cb93a386Sopenharmony_ci        if (verbs[index] == SkPath::kMove_Verb) {
22cb93a386Sopenharmony_ci            return false;
23cb93a386Sopenharmony_ci        }
24cb93a386Sopenharmony_ci    }
25cb93a386Sopenharmony_ci    return true;
26cb93a386Sopenharmony_ci}
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_civoid SkOpBuilder::ReversePath(SkPath* path) {
29cb93a386Sopenharmony_ci    SkPath temp;
30cb93a386Sopenharmony_ci    SkPoint lastPt;
31cb93a386Sopenharmony_ci    SkAssertResult(path->getLastPt(&lastPt));
32cb93a386Sopenharmony_ci    temp.moveTo(lastPt);
33cb93a386Sopenharmony_ci    temp.reversePathTo(*path);
34cb93a386Sopenharmony_ci    temp.close();
35cb93a386Sopenharmony_ci    *path = temp;
36cb93a386Sopenharmony_ci}
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_cibool SkOpBuilder::FixWinding(SkPath* path) {
39cb93a386Sopenharmony_ci    SkPathFillType fillType = path->getFillType();
40cb93a386Sopenharmony_ci    if (fillType == SkPathFillType::kInverseEvenOdd) {
41cb93a386Sopenharmony_ci        fillType = SkPathFillType::kInverseWinding;
42cb93a386Sopenharmony_ci    } else if (fillType == SkPathFillType::kEvenOdd) {
43cb93a386Sopenharmony_ci        fillType = SkPathFillType::kWinding;
44cb93a386Sopenharmony_ci    }
45cb93a386Sopenharmony_ci    if (one_contour(*path)) {
46cb93a386Sopenharmony_ci        SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(*path);
47cb93a386Sopenharmony_ci        if (dir != SkPathFirstDirection::kUnknown) {
48cb93a386Sopenharmony_ci            if (dir == SkPathFirstDirection::kCW) {
49cb93a386Sopenharmony_ci                ReversePath(path);
50cb93a386Sopenharmony_ci            }
51cb93a386Sopenharmony_ci            path->setFillType(fillType);
52cb93a386Sopenharmony_ci            return true;
53cb93a386Sopenharmony_ci        }
54cb93a386Sopenharmony_ci    }
55cb93a386Sopenharmony_ci    SkSTArenaAlloc<4096> allocator;
56cb93a386Sopenharmony_ci    SkOpContourHead contourHead;
57cb93a386Sopenharmony_ci    SkOpGlobalState globalState(&contourHead, &allocator  SkDEBUGPARAMS(false)
58cb93a386Sopenharmony_ci            SkDEBUGPARAMS(nullptr));
59cb93a386Sopenharmony_ci    SkOpEdgeBuilder builder(*path, &contourHead, &globalState);
60cb93a386Sopenharmony_ci    if (builder.unparseable() || !builder.finish()) {
61cb93a386Sopenharmony_ci        return false;
62cb93a386Sopenharmony_ci    }
63cb93a386Sopenharmony_ci    if (!contourHead.count()) {
64cb93a386Sopenharmony_ci        return true;
65cb93a386Sopenharmony_ci    }
66cb93a386Sopenharmony_ci    if (!contourHead.next()) {
67cb93a386Sopenharmony_ci        return false;
68cb93a386Sopenharmony_ci    }
69cb93a386Sopenharmony_ci    contourHead.joinAllSegments();
70cb93a386Sopenharmony_ci    contourHead.resetReverse();
71cb93a386Sopenharmony_ci    bool writePath = false;
72cb93a386Sopenharmony_ci    SkOpSpan* topSpan;
73cb93a386Sopenharmony_ci    globalState.setPhase(SkOpPhase::kFixWinding);
74cb93a386Sopenharmony_ci    while ((topSpan = FindSortableTop(&contourHead))) {
75cb93a386Sopenharmony_ci        SkOpSegment* topSegment = topSpan->segment();
76cb93a386Sopenharmony_ci        SkOpContour* topContour = topSegment->contour();
77cb93a386Sopenharmony_ci        SkASSERT(topContour->isCcw() >= 0);
78cb93a386Sopenharmony_ci#if DEBUG_WINDING
79cb93a386Sopenharmony_ci        SkDebugf("%s id=%d nested=%d ccw=%d\n",  __FUNCTION__,
80cb93a386Sopenharmony_ci                topSegment->debugID(), globalState.nested(), topContour->isCcw());
81cb93a386Sopenharmony_ci#endif
82cb93a386Sopenharmony_ci        if ((globalState.nested() & 1) != SkToBool(topContour->isCcw())) {
83cb93a386Sopenharmony_ci            topContour->setReverse();
84cb93a386Sopenharmony_ci            writePath = true;
85cb93a386Sopenharmony_ci        }
86cb93a386Sopenharmony_ci        topContour->markAllDone();
87cb93a386Sopenharmony_ci        globalState.clearNested();
88cb93a386Sopenharmony_ci    }
89cb93a386Sopenharmony_ci    if (!writePath) {
90cb93a386Sopenharmony_ci        path->setFillType(fillType);
91cb93a386Sopenharmony_ci        return true;
92cb93a386Sopenharmony_ci    }
93cb93a386Sopenharmony_ci    SkPath empty;
94cb93a386Sopenharmony_ci    SkPathWriter woundPath(empty);
95cb93a386Sopenharmony_ci    SkOpContour* test = &contourHead;
96cb93a386Sopenharmony_ci    do {
97cb93a386Sopenharmony_ci        if (!test->count()) {
98cb93a386Sopenharmony_ci            continue;
99cb93a386Sopenharmony_ci        }
100cb93a386Sopenharmony_ci        if (test->reversed()) {
101cb93a386Sopenharmony_ci            test->toReversePath(&woundPath);
102cb93a386Sopenharmony_ci        } else {
103cb93a386Sopenharmony_ci            test->toPath(&woundPath);
104cb93a386Sopenharmony_ci        }
105cb93a386Sopenharmony_ci    } while ((test = test->next()));
106cb93a386Sopenharmony_ci    *path = *woundPath.nativePath();
107cb93a386Sopenharmony_ci    path->setFillType(fillType);
108cb93a386Sopenharmony_ci    return true;
109cb93a386Sopenharmony_ci}
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_civoid SkOpBuilder::add(const SkPath& path, SkPathOp op) {
112cb93a386Sopenharmony_ci    if (0 == fOps.count() && op != kUnion_SkPathOp) {
113cb93a386Sopenharmony_ci        fPathRefs.push_back() = SkPath();
114cb93a386Sopenharmony_ci        *fOps.append() = kUnion_SkPathOp;
115cb93a386Sopenharmony_ci    }
116cb93a386Sopenharmony_ci    fPathRefs.push_back() = path;
117cb93a386Sopenharmony_ci    *fOps.append() = op;
118cb93a386Sopenharmony_ci}
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_civoid SkOpBuilder::reset() {
121cb93a386Sopenharmony_ci    fPathRefs.reset();
122cb93a386Sopenharmony_ci    fOps.reset();
123cb93a386Sopenharmony_ci}
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci/* OPTIMIZATION: Union doesn't need to be all-or-nothing. A run of three or more convex
126cb93a386Sopenharmony_ci   paths with union ops could be locally resolved and still improve over doing the
127cb93a386Sopenharmony_ci   ops one at a time. */
128cb93a386Sopenharmony_cibool SkOpBuilder::resolve(SkPath* result) {
129cb93a386Sopenharmony_ci    SkPath original = *result;
130cb93a386Sopenharmony_ci    int count = fOps.count();
131cb93a386Sopenharmony_ci    bool allUnion = true;
132cb93a386Sopenharmony_ci    SkPathFirstDirection firstDir = SkPathFirstDirection::kUnknown;
133cb93a386Sopenharmony_ci    for (int index = 0; index < count; ++index) {
134cb93a386Sopenharmony_ci        SkPath* test = &fPathRefs[index];
135cb93a386Sopenharmony_ci        if (kUnion_SkPathOp != fOps[index] || test->isInverseFillType()) {
136cb93a386Sopenharmony_ci            allUnion = false;
137cb93a386Sopenharmony_ci            break;
138cb93a386Sopenharmony_ci        }
139cb93a386Sopenharmony_ci        // If all paths are convex, track direction, reversing as needed.
140cb93a386Sopenharmony_ci        if (test->isConvex()) {
141cb93a386Sopenharmony_ci            SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(*test);
142cb93a386Sopenharmony_ci            if (dir == SkPathFirstDirection::kUnknown) {
143cb93a386Sopenharmony_ci                allUnion = false;
144cb93a386Sopenharmony_ci                break;
145cb93a386Sopenharmony_ci            }
146cb93a386Sopenharmony_ci            if (firstDir == SkPathFirstDirection::kUnknown) {
147cb93a386Sopenharmony_ci                firstDir = dir;
148cb93a386Sopenharmony_ci            } else if (firstDir != dir) {
149cb93a386Sopenharmony_ci                ReversePath(test);
150cb93a386Sopenharmony_ci            }
151cb93a386Sopenharmony_ci            continue;
152cb93a386Sopenharmony_ci        }
153cb93a386Sopenharmony_ci        // If the path is not convex but its bounds do not intersect the others, simplify is enough.
154cb93a386Sopenharmony_ci        const SkRect& testBounds = test->getBounds();
155cb93a386Sopenharmony_ci        for (int inner = 0; inner < index; ++inner) {
156cb93a386Sopenharmony_ci            // OPTIMIZE: check to see if the contour bounds do not intersect other contour bounds?
157cb93a386Sopenharmony_ci            if (SkRect::Intersects(fPathRefs[inner].getBounds(), testBounds)) {
158cb93a386Sopenharmony_ci                allUnion = false;
159cb93a386Sopenharmony_ci                break;
160cb93a386Sopenharmony_ci            }
161cb93a386Sopenharmony_ci        }
162cb93a386Sopenharmony_ci    }
163cb93a386Sopenharmony_ci    if (!allUnion) {
164cb93a386Sopenharmony_ci        *result = fPathRefs[0];
165cb93a386Sopenharmony_ci        for (int index = 1; index < count; ++index) {
166cb93a386Sopenharmony_ci            if (!Op(*result, fPathRefs[index], fOps[index], result)) {
167cb93a386Sopenharmony_ci                reset();
168cb93a386Sopenharmony_ci                *result = original;
169cb93a386Sopenharmony_ci                return false;
170cb93a386Sopenharmony_ci            }
171cb93a386Sopenharmony_ci        }
172cb93a386Sopenharmony_ci        reset();
173cb93a386Sopenharmony_ci        return true;
174cb93a386Sopenharmony_ci    }
175cb93a386Sopenharmony_ci    SkPath sum;
176cb93a386Sopenharmony_ci    for (int index = 0; index < count; ++index) {
177cb93a386Sopenharmony_ci        if (!Simplify(fPathRefs[index], &fPathRefs[index])) {
178cb93a386Sopenharmony_ci            reset();
179cb93a386Sopenharmony_ci            *result = original;
180cb93a386Sopenharmony_ci            return false;
181cb93a386Sopenharmony_ci        }
182cb93a386Sopenharmony_ci        if (!fPathRefs[index].isEmpty()) {
183cb93a386Sopenharmony_ci            // convert the even odd result back to winding form before accumulating it
184cb93a386Sopenharmony_ci            if (!FixWinding(&fPathRefs[index])) {
185cb93a386Sopenharmony_ci                *result = original;
186cb93a386Sopenharmony_ci                return false;
187cb93a386Sopenharmony_ci            }
188cb93a386Sopenharmony_ci            sum.addPath(fPathRefs[index]);
189cb93a386Sopenharmony_ci        }
190cb93a386Sopenharmony_ci    }
191cb93a386Sopenharmony_ci    reset();
192cb93a386Sopenharmony_ci    bool success = Simplify(sum, result);
193cb93a386Sopenharmony_ci    if (!success) {
194cb93a386Sopenharmony_ci        *result = original;
195cb93a386Sopenharmony_ci    }
196cb93a386Sopenharmony_ci    return success;
197cb93a386Sopenharmony_ci}
198