Merge "VisualTransformation API review" into androidx-main
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/ComposeVariousInputField.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/ComposeVariousInputField.kt
index 68d298b..4a94c53 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/ComposeVariousInputField.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/ComposeVariousInputField.kt
@@ -34,7 +34,7 @@
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.input.ImeAction
 import androidx.compose.ui.text.input.KeyboardType
-import androidx.compose.ui.text.input.OffsetMap
+import androidx.compose.ui.text.input.OffsetMapping
 import androidx.compose.ui.text.input.PasswordVisualTransformation
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.text.input.TransformedText
@@ -47,7 +47,7 @@
  *
  * @see creditCardFilter
  */
-private val creditCardOffsetTranslator = object : OffsetMap {
+private val creditCardOffsetTranslator = object : OffsetMapping {
     override fun originalToTransformed(offset: Int): Int {
         if (offset <= 3) return offset
         if (offset <= 7) return offset + 1
@@ -86,7 +86,7 @@
 /**
  * The offset translator which works for all offset keep remains the same.
  */
-private val identityTranslater = object : OffsetMap {
+private val identityTranslator = object : OffsetMapping {
     override fun originalToTransformed(offset: Int): Int = offset
     override fun transformedToOriginal(offset: Int): Int = offset
 }
@@ -100,8 +100,8 @@
     val locale: LocaleList = LocaleList("en-US")
 ) : VisualTransformation {
     override fun filter(text: AnnotatedString): TransformedText {
-        // Note: identityTranslater doesn't work for some locale, e.g. Turkish
-        return TransformedText(AnnotatedString(text.text).toUpperCase(locale), identityTranslater)
+        // Note: identityTranslator doesn't work for some locale, e.g. Turkish
+        return TransformedText(AnnotatedString(text.text).toUpperCase(locale), identityTranslator)
     }
 }
 
@@ -110,7 +110,7 @@
  *
  * @see phoneNumberFilter
  */
-private val phoneNumberOffsetTranslater = object : OffsetMap {
+private val phoneNumberOffsetTranslator = object : OffsetMapping {
     override fun originalToTransformed(offset: Int): Int {
         return when (offset) {
             0 -> 1
@@ -160,16 +160,16 @@
         val filled = trimmed + "_".repeat(10 - trimmed.length)
         val res = "(" + filled.substring(0..2) + ") " + filled.substring(3..5) + "-" +
             filled.substring(6..9)
-        return TransformedText(AnnotatedString(text = res), phoneNumberOffsetTranslater)
+        return TransformedText(AnnotatedString(text = res), phoneNumberOffsetTranslator)
     }
 }
 
 private val emailFilter = object : VisualTransformation {
     override fun filter(text: AnnotatedString): TransformedText {
         return if (text.text.indexOf("@") == -1) {
-            TransformedText(AnnotatedString(text = text.text + "@gmail.com"), identityTranslater)
+            TransformedText(AnnotatedString(text = text.text + "@gmail.com"), identityTranslator)
         } else {
-            TransformedText(text, identityTranslater)
+            TransformedText(text, identityTranslator)
         }
     }
 }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/TextFieldDelegateIntegrationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/TextFieldDelegateIntegrationTest.kt
index 1c35c98..684367d 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/TextFieldDelegateIntegrationTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/TextFieldDelegateIntegrationTest.kt
@@ -30,7 +30,7 @@
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.font.Font
 import androidx.compose.ui.text.font.ResourceFont
-import androidx.compose.ui.text.input.OffsetMap
+import androidx.compose.ui.text.input.OffsetMapping
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Density
@@ -91,7 +91,7 @@
             canvas = actualCanvas,
             value = TextFieldValue(text = "Hello, World", selection = selection),
             selectionPaint = Paint().apply { color = selectionColor },
-            offsetMap = OffsetMap.identityOffsetMap,
+            offsetMapping = OffsetMapping.Identity,
             textLayoutResult = layoutResult
         )
 
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
index 9604ecf..982e511 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
@@ -163,7 +163,7 @@
     val selectionBackgroundColor = AmbientTextSelectionColors.current.backgroundColor
 
     // State
-    val (visualText, offsetMap) = remember(value, visualTransformation) {
+    val (visualText, offsetMapping) = remember(value, visualTransformation) {
         val transformed = visualTransformation.filter(AnnotatedString(value.text))
         value.composition?.let {
             TextFieldDelegate.applyCompositionDecoration(it, transformed)
@@ -202,7 +202,7 @@
     state.processor.onNewState(value, textInputService, state.inputSession)
 
     val manager = remember { TextFieldSelectionManager() }
-    manager.offsetMap = offsetMap
+    manager.offsetMapping = offsetMapping
     manager.onValueChange = onValueChangeWrapper
     manager.state = state
     manager.value = value
@@ -246,7 +246,7 @@
                             textInputService,
                             state.inputSession,
                             state.hasFocus,
-                            offsetMap
+                            offsetMapping
                         )
                     }
                 }
@@ -287,7 +287,7 @@
                         it,
                         layoutResult,
                         state.processor,
-                        offsetMap,
+                        offsetMapping,
                         onValueChangeWrapper
                     )
                 }
@@ -315,7 +315,7 @@
                 TextFieldDelegate.draw(
                     canvas,
                     value,
-                    offsetMap,
+                    offsetMapping,
                     layoutResult,
                     state.selectionPaint
                 )
@@ -339,7 +339,7 @@
                     textInputService,
                     state.inputSession,
                     state.hasFocus,
-                    offsetMap
+                    offsetMapping
                 )
             }
         }
@@ -410,7 +410,7 @@
         }
     }
 
-    val cursorModifier = Modifier.cursor(state, value, offsetMap, cursorColor)
+    val cursorModifier = Modifier.cursor(state, value, offsetMapping, cursorColor)
 
     onDispose { manager.hideSelectionToolbar() }
 
@@ -452,8 +452,8 @@
         if (state.hasFocus && state.selectionIsOn && !isMouseInput) {
             manager.state?.layoutResult?.let {
                 if (!value.selection.collapsed) {
-                    val startOffset = offsetMap.originalToTransformed(value.selection.start)
-                    val endOffset = offsetMap.originalToTransformed(value.selection.end)
+                    val startOffset = offsetMapping.originalToTransformed(value.selection.start)
+                    val endOffset = offsetMapping.originalToTransformed(value.selection.end)
                     val startDirection = it.getBidiRunDirection(startOffset)
                     val endDirection = it.getBidiRunDirection(max(endOffset - 1, 0))
                     val directions = Pair(startDirection, endDirection)
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldCursor.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldCursor.kt
index e22c3ab..41dc68f 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldCursor.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldCursor.kt
@@ -37,7 +37,7 @@
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.platform.AmbientAnimationClock
 import androidx.compose.ui.text.InternalTextApi
-import androidx.compose.ui.text.input.OffsetMap
+import androidx.compose.ui.text.input.OffsetMapping
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.util.annotation.VisibleForTesting
@@ -47,7 +47,7 @@
 internal fun Modifier.cursor(
     state: TextFieldState,
     value: TextFieldValue,
-    offsetMap: OffsetMap,
+    offsetMapping: OffsetMapping,
     cursorColor: Color
 ) = composed {
     // this should be a disposable clock, but it's not available in this module
@@ -70,7 +70,7 @@
             this.drawContent()
             val cursorAlphaValue = cursorAlpha.value.coerceIn(0f, 1f)
             if (cursorAlphaValue != 0f) {
-                val transformedOffset = offsetMap
+                val transformedOffset = offsetMapping
                     .originalToTransformed(value.selection.start)
                 val cursorRect = state.layoutResult?.getCursorRect(transformedOffset)
                     ?: Rect(0f, 0f, 0f, 0f)
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
index 5e90b70..a028be9 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
@@ -39,7 +39,7 @@
 import androidx.compose.ui.text.input.ImeAction
 import androidx.compose.ui.text.input.InputSessionToken
 import androidx.compose.ui.text.input.ImeOptions
-import androidx.compose.ui.text.input.OffsetMap
+import androidx.compose.ui.text.input.OffsetMapping
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.text.input.TextInputService
 import androidx.compose.ui.text.input.TransformedText
@@ -120,20 +120,20 @@
          *
          * @param canvas The target canvas.
          * @param value The editor state
-         * @param offsetMap The offset map
+         * @param offsetMapping The offset map
          * @param selectionPaint The selection paint
          */
         @JvmStatic
         internal fun draw(
             canvas: Canvas,
             value: TextFieldValue,
-            offsetMap: OffsetMap,
+            offsetMapping: OffsetMapping,
             textLayoutResult: TextLayoutResult,
             selectionPaint: Paint
         ) {
             if (!value.selection.collapsed) {
-                val start = offsetMap.originalToTransformed(value.selection.min)
-                val end = offsetMap.originalToTransformed(value.selection.max)
+                val start = offsetMapping.originalToTransformed(value.selection.min)
+                val end = offsetMapping.originalToTransformed(value.selection.max)
                 if (start != end) {
                     val selectionPath = textLayoutResult.getPathForRange(start, end)
                     canvas.drawPath(selectionPath, selectionPaint)
@@ -153,7 +153,7 @@
          * @param textInputService The text input service
          * @param token The current input session token.
          * @param hasFocus True if focus is gained.
-         * @param offsetMap The mapper from/to editing buffer to/from visible text.
+         * @param offsetMapping The mapper from/to editing buffer to/from visible text.
          */
         @JvmStatic
         internal fun notifyFocusedRect(
@@ -164,7 +164,7 @@
             textInputService: TextInputService,
             token: InputSessionToken,
             hasFocus: Boolean,
-            offsetMap: OffsetMap
+            offsetMapping: OffsetMapping
         ) {
             if (!hasFocus) {
                 return
@@ -172,11 +172,11 @@
 
             val bbox = if (value.selection.max < value.text.length) {
                 textLayoutResult.getBoundingBox(
-                    offsetMap.originalToTransformed(value.selection.max)
+                    offsetMapping.originalToTransformed(value.selection.max)
                 )
             } else if (value.selection.max != 0) {
                 textLayoutResult.getBoundingBox(
-                    offsetMap.originalToTransformed(value.selection.max) - 1
+                    offsetMapping.originalToTransformed(value.selection.max) - 1
                 )
             } else {
                 val defaultSize = computeSizeForDefaultText(
@@ -216,7 +216,7 @@
          * @param position The event position in composable coordinate.
          * @param textLayoutResult The text layout result
          * @param editProcessor The edit processor
-         * @param offsetMap The offset map
+         * @param offsetMapping The offset map
          * @param onValueChange The callback called when the new editor state arrives.
          */
         @JvmStatic
@@ -224,10 +224,10 @@
             position: Offset,
             textLayoutResult: TextLayoutResult,
             editProcessor: EditProcessor,
-            offsetMap: OffsetMap,
+            offsetMapping: OffsetMapping,
             onValueChange: (TextFieldValue) -> Unit
         ) {
-            val offset = offsetMap.transformedToOriginal(
+            val offset = offsetMapping.transformedToOriginal(
                 textLayoutResult.getOffsetForPosition(position)
             )
             onValueChange(editProcessor.mBufferState.copy(selection = TextRange(offset)))
@@ -305,11 +305,11 @@
                 AnnotatedString.Builder(transformed.transformedText).apply {
                     addStyle(
                         SpanStyle(textDecoration = TextDecoration.Underline),
-                        transformed.offsetMap.originalToTransformed(compositionRange.start),
-                        transformed.offsetMap.originalToTransformed(compositionRange.end)
+                        transformed.offsetMapping.originalToTransformed(compositionRange.start),
+                        transformed.offsetMapping.originalToTransformed(compositionRange.end)
                     )
                 }.toAnnotatedString(),
-                transformed.offsetMap
+                transformed.offsetMapping
             )
     }
 }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldScroll.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldScroll.kt
index df4f65b..3f5e73b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldScroll.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldScroll.kt
@@ -199,7 +199,7 @@
     textFieldWidth: Int
 ): Rect {
     val cursorRect = textLayoutResult?.getCursorRect(
-        transformedText.offsetMap.originalToTransformed(cursorOffset)
+        transformedText.offsetMapping.originalToTransformed(cursorOffset)
     ) ?: Rect.Zero
     val thickness = DefaultCursorThickness.toIntPx()
 
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
index dd4b112..235d5ab 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
@@ -37,7 +37,7 @@
 import androidx.compose.ui.text.InternalTextApi
 import androidx.compose.ui.text.TextRange
 import androidx.compose.ui.text.constrain
-import androidx.compose.ui.text.input.OffsetMap
+import androidx.compose.ui.text.input.OffsetMapping
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.text.input.getSelectedText
 import androidx.compose.ui.text.input.getTextAfterSelection
@@ -55,9 +55,9 @@
 internal class TextFieldSelectionManager() {
 
     /**
-     * The current [OffsetMap] for text field.
+     * The current [OffsetMapping] for text field.
      */
-    internal var offsetMap: OffsetMap = OffsetMap.identityOffsetMap
+    internal var offsetMapping: OffsetMapping = OffsetMapping.Identity
 
     /**
      * Called when the input service updates the values in [TextFieldValue].
@@ -124,7 +124,7 @@
             // Long Press at the blank area, the cursor should show up at the end of the line.
             if (!isPositionOnText(pxPosition)) {
                 state?.layoutResult?.let { layoutResult ->
-                    val offset = offsetMap.transformedToOriginal(
+                    val offset = offsetMapping.transformedToOriginal(
                         layoutResult.getLineEnd(
                             layoutResult.getLineForVerticalPosition(pxPosition.y)
                         )
@@ -196,7 +196,7 @@
                     downPosition,
                     layoutResult,
                     state!!.processor,
-                    offsetMap,
+                    offsetMapping,
                     onValueChange
                 )
             }
@@ -248,10 +248,10 @@
                     val startOffset = if (isStartHandle)
                         layoutResult.getOffsetForPosition(dragBeginPosition + dragTotalDistance)
                     else
-                        offsetMap.originalToTransformed(value.selection.start)
+                        offsetMapping.originalToTransformed(value.selection.start)
 
                     val endOffset = if (isStartHandle)
-                        offsetMap.originalToTransformed(value.selection.end)
+                        offsetMapping.originalToTransformed(value.selection.end)
                     else
                         layoutResult.getOffsetForPosition(dragBeginPosition + dragTotalDistance)
 
@@ -405,7 +405,7 @@
         val offset = if (isStartHandle) value.selection.start else value.selection.end
         return getSelectionHandleCoordinates(
             textLayoutResult = state?.layoutResult!!,
-            offset = offsetMap.originalToTransformed(offset),
+            offset = offsetMapping.originalToTransformed(offset),
             isStart = isStartHandle,
             areHandlesCrossed = value.selection.reversed
         )
@@ -523,8 +523,8 @@
         wordBasedSelection: Boolean
     ) {
         val transformedSelection = TextRange(
-            offsetMap.originalToTransformed(value.selection.start),
-            offsetMap.originalToTransformed(value.selection.end)
+            offsetMapping.originalToTransformed(value.selection.start),
+            offsetMapping.originalToTransformed(value.selection.end)
         )
 
         val newTransformedSelection = getTextFieldSelection(
@@ -538,8 +538,8 @@
         )
 
         val originalSelection = TextRange(
-            start = offsetMap.transformedToOriginal(newTransformedSelection.start),
-            end = offsetMap.transformedToOriginal(newTransformedSelection.end)
+            start = offsetMapping.transformedToOriginal(newTransformedSelection.start),
+            end = offsetMapping.transformedToOriginal(newTransformedSelection.end)
         )
 
         if (originalSelection == value.selection) return
diff --git a/compose/foundation/foundation/src/desktopTest/kotlin/androidx/compose/foundation/text/selection/DesktopTextFieldSelectionManagerTest.kt b/compose/foundation/foundation/src/desktopTest/kotlin/androidx/compose/foundation/text/selection/DesktopTextFieldSelectionManagerTest.kt
index a487495..3857e63 100644
--- a/compose/foundation/foundation/src/desktopTest/kotlin/androidx/compose/foundation/text/selection/DesktopTextFieldSelectionManagerTest.kt
+++ b/compose/foundation/foundation/src/desktopTest/kotlin/androidx/compose/foundation/text/selection/DesktopTextFieldSelectionManagerTest.kt
@@ -25,7 +25,7 @@
 import androidx.compose.ui.text.TextLayoutInput
 import androidx.compose.ui.text.TextRange
 import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.input.OffsetMap
+import androidx.compose.ui.text.input.OffsetMapping
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.Constraints
@@ -46,7 +46,7 @@
 class DesktopTextFieldSelectionManagerTest {
     private val text = "Hello World"
     private val density = Density(density = 1f)
-    private val offsetMap = OffsetMap.identityOffsetMap
+    private val offsetMapping = OffsetMapping.Identity
     private var value = TextFieldValue(text)
     private val lambda: (TextFieldValue) -> Unit = { value = it }
     private val state = TextFieldState(mock())
@@ -65,7 +65,7 @@
 
     @Before
     fun setup() {
-        manager.offsetMap = offsetMap
+        manager.offsetMapping = offsetMapping
         manager.onValueChange = lambda
         manager.state = state
         manager.value = value
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/TextFieldDelegateTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/TextFieldDelegateTest.kt
index a10c5d0..eaa270b 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/TextFieldDelegateTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/TextFieldDelegateTest.kt
@@ -35,7 +35,7 @@
 import androidx.compose.ui.text.input.ImeOptions
 import androidx.compose.ui.text.input.KeyboardCapitalization
 import androidx.compose.ui.text.input.KeyboardType
-import androidx.compose.ui.text.input.OffsetMap
+import androidx.compose.ui.text.input.OffsetMapping
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.text.input.TextInputService
 import androidx.compose.ui.text.input.TransformedText
@@ -77,7 +77,7 @@
     /**
      * Test implementation of offset map which doubles the offset in transformed text.
      */
-    private val skippingOffsetMap = object : OffsetMap {
+    private val skippingOffsetMap = object : OffsetMapping {
         override fun originalToTransformed(offset: Int): Int = offset * 2
         override fun transformedToOriginal(offset: Int): Int = offset / 2
     }
@@ -107,7 +107,7 @@
             position,
             textLayoutResult,
             processor,
-            OffsetMap.identityOffsetMap,
+            OffsetMapping.Identity,
             onValueChange
         )
 
@@ -219,7 +219,7 @@
             textInputService,
             inputSessionToken,
             true /* hasFocus */,
-            OffsetMap.identityOffsetMap
+            OffsetMapping.Identity
         )
         verify(textInputService).notifyFocusedRect(eq(inputSessionToken), any())
     }
@@ -236,7 +236,7 @@
             textInputService,
             inputSessionToken,
             false /* hasFocus */,
-            OffsetMap.identityOffsetMap
+            OffsetMapping.Identity
         )
         verify(textInputService, never()).notifyFocusedRect(any(), any())
     }
@@ -259,7 +259,7 @@
             textInputService,
             inputSessionToken,
             true /* hasFocus */,
-            OffsetMap.identityOffsetMap
+            OffsetMapping.Identity
         )
         verify(textInputService).notifyFocusedRect(eq(inputSessionToken), any())
     }
@@ -312,20 +312,20 @@
 
     @Test
     fun use_identity_mapping_if_none_visual_transformation() {
-        val (visualText, offsetMap) =
+        val (visualText, offsetMapping) =
             VisualTransformation.None.filter(AnnotatedString(text = "Hello, World"))
 
         assertEquals("Hello, World", visualText.text)
         for (i in 0..visualText.text.length) {
             // Identity mapping returns if no visual filter is provided.
-            assertThat(offsetMap.originalToTransformed(i)).isEqualTo(i)
-            assertThat(offsetMap.transformedToOriginal(i)).isEqualTo(i)
+            assertThat(offsetMapping.originalToTransformed(i)).isEqualTo(i)
+            assertThat(offsetMapping.transformedToOriginal(i)).isEqualTo(i)
         }
     }
 
     @Test
     fun apply_composition_decoration() {
-        val identityOffsetMap = object : OffsetMap {
+        val identityOffsetMapping = object : OffsetMapping {
             override fun originalToTransformed(offset: Int): Int = offset
             override fun transformedToOriginal(offset: Int): Int = offset
         }
@@ -335,7 +335,7 @@
                 pushStyle(SpanStyle(color = Color.Red))
                 append("Hello, World")
             }.toAnnotatedString(),
-            offsetMap = identityOffsetMap
+            offsetMapping = identityOffsetMapping
         )
 
         val result = TextFieldDelegate.applyCompositionDecoration(
@@ -353,7 +353,7 @@
     @Test
     fun apply_composition_decoration_with_offsetmap() {
         val offsetAmount = 5
-        val offsetMap = object : OffsetMap {
+        val offsetMapping = object : OffsetMapping {
             override fun originalToTransformed(offset: Int): Int = offsetAmount + offset
             override fun transformedToOriginal(offset: Int): Int = offset - offsetAmount
         }
@@ -363,7 +363,7 @@
                 append(" ".repeat(offsetAmount))
                 append("Hello World")
             }.toAnnotatedString(),
-            offsetMap = offsetMap
+            offsetMapping = offsetMapping
         )
 
         val range = TextRange(0, 2)
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt
index 5c75510..8dbb12a 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt
@@ -30,7 +30,7 @@
 import androidx.compose.ui.text.TextLayoutInput
 import androidx.compose.ui.text.TextRange
 import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.input.OffsetMap
+import androidx.compose.ui.text.input.OffsetMapping
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.text.style.ResolvedTextDirection
 import androidx.compose.ui.text.style.TextOverflow
@@ -57,7 +57,7 @@
 class TextFieldSelectionManagerTest {
     private val text = "Hello World"
     private val density = Density(density = 1f)
-    private val offsetMap = OffsetMap.identityOffsetMap
+    private val offsetMapping = OffsetMapping.Identity
     private var value = TextFieldValue(text)
     private val lambda: (TextFieldValue) -> Unit = { value = it }
     private val spyLambda = spy(lambda)
@@ -79,7 +79,7 @@
 
     @Before
     fun setup() {
-        manager.offsetMap = offsetMap
+        manager.offsetMapping = offsetMapping
         manager.onValueChange = lambda
         manager.state = state
         manager.value = value
@@ -120,7 +120,7 @@
 
     @Test
     fun TextFieldSelectionManager_init() {
-        assertThat(manager.offsetMap).isEqualTo(offsetMap)
+        assertThat(manager.offsetMapping).isEqualTo(offsetMapping)
         assertThat(manager.onValueChange).isEqualTo(lambda)
         assertThat(manager.state).isEqualTo(state)
         assertThat(manager.value).isEqualTo(value)
diff --git a/compose/ui/ui-text/api/current.txt b/compose/ui/ui-text/api/current.txt
index ae42f2a..5f75fcb 100644
--- a/compose/ui/ui-text/api/current.txt
+++ b/compose/ui/ui-text/api/current.txt
@@ -872,22 +872,20 @@
     property public final int amount;
   }
 
-  public interface OffsetMap {
+  public interface OffsetMapping {
     method public int originalToTransformed(int offset);
     method public int transformedToOriginal(int offset);
-    field public static final androidx.compose.ui.text.input.OffsetMap.Companion Companion;
+    field public static final androidx.compose.ui.text.input.OffsetMapping.Companion Companion;
   }
 
-  public static final class OffsetMap.Companion {
-    method public androidx.compose.ui.text.input.OffsetMap getIdentityOffsetMap();
-    property public final androidx.compose.ui.text.input.OffsetMap identityOffsetMap;
+  public static final class OffsetMapping.Companion {
+    method public androidx.compose.ui.text.input.OffsetMapping getIdentity();
+    property public final androidx.compose.ui.text.input.OffsetMapping Identity;
   }
 
   public final class PasswordVisualTransformation implements androidx.compose.ui.text.input.VisualTransformation {
     ctor public PasswordVisualTransformation(char mask);
     ctor public PasswordVisualTransformation();
-    method public char component1();
-    method public androidx.compose.ui.text.input.PasswordVisualTransformation copy(char mask);
     method public androidx.compose.ui.text.input.TransformedText filter(androidx.compose.ui.text.AnnotatedString text);
     method public char getMask();
     property public final char mask;
@@ -969,13 +967,13 @@
   }
 
   public final class TransformedText {
-    ctor public TransformedText(androidx.compose.ui.text.AnnotatedString transformedText, androidx.compose.ui.text.input.OffsetMap offsetMap);
+    ctor public TransformedText(androidx.compose.ui.text.AnnotatedString transformedText, androidx.compose.ui.text.input.OffsetMapping offsetMapping);
     method public androidx.compose.ui.text.AnnotatedString component1();
-    method public androidx.compose.ui.text.input.OffsetMap component2();
-    method public androidx.compose.ui.text.input.TransformedText copy(androidx.compose.ui.text.AnnotatedString transformedText, androidx.compose.ui.text.input.OffsetMap offsetMap);
-    method public androidx.compose.ui.text.input.OffsetMap getOffsetMap();
+    method public androidx.compose.ui.text.input.OffsetMapping component2();
+    method public androidx.compose.ui.text.input.TransformedText copy(androidx.compose.ui.text.AnnotatedString transformedText, androidx.compose.ui.text.input.OffsetMapping offsetMapping);
+    method public androidx.compose.ui.text.input.OffsetMapping getOffsetMapping();
     method public androidx.compose.ui.text.AnnotatedString getTransformedText();
-    property public final androidx.compose.ui.text.input.OffsetMap offsetMap;
+    property public final androidx.compose.ui.text.input.OffsetMapping offsetMapping;
     property public final androidx.compose.ui.text.AnnotatedString transformedText;
   }
 
diff --git a/compose/ui/ui-text/api/public_plus_experimental_current.txt b/compose/ui/ui-text/api/public_plus_experimental_current.txt
index ae42f2a..5f75fcb 100644
--- a/compose/ui/ui-text/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-text/api/public_plus_experimental_current.txt
@@ -872,22 +872,20 @@
     property public final int amount;
   }
 
-  public interface OffsetMap {
+  public interface OffsetMapping {
     method public int originalToTransformed(int offset);
     method public int transformedToOriginal(int offset);
-    field public static final androidx.compose.ui.text.input.OffsetMap.Companion Companion;
+    field public static final androidx.compose.ui.text.input.OffsetMapping.Companion Companion;
   }
 
-  public static final class OffsetMap.Companion {
-    method public androidx.compose.ui.text.input.OffsetMap getIdentityOffsetMap();
-    property public final androidx.compose.ui.text.input.OffsetMap identityOffsetMap;
+  public static final class OffsetMapping.Companion {
+    method public androidx.compose.ui.text.input.OffsetMapping getIdentity();
+    property public final androidx.compose.ui.text.input.OffsetMapping Identity;
   }
 
   public final class PasswordVisualTransformation implements androidx.compose.ui.text.input.VisualTransformation {
     ctor public PasswordVisualTransformation(char mask);
     ctor public PasswordVisualTransformation();
-    method public char component1();
-    method public androidx.compose.ui.text.input.PasswordVisualTransformation copy(char mask);
     method public androidx.compose.ui.text.input.TransformedText filter(androidx.compose.ui.text.AnnotatedString text);
     method public char getMask();
     property public final char mask;
@@ -969,13 +967,13 @@
   }
 
   public final class TransformedText {
-    ctor public TransformedText(androidx.compose.ui.text.AnnotatedString transformedText, androidx.compose.ui.text.input.OffsetMap offsetMap);
+    ctor public TransformedText(androidx.compose.ui.text.AnnotatedString transformedText, androidx.compose.ui.text.input.OffsetMapping offsetMapping);
     method public androidx.compose.ui.text.AnnotatedString component1();
-    method public androidx.compose.ui.text.input.OffsetMap component2();
-    method public androidx.compose.ui.text.input.TransformedText copy(androidx.compose.ui.text.AnnotatedString transformedText, androidx.compose.ui.text.input.OffsetMap offsetMap);
-    method public androidx.compose.ui.text.input.OffsetMap getOffsetMap();
+    method public androidx.compose.ui.text.input.OffsetMapping component2();
+    method public androidx.compose.ui.text.input.TransformedText copy(androidx.compose.ui.text.AnnotatedString transformedText, androidx.compose.ui.text.input.OffsetMapping offsetMapping);
+    method public androidx.compose.ui.text.input.OffsetMapping getOffsetMapping();
     method public androidx.compose.ui.text.AnnotatedString getTransformedText();
-    property public final androidx.compose.ui.text.input.OffsetMap offsetMap;
+    property public final androidx.compose.ui.text.input.OffsetMapping offsetMapping;
     property public final androidx.compose.ui.text.AnnotatedString transformedText;
   }
 
diff --git a/compose/ui/ui-text/api/restricted_current.txt b/compose/ui/ui-text/api/restricted_current.txt
index ae42f2a..5f75fcb 100644
--- a/compose/ui/ui-text/api/restricted_current.txt
+++ b/compose/ui/ui-text/api/restricted_current.txt
@@ -872,22 +872,20 @@
     property public final int amount;
   }
 
-  public interface OffsetMap {
+  public interface OffsetMapping {
     method public int originalToTransformed(int offset);
     method public int transformedToOriginal(int offset);
-    field public static final androidx.compose.ui.text.input.OffsetMap.Companion Companion;
+    field public static final androidx.compose.ui.text.input.OffsetMapping.Companion Companion;
   }
 
-  public static final class OffsetMap.Companion {
-    method public androidx.compose.ui.text.input.OffsetMap getIdentityOffsetMap();
-    property public final androidx.compose.ui.text.input.OffsetMap identityOffsetMap;
+  public static final class OffsetMapping.Companion {
+    method public androidx.compose.ui.text.input.OffsetMapping getIdentity();
+    property public final androidx.compose.ui.text.input.OffsetMapping Identity;
   }
 
   public final class PasswordVisualTransformation implements androidx.compose.ui.text.input.VisualTransformation {
     ctor public PasswordVisualTransformation(char mask);
     ctor public PasswordVisualTransformation();
-    method public char component1();
-    method public androidx.compose.ui.text.input.PasswordVisualTransformation copy(char mask);
     method public androidx.compose.ui.text.input.TransformedText filter(androidx.compose.ui.text.AnnotatedString text);
     method public char getMask();
     property public final char mask;
@@ -969,13 +967,13 @@
   }
 
   public final class TransformedText {
-    ctor public TransformedText(androidx.compose.ui.text.AnnotatedString transformedText, androidx.compose.ui.text.input.OffsetMap offsetMap);
+    ctor public TransformedText(androidx.compose.ui.text.AnnotatedString transformedText, androidx.compose.ui.text.input.OffsetMapping offsetMapping);
     method public androidx.compose.ui.text.AnnotatedString component1();
-    method public androidx.compose.ui.text.input.OffsetMap component2();
-    method public androidx.compose.ui.text.input.TransformedText copy(androidx.compose.ui.text.AnnotatedString transformedText, androidx.compose.ui.text.input.OffsetMap offsetMap);
-    method public androidx.compose.ui.text.input.OffsetMap getOffsetMap();
+    method public androidx.compose.ui.text.input.OffsetMapping component2();
+    method public androidx.compose.ui.text.input.TransformedText copy(androidx.compose.ui.text.AnnotatedString transformedText, androidx.compose.ui.text.input.OffsetMapping offsetMapping);
+    method public androidx.compose.ui.text.input.OffsetMapping getOffsetMapping();
     method public androidx.compose.ui.text.AnnotatedString getTransformedText();
-    property public final androidx.compose.ui.text.input.OffsetMap offsetMap;
+    property public final androidx.compose.ui.text.input.OffsetMapping offsetMapping;
     property public final androidx.compose.ui.text.AnnotatedString transformedText;
   }
 
diff --git a/compose/ui/ui-text/samples/src/main/java/androidx/compose/ui/text/samples/VisualTransformationSamples.kt b/compose/ui/ui-text/samples/src/main/java/androidx/compose/ui/text/samples/VisualTransformationSamples.kt
index 8089395..edbd256 100644
--- a/compose/ui/ui-text/samples/src/main/java/androidx/compose/ui/text/samples/VisualTransformationSamples.kt
+++ b/compose/ui/ui-text/samples/src/main/java/androidx/compose/ui/text/samples/VisualTransformationSamples.kt
@@ -18,7 +18,7 @@
 
 import androidx.annotation.Sampled
 import androidx.compose.ui.text.AnnotatedString
-import androidx.compose.ui.text.input.OffsetMap
+import androidx.compose.ui.text.input.OffsetMapping
 import androidx.compose.ui.text.input.TransformedText
 
 @Sampled
@@ -27,10 +27,10 @@
         AnnotatedString("*".repeat(text.text.length)),
 
         /**
-         * [OffsetMap.identityOffsetMap] is a predefined [OffsetMap] that can be used for the
+         * [OffsetMapping.Identity] is a predefined [OffsetMapping] that can be used for the
          * transformation that does not change the character count.
          */
-        OffsetMap.identityOffsetMap
+        OffsetMapping.Identity
     )
 }
 
@@ -54,7 +54,7 @@
      *  - The 5th char of the transformed text is 4th char in the original text.
      *  - The 12th char of the transformed text is 10th char in the original text.
      */
-    val creditCardOffsetTranslator = object : OffsetMap {
+    val creditCardOffsetTranslator = object : OffsetMapping {
         override fun originalToTransformed(offset: Int): Int {
             if (offset <= 3) return offset
             if (offset <= 7) return offset + 1
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/OffsetMapping.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/OffsetMapping.kt
new file mode 100644
index 0000000..b5c3b38
--- /dev/null
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/OffsetMapping.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.text.input
+
+/**
+ * Provides bidirectional offset mapping between original and transformed text.
+ */
+interface OffsetMapping {
+    /**
+     * Convert offset in original text into the offset in transformed text.
+     *
+     * This function must be a monotonically non-decreasing function. In other words, if a cursor
+     * advances in the original text, the cursor in the transformed text must advance or stay there.
+     *
+     * @param offset offset in original text.
+     * @return offset in transformed text
+     *
+     * @see VisualTransformation
+     */
+    fun originalToTransformed(offset: Int): Int
+
+    /**
+     * Convert offset in transformed text into the offset in original text.
+     *
+     * This function must be a monotonically non-decreasing function. In other words, if a cursor
+     * advances in the transformed text, the cusrsor in the original text must advance or stay
+     * there.
+     *
+     * @param offset offset in transformed text
+     * @return offset in original text
+     *
+     * @see VisualTransformation
+     */
+    fun transformedToOriginal(offset: Int): Int
+
+    companion object {
+        /**
+         * The offset map used for identity mapping.
+         */
+        val Identity = object : OffsetMapping {
+            override fun originalToTransformed(offset: Int): Int = offset
+            override fun transformedToOriginal(offset: Int): Int = offset
+        }
+    }
+}
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/VisualTransformation.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/VisualTransformation.kt
index eb938f4..15880dd 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/VisualTransformation.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/VisualTransformation.kt
@@ -21,46 +21,6 @@
 import androidx.compose.ui.text.AnnotatedString
 
 /**
- * The map interface used for bidirectional offset mapping from original to transformed text.
- */
-interface OffsetMap {
-    /**
-     * Convert offset in original text into the offset in transformed text.
-     *
-     * This function must be a monotonically non-decreasing function. In other words, if a cursor
-     * advances in the original text, the cursor in the transformed text must advance or stay there.
-     *
-     * @param offset offset in original text.
-     * @return offset in transformed text
-     * @see VisualTransformation
-     */
-    fun originalToTransformed(offset: Int): Int
-
-    /**
-     * Convert offset in transformed text into the offset in original text.
-     *
-     * This function must be a monotonically non-decreasing function. In other words, if a cursor
-     * advances in the transformed text, the cusrsor in the original text must advance or stay
-     * there.
-     *
-     * @param offset offset in transformed text
-     * @return offset in original text
-     * @see VisualTransformation
-     */
-    fun transformedToOriginal(offset: Int): Int
-
-    companion object {
-        /**
-         * The offset map used for identity mapping.
-         */
-        val identityOffsetMap = object : OffsetMap {
-            override fun originalToTransformed(offset: Int): Int = offset
-            override fun transformedToOriginal(offset: Int): Int = offset
-        }
-    }
-}
-
-/**
  * The transformed text with offset offset mapping
  */
 data class TransformedText(
@@ -72,7 +32,7 @@
     /**
      * The map used for bidirectional offset mapping from original to transformed text.
      */
-    val offsetMap: OffsetMap
+    val offsetMapping: OffsetMapping
 )
 
 /**
@@ -80,7 +40,7 @@
  *
  * This interface can be used for changing visual output of the text in the input field.
  * For example, you can mask characters in password filed with asterisk with
- * PasswordVisualTransformation.
+ * [PasswordVisualTransformation].
  */
 @Immutable
 interface VisualTransformation {
@@ -115,7 +75,7 @@
         @Stable
         val None: VisualTransformation = object : VisualTransformation {
             override fun filter(text: AnnotatedString) =
-                TransformedText(text, OffsetMap.identityOffsetMap)
+                TransformedText(text, OffsetMapping.Identity)
         }
     }
 }
@@ -127,11 +87,22 @@
  *
  * @param mask The mask character used instead of original text.
  */
-data class PasswordVisualTransformation(val mask: Char = '\u2022') : VisualTransformation {
+class PasswordVisualTransformation(val mask: Char = '\u2022') : VisualTransformation {
     override fun filter(text: AnnotatedString): TransformedText {
         return TransformedText(
             AnnotatedString(mask.toString().repeat(text.text.length)),
-            OffsetMap.identityOffsetMap
+            OffsetMapping.Identity
         )
     }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is PasswordVisualTransformation) return false
+        if (mask != other.mask) return false
+        return true
+    }
+
+    override fun hashCode(): Int {
+        return mask.hashCode()
+    }
 }