Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ad32c7d
Update RBPath callbacks
Kyle-Ye Dec 16, 2025
0b205a8
Update callbacks
Kyle-Ye Dec 16, 2025
3d6f76a
Update callbacks
Kyle-Ye Dec 16, 2025
dcda94e
Add ORBPath header
Kyle-Ye Dec 21, 2025
e539fdc
Add ORBPathPrivate.h
Kyle-Ye Dec 21, 2025
3458632
Update ORBPathStorageAppendPath
Kyle-Ye Dec 21, 2025
8f8de20
Fix ORBPath duplicate def
Kyle-Ye Dec 21, 2025
8ee84de
Update umbrella header
Kyle-Ye Dec 21, 2025
106a172
Add ORB_SWIFT_NAME annotations for path creation functions
Kyle-Ye Dec 21, 2025
e5742ad
Update PathStorage
Kyle-Ye Dec 21, 2025
683ce2a
Move ORBPathPrivate contents back to ORBPath.h
Kyle-Ye Dec 21, 2025
c3e1299
Add reserved2 field to ORBPathCallbacks at offset 0x50
Kyle-Ye Dec 21, 2025
11d2e7b
Add ORBRoundedCornerStyle enum to rounded rect path functions
Kyle-Ye Dec 21, 2025
6babd19
Add ORBPathCopyCGPath API with TODO implementation
Kyle-Ye Dec 21, 2025
346d569
Rename ORBPathElementType to ORBPathElement and update callback signa…
Kyle-Ye Dec 21, 2025
c2c1337
Add ORBPathContainsPoint and ORBPathContainsPoints APIs
Kyle-Ye Dec 21, 2025
7e9ba0f
Update PathTests
Kyle-Ye Dec 21, 2025
6cfa29b
Update ORBPathCallbacks
Kyle-Ye Dec 21, 2025
883fb0e
Update swift_name for global object
Kyle-Ye Dec 21, 2025
8a375f4
Add missing header include
Kyle-Ye Dec 21, 2025
0189eaf
Update callbacks
Kyle-Ye Dec 21, 2025
1dc931d
Fix ORBPathEmptyCallbacks
Kyle-Ye Dec 21, 2025
e169165
Complete ORBPathCallbacks implementation
Kyle-Ye Dec 21, 2025
3bb6875
Add ORBPathStorageApplyElements API
Kyle-Ye Dec 21, 2025
4973824
Update Callbacks API name to boundingRect
Kyle-Ye Dec 21, 2025
abbb946
Update RenderBox dependency
Kyle-Ye Dec 21, 2025
53a173c
[Optimize] Remove empty line
Kyle-Ye Dec 21, 2025
d29b4ce
Update build.sh
Kyle-Ye Dec 21, 2025
c8ce4f1
Fix CGRect issue
Kyle-Ye Dec 21, 2025
23ad601
Fix isEqual(to:)
Kyle-Ye Dec 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,12 @@ let renderBoxCondtion = envBoolValue("RENDERBOX", default: buildForDarwinPlatfor

var sharedCSettings: [CSetting] = [
.unsafeFlags(["-I", libSwiftPath], .when(platforms: .nonDarwinPlatforms)),
.unsafeFlags(["-fmodules"]),
// .unsafeFlags(["-fmodules"]),
.define("__COREFOUNDATION_FORSWIFTFOUNDATIONONLY__", to: "1", .when(platforms: .nonDarwinPlatforms)),
]
var sharedCxxSettings: [CXXSetting] = [
.unsafeFlags(["-I", libSwiftPath], .when(platforms: .nonDarwinPlatforms)),
.unsafeFlags(["-fcxx-modules"]),
// .unsafeFlags(["-fcxx-modules"]),
.define("__COREFOUNDATION_FORSWIFTFOUNDATIONONLY__", to: "1", .when(platforms: .nonDarwinPlatforms)),
]
var sharedSwiftSettings: [SwiftSetting] = [
Expand Down
6 changes: 6 additions & 0 deletions Scripts/build.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@ OPENRENDERBOX_ROOT="$(dirname $(dirname $(filepath $0)))"

cd $OPENRENDERBOX_ROOT

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

swift build
138 changes: 135 additions & 3 deletions Sources/OpenRenderBox/Path/ORBPath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,144 @@
// Created by Kyle on 2025/3/25.
//

#include <OpenRenderBox/ORBPathStorage.h>
#include <OpenRenderBox/ORBPath.h>
#include <OpenRenderBox/ORBPathCallbacks.h>

// Empty path callbacks (all null) - C++ internal linkage
static const ORBPathCallbacks empty_path_callbacks = {
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
};

// Empty path (storage = null)
const ORBPath ORBPathEmpty = {
nullptr,
&empty_path_callbacks,
};

// Null path (storage = 0x1)
const ORBPath ORBPathNull = {
reinterpret_cast<ORBPathStorage *>(0x1),
&empty_path_callbacks,
};

void ORBPathRetain(ORBPath path) {
// TODO
auto retain = path.callbacks->retain;
if (retain != nullptr) {
retain(&path);
}
}

void ORBPathRelease(ORBPath path) {
// TODO
auto release = path.callbacks->release;
if (release != nullptr) {
release(&path);
}
}

#if ORB_TARGET_OS_DARWIN

// MARK: - Path Creation

// TODO: TO be implemented natively

ORBPath ORBPathMakeWithCGPath(CGPathRef cgPath) {
if (cgPath == nullptr) {
return ORBPathNull;
}
CFRetain(cgPath);
return ORBPath {
reinterpret_cast<ORBPathStorage *>(const_cast<CGPath *>(cgPath)),
&ORBPathCGPathCallbacks,
};
}

ORBPath ORBPathMakeRect(CGRect rect, const CGAffineTransform *transform) {
CGPathRef cgPath = CGPathCreateWithRect(rect, transform);
ORBPath path = {
reinterpret_cast<ORBPathStorage *>(const_cast<CGPath *>(cgPath)),
&ORBPathCGPathCallbacks,
};
return path;
}

ORBPath ORBPathMakeEllipse(CGRect rect, const CGAffineTransform *transform) {
CGPathRef cgPath = CGPathCreateWithEllipseInRect(rect, transform);
ORBPath path = {
reinterpret_cast<ORBPathStorage *>(const_cast<CGPath *>(cgPath)),
&ORBPathCGPathCallbacks,
};
return path;
}

ORBPath ORBPathMakeRoundedRect(CGRect rect, CGFloat cornerWidth, CGFloat cornerHeight, ORBPathRoundedCornerStyle style, const CGAffineTransform *transform) {
// TODO: Handle ORBRoundedCornerStyleContinuous with custom bezier curves
CGPathRef cgPath = CGPathCreateWithRoundedRect(rect, cornerWidth, cornerHeight, transform);
ORBPath path = {
reinterpret_cast<ORBPathStorage *>(const_cast<CGPath *>(cgPath)),
&ORBPathCGPathCallbacks,
};
return path;
}

ORBPath ORBPathMakeUnevenRoundedRect(CGRect rect, CGFloat topLeftRadius, CGFloat bottomLeftRadius, CGFloat bottomRightRadius, CGFloat topRightRadius, ORBPathRoundedCornerStyle style, const CGAffineTransform *transform) {
// TODO: Handle ORBRoundedCornerStyleContinuous with custom bezier curves
CGMutablePathRef cgPath = CGPathCreateMutable();

CGFloat minX = CGRectGetMinX(rect);
CGFloat minY = CGRectGetMinY(rect);
CGFloat maxX = CGRectGetMaxX(rect);
CGFloat maxY = CGRectGetMaxY(rect);

// Start at top-left corner (after the rounded corner)
CGPathMoveToPoint(cgPath, transform, minX + topLeftRadius, minY);

// Top edge and top-right corner
CGPathAddLineToPoint(cgPath, transform, maxX - topRightRadius, minY);
CGPathAddArc(cgPath, transform, maxX - topRightRadius, minY + topRightRadius, topRightRadius, -M_PI_2, 0, false);

// Right edge and bottom-right corner
CGPathAddLineToPoint(cgPath, transform, maxX, maxY - bottomRightRadius);
CGPathAddArc(cgPath, transform, maxX - bottomRightRadius, maxY - bottomRightRadius, bottomRightRadius, 0, M_PI_2, false);

// Bottom edge and bottom-left corner
CGPathAddLineToPoint(cgPath, transform, minX + bottomLeftRadius, maxY);
CGPathAddArc(cgPath, transform, minX + bottomLeftRadius, maxY - bottomLeftRadius, bottomLeftRadius, M_PI_2, M_PI, false);

// Left edge and top-left corner
CGPathAddLineToPoint(cgPath, transform, minX, minY + topLeftRadius);
CGPathAddArc(cgPath, transform, minX + topLeftRadius, minY + topLeftRadius, topLeftRadius, M_PI, M_PI + M_PI_2, false);

CGPathCloseSubpath(cgPath);

ORBPath path = {
reinterpret_cast<ORBPathStorage *>(cgPath),
&ORBPathCGPathCallbacks,
};
return path;
}

CGPathRef ORBPathCopyCGPath(ORBPath path) {
// TODO: Return a retained copy of the CGPath
return nullptr;
}

bool ORBPathContainsPoint(ORBPath path, CGPoint point, bool eoFill) {
return ORBPathContainsPoints(path, 1, &point, eoFill, nullptr);
}

bool ORBPathContainsPoints(ORBPath path, uint64_t count, const CGPoint *points, bool eoFill, const CGAffineTransform *transform) {
// TODO: Implement point containment testing with winding rule
return false;
}

#endif /* ORB_TARGET_OS_DARWIN */
75 changes: 75 additions & 0 deletions Sources/OpenRenderBox/Path/ORBPathCallbacks.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//
// ORBPathCallbacks.cpp
// OpenRenderBox
//
// Audited for 6.5.1
// Status: Complete

#include <OpenRenderBox/ORBPathCallbacks.h>
#include <OpenRenderBoxCxx/Util/assert.hpp>

#if ORB_TARGET_OS_DARWIN

CG_EXTERN size_t CGPathGetNumberOfPoints(CGPathRef cg_nullable path);
CG_EXTERN size_t CGPathGetNumberOfElements(CGPathRef cg_nullable path);
typedef void (^CGPathApplyBlock2)(const CGPathElement * element, bool *stop);
CG_EXTERN void CGPathApplyWithBlock2(CGPathRef path, CGPathApplyBlock2 CF_NOESCAPE block);

namespace {
uint32_t cgpath_bezier_order(CGPathRef cgPath) {
size_t pointsCount = CGPathGetNumberOfPoints(cgPath);
size_t elementsCount = CGPathGetNumberOfElements(cgPath);
if (pointsCount > elementsCount) { return 3; }
if (pointsCount != 3 || elementsCount != 3) { return 1; }
bool hasCurve = false;
CGPathApply(cgPath, &hasCurve, [](void *info, const CGPathElement *element) {
if (element->type == kCGPathElementAddQuadCurveToPoint
|| element->type == kCGPathElementAddCurveToPoint) {
*static_cast<bool*>(info) = true;
}
});
return hasCurve ? 3 : 1;
}
}

const ORBPathCallbacks ORBPathCGPathCallbacks = {
nullptr,
CFRetain,
CFRelease,
+[](const void *object, void *info, ORBPathApplyCallback callback) -> bool {
CGPathRef cgPath = reinterpret_cast<CGPathRef>(object);
__block bool shouldStop = false;
CGPathApplyWithBlock2(cgPath, ^(const CGPathElement *element, bool *stop) {
bool result = callback(info,
(ORBPathElement)element->type,
(CGFloat *)element->points,
nullptr);
if (!result) {
*stop = true;
shouldStop = true;
}
});
return !shouldStop;
},
+[](const void *object, const void *otherObject) -> bool {
return CGPathEqualToPath(static_cast<CGPathRef>(object), static_cast<CGPathRef>(otherObject));
},
+[](const void *object) -> bool {
return CGPathIsEmpty(static_cast<CGPathRef>(object));
},
+[](const void *object) -> bool {
return false;
},
+[](const void *object) -> uint32_t {
return cgpath_bezier_order(static_cast<CGPathRef>(object));
},
+[](const void *object) -> CGRect {
return CGPathGetPathBoundingBox(static_cast<CGPathRef>(object));
},
+[](const void *object) -> CGPathRef {
return static_cast<CGPathRef>(object);
},
nullptr,
};

#endif /* ORB_TARGET_OS_DARWIN */
12 changes: 11 additions & 1 deletion Sources/OpenRenderBox/Path/ORBPathStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,17 @@ void ORBPathStorageClear(ORBPathStorageRef storage) {
storage->storage.clear();
}

// ...
bool ORBPathStorageAppendElement(ORBPathStorageRef storage, ORBPathElement element, double const * points, const void * userInfo) {
precondition_failure("TODO");
}

void ORBPathStorageAppendPath(ORBPathStorageRef storage, ORBPath path) {
precondition_failure("TODO");
}

void ORBPathStorageApplyElements(ORBPathStorageRef, void *info, ORBPathApplyCallback callback) {
precondition_failure("TODO");
}

bool ORBPathStorageIsEmpty(ORBPathStorageRef storage) {
return storage->storage.isEmpty();
Expand Down
29 changes: 27 additions & 2 deletions Sources/OpenRenderBox/Path/PathStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,24 @@
#include <OpenRenderBoxCxx/Path/PathStorage.hpp>
#include <OpenRenderBoxCxx/Util/assert.hpp>

#if ORB_TARGET_OS_DARWIN
#include <CoreGraphics/CoreGraphics.h>
#endif

namespace ORB {
namespace Path {
atomic_long Storage::_last_identifier;

Storage::Storage(uint32_t capacity) {
_unknown = nullptr;
if (capacity <= 63) {
precondition_failure("invalid capacity");
}
uint32_t cappedCapacity = fmin(capacity - 16, 4095);
_flags = StorageFlags().withCapacity(cappedCapacity);
_identifier = get_identifier();
}

Storage::Storage(uint32_t capacity, const Storage &storage): Storage(capacity) {
uint32_t originalCapity = flags().capacity();
StorageFlags sourceFlags = storage.flags();
Expand Down Expand Up @@ -44,8 +58,8 @@ Storage::Storage(uint32_t capacity, const Storage &storage): Storage(capacity) {
}

Storage::~Storage() {
if (_unknonw != nullptr) {
_unknonw = nullptr;
if (_unknown != nullptr) {
_unknown = nullptr;
// TODO
}
}
Expand All @@ -59,5 +73,16 @@ void Storage::clear() {
// TODO
}

void * Storage::cgpath() const ORB_NOEXCEPT {
if (_flags.isInline()) {
return nullptr;
}
if (_cached_cgPath != nullptr) {
return _cached_cgPath;
}
// TODO: Create CGPath via RBPathCopyCGPath
return nullptr;
}

} /* Path */
} /* ORB */
2 changes: 1 addition & 1 deletion Sources/OpenRenderBox/Util/assert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ void precondition_failure(const char *format, ...) {
os_log_error(error_log(), "precondition failure: %s", s);
#endif /* ORB_TARGET_OS_DARWIN */
if (error_message == nullptr) {
asprintf(&error_message, "OpenGraph precondition failure: %s.\n", s);
asprintf(&error_message, "OpenRenderBox precondition failure: %s.\n", s);
}
free(s);
}
Expand Down
Loading