Skip to content

Commit

Permalink
Fix Affine Transform in CGPath (#1550)
Browse files Browse the repository at this point in the history
* Affine Transform

* Remove excess com pointer usage from getters.

* Update API status.

* Enable Path Tests + Reference Images

* Disabled AddEllipseInRect test until CGContextSetStrokeColor is supported.
  • Loading branch information
MSFTFox authored Dec 16, 2016
1 parent 7fddae9 commit 470fd9b
Show file tree
Hide file tree
Showing 16 changed files with 85 additions and 43 deletions.
5 changes: 3 additions & 2 deletions Frameworks/CoreGraphics/CGContext.mm
Original file line number Diff line number Diff line change
Expand Up @@ -827,14 +827,15 @@ void CGContextAddPath(CGContextRef context, CGPathRef path) {
return;
}

CGAffineTransform userToDeviceTransform = CGContextGetUserSpaceToDeviceSpaceTransform(context);

if (!context->HasPath()) {
// If we don't curerntly have a path, take this one in as our own.
woc::unique_cf<CGMutablePathRef> copiedPath{ CGPathCreateMutableCopy(path) };
woc::unique_cf<CGMutablePathRef> copiedPath{ CGPathCreateMutableCopyByTransformingPath(path, &userToDeviceTransform) };
context->SetPath(copiedPath.get());
return;
}

CGAffineTransform userToDeviceTransform = CGContextGetUserSpaceToDeviceSpaceTransform(context);
CGPathAddPath(context->Path(), &userToDeviceTransform, path);
}

Expand Down
54 changes: 30 additions & 24 deletions Frameworks/CoreGraphics/CGPath.mm
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ static inline CGPoint __CreateCGPointWithTransform(CGFloat x, CGFloat y, const C
__CGPath() : figureClosed(true), lastTransform(CGAffineTransformIdentity) {
}

ComPtr<ID2D1PathGeometry> GetPathGeometry() const {
return pathGeometry;
ID2D1PathGeometry* GetPathGeometry() const {
return pathGeometry.Get();
}

ComPtr<ID2D1GeometrySink> GetGeometrySink() const {
return geometrySink;
ID2D1GeometrySink* GetGeometrySink() const {
return geometrySink.Get();
}

CGPoint GetCurrentPoint() const {
Expand Down Expand Up @@ -168,8 +168,7 @@ HRESULT AddGeometryToPathWithTransformation(const ID2D1Geometry* geometry, const
if (transform) {
transformation = __CGAffineTransformToD2D_F(*transform);
}
RETURN_IF_FAILED(
geometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, &transformation, GetGeometrySink().Get()));
RETURN_IF_FAILED(geometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, &transformation, GetGeometrySink()));

SetLastTransform(transform);
return S_OK;
Expand All @@ -180,7 +179,7 @@ HRESULT _CGPathGetGeometry(CGPathRef path, ID2D1Geometry** pGeometry) {
RETURN_HR_IF_NULL(E_POINTER, pGeometry);
RETURN_HR_IF_NULL(E_POINTER, path);
RETURN_IF_FAILED(path->ClosePath());
path->GetPathGeometry().CopyTo(pGeometry);
path->pathGeometry.CopyTo(pGeometry);
return S_OK;
}

Expand All @@ -204,13 +203,11 @@ static Boolean __CGPathEqual(CFTypeRef cf1, CFTypeRef cf2) {
// ID2D1 Geometries have no isEquals method. However, for two geometries to be equal they are both reported to contain the other.
// Thus we must do two comparisons.
D2D1_GEOMETRY_RELATION relation = D2D1_GEOMETRY_RELATION_UNKNOWN;
RETURN_FALSE_IF_FAILED(
path1->GetPathGeometry()->CompareWithGeometry(path2->GetPathGeometry().Get(), D2D1::IdentityMatrix(), &relation));
RETURN_FALSE_IF_FAILED(path1->GetPathGeometry()->CompareWithGeometry(path2->GetPathGeometry(), D2D1::IdentityMatrix(), &relation));

// Does path 1 contain path 2?
if (relation == D2D1_GEOMETRY_RELATION_IS_CONTAINED) {
RETURN_FALSE_IF_FAILED(
path2->GetPathGeometry()->CompareWithGeometry(path1->GetPathGeometry().Get(), D2D1::IdentityMatrix(), &relation));
RETURN_FALSE_IF_FAILED(path2->GetPathGeometry()->CompareWithGeometry(path1->GetPathGeometry(), D2D1::IdentityMatrix(), &relation));

// Return true if path 2 also contains path 1
return (relation == D2D1_GEOMETRY_RELATION_IS_CONTAINED ? true : false);
Expand All @@ -231,7 +228,7 @@ CGMutablePathRef CGPathCreateMutable() {
}

/**
@Status Caveat
@Status Interoperable
@Notes Creates a mutable copy
*/
CGPathRef CGPathCreateCopy(CGPathRef path) {
Expand All @@ -253,7 +250,7 @@ CGMutablePathRef CGPathCreateMutableCopy(CGPathRef path) {
// Otherwise the D2D calls will return that a bad state has been entered.
FAIL_FAST_IF_FAILED(path->ClosePath());

FAIL_FAST_IF_FAILED(path->GetPathGeometry()->Stream(mutableRet->GetGeometrySink().Get()));
FAIL_FAST_IF_FAILED(path->GetPathGeometry()->Stream(mutableRet->GetGeometrySink()));

mutableRet->SetCurrentPoint(path->GetCurrentPoint());
mutableRet->SetStartingPoint(path->GetStartingPoint());
Expand Down Expand Up @@ -476,7 +473,7 @@ void CGPathAddPath(CGMutablePathRef path, const CGAffineTransform* transform, CG

// Close the path being added.
FAIL_FAST_IF_FAILED(toAdd->ClosePath());
FAIL_FAST_IF_FAILED(path->AddGeometryToPathWithTransformation(toAdd->GetPathGeometry().Get(), transform));
FAIL_FAST_IF_FAILED(path->AddGeometryToPathWithTransformation(toAdd->GetPathGeometry(), transform));

CGPoint currentPoint = toAdd->GetCurrentPoint();
CGPoint startingPoint = toAdd->GetStartingPoint();
Expand Down Expand Up @@ -711,7 +708,7 @@ void CGPathAddRoundedRect(
void CGPathApply(CGPathRef path, void* info, CGPathApplierFunction function) {
RETURN_IF(!path);
FAIL_FAST_IF_FAILED(path->ClosePath());
FAIL_FAST_IF_FAILED(_CGPathApplyInternal(path->GetPathGeometry().Get(), info, function));
FAIL_FAST_IF_FAILED(_CGPathApplyInternal(path->GetPathGeometry(), info, function));
}

/**
Expand Down Expand Up @@ -754,21 +751,30 @@ CGPathRef CGPathCreateCopyByStrokingPath(
}

/**
@Status Stub
@Notes
@Status Interoperable
@Notes Creates a mutable copy
*/
CGPathRef CGPathCreateCopyByTransformingPath(CGPathRef path, const CGAffineTransform* transform) {
UNIMPLEMENTED();
return StubReturn();
return CGPathCreateMutableCopyByTransformingPath(path, transform);
}

/**
@Status Stub
@Notes
@Status Interoperable
*/
CGMutablePathRef CGPathCreateMutableCopyByTransformingPath(CGPathRef path, const CGAffineTransform* transform) {
UNIMPLEMENTED();
return StubReturn();
RETURN_NULL_IF(!path);

if (transform && !CGAffineTransformEqualToTransform(*transform, CGAffineTransformIdentity)) {
CGMutablePathRef transformedPath = CGPathCreateMutable();
path->ClosePath();

FAIL_FAST_IF_FAILED(transformedPath->AddGeometryToPathWithTransformation(path->GetPathGeometry(), transform));
transformedPath->SetCurrentPoint(CGPointApplyAffineTransform(path->GetCurrentPoint(), *transform));
transformedPath->SetStartingPoint(CGPointApplyAffineTransform(path->GetStartingPoint(), *transform));
transformedPath->SetLastTransform(transform);
return transformedPath;
}
return CGPathCreateMutableCopy(path);
}

/**
Expand All @@ -782,7 +788,7 @@ CGPathRef CGPathCreateWithRoundedRect(CGRect rect, CGFloat cornerWidth, CGFloat
}

/**
@Status Stub
@Status Interoperable
*/
bool CGPathEqualToPath(CGPathRef path1, CGPathRef path2) {
return __CGPathEqual(path1, path2);
Expand Down
9 changes: 4 additions & 5 deletions include/CoreGraphics/CGPath.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ COREGRAPHICS_EXPORT CGPathRef CGPathCreateWithRect(CGRect rect, const CGAffineTr
COREGRAPHICS_EXPORT CGPathRef CGPathCreateWithRoundedRect(CGRect rect,
CGFloat cornerWidth,
CGFloat cornerHeight,
const CGAffineTransform* transform) STUB_METHOD;
const CGAffineTransform* transform);

COREGRAPHICS_EXPORT CGPathRef CGPathCreateCopy(CGPathRef path);

COREGRAPHICS_EXPORT CGPathRef CGPathCreateCopyByTransformingPath(CGPathRef path, const CGAffineTransform* transform) STUB_METHOD;
COREGRAPHICS_EXPORT CGPathRef CGPathCreateCopyByTransformingPath(CGPathRef path, const CGAffineTransform* transform);

COREGRAPHICS_EXPORT CGPathRef CGPathCreateCopyByDashingPath(
CGPathRef path, const CGAffineTransform* transform, CGFloat phase, const CGFloat* lengths, size_t count) STUB_METHOD;
Expand All @@ -74,8 +74,7 @@ COREGRAPHICS_EXPORT CGPathRef CGPathCreateCopyByStrokingPath(CGPathRef path,

COREGRAPHICS_EXPORT CGMutablePathRef CGPathCreateMutableCopy(CGPathRef path);

COREGRAPHICS_EXPORT CGMutablePathRef CGPathCreateMutableCopyByTransformingPath(CGPathRef path,
const CGAffineTransform* transform) STUB_METHOD;
COREGRAPHICS_EXPORT CGMutablePathRef CGPathCreateMutableCopyByTransformingPath(CGPathRef path, const CGAffineTransform* transform);

COREGRAPHICS_EXPORT void CGPathRelease(CGPathRef path);
COREGRAPHICS_EXPORT CGPathRef CGPathRetain(CGPathRef path);
Expand Down Expand Up @@ -110,7 +109,7 @@ COREGRAPHICS_EXPORT void CGPathAddRect(CGMutablePathRef path, const CGAffineTran

COREGRAPHICS_EXPORT void CGPathAddRects(CGMutablePathRef path, const CGAffineTransform* m, const CGRect* rects, size_t count) STUB_METHOD;
COREGRAPHICS_EXPORT void CGPathAddRoundedRect(
CGMutablePathRef path, const CGAffineTransform* transform, CGRect rect, CGFloat cornerWidth, CGFloat cornerHeight) STUB_METHOD;
CGMutablePathRef path, const CGAffineTransform* transform, CGRect rect, CGFloat cornerWidth, CGFloat cornerHeight);
COREGRAPHICS_EXPORT void CGPathApply(CGPathRef path, void* info, CGPathApplierFunction function);

COREGRAPHICS_EXPORT void CGPathMoveToPoint(CGMutablePathRef path, const CGAffineTransform* m, CGFloat x, CGFloat y);
Expand Down
24 changes: 12 additions & 12 deletions tests/unittests/CoreGraphics.Drawing/CGPathDrawingTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#include "DrawingTest.h"

DISABLED_DRAW_TEST_F(CGPath, AddCurveToPoint, UIKitMimicTest) {
DRAW_TEST_F(CGPath, AddCurveToPoint, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

Expand Down Expand Up @@ -58,7 +58,7 @@ DISABLED_DRAW_TEST_F(CGPath, AddEllipse, UIKitMimicTest) {
CGPathRelease(thepath);
}

DISABLED_DRAW_TEST_F(CGPath, AddLineToPoint, UIKitMimicTest) {
DRAW_TEST_F(CGPath, AddLineToPoint, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

Expand All @@ -84,7 +84,7 @@ DISABLED_DRAW_TEST_F(CGPath, AddLineToPoint, UIKitMimicTest) {
CGPathRelease(thepath);
}

DISABLED_DRAW_TEST_F(CGPath, AddPath, UIKitMimicTest) {
DRAW_TEST_F(CGPath, AddPath, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

Expand Down Expand Up @@ -116,7 +116,7 @@ DISABLED_DRAW_TEST_F(CGPath, AddPath, UIKitMimicTest) {
CGPathRelease(theSecondPath);
}

DISABLED_DRAW_TEST_F(CGPath, AddQuadCurveToPoint, UIKitMimicTest) {
DRAW_TEST_F(CGPath, AddQuadCurveToPoint, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

Expand All @@ -141,7 +141,7 @@ DISABLED_DRAW_TEST_F(CGPath, AddQuadCurveToPoint, UIKitMimicTest) {
CGPathRelease(thePath);
}

DISABLED_DRAW_TEST_F(CGPath, AddRect, UIKitMimicTest) {
DRAW_TEST_F(CGPath, AddRect, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

Expand All @@ -159,7 +159,7 @@ DISABLED_DRAW_TEST_F(CGPath, AddRect, UIKitMimicTest) {
CGPathRelease(thePath);
}

DISABLED_DRAW_TEST_F(CGPath, Apply, UIKitMimicTest) {
DRAW_TEST_F(CGPath, Apply, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

Expand Down Expand Up @@ -196,7 +196,7 @@ DISABLED_DRAW_TEST_F(CGPath, Apply, UIKitMimicTest) {
CGPathRelease(thepath);
}

DISABLED_DRAW_TEST_F(CGPath, CloseSubpath, UIKitMimicTest) {
DRAW_TEST_F(CGPath, CloseSubpath, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

Expand All @@ -223,7 +223,7 @@ DISABLED_DRAW_TEST_F(CGPath, CloseSubpath, UIKitMimicTest) {
CGPathRelease(thePath);
}

DISABLED_DRAW_TEST_F(CGPath, GetBoundingBox, UIKitMimicTest) {
DRAW_TEST_F(CGPath, GetBoundingBox, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();

Expand Down Expand Up @@ -261,7 +261,7 @@ static void CGPathApplyCallback(void* context, const CGPathElement* element) {
CGContextStrokePath((CGContextRef)context);
}

DISABLED_DRAW_TEST_F(CGPath, PathApplyDraw, UIKitMimicTest) {
DRAW_TEST_F(CGPath, PathApplyDraw, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
applyBounds = GetDrawingBounds();
CGFloat width = applyBounds.size.width;
Expand Down Expand Up @@ -319,7 +319,7 @@ static void CGPathControlPointCallback(void* context, const CGPathElement* eleme
}
}

DISABLED_DRAW_TEST_F(CGPath, PathApplyControlPointsQuadCurve, UIKitMimicTest) {
DRAW_TEST_F(CGPath, PathApplyControlPointsQuadCurve, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();
CGFloat width = bounds.size.width;
Expand All @@ -345,7 +345,7 @@ DISABLED_DRAW_TEST_F(CGPath, PathApplyControlPointsQuadCurve, UIKitMimicTest) {
CGPathRelease(thepath);
}

DISABLED_DRAW_TEST_F(CGPath, PathApplyControlPointsArcs, UIKitMimicTest) {
DRAW_TEST_F(CGPath, PathApplyControlPointsArcs, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();
CGFloat width = bounds.size.width;
Expand Down Expand Up @@ -381,7 +381,7 @@ DISABLED_DRAW_TEST_F(CGPath, PathApplyControlPointsArcs, UIKitMimicTest) {
CGPathRelease(thepath);
}

DISABLED_DRAW_TEST_F(CGPath, PathApplyControlPointsArcsSimple, UIKitMimicTest) {
DRAW_TEST_F(CGPath, PathApplyControlPointsArcsSimple, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
CGRect bounds = GetDrawingBounds();
CGFloat width = bounds.size.width;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 470fd9b

Please sign in to comment.