Index: skia/sgl/SkPath.cpp |
=================================================================== |
--- skia/sgl/SkPath.cpp (revision 16859) |
+++ skia/sgl/SkPath.cpp (working copy) |
@@ -1,1427 +0,0 @@ |
-/* libs/graphics/sgl/SkPath.cpp |
-** |
-** Copyright 2006, The Android Open Source Project |
-** |
-** Licensed under the Apache License, Version 2.0 (the "License"); |
-** you may not use this file except in compliance with the License. |
-** You may obtain a copy of the License at |
-** |
-** http://www.apache.org/licenses/LICENSE-2.0 |
-** |
-** Unless required by applicable law or agreed to in writing, software |
-** distributed under the License is distributed on an "AS IS" BASIS, |
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-** See the License for the specific language governing permissions and |
-** limitations under the License. |
-*/ |
- |
-#include "SkPath.h" |
-#include "SkFlattenable.h" |
-#include "SkMath.h" |
- |
-//////////////////////////////////////////////////////////////////////////// |
- |
-/* This guy's constructor/destructor bracket a path editing operation. It is |
- used when we know the bounds of the amount we are going to add to the path |
- (usually a new contour, but not required). |
- |
- It captures some state about the path up front (i.e. if it already has a |
- cached bounds), and the if it can, it updates the cache bounds explicitly, |
- avoiding the need to revisit all of the points in computeBounds(). |
- */ |
-class SkAutoPathBoundsUpdate { |
-public: |
- SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) { |
- this->init(path); |
- } |
- |
- SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top, |
- SkScalar right, SkScalar bottom) { |
- fRect.set(left, top, right, bottom); |
- this->init(path); |
- } |
- |
- ~SkAutoPathBoundsUpdate() { |
- if (fEmpty) { |
- fPath->fFastBounds = fRect; |
- fPath->fFastBoundsIsDirty = false; |
- } else if (!fDirty) { |
- fPath->fFastBounds.join(fRect); |
- fPath->fFastBoundsIsDirty = false; |
- } |
- } |
- |
-private: |
- const SkPath* fPath; |
- SkRect fRect; |
- bool fDirty; |
- bool fEmpty; |
- |
- // returns true if we should proceed |
- void init(const SkPath* path) { |
- fPath = path; |
- fDirty = path->fFastBoundsIsDirty; |
- fEmpty = path->isEmpty(); |
- } |
-}; |
- |
-static void compute_fast_bounds(SkRect* bounds, const SkTDArray<SkPoint>& pts) { |
- if (pts.count() <= 1) { // we ignore just 1 point (moveto) |
- bounds->set(0, 0, 0, 0); |
- } else { |
- bounds->set(pts.begin(), pts.count()); |
-// SkDebugf("------- compute bounds %p %d", &pts, pts.count()); |
- } |
-} |
- |
-//////////////////////////////////////////////////////////////////////////// |
- |
-/* |
- Stores the verbs and points as they are given to us, with exceptions: |
- - we only record "Close" if it was immediately preceeded by Line | Quad | Cubic |
- - we insert a Move(0,0) if Line | Quad | Cubic is our first command |
- |
- The iterator does more cleanup, especially if forceClose == true |
- 1. if we encounter Close, return a cons'd up Line() first (if the curr-pt != start-pt) |
- 2. if we encounter Move without a preceeding Close, and forceClose is true, goto #1 |
- 3. if we encounter Line | Quad | Cubic after Close, cons up a Move |
-*/ |
- |
-//////////////////////////////////////////////////////////////////////////// |
- |
-SkPath::SkPath() : fFastBoundsIsDirty(true), fFillType(kWinding_FillType) {} |
- |
-SkPath::SkPath(const SkPath& src) { |
- SkDEBUGCODE(src.validate();) |
- *this = src; |
-} |
- |
-SkPath::~SkPath() { |
- SkDEBUGCODE(this->validate();) |
-} |
- |
-SkPath& SkPath::operator=(const SkPath& src) { |
- SkDEBUGCODE(src.validate();) |
- |
- if (this != &src) { |
- fFastBounds = src.fFastBounds; |
- fPts = src.fPts; |
- fVerbs = src.fVerbs; |
- fFillType = src.fFillType; |
- fFastBoundsIsDirty = src.fFastBoundsIsDirty; |
- } |
- SkDEBUGCODE(this->validate();) |
- return *this; |
-} |
- |
-void SkPath::swap(SkPath& other) { |
- SkASSERT(&other != NULL); |
- |
- if (this != &other) { |
- SkTSwap<SkRect>(fFastBounds, other.fFastBounds); |
- fPts.swap(other.fPts); |
- fVerbs.swap(other.fVerbs); |
- SkTSwap<uint8_t>(fFillType, other.fFillType); |
- SkTSwap<uint8_t>(fFastBoundsIsDirty, other.fFastBoundsIsDirty); |
- } |
-} |
- |
-void SkPath::reset() { |
- SkDEBUGCODE(this->validate();) |
- |
- fPts.reset(); |
- fVerbs.reset(); |
- fFastBoundsIsDirty = true; |
-} |
- |
-void SkPath::rewind() { |
- SkDEBUGCODE(this->validate();) |
- |
- fPts.rewind(); |
- fVerbs.rewind(); |
- fFastBoundsIsDirty = true; |
-} |
- |
-bool SkPath::isEmpty() const { |
- SkDEBUGCODE(this->validate();) |
- |
- int count = fVerbs.count(); |
- return count == 0 || (count == 1 && fVerbs[0] == kMove_Verb); |
-} |
- |
-bool SkPath::isRect(SkRect*) const { |
- SkDEBUGCODE(this->validate();) |
- |
- SkASSERT(!"unimplemented"); |
- return false; |
-} |
- |
-int SkPath::getPoints(SkPoint copy[], int max) const { |
- SkDEBUGCODE(this->validate();) |
- |
- SkASSERT(max >= 0); |
- int count = fPts.count(); |
- if (copy && max > 0 && count > 0) { |
- memcpy(copy, fPts.begin(), sizeof(SkPoint) * SkMin32(max, count)); |
- } |
- return count; |
-} |
- |
-void SkPath::getLastPt(SkPoint* lastPt) const { |
- SkDEBUGCODE(this->validate();) |
- |
- if (lastPt) { |
- int count = fPts.count(); |
- if (count == 0) { |
- lastPt->set(0, 0); |
- } else { |
- *lastPt = fPts[count - 1]; |
- } |
- } |
-} |
- |
-void SkPath::setLastPt(SkScalar x, SkScalar y) { |
- SkDEBUGCODE(this->validate();) |
- |
- int count = fPts.count(); |
- if (count == 0) { |
- this->moveTo(x, y); |
- } else { |
- fPts[count - 1].set(x, y); |
- } |
-} |
- |
-#define ALWAYS_FAST_BOUNDS_FOR_NOW true |
- |
-void SkPath::computeBounds(SkRect* bounds, BoundsType bt) const { |
- SkDEBUGCODE(this->validate();) |
- |
- SkASSERT(bounds); |
- |
- // we BoundsType for now |
- |
- if (fFastBoundsIsDirty) { |
- fFastBoundsIsDirty = false; |
- compute_fast_bounds(&fFastBounds, fPts); |
- } |
- *bounds = fFastBounds; |
-} |
- |
-////////////////////////////////////////////////////////////////////////////// |
-// Construction methods |
- |
-void SkPath::incReserve(U16CPU inc) { |
- SkDEBUGCODE(this->validate();) |
- |
- fVerbs.setReserve(fVerbs.count() + inc); |
- fPts.setReserve(fPts.count() + inc); |
- |
- SkDEBUGCODE(this->validate();) |
-} |
- |
-void SkPath::moveTo(SkScalar x, SkScalar y) { |
- SkDEBUGCODE(this->validate();) |
- |
- int vc = fVerbs.count(); |
- SkPoint* pt; |
- |
- if (vc > 0 && fVerbs[vc - 1] == kMove_Verb) { |
- pt = &fPts[fPts.count() - 1]; |
- } else { |
- pt = fPts.append(); |
- *fVerbs.append() = kMove_Verb; |
- } |
- pt->set(x, y); |
- |
- fFastBoundsIsDirty = true; |
-} |
- |
-void SkPath::rMoveTo(SkScalar x, SkScalar y) { |
- SkPoint pt; |
- this->getLastPt(&pt); |
- this->moveTo(pt.fX + x, pt.fY + y); |
-} |
- |
-void SkPath::lineTo(SkScalar x, SkScalar y) { |
- SkDEBUGCODE(this->validate();) |
- |
- if (fVerbs.count() == 0) { |
- fPts.append()->set(0, 0); |
- *fVerbs.append() = kMove_Verb; |
- } |
- fPts.append()->set(x, y); |
- *fVerbs.append() = kLine_Verb; |
- |
- fFastBoundsIsDirty = true; |
-} |
- |
-void SkPath::rLineTo(SkScalar x, SkScalar y) { |
- SkPoint pt; |
- this->getLastPt(&pt); |
- this->lineTo(pt.fX + x, pt.fY + y); |
-} |
- |
-void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { |
- SkDEBUGCODE(this->validate();) |
- |
- if (fVerbs.count() == 0) { |
- fPts.append()->set(0, 0); |
- *fVerbs.append() = kMove_Verb; |
- } |
- |
- SkPoint* pts = fPts.append(2); |
- pts[0].set(x1, y1); |
- pts[1].set(x2, y2); |
- *fVerbs.append() = kQuad_Verb; |
- |
- fFastBoundsIsDirty = true; |
-} |
- |
-void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { |
- SkPoint pt; |
- this->getLastPt(&pt); |
- this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2); |
-} |
- |
-void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
- SkScalar x3, SkScalar y3) { |
- SkDEBUGCODE(this->validate();) |
- |
- if (fVerbs.count() == 0) { |
- fPts.append()->set(0, 0); |
- *fVerbs.append() = kMove_Verb; |
- } |
- SkPoint* pts = fPts.append(3); |
- pts[0].set(x1, y1); |
- pts[1].set(x2, y2); |
- pts[2].set(x3, y3); |
- *fVerbs.append() = kCubic_Verb; |
- |
- fFastBoundsIsDirty = true; |
-} |
- |
-void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
- SkScalar x3, SkScalar y3) { |
- SkPoint pt; |
- this->getLastPt(&pt); |
- this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2, |
- pt.fX + x3, pt.fY + y3); |
-} |
- |
-void SkPath::close() { |
- SkDEBUGCODE(this->validate();) |
- |
- int count = fVerbs.count(); |
- if (count > 0) { |
- switch (fVerbs[count - 1]) { |
- case kLine_Verb: |
- case kQuad_Verb: |
- case kCubic_Verb: |
- *fVerbs.append() = kClose_Verb; |
- break; |
- default: |
- // don't add a close if the prev wasn't a primitive |
- break; |
- } |
- } |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-void SkPath::addRect(const SkRect& rect, Direction dir) { |
- this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); |
-} |
- |
-void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, |
- SkScalar bottom, Direction dir) { |
- SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom); |
- |
- this->incReserve(5); |
- |
- this->moveTo(left, top); |
- if (dir == kCCW_Direction) { |
- this->lineTo(left, bottom); |
- this->lineTo(right, bottom); |
- this->lineTo(right, top); |
- } else { |
- this->lineTo(right, top); |
- this->lineTo(right, bottom); |
- this->lineTo(left, bottom); |
- } |
- this->close(); |
-} |
- |
-#define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3) |
- |
-void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, |
- Direction dir) { |
- SkAutoPathBoundsUpdate apbu(this, rect); |
- |
- SkScalar w = rect.width(); |
- SkScalar halfW = SkScalarHalf(w); |
- SkScalar h = rect.height(); |
- SkScalar halfH = SkScalarHalf(h); |
- |
- if (halfW <= 0 || halfH <= 0) { |
- return; |
- } |
- |
- bool skip_hori = rx >= halfW; |
- bool skip_vert = ry >= halfH; |
- |
- if (skip_hori && skip_vert) { |
- this->addOval(rect, dir); |
- return; |
- } |
- if (skip_hori) { |
- rx = halfW; |
- } else if (skip_vert) { |
- ry = halfH; |
- } |
- |
- SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR); |
- SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR); |
- |
- this->incReserve(17); |
- this->moveTo(rect.fRight - rx, rect.fTop); |
- if (dir == kCCW_Direction) { |
- if (!skip_hori) { |
- this->lineTo(rect.fLeft + rx, rect.fTop); // top |
- } |
- this->cubicTo(rect.fLeft + rx - sx, rect.fTop, |
- rect.fLeft, rect.fTop + ry - sy, |
- rect.fLeft, rect.fTop + ry); // top-left |
- if (!skip_vert) { |
- this->lineTo(rect.fLeft, rect.fBottom - ry); // left |
- } |
- this->cubicTo(rect.fLeft, rect.fBottom - ry + sy, |
- rect.fLeft + rx - sx, rect.fBottom, |
- rect.fLeft + rx, rect.fBottom); // bot-left |
- if (!skip_hori) { |
- this->lineTo(rect.fRight - rx, rect.fBottom); // bottom |
- } |
- this->cubicTo(rect.fRight - rx + sx, rect.fBottom, |
- rect.fRight, rect.fBottom - ry + sy, |
- rect.fRight, rect.fBottom - ry); // bot-right |
- if (!skip_vert) { |
- this->lineTo(rect.fRight, rect.fTop + ry); |
- } |
- this->cubicTo(rect.fRight, rect.fTop + ry - sy, |
- rect.fRight - rx + sx, rect.fTop, |
- rect.fRight - rx, rect.fTop); // top-right |
- } else { |
- this->cubicTo(rect.fRight - rx + sx, rect.fTop, |
- rect.fRight, rect.fTop + ry - sy, |
- rect.fRight, rect.fTop + ry); // top-right |
- if (!skip_vert) { |
- this->lineTo(rect.fRight, rect.fBottom - ry); |
- } |
- this->cubicTo(rect.fRight, rect.fBottom - ry + sy, |
- rect.fRight - rx + sx, rect.fBottom, |
- rect.fRight - rx, rect.fBottom); // bot-right |
- if (!skip_hori) { |
- this->lineTo(rect.fLeft + rx, rect.fBottom); // bottom |
- } |
- this->cubicTo(rect.fLeft + rx - sx, rect.fBottom, |
- rect.fLeft, rect.fBottom - ry + sy, |
- rect.fLeft, rect.fBottom - ry); // bot-left |
- if (!skip_vert) { |
- this->lineTo(rect.fLeft, rect.fTop + ry); // left |
- } |
- this->cubicTo(rect.fLeft, rect.fTop + ry - sy, |
- rect.fLeft + rx - sx, rect.fTop, |
- rect.fLeft + rx, rect.fTop); // top-left |
- if (!skip_hori) { |
- this->lineTo(rect.fRight - rx, rect.fTop); // top |
- } |
- } |
- this->close(); |
-} |
- |
-static void add_corner_arc(SkPath* path, const SkRect& rect, |
- SkScalar rx, SkScalar ry, int startAngle, |
- SkPath::Direction dir, bool forceMoveTo) { |
- rx = SkMinScalar(SkScalarHalf(rect.width()), rx); |
- ry = SkMinScalar(SkScalarHalf(rect.height()), ry); |
- |
- SkRect r; |
- r.set(-rx, -ry, rx, ry); |
- |
- switch (startAngle) { |
- case 0: |
- r.offset(rect.fRight - r.fRight, rect.fBottom - r.fBottom); |
- break; |
- case 90: |
- r.offset(rect.fLeft - r.fLeft, rect.fBottom - r.fBottom); |
- break; |
- case 180: r.offset(rect.fLeft - r.fLeft, rect.fTop - r.fTop); break; |
- case 270: r.offset(rect.fRight - r.fRight, rect.fTop - r.fTop); break; |
- default: SkASSERT(!"unexpected startAngle in add_corner_arc"); |
- } |
- |
- SkScalar start = SkIntToScalar(startAngle); |
- SkScalar sweep = SkIntToScalar(90); |
- if (SkPath::kCCW_Direction == dir) { |
- start += sweep; |
- sweep = -sweep; |
- } |
- |
- path->arcTo(r, start, sweep, forceMoveTo); |
-} |
- |
-void SkPath::addRoundRect(const SkRect& rect, const SkScalar rad[], |
- Direction dir) { |
- SkAutoPathBoundsUpdate apbu(this, rect); |
- |
- if (kCW_Direction == dir) { |
- add_corner_arc(this, rect, rad[0], rad[1], 180, dir, true); |
- add_corner_arc(this, rect, rad[2], rad[3], 270, dir, false); |
- add_corner_arc(this, rect, rad[4], rad[5], 0, dir, false); |
- add_corner_arc(this, rect, rad[6], rad[7], 90, dir, false); |
- } else { |
- add_corner_arc(this, rect, rad[0], rad[1], 180, dir, true); |
- add_corner_arc(this, rect, rad[6], rad[7], 90, dir, false); |
- add_corner_arc(this, rect, rad[4], rad[5], 0, dir, false); |
- add_corner_arc(this, rect, rad[2], rad[3], 270, dir, false); |
- } |
- this->close(); |
-} |
- |
-void SkPath::addOval(const SkRect& oval, Direction dir) { |
- SkAutoPathBoundsUpdate apbu(this, oval); |
- |
- SkScalar cx = oval.centerX(); |
- SkScalar cy = oval.centerY(); |
- SkScalar rx = SkScalarHalf(oval.width()); |
- SkScalar ry = SkScalarHalf(oval.height()); |
-#if 0 // these seem faster than using quads (1/2 the number of edges) |
- SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR); |
- SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR); |
- |
- this->incReserve(13); |
- this->moveTo(cx + rx, cy); |
- if (dir == kCCW_Direction) { |
- this->cubicTo(cx + rx, cy - sy, cx + sx, cy - ry, cx, cy - ry); |
- this->cubicTo(cx - sx, cy - ry, cx - rx, cy - sy, cx - rx, cy); |
- this->cubicTo(cx - rx, cy + sy, cx - sx, cy + ry, cx, cy + ry); |
- this->cubicTo(cx + sx, cy + ry, cx + rx, cy + sy, cx + rx, cy); |
- } else { |
- this->cubicTo(cx + rx, cy + sy, cx + sx, cy + ry, cx, cy + ry); |
- this->cubicTo(cx - sx, cy + ry, cx - rx, cy + sy, cx - rx, cy); |
- this->cubicTo(cx - rx, cy - sy, cx - sx, cy - ry, cx, cy - ry); |
- this->cubicTo(cx + sx, cy - ry, cx + rx, cy - sy, cx + rx, cy); |
- } |
-#else |
- SkScalar sx = SkScalarMul(rx, SK_ScalarTanPIOver8); |
- SkScalar sy = SkScalarMul(ry, SK_ScalarTanPIOver8); |
- SkScalar mx = SkScalarMul(rx, SK_ScalarRoot2Over2); |
- SkScalar my = SkScalarMul(ry, SK_ScalarRoot2Over2); |
- |
- this->incReserve(17); // 8 quads + close |
- this->moveTo(cx + rx, cy); |
- if (dir == kCCW_Direction) { |
- this->quadTo(cx + rx, cy - sy, cx + mx, cy - my); |
- this->quadTo(cx + sx, cy - ry, cx + 0, cy - ry); |
- this->quadTo(cx - sx, cy - ry, cx - mx, cy - my); |
- this->quadTo(cx - rx, cy - sy, cx - rx, cy - 0); |
- this->quadTo(cx - rx, cy + sy, cx - mx, cy + my); |
- this->quadTo(cx - sx, cy + ry, cx - 0, cy + ry); |
- this->quadTo(cx + sx, cy + ry, cx + mx, cy + my); |
- this->quadTo(cx + rx, cy + sy, cx + rx, cy + 0); |
- } else { |
- this->quadTo(cx + rx, cy + sy, cx + mx, cy + my); |
- this->quadTo(cx + sx, cy + ry, cx - 0, cy + ry); |
- this->quadTo(cx - sx, cy + ry, cx - mx, cy + my); |
- this->quadTo(cx - rx, cy + sy, cx - rx, cy - 0); |
- this->quadTo(cx - rx, cy - sy, cx - mx, cy - my); |
- this->quadTo(cx - sx, cy - ry, cx + 0, cy - ry); |
- this->quadTo(cx + sx, cy - ry, cx + mx, cy - my); |
- this->quadTo(cx + rx, cy - sy, cx + rx, cy + 0); |
- } |
-#endif |
- this->close(); |
-} |
- |
-void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { |
- if (r > 0) { |
- SkRect rect; |
- rect.set(x - r, y - r, x + r, y + r); |
- this->addOval(rect, dir); |
- } |
-} |
- |
-#include "SkGeometry.h" |
- |
-static int build_arc_points(const SkRect& oval, SkScalar startAngle, |
- SkScalar sweepAngle, |
- SkPoint pts[kSkBuildQuadArcStorage]) { |
- SkVector start, stop; |
- |
- start.fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &start.fX); |
- stop.fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle), |
- &stop.fX); |
- |
- SkMatrix matrix; |
- |
- matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height())); |
- matrix.postTranslate(oval.centerX(), oval.centerY()); |
- |
- return SkBuildQuadArc(start, stop, |
- sweepAngle > 0 ? kCW_SkRotationDirection : kCCW_SkRotationDirection, |
- &matrix, pts); |
-} |
- |
-void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, |
- bool forceMoveTo) { |
- if (oval.width() < 0 || oval.height() < 0) { |
- return; |
- } |
- |
- SkPoint pts[kSkBuildQuadArcStorage]; |
- int count = build_arc_points(oval, startAngle, sweepAngle, pts); |
- SkASSERT((count & 1) == 1); |
- |
- if (fVerbs.count() == 0) { |
- forceMoveTo = true; |
- } |
- this->incReserve(count); |
- forceMoveTo ? this->moveTo(pts[0]) : this->lineTo(pts[0]); |
- for (int i = 1; i < count; i += 2) { |
- this->quadTo(pts[i], pts[i+1]); |
- } |
-} |
- |
-void SkPath::addArc(const SkRect& oval, SkScalar startAngle, |
- SkScalar sweepAngle) { |
- if (oval.isEmpty() || 0 == sweepAngle) { |
- return; |
- } |
- |
- const SkScalar kFullCircleAngle = SkIntToScalar(360); |
- |
- if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) { |
- this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction); |
- return; |
- } |
- |
- SkPoint pts[kSkBuildQuadArcStorage]; |
- int count = build_arc_points(oval, startAngle, sweepAngle, pts); |
- |
- this->incReserve(count); |
- this->moveTo(pts[0]); |
- for (int i = 1; i < count; i += 2) { |
- this->quadTo(pts[i], pts[i+1]); |
- } |
-} |
- |
-/* |
- Need to handle the case when the angle is sharp, and our computed end-points |
- for the arc go behind pt1 and/or p2... |
-*/ |
-void SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
- SkScalar radius) { |
- SkVector before, after; |
- |
- // need to know our prev pt so we can construct tangent vectors |
- { |
- SkPoint start; |
- this->getLastPt(&start); |
- before.setNormalize(x1 - start.fX, y1 - start.fY); |
- after.setNormalize(x2 - x1, y2 - y1); |
- } |
- |
- SkScalar cosh = SkPoint::DotProduct(before, after); |
- SkScalar sinh = SkPoint::CrossProduct(before, after); |
- |
- if (SkScalarNearlyZero(sinh)) { // angle is too tight |
- return; |
- } |
- |
- SkScalar dist = SkScalarMulDiv(radius, SK_Scalar1 - cosh, sinh); |
- if (dist < 0) { |
- dist = -dist; |
- } |
- |
- SkScalar xx = x1 - SkScalarMul(dist, before.fX); |
- SkScalar yy = y1 - SkScalarMul(dist, before.fY); |
- SkRotationDirection arcDir; |
- |
- // now turn before/after into normals |
- if (sinh > 0) { |
- before.rotateCCW(); |
- after.rotateCCW(); |
- arcDir = kCW_SkRotationDirection; |
- } else { |
- before.rotateCW(); |
- after.rotateCW(); |
- arcDir = kCCW_SkRotationDirection; |
- } |
- |
- SkMatrix matrix; |
- SkPoint pts[kSkBuildQuadArcStorage]; |
- |
- matrix.setScale(radius, radius); |
- matrix.postTranslate(xx - SkScalarMul(radius, before.fX), |
- yy - SkScalarMul(radius, before.fY)); |
- |
- int count = SkBuildQuadArc(before, after, arcDir, &matrix, pts); |
- |
- this->incReserve(count); |
- // [xx,yy] == pts[0] |
- this->lineTo(xx, yy); |
- for (int i = 1; i < count; i += 2) { |
- this->quadTo(pts[i], pts[i+1]); |
- } |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) { |
- SkMatrix matrix; |
- |
- matrix.setTranslate(dx, dy); |
- this->addPath(path, matrix); |
-} |
- |
-void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) { |
- this->incReserve(path.fPts.count()); |
- |
- Iter iter(path, false); |
- SkPoint pts[4]; |
- Verb verb; |
- |
- SkMatrix::MapPtsProc proc = matrix.getMapPtsProc(); |
- |
- while ((verb = iter.next(pts)) != kDone_Verb) { |
- switch (verb) { |
- case kMove_Verb: |
- proc(matrix, &pts[0], &pts[0], 1); |
- this->moveTo(pts[0]); |
- break; |
- case kLine_Verb: |
- proc(matrix, &pts[1], &pts[1], 1); |
- this->lineTo(pts[1]); |
- break; |
- case kQuad_Verb: |
- proc(matrix, &pts[1], &pts[1], 2); |
- this->quadTo(pts[1], pts[2]); |
- break; |
- case kCubic_Verb: |
- proc(matrix, &pts[1], &pts[1], 3); |
- this->cubicTo(pts[1], pts[2], pts[3]); |
- break; |
- case kClose_Verb: |
- this->close(); |
- break; |
- default: |
- SkASSERT(!"unknown verb"); |
- } |
- } |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-static const uint8_t gPtsInVerb[] = { |
- 1, // kMove |
- 1, // kLine |
- 2, // kQuad |
- 3, // kCubic |
- 0, // kClose |
- 0 // kDone |
-}; |
- |
-// ignore the initial moveto, and stop when the 1st contour ends |
-void SkPath::pathTo(const SkPath& path) { |
- int i, vcount = path.fVerbs.count(); |
- if (vcount == 0) { |
- return; |
- } |
- |
- this->incReserve(vcount); |
- |
- const uint8_t* verbs = path.fVerbs.begin(); |
- const SkPoint* pts = path.fPts.begin() + 1; // 1 for the initial moveTo |
- |
- SkASSERT(verbs[0] == kMove_Verb); |
- for (i = 1; i < vcount; i++) { |
- switch (verbs[i]) { |
- case kLine_Verb: |
- this->lineTo(pts[0].fX, pts[0].fY); |
- break; |
- case kQuad_Verb: |
- this->quadTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY); |
- break; |
- case kCubic_Verb: |
- this->cubicTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, |
- pts[2].fX, pts[2].fY); |
- break; |
- case kClose_Verb: |
- return; |
- } |
- pts += gPtsInVerb[verbs[i]]; |
- } |
-} |
- |
-// ignore the last point of the 1st contour |
-void SkPath::reversePathTo(const SkPath& path) { |
- int i, vcount = path.fVerbs.count(); |
- if (vcount == 0) { |
- return; |
- } |
- |
- this->incReserve(vcount); |
- |
- const uint8_t* verbs = path.fVerbs.begin(); |
- const SkPoint* pts = path.fPts.begin(); |
- |
- SkASSERT(verbs[0] == kMove_Verb); |
- for (i = 1; i < vcount; i++) { |
- int n = gPtsInVerb[verbs[i]]; |
- if (n == 0) { |
- break; |
- } |
- pts += n; |
- } |
- |
- while (--i > 0) { |
- switch (verbs[i]) { |
- case kLine_Verb: |
- this->lineTo(pts[-1].fX, pts[-1].fY); |
- break; |
- case kQuad_Verb: |
- this->quadTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY); |
- break; |
- case kCubic_Verb: |
- this->cubicTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY, |
- pts[-3].fX, pts[-3].fY); |
- break; |
- default: |
- SkASSERT(!"bad verb"); |
- break; |
- } |
- pts -= gPtsInVerb[verbs[i]]; |
- } |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-void SkPath::offset(SkScalar dx, SkScalar dy, SkPath* dst) const { |
- SkMatrix matrix; |
- |
- matrix.setTranslate(dx, dy); |
- this->transform(matrix, dst); |
-} |
- |
-#include "SkGeometry.h" |
- |
-static void subdivide_quad_to(SkPath* path, const SkPoint pts[3], |
- int level = 2) { |
- if (--level >= 0) { |
- SkPoint tmp[5]; |
- |
- SkChopQuadAtHalf(pts, tmp); |
- subdivide_quad_to(path, &tmp[0], level); |
- subdivide_quad_to(path, &tmp[2], level); |
- } else { |
- path->quadTo(pts[1], pts[2]); |
- } |
-} |
- |
-static void subdivide_cubic_to(SkPath* path, const SkPoint pts[4], |
- int level = 2) { |
- if (--level >= 0) { |
- SkPoint tmp[7]; |
- |
- SkChopCubicAtHalf(pts, tmp); |
- subdivide_cubic_to(path, &tmp[0], level); |
- subdivide_cubic_to(path, &tmp[3], level); |
- } else { |
- path->cubicTo(pts[1], pts[2], pts[3]); |
- } |
-} |
- |
-void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const { |
- SkDEBUGCODE(this->validate();) |
- if (dst == NULL) { |
- dst = (SkPath*)this; |
- } |
- |
- if (matrix.getType() & SkMatrix::kPerspective_Mask) { |
- SkPath tmp; |
- tmp.fFillType = fFillType; |
- |
- SkPath::Iter iter(*this, false); |
- SkPoint pts[4]; |
- SkPath::Verb verb; |
- |
- while ((verb = iter.next(pts)) != kDone_Verb) { |
- switch (verb) { |
- case kMove_Verb: |
- tmp.moveTo(pts[0]); |
- break; |
- case kLine_Verb: |
- tmp.lineTo(pts[1]); |
- break; |
- case kQuad_Verb: |
- subdivide_quad_to(&tmp, pts); |
- break; |
- case kCubic_Verb: |
- subdivide_cubic_to(&tmp, pts); |
- break; |
- case kClose_Verb: |
- tmp.close(); |
- break; |
- default: |
- SkASSERT(!"unknown verb"); |
- break; |
- } |
- } |
- |
- dst->swap(tmp); |
- matrix.mapPoints(dst->fPts.begin(), dst->fPts.count()); |
- } else { |
- // remember that dst might == this, so be sure to check |
- // fFastBoundsIsDirty before we set it |
- if (!fFastBoundsIsDirty && matrix.rectStaysRect() && fPts.count() > 1) { |
- // if we're empty, fastbounds should not be mapped |
- matrix.mapRect(&dst->fFastBounds, fFastBounds); |
- dst->fFastBoundsIsDirty = false; |
- } else { |
- dst->fFastBoundsIsDirty = true; |
- } |
- |
- if (this != dst) { |
- dst->fVerbs = fVerbs; |
- dst->fPts.setCount(fPts.count()); |
- dst->fFillType = fFillType; |
- } |
- matrix.mapPoints(dst->fPts.begin(), fPts.begin(), fPts.count()); |
- SkDEBUGCODE(dst->validate();) |
- } |
-} |
- |
-void SkPath::updateBoundsCache() const { |
- if (fFastBoundsIsDirty) { |
- SkRect r; |
- this->computeBounds(&r, kFast_BoundsType); |
- SkASSERT(!fFastBoundsIsDirty); |
- } |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-enum NeedMoveToState { |
- kAfterClose_NeedMoveToState, |
- kAfterCons_NeedMoveToState, |
- kAfterPrefix_NeedMoveToState |
-}; |
- |
-SkPath::Iter::Iter() { |
-#ifdef SK_DEBUG |
- fPts = NULL; |
- fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0; |
- fForceClose = fNeedMoveTo = fCloseLine = false; |
-#endif |
- // need to init enough to make next() harmlessly return kDone_Verb |
- fVerbs = NULL; |
- fVerbStop = NULL; |
- fNeedClose = false; |
-} |
- |
-SkPath::Iter::Iter(const SkPath& path, bool forceClose) { |
- this->setPath(path, forceClose); |
-} |
- |
-void SkPath::Iter::setPath(const SkPath& path, bool forceClose) { |
- fPts = path.fPts.begin(); |
- fVerbs = path.fVerbs.begin(); |
- fVerbStop = path.fVerbs.end(); |
- fForceClose = SkToU8(forceClose); |
- fNeedClose = false; |
- fNeedMoveTo = kAfterPrefix_NeedMoveToState; |
-} |
- |
-bool SkPath::Iter::isClosedContour() const { |
- if (fVerbs == NULL || fVerbs == fVerbStop) { |
- return false; |
- } |
- if (fForceClose) { |
- return true; |
- } |
- |
- const uint8_t* verbs = fVerbs; |
- const uint8_t* stop = fVerbStop; |
- |
- if (kMove_Verb == *verbs) { |
- verbs += 1; // skip the initial moveto |
- } |
- |
- while (verbs < stop) { |
- unsigned v = *verbs++; |
- if (kMove_Verb == v) { |
- break; |
- } |
- if (kClose_Verb == v) { |
- return true; |
- } |
- } |
- return false; |
-} |
- |
-SkPath::Verb SkPath::Iter::autoClose(SkPoint pts[2]) { |
- if (fLastPt != fMoveTo) { |
- if (pts) { |
- pts[0] = fLastPt; |
- pts[1] = fMoveTo; |
- } |
- fLastPt = fMoveTo; |
- fCloseLine = true; |
- return kLine_Verb; |
- } |
- return kClose_Verb; |
-} |
- |
-bool SkPath::Iter::cons_moveTo(SkPoint pts[1]) { |
- if (fNeedMoveTo == kAfterClose_NeedMoveToState) { |
- if (pts) { |
- *pts = fMoveTo; |
- } |
- fNeedClose = fForceClose; |
- fNeedMoveTo = kAfterCons_NeedMoveToState; |
- fVerbs -= 1; |
- return true; |
- } |
- |
- if (fNeedMoveTo == kAfterCons_NeedMoveToState) { |
- if (pts) { |
- *pts = fMoveTo; |
- } |
- fNeedMoveTo = kAfterPrefix_NeedMoveToState; |
- } else { |
- SkASSERT(fNeedMoveTo == kAfterPrefix_NeedMoveToState); |
- if (pts) { |
- *pts = fPts[-1]; |
- } |
- } |
- return false; |
-} |
- |
-SkPath::Verb SkPath::Iter::next(SkPoint pts[4]) { |
- if (fVerbs == fVerbStop) { |
- if (fNeedClose) { |
- if (kLine_Verb == this->autoClose(pts)) { |
- return kLine_Verb; |
- } |
- fNeedClose = false; |
- return kClose_Verb; |
- } |
- return kDone_Verb; |
- } |
- |
- unsigned verb = *fVerbs++; |
- const SkPoint* srcPts = fPts; |
- |
- switch (verb) { |
- case kMove_Verb: |
- if (fNeedClose) { |
- fVerbs -= 1; |
- verb = this->autoClose(pts); |
- if (verb == kClose_Verb) { |
- fNeedClose = false; |
- } |
- return (Verb)verb; |
- } |
- if (fVerbs == fVerbStop) { // might be a trailing moveto |
- return kDone_Verb; |
- } |
- fMoveTo = *srcPts; |
- if (pts) { |
- pts[0] = *srcPts; |
- } |
- srcPts += 1; |
- fNeedMoveTo = kAfterCons_NeedMoveToState; |
- fNeedClose = fForceClose; |
- break; |
- case kLine_Verb: |
- if (this->cons_moveTo(pts)) { |
- return kMove_Verb; |
- } |
- if (pts) { |
- pts[1] = srcPts[0]; |
- } |
- fLastPt = srcPts[0]; |
- fCloseLine = false; |
- srcPts += 1; |
- break; |
- case kQuad_Verb: |
- if (this->cons_moveTo(pts)) { |
- return kMove_Verb; |
- } |
- if (pts) { |
- memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint)); |
- } |
- fLastPt = srcPts[1]; |
- srcPts += 2; |
- break; |
- case kCubic_Verb: |
- if (this->cons_moveTo(pts)) { |
- return kMove_Verb; |
- } |
- if (pts) { |
- memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint)); |
- } |
- fLastPt = srcPts[2]; |
- srcPts += 3; |
- break; |
- case kClose_Verb: |
- verb = this->autoClose(pts); |
- if (verb == kLine_Verb) { |
- fVerbs -= 1; |
- } else { |
- fNeedClose = false; |
- } |
- fNeedMoveTo = kAfterClose_NeedMoveToState; |
- break; |
- } |
- fPts = srcPts; |
- return (Verb)verb; |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-static bool exceeds_dist(const SkScalar p[], const SkScalar q[], SkScalar dist, |
- int count) { |
- SkASSERT(dist > 0); |
- |
- count *= 2; |
- for (int i = 0; i < count; i++) { |
- if (SkScalarAbs(p[i] - q[i]) > dist) { |
- return true; |
- } |
- } |
- return false; |
-} |
- |
-static void subdivide_quad(SkPath* dst, const SkPoint pts[3], SkScalar dist, |
- int subLevel = 4) { |
- if (--subLevel >= 0 && exceeds_dist(&pts[0].fX, &pts[1].fX, dist, 4)) { |
- SkPoint tmp[5]; |
- SkChopQuadAtHalf(pts, tmp); |
- |
- subdivide_quad(dst, &tmp[0], dist, subLevel); |
- subdivide_quad(dst, &tmp[2], dist, subLevel); |
- } else { |
- dst->quadTo(pts[1], pts[2]); |
- } |
-} |
- |
-static void subdivide_cubic(SkPath* dst, const SkPoint pts[4], SkScalar dist, |
- int subLevel = 4) { |
- if (--subLevel >= 0 && exceeds_dist(&pts[0].fX, &pts[1].fX, dist, 6)) { |
- SkPoint tmp[7]; |
- SkChopCubicAtHalf(pts, tmp); |
- |
- subdivide_cubic(dst, &tmp[0], dist, subLevel); |
- subdivide_cubic(dst, &tmp[3], dist, subLevel); |
- } else { |
- dst->cubicTo(pts[1], pts[2], pts[3]); |
- } |
-} |
- |
-void SkPath::subdivide(SkScalar dist, bool bendLines, SkPath* dst) const { |
- SkPath tmpPath; |
- if (NULL == dst || this == dst) { |
- dst = &tmpPath; |
- } |
- |
- SkPath::Iter iter(*this, false); |
- SkPoint pts[4]; |
- |
- for (;;) { |
- switch (iter.next(pts)) { |
- case SkPath::kMove_Verb: |
- dst->moveTo(pts[0]); |
- break; |
- case SkPath::kLine_Verb: |
- if (!bendLines) { |
- dst->lineTo(pts[1]); |
- break; |
- } |
- // construct a quad from the line |
- pts[2] = pts[1]; |
- pts[1].set(SkScalarAve(pts[0].fX, pts[2].fX), |
- SkScalarAve(pts[0].fY, pts[2].fY)); |
- // fall through to the quad case |
- case SkPath::kQuad_Verb: |
- subdivide_quad(dst, pts, dist); |
- break; |
- case SkPath::kCubic_Verb: |
- subdivide_cubic(dst, pts, dist); |
- break; |
- case SkPath::kClose_Verb: |
- dst->close(); |
- break; |
- case SkPath::kDone_Verb: |
- goto DONE; |
- } |
- } |
-DONE: |
- if (&tmpPath == dst) { // i.e. the dst should be us |
- dst->swap(*(SkPath*)this); |
- } |
-} |
- |
-/////////////////////////////////////////////////////////////////////// |
-/* |
- Format in flattened buffer: [ptCount, verbCount, pts[], verbs[]] |
-*/ |
- |
-void SkPath::flatten(SkFlattenableWriteBuffer& buffer) const { |
- SkDEBUGCODE(this->validate();) |
- |
- buffer.write32(fPts.count()); |
- buffer.write32(fVerbs.count()); |
- buffer.write32(fFillType); |
- buffer.writeMul4(fPts.begin(), sizeof(SkPoint) * fPts.count()); |
- buffer.writePad(fVerbs.begin(), fVerbs.count()); |
-} |
- |
-void SkPath::unflatten(SkFlattenableReadBuffer& buffer) { |
- fPts.setCount(buffer.readS32()); |
- fVerbs.setCount(buffer.readS32()); |
- fFillType = buffer.readS32(); |
- buffer.read(fPts.begin(), sizeof(SkPoint) * fPts.count()); |
- buffer.read(fVerbs.begin(), fVerbs.count()); |
- |
- fFastBoundsIsDirty = true; |
- |
- SkDEBUGCODE(this->validate();) |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-#include "SkString.h" |
-#include "SkStream.h" |
- |
-static void write_scalar(SkWStream* stream, SkScalar value) { |
- char buffer[SkStrAppendScalar_MaxSize]; |
- char* stop = SkStrAppendScalar(buffer, value); |
- stream->write(buffer, stop - buffer); |
-} |
- |
-static void append_scalars(SkWStream* stream, char verb, const SkScalar data[], |
- int count) { |
- stream->write(&verb, 1); |
- write_scalar(stream, data[0]); |
- for (int i = 1; i < count; i++) { |
- if (data[i] >= 0) { |
- // can skip the separater if data[i] is negative |
- stream->write(" ", 1); |
- } |
- write_scalar(stream, data[i]); |
- } |
-} |
- |
-void SkPath::toString(SkString* str) const { |
- SkDynamicMemoryWStream stream; |
- |
- SkPath::Iter iter(*this, false); |
- SkPoint pts[4]; |
- |
- for (;;) { |
- switch (iter.next(pts)) { |
- case SkPath::kMove_Verb: |
- append_scalars(&stream, 'M', &pts[0].fX, 2); |
- break; |
- case SkPath::kLine_Verb: |
- append_scalars(&stream, 'L', &pts[1].fX, 2); |
- break; |
- case SkPath::kQuad_Verb: |
- append_scalars(&stream, 'Q', &pts[1].fX, 4); |
- break; |
- case SkPath::kCubic_Verb: |
- append_scalars(&stream, 'C', &pts[1].fX, 6); |
- break; |
- case SkPath::kClose_Verb: |
- stream.write("Z", 1); |
- break; |
- case SkPath::kDone_Verb: |
- str->resize(stream.getOffset()); |
- stream.copyTo(str->writable_str()); |
- return; |
- } |
- } |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-#ifdef SK_DEBUG |
- |
-void SkPath::validate() const { |
- SkASSERT(this != NULL); |
- SkASSERT((fFillType & ~3) == 0); |
- fPts.validate(); |
- fVerbs.validate(); |
- |
- if (!fFastBoundsIsDirty) { |
- SkRect bounds; |
- compute_fast_bounds(&bounds, fPts); |
- // can't call contains(), since it returns false if the rect is empty |
- SkASSERT(fFastBounds.fLeft <= bounds.fLeft); |
- SkASSERT(fFastBounds.fTop <= bounds.fTop); |
- SkASSERT(fFastBounds.fRight >= bounds.fRight); |
- SkASSERT(fFastBounds.fBottom >= bounds.fBottom); |
- } |
-} |
- |
-#if 0 // test to ensure that the iterator returns the same data as the path |
-void SkPath::test() const |
-{ |
- Iter iter(*this, false); |
- SkPoint pts[4]; |
- Verb verb; |
- |
- const uint8_t* verbs = fVerbs.begin(); |
- const SkPoint* points = fPts.begin(); |
- |
- while ((verb = iter.next(pts)) != kDone_Verb) |
- { |
- SkASSERT(*verbs == verb); |
- verbs += 1; |
- |
- int count; |
- switch (verb) { |
- case kMove_Verb: |
- count = 1; |
- break; |
- case kLine_Verb: |
- count = 2; |
- break; |
- case kQuad_Verb: |
- count = 3; |
- break; |
- case kCubic_Verb: |
- count = 4; |
- break; |
- case kClose_Verb: |
- default: |
- count = 0; |
- break; |
- } |
- if (count > 1) |
- points -= 1; |
- SkASSERT(memcmp(pts, points, count * sizeof(SkPoint)) == 0); |
- points += count; |
- } |
- |
- int vc = fVerbs.count(), pc = fPts.count(); |
- if (vc && fVerbs.begin()[vc-1] == kMove_Verb) |
- { |
- vc -= 1; |
- pc -= 1; |
- } |
- SkASSERT(verbs - fVerbs.begin() == vc); |
- SkASSERT(points - fPts.begin() == pc); |
-} |
-#endif |
- |
-void SkPath::dump(bool forceClose, const char title[]) const { |
- Iter iter(*this, forceClose); |
- SkPoint pts[4]; |
- Verb verb; |
- |
- SkDebugf("path: forceClose=%s %s\n", forceClose ? "true" : "false", |
- title ? title : ""); |
- |
- while ((verb = iter.next(pts)) != kDone_Verb) { |
- switch (verb) { |
- case kMove_Verb: |
-#ifdef SK_CAN_USE_FLOAT |
- SkDebugf(" path: moveTo [%g %g]\n", |
- SkScalarToFloat(pts[0].fX), SkScalarToFloat(pts[0].fY)); |
-#else |
- SkDebugf(" path: moveTo [%x %x]\n", pts[0].fX, pts[0].fY); |
-#endif |
- break; |
- case kLine_Verb: |
-#ifdef SK_CAN_USE_FLOAT |
- SkDebugf(" path: lineTo [%g %g]\n", |
- SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY)); |
-#else |
- SkDebugf(" path: lineTo [%x %x]\n", pts[1].fX, pts[1].fY); |
-#endif |
- break; |
- case kQuad_Verb: |
-#ifdef SK_CAN_USE_FLOAT |
- SkDebugf(" path: quadTo [%g %g] [%g %g]\n", |
- SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY), |
- SkScalarToFloat(pts[2].fX), SkScalarToFloat(pts[2].fY)); |
-#else |
- SkDebugf(" path: quadTo [%x %x] [%x %x]\n", |
- pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); |
-#endif |
- break; |
- case kCubic_Verb: |
-#ifdef SK_CAN_USE_FLOAT |
- SkDebugf(" path: cubeTo [%g %g] [%g %g] [%g %g]\n", |
- SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY), |
- SkScalarToFloat(pts[2].fX), SkScalarToFloat(pts[2].fY), |
- SkScalarToFloat(pts[3].fX), SkScalarToFloat(pts[3].fY)); |
-#else |
- SkDebugf(" path: cubeTo [%x %x] [%x %x] [%x %x]\n", |
- pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, |
- pts[3].fX, pts[3].fY); |
-#endif |
- break; |
- case kClose_Verb: |
- SkDebugf(" path: close\n"); |
- break; |
- default: |
- SkDebugf(" path: UNKNOWN VERB %d, aborting dump...\n", verb); |
- verb = kDone_Verb; // stop the loop |
- break; |
- } |
- } |
- SkDebugf("path: done %s\n", title ? title : ""); |
-} |
- |
-#include "SkTSort.h" |
- |
-void SkPath::UnitTest() { |
-#ifdef SK_SUPPORT_UNITTEST |
- SkPath p; |
- SkRect r; |
- |
- r.set(0, 0, 10, 20); |
- p.addRect(r); |
- p.dump(false); |
- p.dump(true); |
- |
- { |
- int array[] = { 5, 3, 7, 2, 6, 1, 2, 9, 5, 0 }; |
- int i; |
- |
- for (i = 0; i < (int)SK_ARRAY_COUNT(array); i++) { |
- SkDebugf(" %d", array[i]); |
- } |
- SkDebugf("\n"); |
- SkTHeapSort<int>(array, SK_ARRAY_COUNT(array)); |
- for (i = 0; i < (int)SK_ARRAY_COUNT(array); i++) |
- SkDebugf(" %d", array[i]); |
- SkDebugf("\n"); |
- } |
- |
- { |
- SkPath p; |
- SkPoint pt; |
- |
- p.moveTo(SK_Scalar1, 0); |
- p.getLastPt(&pt); |
- SkASSERT(pt.fX == SK_Scalar1); |
- } |
-#endif |
-} |
- |
-#endif |