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
|
@@ -4,23 +4,20 @@ import android.graphics.Path
|
|
|
4
4
|
import android.view.View
|
|
5
5
|
import kotlin.math.max
|
|
6
6
|
import kotlin.math.min
|
|
7
|
-
import kotlin.math.roundToInt
|
|
8
7
|
|
|
9
8
|
internal const val CLIP_CURVE_CIRCULAR = 0
|
|
10
9
|
internal const val CLIP_CURVE_CONTINUOUS = 1
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* Canonicalizes raw clip geometry without allocating a result object. Host
|
|
13
|
+
* bounds deliberately do not participate; SmoothClipView crops at draw time.
|
|
15
14
|
*/
|
|
16
|
-
internal inline fun
|
|
15
|
+
internal inline fun canonicalizeClipGeometryPx(
|
|
17
16
|
x: Float,
|
|
18
17
|
y: Float,
|
|
19
18
|
width: Float,
|
|
20
19
|
height: Float,
|
|
21
20
|
radius: Float,
|
|
22
|
-
hostWidth: Float,
|
|
23
|
-
hostHeight: Float,
|
|
24
21
|
apply: (
|
|
25
22
|
left: Float,
|
|
26
23
|
top: Float,
|
|
@@ -30,38 +27,32 @@ internal inline fun normalizeClipGeometryPx(
|
|
|
30
27
|
) -> Unit,
|
|
31
28
|
): Boolean {
|
|
32
29
|
if (!x.isFinite() || !y.isFinite() || !width.isFinite() ||
|
|
33
|
-
!height.isFinite() || !radius.isFinite()
|
|
34
|
-
!hostWidth.isFinite() || !hostHeight.isFinite()
|
|
30
|
+
!height.isFinite() || !radius.isFinite()
|
|
35
31
|
) {
|
|
36
32
|
return false
|
|
37
33
|
}
|
|
38
34
|
|
|
39
|
-
val
|
|
40
|
-
val
|
|
41
|
-
val
|
|
42
|
-
val
|
|
43
|
-
|
|
44
|
-
val
|
|
45
|
-
val right = requestedRight.coerceIn(0f, boundedHostWidth)
|
|
46
|
-
val bottom = requestedBottom.coerceIn(0f, boundedHostHeight)
|
|
47
|
-
val visibleWidth = max(0f, right - left)
|
|
48
|
-
val visibleHeight = max(0f, bottom - top)
|
|
49
|
-
val normalizedRadius = min(
|
|
35
|
+
val canonicalWidth = max(0f, width)
|
|
36
|
+
val canonicalHeight = max(0f, height)
|
|
37
|
+
val right = x + canonicalWidth
|
|
38
|
+
val bottom = y + canonicalHeight
|
|
39
|
+
if (!right.isFinite() || !bottom.isFinite()) return false
|
|
40
|
+
val canonicalRadius = min(
|
|
50
41
|
radius.coerceAtLeast(0f),
|
|
51
|
-
min(
|
|
42
|
+
min(canonicalWidth, canonicalHeight) / 2f,
|
|
52
43
|
)
|
|
53
44
|
|
|
54
|
-
apply(
|
|
45
|
+
apply(x, y, right, bottom, canonicalRadius)
|
|
55
46
|
return true
|
|
56
47
|
}
|
|
57
48
|
|
|
58
49
|
/**
|
|
59
|
-
*
|
|
50
|
+
* Canonicalization with independent radii. Radii use the CSS overlap rule:
|
|
60
51
|
* one shared factor keeps all four corners proportional when any opposing pair
|
|
61
|
-
* exceeds the
|
|
62
|
-
* the shared C++ delivery path.
|
|
52
|
+
* exceeds the requested width or height. This mirrors
|
|
53
|
+
* SmoothClipCanonicalize in the shared C++ delivery path.
|
|
63
54
|
*/
|
|
64
|
-
internal inline fun
|
|
55
|
+
internal inline fun canonicalizeClipGeometryPx(
|
|
65
56
|
x: Float,
|
|
66
57
|
y: Float,
|
|
67
58
|
width: Float,
|
|
@@ -71,40 +62,32 @@ internal inline fun normalizeClipGeometryV2Px(
|
|
|
71
62
|
bottomRightRadius: Float,
|
|
72
63
|
bottomLeftRadius: Float,
|
|
73
64
|
curveCode: Int,
|
|
74
|
-
hostWidth: Float,
|
|
75
|
-
hostHeight: Float,
|
|
76
65
|
apply: (
|
|
77
66
|
left: Float,
|
|
78
67
|
top: Float,
|
|
79
68
|
right: Float,
|
|
80
69
|
bottom: Float,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
70
|
+
canonicalTopLeftRadius: Float,
|
|
71
|
+
canonicalTopRightRadius: Float,
|
|
72
|
+
canonicalBottomRightRadius: Float,
|
|
73
|
+
canonicalBottomLeftRadius: Float,
|
|
74
|
+
canonicalCurveCode: Int,
|
|
86
75
|
) -> Unit,
|
|
87
76
|
): Boolean {
|
|
88
77
|
if (!x.isFinite() || !y.isFinite() || !width.isFinite() ||
|
|
89
78
|
!height.isFinite() || !topLeftRadius.isFinite() ||
|
|
90
79
|
!topRightRadius.isFinite() || !bottomRightRadius.isFinite() ||
|
|
91
|
-
!bottomLeftRadius.isFinite() ||
|
|
92
|
-
!hostHeight.isFinite() ||
|
|
80
|
+
!bottomLeftRadius.isFinite() ||
|
|
93
81
|
(curveCode != CLIP_CURVE_CIRCULAR && curveCode != CLIP_CURVE_CONTINUOUS)
|
|
94
82
|
) {
|
|
95
83
|
return false
|
|
96
84
|
}
|
|
97
85
|
|
|
98
|
-
val
|
|
99
|
-
val
|
|
100
|
-
val
|
|
101
|
-
val
|
|
102
|
-
|
|
103
|
-
val top = y.coerceIn(0f, boundedHostHeight)
|
|
104
|
-
val right = requestedRight.coerceIn(0f, boundedHostWidth)
|
|
105
|
-
val bottom = requestedBottom.coerceIn(0f, boundedHostHeight)
|
|
106
|
-
val visibleWidth = max(0f, right - left)
|
|
107
|
-
val visibleHeight = max(0f, bottom - top)
|
|
86
|
+
val canonicalWidth = max(0f, width)
|
|
87
|
+
val canonicalHeight = max(0f, height)
|
|
88
|
+
val right = x + canonicalWidth
|
|
89
|
+
val bottom = y + canonicalHeight
|
|
90
|
+
if (!right.isFinite() || !bottom.isFinite()) return false
|
|
108
91
|
val topLeft = topLeftRadius.coerceAtLeast(0f)
|
|
109
92
|
val topRight = topRightRadius.coerceAtLeast(0f)
|
|
110
93
|
val bottomRight = bottomRightRadius.coerceAtLeast(0f)
|
|
@@ -115,15 +98,15 @@ internal inline fun normalizeClipGeometryV2Px(
|
|
|
115
98
|
val bottomWidth = bottomLeft + bottomRight
|
|
116
99
|
val leftHeight = topLeft + bottomLeft
|
|
117
100
|
val rightHeight = topRight + bottomRight
|
|
118
|
-
if (topWidth > 0f) radiusScale = min(radiusScale,
|
|
119
|
-
if (bottomWidth > 0f) radiusScale = min(radiusScale,
|
|
120
|
-
if (leftHeight > 0f) radiusScale = min(radiusScale,
|
|
121
|
-
if (rightHeight > 0f) radiusScale = min(radiusScale,
|
|
101
|
+
if (topWidth > 0f) radiusScale = min(radiusScale, canonicalWidth / topWidth)
|
|
102
|
+
if (bottomWidth > 0f) radiusScale = min(radiusScale, canonicalWidth / bottomWidth)
|
|
103
|
+
if (leftHeight > 0f) radiusScale = min(radiusScale, canonicalHeight / leftHeight)
|
|
104
|
+
if (rightHeight > 0f) radiusScale = min(radiusScale, canonicalHeight / rightHeight)
|
|
122
105
|
radiusScale = radiusScale.coerceIn(0f, 1f)
|
|
123
106
|
|
|
124
107
|
apply(
|
|
125
|
-
|
|
126
|
-
|
|
108
|
+
x,
|
|
109
|
+
y,
|
|
127
110
|
right,
|
|
128
111
|
bottom,
|
|
129
112
|
topLeft * radiusScale,
|
|
@@ -136,7 +119,7 @@ internal inline fun normalizeClipGeometryV2Px(
|
|
|
136
119
|
}
|
|
137
120
|
|
|
138
121
|
/**
|
|
139
|
-
* Emits one fixed-topology rounded rectangle for both
|
|
122
|
+
* Emits one fixed-topology rounded rectangle for both curve families.
|
|
140
123
|
* Circular uses the standard quarter-circle cubic coefficient; continuous
|
|
141
124
|
* keeps both control points at the rectangle corner (coefficient 1), yielding
|
|
142
125
|
* zero endpoint curvature and a visibly smoother shoulder. "Continuous" is a
|
|
@@ -245,153 +228,8 @@ internal fun containsPathPoint(path: Path, x: Float, y: Float): Boolean {
|
|
|
245
228
|
return inside
|
|
246
229
|
}
|
|
247
230
|
|
|
248
|
-
internal fun
|
|
249
|
-
|
|
250
|
-
y: Float,
|
|
251
|
-
left: Float,
|
|
252
|
-
top: Float,
|
|
253
|
-
right: Float,
|
|
254
|
-
bottom: Float,
|
|
255
|
-
topLeftRadius: Float,
|
|
256
|
-
topRightRadius: Float,
|
|
257
|
-
bottomRightRadius: Float,
|
|
258
|
-
bottomLeftRadius: Float,
|
|
259
|
-
curveCode: Int,
|
|
260
|
-
isEmpty: Boolean,
|
|
261
|
-
): Boolean {
|
|
262
|
-
if (isEmpty || x < left || x > right || y < top || y > bottom) return false
|
|
263
|
-
|
|
264
|
-
fun containsCorner(inwardX: Float, inwardY: Float): Boolean {
|
|
265
|
-
if (curveCode == CLIP_CURVE_CIRCULAR) {
|
|
266
|
-
val dx = inwardX - 1f
|
|
267
|
-
val dy = inwardY - 1f
|
|
268
|
-
return dx * dx + dy * dy <= 1f
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Invert the rendered cubic's inward-x component. This runs only for
|
|
272
|
-
// ACTION_DOWN hit testing, never on the animation/render hot path.
|
|
273
|
-
var low = 0f
|
|
274
|
-
var high = 1f
|
|
275
|
-
repeat(12) {
|
|
276
|
-
val t = (low + high) / 2f
|
|
277
|
-
val inverse = 1f - t
|
|
278
|
-
val boundaryInwardX = inverse * inverse * inverse
|
|
279
|
-
if (boundaryInwardX > inwardX) {
|
|
280
|
-
low = t
|
|
281
|
-
} else {
|
|
282
|
-
high = t
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
val t = (low + high) / 2f
|
|
286
|
-
val boundaryInwardY = t * t * t
|
|
287
|
-
return inwardY >= boundaryInwardY
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
if (topLeftRadius > 0f && x < left + topLeftRadius && y < top + topLeftRadius) {
|
|
291
|
-
return containsCorner(
|
|
292
|
-
(x - left) / topLeftRadius,
|
|
293
|
-
(y - top) / topLeftRadius,
|
|
294
|
-
)
|
|
295
|
-
}
|
|
296
|
-
if (topRightRadius > 0f && x > right - topRightRadius && y < top + topRightRadius) {
|
|
297
|
-
return containsCorner(
|
|
298
|
-
(right - x) / topRightRadius,
|
|
299
|
-
(y - top) / topRightRadius,
|
|
300
|
-
)
|
|
301
|
-
}
|
|
302
|
-
if (bottomRightRadius > 0f &&
|
|
303
|
-
x > right - bottomRightRadius && y > bottom - bottomRightRadius
|
|
304
|
-
) {
|
|
305
|
-
return containsCorner(
|
|
306
|
-
(right - x) / bottomRightRadius,
|
|
307
|
-
(bottom - y) / bottomRightRadius,
|
|
308
|
-
)
|
|
309
|
-
}
|
|
310
|
-
if (bottomLeftRadius > 0f && x < left + bottomLeftRadius && y > bottom - bottomLeftRadius) {
|
|
311
|
-
return containsCorner(
|
|
312
|
-
(x - left) / bottomLeftRadius,
|
|
313
|
-
(bottom - y) / bottomLeftRadius,
|
|
314
|
-
)
|
|
315
|
-
}
|
|
316
|
-
return true
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
internal fun clipVisibility(isEmpty: Boolean): Int =
|
|
320
|
-
if (isEmpty) View.INVISIBLE else View.VISIBLE
|
|
321
|
-
|
|
322
|
-
/** Rounded integer origin of an outline edge. */
|
|
323
|
-
internal fun outlineOrigin(value: Float): Int = value.roundToInt()
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Rounded far edge, derived from the rounded origin plus the rounded extent.
|
|
327
|
-
*
|
|
328
|
-
* `Outline.setRoundRect` takes an int rect, and rounding the two edges
|
|
329
|
-
* independently makes `round(far) - round(origin)` alternate between the floor
|
|
330
|
-
* and the ceil of a *constant* extent as the origin's fraction sweeps: a pure
|
|
331
|
-
* translation breathes the emitted size by 1 px, frame after frame, while the
|
|
332
|
-
* content inside translates in floats. That oscillation is what reads as
|
|
333
|
-
* shimmer on the slow tail of an animation, where the per-frame delta drops
|
|
334
|
-
* below a pixel and the rounding becomes the motion.
|
|
335
|
-
*
|
|
336
|
-
* An int rect cannot hold origin, far edge and extent within half a pixel at
|
|
337
|
-
* once (extent = far - origin, so bounding both edges at 0.5 bounds the extent
|
|
338
|
-
* at 1.0); the only choice is which error oscillates. Deriving the far edge
|
|
339
|
-
* makes the emitted extent a pure function of the true extent — stable, error
|
|
340
|
-
* <= 0.5 px — and moves the slack onto the far edge, <= 1.0 px and static. A
|
|
341
|
-
* static bias does not read as jank; an alternating one does.
|
|
342
|
-
*
|
|
343
|
-
* Two consequences, both benign:
|
|
344
|
-
* - The far edge can overshoot the host bound by up to 1 px instead of 0.5. The
|
|
345
|
-
* view's own bounds already clip, so an over-large outline just means that
|
|
346
|
-
* edge is not clipped that frame — which independent rounding already
|
|
347
|
-
* produced whenever `round(far)` rounded up.
|
|
348
|
-
* - A sub-pixel extent (0 < extent < 0.5) rounds to a degenerate rect, which
|
|
349
|
-
* `Outline.setRoundRect` collapses to `setEmpty()`. Independent rounding hit
|
|
350
|
-
* that state on some frames and a 1 px rect on others, i.e. it flickered;
|
|
351
|
-
* deriving the far edge makes it consistent. The emitted integer rect also
|
|
352
|
-
* governs visibility, accessibility and hit testing, so a view never remains
|
|
353
|
-
* logically visible while its outline clips every pixel.
|
|
354
|
-
*/
|
|
355
|
-
internal fun outlineFarEdge(origin: Float, far: Float): Int =
|
|
356
|
-
outlineOrigin(origin) + (far - origin).roundToInt()
|
|
357
|
-
|
|
358
|
-
/** Exactly mirrors the non-empty requirement of Outline.setRoundRect(Int...). */
|
|
359
|
-
internal fun outlineRectIsEmpty(
|
|
360
|
-
left: Int,
|
|
361
|
-
top: Int,
|
|
362
|
-
right: Int,
|
|
363
|
-
bottom: Int,
|
|
364
|
-
): Boolean = right <= left || bottom <= top
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Outline dedupe on the rounded integer physical-pixel edges actually emitted
|
|
368
|
-
* to the outline provider. Takes the already-derived edges rather than raw
|
|
369
|
-
* floats so the caller rounds once per frame and the predicate can never drift
|
|
370
|
-
* from what the provider emits; the radius stays a float comparison because it
|
|
371
|
-
* is emitted to the outline as a float.
|
|
372
|
-
*
|
|
373
|
-
* Sub-pixel motion that rounds to the cached integers must NOT invalidate the
|
|
374
|
-
* outline — it is carried on the view's translation instead (see
|
|
375
|
-
* SmoothClipView.applyClipPlacement), which is both cheaper and smoother than
|
|
376
|
-
* restaging an identical rect.
|
|
377
|
-
*/
|
|
378
|
-
internal fun outlineChanged(
|
|
379
|
-
left: Int,
|
|
380
|
-
top: Int,
|
|
381
|
-
right: Int,
|
|
382
|
-
bottom: Int,
|
|
383
|
-
radius: Float,
|
|
384
|
-
cachedLeft: Int,
|
|
385
|
-
cachedTop: Int,
|
|
386
|
-
cachedRight: Int,
|
|
387
|
-
cachedBottom: Int,
|
|
388
|
-
cachedRadius: Float,
|
|
389
|
-
): Boolean =
|
|
390
|
-
left != cachedLeft ||
|
|
391
|
-
top != cachedTop ||
|
|
392
|
-
right != cachedRight ||
|
|
393
|
-
bottom != cachedBottom ||
|
|
394
|
-
radius != cachedRadius
|
|
231
|
+
internal fun renderVisibility(rendersIntoHost: Boolean): Int =
|
|
232
|
+
if (rendersIntoHost) View.VISIBLE else View.INVISIBLE
|
|
395
233
|
|
|
396
234
|
internal fun clipAccessibility(
|
|
397
235
|
isEmpty: Boolean,
|
|
@@ -402,32 +240,3 @@ internal fun clipAccessibility(
|
|
|
402
240
|
} else {
|
|
403
241
|
requestedAccessibility
|
|
404
242
|
}
|
|
405
|
-
|
|
406
|
-
internal fun containsRoundedPointPx(
|
|
407
|
-
x: Float,
|
|
408
|
-
y: Float,
|
|
409
|
-
left: Float,
|
|
410
|
-
top: Float,
|
|
411
|
-
right: Float,
|
|
412
|
-
bottom: Float,
|
|
413
|
-
radius: Float,
|
|
414
|
-
isEmpty: Boolean,
|
|
415
|
-
): Boolean {
|
|
416
|
-
if (isEmpty || x < left || x > right || y < top || y > bottom) {
|
|
417
|
-
return false
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
if (radius <= 0f) return true
|
|
421
|
-
|
|
422
|
-
val innerLeft = left + radius
|
|
423
|
-
val innerRight = right - radius
|
|
424
|
-
val innerTop = top + radius
|
|
425
|
-
val innerBottom = bottom - radius
|
|
426
|
-
if (x in innerLeft..innerRight || y in innerTop..innerBottom) return true
|
|
427
|
-
|
|
428
|
-
val centerX = if (x < innerLeft) innerLeft else innerRight
|
|
429
|
-
val centerY = if (y < innerTop) innerTop else innerBottom
|
|
430
|
-
val dx = x - centerX
|
|
431
|
-
val dy = y - centerY
|
|
432
|
-
return dx * dx + dy * dy <= radius * radius
|
|
433
|
-
}
|
|
@@ -20,22 +20,6 @@ internal object SmoothClipBindings {
|
|
|
20
20
|
external fun getBindingsInstaller(): BindingsInstallerHolder
|
|
21
21
|
|
|
22
22
|
external fun nativeRegisterView(
|
|
23
|
-
driverId: Double,
|
|
24
|
-
view: SmoothClipView,
|
|
25
|
-
x: Double,
|
|
26
|
-
y: Double,
|
|
27
|
-
width: Double,
|
|
28
|
-
height: Double,
|
|
29
|
-
radius: Double,
|
|
30
|
-
contentTranslateX: Double,
|
|
31
|
-
contentTranslateY: Double,
|
|
32
|
-
density: Double,
|
|
33
|
-
widthPx: Double,
|
|
34
|
-
heightPx: Double,
|
|
35
|
-
lifecycleVisible: Boolean,
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
external fun nativeRegisterViewV2(
|
|
39
23
|
driverId: Double,
|
|
40
24
|
view: SmoothClipView,
|
|
41
25
|
x: Double,
|
|
@@ -50,6 +34,15 @@ internal object SmoothClipBindings {
|
|
|
50
34
|
contentTranslateX: Double,
|
|
51
35
|
contentTranslateY: Double,
|
|
52
36
|
contentScale: Double,
|
|
37
|
+
shadowEnabled: Boolean,
|
|
38
|
+
shadowRed: Double,
|
|
39
|
+
shadowGreen: Double,
|
|
40
|
+
shadowBlue: Double,
|
|
41
|
+
shadowAlpha: Double,
|
|
42
|
+
shadowOffsetX: Double,
|
|
43
|
+
shadowOffsetY: Double,
|
|
44
|
+
shadowBlurRadius: Double,
|
|
45
|
+
shadowSpreadDistance: Double,
|
|
53
46
|
density: Double,
|
|
54
47
|
widthPx: Double,
|
|
55
48
|
heightPx: Double,
|
|
@@ -57,8 +50,9 @@ internal object SmoothClipBindings {
|
|
|
57
50
|
)
|
|
58
51
|
|
|
59
52
|
/**
|
|
60
|
-
* Pushes a registered view's density and pixel host size
|
|
61
|
-
*
|
|
53
|
+
* Pushes a registered view's density and pixel host size. Density converts
|
|
54
|
+
* raw DIP presentations to pixels; host size controls readiness and the
|
|
55
|
+
* fixed rendering viewport, but never rewrites registry geometry.
|
|
62
56
|
*/
|
|
63
57
|
external fun nativeSetViewHostGeometry(
|
|
64
58
|
driverId: Double,
|
|
@@ -70,9 +64,12 @@ internal object SmoothClipBindings {
|
|
|
70
64
|
|
|
71
65
|
external fun nativeUnregisterView(driverId: Double, view: SmoothClipView)
|
|
72
66
|
|
|
67
|
+
/** Destroys a controller after [SmoothClipModule] forwards teardown to main. */
|
|
68
|
+
external fun nativeDestroyDriver(driverId: Double)
|
|
69
|
+
|
|
73
70
|
/**
|
|
74
71
|
* Pushes both positive and negative attachment/window-visibility state.
|
|
75
|
-
* The registry combines it with real host geometry before a
|
|
72
|
+
* The registry combines it with real host geometry before a pending run starts.
|
|
76
73
|
*/
|
|
77
74
|
external fun nativeSetViewLifecycleVisibility(
|
|
78
75
|
driverId: Double,
|