Closed MohamedRejeb closed 11 months ago
It's been like that for a while, I have been waiting for this for quite some time. Hopefully it gets fixed soon.
Thanks for the report! We're getting closer to begin the TextField improvenents/fixes in Compose for Web. The cursor fix is in the scope.
Also change the mouse pointer arrow to a cursor
Any workarounds for now?
it does not allow me to copy or paste content.
do any one know reason and fix ?
For now Compose for Web with Canvas is experimental target. And we have higher priority Issues on other platforms for now. But we will try to fix it in the future.
thanks so much. can I have a start point so I can work on it ? if possible. @dima-avdeev-jb
@MahmoudMabrok
thanks so much. can I have a start point so I can work on it ? if possible. @dima-avdeev-jb
Yes, we have a doc how to prepare dev environment here: https://github.com/JetBrains/compose-multiplatform-core/blob/jb-main/MULTIPLATFORM.md
Just hit this issue myself, so I did some digging into how it happens.
The high-level problem is that the cursorRect
that is used to draw the cursor only has a reasonable height (a non-zero bottom
value) for empty strings. As characters are added to the text field, this Rect will have values like (left=60, top=0, right=60, bottom=0)
, which as I understand make it zero-height, and thus invisible.
Looking into where that bottom
value comes from... It's calculated by SkiaParagraph.getCursorRect
, based on ascent, descent, and baselines values, which come from lineMetrics
.
This is where the problem originates. Whenever we get the lineMetrics
for a paragraph that's not an empty string, we use paragraph.lineMetrics
, which has completely useless, all zero values (including for descent, ascent, and baseline):
LineMetrics(_startIndex=0, _endIndex=0, _endExcludingWhitespaces=0, _endIncludingNewline=0, _hardBreak=false, _ascent=0, _descent=0, _unscaledAscent=0, _height=0, _width=0, _left=0, _baseline=0, _lineNumber=0)
I'm not sure why it has these values, the underlying implementation goes into external
calls that I couldn't easily explore further.
In contrast, if we were to read these three values like we do in the special case for empty strings, we'd get good data here:
metrics.ascent 46.38671875
metrics.descent 12.20703125
paragraph.alphabeticBaseline 46.38671875
So it seems we could either:
paragraph.lineMetrics
manually before returning this objectFor single-line text editing, option (1) from above seems to work fine, with code as simple as this (though it does not work nicely with multi-line text):
text/src/skikoMain/kotlin/androidx/compose/ui/text/SkiaParagraph.skiko.kt
--- a/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/SkiaParagraph.skiko.kt (revision dd86b0b699a1a7d2e7e24fa08af86d4cce4dcff5)
+++ b/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/SkiaParagraph.skiko.kt (date 1697991557668)
@@ -263,7 +263,25 @@
)
} else {
@Suppress("UNCHECKED_CAST", "USELESS_CAST")
- paragraph.lineMetrics as Array<LineMetrics>
+ val paragraphMetrics = paragraph.lineMetrics as Array<LineMetrics>
+ val original = paragraphMetrics[paragraphMetrics.lastIndex]
+ val metrics = layouter.defaultFont.metrics
+ paragraphMetrics[paragraphMetrics.lastIndex] = LineMetrics(
+ startIndex = original.startIndex,
+ endIndex = original.endIndex,
+ endExcludingWhitespaces = original.endExcludingWhitespaces,
+ endIncludingNewline = original.endIncludingNewline,
+ isHardBreak = original.isHardBreak,
+ ascent = -metrics.ascent.toDouble(),
+ descent = metrics.descent.toDouble(),
+ unscaledAscent = original.unscaledAscent,
+ height = original.height,
+ width = original.width,
+ left = original.left,
+ baseline = paragraph.alphabeticBaseline.toDouble(),
+ lineNumber = original.lineNumber,
+ )
+ paragraphMetrics
}
private fun getBoxForwardByOffset(offset: Int): TextBox? {
@zsmb13 Thanks! Can you please open a Pull Request to branch jb-main
in repository https://github.com/JetBrains/compose-multiplatform-core.
You may fork it first, and after that select our repository in Pull Request.
@zsmb13 thank you a lot for your investigation! It's super helpful.
Since SkiaParagraph.skiko.kt is a common code for desktop/ios/web we expect it to work everywhere the same way. The patch seems to break the multiline textfields for at least desktop (probably for ios too).
So I think we'll have to 2. Fix the underlying external/native implementation that gives us this all-zero object
.
iOS and web use the same simple C++ wrapper in skiko - https://github.com/JetBrains/skiko/blob/master/skiko/src/nativeJsMain/cpp/paragraph/Paragraph.cc#L121
Probably, we'll have to dig into skia implementation details. I doubt there is something so wrong in it - perhaps, it's our mistake with how we provide/embed a default font.
Yes, the path definitely breaks multi-line on wasm/web as well, that's why I just added this here and didn't create a PR. I have no idea what I'm doing here, I just kept digging and looked for values that are more sensible 😀
Was addressed in https://github.com/JetBrains/skiko/pull/846
Also hitting this issue. Trying to use TextFields in JS target. Seems that the lineMetrics issue causes many problems.
Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.
For compose web the cursor is invisible in the TextField. It's visible only when the TextField is empty but as soon as we type some text the cursor disappears.
https://user-images.githubusercontent.com/41842296/235705551-e2769f0a-2180-470f-b6ef-1c50c259fa87.mov