react-native-smooth-clip-view 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +135 -386
- package/android/build.gradle +4 -7
- package/android/proguard-rules.pro +2 -2
- package/android/src/main/cpp/SmoothClipAndroid.h +9 -12
- package/android/src/main/cpp/SmoothClipBindings.cpp +300 -704
- package/android/src/main/cpp/SmoothClipRegistry.cpp +348 -594
- package/android/src/main/java/com/smoothclipview/ClipGeometryNormalizer.kt +36 -227
- package/android/src/main/java/com/smoothclipview/SmoothClipBindings.kt +16 -19
- package/android/src/main/java/com/smoothclipview/SmoothClipModule.kt +36 -294
- package/android/src/main/java/com/smoothclipview/SmoothClipView.kt +369 -486
- package/android/src/main/java/com/smoothclipview/SmoothClipViewManager.kt +75 -77
- package/cpp/SmoothClipAnimationCurve.h +237 -346
- package/cpp/SmoothClipRegistry.h +24 -52
- package/cpp/SmoothClipSharedGeometry.h +64 -94
- package/cpp/SmoothClipVelocityTracker.h +5 -5
- package/ios/SmoothClipGeometry.h +23 -34
- package/ios/SmoothClipRegistry.mm +206 -711
- package/ios/SmoothClipTurboModule.cpp +217 -715
- package/ios/SmoothClipTurboModule.h +54 -297
- package/ios/SmoothClipView.mm +599 -505
- package/ios/SmoothClipViewRegistry.h +2 -7
- package/lib/module/NativeSmoothClipModule.js.map +1 -1
- package/lib/module/SmoothClipView.ios.js +84 -17
- package/lib/module/SmoothClipView.ios.js.map +1 -1
- package/lib/module/SmoothClipView.js +1 -1
- package/lib/module/SmoothClipView.js.map +1 -1
- package/lib/module/SmoothClipViewNativeComponent.ts +20 -26
- package/lib/module/capabilities.native.js +1 -19
- package/lib/module/capabilities.native.js.map +1 -1
- package/lib/module/capabilityTypes.js +0 -9
- package/lib/module/capabilityTypes.js.map +1 -1
- package/lib/module/controllerInternals.js +28 -0
- package/lib/module/controllerInternals.js.map +1 -0
- package/lib/module/controllerLifecycle.js +9 -0
- package/lib/module/controllerLifecycle.js.map +1 -0
- package/lib/module/controllerTypes.js +4 -0
- package/lib/module/controllerTypes.js.map +1 -0
- package/lib/module/controllers.android.js +4 -0
- package/lib/module/controllers.android.js.map +1 -0
- package/lib/module/controllers.ios.js +4 -0
- package/lib/module/controllers.ios.js.map +1 -0
- package/lib/module/controllers.js +4 -0
- package/lib/module/controllers.js.map +1 -0
- package/lib/module/controllers.native.js +89 -0
- package/lib/module/controllers.native.js.map +1 -0
- package/lib/module/geometry.js +71 -51
- package/lib/module/geometry.js.map +1 -1
- package/lib/module/groupTypes.js +4 -0
- package/lib/module/{groupDriverTypes.js.map → groupTypes.js.map} +1 -1
- package/lib/module/groups.android.js +4 -0
- package/lib/module/groups.android.js.map +1 -0
- package/lib/module/groups.ios.js +4 -0
- package/lib/module/groups.ios.js.map +1 -0
- package/lib/module/groups.js +4 -0
- package/lib/module/groups.js.map +1 -0
- package/lib/module/groups.native.js +399 -0
- package/lib/module/groups.native.js.map +1 -0
- package/lib/module/ids.js +8 -0
- package/lib/module/ids.js.map +1 -0
- package/lib/module/index.js +3 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/nativeCompletion.js +37 -16
- package/lib/module/nativeCompletion.js.map +1 -1
- package/lib/module/presentationCodec.js +81 -0
- package/lib/module/presentationCodec.js.map +1 -0
- package/lib/typescript/src/NativeSmoothClipModule.d.ts +14 -23
- package/lib/typescript/src/NativeSmoothClipModule.d.ts.map +1 -1
- package/lib/typescript/src/SmoothClipView.d.ts +1 -1
- package/lib/typescript/src/SmoothClipView.d.ts.map +1 -1
- package/lib/typescript/src/SmoothClipView.ios.d.ts +18 -14
- package/lib/typescript/src/SmoothClipView.ios.d.ts.map +1 -1
- package/lib/typescript/src/SmoothClipViewNativeComponent.d.ts +10 -5
- package/lib/typescript/src/SmoothClipViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/capabilities.native.d.ts +1 -1
- package/lib/typescript/src/capabilities.native.d.ts.map +1 -1
- package/lib/typescript/src/capabilityTypes.d.ts +0 -6
- package/lib/typescript/src/capabilityTypes.d.ts.map +1 -1
- package/lib/typescript/src/controllerInternals.d.ts +14 -0
- package/lib/typescript/src/controllerInternals.d.ts.map +1 -0
- package/lib/typescript/src/controllerLifecycle.d.ts +3 -0
- package/lib/typescript/src/controllerLifecycle.d.ts.map +1 -0
- package/lib/typescript/src/controllerTypes.d.ts +62 -0
- package/lib/typescript/src/controllerTypes.d.ts.map +1 -0
- package/lib/typescript/src/controllers.android.d.ts +2 -0
- package/lib/typescript/src/controllers.android.d.ts.map +1 -0
- package/lib/typescript/src/controllers.d.ts +2 -0
- package/lib/typescript/src/controllers.d.ts.map +1 -0
- package/lib/typescript/src/controllers.ios.d.ts +2 -0
- package/lib/typescript/src/controllers.ios.d.ts.map +1 -0
- package/lib/typescript/src/controllers.native.d.ts +3 -0
- package/lib/typescript/src/controllers.native.d.ts.map +1 -0
- package/lib/typescript/src/geometry.d.ts +22 -12
- package/lib/typescript/src/geometry.d.ts.map +1 -1
- package/lib/typescript/src/groupTypes.d.ts +31 -0
- package/lib/typescript/src/groupTypes.d.ts.map +1 -0
- package/lib/typescript/src/groups.android.d.ts +2 -0
- package/lib/typescript/src/groups.android.d.ts.map +1 -0
- package/lib/typescript/src/groups.d.ts +2 -0
- package/lib/typescript/src/groups.d.ts.map +1 -0
- package/lib/typescript/src/groups.ios.d.ts +2 -0
- package/lib/typescript/src/groups.ios.d.ts.map +1 -0
- package/lib/typescript/src/groups.native.d.ts +3 -0
- package/lib/typescript/src/groups.native.d.ts.map +1 -0
- package/lib/typescript/src/ids.d.ts +2 -0
- package/lib/typescript/src/ids.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +6 -6
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/nativeCompletion.d.ts +16 -6
- package/lib/typescript/src/nativeCompletion.d.ts.map +1 -1
- package/lib/typescript/src/presentationCodec.d.ts +10 -0
- package/lib/typescript/src/presentationCodec.d.ts.map +1 -0
- package/package.json +8 -3
- package/src/NativeSmoothClipModule.ts +41 -292
- package/src/SmoothClipView.ios.tsx +130 -23
- package/src/SmoothClipView.tsx +5 -1
- package/src/SmoothClipViewNativeComponent.ts +20 -26
- package/src/capabilities.native.ts +2 -52
- package/src/capabilityTypes.ts +0 -14
- package/src/controllerInternals.ts +52 -0
- package/src/controllerLifecycle.ts +6 -0
- package/src/controllerTypes.ts +87 -0
- package/src/controllers.android.ts +1 -0
- package/src/controllers.ios.ts +1 -0
- package/src/controllers.native.ts +104 -0
- package/src/controllers.ts +1 -0
- package/src/geometry.ts +118 -74
- package/src/groupTypes.ts +53 -0
- package/src/groups.android.ts +1 -0
- package/src/groups.ios.ts +1 -0
- package/src/groups.native.ts +604 -0
- package/src/groups.ts +1 -0
- package/src/ids.ts +6 -0
- package/src/index.ts +20 -28
- package/src/nativeCompletion.ts +67 -32
- package/src/presentationCodec.ts +134 -0
- package/lib/module/driverState.js +0 -82
- package/lib/module/driverState.js.map +0 -1
- package/lib/module/driverTypes.js +0 -4
- package/lib/module/driverTypes.js.map +0 -1
- package/lib/module/drivers.android.js +0 -6
- package/lib/module/drivers.android.js.map +0 -1
- package/lib/module/drivers.ios.js +0 -6
- package/lib/module/drivers.ios.js.map +0 -1
- package/lib/module/drivers.js +0 -4
- package/lib/module/drivers.js.map +0 -1
- package/lib/module/drivers.native.js +0 -756
- package/lib/module/drivers.native.js.map +0 -1
- package/lib/module/groupDriverTypes.js +0 -4
- package/lib/module/groupDrivers.android.js +0 -4
- package/lib/module/groupDrivers.android.js.map +0 -1
- package/lib/module/groupDrivers.ios.js +0 -4
- package/lib/module/groupDrivers.ios.js.map +0 -1
- package/lib/module/groupDrivers.js +0 -4
- package/lib/module/groupDrivers.js.map +0 -1
- package/lib/module/groupDrivers.native.js +0 -799
- package/lib/module/groupDrivers.native.js.map +0 -1
- package/lib/module/presentationProtocol.js +0 -15
- package/lib/module/presentationProtocol.js.map +0 -1
- package/lib/module/reactRequests.js +0 -56
- package/lib/module/reactRequests.js.map +0 -1
- package/lib/typescript/src/driverState.d.ts +0 -26
- package/lib/typescript/src/driverState.d.ts.map +0 -1
- package/lib/typescript/src/driverTypes.d.ts +0 -121
- package/lib/typescript/src/driverTypes.d.ts.map +0 -1
- package/lib/typescript/src/drivers.android.d.ts +0 -3
- package/lib/typescript/src/drivers.android.d.ts.map +0 -1
- package/lib/typescript/src/drivers.d.ts +0 -3
- package/lib/typescript/src/drivers.d.ts.map +0 -1
- package/lib/typescript/src/drivers.ios.d.ts +0 -3
- package/lib/typescript/src/drivers.ios.d.ts.map +0 -1
- package/lib/typescript/src/drivers.native.d.ts +0 -5
- package/lib/typescript/src/drivers.native.d.ts.map +0 -1
- package/lib/typescript/src/groupDriverTypes.d.ts +0 -66
- package/lib/typescript/src/groupDriverTypes.d.ts.map +0 -1
- package/lib/typescript/src/groupDrivers.android.d.ts +0 -2
- package/lib/typescript/src/groupDrivers.android.d.ts.map +0 -1
- package/lib/typescript/src/groupDrivers.d.ts +0 -2
- package/lib/typescript/src/groupDrivers.d.ts.map +0 -1
- package/lib/typescript/src/groupDrivers.ios.d.ts +0 -2
- package/lib/typescript/src/groupDrivers.ios.d.ts.map +0 -1
- package/lib/typescript/src/groupDrivers.native.d.ts +0 -4
- package/lib/typescript/src/groupDrivers.native.d.ts.map +0 -1
- package/lib/typescript/src/presentationProtocol.d.ts +0 -4
- package/lib/typescript/src/presentationProtocol.d.ts.map +0 -1
- package/lib/typescript/src/reactRequests.d.ts +0 -9
- package/lib/typescript/src/reactRequests.d.ts.map +0 -1
- package/src/driverState.ts +0 -118
- package/src/driverTypes.ts +0 -171
- package/src/drivers.android.ts +0 -8
- package/src/drivers.ios.ts +0 -8
- package/src/drivers.native.ts +0 -1599
- package/src/drivers.ts +0 -6
- package/src/groupDriverTypes.ts +0 -117
- package/src/groupDrivers.android.ts +0 -1
- package/src/groupDrivers.ios.ts +0 -1
- package/src/groupDrivers.native.ts +0 -1189
- package/src/groupDrivers.ts +0 -1
- package/src/presentationProtocol.ts +0 -28
- package/src/reactRequests.ts +0 -76
package/cpp/SmoothClipRegistry.h
CHANGED
|
@@ -18,9 +18,7 @@ struct Geometry {
|
|
|
18
18
|
double width;
|
|
19
19
|
double height;
|
|
20
20
|
double radius;
|
|
21
|
-
// NaN means "use radius"
|
|
22
|
-
// existing five-value aggregate initializer used by the V1 implementation
|
|
23
|
-
// and its native tests.
|
|
21
|
+
// NaN means "use radius", allowing concise uniform-radius presentations.
|
|
24
22
|
double topLeftRadius = std::numeric_limits<double>::quiet_NaN();
|
|
25
23
|
double topRightRadius = std::numeric_limits<double>::quiet_NaN();
|
|
26
24
|
double bottomRightRadius = std::numeric_limits<double>::quiet_NaN();
|
|
@@ -28,16 +26,24 @@ struct Geometry {
|
|
|
28
26
|
ClipCurve curve = ClipCurve::Circular;
|
|
29
27
|
};
|
|
30
28
|
|
|
29
|
+
struct Shadow {
|
|
30
|
+
bool enabled = false;
|
|
31
|
+
double red = 0;
|
|
32
|
+
double green = 0;
|
|
33
|
+
double blue = 0;
|
|
34
|
+
double alpha = 1;
|
|
35
|
+
double offsetX = 0;
|
|
36
|
+
double offsetY = 0;
|
|
37
|
+
double blurRadius = 0;
|
|
38
|
+
double spreadDistance = 0;
|
|
39
|
+
};
|
|
40
|
+
|
|
31
41
|
struct Presentation {
|
|
32
42
|
Geometry clip;
|
|
33
43
|
double contentTranslateX;
|
|
34
44
|
double contentTranslateY;
|
|
35
45
|
double contentScale = 1.0;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
struct Keyframe {
|
|
39
|
-
double offset;
|
|
40
|
-
Presentation presentation;
|
|
46
|
+
Shadow shadow{};
|
|
41
47
|
};
|
|
42
48
|
|
|
43
49
|
struct TimingAnimation {
|
|
@@ -56,6 +62,7 @@ struct SpringAnimation {
|
|
|
56
62
|
double initialVelocity;
|
|
57
63
|
bool inheritVelocity;
|
|
58
64
|
int32_t reduceMotion;
|
|
65
|
+
double energyThreshold = 6e-9;
|
|
59
66
|
};
|
|
60
67
|
|
|
61
68
|
struct AnimationStart {
|
|
@@ -92,12 +99,6 @@ struct GroupMotionEntry {
|
|
|
92
99
|
bool hasFrom;
|
|
93
100
|
Presentation from;
|
|
94
101
|
Presentation target;
|
|
95
|
-
std::vector<Keyframe> keyframes;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
enum class GroupSuspensionPolicy : int32_t {
|
|
99
|
-
Pause = 0,
|
|
100
|
-
Finish = 1,
|
|
101
102
|
};
|
|
102
103
|
|
|
103
104
|
enum class GroupCancelBehavior : int32_t {
|
|
@@ -105,19 +106,11 @@ enum class GroupCancelBehavior : int32_t {
|
|
|
105
106
|
Finish = 1,
|
|
106
107
|
};
|
|
107
108
|
|
|
108
|
-
// The seven-scalar V1 bridge predates protocol-V2 host-normalization
|
|
109
|
-
// preflight and strict spring/duration rejection. Keep that wire contract
|
|
110
|
-
// selectable without widening any V1 entry point; V2 and grouped calls retain
|
|
111
|
-
// the conservative validation required for portable native ownership.
|
|
112
|
-
enum class AnimationValidationMode : int32_t {
|
|
113
|
-
LegacyV1 = 1,
|
|
114
|
-
ProtocolV2 = 2,
|
|
115
|
-
};
|
|
116
|
-
|
|
117
109
|
using CompletionCallback =
|
|
118
|
-
std::function<void(uint64_t, int32_t, bool)>;
|
|
110
|
+
std::function<void(uint64_t, int32_t, int32_t, bool)>;
|
|
119
111
|
using GroupCompletionCallback =
|
|
120
|
-
std::function<
|
|
112
|
+
std::function<
|
|
113
|
+
void(uint64_t, int32_t, int32_t, bool, std::vector<DriverSnapshot>)>;
|
|
121
114
|
|
|
122
115
|
void setCompletionCallback(
|
|
123
116
|
const void *owner,
|
|
@@ -128,11 +121,8 @@ void setGroupCompletionCallback(
|
|
|
128
121
|
GroupCompletionCallback callback);
|
|
129
122
|
void clearGroupCompletionCallback(const void *owner);
|
|
130
123
|
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
// setScalars hot writes on drivers without SmoothClipDriverOptions
|
|
134
|
-
// .velocityTracking, so the per-frame drag stream skips the clock read and
|
|
135
|
-
// channel copies. iOS callers never pass it and keep recording always.
|
|
124
|
+
// Interactive writes always keep the two samples needed by a later
|
|
125
|
+
// `initialVelocity: "inherit"` spring.
|
|
136
126
|
void setPresentation(
|
|
137
127
|
uint64_t driverId,
|
|
138
128
|
Presentation presentation,
|
|
@@ -150,20 +140,13 @@ int32_t animateTimingGroup(
|
|
|
150
140
|
uint64_t controllerId,
|
|
151
141
|
std::vector<GroupMotionEntry> entries,
|
|
152
142
|
TimingAnimation animation,
|
|
153
|
-
|
|
143
|
+
int32_t completionTag = 0,
|
|
154
144
|
double startedAtHintS = std::numeric_limits<double>::quiet_NaN());
|
|
155
145
|
int32_t animateSpringGroup(
|
|
156
146
|
uint64_t controllerId,
|
|
157
147
|
std::vector<GroupMotionEntry> entries,
|
|
158
148
|
SpringAnimation animation,
|
|
159
|
-
|
|
160
|
-
double startedAtHintS = std::numeric_limits<double>::quiet_NaN());
|
|
161
|
-
int32_t animateKeyframesGroup(
|
|
162
|
-
uint64_t controllerId,
|
|
163
|
-
std::vector<GroupMotionEntry> entries,
|
|
164
|
-
double durationMs,
|
|
165
|
-
int32_t reduceMotion,
|
|
166
|
-
GroupSuspensionPolicy suspensionPolicy,
|
|
149
|
+
int32_t completionTag = 0,
|
|
167
150
|
double startedAtHintS = std::numeric_limits<double>::quiet_NaN());
|
|
168
151
|
std::vector<DriverSnapshot> cancelAnimationGroup(
|
|
169
152
|
int32_t groupId,
|
|
@@ -173,24 +156,13 @@ int32_t animateTiming(
|
|
|
173
156
|
AnimationStart start,
|
|
174
157
|
Presentation presentation,
|
|
175
158
|
TimingAnimation animation,
|
|
176
|
-
|
|
177
|
-
AnimationValidationMode::ProtocolV2);
|
|
159
|
+
int32_t completionTag = 0);
|
|
178
160
|
int32_t animateSpring(
|
|
179
161
|
uint64_t driverId,
|
|
180
162
|
AnimationStart start,
|
|
181
163
|
Presentation presentation,
|
|
182
164
|
SpringAnimation animation,
|
|
183
|
-
|
|
184
|
-
AnimationValidationMode::ProtocolV2);
|
|
185
|
-
int32_t animateKeyframes(
|
|
186
|
-
uint64_t driverId,
|
|
187
|
-
AnimationStart start,
|
|
188
|
-
Presentation presentation,
|
|
189
|
-
double durationMs,
|
|
190
|
-
std::vector<Keyframe> keyframes,
|
|
191
|
-
int32_t reduceMotion,
|
|
192
|
-
AnimationValidationMode validationMode =
|
|
193
|
-
AnimationValidationMode::ProtocolV2);
|
|
165
|
+
int32_t completionTag = 0);
|
|
194
166
|
int32_t rejectAnimation(uint64_t driverId);
|
|
195
167
|
CancelResult cancelAnimation(
|
|
196
168
|
uint64_t driverId,
|
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
namespace smoothclip {
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Host-independent canonical clip geometry expressed as edges.
|
|
12
|
+
*
|
|
13
|
+
* The moving aperture is allowed to cross or sit outside any host. Hosts crop
|
|
14
|
+
* the rendered result; they never rewrite the geometry stored by the driver.
|
|
15
|
+
*/
|
|
16
|
+
struct CanonicalClip {
|
|
11
17
|
double left = 0;
|
|
12
18
|
double top = 0;
|
|
13
19
|
double right = 0;
|
|
@@ -25,71 +31,13 @@ inline double SmoothClipResolvedRadius(double overrideValue, double radius) {
|
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* Timing/keyframe renderers interpolate already-normalized native values on
|
|
31
|
-
* iOS, while Android interpolates presentation scalars and normalizes each
|
|
32
|
-
* delivered frame. Those operations commute exactly when every anchor stays
|
|
33
|
-
* inside one host and the CSS corner-overlap rule never activates. Because
|
|
34
|
-
* each condition below is linear, it also holds for every convex interpolation
|
|
35
|
-
* between accepted anchors.
|
|
34
|
+
* Canonicalizes a requested rectangle without consulting host dimensions.
|
|
36
35
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
36
|
+
* Negative dimensions collapse to zero. Corner radii follow the CSS
|
|
37
|
+
* corner-overlap rule against the requested rectangle, using one common scale
|
|
38
|
+
* factor so their proportions are preserved.
|
|
39
39
|
*/
|
|
40
|
-
inline bool
|
|
41
|
-
const Geometry &geometry,
|
|
42
|
-
double hostWidth,
|
|
43
|
-
double hostHeight) {
|
|
44
|
-
const double topLeft = SmoothClipResolvedRadius(
|
|
45
|
-
geometry.topLeftRadius, geometry.radius);
|
|
46
|
-
const double topRight = SmoothClipResolvedRadius(
|
|
47
|
-
geometry.topRightRadius, geometry.radius);
|
|
48
|
-
const double bottomRight = SmoothClipResolvedRadius(
|
|
49
|
-
geometry.bottomRightRadius, geometry.radius);
|
|
50
|
-
const double bottomLeft = SmoothClipResolvedRadius(
|
|
51
|
-
geometry.bottomLeftRadius, geometry.radius);
|
|
52
|
-
const double right = geometry.x + geometry.width;
|
|
53
|
-
const double bottom = geometry.y + geometry.height;
|
|
54
|
-
const double topRadii = topLeft + topRight;
|
|
55
|
-
const double bottomRadii = bottomLeft + bottomRight;
|
|
56
|
-
const double leftRadii = topLeft + bottomLeft;
|
|
57
|
-
const double rightRadii = topRight + bottomRight;
|
|
58
|
-
const double values[] = {
|
|
59
|
-
geometry.x,
|
|
60
|
-
geometry.y,
|
|
61
|
-
geometry.width,
|
|
62
|
-
geometry.height,
|
|
63
|
-
geometry.radius,
|
|
64
|
-
topLeft,
|
|
65
|
-
topRight,
|
|
66
|
-
bottomRight,
|
|
67
|
-
bottomLeft,
|
|
68
|
-
right,
|
|
69
|
-
bottom,
|
|
70
|
-
topRadii,
|
|
71
|
-
bottomRadii,
|
|
72
|
-
leftRadii,
|
|
73
|
-
rightRadii,
|
|
74
|
-
hostWidth,
|
|
75
|
-
hostHeight,
|
|
76
|
-
};
|
|
77
|
-
for (const double value : values) {
|
|
78
|
-
if (!std::isfinite(value)) return false;
|
|
79
|
-
}
|
|
80
|
-
return hostWidth >= 0 && hostHeight >= 0 &&
|
|
81
|
-
geometry.x >= 0 && geometry.y >= 0 &&
|
|
82
|
-
geometry.width >= 0 && geometry.height >= 0 &&
|
|
83
|
-
right <= hostWidth && bottom <= hostHeight &&
|
|
84
|
-
topLeft >= 0 && topRight >= 0 &&
|
|
85
|
-
bottomRight >= 0 && bottomLeft >= 0 &&
|
|
86
|
-
topRadii <= geometry.width &&
|
|
87
|
-
bottomRadii <= geometry.width &&
|
|
88
|
-
leftRadii <= geometry.height &&
|
|
89
|
-
rightRadii <= geometry.height;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
inline bool SmoothClipNormalizeV2(
|
|
40
|
+
inline bool SmoothClipCanonicalize(
|
|
93
41
|
double x,
|
|
94
42
|
double y,
|
|
95
43
|
double width,
|
|
@@ -100,9 +48,7 @@ inline bool SmoothClipNormalizeV2(
|
|
|
100
48
|
double bottomRightRadius,
|
|
101
49
|
double bottomLeftRadius,
|
|
102
50
|
ClipCurve curve,
|
|
103
|
-
|
|
104
|
-
double hostHeight,
|
|
105
|
-
NormalizedClip &out) {
|
|
51
|
+
CanonicalClip &out) {
|
|
106
52
|
const double resolvedTopLeft =
|
|
107
53
|
SmoothClipResolvedRadius(topLeftRadius, radius);
|
|
108
54
|
const double resolvedTopRight =
|
|
@@ -117,20 +63,19 @@ inline bool SmoothClipNormalizeV2(
|
|
|
117
63
|
!std::isfinite(resolvedTopRight) ||
|
|
118
64
|
!std::isfinite(resolvedBottomRight) ||
|
|
119
65
|
!std::isfinite(resolvedBottomLeft) ||
|
|
120
|
-
|
|
66
|
+
(curve != ClipCurve::Circular && curve != ClipCurve::Continuous)) {
|
|
121
67
|
return false;
|
|
122
68
|
}
|
|
123
69
|
|
|
124
|
-
const double
|
|
125
|
-
const double
|
|
126
|
-
const double
|
|
127
|
-
const double
|
|
128
|
-
|
|
129
|
-
out.
|
|
130
|
-
out.
|
|
131
|
-
out.
|
|
132
|
-
|
|
133
|
-
const double visibleHeight = std::max(0.0, out.bottom - out.top);
|
|
70
|
+
const double canonicalWidth = std::max(0.0, width);
|
|
71
|
+
const double canonicalHeight = std::max(0.0, height);
|
|
72
|
+
const double right = x + canonicalWidth;
|
|
73
|
+
const double bottom = y + canonicalHeight;
|
|
74
|
+
if (!std::isfinite(right) || !std::isfinite(bottom)) return false;
|
|
75
|
+
out.left = x;
|
|
76
|
+
out.top = y;
|
|
77
|
+
out.right = right;
|
|
78
|
+
out.bottom = bottom;
|
|
134
79
|
|
|
135
80
|
double topLeft = std::max(0.0, resolvedTopLeft);
|
|
136
81
|
double topRight = std::max(0.0, resolvedTopRight);
|
|
@@ -140,11 +85,12 @@ inline bool SmoothClipNormalizeV2(
|
|
|
140
85
|
const auto includeLimit = [&scale](double available, double requested) {
|
|
141
86
|
if (requested > 0) scale = std::min(scale, available / requested);
|
|
142
87
|
};
|
|
143
|
-
includeLimit(
|
|
144
|
-
includeLimit(
|
|
145
|
-
includeLimit(
|
|
146
|
-
includeLimit(
|
|
147
|
-
scale = std::
|
|
88
|
+
includeLimit(canonicalWidth, topLeft + topRight);
|
|
89
|
+
includeLimit(canonicalWidth, bottomLeft + bottomRight);
|
|
90
|
+
includeLimit(canonicalHeight, topLeft + bottomLeft);
|
|
91
|
+
includeLimit(canonicalHeight, topRight + bottomRight);
|
|
92
|
+
scale = std::clamp(scale, 0.0, 1.0);
|
|
93
|
+
|
|
148
94
|
out.topLeftRadius = topLeft * scale;
|
|
149
95
|
out.topRightRadius = topRight * scale;
|
|
150
96
|
out.bottomRightRadius = bottomRight * scale;
|
|
@@ -157,20 +103,31 @@ inline bool SmoothClipNormalizeV2(
|
|
|
157
103
|
return true;
|
|
158
104
|
}
|
|
159
105
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
106
|
+
inline bool SmoothClipCanonicalize(
|
|
107
|
+
const Geometry &geometry,
|
|
108
|
+
CanonicalClip &out) {
|
|
109
|
+
return SmoothClipCanonicalize(
|
|
110
|
+
geometry.x,
|
|
111
|
+
geometry.y,
|
|
112
|
+
geometry.width,
|
|
113
|
+
geometry.height,
|
|
114
|
+
geometry.radius,
|
|
115
|
+
geometry.topLeftRadius,
|
|
116
|
+
geometry.topRightRadius,
|
|
117
|
+
geometry.bottomRightRadius,
|
|
118
|
+
geometry.bottomLeftRadius,
|
|
119
|
+
geometry.curve,
|
|
120
|
+
out);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
inline bool SmoothClipCanonicalize(
|
|
165
124
|
double x,
|
|
166
125
|
double y,
|
|
167
126
|
double width,
|
|
168
127
|
double height,
|
|
169
128
|
double radius,
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
NormalizedClip &out) {
|
|
173
|
-
return SmoothClipNormalizeV2(
|
|
129
|
+
CanonicalClip &out) {
|
|
130
|
+
return SmoothClipCanonicalize(
|
|
174
131
|
x,
|
|
175
132
|
y,
|
|
176
133
|
width,
|
|
@@ -181,9 +138,22 @@ inline bool SmoothClipNormalize(
|
|
|
181
138
|
radius,
|
|
182
139
|
radius,
|
|
183
140
|
ClipCurve::Circular,
|
|
184
|
-
hostWidth,
|
|
185
|
-
hostHeight,
|
|
186
141
|
out);
|
|
187
142
|
}
|
|
188
143
|
|
|
144
|
+
inline Geometry SmoothClipGeometry(const CanonicalClip &clip) {
|
|
145
|
+
Geometry geometry{
|
|
146
|
+
clip.left,
|
|
147
|
+
clip.top,
|
|
148
|
+
std::max(0.0, clip.right - clip.left),
|
|
149
|
+
std::max(0.0, clip.bottom - clip.top),
|
|
150
|
+
clip.radius};
|
|
151
|
+
geometry.topLeftRadius = clip.topLeftRadius;
|
|
152
|
+
geometry.topRightRadius = clip.topRightRadius;
|
|
153
|
+
geometry.bottomRightRadius = clip.bottomRightRadius;
|
|
154
|
+
geometry.bottomLeftRadius = clip.bottomLeftRadius;
|
|
155
|
+
geometry.curve = clip.curve;
|
|
156
|
+
return geometry;
|
|
157
|
+
}
|
|
158
|
+
|
|
189
159
|
} // namespace smoothclip
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
namespace smoothclip {
|
|
7
7
|
|
|
8
8
|
// The two most recent interactive samples used by `initialVelocity: 'inherit'`.
|
|
9
|
-
// Channels are the eleven
|
|
9
|
+
// Channels are the eleven geometry/content presentation scalars. Scale is stored
|
|
10
10
|
// so histories remain coherent but excluded from velocity projection; each of
|
|
11
|
-
// the four radius channels contributes one quarter of the
|
|
12
|
-
//
|
|
13
|
-
// projection only needs both samples and the target in the same space.
|
|
11
|
+
// the four radius channels contributes one quarter of the uniform-radius weight.
|
|
12
|
+
// Both platforms record raw canonical geometry, including off-host coordinates.
|
|
13
|
+
// The projection only needs both samples and the target in the same space.
|
|
14
14
|
// Shared by ios/SmoothClipView.mm and android/.../SmoothClipRegistry.cpp; a
|
|
15
15
|
// behavior change here changes both platforms.
|
|
16
16
|
struct VelocitySampleHistory {
|
|
@@ -69,7 +69,7 @@ inline void recordVelocitySample(
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
// Only explicit interactive writes route through this recorder. Native
|
|
72
|
-
// freeze
|
|
72
|
+
// Native freeze and endpoint-finalization paths deliberately do not, so an
|
|
73
73
|
// animation cannot manufacture a later inherited velocity. During ordinary
|
|
74
74
|
// interaction, the staleness decay below is the forgetting mechanism and it
|
|
75
75
|
// forgets gradually rather than all at once.
|
package/ios/SmoothClipGeometry.h
CHANGED
|
@@ -16,12 +16,11 @@ typedef NS_ENUM(NSInteger, SmoothClipCornerCurve) {
|
|
|
16
16
|
|
|
17
17
|
typedef struct {
|
|
18
18
|
CGRect rect;
|
|
19
|
-
//
|
|
20
|
-
// `radii`; this field is zero when the normalized radii are unequal.
|
|
19
|
+
// Uniform-radius fast-path value; zero when canonical radii are unequal.
|
|
21
20
|
CGFloat radius;
|
|
22
21
|
SmoothClipCornerRadii radii;
|
|
23
22
|
SmoothClipCornerCurve curve;
|
|
24
|
-
}
|
|
23
|
+
} SmoothClipCanonicalGeometry;
|
|
25
24
|
|
|
26
25
|
NS_INLINE BOOL SmoothClipCornerRadiiEqual(
|
|
27
26
|
SmoothClipCornerRadii first,
|
|
@@ -48,13 +47,13 @@ NS_INLINE CGFloat SmoothClipSafeOverlapFactor(
|
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
/**
|
|
51
|
-
*
|
|
50
|
+
* Canonicalizes the rectangle and four radii without allocating.
|
|
52
51
|
*
|
|
53
52
|
* The proportional overlap rule matches CSS border radii and the shared
|
|
54
53
|
* Android/C++ contract: all corners use one scale factor, preserving their
|
|
55
54
|
* relative shape while no opposing pair exceeds its edge.
|
|
56
55
|
*/
|
|
57
|
-
NS_INLINE BOOL
|
|
56
|
+
NS_INLINE BOOL SmoothClipCanonicalizeGeometry(
|
|
58
57
|
CGFloat x,
|
|
59
58
|
CGFloat y,
|
|
60
59
|
CGFloat width,
|
|
@@ -64,30 +63,21 @@ NS_INLINE BOOL SmoothClipNormalizeGeometryV2(
|
|
|
64
63
|
CGFloat bottomRightRadius,
|
|
65
64
|
CGFloat bottomLeftRadius,
|
|
66
65
|
NSInteger curveCode,
|
|
67
|
-
|
|
68
|
-
SmoothNormalizedClipGeometry *result) {
|
|
66
|
+
SmoothClipCanonicalGeometry *result) {
|
|
69
67
|
if (!isfinite(x) || !isfinite(y) || !isfinite(width) ||
|
|
70
68
|
!isfinite(height) || !isfinite(topLeftRadius) ||
|
|
71
69
|
!isfinite(topRightRadius) || !isfinite(bottomRightRadius) ||
|
|
72
|
-
!isfinite(bottomLeftRadius) ||
|
|
73
|
-
!isfinite(hostSize.height) ||
|
|
70
|
+
!isfinite(bottomLeftRadius) ||
|
|
74
71
|
(curveCode != SmoothClipCornerCurveCircular &&
|
|
75
72
|
curveCode != SmoothClipCornerCurveContinuous)) {
|
|
76
73
|
return NO;
|
|
77
74
|
}
|
|
78
75
|
|
|
79
|
-
const CGFloat hostWidth = MAX(0, hostSize.width);
|
|
80
|
-
const CGFloat hostHeight = MAX(0, hostSize.height);
|
|
81
76
|
const CGFloat requestedWidth = MAX(0, width);
|
|
82
77
|
const CGFloat requestedHeight = MAX(0, height);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const CGFloat top = MIN(hostHeight, MAX(0, y));
|
|
87
|
-
const CGFloat right = MIN(hostWidth, MAX(0, requestedRight));
|
|
88
|
-
const CGFloat bottom = MIN(hostHeight, MAX(0, requestedBottom));
|
|
89
|
-
const CGFloat visibleWidth = MAX(0, right - left);
|
|
90
|
-
const CGFloat visibleHeight = MAX(0, bottom - top);
|
|
78
|
+
if (!isfinite(x + requestedWidth) || !isfinite(y + requestedHeight)) {
|
|
79
|
+
return NO;
|
|
80
|
+
}
|
|
91
81
|
|
|
92
82
|
SmoothClipCornerRadii radii = {
|
|
93
83
|
MAX(0, topLeftRadius),
|
|
@@ -100,20 +90,20 @@ NS_INLINE BOOL SmoothClipNormalizeGeometryV2(
|
|
|
100
90
|
MIN(
|
|
101
91
|
MIN(
|
|
102
92
|
SmoothClipSafeOverlapFactor(
|
|
103
|
-
|
|
93
|
+
requestedWidth, radii.topLeft, radii.topRight),
|
|
104
94
|
SmoothClipSafeOverlapFactor(
|
|
105
|
-
|
|
95
|
+
requestedWidth, radii.bottomLeft, radii.bottomRight)),
|
|
106
96
|
MIN(
|
|
107
97
|
SmoothClipSafeOverlapFactor(
|
|
108
|
-
|
|
98
|
+
requestedHeight, radii.topLeft, radii.bottomLeft),
|
|
109
99
|
SmoothClipSafeOverlapFactor(
|
|
110
|
-
|
|
100
|
+
requestedHeight, radii.topRight, radii.bottomRight))));
|
|
111
101
|
radii.topLeft *= overlapScale;
|
|
112
102
|
radii.topRight *= overlapScale;
|
|
113
103
|
radii.bottomRight *= overlapScale;
|
|
114
104
|
radii.bottomLeft *= overlapScale;
|
|
115
105
|
|
|
116
|
-
result->rect = CGRectMake(
|
|
106
|
+
result->rect = CGRectMake(x, y, requestedWidth, requestedHeight);
|
|
117
107
|
result->radii = radii;
|
|
118
108
|
result->radius = SmoothClipCornerRadiiAreUniform(radii)
|
|
119
109
|
? radii.topLeft
|
|
@@ -123,15 +113,14 @@ NS_INLINE BOOL SmoothClipNormalizeGeometryV2(
|
|
|
123
113
|
}
|
|
124
114
|
|
|
125
115
|
/** Mirrors the Android and JavaScript geometry contract without allocating. */
|
|
126
|
-
NS_INLINE BOOL
|
|
116
|
+
NS_INLINE BOOL SmoothClipCanonicalizeGeometry(
|
|
127
117
|
CGFloat x,
|
|
128
118
|
CGFloat y,
|
|
129
119
|
CGFloat width,
|
|
130
120
|
CGFloat height,
|
|
131
121
|
CGFloat radius,
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return SmoothClipNormalizeGeometryV2(
|
|
122
|
+
SmoothClipCanonicalGeometry *result) {
|
|
123
|
+
return SmoothClipCanonicalizeGeometry(
|
|
135
124
|
x,
|
|
136
125
|
y,
|
|
137
126
|
width,
|
|
@@ -141,20 +130,21 @@ NS_INLINE BOOL SmoothClipNormalizeGeometry(
|
|
|
141
130
|
radius,
|
|
142
131
|
radius,
|
|
143
132
|
SmoothClipCornerCurveCircular,
|
|
144
|
-
hostSize,
|
|
145
133
|
result);
|
|
146
134
|
}
|
|
147
135
|
|
|
148
136
|
/**
|
|
149
|
-
* Creates
|
|
150
|
-
*
|
|
151
|
-
* zero-radius corner, so Core Animation can interpolate paths
|
|
152
|
-
* topology change.
|
|
137
|
+
* Creates an empty path for an empty clip. Non-empty rounded rectangles use a
|
|
138
|
+
* stable nine-segment topology. Every corner is one cubic, including a
|
|
139
|
+
* zero-radius corner, so Core Animation can interpolate non-empty paths
|
|
140
|
+
* without a topology change.
|
|
153
141
|
*/
|
|
154
142
|
NS_INLINE CGPathRef SmoothClipCreateRoundedRectPath(
|
|
155
143
|
CGRect rect,
|
|
156
144
|
SmoothClipCornerRadii radii,
|
|
157
145
|
SmoothClipCornerCurve curve) CF_RETURNS_RETAINED {
|
|
146
|
+
CGMutablePathRef path = CGPathCreateMutable();
|
|
147
|
+
if (CGRectIsEmpty(rect)) return path;
|
|
158
148
|
const CGFloat minX = CGRectGetMinX(rect);
|
|
159
149
|
const CGFloat minY = CGRectGetMinY(rect);
|
|
160
150
|
const CGFloat maxX = CGRectGetMaxX(rect);
|
|
@@ -171,7 +161,6 @@ NS_INLINE CGPathRef SmoothClipCreateRoundedRectPath(
|
|
|
171
161
|
? 1.0
|
|
172
162
|
: 0.5522847498307936;
|
|
173
163
|
|
|
174
|
-
CGMutablePathRef path = CGPathCreateMutable();
|
|
175
164
|
CGPathMoveToPoint(path, NULL, minX + radii.topLeft, minY);
|
|
176
165
|
CGPathAddLineToPoint(path, NULL, maxX - radii.topRight, minY);
|
|
177
166
|
CGPathAddCurveToPoint(
|