Skip to content

Commit 9000acb

Browse files
authored
Add ORBPath, ORBPathCallbacks, and ORBPathStorage APIs (#12)
1 parent ebed504 commit 9000acb

File tree

21 files changed

+762
-41
lines changed

21 files changed

+762
-41
lines changed

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,12 @@ let renderBoxCondtion = envBoolValue("RENDERBOX", default: buildForDarwinPlatfor
159159

160160
var sharedCSettings: [CSetting] = [
161161
.unsafeFlags(["-I", libSwiftPath], .when(platforms: .nonDarwinPlatforms)),
162-
.unsafeFlags(["-fmodules"]),
162+
// .unsafeFlags(["-fmodules"]),
163163
.define("__COREFOUNDATION_FORSWIFTFOUNDATIONONLY__", to: "1", .when(platforms: .nonDarwinPlatforms)),
164164
]
165165
var sharedCxxSettings: [CXXSetting] = [
166166
.unsafeFlags(["-I", libSwiftPath], .when(platforms: .nonDarwinPlatforms)),
167-
.unsafeFlags(["-fcxx-modules"]),
167+
// .unsafeFlags(["-fcxx-modules"]),
168168
.define("__COREFOUNDATION_FORSWIFTFOUNDATIONONLY__", to: "1", .when(platforms: .nonDarwinPlatforms)),
169169
]
170170
var sharedSwiftSettings: [SwiftSetting] = [

Scripts/build.sh

100644100755
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,10 @@ OPENRENDERBOX_ROOT="$(dirname $(dirname $(filepath $0)))"
99

1010
cd $OPENRENDERBOX_ROOT
1111

12+
# Set OPENRENDERBOX_LIB_SWIFT_PATH on Linux if swiftly is installed
13+
if [[ "$(uname)" == "Linux" ]] && command -v swiftly &> /dev/null && [[ -z "$OPENRENDERBOX_LIB_SWIFT_PATH" ]]; then
14+
export OPENRENDERBOX_LIB_SWIFT_PATH="$(swiftly use --print-location)/usr/lib/swift"
15+
echo "Set OPENRENDERBOX_LIB_SWIFT_PATH=$OPENRENDERBOX_LIB_SWIFT_PATH"
16+
fi
17+
1218
swift build

Sources/OpenRenderBox/Path/ORBPath.cpp

Lines changed: 135 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,144 @@
55
// Created by Kyle on 2025/3/25.
66
//
77

8-
#include <OpenRenderBox/ORBPathStorage.h>
8+
#include <OpenRenderBox/ORBPath.h>
9+
#include <OpenRenderBox/ORBPathCallbacks.h>
10+
11+
// Empty path callbacks (all null) - C++ internal linkage
12+
static const ORBPathCallbacks empty_path_callbacks = {
13+
nullptr,
14+
nullptr,
15+
nullptr,
16+
nullptr,
17+
nullptr,
18+
nullptr,
19+
nullptr,
20+
nullptr,
21+
nullptr,
22+
nullptr,
23+
nullptr,
24+
};
25+
26+
// Empty path (storage = null)
27+
const ORBPath ORBPathEmpty = {
28+
nullptr,
29+
&empty_path_callbacks,
30+
};
31+
32+
// Null path (storage = 0x1)
33+
const ORBPath ORBPathNull = {
34+
reinterpret_cast<ORBPathStorage *>(0x1),
35+
&empty_path_callbacks,
36+
};
937

1038
void ORBPathRetain(ORBPath path) {
11-
// TODO
39+
auto retain = path.callbacks->retain;
40+
if (retain != nullptr) {
41+
retain(&path);
42+
}
1243
}
1344

1445
void ORBPathRelease(ORBPath path) {
15-
// TODO
46+
auto release = path.callbacks->release;
47+
if (release != nullptr) {
48+
release(&path);
49+
}
50+
}
51+
52+
#if ORB_TARGET_OS_DARWIN
53+
54+
// MARK: - Path Creation
55+
56+
// TODO: TO be implemented natively
57+
58+
ORBPath ORBPathMakeWithCGPath(CGPathRef cgPath) {
59+
if (cgPath == nullptr) {
60+
return ORBPathNull;
61+
}
62+
CFRetain(cgPath);
63+
return ORBPath {
64+
reinterpret_cast<ORBPathStorage *>(const_cast<CGPath *>(cgPath)),
65+
&ORBPathCGPathCallbacks,
66+
};
1667
}
68+
69+
ORBPath ORBPathMakeRect(CGRect rect, const CGAffineTransform *transform) {
70+
CGPathRef cgPath = CGPathCreateWithRect(rect, transform);
71+
ORBPath path = {
72+
reinterpret_cast<ORBPathStorage *>(const_cast<CGPath *>(cgPath)),
73+
&ORBPathCGPathCallbacks,
74+
};
75+
return path;
76+
}
77+
78+
ORBPath ORBPathMakeEllipse(CGRect rect, const CGAffineTransform *transform) {
79+
CGPathRef cgPath = CGPathCreateWithEllipseInRect(rect, transform);
80+
ORBPath path = {
81+
reinterpret_cast<ORBPathStorage *>(const_cast<CGPath *>(cgPath)),
82+
&ORBPathCGPathCallbacks,
83+
};
84+
return path;
85+
}
86+
87+
ORBPath ORBPathMakeRoundedRect(CGRect rect, CGFloat cornerWidth, CGFloat cornerHeight, ORBPathRoundedCornerStyle style, const CGAffineTransform *transform) {
88+
// TODO: Handle ORBRoundedCornerStyleContinuous with custom bezier curves
89+
CGPathRef cgPath = CGPathCreateWithRoundedRect(rect, cornerWidth, cornerHeight, transform);
90+
ORBPath path = {
91+
reinterpret_cast<ORBPathStorage *>(const_cast<CGPath *>(cgPath)),
92+
&ORBPathCGPathCallbacks,
93+
};
94+
return path;
95+
}
96+
97+
ORBPath ORBPathMakeUnevenRoundedRect(CGRect rect, CGFloat topLeftRadius, CGFloat bottomLeftRadius, CGFloat bottomRightRadius, CGFloat topRightRadius, ORBPathRoundedCornerStyle style, const CGAffineTransform *transform) {
98+
// TODO: Handle ORBRoundedCornerStyleContinuous with custom bezier curves
99+
CGMutablePathRef cgPath = CGPathCreateMutable();
100+
101+
CGFloat minX = CGRectGetMinX(rect);
102+
CGFloat minY = CGRectGetMinY(rect);
103+
CGFloat maxX = CGRectGetMaxX(rect);
104+
CGFloat maxY = CGRectGetMaxY(rect);
105+
106+
// Start at top-left corner (after the rounded corner)
107+
CGPathMoveToPoint(cgPath, transform, minX + topLeftRadius, minY);
108+
109+
// Top edge and top-right corner
110+
CGPathAddLineToPoint(cgPath, transform, maxX - topRightRadius, minY);
111+
CGPathAddArc(cgPath, transform, maxX - topRightRadius, minY + topRightRadius, topRightRadius, -M_PI_2, 0, false);
112+
113+
// Right edge and bottom-right corner
114+
CGPathAddLineToPoint(cgPath, transform, maxX, maxY - bottomRightRadius);
115+
CGPathAddArc(cgPath, transform, maxX - bottomRightRadius, maxY - bottomRightRadius, bottomRightRadius, 0, M_PI_2, false);
116+
117+
// Bottom edge and bottom-left corner
118+
CGPathAddLineToPoint(cgPath, transform, minX + bottomLeftRadius, maxY);
119+
CGPathAddArc(cgPath, transform, minX + bottomLeftRadius, maxY - bottomLeftRadius, bottomLeftRadius, M_PI_2, M_PI, false);
120+
121+
// Left edge and top-left corner
122+
CGPathAddLineToPoint(cgPath, transform, minX, minY + topLeftRadius);
123+
CGPathAddArc(cgPath, transform, minX + topLeftRadius, minY + topLeftRadius, topLeftRadius, M_PI, M_PI + M_PI_2, false);
124+
125+
CGPathCloseSubpath(cgPath);
126+
127+
ORBPath path = {
128+
reinterpret_cast<ORBPathStorage *>(cgPath),
129+
&ORBPathCGPathCallbacks,
130+
};
131+
return path;
132+
}
133+
134+
CGPathRef ORBPathCopyCGPath(ORBPath path) {
135+
// TODO: Return a retained copy of the CGPath
136+
return nullptr;
137+
}
138+
139+
bool ORBPathContainsPoint(ORBPath path, CGPoint point, bool eoFill) {
140+
return ORBPathContainsPoints(path, 1, &point, eoFill, nullptr);
141+
}
142+
143+
bool ORBPathContainsPoints(ORBPath path, uint64_t count, const CGPoint *points, bool eoFill, const CGAffineTransform *transform) {
144+
// TODO: Implement point containment testing with winding rule
145+
return false;
146+
}
147+
148+
#endif /* ORB_TARGET_OS_DARWIN */
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//
2+
// ORBPathCallbacks.cpp
3+
// OpenRenderBox
4+
//
5+
// Audited for 6.5.1
6+
// Status: Complete
7+
8+
#include <OpenRenderBox/ORBPathCallbacks.h>
9+
#include <OpenRenderBoxCxx/Util/assert.hpp>
10+
11+
#if ORB_TARGET_OS_DARWIN
12+
13+
CG_EXTERN size_t CGPathGetNumberOfPoints(CGPathRef cg_nullable path);
14+
CG_EXTERN size_t CGPathGetNumberOfElements(CGPathRef cg_nullable path);
15+
typedef void (^CGPathApplyBlock2)(const CGPathElement * element, bool *stop);
16+
CG_EXTERN void CGPathApplyWithBlock2(CGPathRef path, CGPathApplyBlock2 CF_NOESCAPE block);
17+
18+
namespace {
19+
uint32_t cgpath_bezier_order(CGPathRef cgPath) {
20+
size_t pointsCount = CGPathGetNumberOfPoints(cgPath);
21+
size_t elementsCount = CGPathGetNumberOfElements(cgPath);
22+
if (pointsCount > elementsCount) { return 3; }
23+
if (pointsCount != 3 || elementsCount != 3) { return 1; }
24+
bool hasCurve = false;
25+
CGPathApply(cgPath, &hasCurve, [](void *info, const CGPathElement *element) {
26+
if (element->type == kCGPathElementAddQuadCurveToPoint
27+
|| element->type == kCGPathElementAddCurveToPoint) {
28+
*static_cast<bool*>(info) = true;
29+
}
30+
});
31+
return hasCurve ? 3 : 1;
32+
}
33+
}
34+
35+
const ORBPathCallbacks ORBPathCGPathCallbacks = {
36+
nullptr,
37+
CFRetain,
38+
CFRelease,
39+
+[](const void *object, void *info, ORBPathApplyCallback callback) -> bool {
40+
CGPathRef cgPath = reinterpret_cast<CGPathRef>(object);
41+
__block bool shouldStop = false;
42+
CGPathApplyWithBlock2(cgPath, ^(const CGPathElement *element, bool *stop) {
43+
bool result = callback(info,
44+
(ORBPathElement)element->type,
45+
(CGFloat *)element->points,
46+
nullptr);
47+
if (!result) {
48+
*stop = true;
49+
shouldStop = true;
50+
}
51+
});
52+
return !shouldStop;
53+
},
54+
+[](const void *object, const void *otherObject) -> bool {
55+
return CGPathEqualToPath(static_cast<CGPathRef>(object), static_cast<CGPathRef>(otherObject));
56+
},
57+
+[](const void *object) -> bool {
58+
return CGPathIsEmpty(static_cast<CGPathRef>(object));
59+
},
60+
+[](const void *object) -> bool {
61+
return false;
62+
},
63+
+[](const void *object) -> uint32_t {
64+
return cgpath_bezier_order(static_cast<CGPathRef>(object));
65+
},
66+
+[](const void *object) -> CGRect {
67+
return CGPathGetPathBoundingBox(static_cast<CGPathRef>(object));
68+
},
69+
+[](const void *object) -> CGPathRef {
70+
return static_cast<CGPathRef>(object);
71+
},
72+
nullptr,
73+
};
74+
75+
#endif /* ORB_TARGET_OS_DARWIN */

Sources/OpenRenderBox/Path/ORBPathStorage.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,17 @@ void ORBPathStorageClear(ORBPathStorageRef storage) {
2424
storage->storage.clear();
2525
}
2626

27-
// ...
27+
bool ORBPathStorageAppendElement(ORBPathStorageRef storage, ORBPathElement element, double const * points, const void * userInfo) {
28+
precondition_failure("TODO");
29+
}
30+
31+
void ORBPathStorageAppendPath(ORBPathStorageRef storage, ORBPath path) {
32+
precondition_failure("TODO");
33+
}
34+
35+
void ORBPathStorageApplyElements(ORBPathStorageRef, void *info, ORBPathApplyCallback callback) {
36+
precondition_failure("TODO");
37+
}
2838

2939
bool ORBPathStorageIsEmpty(ORBPathStorageRef storage) {
3040
return storage->storage.isEmpty();

Sources/OpenRenderBox/Path/PathStorage.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,24 @@
55
#include <OpenRenderBoxCxx/Path/PathStorage.hpp>
66
#include <OpenRenderBoxCxx/Util/assert.hpp>
77

8+
#if ORB_TARGET_OS_DARWIN
9+
#include <CoreGraphics/CoreGraphics.h>
10+
#endif
11+
812
namespace ORB {
913
namespace Path {
1014
atomic_long Storage::_last_identifier;
1115

16+
Storage::Storage(uint32_t capacity) {
17+
_unknown = nullptr;
18+
if (capacity <= 63) {
19+
precondition_failure("invalid capacity");
20+
}
21+
uint32_t cappedCapacity = fmin(capacity - 16, 4095);
22+
_flags = StorageFlags().withCapacity(cappedCapacity);
23+
_identifier = get_identifier();
24+
}
25+
1226
Storage::Storage(uint32_t capacity, const Storage &storage): Storage(capacity) {
1327
uint32_t originalCapity = flags().capacity();
1428
StorageFlags sourceFlags = storage.flags();
@@ -44,8 +58,8 @@ Storage::Storage(uint32_t capacity, const Storage &storage): Storage(capacity) {
4458
}
4559

4660
Storage::~Storage() {
47-
if (_unknonw != nullptr) {
48-
_unknonw = nullptr;
61+
if (_unknown != nullptr) {
62+
_unknown = nullptr;
4963
// TODO
5064
}
5165
}
@@ -59,5 +73,16 @@ void Storage::clear() {
5973
// TODO
6074
}
6175

76+
void * Storage::cgpath() const ORB_NOEXCEPT {
77+
if (_flags.isInline()) {
78+
return nullptr;
79+
}
80+
if (_cached_cgPath != nullptr) {
81+
return _cached_cgPath;
82+
}
83+
// TODO: Create CGPath via RBPathCopyCGPath
84+
return nullptr;
85+
}
86+
6287
} /* Path */
6388
} /* ORB */

Sources/OpenRenderBox/Util/assert.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ void precondition_failure(const char *format, ...) {
1919
os_log_error(error_log(), "precondition failure: %s", s);
2020
#endif /* ORB_TARGET_OS_DARWIN */
2121
if (error_message == nullptr) {
22-
asprintf(&error_message, "OpenGraph precondition failure: %s.\n", s);
22+
asprintf(&error_message, "OpenRenderBox precondition failure: %s.\n", s);
2323
}
2424
free(s);
2525
}

0 commit comments

Comments
 (0)