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