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; } }
void PathBuilderCG::BezierTo(const Point &aCP1, const Point &aCP2, const Point &aCP3) { if (!aCP1.IsFinite() || !aCP2.IsFinite() || !aCP3.IsFinite()) { return; } if (CGPathIsEmpty(mCGPath)) MoveTo(aCP1); CGPathAddCurveToPoint(mCGPath, nullptr, aCP1.x, aCP1.y, aCP2.x, aCP2.y, aCP3.x, aCP3.y); }
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::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) { CGPathAddCurveToPoint(m_path, 0, cp1.x(), cp1.y(), cp2.x(), cp2.y(), p.x(), p.y()); }
void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) { CGPathAddCurveToPoint(ensurePlatformPath(), 0, cp1.x(), cp1.y(), cp2.x(), cp2.y(), p.x(), p.y()); }