1 /*
<lambda>null2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.compose.material3.internal
18 
19 import androidx.compose.ui.Modifier
20 import androidx.compose.ui.node.ModifierNodeElement
21 import androidx.compose.ui.node.SemanticsModifierNode
22 import androidx.compose.ui.node.TraversableNode
23 import androidx.compose.ui.node.invalidateSemantics
24 import androidx.compose.ui.node.traverseAncestors
25 import androidx.compose.ui.platform.InspectorInfo
26 import androidx.compose.ui.semantics.SemanticsPropertyReceiver
27 
28 internal fun Modifier.childSemantics(properties: SemanticsPropertyReceiver.() -> Unit = {}) =
29     this then ChildSemanticsNodeElement(properties)
30 
parentSemanticsnull31 internal fun Modifier.parentSemantics(properties: SemanticsPropertyReceiver.() -> Unit) =
32     this then ParentSemanticsNodeElement(properties)
33 
34 internal class ChildSemanticsNodeElement(val properties: SemanticsPropertyReceiver.() -> Unit) :
35     ModifierNodeElement<ChildSemanticsNode>() {
36     override fun create(): ChildSemanticsNode = ChildSemanticsNode(properties)
37 
38     override fun update(node: ChildSemanticsNode) {
39         node.properties = properties
40         node.invalidateSemantics()
41     }
42 
43     override fun InspectorInfo.inspectableProperties() {
44         name = "childSemantics"
45         this@inspectableProperties.properties["properties"] =
46             this@ChildSemanticsNodeElement.properties
47     }
48 
49     override fun equals(other: Any?): Boolean {
50         if (this === other) return true
51         if (other !is ChildSemanticsNodeElement) return false
52 
53         return properties === other.properties
54     }
55 
56     override fun hashCode(): Int {
57         return properties.hashCode()
58     }
59 }
60 
61 internal class ParentSemanticsNodeElement(val properties: SemanticsPropertyReceiver.() -> Unit) :
62     ModifierNodeElement<ParentSemanticsNode>() {
createnull63     override fun create(): ParentSemanticsNode = ParentSemanticsNode(properties)
64 
65     override fun update(node: ParentSemanticsNode) {
66         node.properties = properties
67         node.invalidateSemantics()
68     }
69 
inspectablePropertiesnull70     override fun InspectorInfo.inspectableProperties() {
71         name = "parentSemantics"
72         this@inspectableProperties.properties["properties"] =
73             this@ParentSemanticsNodeElement.properties
74     }
75 
equalsnull76     override fun equals(other: Any?): Boolean {
77         if (this === other) return true
78         if (other !is ParentSemanticsNodeElement) return false
79 
80         return properties === other.properties
81     }
82 
hashCodenull83     override fun hashCode(): Int {
84         return properties.hashCode()
85     }
86 }
87 
88 internal class ChildSemanticsNode(var properties: SemanticsPropertyReceiver.() -> Unit) :
89     Modifier.Node(), SemanticsModifierNode {
90 
applySemanticsnull91     override fun SemanticsPropertyReceiver.applySemantics() {
92         traverseAncestors(ParentSemanticsNodeKey) { node ->
93             with(node as ParentSemanticsNode) {
94                 obtainSemantics()
95                 false
96             }
97         }
98         properties()
99     }
100 
onDetachnull101     override fun onDetach() {
102         super.onDetach()
103         traverseAncestors(ParentSemanticsNodeKey) { node ->
104             (node as ParentSemanticsNode)
105             node.releaseSemantics()
106             false
107         }
108     }
109 }
110 
111 internal class ParentSemanticsNode(var properties: SemanticsPropertyReceiver.() -> Unit) :
112     Modifier.Node(), TraversableNode, SemanticsModifierNode {
113 
114     private var semanticsConsumed: Boolean = false
115 
116     override val shouldMergeDescendantSemantics: Boolean
117         get() = true
118 
119     override val traverseKey: Any = ParentSemanticsNodeKey
120 
applySemanticsnull121     override fun SemanticsPropertyReceiver.applySemantics() {
122         if (!semanticsConsumed) {
123             properties()
124         }
125     }
126 
SemanticsPropertyReceivernull127     fun SemanticsPropertyReceiver.obtainSemantics() {
128         semanticsConsumed = true
129         properties()
130         invalidateSemantics()
131     }
132 
releaseSemanticsnull133     fun releaseSemantics() {
134         semanticsConsumed = false
135         invalidateSemantics()
136     }
137 }
138 
139 internal object ParentSemanticsNodeKey
140