CGMutablePathRef TIPCGUtilsPartialRoundedBoxCreate( CGRect inRect, float radius, bool lowerRight, bool upperRight, bool upperLeft, bool lowerLeft ) { CGMutablePathRef roundedBoxRef = CGPathCreateMutable(); if( lowerRight ) { CGPathMoveToPoint(roundedBoxRef, NULL, inRect.origin.x, inRect.origin.y + radius); } else { CGPathMoveToPoint(roundedBoxRef, NULL, inRect.origin.x, inRect.origin.y); } if( upperRight ) { CGPathAddLineToPoint(roundedBoxRef, NULL, inRect.origin.x, inRect.origin.y + inRect.size.height - radius); CGPathAddArcToPoint(roundedBoxRef, NULL, inRect.origin.x, inRect.origin.y + inRect.size.height, inRect.origin.x + radius, inRect.origin.y + inRect.size.height, radius); } else { CGPathAddLineToPoint(roundedBoxRef, NULL, inRect.origin.x, inRect.origin.y + inRect.size.height); } if( upperLeft ) { CGPathAddArcToPoint(roundedBoxRef, NULL, inRect.origin.x + inRect.size.width, inRect.origin.y + inRect.size.height, inRect.origin.x + inRect.size.width, inRect.origin.y + inRect.size.height - radius, radius); } else { CGPathAddLineToPoint(roundedBoxRef, NULL, inRect.origin.x + inRect.size.width, inRect.origin.y + inRect.size.height); } if( lowerLeft ) { CGPathAddArcToPoint(roundedBoxRef, NULL, inRect.origin.x + inRect.size.width, inRect.origin.y, inRect.origin.x + inRect.size.width - radius, inRect.origin.y, radius); } else { CGPathAddLineToPoint(roundedBoxRef, NULL, inRect.origin.x + inRect.size.width, inRect.origin.y); } if( lowerRight ) { CGPathAddArcToPoint(roundedBoxRef, NULL, inRect.origin.x, inRect.origin.y, inRect.origin.x, inRect.origin.y + radius, radius); } return roundedBoxRef; }
DRAW_TEST_P(CGContextFillMode, OverlappedEllipses) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); bounds = CGRectInset(bounds, 16.f, 16.f); CGFloat width = bounds.size.width; CGFloat height = bounds.size.height; CGFloat xstart = bounds.origin.x; CGFloat ystart = bounds.origin.y; CGPathDrawingMode fillMode = GetParam(); CGMutablePathRef leftCircles = CGPathCreateMutable(); CGPathMoveToPoint(leftCircles, NULL, xstart + .25 * width + .4 * height, ystart + .5 * height); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .4 * height, 0, M_PI, true); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .4 * height, M_PI, 0, true); CGPathMoveToPoint(leftCircles, NULL, xstart + .25 * width + .3 * height, ystart + .5 * height); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .3 * height, 0, M_PI, true); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .3 * height, M_PI, 0, true); CGPathMoveToPoint(leftCircles, NULL, xstart + .25 * width + .2 * height, ystart + .5 * height); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .2 * height, 0, M_PI, true); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .2 * height, M_PI, 0, true); CGPathMoveToPoint(leftCircles, NULL, xstart + .25 * width + .1 * height, ystart + .5 * height); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .1 * height, 0, M_PI, true); CGPathAddArc(leftCircles, NULL, xstart + .25 * width, ystart + .5 * height, .1 * height, M_PI, 0, true); CGPathCloseSubpath(leftCircles); CGMutablePathRef rightCircles = CGPathCreateMutable(); CGPathMoveToPoint(rightCircles, NULL, xstart + .75 * width + .4 * height, ystart + .5 * height); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .4 * height, 0, M_PI, false); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .4 * height, M_PI, 0, false); CGPathMoveToPoint(rightCircles, NULL, xstart + .75 * width + .3 * height, ystart + .5 * height); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .3 * height, 0, M_PI, true); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .3 * height, M_PI, 0, true); CGPathMoveToPoint(rightCircles, NULL, xstart + .75 * width + .2 * height, ystart + .5 * height); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .2 * height, 0, M_PI, false); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .2 * height, M_PI, 0, false); CGPathMoveToPoint(rightCircles, NULL, xstart + .75 * width + .1 * height, ystart + .5 * height); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .1 * height, 0, M_PI, true); CGPathAddArc(rightCircles, NULL, xstart + .75 * width, ystart + .5 * height, .1 * height, M_PI, 0, true); CGPathCloseSubpath(rightCircles); CGContextAddPath(context, leftCircles); CGContextAddPath(context, rightCircles); CGContextSetRGBFillColor(context, 0, 0, 1, 1); CGContextSetRGBStrokeColor(context, 1, 0, 0, 1); CGContextDrawPath(context, fillMode); CGPathRelease(leftCircles); CGPathRelease(rightCircles); }
static void copyClosingSubpathsApplierFunction(void* info, const CGPathElement* element) { CGMutablePathRef path = static_cast<CGMutablePathRef>(info); CGPoint* points = element->points; switch (element->type) { case kCGPathElementMoveToPoint: if (!CGPathIsEmpty(path)) // to silence a warning when trying to close an empty path CGPathCloseSubpath(path); // This is the only change from CGPathCreateMutableCopy CGPathMoveToPoint(path, 0, points[0].x, points[0].y); break; case kCGPathElementAddLineToPoint: CGPathAddLineToPoint(path, 0, points[0].x, points[0].y); break; case kCGPathElementAddQuadCurveToPoint: CGPathAddQuadCurveToPoint(path, 0, points[0].x, points[0].y, points[1].x, points[1].y); break; case kCGPathElementAddCurveToPoint: CGPathAddCurveToPoint(path, 0, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y); break; case kCGPathElementCloseSubpath: CGPathCloseSubpath(path); break; } }
CGMutablePathRef TIPCGUtilsRoundedBoxCreate( CGRect inRect, float margin, float radius, float lineWidth ) { float halfLineWidth = lineWidth/2.0f; inRect.origin.x += margin; inRect.origin.y += margin; inRect.size.width -= 2.0f*margin; inRect.size.height -= 2.0f*margin; CGMutablePathRef roundedBoxRef = CGPathCreateMutable(); CGPathMoveToPoint(roundedBoxRef, NULL, inRect.origin.x + halfLineWidth, inRect.origin.y + halfLineWidth + radius); CGPathAddLineToPoint(roundedBoxRef, NULL, inRect.origin.x + halfLineWidth, inRect.origin.y + inRect.size.height - radius - halfLineWidth); CGPathAddArcToPoint(roundedBoxRef, NULL, inRect.origin.x + halfLineWidth, inRect.origin.y + inRect.size.height - halfLineWidth, inRect.origin.x + halfLineWidth + radius, inRect.origin.y + inRect.size.height - halfLineWidth, radius); CGPathAddArcToPoint(roundedBoxRef, NULL, inRect.origin.x + inRect.size.width - halfLineWidth, inRect.origin.y + inRect.size.height - halfLineWidth, inRect.origin.x + inRect.size.width - halfLineWidth, inRect.origin.y + inRect.size.height - radius - halfLineWidth, radius); CGPathAddArcToPoint(roundedBoxRef, NULL, inRect.origin.x + inRect.size.width - halfLineWidth, inRect.origin.y + halfLineWidth, inRect.origin.x + inRect.size.width - radius - halfLineWidth, inRect.origin.y + halfLineWidth, radius); CGPathAddArcToPoint(roundedBoxRef, NULL, inRect.origin.x + halfLineWidth, inRect.origin.y + halfLineWidth, inRect.origin.x + halfLineWidth, inRect.origin.y + halfLineWidth + radius, radius); return roundedBoxRef; }
void PathBuilderCG::MoveTo(const Point &aPoint) { if (!aPoint.IsFinite()) { return; } CGPathMoveToPoint(mCGPath, nullptr, aPoint.x, aPoint.y); }
//----------------------------------------------------------------------------------- static void DoTheTracking(EventRef inEvent, MTViewData* data) { MouseTrackingResult mouseResult; ControlPartCode part; Point qdPt; HIPoint where; // Extract the mouse location (local coordinates!) GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(HIPoint), NULL, &where); CGAffineTransform m = CGAffineTransformIdentity; // Reset the path if (data->thePath != NULL) CGPathRelease(data->thePath); data->thePath = CGPathCreateMutable(); #if CG_COORDINATES where.y = FlipHIViewYCoordinate(data->theView, where.y); #endif CGPathMoveToPoint(data->thePath, &m, where.x, where.y); // fprintf(stderr, "StartPt: (%g, %g\n", where.x, where.y); while (true) { // Watch the mouse for change: qdPt comes back in global coordinates! TrackMouseLocation((GrafPtr)(-1), &qdPt, &mouseResult); // Bail out when the mouse is released if ( mouseResult == kMouseTrackingMouseReleased ) { HIViewSetNeedsDisplay(data->theView, true); break; } // Need to convert from global where = QDGlobalToHIViewLocal(qdPt, data->theView); #if CG_COORDINATES where.y = FlipHIViewYCoordinate(data->theView, where.y); #endif CGPathAddLineToPoint(data->thePath, &m, where.x, where.y); // fprintf(stderr, "TrackPt: (%g, %g\n", where.x, where.y); part = 0; SetEventParameter(inEvent, kEventParamControlPart, typeControlPartCode, sizeof(ControlPartCode), &part); HIViewSetNeedsDisplay(data->theView, true); } // Send back the part upon which the mouse was released part = kControlEntireControl; SetEventParameter(inEvent, kEventParamControlPart, typeControlPartCode, sizeof(ControlPartCode), &part); }
static void TranformCGPathApplierFunc(void *vinfo, const CGPathElement *element) { TransformApplier *info = reinterpret_cast<TransformApplier*>(vinfo); switch (element->type) { case kCGPathElementMoveToPoint: { CGPoint pt = element->points[0]; CGPathMoveToPoint(info->path, &info->transform, pt.x, pt.y); break; } case kCGPathElementAddLineToPoint: { CGPoint pt = element->points[0]; CGPathAddLineToPoint(info->path, &info->transform, pt.x, pt.y); break; } case kCGPathElementAddQuadCurveToPoint: { CGPoint cpt = element->points[0]; CGPoint pt = element->points[1]; CGPathAddQuadCurveToPoint(info->path, &info->transform, cpt.x, cpt.y, pt.x, pt.y); break; } case kCGPathElementAddCurveToPoint: { CGPoint cpt1 = element->points[0]; CGPoint cpt2 = element->points[1]; CGPoint pt = element->points[2]; CGPathAddCurveToPoint(info->path, &info->transform, cpt1.x, cpt1.y, cpt2.x, cpt2.y, pt.x, pt.y); break; } case kCGPathElementCloseSubpath: { CGPathCloseSubpath(info->path); break; } } }
static CGPathRef createPathForGlyph(HDC hdc, Glyph glyph) { CGMutablePathRef path = CGPathCreateMutable(); static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 }; GLYPHMETRICS glyphMetrics; // GGO_NATIVE matches the outline perfectly when Windows font smoothing is off. // GGO_NATIVE | GGO_UNHINTED does not match perfectly either when Windows font smoothing is on or off. DWORD outlineLength = GetGlyphOutline(hdc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE, &glyphMetrics, 0, 0, &identity); ASSERT(outlineLength >= 0); if (outlineLength < 0) return path; Vector<UInt8> outline(outlineLength); GetGlyphOutline(hdc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE, &glyphMetrics, outlineLength, outline.data(), &identity); unsigned offset = 0; while (offset < outlineLength) { LPTTPOLYGONHEADER subpath = reinterpret_cast<LPTTPOLYGONHEADER>(outline.data() + offset); ASSERT(subpath->dwType == TT_POLYGON_TYPE); if (subpath->dwType != TT_POLYGON_TYPE) return path; CGPathMoveToPoint(path, 0, toCGFloat(subpath->pfxStart.x), toCGFloat(subpath->pfxStart.y)); unsigned subpathOffset = sizeof(*subpath); while (subpathOffset < subpath->cb) { LPTTPOLYCURVE segment = reinterpret_cast<LPTTPOLYCURVE>(reinterpret_cast<UInt8*>(subpath) + subpathOffset); switch (segment->wType) { case TT_PRIM_LINE: for (unsigned i = 0; i < segment->cpfx; i++) CGPathAddLineToPoint(path, 0, toCGFloat(segment->apfx[i].x), toCGFloat(segment->apfx[i].y)); break; case TT_PRIM_QSPLINE: for (unsigned i = 0; i < segment->cpfx; i++) { CGFloat x = toCGFloat(segment->apfx[i].x); CGFloat y = toCGFloat(segment->apfx[i].y); CGFloat cpx; CGFloat cpy; if (i == segment->cpfx - 2) { cpx = toCGFloat(segment->apfx[i + 1].x); cpy = toCGFloat(segment->apfx[i + 1].y); i++; } else { cpx = (toCGFloat(segment->apfx[i].x) + toCGFloat(segment->apfx[i + 1].x)) / 2; cpy = (toCGFloat(segment->apfx[i].y) + toCGFloat(segment->apfx[i + 1].y)) / 2; } CGPathAddQuadCurveToPoint(path, 0, x, y, cpx, cpy); } break; case TT_PRIM_CSPLINE: for (unsigned i = 0; i < segment->cpfx; i += 3) { CGFloat cp1x = toCGFloat(segment->apfx[i].x); CGFloat cp1y = toCGFloat(segment->apfx[i].y); CGFloat cp2x = toCGFloat(segment->apfx[i + 1].x); CGFloat cp2y = toCGFloat(segment->apfx[i + 1].y); CGFloat x = toCGFloat(segment->apfx[i + 2].x); CGFloat y = toCGFloat(segment->apfx[i + 2].y); CGPathAddCurveToPoint(path, 0, cp1x, cp1y, cp2x, cp2y, x, y); } break; default: ASSERT_NOT_REACHED(); return path; } subpathOffset += sizeof(*segment) + (segment->cpfx - 1) * sizeof(segment->apfx[0]); } CGPathCloseSubpath(path); offset += subpath->cb; } return path; }
void Path::moveTo(const FloatPoint& point) { CGPathMoveToPoint(m_path, 0, point.x(), point.y()); }
/* Event handler for the content view that gets attached to the menu frame. The content view will (eventually) contain the menu view. */ OSStatus ContentViewEventHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void *refcon) { OSStatus retVal = eventNotHandledErr; if(GetEventClass(inEvent) == kEventClassMenu) { return noErr; } else if(GetEventClass(inEvent) == kEventClassControl) { HIViewRef hiSelf = NULL; verify_noerr(GetEventParameter(inEvent, kEventParamDirectObject, typeControlRef, NULL, sizeof(hiSelf), NULL, &hiSelf)); if(hiSelf) { HIRect frame; HIViewGetFrame(hiSelf, &frame); switch(GetEventKind(inEvent)) { case kEventControlAddedSubControl : { HIViewRef subControl; ControlID subControlID; GetEventParameter(inEvent, kEventParamControlSubControl, typeControlRef, NULL, sizeof(subControl), NULL, &subControl ); GetControlID(subControl, &subControlID); // This should be comparing against kHIViewMenuContentID as shown inside the // #if 0. At the time of this writing, however, using that constant causes a // linker error (and a crash if you use ZeroLink). I extracted the signature // and id by determining the value at run-time the value I compare against. #if 0 if( kHIViewMenuContentID.signature == subControlID.signature && kHIViewMenuContentID.id == subControlID.id ) { #else if( 'menu' == subControlID.signature && 0 == subControlID.id ) { #endif // If we have the menu content view then set up some view bindings for it. HIRect bounds; HIViewGetBounds(hiSelf, &bounds); HIViewSetFrame(subControl, &bounds); HILayoutInfo contentLayout = { kHILayoutInfoVersionZero, { { NULL, kHILayoutBindTop }, { NULL, kHILayoutBindLeft }, { NULL, kHILayoutBindBottom }, { NULL, kHILayoutBindRight } }, { { NULL, kHILayoutScaleAbsolute, 0 }, { NULL, kHILayoutScaleAbsolute, 0 } }, { { NULL, kHILayoutPositionTop, 0 }, { NULL, kHILayoutPositionLeft, 0 } } }; verify_noerr(HIViewSetLayoutInfo(subControl, &contentLayout)); } retVal = noErr; } break; case kEventControlGetFrameMetrics : HIViewFrameMetrics metrics; // The offset from the frame view to the content view is // given by the kFrameOffset constant metrics.top = kFrameOffset; metrics.left = kFrameOffset; metrics.right = kFrameOffset; metrics.bottom = kFrameOffset; verify_noerr(SetEventParameter(inEvent, kEventParamControlFrameMetrics, typeControlFrameMetrics, sizeof(metrics), &metrics)); retVal = noErr; break; case kEventControlBoundsChanged : case kEventControlOwningWindowChanged : { // Maintain the QuickDraw port by changing its position to // match that of the content view. CGrafPtr windowPort = NULL; WindowRef window = GetControlOwner(hiSelf); if(window && (windowPort = GetWindowPort(window))) { CGrafPtr savePort; bool swapped = QDSwapPort(windowPort, &savePort); MovePortTo((short) frame.origin.x, (short) frame.origin.y); PortSize((short) frame.size.width, (short) frame.size.height); if(swapped) { QDSwapPort(savePort, NULL); } } retVal = noErr; } break; } // switch } // if (hiSelf) } return retVal; } /* ------------------------------------------ CreatePathForEntireStarMenu */ /* Create a path shape for the star frame. This looks an awful lot like CreatePathForEntireStarMenu in StarMenu.cpp but takes the radius to use as a parameter and then takes into account the kFrameOffest when creating the path. In true Core Foundation style, this is a CreateXXX routine and the caller is responsible for freeing the path that is returned. */ CGPathRef CreatePathForStarFrame(StarFrameData *menuData, float radius) { CGMutablePathRef retVal = CGPathCreateMutable(); MenuItemIndex numItems = CountMenuItems(menuData->menu); if(numItems > 0) { const CGPoint fullRadiusPoint = { radius, 0 }; const CGPoint halfRadiusPoint = { ((radius - kFrameOffset) / 2.0) + kFrameOffset , 0 }; float anglePerItem = 2 * pi / (float)numItems; // in radians naturally float halfAngle = anglePerItem / 2.0; CGPoint startPoint = halfRadiusPoint; CGAffineTransform midRotate = CGAffineTransformMakeRotation(halfAngle); CGPoint midPoint = CGPointApplyAffineTransform(fullRadiusPoint, midRotate); CGAffineTransform rotateToNext = CGAffineTransformMakeRotation(anglePerItem); CGPathMoveToPoint(retVal, NULL, startPoint.x, startPoint.y); CGPathAddLineToPoint(retVal, NULL, midPoint.x, midPoint.y); for(short ctr = 0; ctr < numItems; ctr++) { startPoint = CGPointApplyAffineTransform(startPoint, rotateToNext); midPoint = CGPointApplyAffineTransform(midPoint, rotateToNext); CGPathAddLineToPoint(retVal, NULL, startPoint.x, startPoint.y); CGPathAddLineToPoint(retVal, NULL, midPoint.x, midPoint.y); } CGPathCloseSubpath(retVal); } return retVal; }
void Path::moveTo(const FloatPoint& point) { CGPathMoveToPoint(ensurePlatformPath(), 0, point.x(), point.y()); }