/* * 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 "SkPathOpsPoint.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::conicTo(const SkPoint& pt1, const SkPoint& pt2, SkScalar weight) { lineTo(); if (fEmpty && AlmostEqualUlps(fDefer[0], pt1) && AlmostEqualUlps(pt1, pt2)) { deferredLine(pt2); return; } moveTo(); fDefer[1] = pt2; nudge(); fDefer[0] = fDefer[1]; #if DEBUG_PATH_CONSTRUCTION SkDebugf("path.conicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g);\n", pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY, weight); #endif fPathPtr->conicTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY, weight); fEmpty = false; } void SkPathWriter::cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) { lineTo(); if (fEmpty && AlmostEqualUlps(fDefer[0], pt1) && AlmostEqualUlps(pt1, pt2) && AlmostEqualUlps(pt2, pt3)) { deferredLine(pt3); return; } 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 && SkDPoint::ApproximatelyEqual(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(); if (fEmpty && AlmostEqualUlps(fDefer[0], pt1) && AlmostEqualUlps(pt1, pt2)) { deferredLine(pt2); return; } 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++; }