mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 13:07:02 +00:00
Previously, Cappuccino was using preprocessor macros internally for the CGPoint/Size/Rect/Inset/Affine functions, as well as for CPRange. These macros had the same name as the corresponding function, but began with _. The functions were actually defined using the macros.
The motivation behind using macros was to increase performance by reducing function calls. However, there were a number of problems with this approach:
- There was an artificial dichotomy between _CG macros and the corresponding CG functions. We never completely replaced CG function calls with _CG macros. In fact, they were often mixed up in the same file. There was an extra burden on the programmer to remember to use the macro instead of the function.
- If a method call was passed as an argument to a macro, performance could actually be significantly *worse* than a function call. For example, _CGGetRectMakeCopy([view frame]) would expand to `{ origin:{ x:[view frame].origin.x, y:[view frame].origin.y }, size:{ width:[view frame].size.width, height:[view frame].size.height } }`. So instead of a single objj_msgSend and a single simple function call, we ended up with 4 objj_msgSend calls, which are way more expensive than simple function calls.
- Because of this expansion problem, to use macros efficiently required us to remember to use variables for all macro parameters. This didn't happen, and shouldn't have to happen.
- Finally, with modern Javascript engines, function call overhead is so small that it really isn't worth using the macros.
This commit eliminates the _CGGeometry, CGAffineTransformation and CPRange macros and replaces them with function calls.
BREAKING CHANGE:
The macros are no longer available. They could only be used with compiled code, but if there is any user code that used them, they will have to be replaced with the corresponding functions.
615 lines
19 KiB
Plaintext
615 lines
19 KiB
Plaintext
/*
|
||
* CGPath.j
|
||
* AppKit
|
||
*
|
||
* Created by Francisco Tolmasky.
|
||
* Copyright 2008, 280 North, Inc.
|
||
*
|
||
* This library is free software; you can redistribute it and/or
|
||
* modify it under the terms of the GNU Lesser General Public
|
||
* License as published by the Free Software Foundation; either
|
||
* version 2.1 of the License, or (at your option) any later version.
|
||
*
|
||
* This library is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
* Lesser General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU Lesser General Public
|
||
* License along with this library; if not, write to the Free Software
|
||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
*/
|
||
|
||
@import "CGAffineTransform.j"
|
||
@import "CGGeometry.j"
|
||
|
||
|
||
kCGPathElementMoveToPoint = 0;
|
||
kCGPathElementAddLineToPoint = 1;
|
||
kCGPathElementAddQuadCurveToPoint = 2;
|
||
kCGPathElementAddCurveToPoint = 3;
|
||
kCGPathElementCloseSubpath = 4;
|
||
|
||
kCGPathElementAddArc = 5;
|
||
kCGPathElementAddArcToPoint = 6;
|
||
|
||
/*!
|
||
@addtogroup coregraphics
|
||
@{
|
||
*/
|
||
|
||
/*!
|
||
Returns a new CGPath object.
|
||
*/
|
||
function CGPathCreateMutable()
|
||
{
|
||
return { count:0, start:CGPointMake(0, 0), current:CGPointMake(0, 0), elements:[] };
|
||
}
|
||
|
||
/*!
|
||
Returns a copy of the given path object.
|
||
*/
|
||
|
||
function CGPathCreateMutableCopy(aPath)
|
||
{
|
||
var path = CGPathCreateMutable();
|
||
|
||
CGPathAddPath(path, aPath);
|
||
|
||
return path;
|
||
}
|
||
|
||
/*!
|
||
Returns a copy of the given path object.
|
||
*/
|
||
|
||
function CGPathCreateCopy(aPath)
|
||
{
|
||
return CGPathCreateMutableCopy(aPath);
|
||
}
|
||
|
||
function CGPathRelease(aPath)
|
||
{
|
||
}
|
||
|
||
function CGPathRetain(aPath)
|
||
{
|
||
return aPath;
|
||
}
|
||
|
||
function CGPathAddArc(aPath, aTransform, x, y, aRadius, aStartAngle, anEndAngle, isClockwise)
|
||
{
|
||
if (aTransform && !CGAffineTransformIsIdentity(aTransform))
|
||
{
|
||
var center = CGPointMake(x, y),
|
||
end = CGPointMake(COS(anEndAngle), SIN(anEndAngle)),
|
||
start = CGPointMake(COS(aStartAngle), SIN(aStartAngle));
|
||
|
||
end = CGPointApplyAffineTransform(end, aTransform);
|
||
start = CGPointApplyAffineTransform(start, aTransform);
|
||
center = CGPointApplyAffineTransform(center, aTransform);
|
||
|
||
x = center.x;
|
||
y = center.y;
|
||
|
||
var oldEndAngle = anEndAngle,
|
||
oldStartAngle = aStartAngle;
|
||
|
||
anEndAngle = ATAN2(end.y - aTransform.ty, end.x - aTransform.tx);
|
||
aStartAngle = ATAN2(start.y - aTransform.ty, start.x - aTransform.tx);
|
||
|
||
// Angles that equal "modulo" 2 pi return as equal after transforming them,
|
||
// so we have to make sure to make them different again if they were different
|
||
// to start out with. It's the difference between no circle and a full circle.
|
||
if (anEndAngle === aStartAngle && oldEndAngle !== oldStartAngle)
|
||
if (oldStartAngle > oldEndAngle)
|
||
anEndAngle = anEndAngle - PI2;
|
||
else
|
||
aStartAngle = aStartAngle - PI2;
|
||
|
||
aRadius = CGSizeMake(aRadius, 0);
|
||
aRadius = CGSizeApplyAffineTransform(aRadius, aTransform);
|
||
aRadius = SQRT(aRadius.width * aRadius.width + aRadius.height * aRadius.height);
|
||
}
|
||
|
||
/*
|
||
From the Cocoa docs:
|
||
|
||
If the specified path already contains a subpath, Quartz implicitly adds a line connecting the subpath’s current point to the beginning of the arc. If the path is empty, Quartz creates a new subpath with a starting point set to the starting point of the arc.
|
||
|
||
The ending point of the arc becomes the new current point of the path.
|
||
*/
|
||
var arcEndX = x + aRadius * COS(anEndAngle),
|
||
arcEndY = y + aRadius * SIN(anEndAngle);
|
||
|
||
if (aPath.count)
|
||
{
|
||
if (aPath.current.x !== arcEndX || aPath.current.y !== arcEndY)
|
||
CGPathAddLineToPoint(aPath, aTransform, arcEndX, arcEndY);
|
||
}
|
||
else
|
||
{
|
||
var arcStartX = x + aRadius * COS(aStartAngle),
|
||
arcStartY = y + aRadius * SIN(aStartAngle);
|
||
|
||
aPath.start = CGPointMake(arcStartX, arcStartY);
|
||
}
|
||
|
||
aPath.current = CGPointMake(arcEndX, arcEndY);
|
||
aPath.elements[aPath.count++] = { type:kCGPathElementAddArc, x:x, y:y, radius:aRadius, startAngle:aStartAngle, endAngle:anEndAngle, clockwise:isClockwise };
|
||
}
|
||
|
||
function CGPathAddArcToPoint(aPath, aTransform, x1, y1, x2, y2, aRadius)
|
||
{
|
||
var p1 = CGPointMake(x1, y1),
|
||
p2 = CGPointMake(x2, y2);
|
||
|
||
if (aTransform)
|
||
{
|
||
p1 = CGPointApplyAffineTransform(p1, aTransform);
|
||
p2 = CGPointApplyAffineTransform(p2, aTransform);
|
||
}
|
||
|
||
/*
|
||
From the Cocoa docs:
|
||
|
||
If the current point and the first tangent point of the arc (the starting point) are not equal, Quartz appends a straight line segment from the current point to the first tangent point.
|
||
|
||
The ending point of the arc becomes the new current point of the path.
|
||
*/
|
||
if (aPath.count)
|
||
{
|
||
if (aPath.current.x !== p1.x || aPath.current.y !== p1.y)
|
||
CGPathAddLineToPoint(aPath, aTransform, p1.x, p1.y);
|
||
}
|
||
else
|
||
aPath.start = p1;
|
||
|
||
aPath.current = p2;
|
||
aPath.elements[aPath.count++] = { type:kCGPathElementAddArcToPoint, p1x:p1.x, p1y:p1.y, p2x:p2.x, p2y:p2.y, radius:aRadius };
|
||
}
|
||
|
||
function CGPathAddCurveToPoint(aPath, aTransform, cp1x, cp1y, cp2x, cp2y, x, y)
|
||
{
|
||
var cp1 = CGPointMake(cp1x, cp1y),
|
||
cp2 = CGPointMake(cp2x, cp2y),
|
||
end = CGPointMake(x, y);
|
||
|
||
if (aTransform)
|
||
{
|
||
cp1 = CGPointApplyAffineTransform(cp1, aTransform);
|
||
cp2 = CGPointApplyAffineTransform(cp2, aTransform);
|
||
end = CGPointApplyAffineTransform(end, aTransform);
|
||
}
|
||
|
||
aPath.current = end;
|
||
aPath.elements[aPath.count++] = { type:kCGPathElementAddCurveToPoint, cp1x:cp1.x, cp1y:cp1.y, cp2x:cp2.x, cp2y:cp2.y, x:end.x, y:end.y };
|
||
}
|
||
|
||
function CGPathAddLines(aPath, aTransform, points, count)
|
||
{
|
||
if (count === null || count === undefined)
|
||
count = points.length;
|
||
|
||
if (!aPath || count < 1)
|
||
return;
|
||
|
||
CGPathMoveToPoint(aPath, aTransform, points[0].x, points[0].y);
|
||
|
||
for (var i = 1; i < count; ++i)
|
||
CGPathAddLineToPoint(aPath, aTransform, points[i].x, points[i].y);
|
||
}
|
||
|
||
function CGPathAddLineToPoint(aPath, aTransform, x, y)
|
||
{
|
||
var point = CGPointMake(x, y);
|
||
|
||
if (aTransform !== NULL)
|
||
point = CGPointApplyAffineTransform(point, aTransform);
|
||
|
||
aPath.elements[aPath.count++] = { type: kCGPathElementAddLineToPoint, x:point.x, y:point.y };
|
||
aPath.current = point;
|
||
}
|
||
|
||
function CGPathAddPath(aPath, aTransform, anotherPath)
|
||
{
|
||
for (var i = 0, count = anotherPath.count; i < count; ++i)
|
||
{
|
||
var element = anotherPath.elements[i];
|
||
|
||
switch (element.type)
|
||
{
|
||
case kCGPathElementAddLineToPoint:
|
||
CGPathAddLineToPoint(aPath, aTransform, element.x, element.y);
|
||
break;
|
||
|
||
case kCGPathElementAddCurveToPoint:
|
||
CGPathAddCurveToPoint(aPath, aTransform,
|
||
element.cp1x, element.cp1y,
|
||
element.cp2x, element.cp2y,
|
||
element.x, element.y);
|
||
break;
|
||
|
||
case kCGPathElementAddArc:
|
||
CGPathAddArc(aPath, aTransform, element.x, element.y,
|
||
element.radius, element.startAngle,
|
||
element.endAngle, element.clockwise);
|
||
break;
|
||
|
||
case kCGPathElementAddArcToPoint:
|
||
CGPathAddArcToPoint(aPath, aTransform,
|
||
element.p1x, element.p1y,
|
||
element.p2x, element.p2y,
|
||
element.radius);
|
||
break;
|
||
|
||
case kCGPathElementAddQuadCurveToPoint:
|
||
CGPathAddQuadCurveToPoint(aPath, aTransform,
|
||
element.cpx, element.cpy,
|
||
element.x, element.y);
|
||
break;
|
||
|
||
case kCGPathElementMoveToPoint:
|
||
CGPathMoveToPoint(aPath, aTransform, element.x, element.y);
|
||
break;
|
||
|
||
case kCGPathElementCloseSubpath:
|
||
CGPathCloseSubpath(aPath);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
function CGPathAddQuadCurveToPoint(aPath, aTransform, cpx, cpy, x, y)
|
||
{
|
||
var cp = CGPointMake(cpx, cpy),
|
||
end = CGPointMake(x, y);
|
||
|
||
if (aTransform)
|
||
{
|
||
cp = CGPointApplyAffineTransform(cp, aTransform);
|
||
end = CGPointApplyAffineTransform(end, aTransform);
|
||
}
|
||
|
||
aPath.elements[aPath.count++] = { type:kCGPathElementAddQuadCurveToPoint, cpx:cp.x, cpy:cp.y, x:end.x, y:end.y }
|
||
aPath.current = end;
|
||
}
|
||
|
||
function CGPathAddRect(aPath, aTransform, aRect)
|
||
{
|
||
CGPathAddRects(aPath, aTransform, [aRect], 1);
|
||
}
|
||
|
||
function CGPathAddRects(aPath, aTransform, rects, count)
|
||
{
|
||
var i = 0;
|
||
|
||
if (count === NULL)
|
||
var count = rects.length;
|
||
|
||
for (; i < count; ++i)
|
||
{
|
||
var rect = rects[i];
|
||
|
||
CGPathMoveToPoint(aPath, aTransform, CGRectGetMinX(rect), CGRectGetMinY(rect));
|
||
CGPathAddLineToPoint(aPath, aTransform, CGRectGetMaxX(rect), CGRectGetMinY(rect));
|
||
CGPathAddLineToPoint(aPath, aTransform, CGRectGetMaxX(rect), CGRectGetMaxY(rect));
|
||
CGPathAddLineToPoint(aPath, aTransform, CGRectGetMinX(rect), CGRectGetMaxY(rect));
|
||
|
||
CGPathCloseSubpath(aPath);
|
||
}
|
||
}
|
||
|
||
function CGPathMoveToPoint(aPath, aTransform, x, y)
|
||
{
|
||
var point = CGPointMake(x, y);
|
||
|
||
if (aTransform !== NULL)
|
||
point = CGPointApplyAffineTransform(point, aTransform);
|
||
|
||
aPath.start = aPath.current = point;
|
||
|
||
// If the previous op was a move, just update that point
|
||
if (aPath.count)
|
||
{
|
||
var previous = aPath.elements[aPath.count - 1];
|
||
|
||
if (previous.type === kCGPathElementMoveToPoint)
|
||
{
|
||
previous.x = point.x;
|
||
previous.y = point.y;
|
||
return;
|
||
}
|
||
}
|
||
|
||
aPath.elements[aPath.count++] = { type:kCGPathElementMoveToPoint, x:point.x, y:point.y };
|
||
}
|
||
|
||
var KAPPA = 4.0 * ((SQRT2 - 1.0) / 3.0);
|
||
|
||
function CGPathWithEllipseInRect(aRect)
|
||
{
|
||
var path = CGPathCreateMutable();
|
||
|
||
if (CGRectGetWidth(aRect) === CGRectGetHeight(aRect))
|
||
CGPathAddArc(path, nil, CGRectGetMidX(aRect), CGRectGetMidY(aRect), CGRectGetWidth(aRect) / 2.0, 0.0, 2 * PI, YES);
|
||
else
|
||
{
|
||
var axis = CGSizeMake(CGRectGetWidth(aRect) / 2.0, CGRectGetHeight(aRect) / 2.0),
|
||
center = CGPointMake(CGRectGetMinX(aRect) + axis.width, CGRectGetMinY(aRect) + axis.height);
|
||
|
||
CGPathMoveToPoint(path, nil, center.x, center.y - axis.height);
|
||
|
||
CGPathAddCurveToPoint(path, nil, center.x + (KAPPA * axis.width), center.y - axis.height, center.x + axis.width, center.y - (KAPPA * axis.height), center.x + axis.width, center.y);
|
||
CGPathAddCurveToPoint(path, nil, center.x + axis.width, center.y + (KAPPA * axis.height), center.x + (KAPPA * axis.width), center.y + axis.height, center.x, center.y + axis.height);
|
||
CGPathAddCurveToPoint(path, nil, center.x - (KAPPA * axis.width), center.y + axis.height, center.x - axis.width, center.y + (KAPPA * axis.height), center.x - axis.width, center.y);
|
||
CGPathAddCurveToPoint(path, nil, center.x - axis.width, center.y - (KAPPA * axis.height), center.x - (KAPPA * axis.width), center.y - axis.height, center.x, center.y - axis.height);
|
||
}
|
||
|
||
CGPathCloseSubpath(path);
|
||
|
||
return path;
|
||
}
|
||
|
||
function CGPathWithRoundedRectangleInRect(aRect, xRadius, yRadius/*not currently supported*/, ne, se, sw, nw)
|
||
{
|
||
var path = CGPathCreateMutable(),
|
||
xMin = CGRectGetMinX(aRect),
|
||
xMax = CGRectGetMaxX(aRect),
|
||
yMin = CGRectGetMinY(aRect),
|
||
yMax = CGRectGetMaxY(aRect);
|
||
|
||
CGPathMoveToPoint(path, nil, xMin + xRadius, yMin);
|
||
|
||
if (ne)
|
||
{
|
||
CGPathAddLineToPoint(path, nil, xMax - xRadius, yMin);
|
||
CGPathAddCurveToPoint(path, nil, xMax - xRadius, yMin, xMax, yMin, xMax, yMin + xRadius);
|
||
}
|
||
else
|
||
CGPathAddLineToPoint(path, nil, xMax, yMin);
|
||
|
||
if (se)
|
||
{
|
||
CGPathAddLineToPoint(path, nil, xMax, yMax - xRadius);
|
||
CGPathAddCurveToPoint(path, nil, xMax, yMax - xRadius, xMax, yMax, xMax - xRadius, yMax);
|
||
}
|
||
else
|
||
CGPathAddLineToPoint(path, nil, xMax, yMax);
|
||
|
||
if (sw)
|
||
{
|
||
CGPathAddLineToPoint(path, nil, xMin + xRadius, yMax);
|
||
CGPathAddCurveToPoint(path, nil, xMin + xRadius, yMax, xMin, yMax, xMin, yMax - xRadius);
|
||
}
|
||
else
|
||
CGPathAddLineToPoint(path, nil, xMin, yMax);
|
||
|
||
if (nw)
|
||
{
|
||
CGPathAddLineToPoint(path, nil, xMin, yMin + xRadius);
|
||
CGPathAddCurveToPoint(path, nil, xMin, yMin + xRadius, xMin, yMin, xMin + xRadius, yMin);
|
||
}
|
||
else
|
||
CGPathAddLineToPoint(path, nil, xMin, yMin);
|
||
|
||
CGPathCloseSubpath(path);
|
||
|
||
return path;
|
||
}
|
||
|
||
function CGPathCloseSubpath(aPath)
|
||
{
|
||
var count = aPath.count;
|
||
|
||
// Don't bother closing this subpath if there aren't any current elements, or the last element already closed the subpath.
|
||
if (count === 0 || aPath.elements[count - 1].type === kCGPathElementCloseSubpath)
|
||
return;
|
||
|
||
// After closing, the current point is the previous path's starting point
|
||
aPath.current = CGPointCreateCopy(aPath.start);
|
||
aPath.elements[aPath.count++] = { type:kCGPathElementCloseSubpath, start:aPath.start };
|
||
}
|
||
|
||
function CGPathEqualToPath(aPath, anotherPath)
|
||
{
|
||
if (aPath === anotherPath)
|
||
return YES;
|
||
|
||
if (aPath.count !== anotherPath.count || !CGPointEqualToPoint(aPath.start, anotherPath.start) || !CGPointEqualToPoint(aPath.current, anotherPath.current))
|
||
return NO;
|
||
|
||
var i = 0,
|
||
count = aPath.count;
|
||
|
||
for (; i < count; ++i)
|
||
{
|
||
var element = aPath[i],
|
||
anotherElement = anotherPath[i];
|
||
|
||
if (element.type !== anotherElement.type)
|
||
return NO;
|
||
|
||
switch (element.type)
|
||
{
|
||
case kCGPathElementAddArc:
|
||
if (element.x !== anotherElement.x ||
|
||
element.y !== anotherElement.y ||
|
||
element.radius !== anotherElement.radius ||
|
||
element.startAngle !== anotherElement.startAngle ||
|
||
element.endAngle !== anotherElement.endAngle ||
|
||
element.clockwise !== anotherElement.clockwise)
|
||
{
|
||
return NO;
|
||
}
|
||
break;
|
||
|
||
case kCGPathElementAddArcToPoint:
|
||
if (element.p1x !== anotherElement.p1x ||
|
||
element.p1y !== anotherElement.p1y ||
|
||
element.p2x !== anotherElement.p2x ||
|
||
element.p2y !== anotherElement.p2y ||
|
||
element.radius !== anotherElement.radius)
|
||
{
|
||
return NO;
|
||
}
|
||
break;
|
||
|
||
case kCGPathElementAddCurveToPoint:
|
||
if (element.cp1x !== anotherElement.cp1x ||
|
||
element.cp1y !== anotherElement.cp1y ||
|
||
element.cp2x !== anotherElement.cp2x ||
|
||
element.cp2y !== anotherElement.cp2y ||
|
||
element.x !== anotherElement.x ||
|
||
element.y !== anotherElement.y)
|
||
{
|
||
return NO;
|
||
}
|
||
break;
|
||
|
||
case kCGPathElementAddLineToPoint:
|
||
case kCGPathElementMoveToPoint:
|
||
if (element.x !== anotherElement.x ||
|
||
element.y !== anotherElement.y)
|
||
{
|
||
return NO;
|
||
}
|
||
break;
|
||
|
||
case kCGPathElementAddQuadCurveToPoint:
|
||
if (element.cpx !== anotherElement.cpx ||
|
||
element.cpy !== anotherElement.cpy ||
|
||
element.x !== anotherElement.x ||
|
||
element.y !== anotherElement.y)
|
||
{
|
||
return NO;
|
||
}
|
||
break;
|
||
|
||
case kCGPathElementCloseSubpath:
|
||
if (!CGPointEqualToPoint(element.start, anotherElement.start))
|
||
return NO;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return YES;
|
||
}
|
||
|
||
function CGPathGetCurrentPoint(aPath)
|
||
{
|
||
return CGPointCreateCopy(aPath.current);
|
||
}
|
||
|
||
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 CGPathGetBoundingBox.
|
||
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);
|
||
}
|
||
|
||
/*!
|
||
@}
|
||
*/
|
||
|