| /* |
| * Copyright 2012 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| #include "SkPathOpsTypes.h" |
| #include "SkPathWriter.h" |
| |
| // wrap path to keep track of whether the contour is initialized and non-empty |
| SkPathWriter::SkPathWriter(SkPath& path) |
| : fPathPtr(&path) |
| , fCloses(0) |
| , fMoves(0) |
| { |
| init(); |
| } |
| |
| void SkPathWriter::close() { |
| if (!fHasMove) { |
| return; |
| } |
| bool callClose = isClosed(); |
| lineTo(); |
| if (fEmpty) { |
| return; |
| } |
| if (callClose) { |
| #if DEBUG_PATH_CONSTRUCTION |
| SkDebugf("path.close();\n"); |
| #endif |
| fPathPtr->close(); |
| fCloses++; |
| } |
| init(); |
| } |
| |
| void SkPathWriter::cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) { |
| lineTo(); |
| moveTo(); |
| fDefer[1] = pt3; |
| nudge(); |
| fDefer[0] = fDefer[1]; |
| #if DEBUG_PATH_CONSTRUCTION |
| SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n", |
| pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY); |
| #endif |
| fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY); |
| fEmpty = false; |
| } |
| |
| void SkPathWriter::deferredLine(const SkPoint& pt) { |
| if (pt == fDefer[1]) { |
| return; |
| } |
| if (changedSlopes(pt)) { |
| lineTo(); |
| fDefer[0] = fDefer[1]; |
| } |
| fDefer[1] = pt; |
| } |
| |
| void SkPathWriter::deferredMove(const SkPoint& pt) { |
| fMoved = true; |
| fHasMove = true; |
| fEmpty = true; |
| fDefer[0] = fDefer[1] = pt; |
| } |
| |
| void SkPathWriter::deferredMoveLine(const SkPoint& pt) { |
| if (!fHasMove) { |
| deferredMove(pt); |
| } |
| deferredLine(pt); |
| } |
| |
| bool SkPathWriter::hasMove() const { |
| return fHasMove; |
| } |
| |
| void SkPathWriter::init() { |
| fEmpty = true; |
| fHasMove = false; |
| fMoved = false; |
| } |
| |
| bool SkPathWriter::isClosed() const { |
| return !fEmpty && fFirstPt == fDefer[1]; |
| } |
| |
| void SkPathWriter::lineTo() { |
| if (fDefer[0] == fDefer[1]) { |
| return; |
| } |
| moveTo(); |
| nudge(); |
| fEmpty = false; |
| #if DEBUG_PATH_CONSTRUCTION |
| SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY); |
| #endif |
| fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY); |
| fDefer[0] = fDefer[1]; |
| } |
| |
| const SkPath* SkPathWriter::nativePath() const { |
| return fPathPtr; |
| } |
| |
| void SkPathWriter::nudge() { |
| if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX) |
| || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) { |
| return; |
| } |
| fDefer[1] = fFirstPt; |
| } |
| |
| void SkPathWriter::quadTo(const SkPoint& pt1, const SkPoint& pt2) { |
| lineTo(); |
| moveTo(); |
| fDefer[1] = pt2; |
| nudge(); |
| fDefer[0] = fDefer[1]; |
| #if DEBUG_PATH_CONSTRUCTION |
| SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n", |
| pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY); |
| #endif |
| fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY); |
| fEmpty = false; |
| } |
| |
| bool SkPathWriter::someAssemblyRequired() const { |
| return fCloses < fMoves; |
| } |
| |
| bool SkPathWriter::changedSlopes(const SkPoint& pt) const { |
| if (fDefer[0] == fDefer[1]) { |
| return false; |
| } |
| SkScalar deferDx = fDefer[1].fX - fDefer[0].fX; |
| SkScalar deferDy = fDefer[1].fY - fDefer[0].fY; |
| SkScalar lineDx = pt.fX - fDefer[1].fX; |
| SkScalar lineDy = pt.fY - fDefer[1].fY; |
| return deferDx * lineDy != deferDy * lineDx; |
| } |
| |
| void SkPathWriter::moveTo() { |
| if (!fMoved) { |
| return; |
| } |
| fFirstPt = fDefer[0]; |
| #if DEBUG_PATH_CONSTRUCTION |
| SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY); |
| #endif |
| fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY); |
| fMoved = false; |
| fMoves++; |
| } |