From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- gfx/2d/PathCG.cpp | 435 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 435 insertions(+) create mode 100644 gfx/2d/PathCG.cpp (limited to 'gfx/2d/PathCG.cpp') diff --git a/gfx/2d/PathCG.cpp b/gfx/2d/PathCG.cpp new file mode 100644 index 000000000..4d70b2607 --- /dev/null +++ b/gfx/2d/PathCG.cpp @@ -0,0 +1,435 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "PathCG.h" +#include +#include "Logging.h" +#include "PathHelpers.h" + +namespace mozilla { +namespace gfx { + +static inline Rect +CGRectToRect(CGRect rect) +{ + return Rect(rect.origin.x, + rect.origin.y, + rect.size.width, + rect.size.height); +} + +static inline Point +CGPointToPoint(CGPoint point) +{ + return Point(point.x, point.y); +} + +static inline void +SetStrokeOptions(CGContextRef cg, const StrokeOptions &aStrokeOptions) +{ + switch (aStrokeOptions.mLineCap) + { + case CapStyle::BUTT: + CGContextSetLineCap(cg, kCGLineCapButt); + break; + case CapStyle::ROUND: + CGContextSetLineCap(cg, kCGLineCapRound); + break; + case CapStyle::SQUARE: + CGContextSetLineCap(cg, kCGLineCapSquare); + break; + } + + switch (aStrokeOptions.mLineJoin) + { + case JoinStyle::BEVEL: + CGContextSetLineJoin(cg, kCGLineJoinBevel); + break; + case JoinStyle::ROUND: + CGContextSetLineJoin(cg, kCGLineJoinRound); + break; + case JoinStyle::MITER: + case JoinStyle::MITER_OR_BEVEL: + CGContextSetLineJoin(cg, kCGLineJoinMiter); + break; + } + + CGContextSetLineWidth(cg, aStrokeOptions.mLineWidth); + CGContextSetMiterLimit(cg, aStrokeOptions.mMiterLimit); + + // XXX: rename mDashLength to dashLength + if (aStrokeOptions.mDashLength > 0) { + // we use a regular array instead of a std::vector here because we don't want to leak the include + CGFloat *dashes = new CGFloat[aStrokeOptions.mDashLength]; + for (size_t i=0; i +PathBuilderCG::Finish() +{ + return MakeAndAddRef(mCGPath, mFillRule); +} + +already_AddRefed +PathCG::CopyToBuilder(FillRule aFillRule) const +{ + CGMutablePathRef path = CGPathCreateMutableCopy(mPath); + return MakeAndAddRef(path, aFillRule); +} + + + +already_AddRefed +PathCG::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const +{ + // 10.7 adds CGPathCreateMutableCopyByTransformingPath it might be faster than doing + // this by hand + + struct TransformApplier { + CGMutablePathRef path; + CGAffineTransform transform; + static void + TranformCGPathApplierFunc(void *vinfo, const CGPathElement *element) + { + TransformApplier *info = reinterpret_cast(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; + } + } + } + }; + + TransformApplier ta; + ta.path = CGPathCreateMutable(); + ta.transform = GfxMatrixToCGAffineTransform(aTransform); + + CGPathApply(mPath, &ta, TransformApplier::TranformCGPathApplierFunc); + return MakeAndAddRef(ta.path, aFillRule); +} + +static void +StreamPathToSinkApplierFunc(void *vinfo, const CGPathElement *element) +{ + PathSink *sink = reinterpret_cast(vinfo); + switch (element->type) { + case kCGPathElementMoveToPoint: + { + CGPoint pt = element->points[0]; + sink->MoveTo(CGPointToPoint(pt)); + break; + } + case kCGPathElementAddLineToPoint: + { + CGPoint pt = element->points[0]; + sink->LineTo(CGPointToPoint(pt)); + break; + } + case kCGPathElementAddQuadCurveToPoint: + { + CGPoint cpt = element->points[0]; + CGPoint pt = element->points[1]; + sink->QuadraticBezierTo(CGPointToPoint(cpt), + CGPointToPoint(pt)); + break; + } + case kCGPathElementAddCurveToPoint: + { + CGPoint cpt1 = element->points[0]; + CGPoint cpt2 = element->points[1]; + CGPoint pt = element->points[2]; + sink->BezierTo(CGPointToPoint(cpt1), + CGPointToPoint(cpt2), + CGPointToPoint(pt)); + break; + } + case kCGPathElementCloseSubpath: + { + sink->Close(); + break; + } + } +} + +void +PathCG::StreamToSink(PathSink *aSink) const +{ + CGPathApply(mPath, aSink, StreamPathToSinkApplierFunc); +} + +bool +PathCG::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const +{ + Matrix inverse = aTransform; + inverse.Invert(); + Point transformedPoint = inverse.TransformPoint(aPoint); + // We could probably drop the input transform and just transform the point at the caller? + CGPoint point = {transformedPoint.x, transformedPoint.y}; + + // The transform parameter of CGPathContainsPoint doesn't seem to work properly on OS X 10.5 + // so we transform aPoint ourselves. + return CGPathContainsPoint(mPath, nullptr, point, mFillRule == FillRule::FILL_EVEN_ODD); +} + +static size_t +PutBytesNull(void *info, const void *buffer, size_t count) +{ + return count; +} + +/* The idea of a scratch context comes from WebKit */ +static CGContextRef +CreateScratchContext() +{ + CGDataConsumerCallbacks callbacks = {PutBytesNull, nullptr}; + CGDataConsumerRef consumer = CGDataConsumerCreate(nullptr, &callbacks); + CGContextRef cg = CGPDFContextCreate(consumer, nullptr, nullptr); + CGDataConsumerRelease(consumer); + return cg; +} + +static CGContextRef +ScratchContext() +{ + static CGContextRef cg = CreateScratchContext(); + return cg; +} + +bool +PathCG::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, + const Point &aPoint, + const Matrix &aTransform) const +{ + Matrix inverse = aTransform; + inverse.Invert(); + Point transformedPoint = inverse.TransformPoint(aPoint); + // We could probably drop the input transform and just transform the point at the caller? + CGPoint point = {transformedPoint.x, transformedPoint.y}; + + CGContextRef cg = ScratchContext(); + + CGContextSaveGState(cg); + + CGContextBeginPath(cg); + CGContextAddPath(cg, mPath); + + SetStrokeOptions(cg, aStrokeOptions); + + CGContextReplacePathWithStrokedPath(cg); + CGContextRestoreGState(cg); + + CGPathRef sPath = CGContextCopyPath(cg); + bool inStroke = CGPathContainsPoint(sPath, nullptr, point, false); + CGPathRelease(sPath); + + return inStroke; +} + +//XXX: what should these functions return for an empty path? +// currently they return CGRectNull {inf,inf, 0, 0} +Rect +PathCG::GetBounds(const Matrix &aTransform) const +{ + //XXX: are these bounds tight enough + Rect bounds = CGRectToRect(CGPathGetBoundingBox(mPath)); + + //XXX: currently this returns the bounds of the transformed bounds + // this is strictly looser than the bounds of the transformed path + return aTransform.TransformBounds(bounds); +} + +Rect +PathCG::GetStrokedBounds(const StrokeOptions &aStrokeOptions, + const Matrix &aTransform) const +{ + // 10.7 has CGPathCreateCopyByStrokingPath which we could use + // instead of this scratch context business + CGContextRef cg = ScratchContext(); + + CGContextSaveGState(cg); + + CGContextBeginPath(cg); + CGContextAddPath(cg, mPath); + + SetStrokeOptions(cg, aStrokeOptions); + + CGContextReplacePathWithStrokedPath(cg); + Rect bounds = CGRectToRect(CGContextGetPathBoundingBox(cg)); + + CGContextRestoreGState(cg); + + if (!bounds.IsFinite()) { + return Rect(); + } + + return aTransform.TransformBounds(bounds); +} + + +} // namespace gfx + +} // namespace mozilla -- cgit v1.2.3