Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4912220

1.4 REGRESSION: Flipping with asymmetric scaling often distorts fonts

XMLWordPrintable

    • 2d
    • b77
    • x86
    • windows_xp

      Name: jk109818 Date: 08/25/2003


      FULL PRODUCT VERSION :
      java version "1.4.1_02"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_02-b06)
      Java HotSpot(TM) Client VM (build 1.4.1_02-b06, mixed mode)

      FULL OS VERSION :
      Microsoft Windows XP [Version 5.1.2600]

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      Adapter Type S3 Savage/IX, S3 Graphics, Inc. compatible
      Adapter Description S3 Graphics Savage/IX 103C
      Adapter RAM 4.00 MB (4,194,304 bytes)


      A DESCRIPTION OF THE PROBLEM :
      Some combinations of scaling parameters and font sizes cause severe font distortion when applying a flip transform as well. That is, some values of "xscale" and "yscale" used in the following transformation with some font sizes will cause severe font rendering problems:

          | xscale 0 0 |
          | 0 -yscale 0 |

      where as the "non-flipped" transformation does not cause any problems:

          | xscale 0 0 |
          | 0 yscale 0 |

      Examples are given in the sample program below.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile and run the sample program below.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      Flipped fonts should look like mirror images of non-flipped fonts when the same (assymetric) scaling is applied to both.
      Fonts are severely distorted when flipped for many combinations of scaling factors and font sizes.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.awt.*;
      import java.awt.geom.*;

      public class TextFlipBug extends Component {
          static final float PAD = 15.0f;
          static final String STR = "J Q K";

          Font font1 = null;
          Font font2 = null;
          float xscale1, xscale2, yscale1, yscale2;
          static final Font IFONT = new Font("Dialog", Font.PLAIN, 12);

          TextFlipBug(float xs1, float ys1, int fs1,
                    float xs2, float ys2, int fs2) {
              xscale1 = xs1;
              yscale1 = ys1;
              font1 = new Font("serif", Font.PLAIN, fs1);

              xscale2 = xs2;
              yscale2 = ys2;
              font2 = new Font("serif", Font.PLAIN, fs2);
          }

          private void draw_flip(Graphics2D g2,
                                 Font font, // Font to use
                                 String str, // String to point
                                 float xscale, float yscale, // Scale for X and Y
                                 float midx, float midy, // Mid point to draw around
                                 boolean left) // Print to left or right of midx?
          {
              AffineTransform oldtx = g2.getTransform();

              g2.setFont(font);
              FontMetrics fm = g2.getFontMetrics();

              // If printing left of
              float len = xscale * (float) fm.stringWidth(str);
              float lshift = PAD;
              if (left) {
                  lshift = -PAD - len;
              }
              // Scale X and Y and draw string:
              g2.translate(midx + lshift, midy - PAD);
              g2.scale(xscale, yscale);
              g2.drawString(str, 0f, 0f);

              // Flip about Y and draw string:
              g2.setTransform(oldtx);
              g2.translate(midx + lshift, midy + PAD);
              g2.scale(xscale, -yscale);
              g2.drawString(str, 0f, 0f);

              g2.setTransform(oldtx);

              g2.setFont(IFONT);
              String istr = "(XS=" + xscale + ", YS=" + yscale + ", FS=" + font.getSize() + ")";
              fm = g2.getFontMetrics();
              lshift = 2*PAD + len;
              if (left) {
                  lshift = - 2*PAD - len - (float) fm.stringWidth(istr);
              }
              g2.drawString(istr, midx + lshift , midy - PAD);


          }

          public void paint(Graphics g) {
              Graphics2D g2 = (Graphics2D)g;

              // Turning these off/on makes no difference in distortion:
              g2.setRenderingHint( RenderingHints.KEY_FRACTIONALMETRICS,
                                   RenderingHints.VALUE_FRACTIONALMETRICS_ON );
              g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING,
                                   RenderingHints.VALUE_ANTIALIAS_ON );
              g2.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING,
                                   RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
              
              Dimension d = this.getSize();
              float midx = (float) d.getWidth()/2;
              float midy = (float) d.getHeight()/2;

              g2.drawLine((int) midx, 0, (int) midx, d.height);
              g2.drawLine(0, (int) midy, d.width, (int) midy);

              draw_flip(g2, font1, STR, xscale1, yscale1, midx, midy, true);
              draw_flip(g2, font2, STR, xscale2, yscale2, midx, midy, false);
          }

          public static void main(String args[]) {
              Frame f;
              int loc = 0;

              f = new Frame("Yscale under 10.1 is very bad for font size 10 (Xscale closer to 10 helps).");
              TextFlipBug tf = new TextFlipBug(2f, 10.1f, 10, 2f, 10.0f, 10);
              f.add("Center", tf);
              f.pack();
              f.setLocation(loc, loc);
              f.show();
              loc += 50;

              f = new Frame("Font size under 26 is bad for Xscale=2 and Yscale=4.");
              // Any font size below 26 is bad with xscale=2, yscale=4
              tf = new TextFlipBug(2f, 4f, 26, 2f, 4f, 25);
              f.add("Center", tf);
              f.pack();
              f.setLocation(loc, loc);
              f.show();
              loc += 50;

              f = new Frame("Xscale less than 0.9 is bad for Yscale=1.0.");
              //
              tf = new TextFlipBug(0.9f, 1f, 50, 0.5f, 1f, 50);
              f.add("Center", tf);
              f.pack();
              f.setLocation(loc, loc);
              f.show();
              loc += 50;
          }

          public Dimension getPreferredSize() {
              return new Dimension (700, 200);
          }

          public Dimension getMinimumSize() {
              return getPreferredSize();
          }

      }


      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      I couldn't find a satisfactory one. In some cases drawing to a BufferedImage and then flipping the image with a BufferedImageOp might be sufficient, unless you are drawing within the rectangle which bounds the text. I've tried making the image transparent, but this introduces other artifacts.

      Release Regression From : 1.3.1_08
      The above release value was the last known release where this
      bug was known to work. Since then there has been a regression.

      (Incident Review ID: 184900)
      ======================================================================

            igor Igor Nekrestyanov (Inactive)
            jkimsunw Jeffrey Kim (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: