|  | /* | 
|  | * Copyright 2013 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  | #include "src/core/SkTSort.h" | 
|  | #include "src/pathops/SkOpContour.h" | 
|  | #include "src/pathops/SkPathWriter.h" | 
|  | #include "src/pathops/SkReduceOrder.h" | 
|  |  | 
|  | void SkOpContour::toPath(SkPathWriter* path) const { | 
|  | if (!this->count()) { | 
|  | return; | 
|  | } | 
|  | const SkOpSegment* segment = &fHead; | 
|  | do { | 
|  | SkAssertResult(segment->addCurveTo(segment->head(), segment->tail(), path)); | 
|  | } while ((segment = segment->next())); | 
|  | path->finishContour(); | 
|  | path->assemble(); | 
|  | } | 
|  |  | 
|  | void SkOpContour::toReversePath(SkPathWriter* path) const { | 
|  | const SkOpSegment* segment = fTail; | 
|  | do { | 
|  | SkAssertResult(segment->addCurveTo(segment->tail(), segment->head(), path)); | 
|  | } while ((segment = segment->prev())); | 
|  | path->finishContour(); | 
|  | path->assemble(); | 
|  | } | 
|  |  | 
|  | SkOpSpan* SkOpContour::undoneSpan() { | 
|  | SkOpSegment* testSegment = &fHead; | 
|  | do { | 
|  | if (testSegment->done()) { | 
|  | continue; | 
|  | } | 
|  | return testSegment->undoneSpan(); | 
|  | } while ((testSegment = testSegment->next())); | 
|  | fDone = true; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | void SkOpContourBuilder::addConic(SkPoint pts[3], SkScalar weight) { | 
|  | this->flush(); | 
|  | fContour->addConic(pts, weight); | 
|  | } | 
|  |  | 
|  | void SkOpContourBuilder::addCubic(SkPoint pts[4]) { | 
|  | this->flush(); | 
|  | fContour->addCubic(pts); | 
|  | } | 
|  |  | 
|  | void SkOpContourBuilder::addCurve(SkPath::Verb verb, const SkPoint pts[4], SkScalar weight) { | 
|  | if (SkPath::kLine_Verb == verb) { | 
|  | this->addLine(pts); | 
|  | return; | 
|  | } | 
|  | SkArenaAlloc* allocator = fContour->globalState()->allocator(); | 
|  | switch (verb) { | 
|  | case SkPath::kQuad_Verb: { | 
|  | SkPoint* ptStorage = allocator->makeArrayDefault<SkPoint>(3); | 
|  | memcpy(ptStorage, pts, sizeof(SkPoint) * 3); | 
|  | this->addQuad(ptStorage); | 
|  | } break; | 
|  | case SkPath::kConic_Verb: { | 
|  | SkPoint* ptStorage = allocator->makeArrayDefault<SkPoint>(3); | 
|  | memcpy(ptStorage, pts, sizeof(SkPoint) * 3); | 
|  | this->addConic(ptStorage, weight); | 
|  | } break; | 
|  | case SkPath::kCubic_Verb: { | 
|  | SkPoint* ptStorage = allocator->makeArrayDefault<SkPoint>(4); | 
|  | memcpy(ptStorage, pts, sizeof(SkPoint) * 4); | 
|  | this->addCubic(ptStorage); | 
|  | } break; | 
|  | default: | 
|  | SkASSERT(0); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SkOpContourBuilder::addLine(const SkPoint pts[2]) { | 
|  | // if the previous line added is the exact opposite, eliminate both | 
|  | if (fLastIsLine) { | 
|  | if (fLastLine[0] == pts[1] && fLastLine[1] == pts[0]) { | 
|  | fLastIsLine = false; | 
|  | return; | 
|  | } else { | 
|  | flush(); | 
|  | } | 
|  | } | 
|  | memcpy(fLastLine, pts, sizeof(fLastLine)); | 
|  | fLastIsLine = true; | 
|  | } | 
|  |  | 
|  | void SkOpContourBuilder::addQuad(SkPoint pts[3]) { | 
|  | this->flush(); | 
|  | fContour->addQuad(pts); | 
|  | } | 
|  |  | 
|  | void SkOpContourBuilder::flush() { | 
|  | if (!fLastIsLine) | 
|  | return; | 
|  | SkArenaAlloc* allocator = fContour->globalState()->allocator(); | 
|  | SkPoint* ptStorage = allocator->makeArrayDefault<SkPoint>(2); | 
|  | memcpy(ptStorage, fLastLine, sizeof(fLastLine)); | 
|  | (void) fContour->addLine(ptStorage); | 
|  | fLastIsLine = false; | 
|  | } |