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) 
======================================================================