From a279d2369f6d30cbb1b57d7bb641475ab1f34115 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 27 Dec 2025 10:34:55 +0800 Subject: [PATCH 1/9] Fix storage.cgpath --- .gitignore | 1 + Sources/OpenRenderBox/Path/ORBPathStorage.cpp | 3 +- Sources/OpenRenderBox/Path/PathStorage.cpp | 49 ++++++++++++++++--- .../include/OpenRenderBox/ORBBase.h | 2 +- .../include/OpenRenderBox/ORBPathStorage.h | 2 +- .../OpenRenderBoxCxx/Path/PathStorage.hpp | 33 ++++++++----- 6 files changed, 69 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 2b3eccb..92559ae 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ DerivedData/ .netrc .claude/ .rb_template/ +.augment/ diff --git a/Sources/OpenRenderBox/Path/ORBPathStorage.cpp b/Sources/OpenRenderBox/Path/ORBPathStorage.cpp index a8a42bb..85ffab6 100644 --- a/Sources/OpenRenderBox/Path/ORBPathStorage.cpp +++ b/Sources/OpenRenderBox/Path/ORBPathStorage.cpp @@ -59,6 +59,7 @@ CGRect ORBPathStorageGetBoundingRect(ORBPathStorageRef storage) { } CGPathRef ORBPathStorageGetCGPath(ORBPathStorageRef storage) { - precondition_failure("TODO"); + // FIXME + return storage->storage.cgpath(); } #endif diff --git a/Sources/OpenRenderBox/Path/PathStorage.cpp b/Sources/OpenRenderBox/Path/PathStorage.cpp index c75a81f..5a17492 100644 --- a/Sources/OpenRenderBox/Path/PathStorage.cpp +++ b/Sources/OpenRenderBox/Path/PathStorage.cpp @@ -2,6 +2,8 @@ // PathStorage.cpp // OpenRenderBox +#include +#include #include #include @@ -11,7 +13,7 @@ namespace ORB { namespace Path { -atomic_long Storage::_last_identifier; +atomic_uint Storage::_last_identifier; Storage::Storage(uint32_t capacity) { _unknown = nullptr; @@ -73,15 +75,48 @@ void Storage::clear() { // TODO } -void * Storage::cgpath() const ORB_NOEXCEPT { - if (_flags.isInline()) { +bool Storage::apply_elements(void *info, ORBPathApplyCallback callback) const ORB_NOEXCEPT { + // TODO: Implement element iteration + return true; +} + +CGPathRef Storage::cgpath() const ORB_NOEXCEPT { + if (flags().isInline()) { return nullptr; } - if (_cached_cgPath != nullptr) { - return _cached_cgPath; + CGPathRef cached = __atomic_load_n(&_cached_cgPath, __ATOMIC_SEQ_CST); + if (cached != nullptr) { + return cached; + } + static const ORBPathCallbacks callbacks = { + nullptr, + nullptr, + nullptr, + +[](const void *object, void *info, ORBPathApplyCallback callback) -> bool { + auto storage = reinterpret_cast(object); + return storage->apply_elements(info, callback); + }, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + }; + ORBPath path = { + const_cast(reinterpret_cast(this)), + &callbacks + }; + CGPathRef new_path = ORBPathCopyCGPath(path); + CGPathRef expected = nullptr; + if (__atomic_compare_exchange_n(&_cached_cgPath, &expected, new_path, + false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) { + return new_path; + } else { + CGPathRelease(new_path); + return expected; } - // TODO: Create CGPath via RBPathCopyCGPath - return nullptr; } } /* Path */ diff --git a/Sources/OpenRenderBox/include/OpenRenderBox/ORBBase.h b/Sources/OpenRenderBox/include/OpenRenderBox/ORBBase.h index e5710a8..a070f88 100644 --- a/Sources/OpenRenderBox/include/OpenRenderBox/ORBBase.h +++ b/Sources/OpenRenderBox/include/OpenRenderBox/ORBBase.h @@ -68,4 +68,4 @@ #if !ORB_TRRET_OS_DARWIN #include "CFCGTypes.h" -#endif \ No newline at end of file +#endif diff --git a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h index 45c13d1..f8cd013 100644 --- a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h +++ b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h @@ -64,7 +64,7 @@ CGRect ORBPathStorageGetBoundingRect(ORBPathStorageRef storage) ORB_SWIFT_NAME(g ORB_EXPORT ORB_REFINED_FOR_SWIFT -CGPathRef RBPathStorageGetCGPath(ORBPathStorageRef storage) ORB_SWIFT_NAME(getter:ORBPathStorageRef.cgPath(self:)); +__nullable CGPathRef ORBPathStorageGetCGPath(ORBPathStorageRef storage) ORB_SWIFT_NAME(getter:ORBPathStorageRef.cgPath(self:)); #endif ORB_EXTERN_C_END diff --git a/Sources/OpenRenderBox/include/OpenRenderBoxCxx/Path/PathStorage.hpp b/Sources/OpenRenderBox/include/OpenRenderBoxCxx/Path/PathStorage.hpp index 09d6b4c..7bc8875 100644 --- a/Sources/OpenRenderBox/include/OpenRenderBoxCxx/Path/PathStorage.hpp +++ b/Sources/OpenRenderBox/include/OpenRenderBoxCxx/Path/PathStorage.hpp @@ -5,9 +5,12 @@ #pragma once #include +#include #include - #include +#if ORB_TARGET_OS_DARWIN +#include +#endif ORB_ASSUME_NONNULL_BEGIN @@ -128,7 +131,7 @@ struct StorageFlags { class Storage { public: ORB_INLINE ORB_CONSTEXPR - const static atomic_long& last_identifier() ORB_NOEXCEPT { + const static atomic_uint& last_identifier() ORB_NOEXCEPT { return _last_identifier; } @@ -138,7 +141,7 @@ class Storage { } private: - static atomic_long _last_identifier; + static atomic_uint _last_identifier; public: Storage(uint32_t capacity); @@ -153,20 +156,19 @@ class Storage { // push_values(unsigned char, double const*, unsigned long) // update_single_element() - /// Get cached CGPath, lazily creating if needed (matches RB::Path::Storage::cgpath) - void * cgpath() const ORB_NOEXCEPT; + /// Apply callback to each path element + bool apply_elements(void *info, ORBPathApplyCallback callback) const ORB_NOEXCEPT; + #if ORB_TARGET_OS_DARWIN + /// Get cached CGPath, lazily creating if needed (thread-safe with casal) + CGPathRef _Nullable cgpath() const ORB_NOEXCEPT; + #endif public: ORB_INLINE ORB_CONSTEXPR void * unknown() const ORB_NOEXCEPT { return _unknown; } - ORB_INLINE - void * cachedCGPath() const ORB_NOEXCEPT { - return _cached_cgPath; - } - ORB_INLINE ORB_CONSTEXPR StorageFlags flags() const ORB_NOEXCEPT { return _flags; @@ -209,6 +211,13 @@ class Storage { bool isEmpty() const ORB_NOEXCEPT { return actual_size() == 0; } + + #if ORB_TARGET_OS_DARWIN + ORB_INLINE + CGPathRef cachedCGPath() const ORB_NOEXCEPT { + return _cached_cgPath; + } + #endif private: void * _unknown; // 0x00 StorageFlags _flags; // 0x08 @@ -218,7 +227,9 @@ class Storage { void * _reserved1; // 0x20 void * _reserved2; // 0x28 void * _reserved3; // 0x30 - mutable void * _cached_cgPath; // 0x38 - lazily cached CGPath + #if ORB_TARGET_OS_DARWIN + mutable CGPathRef _cached_cgPath; // 0x38 - lazily cached CGPath + #endif }; } /* Path */ } /* ORB */ From 6c22bd198d12a3c3e9aa035f0d2aaeb6a8e80b35 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 27 Dec 2025 11:32:31 +0800 Subject: [PATCH 2/9] Remove unnessary ORB_REFINED_FOR_SWIFT --- Sources/OpenRenderBox/Path/ORBPath.cpp | 5 +++++ .../OpenRenderBox/include/OpenRenderBox/ORBPath.h | 14 ++++++++++---- .../include/OpenRenderBox/ORBPathStorage.h | 12 ------------ .../OpenRenderBox/include/OpenRenderBox/ORBUUID.h | 2 -- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/Sources/OpenRenderBox/Path/ORBPath.cpp b/Sources/OpenRenderBox/Path/ORBPath.cpp index 2aadf2e..443d84c 100644 --- a/Sources/OpenRenderBox/Path/ORBPath.cpp +++ b/Sources/OpenRenderBox/Path/ORBPath.cpp @@ -7,6 +7,7 @@ #include #include +#include // Empty path callbacks (all null) - C++ internal linkage static const ORBPathCallbacks empty_path_callbacks = { @@ -145,4 +146,8 @@ bool ORBPathContainsPoints(ORBPath path, uint64_t count, const CGPoint *points, return false; } +bool ORBPathApplyElements(ORBPath path, void *info, ORBPathApplyCallback callback) { + ORB::precondition_failure("TODO"); +} + #endif /* ORB_TARGET_OS_DARWIN */ diff --git a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPath.h b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPath.h index 4377fba..549f3fa 100644 --- a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPath.h +++ b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPath.h @@ -23,7 +23,9 @@ typedef ORB_ENUM(int32_t, ORBPathElement) { ORBPathElementFixedRoundedRectCircular = 8, ORBPathElementFixedRoundedRectContinuous = 9, -}; + + ORBPathElementInvalid = 25, +} ORB_SWIFT_NAME(ORBPath.Element); /// Defines the shape of a rounded rectangle's corners. typedef ORB_ENUM(int32_t, ORBPathRoundedCornerStyle) { @@ -37,7 +39,7 @@ typedef ORB_ENUM(int32_t, ORBPathRoundedCornerStyle) { /// Returns true to stop enumeration, false to continue typedef bool (*ORBPathApplyCallback)(void * info, ORBPathElement element, const CGFloat *points, const void * _Nullable userInfo); -typedef struct ORBPathCallbacks ORBPathCallbacks; +typedef struct ORBPathCallbacks ORBPathCallbacks ORB_SWIFT_NAME(ORBPath.ApplyCallback); typedef struct ORBPathStorage * ORBPathStorageRef ORB_SWIFT_STRUCT ORB_SWIFT_NAME(ORBPath.Storage); @@ -55,11 +57,9 @@ ORB_EXPORT const ORBPath ORBPathNull ORB_SWIFT_NAME(ORBPath.null); ORB_EXPORT -ORB_REFINED_FOR_SWIFT void ORBPathRetain(ORBPath path) ORB_SWIFT_NAME(ORBPath.retain(self:)); ORB_EXPORT -ORB_REFINED_FOR_SWIFT void ORBPathRelease(ORBPath path) ORB_SWIFT_NAME(ORBPath.release(self:)); #if ORB_TARGET_OS_DARWIN @@ -95,6 +95,12 @@ ORB_EXPORT bool ORBPathContainsPoints(ORBPath path, uint64_t count, const CGPoint *points, bool eoFill, const CGAffineTransform * _Nullable transform) ORB_SWIFT_NAME(ORBPath.containsPoints(self:count:points:eoFill:transform:)); #endif +// MARK: - Apply Callback + +ORB_EXPORT + +bool ORBPathApplyElements(ORBPath path, void * info, ORBPathApplyCallback callback) ; + ORB_EXTERN_C_END ORB_ASSUME_NONNULL_END diff --git a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h index f8cd013..c0c8963 100644 --- a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h +++ b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h @@ -18,52 +18,40 @@ ORB_ASSUME_NONNULL_BEGIN ORB_EXTERN_C_BEGIN ORB_EXPORT -ORB_REFINED_FOR_SWIFT void ORBPathStorageInit(ORBPathStorageRef dst, uint32_t capacity, ORBPathStorageRef _Nullable source) ORB_SWIFT_NAME(ORBPathStorageRef.initialize(self:capacity:source:)); ORB_EXPORT -ORB_REFINED_FOR_SWIFT void ORBPathStorageDestroy(ORBPathStorageRef storage) ORB_SWIFT_NAME(ORBPathStorageRef.destroy(self:)); ORB_EXPORT -ORB_REFINED_FOR_SWIFT void ORBPathStorageClear(ORBPathStorageRef storage) ORB_SWIFT_NAME(ORBPathStorageRef.clear(self:)); ORB_EXPORT -ORB_REFINED_FOR_SWIFT bool ORBPathStorageAppendElement(ORBPathStorageRef storage, ORBPathElement element, CGFloat const * points, const void * _Nullable userInfo) ORB_SWIFT_NAME(ORBPathStorageRef.append(self:element:points:userInfo:)); ORB_EXPORT -ORB_REFINED_FOR_SWIFT void ORBPathStorageAppendPath(ORBPathStorageRef, ORBPath) ORB_SWIFT_NAME(ORBPathStorageRef.append(self:path:)); ORB_EXPORT -ORB_REFINED_FOR_SWIFT bool ORBPathStorageApplyElements(ORBPathStorageRef, void *info, ORBPathApplyCallback _Nullable callback) ORB_SWIFT_NAME(ORBPathStorageRef.apply(self:info:callback:)); ORB_EXPORT -ORB_REFINED_FOR_SWIFT bool ORBPathStorageIsEmpty(ORBPathStorageRef storage) ORB_SWIFT_NAME(getter:ORBPathStorageRef.isEmpty(self:)); ORB_EXPORT -ORB_REFINED_FOR_SWIFT bool ORBPathStorageEqualToStorage(ORBPathStorageRef lhs, ORBPathStorageRef rhs) ORB_SWIFT_NAME(ORBPathStorageRef.isEqual(self:to:)); ORB_EXPORT -ORB_REFINED_FOR_SWIFT bool ORBPathStorageIsSingleElement(ORBPathStorageRef storage) ORB_SWIFT_NAME(getter:ORBPathStorageRef.isSingleElement(self:)); ORB_EXPORT -ORB_REFINED_FOR_SWIFT uint32_t ORBPathStorageGetBezierOrder(ORBPathStorageRef storage) ORB_SWIFT_NAME(getter:ORBPathStorageRef.bezierOrder(self:)); #if ORB_TARGET_OS_DARWIN ORB_EXPORT -ORB_REFINED_FOR_SWIFT CGRect ORBPathStorageGetBoundingRect(ORBPathStorageRef storage) ORB_SWIFT_NAME(getter:ORBPathStorageRef.boundingRect(self:)); ORB_EXPORT -ORB_REFINED_FOR_SWIFT __nullable CGPathRef ORBPathStorageGetCGPath(ORBPathStorageRef storage) ORB_SWIFT_NAME(getter:ORBPathStorageRef.cgPath(self:)); #endif diff --git a/Sources/OpenRenderBox/include/OpenRenderBox/ORBUUID.h b/Sources/OpenRenderBox/include/OpenRenderBox/ORBUUID.h index e270b2c..69fd007 100644 --- a/Sources/OpenRenderBox/include/OpenRenderBox/ORBUUID.h +++ b/Sources/OpenRenderBox/include/OpenRenderBox/ORBUUID.h @@ -18,12 +18,10 @@ ORB_EXTERN_C_BEGIN #if ORB_TARGET_OS_DARWIN && __OBJC__ ORB_EXPORT -ORB_REFINED_FOR_SWIFT ORBUUID ORBUUIDInitFromNSUUID(NSUUID *uuid) ORB_SWIFT_NAME(ORBUUID.init(uuid:)); #endif ORB_EXPORT -ORB_REFINED_FOR_SWIFT ORBUUID ORBUUIDInitFromHash(uint64_t words0, uint64_t words1, uint32_t words2) ORB_SWIFT_NAME(ORBUUID.init(_:_:_:)); ORB_EXTERN_C_END From 218258a8cff0d997e24ab8e536452357e7c5f583 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 27 Dec 2025 11:54:06 +0800 Subject: [PATCH 3/9] Implement ORBPathApplyElements --- Sources/OpenRenderBox/Path/ORBPath.cpp | 14 +++++++++++++- Sources/OpenRenderBox/Path/ORBPathStorage.cpp | 15 +++++++++++++-- Sources/OpenRenderBox/Path/PathStorage.cpp | 19 ++++++++++++++++++- .../include/OpenRenderBox/ORBPath.h | 3 +-- .../include/OpenRenderBox/ORBPathStorage.h | 2 +- .../OpenRenderBoxCxx/Path/PathStorage.hpp | 10 ++++++++-- 6 files changed, 54 insertions(+), 9 deletions(-) diff --git a/Sources/OpenRenderBox/Path/ORBPath.cpp b/Sources/OpenRenderBox/Path/ORBPath.cpp index 443d84c..71f2854 100644 --- a/Sources/OpenRenderBox/Path/ORBPath.cpp +++ b/Sources/OpenRenderBox/Path/ORBPath.cpp @@ -147,7 +147,19 @@ bool ORBPathContainsPoints(ORBPath path, uint64_t count, const CGPoint *points, } bool ORBPathApplyElements(ORBPath path, void *info, ORBPathApplyCallback callback) { - ORB::precondition_failure("TODO"); + auto apply = path.callbacks->apply; + bool flag = false; // TODO: calllbacks's flag to indicate whether it supports extra features + if (flag) { + if (callback == nullptr) { + return true; + } + apply(path.storage, info, callback/*, path.callbacks*/); + } else { + if (callback == nullptr) { + return true; + } + apply(path.storage, info, callback); + } } #endif /* ORB_TARGET_OS_DARWIN */ diff --git a/Sources/OpenRenderBox/Path/ORBPathStorage.cpp b/Sources/OpenRenderBox/Path/ORBPathStorage.cpp index 85ffab6..b9b2911 100644 --- a/Sources/OpenRenderBox/Path/ORBPathStorage.cpp +++ b/Sources/OpenRenderBox/Path/ORBPathStorage.cpp @@ -8,6 +8,17 @@ using namespace ORB; +namespace ORB { +namespace Path { +namespace { +bool append_element_callback(void * info, ORBPathElement element, const CGFloat *points, const void * _Nullable userInfo) { + reinterpret_cast(info)->append_element(element, points, userInfo); + return true; +} +} /* anonymous namespace */ +} /* Path */ +} /* ORB */ + void ORBPathStorageInit(ORBPathStorageRef dst, uint32_t capacity, ORBPathStorageRef source) { if (source != nullptr) { dst->storage = ORB::Path::Storage(capacity, source->storage); @@ -28,8 +39,8 @@ bool ORBPathStorageAppendElement(ORBPathStorageRef storage, ORBPathElement eleme precondition_failure("TODO"); } -void ORBPathStorageAppendPath(ORBPathStorageRef storage, ORBPath path) { - precondition_failure("TODO"); +bool ORBPathStorageAppendPath(ORBPathStorageRef storage, ORBPath path) { + return ORBPathApplyElements(path, storage, ORB::Path::append_element_callback); } bool ORBPathStorageApplyElements(ORBPathStorageRef, void *info, ORBPathApplyCallback callback) { diff --git a/Sources/OpenRenderBox/Path/PathStorage.cpp b/Sources/OpenRenderBox/Path/PathStorage.cpp index 5a17492..c7a2362 100644 --- a/Sources/OpenRenderBox/Path/PathStorage.cpp +++ b/Sources/OpenRenderBox/Path/PathStorage.cpp @@ -75,8 +75,25 @@ void Storage::clear() { // TODO } +void Storage::append_element(ORBPathElement element, const CGFloat *points, const void *info) { + if (element >= ORBPathElementInvalid) { + precondition_failure("invalid path element: %d", element); + } + // TODO: Implement element appending + precondition_failure("TODO"); +} + bool Storage::apply_elements(void *info, ORBPathApplyCallback callback) const ORB_NOEXCEPT { - // TODO: Implement element iteration + // TODO: Add fast-path checks for special callbacks: + // - append_element_callback → append_storage(info, this) + // - NestedCallbacks::apply_elements_callback → apply_elements_fast + // - NestedCallbacks::single_element_callback → single_element_fast + // - Mapper::apply_callback with flags check → MapCache::apply + return apply_elements_(info, callback); +} + +bool Storage::apply_elements_(void *info, ORBPathApplyCallback callback) const ORB_NOEXCEPT { + // TODO: Implement actual element iteration over storage return true; } diff --git a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPath.h b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPath.h index 549f3fa..9ed4eeb 100644 --- a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPath.h +++ b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPath.h @@ -98,8 +98,7 @@ bool ORBPathContainsPoints(ORBPath path, uint64_t count, const CGPoint *points, // MARK: - Apply Callback ORB_EXPORT - -bool ORBPathApplyElements(ORBPath path, void * info, ORBPathApplyCallback callback) ; +bool ORBPathApplyElements(ORBPath path, void * info, _Nullable ORBPathApplyCallback callback) ORB_SWIFT_NAME(ORBPath.apply(self:info:callback:)); ORB_EXTERN_C_END diff --git a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h index c0c8963..51a68fa 100644 --- a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h +++ b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h @@ -30,7 +30,7 @@ ORB_EXPORT bool ORBPathStorageAppendElement(ORBPathStorageRef storage, ORBPathElement element, CGFloat const * points, const void * _Nullable userInfo) ORB_SWIFT_NAME(ORBPathStorageRef.append(self:element:points:userInfo:)); ORB_EXPORT -void ORBPathStorageAppendPath(ORBPathStorageRef, ORBPath) ORB_SWIFT_NAME(ORBPathStorageRef.append(self:path:)); +bool ORBPathStorageAppendPath(ORBPathStorageRef, ORBPath) ORB_SWIFT_NAME(ORBPathStorageRef.append(self:path:)); ORB_EXPORT bool ORBPathStorageApplyElements(ORBPathStorageRef, void *info, ORBPathApplyCallback _Nullable callback) ORB_SWIFT_NAME(ORBPathStorageRef.apply(self:info:callback:)); diff --git a/Sources/OpenRenderBox/include/OpenRenderBoxCxx/Path/PathStorage.hpp b/Sources/OpenRenderBox/include/OpenRenderBoxCxx/Path/PathStorage.hpp index 7bc8875..7d479d2 100644 --- a/Sources/OpenRenderBox/include/OpenRenderBoxCxx/Path/PathStorage.hpp +++ b/Sources/OpenRenderBox/include/OpenRenderBoxCxx/Path/PathStorage.hpp @@ -152,13 +152,19 @@ class Storage { void clear(); -// void append_element(RBPathElement, double const*, void const*); + void append_element(ORBPathElement element, const double *points, const void *info); // push_values(unsigned char, double const*, unsigned long) // update_single_element() - /// Apply callback to each path element + /// Apply callback to each path element (with fast-path checks) bool apply_elements(void *info, ORBPathApplyCallback callback) const ORB_NOEXCEPT; +private: + /// Core element iteration (no fast-path checks) + bool apply_elements_(void *info, ORBPathApplyCallback callback) const ORB_NOEXCEPT; + +public: + #if ORB_TARGET_OS_DARWIN /// Get cached CGPath, lazily creating if needed (thread-safe with casal) CGPathRef _Nullable cgpath() const ORB_NOEXCEPT; From 901734affd5284867591f0b846d39850993f567d Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 27 Dec 2025 12:00:12 +0800 Subject: [PATCH 4/9] Update append path API --- Sources/OpenRenderBox/Path/ORBPathStorage.cpp | 8 ++++---- Sources/OpenRenderBox/Path/PathStorage.cpp | 2 +- .../include/OpenRenderBoxCxx/Path/PathStorage.hpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/OpenRenderBox/Path/ORBPathStorage.cpp b/Sources/OpenRenderBox/Path/ORBPathStorage.cpp index b9b2911..9f2e480 100644 --- a/Sources/OpenRenderBox/Path/ORBPathStorage.cpp +++ b/Sources/OpenRenderBox/Path/ORBPathStorage.cpp @@ -35,16 +35,16 @@ void ORBPathStorageClear(ORBPathStorageRef storage) { storage->storage.clear(); } -bool ORBPathStorageAppendElement(ORBPathStorageRef storage, ORBPathElement element, double const * points, const void * userInfo) { - precondition_failure("TODO"); +bool ORBPathStorageAppendElement(ORBPathStorageRef storage, ORBPathElement element, const CGFloat * points, const void * userInfo) { + return storage->storage.append_element(element, points, userInfo); } bool ORBPathStorageAppendPath(ORBPathStorageRef storage, ORBPath path) { return ORBPathApplyElements(path, storage, ORB::Path::append_element_callback); } -bool ORBPathStorageApplyElements(ORBPathStorageRef, void *info, ORBPathApplyCallback callback) { - precondition_failure("TODO"); +bool ORBPathStorageApplyElements(ORBPathStorageRef storage, void *info, ORBPathApplyCallback callback) { + return storage->storage.apply_elements(info, callback); } bool ORBPathStorageIsEmpty(ORBPathStorageRef storage) { diff --git a/Sources/OpenRenderBox/Path/PathStorage.cpp b/Sources/OpenRenderBox/Path/PathStorage.cpp index c7a2362..1508110 100644 --- a/Sources/OpenRenderBox/Path/PathStorage.cpp +++ b/Sources/OpenRenderBox/Path/PathStorage.cpp @@ -75,7 +75,7 @@ void Storage::clear() { // TODO } -void Storage::append_element(ORBPathElement element, const CGFloat *points, const void *info) { +bool Storage::append_element(ORBPathElement element, const CGFloat *points, const void *info) { if (element >= ORBPathElementInvalid) { precondition_failure("invalid path element: %d", element); } diff --git a/Sources/OpenRenderBox/include/OpenRenderBoxCxx/Path/PathStorage.hpp b/Sources/OpenRenderBox/include/OpenRenderBoxCxx/Path/PathStorage.hpp index 7d479d2..1dcf843 100644 --- a/Sources/OpenRenderBox/include/OpenRenderBoxCxx/Path/PathStorage.hpp +++ b/Sources/OpenRenderBox/include/OpenRenderBoxCxx/Path/PathStorage.hpp @@ -152,7 +152,7 @@ class Storage { void clear(); - void append_element(ORBPathElement element, const double *points, const void *info); + bool append_element(ORBPathElement element, const CGFloat *points, const void * _Nullable userInfo); // push_values(unsigned char, double const*, unsigned long) // update_single_element() From 0d67f35215e7a175803369c60edcef43069f071e Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 27 Dec 2025 12:24:32 +0800 Subject: [PATCH 5/9] Update make_rect --- Sources/OpenRenderBox/Path/ORBPath.cpp | 27 +++++++++++++------ .../include/OpenRenderBox/ORBPath.h | 3 ++- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/Sources/OpenRenderBox/Path/ORBPath.cpp b/Sources/OpenRenderBox/Path/ORBPath.cpp index 71f2854..53908ca 100644 --- a/Sources/OpenRenderBox/Path/ORBPath.cpp +++ b/Sources/OpenRenderBox/Path/ORBPath.cpp @@ -7,6 +7,7 @@ #include #include +#include #include // Empty path callbacks (all null) - C++ internal linkage @@ -24,6 +25,21 @@ static const ORBPathCallbacks empty_path_callbacks = { nullptr, }; +namespace { +ORBPath make_rect(CGRect rect, const CGAffineTransform *transform, ORBPathElement element) { + if (CGRectIsNull(rect)) { + return ORBPathNull; + } + if (transform == nullptr || CGAffineTransformIsIdentity(*transform)) { + // TODO + return ORBPathNull; + } else { + // TODO + return ORBPathNull; + } +} +} /* anonymous namespace */ + // Empty path (storage = null) const ORBPath ORBPathEmpty = { nullptr, @@ -68,12 +84,7 @@ ORBPath ORBPathMakeWithCGPath(CGPathRef cgPath) { } ORBPath ORBPathMakeRect(CGRect rect, const CGAffineTransform *transform) { - CGPathRef cgPath = CGPathCreateWithRect(rect, transform); - ORBPath path = { - reinterpret_cast(const_cast(cgPath)), - &ORBPathCGPathCallbacks, - }; - return path; + return make_rect(rect, transform, ORBPathElementRect); } ORBPath ORBPathMakeEllipse(CGRect rect, const CGAffineTransform *transform) { @@ -153,12 +164,12 @@ bool ORBPathApplyElements(ORBPath path, void *info, ORBPathApplyCallback callbac if (callback == nullptr) { return true; } - apply(path.storage, info, callback/*, path.callbacks*/); + return apply(path.storage, info, callback/*, path.callbacks*/); } else { if (callback == nullptr) { return true; } - apply(path.storage, info, callback); + return apply(path.storage, info, callback); } } diff --git a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPath.h b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPath.h index 9ed4eeb..2b7361d 100644 --- a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPath.h +++ b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPath.h @@ -20,7 +20,8 @@ typedef ORB_ENUM(int32_t, ORBPathElement) { ORBPathElementAddQuadCurveToPoint = 2, ORBPathElementAddCurveToPoint = 3, ORBPathElementCloseSubpath = 4, - + ORBPathElementRect = 5, + ORBPathElementRoundedRect = 6, ORBPathElementFixedRoundedRectCircular = 8, ORBPathElementFixedRoundedRectContinuous = 9, From 76fe5df071687d5d275eac05a56707c9f7e0f22b Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 27 Dec 2025 12:34:27 +0800 Subject: [PATCH 6/9] Update PathStorage dealloc --- Sources/OpenRenderBox/Path/PathStorage.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Sources/OpenRenderBox/Path/PathStorage.cpp b/Sources/OpenRenderBox/Path/PathStorage.cpp index 1508110..3fbe4f3 100644 --- a/Sources/OpenRenderBox/Path/PathStorage.cpp +++ b/Sources/OpenRenderBox/Path/PathStorage.cpp @@ -61,9 +61,19 @@ Storage::Storage(uint32_t capacity, const Storage &storage): Storage(capacity) { Storage::~Storage() { if (_unknown != nullptr) { + auto oldValue = _unknown; _unknown = nullptr; // TODO } + // TODO: MapCache + if (flags().isExternal()) { + if (cachedCGPath() != nullptr) { + auto oldCache = cachedCGPath(); + _cached_cgPath = nullptr; + CFRelease(oldCache); + } + free((void *)external_storage()); + } } bool Storage::operator==(const Storage &other) const ORB_NOEXCEPT { From 0f52a539a43ba485ee581c3d321b4d592fd2b4af Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 27 Dec 2025 12:44:41 +0800 Subject: [PATCH 7/9] Update ORBPathStorageGetCGPath --- .../include/OpenRenderBox/ORBPathStorage.h | 1 + .../PathStorageTests.swift | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h index 51a68fa..aa378a4 100644 --- a/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h +++ b/Sources/OpenRenderBox/include/OpenRenderBox/ORBPathStorage.h @@ -52,6 +52,7 @@ ORB_EXPORT CGRect ORBPathStorageGetBoundingRect(ORBPathStorageRef storage) ORB_SWIFT_NAME(getter:ORBPathStorageRef.boundingRect(self:)); ORB_EXPORT +CF_RETURNS_NOT_RETAINED __nullable CGPathRef ORBPathStorageGetCGPath(ORBPathStorageRef storage) ORB_SWIFT_NAME(getter:ORBPathStorageRef.cgPath(self:)); #endif diff --git a/Tests/OpenRenderBoxCompatibilityTests/PathStorageTests.swift b/Tests/OpenRenderBoxCompatibilityTests/PathStorageTests.swift index aa2e15c..1b6e1ca 100644 --- a/Tests/OpenRenderBoxCompatibilityTests/PathStorageTests.swift +++ b/Tests/OpenRenderBoxCompatibilityTests/PathStorageTests.swift @@ -93,6 +93,29 @@ struct PathStorageTests { path1.release() path2.release() } + + @Test("Verify no crash or memleak of ORBPathStorageGetCGPath call") + func storageGetCGPath() { + let rect = CGRect(x: 0, y: 0, width: 100, height: 100) + let path = ORBPath(rect: rect, transform: nil) + let storage = path.storage + storage.initialize(capacity: 64, source: nil) + storage.append(path: path) + for _ in 1 ... 7 { + storage.append(element: .moveToPoint, points: [50, 50], userInfo: nil) + storage.append(element: .addLineToPoint, points: [100, 50], userInfo: nil) + storage.append(element: .closeSubpath, points: [], userInfo: nil) + } + func test(_ s: ORBPath.Storage) { + if let p = s.cgPath { + _ = p.isEmpty + _ = p.boundingBox + } + } + for i in 1 ... 20 { + test(storage) + } + } } #endif From b698b77c68c7b2d68adf89121e8acb32d956cedb Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 27 Dec 2025 12:56:19 +0800 Subject: [PATCH 8/9] Update DarwinPrivateFrameworks dependency --- Package.resolved | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.resolved b/Package.resolved index bc372ce..bcbf67b 100644 --- a/Package.resolved +++ b/Package.resolved @@ -7,7 +7,7 @@ "location" : "https://github.com/OpenSwiftUIProject/DarwinPrivateFrameworks.git", "state" : { "branch" : "main", - "revision" : "145cfde7a6b78248622bb2cd267101a8083bb126" + "revision" : "e8090a2f05b2bba73e7772cde4427b3cd1bf1f0a" } }, { From ea07df0f937b0d8463255780c735ebaad98414af Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 27 Dec 2025 13:00:46 +0800 Subject: [PATCH 9/9] Fix Linux build: guard Darwin-only CGPath code --- Sources/OpenRenderBox/Path/ORBPath.cpp | 34 +++++++++++----------- Sources/OpenRenderBox/Path/PathStorage.cpp | 4 +++ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Sources/OpenRenderBox/Path/ORBPath.cpp b/Sources/OpenRenderBox/Path/ORBPath.cpp index 53908ca..eee22f7 100644 --- a/Sources/OpenRenderBox/Path/ORBPath.cpp +++ b/Sources/OpenRenderBox/Path/ORBPath.cpp @@ -25,21 +25,6 @@ static const ORBPathCallbacks empty_path_callbacks = { nullptr, }; -namespace { -ORBPath make_rect(CGRect rect, const CGAffineTransform *transform, ORBPathElement element) { - if (CGRectIsNull(rect)) { - return ORBPathNull; - } - if (transform == nullptr || CGAffineTransformIsIdentity(*transform)) { - // TODO - return ORBPathNull; - } else { - // TODO - return ORBPathNull; - } -} -} /* anonymous namespace */ - // Empty path (storage = null) const ORBPath ORBPathEmpty = { nullptr, @@ -70,6 +55,21 @@ void ORBPathRelease(ORBPath path) { // MARK: - Path Creation +namespace { +ORBPath make_rect(CGRect rect, const CGAffineTransform *transform, ORBPathElement element) { + if (CGRectIsNull(rect)) { + return ORBPathNull; + } + if (transform == nullptr || CGAffineTransformIsIdentity(*transform)) { + // TODO + return ORBPathNull; + } else { + // TODO + return ORBPathNull; + } +} +} /* anonymous namespace */ + // TODO: TO be implemented natively ORBPath ORBPathMakeWithCGPath(CGPathRef cgPath) { @@ -157,6 +157,8 @@ bool ORBPathContainsPoints(ORBPath path, uint64_t count, const CGPoint *points, return false; } +#endif /* ORB_TARGET_OS_DARWIN */ + bool ORBPathApplyElements(ORBPath path, void *info, ORBPathApplyCallback callback) { auto apply = path.callbacks->apply; bool flag = false; // TODO: calllbacks's flag to indicate whether it supports extra features @@ -172,5 +174,3 @@ bool ORBPathApplyElements(ORBPath path, void *info, ORBPathApplyCallback callbac return apply(path.storage, info, callback); } } - -#endif /* ORB_TARGET_OS_DARWIN */ diff --git a/Sources/OpenRenderBox/Path/PathStorage.cpp b/Sources/OpenRenderBox/Path/PathStorage.cpp index 3fbe4f3..b7d56bc 100644 --- a/Sources/OpenRenderBox/Path/PathStorage.cpp +++ b/Sources/OpenRenderBox/Path/PathStorage.cpp @@ -67,11 +67,13 @@ Storage::~Storage() { } // TODO: MapCache if (flags().isExternal()) { + #if ORB_TARGET_OS_DARWIN if (cachedCGPath() != nullptr) { auto oldCache = cachedCGPath(); _cached_cgPath = nullptr; CFRelease(oldCache); } + #endif free((void *)external_storage()); } } @@ -107,6 +109,7 @@ bool Storage::apply_elements_(void *info, ORBPathApplyCallback callback) const O return true; } +#if ORB_TARGET_OS_DARWIN CGPathRef Storage::cgpath() const ORB_NOEXCEPT { if (flags().isInline()) { return nullptr; @@ -145,6 +148,7 @@ CGPathRef Storage::cgpath() const ORB_NOEXCEPT { return expected; } } +#endif } /* Path */ } /* ORB */