Skip to content

Fix cursor metrics in SkikoParagraph - #3405

Open
gavr (gavr123456789) wants to merge 5 commits into
JetBrains:jb-mainfrom
gavr123456789:gavr/CMP-8371
Open

gavr (gavr123456789) wants to merge 5 commits into
JetBrains:jb-mainfrom
gavr123456789:gavr/CMP-8371

Conversation

@gavr123456789

@gavr123456789 gavr (gavr123456789) commented Sep 10, 2026 •

Copy link
Copy Markdown

Fixes CMP-8371 Text cursor shrinks after typing begins when a TextField
There are 2 problems fixed.

  1. cursor height is different between empty string and non-empty string
Screen.Recording.2026-09-09.at.22.36.40.mov
  1. new symbol on the second line changes the baseline when font size is larger than line height
Screen.Recording.2026-09-09.at.22.38.07.mov

(fix by SkikoParagraphBuilder.nonAndroid.kt file)

To reproduce:

 Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceEvenly
        ) {

            var text by remember { mutableStateOf("") }
            val textFieldStyle = LocalTextStyle.current.copy(fontSize = 64.sp)
            TextField(
                value = text,
                onValueChange = {
                    println(
                        "[TextFieldDebug] text=${it} " +
                            "length=${it.length} style=$textFieldStyle"
                    )
                    text = it
                },
                modifier = Modifier.onFocusChanged {
                    println(
                        "[TextFieldDebug] focus=" +
                            "isFocused=${it.isFocused} isCaptured=${it.isCaptured}"
                    )
                },
                textStyle = textFieldStyle,
            )

            Column(modifier = Modifier.width(340.dp)) {
                var multilineText by remember { mutableStateOf("") }
                TextField(
                    value = multilineText,
                    onValueChange = { multilineText = it },
                    label = { Text("Multiline: 48sp font / 28sp lineH") },
                    textStyle = LocalTextStyle.current.copy(fontSize = 48.sp, lineHeight = 28.sp),
                    maxLines = 4,
                    modifier = Modifier.fillMaxWidth().height(150.dp),
                )

                var monospaceText by remember { mutableStateOf("") }
                TextField(
                    value = monospaceText,
                    onValueChange = { monospaceText = it },
                    label = { Text("Monospace: 32sp font / 48sp lineH") },
                    textStyle = LocalTextStyle.current.copy(
                        fontSize = 32.sp,
                        fontFamily = FontFamily.Monospace,
                        lineHeight = 48.sp,
                    ),
                    modifier = Modifier.fillMaxWidth(),
                )

                var smallText by remember { mutableStateOf("") }
                TextField(
                    value = smallText,
                    onValueChange = { smallText = it },
                    label = { Text("Small: 14sp font / 20sp lineH") },
                    textStyle = LocalTextStyle.current.copy(fontSize = 14.sp, lineHeight = 20.sp),
                    modifier = Modifier.fillMaxWidth(),
                )
            }
        }

Testing

Screen.Recording.2026-09-09.at.22.48.18.mov
image

Release Notes

Fixes - Multiple Platforms

  • Fixed the cursor metrics difference between empty and non-empty string
  • Fixed line spacing when the line height is less than the font size.

@gavr123456789

gavr (gavr123456789) commented Sep 10, 2026 •

Copy link
Copy Markdown
Author

test getBoundingBox_lineHeight is broken after my second fix.
https://youtrack.jetbrains.com/issue/CMP-7963

Expected Behavior
Hello and There should overlap each other

image

Now I see that this isn’t a bug: when the user chooses a font size > lineH, overlap is expected. Will unroll second fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants