JDK-6684056 : SUPERSCRIPT TextAttribute on font needs to trigger layout.
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 6
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2008-04-03
  • Updated: 2011-03-07
  • Resolved: 2011-03-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7
6u10Fixed 7 b28Fixed
Description
The program below draws a simple string under a rotation transform from
0->360 degrees, and offers options to select strike through, underline,
and superscript options.

When just the superscript option is shown it can be seen that under
rotations, the position of the text from drawString and TextLayout is not
in agreement. If its used in conjunction with either or both of the other
attributes there is no problem.

import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
import java.awt.geom.AffineTransform;
import java.util.HashMap;

public class TBT extends Canvas implements Runnable {
    Checkbox strikethrough;
    Checkbox underline;
    Checkbox superscript;

    int angle;

    @Override
    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        Font fnt = new Font("Arial", Font.PLAIN, 20);
        fnt = fnt.deriveFont(60.0f);
        HashMap attrMap = new HashMap();
        if (strikethrough.getState()) {
            attrMap.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
        }
        if (underline.getState()) {
            attrMap.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
        }
        if (superscript.getState()) {
            attrMap.put(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER);
        }
        fnt = fnt.deriveFont(attrMap);
        AffineTransform aff = AffineTransform.getRotateInstance(angle * Math.PI/180.0);
        fnt = fnt.deriveFont(aff);

        g2d.setFont(fnt);
        g2d.translate(200, 200);

        TextLayout tl = new TextLayout("Text", fnt, g2d.getFontRenderContext());        g2d.setColor(Color.yellow);
        g2d.fill(tl.getBounds());

        g2d.setColor(Color.blue);
        tl.draw(g2d,0f,0f);

        g2d.setColor(Color.black);
        g2d.drawString("Text", 0, 0);
    }

    public void start() {
        Thread t = new Thread(this);
        t.run();
    }
    public void run() {
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                return;
            }
            angle += 1;
            repaint();
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(400, 400);
    }

    public Panel getPanel() {
        Panel p = new Panel();
        p.add(strikethrough = makeCheckbox("strikethrough"));
        p.add(underline = makeCheckbox("underline"));
        p.add(superscript = makeCheckbox("superscript"));
        return p;
    }

    public Checkbox makeCheckbox(String label) {
        Checkbox cb = new Checkbox(label);
        cb.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                repaint();
            }
        });
        return cb;
    }

    public static void main(String argv[]) {
        Frame f = new Frame("Text bounds test");
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        TBT tbt = new TBT();
        f.add(tbt, BorderLayout.CENTER);
        f.add(tbt.getPanel(), BorderLayout.SOUTH);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        tbt.start();
    }
}

Comments
EVALUATION All of these attributes should trigger layout (ie TextLayout.draw to be internally used to implement drawString), but presently the superscript does not on its own. Superscripting is presently implemented as a font transformation, but drawString can't handle this properly under rotation. And in any case if we were to provide proper font table driven superscripting that would require layout.
03-04-2008