From eba3e95b81edf128a4af455aee34fbde61376188 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Mon, 15 Oct 2012 11:10:23 +0100 Subject: [PATCH] `CPBezierPath controlPointBounds` and `CGPathGetBoundingBox`. --- AppKit/CPBezierPath.j | 13 +++++ AppKit/CoreGraphics/CGPath.j | 102 +++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/AppKit/CPBezierPath.j b/AppKit/CPBezierPath.j index de90822c4..213a61e96 100644 --- a/AppKit/CPBezierPath.j +++ b/AppKit/CPBezierPath.j @@ -165,6 +165,19 @@ var DefaultLineWidth = 1.0; CGPathAddCurveToPoint(_path, nil, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, endPoint.x, endPoint.y); } +- (CGRect)bounds +{ + // TODO: this should return this. The controlPointBounds is not a tight fit. + // return CGPathGetPathBoundingBox(_path); + + return [self controlPointBounds]; +} + +- (CGRect)controlPointBounds +{ + return CGPathGetBoundingBox(_path); +} + /*! Create a line segment between the first and last points in the subpath, closing it. */ diff --git a/AppKit/CoreGraphics/CGPath.j b/AppKit/CoreGraphics/CGPath.j index 6d6a77301..9db475c66 100644 --- a/AppKit/CoreGraphics/CGPath.j +++ b/AppKit/CoreGraphics/CGPath.j @@ -406,6 +406,108 @@ function CGPathIsEmpty(aPath) return !aPath || aPath.count == 0; } +/*! + Calculate the smallest rectangle to contain both the path of the receiver and all control points. +*/ +function CGPathGetBoundingBox(aPath) +{ + if (!aPath || !aPath.count) + return _CGRectMakeZero(); + + var ox = 0, + oy = 0, + rx = 0, + ry = 0, + movePoint = nil; + + function addPoint(x, y) + { + ox = MIN(ox, x); + oy = MIN(oy, y); + rx = MAX(rx, x); + ry = MAX(ry, y); + } + + for (var i = 0, count = aPath.count; i < count; ++i) + { + var element = aPath.elements[i]; + + // Just enclose all the control points. The curves must be inside of the control points. + // This won't work for CGPathGetPathBoundingBox. + switch (element.type) + { + case kCGPathElementAddLineToPoint: + if (movePoint) + { + addPoint(movePoint.x, movePoint.y); + movePoint = nil; + } + + addPoint(element.x, element.y); + break; + + case kCGPathElementAddCurveToPoint: + if (movePoint) + { + addPoint(movePoint.x, movePoint.y); + movePoint = nil; + } + + addPoint(element.cp1x, element.cp1y); + addPoint(element.cp2x, element.cp2y); + addPoint(element.x, element.y); + break; + + case kCGPathElementAddArc: + if (movePoint) + { + addPoint(movePoint.x, movePoint.y); + movePoint = nil; + } + + addPoint(element.x, element.y); + break; + + case kCGPathElementAddArcToPoint: + if (movePoint) + { + addPoint(movePoint.x, movePoint.y); + movePoint = nil; + } + + addPoint(element.p1x, element.p1y); + addPoint(element.p2x, element.p2y); + break; + + case kCGPathElementAddQuadCurveToPoint: + if (movePoint) + { + addPoint(movePoint.x, movePoint.y); + movePoint = nil; + } + + addPoint(element.cpx, element.cpy); + addPoint(element.x, element.y); + break; + + case kCGPathElementMoveToPoint: + movePoint = _CGPointMake(element.x, element.y); + break; + + case kCGPathElementCloseSubpath: + if (movePoint) + { + addPoint(movePoint.x, movePoint.y); + movePoint = nil; + } + + break; + } + } + + return _CGRectMake(ox, oy, rx - ox, ry - oy); +} + /*! @} */