I referred to this issue on this thread many emails ago as one reason why float might be better.

> But we have only API which gets a chars width and draws a text from int position in the user space.

There have been such APIs on the 2D classes since JDK 1.2, eg :

https://docs.oracle.com/javase/8/docs/api/java/awt/Graphics2D.html#drawString-java.lang.String-float-float-
https://docs.oracle.com/javase/8/docs/api/java/awt/Font.html#getStringBounds-java.lang.String-java.awt.font.FontRenderContext-

Swing should be able to use these - or one of the other related ones - where it needs floating point.

When Swing detects complex text it turns over editing and highlighting to TextLayout, does it not ?
Perhaps doing the same for hi-dpi would work as well.

-phil.

On 04/27/2016 01:41 PM, Alexandr Scherbatiy wrote:


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?






Reply via email to