1/*
2* Copyright 2013 Google Inc.
3*
4* Use of this source code is governed by a BSD-style license that can be
5* found in the LICENSE file.
6*/
7#include "SkOpContour.h"
8#include "SkPathWriter.h"
9#include "SkReduceOrder.h"
10#include "SkTSort.h"
11
12void SkOpContour::toPath(SkPathWriter* path) const {
13    if (!this->count()) {
14        return;
15    }
16    const SkOpSegment* segment = &fHead;
17    do {
18        SkAssertResult(segment->addCurveTo(segment->head(), segment->tail(), path));
19    } while ((segment = segment->next()));
20    path->finishContour();
21    path->assemble();
22}
23
24void SkOpContour::toReversePath(SkPathWriter* path) const {
25    const SkOpSegment* segment = fTail;
26    do {
27        SkAssertResult(segment->addCurveTo(segment->tail(), segment->head(), path));
28    } while ((segment = segment->prev()));
29    path->finishContour();
30    path->assemble();
31}
32
33SkOpSpan* SkOpContour::undoneSpan() {
34    SkOpSegment* testSegment = &fHead;
35    do {
36        if (testSegment->done()) {
37            continue;
38        }
39        return testSegment->undoneSpan();
40    } while ((testSegment = testSegment->next()));
41    fDone = true;
42    return nullptr;
43}
44
45void SkOpContourBuilder::addConic(SkPoint pts[3], SkScalar weight) {
46    this->flush();
47    fContour->addConic(pts, weight);
48}
49
50void SkOpContourBuilder::addCubic(SkPoint pts[4]) {
51    this->flush();
52    fContour->addCubic(pts);
53}
54
55void SkOpContourBuilder::addCurve(SkPath::Verb verb, const SkPoint pts[4], SkScalar weight) {
56    if (SkPath::kLine_Verb == verb) {
57        this->addLine(pts);
58        return;
59    }
60    SkArenaAlloc* allocator = fContour->globalState()->allocator();
61    switch (verb) {
62        case SkPath::kQuad_Verb: {
63            SkPoint* ptStorage = allocator->makeArrayDefault<SkPoint>(3);
64            memcpy(ptStorage, pts, sizeof(SkPoint) * 3);
65            this->addQuad(ptStorage);
66        } break;
67        case SkPath::kConic_Verb: {
68            SkPoint* ptStorage = allocator->makeArrayDefault<SkPoint>(3);
69            memcpy(ptStorage, pts, sizeof(SkPoint) * 3);
70            this->addConic(ptStorage, weight);
71        } break;
72        case SkPath::kCubic_Verb: {
73            SkPoint* ptStorage = allocator->makeArrayDefault<SkPoint>(4);
74            memcpy(ptStorage, pts, sizeof(SkPoint) * 4);
75            this->addCubic(ptStorage);
76        } break;
77        default:
78            SkASSERT(0);
79    }
80}
81
82void SkOpContourBuilder::addLine(const SkPoint pts[2]) {
83    // if the previous line added is the exact opposite, eliminate both
84    if (fLastIsLine) {
85        if (fLastLine[0] == pts[1] && fLastLine[1] == pts[0]) {
86            fLastIsLine = false;
87            return;
88        } else {
89            flush();
90        }
91    }
92    memcpy(fLastLine, pts, sizeof(fLastLine));
93    fLastIsLine = true;
94}
95
96void SkOpContourBuilder::addQuad(SkPoint pts[3]) {
97    this->flush();
98    fContour->addQuad(pts);
99}
100
101void SkOpContourBuilder::flush() {
102    if (!fLastIsLine)
103        return;
104    SkArenaAlloc* allocator = fContour->globalState()->allocator();
105    SkPoint* ptStorage = allocator->makeArrayDefault<SkPoint>(2);
106    memcpy(ptStorage, fLastLine, sizeof(fLastLine));
107    (void) fContour->addLine(ptStorage);
108    fLastIsLine = false;
109}
110