<Swing Dev> [9] Review request for 8163124 Add floating point API support to javax.swing.text.Caret
Alexandr Scherbatiy
alexandr.scherbatiy at oracle.com
Wed Sep 21 16:21:02 UTC 2016
When a font size is small and UI scale is large it is possible that a
char advance can be smaller than 1. For example, if font is Dialog plain
with size 2 and UI scale is 32 the 'j' char width has value 0.47. For
this case saved int caret position which is used to move a caret to next
line does not have enough precision to be placed between the first and
the second 'j' char.
I have prepared the test [1]. It should be run with the applied patch
[2] for the fix JDK-8156217 because it contains implementation of the
TextComponent.modelToView2D(pos) method. The test shows a JTextArea with
two lines "jjjjjjjjjjj" and uses a custom caret implementation. Pressing
the arrow key to the right and down leads that the caret is moved before
the first character on the second line instead of the second character.
[1]
http://cr.openjdk.java.net/~alexsch/8163124/samples/MagicCaretPositionTest.java
[2] http://cr.openjdk.java.net/~alexsch/8156217/webrev.07/all_01
Thanks,
Alexandr.
On 8/25/2016 8:58 AM, Philip Race wrote:
> On 8/24/16, 9:45 AM, Alexander Scherbatiy wrote:
>> On 17/08/16 22:49, Phil Race wrote:
>>> Sorry, but I have had some trouble trying to picture this.
>>> If the caret is between "b" and "c", being off by a fractional value
>>> seems
>>> unlikely to make it jump to between "a" and "b".
>>> It might now "round" to somewhere in the trailing pixel of "b" but
>>> nowhere
>>> near the leading edge.
>> I suppose yes.
>>
>> Another case is when a caret is in the center of the "b". In this
>> case it can be moved to another character if fractional values are
>> not taken into account. However, may be it does not matter which
>> character "a" or "c" would be chosen because they have nearly the
>> same distance to the center of the "b".
>
> Indeed. And I think that is no different than today that "in the
> middle" means
> it is 50:50 which way it goes with integers too.
> Also unless this position was set by some code that just picked a
> position
> out thin air, I would expect this to always be "between" the
> characters as
> a result of normal calculation of the caret.
>
> -phil.
>>
>> Thanks,
>> Alexandr.
>>
>>>
>>> -phil.
>>>
>>>
>>> On 08/11/2016 09:55 AM, Alexandr Scherbatiy wrote:
>>>>
>>>> I am sorry. The JTextComponent.viewToModel(Point) method returns
>>>> the closest location for the provided point. If the caret position
>>>> is N.25 the distance to the right character is 0.25 and to the left
>>>> one is greater than 0.75. Even in for the worst case the distance
>>>> to the right character is less than 1 and to the left is greater
>>>> than 1 (suppose a character width is greater than 1). For the
>>>> provided cases the caret should always be placed in the proper
>>>> closest location.
>>>>
>>>> There is just a question could a user just compare the provided
>>>> magic caret position (which coordinates are rounded) with the
>>>> result of rectangle from the method
>>>> JTextComponent.modelToView2(position) which returns the floating
>>>> point positions. So for the same position the rounded point can be
>>>> (N, y) and the rectangle can have bounds (N.25, y, w, h). Comparing
>>>> these results can lead that the magic caret point does not belong
>>>> to the provided rectangle but it is definitely that the x
>>>> coordinate of this rectangle is the closest one to this point.
>>>>
>>>> By the way, I can merge the added JTextComponent.modelToView2D(int
>>>> pos)/viewToModel2D(Point2D pt) public methods with the fix for the
>>>> 8156217 Selected text is shifted on HiDPI display
>>>> http://cr.openjdk.java.net/~alexsch/8156217/webrev.04/
>>>>
>>>> Thanks,
>>>> Alexandr.
>>>>
>>>> On 8/10/2016 5:22 PM, Alexandr Scherbatiy wrote:
>>>>>
>>>>> Suppose there is a text area with two lines with the same text:
>>>>> abcdefghij
>>>>> abcdefghij
>>>>>
>>>>> The char 'c' on the fist line has offset 2 and some coordinates
>>>>> (x1, y1) where x1 can have a floating point values like 21.25.
>>>>> The char 'c' on the second line has offset 13 and coordinates (x2,
>>>>> y2) where x2 is equal to x1.
>>>>>
>>>>> Setting the caret to the first 'c' character sets the magic caret
>>>>> position to (round (x1), round (y1)) position.
>>>>> Pressing the arrow down key calculates the new y position and
>>>>> uses the x position from the magic caret position which is
>>>>> round(21.5) = 21.
>>>>> Now the new offset can be calculated as
>>>>> textComponent.viewToModel(new Point(21, newY)) which returns
>>>>> offset 12 for char 'b' on the second line instead the offset 13
>>>>> for char 'c'.
>>>>>
>>>>> Thanks,
>>>>> Alexandr.
>>>>>
>>>>> On 8/9/2016 11:32 PM, Philip Race wrote:
>>>>>> But characters are of varying width. Being on the "20th" char on
>>>>>> line N
>>>>>> may mean being on the "25th" on line N+1.
>>>>>>
>>>>>> So I am claiming this is nothing new and we really do not need do
>>>>>> anything here.
>>>>>>
>>>>>> -phil.
>>>>>>
>>>>>> On 8/9/16, 1:06 PM, Alexandr Scherbatiy wrote:
>>>>>>> On 8/9/2016 12:44 AM, Phil Race wrote:
>>>>>>>> I was not familiar with this "magic caret" but from reading it
>>>>>>>> seems like it has just one use/purpose.
>>>>>>>> In the event that someone has multi-line text that you can
>>>>>>>> navigate around with up/down arrow keys
>>>>>>>> and that text has lines of varying length, you want a
>>>>>>>> "preferred" horizontal position for the caret
>>>>>>>> to be remembered so the caret is placed at that position
>>>>>>>> whenever the line of text has a length
>>>>>>>> greater than the caret position. Is there anything more to it
>>>>>>>> than that ?
>>>>>>>>
>>>>>>>> Obviously the caret needs to be placed correctly in the context
>>>>>>>> of the text, so the precise position,
>>>>>>>> even in an all-integer world, is not going to line up on every
>>>>>>>> single line, unless you have monospaced text.
>>>>>>>> ie the "pixel" position is going to get converted into a
>>>>>>>> position on the leading or trailing edge of some glyph
>>>>>>>>
>>>>>>>> So I wonder, does adding float matter .. is the extra precision
>>>>>>>> valuable here ?
>>>>>>> It may depend on the rounding of a point position.
>>>>>>> Suppose there are two lines with the same text. The caret is
>>>>>>> on the first line can have x position N.25. Pressing down the
>>>>>>> arrow key can round it to the N and the caret can be set to a
>>>>>>> previous char on the second line.
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Alexandr.
>>>>>>>
>>>>>>>>
>>>>>>>> -phil.
>>>>>>>>
>>>>>>>> On 08/04/2016 05:44 AM, Alexandr Scherbatiy wrote:
>>>>>>>>>
>>>>>>>>> Hello,
>>>>>>>>>
>>>>>>>>> Could you review the fix:
>>>>>>>>> bug: https://bugs.openjdk.java.net/browse/JDK-8163124
>>>>>>>>> webrev: http://cr.openjdk.java.net/~alexsch/8163124/webrev.00
>>>>>>>>>
>>>>>>>>> The text position can have floating point value on HiDPI
>>>>>>>>> display. The Caret interface should be updated to allow use
>>>>>>>>> floating point positions.
>>>>>>>>>
>>>>>>>>> The fix adds the following public API with floating point
>>>>>>>>> positions:
>>>>>>>>> javax.swing.text.Caret.getMagicCaretPosition2D()
>>>>>>>>> javax.swing.text.Caret.setMagicCaretPosition2D(Point2D p)
>>>>>>>>> javax.swing.text.JTextComponent.modelToView2D(int pos)
>>>>>>>>> javax.swing.text.JTextComponent.viewToModel2D(Point2D pt)
>>>>>>>>> javax.swing.text.ParagraphView.getClosestPositionTo(int pos,
>>>>>>>>> Position.Bias b, Shape a, int direction, Position.Bias[], int
>>>>>>>>> rowIndex, float x)
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> The fix replaces
>>>>>>>>> Caret.getMagicCaretPosition()/setMagicCaretPosition(Point p)
>>>>>>>>> to
>>>>>>>>> Caret.getMagicCaretPosition2D()/setMagicCaretPosition2D(Point2D
>>>>>>>>> p) in all places
>>>>>>>>> except DefaultCaret because DefaultCaret extends Rectangle
>>>>>>>>> so its coordinates always have int values.
>>>>>>>>> I have filled a separated enhancement for this JDK-8163174
>>>>>>>>> Add DefaultCaret2D which supports floating point API
>>>>>>>>>
>>>>>>>>> To make a custom caret use floating point API it is also
>>>>>>>>> necessary that PlainView.modelToView() returns a rectangle
>>>>>>>>> with floating point values. It can be done after the fix
>>>>>>>>> JDK-8156217 Selected text is shifted on HiDPI display
>>>>>>>>> which implements Utilities.getTabbedTextWidth(Segment s,
>>>>>>>>> FontMetrics metrics, float x, TabExpander e, int startOffset)
>>>>>>>>> method.
>>>>>>>>> I have filled a separated issue on it:
>>>>>>>>> JDK-8163175 PlainView.modelToView() method should return
>>>>>>>>> Rectangle2D
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Alexandr.
>>>>>>>>
>>>>>>>
>>>>>
>>>>
>>>
>>
More information about the swing-dev
mailing list