<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