Skip to content

Commit

Permalink
Implement CGPathApply (#1507)
Browse files Browse the repository at this point in the history
* CGPathApply

* Curve Apply Test Page

* Update tests, address CR feedback, move geometry sink to individual file.

* Addressing CR Feedback.

* Fix no-op on cgpathapply when path is null.

* Address CR Feedback

* Single element point arrays are now just a variable

* Ignoring clang warnings on ARM builds for WRL helpers.

* Replace lost ID from last commit.
  • Loading branch information
MSFTFox authored Dec 13, 2016
1 parent 3176d73 commit 3b776a3
Show file tree
Hide file tree
Showing 27 changed files with 497 additions and 142 deletions.
42 changes: 12 additions & 30 deletions Frameworks/CoreGraphics/CGPath.mm
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#import "CGPathInternal.h"

#include <COMIncludes.h>
#import <wrl/client.h>
#import <WRLHelpers.h>
#include <COMIncludes_End.h>

#import <CFCPPBase.h>
Expand Down Expand Up @@ -241,7 +241,7 @@ CGPathRef CGPathCreateCopy(CGPathRef path) {
}

/**
@Status Interoperable
@Status Interoperable
*/
CGMutablePathRef CGPathCreateMutableCopy(CGPathRef path) {
RETURN_NULL_IF(!path);
Expand Down Expand Up @@ -525,7 +525,7 @@ void CGPathCloseSubpath(CGMutablePathRef path) {
}

/**
@Status Interoperable
@Status Interoperable
*/
CGRect CGPathGetBoundingBox(CGPathRef path) {
if (path == NULL) {
Expand All @@ -546,8 +546,7 @@ CGRect CGPathGetBoundingBox(CGPathRef path) {
}

/**
@Status Interoperable
@Status Interoperable
*/
bool CGPathIsEmpty(CGPathRef path) {
if (path == NULL) {
Expand Down Expand Up @@ -582,7 +581,7 @@ CGPathRef CGPathRetain(CGPathRef path) {
}

/**
@Status Interoperable
@Status Interoperable
*/
void CGPathAddQuadCurveToPoint(CGMutablePathRef path, const CGAffineTransform* transform, CGFloat cpx, CGFloat cpy, CGFloat x, CGFloat y) {
RETURN_IF(!path);
Expand All @@ -607,7 +606,7 @@ void CGPathAddQuadCurveToPoint(CGMutablePathRef path, const CGAffineTransform* t
}

/**
@Status Interoperable
@Status Interoperable
*/
void CGPathAddCurveToPoint(CGMutablePathRef path,
const CGAffineTransform* transform,
Expand Down Expand Up @@ -704,32 +703,15 @@ void CGPathAddRoundedRect(
FAIL_FAST_IF_FAILED(path->AddGeometryToPathWithTransformation(rectangleGeometry.Get(), transform));
}

int _CGPathPointCountForElementType(CGPathElementType type) {
int pointCount = 0;

switch (type) {
case kCGPathElementMoveToPoint:
case kCGPathElementAddLineToPoint:
pointCount = 1;
break;
case kCGPathElementAddQuadCurveToPoint:
pointCount = 2;
break;
case kCGPathElementAddCurveToPoint:
pointCount = 3;
break;
case kCGPathElementCloseSubpath:
pointCount = 0;
break;
}
return pointCount;
}

/**
@Status Stub
@Status Caveat
@Notes Quadratic Bezier Curves are simplified into Cubic Bezier curves. Control point approximation for arcs differs from reference
platform. TODO 1419 : Fix figure logic in D2D to eliminate extra start point callbacks.
*/
void CGPathApply(CGPathRef path, void* info, CGPathApplierFunction function) {
UNIMPLEMENTED();
RETURN_IF(!path);
FAIL_FAST_IF_FAILED(path->ClosePath());
FAIL_FAST_IF_FAILED(_CGPathApplyInternal(path->GetPathGeometry().Get(), info, function));
}

/**
Expand Down
91 changes: 91 additions & 0 deletions Frameworks/CoreGraphics/D2DWrapper_CGPathApply.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//******************************************************************************
//
// Copyright (c) Microsoft. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//******************************************************************************

#import <CoreGraphics/D2DWrapper.h>

#import "CGPathInternal.h"

#include <COMIncludes.h>
#import <WRLHelpers.h>
#include <COMIncludes_End.h>

using namespace Microsoft::WRL;

// The CGPathApplySink is an implementation of the ID2D1SimplifiedGeometrySink. We use this sink to create a custom callback for each
// figure type of the path. This will let us call the CGPathApplierFunction provided to us automatically through the use of D2D APIs.
// This should only be used with CGPathApply as it is very specialized for this case only.
class _CGPathApplySink : public RuntimeClass<RuntimeClassFlags<RuntimeClassType::WinRtClassicComMix>, ID2D1SimplifiedGeometrySink> {
protected:
InspectableClass(L"Windows.Bridge.Direct2D._CGPathApplySink", TrustLevel::BaseTrust);

public:
_CGPathApplySink(_In_ void* info, _In_ CGPathApplierFunction function) : m_info(info), m_pathApplierFunction(function) {
}

STDMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT* beziers, UINT bezierCount) {
FAIL_FAST_IF_NULL(beziers);
for (UINT i = 0; i < bezierCount; ++i) {
CGPoint pathPoints[3] = { _D2DPointToCGPoint(beziers[i].point1),
_D2DPointToCGPoint(beziers[i].point2),
_D2DPointToCGPoint(beziers[i].point3) };
CGPathElement element = { kCGPathElementAddCurveToPoint, pathPoints };
m_pathApplierFunction(m_info, &element);
}
}

STDMETHOD_(void, AddLines)(const D2D1_POINT_2F* points, UINT pointsCount) {
FAIL_FAST_IF_NULL(points);
for (UINT i = 0; i < pointsCount; ++i) {
CGPoint pathPoint = _D2DPointToCGPoint(points[i]);

CGPathElement element = { kCGPathElementAddLineToPoint, &pathPoint };
m_pathApplierFunction(m_info, &element);
}
}

STDMETHOD_(void, BeginFigure)(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin) {
CGPoint pathPoint = _D2DPointToCGPoint(startPoint);

CGPathElement element = { kCGPathElementMoveToPoint, &pathPoint };
m_pathApplierFunction(m_info, &element);
}

// End Figure is empty as there is no expected callback for a figure ending, there is a callback strictly for a sub path being closed.
STDMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd) {
}

// This custom class is striclty for callbacks on figures.
STDMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode) {
}

// This custom class is striclty for callbacks on figures.
STDMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags) {
}

STDMETHOD(Close)() {
return S_OK;
}

private:
void* m_info;
CGPathApplierFunction m_pathApplierFunction;
};

HRESULT _CGPathApplyInternal(ID2D1PathGeometry* pathGeometry, void* info, CGPathApplierFunction function) {
ComPtr<_CGPathApplySink> sink = Make<_CGPathApplySink>(info, function);
RETURN_IF_FAILED(pathGeometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, D2D1::IdentityMatrix(), sink.Get()));
return S_OK;
}
18 changes: 18 additions & 0 deletions Frameworks/include/CGPathInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,28 @@
//
//******************************************************************************

#pragma once

#ifndef __CGPATHINTERNAL_H
#define __CGPATHINTERNAL_H

#include "CFBridgeBase.h"
#include "CoreGraphics/CGContext.h"
#include "CoreGraphics/CGPath.h"

#if defined __clang__

#pragma clang diagnostic push
#ifdef _M_ARM
// Disable 'invalid calling convention' warnings for __stdcall usage in ARM builds
#pragma clang diagnostic ignored "-Wignored-attributes"
#endif // _M_ARM

#endif // __clang__

#include <COMIncludes.h>
#include <d2d1.h>
#import <WRLHelpers.h>
#include <COMIncludes_End.h>

const int kCGPathMaxPointCount = 3;
Expand Down Expand Up @@ -56,5 +69,10 @@ struct CGPathElementInternal : CGPathElement {
typedef struct CGPathElementInternal CGPathElementInternal;

HRESULT _CGPathGetGeometry(CGPathRef path, ID2D1Geometry** pGeometry);
HRESULT _CGPathApplyInternal(ID2D1PathGeometry* pathGeometry, void* info, CGPathApplierFunction function);

#if defined __clang__
#pragma clang diagnostic pop
#endif

#endif
6 changes: 5 additions & 1 deletion Frameworks/include/CoreGraphics/D2DWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,17 @@ inline D2D_POINT_2F _CGPointToD2D_F(CGPoint point) {
return { point.x, point.y };
}

inline CGPoint _D2DPointToCGPoint(D2D_POINT_2F point) {
return { point.x, point.y };
}

inline CGRect _D2DRectToCGRect(D2D1_RECT_F rect) {
CGFloat x = rect.left;
CGFloat y = rect.top;
CGFloat width = rect.right - x;
CGFloat height = rect.bottom - y;

return CGRectMake(x, y, width, height);
return { { x, y }, { width, height } };
}

inline D2D1_MATRIX_3X2_F __CGAffineTransformToD2D_F(CGAffineTransform transform) {
Expand Down
3 changes: 2 additions & 1 deletion build/CoreGraphics/lib/CoreGraphicsLib.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
<ClangCompile Include="$(MSBuildThisFileDirectory)..\..\..\Frameworks\CoreGraphics\CGShading.mm" />
<ClangCompile Include="$(MSBuildThisFileDirectory)..\..\..\Frameworks\CoreGraphics\DWriteWrapper.mm" />
<ClangCompile Include="$(MSBuildThisFileDirectory)..\..\..\Frameworks\CoreGraphics\D2DWrapper.mm" />
<ClangCompile Include="$(MSBuildThisFileDirectory)..\..\..\Frameworks\CoreGraphics\D2DWrapper_CGPathApply.mm" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\..\Frameworks\include\CoreGraphics\DWriteWrapper.h" />
Expand Down Expand Up @@ -113,4 +114,4 @@
<ImportGroup Label="ExtensionTargets">
<Import Project="$(StarboardBasePath)\msvc\sdk-build.targets" />
</ImportGroup>
</Project>
</Project>
1 change: 1 addition & 0 deletions build/build.sln
Original file line number Diff line number Diff line change
Expand Up @@ -2084,6 +2084,7 @@ Global
{BF6F340B-4EFA-4594-A0A0-CC2CEC13C9BA} = {B6FC74CF-9B21-4B23-BBA2-B015641DD16F}
{CC5BF26B-322D-4E39-9555-39C77C1E70A4} = {E93B116D-5467-4B1F-8815-B6B81F81B6D0}
{E3D304DB-7308-4516-808C-EC33CCC69FCF} = {80B1F276-7F9E-408B-A526-B75B0252E848}
{5E329D85-040E-4DC9-BD3F-9BC105F2979A} = {52E0654B-3B43-4514-B48B-6BAE3E580A6F}
{D9DB2464-1EC3-4A9A-9D28-B4EB59502B53} = {91DDC4B7-AAED-4B75-AB06-16F6085052F9}
{91DDC4B7-AAED-4B75-AB06-16F6085052F9} = {5E329D85-040E-4DC9-BD3F-9BC105F2979A}
{8CE3A6C5-54B7-4B30-BC6C-5E1323FB8CC6} = {5E329D85-040E-4DC9-BD3F-9BC105F2979A}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\CGCatalog\CGPathAddQuadCurveToPointViewController.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\CGCatalog\CGPathAddRectViewController.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\CGCatalog\CGPathAddRoundedRectViewController.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\CGCatalog\CGPathApplyCurveViewController.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\CGCatalog\CGPathApplyViewController.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\CGCatalog\CGPathCloseSubpathViewController.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\CGCatalog\CGPathContainsPointViewController.h" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,8 @@
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\CGCatalog\CGPathAddRoundedRectViewController.h">
<Filter>CGCatalog\NewSamples</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\CGCatalog\CGPathApplyCurveViewController.h">
<Filter>CGCatalog\NewSamples</Filter>
</ClInclude>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,19 @@
</AppxManifest>
<Xml Include="default.rd.xml" />
<None Include="CGCatalog_TemporaryKey.pfx" />
<Image Include="..\..\CGCatalog\Resources\AddArc.png" />
<Image Include="..\..\CGCatalog\Resources\AddArcToPoint.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\AddArc.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\AddArcToPoint.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\AddCurveToPoint.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\AddElipseToRect.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\AddLineToPoint.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\AddPath.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\AddQuadCurveToPoint.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\CloseSubPath.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\GetBoundingBox.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\LogoAutodesk.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\PathAddRect.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\PathApply.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\RoundedRect.png" />
<Image Include="Assets\LockScreenLogo.scale-200.png" />
<Image Include="Assets\SplashScreen.scale-200.png" />
<Image Include="Assets\Square150x150Logo.scale-200.png" />
Expand All @@ -193,6 +204,7 @@
<ClangCompile Include="..\..\CGCatalog\CGPathAddArcToPointViewController.m" />
<ClangCompile Include="..\..\CGCatalog\CGPathAddArcViewController.m" />
<ClangCompile Include="..\..\CGCatalog\CGPathAddRoundedRectViewController.m" />
<ClangCompile Include="..\..\CGCatalog\CGPathApplyCurveViewController.m" />
<ClangCompile Include="..\..\CGCatalog\CGPathCloseSubpathViewController.m" />
<ClangCompile Include="..\..\CGCatalog\Samples\CGContextNewTestsController.m" />
<ClangCompile Include="..\..\CGCatalog\CGCRootViewController.m" />
Expand All @@ -219,20 +231,8 @@
<ClangCompile Include="..\..\CGCatalog\main.m" />
<ClangCompile Include="..\..\CGCatalog\CGPathGetBoundingBoxViewController.m" />
<ClangCompile Include="..\..\CGCatalog\CGPathAddElipseViewController.m" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\AddLineToPoint.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\PathApply.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\AddElipseToRect.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\AddQuadCurveToPoint.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\CloseSubPath.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\AddCurveToPoint.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\AddPath.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\LogoAutodesk.png" />
<StoryboardCompile Include="..\..\CGCatalog\Resources\Launch Screen.storyboard" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\GetBoundingBox.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\PathAddRect.png" />
<AssetCatalogCompile Include="..\..\CGCatalog\Resources\Assets.xcassets" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\GetBoundingBox.png" />
<SBResourceCopy Include="..\..\CGCatalog\Resources\CloseSubPath.png" />
<SBInfoPlistCopy Include="..\..\CGCatalog\Info.plist">
<ExcludedFromBuild Condition="'$(Configuration)'=='Debug'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)'=='Release'">false</ExcludedFromBuild>
Expand Down
Loading

0 comments on commit 3b776a3

Please sign in to comment.