<Swing Dev> [9] Review request for 8132119 Provide public API for text related methods in SwingUtilities2
Alexandr Scherbatiy
alexandr.scherbatiy at oracle.com
Wed Apr 27 20:41:19 UTC 2016
I just want to highlight one more problem which happen even font
metrics with right transform are used.
It refers to the text selection.
Suppose there is a graphics with scale 2. The char 'a' advance can be
13 in device space and 13 / 2 = 6.5 in user space.
The task is to highlight a selected text in the middle of a string
Let's the selected index will be 11. The x coordinate to draw the
selected text is FontMetrics.charsWidth(chars, 0, index) = 72.
The selected text drawn from this position will be shifted to the
right because real x coordinate in user space is 6.5 * 11 = 71.5.
This leads that text is jumping when it is selected and deselected.
To properly draw a selected text in this case there should be API
which allows both return float chars width and draw a text from float
position.
But we have only API which gets a chars width and draws a text from
int position in the user space.
Below is a code which illustrate the text selection issue.
The image shows two strings which are selected from index 10 and 11.
The second selection is shifted to the right:
http://cr.openjdk.java.net/~alexsch/8142966/images/text-selection.png
----------------------------
int imgWidth = 400;
int imgHeight = 150;
BufferedImage buffImage = new BufferedImage(imgWidth, imgHeight,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = buffImage.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, imgWidth, imgHeight);
int x = 10;
int y1 = 20;
int y2 = 40;
g.scale(2, 2);
String text = "aaaaaaaaaaaaaaaaaaaaaaaa";
g.setColor(Color.BLUE);
char[] chars = text.toCharArray();
g.drawChars(chars, 0, chars.length, x, y1);
g.drawChars(chars, 0, chars.length, x, y2);
int selIndex = 10;
int selNum = 6;
FontMetrics fm = g.getFontMetrics(g.getFont());
g.setColor(Color.RED);
g.drawChars(chars, selIndex, selNum, x + fm.charsWidth(chars,
0, selIndex), y1);
selIndex++;
g.drawChars(chars, selIndex, selNum, x + fm.charsWidth(chars,
0, selIndex), y2);
g.dispose();
----------------------------
On 4/27/2016 6:17 AM, Philip Race wrote:
> Applications cannot change the device transform and expect the same
> user space
> metrics unless they specify fractional metrics to be ON.
>
> In your example below you may already have a scaled graphics context
> if you were printing (for example).
>
> If you want no change to the user space positions or [as also implied]
> shapes of the glyphs
> as the transform changes then you are asking for text that will not look
> right at other resolutions. Printed text will look poorly spaced.
>
> Changing what happens in the font system is not an option since it
> will break many applications - even if it were the right thing to do -
> which it is not.
>
> -phil.
>
>
> On 4/26/16, 4:49 PM, Sergey Bylokhov wrote:
>> On 27.04.16 1:50, Phil Race wrote:
>>> Glyphs are always rasterised in device space so it does mean device
>>> space.
>>
>> I don't argue with it, the question is how to round.
>>
>>> The identity transform therefore happens to always return a user space
>>> advance is that is an integer, but it is not bound to be so under any
>>> other transform.
>>
>> I am not sure that this is correct. The simple example:
>>
>> BufferedImage bi = new BufferedImage(width, height,TYPE_INT_ARGB);
>> int length = g2d.getFontMetrics().stringWidth(TEXT);
>> Graphics2D g2d = bi.createGraphics();
>> g2d.scale(2, 2);
>> length = g2d.getFontMetrics().stringWidth(TEXT);
>>
>> In what space will be the length? I assume that this is the user
>> space. Note that if in the second time we get 13 pixels we will round
>> it to 7 (but rendering will be done to 6.5 * 2 = 13). My suggestion
>> in the fix is to make this round on the lower level and use the same
>> values as stringWidth() and during rendering.
>>
>>>
>>> -phil.
>>>
>>> On 04/26/2016 03:28 PM, Sergey Bylokhov wrote:
>>>> On 27.04.16 0:34, Phil Race wrote:
>>>>> Fractional metrics being "off" does not mean that *user space*
>>>>> advances
>>>>> need to be integers,
>>>>> it refers to *device* space advances. Of course if your API does not
>>>>> support floats you have a
>>>>> problem - particularly if - you are character advance adding in which
>>>>> case it is better to ask the
>>>>> font system for the overall advance of the text.
>>>>> https://docs.oracle.com/javase/8/docs/api/java/awt/RenderingHints.html#KEY_FRACTIONALMETRICS
>>>>>
>>>>>
>>>>
>>>> The documentation says that in case of "fm-off" the "simplified system
>>>> based on integer device positions is typically used" + "rounding
>>>> advance widths for rasterized glyphs to integer distances", it does
>>>> not say that the "integer distance" should be rounded to the nearest
>>>> device/pixel. It says that "rounding operations as the high quality
>>>> and very precise definition of the shape and metrics of the character
>>>> glyphs must be matched to discrete device pixels" I guess we should
>>>> confirm the specification because results of the fix will be "discrete
>>>> number of device pixels", isn't it?
>>>>
>>>
>>
>>
More information about the swing-dev
mailing list