提交 e5c72fdd 编写于 作者: G gsm

4337267: Arabic Numeral Shaping

Reviewed-by: peterz
上级 6dddd7cd
......@@ -30,6 +30,7 @@ import java.text.AttributedCharacterIterator;
import java.text.BreakIterator;
import java.awt.font.*;
import java.awt.geom.AffineTransform;
import javax.swing.JComponent;
import javax.swing.event.DocumentEvent;
import sun.font.BidiUtils;
......@@ -301,6 +302,13 @@ class TextLayoutStrategy extends FlowView.FlowStrategy {
iter = BreakIterator.getLineInstance();
}
Object shaper = null;
if (c instanceof JComponent) {
shaper = ((JComponent) c).getClientProperty(
TextAttribute.NUMERIC_SHAPING);
}
text.setShaper(shaper);
measurer = new LineBreakMeasurer(text, iter, frc);
// If the children of the FlowView's logical view are GlyphViews, they
......@@ -399,6 +407,10 @@ class TextLayoutStrategy extends FlowView.FlowStrategy {
return pos - v.getStartOffset() + getBeginIndex();
}
private void setShaper(Object shaper) {
this.shaper = shaper;
}
// --- AttributedCharacterIterator methods -------------------------
/**
......@@ -511,6 +523,8 @@ class TextLayoutStrategy extends FlowView.FlowStrategy {
} else if( attribute == TextAttribute.RUN_DIRECTION ) {
return
v.getDocument().getProperty(TextAttribute.RUN_DIRECTION);
} else if (attribute == TextAttribute.NUMERIC_SHAPING) {
return shaper;
}
return null;
}
......@@ -532,8 +546,10 @@ class TextLayoutStrategy extends FlowView.FlowStrategy {
keys = new HashSet<Attribute>();
keys.add(TextAttribute.FONT);
keys.add(TextAttribute.RUN_DIRECTION);
keys.add(TextAttribute.NUMERIC_SHAPING);
}
private Object shaper = null;
}
}
......@@ -192,6 +192,19 @@ public class SwingUtilities2 {
fontCache = new LSBCacheEntry[CACHE_SIZE];
}
/**
* Fill the character buffer cache. Return the buffer length.
*/
private static int syncCharsBuffer(String s) {
int length = s.length();
if ((charsBuffer == null) || (charsBuffer.length < length)) {
charsBuffer = s.toCharArray();
} else {
s.getChars(0, length, charsBuffer, 0);
}
return length;
}
/**
* checks whether TextLayout is required to handle characters.
*
......@@ -353,7 +366,21 @@ public class SwingUtilities2 {
if (string == null || string.equals("")) {
return 0;
}
return fm.stringWidth(string);
boolean needsTextLayout = ((c != null) &&
(c.getClientProperty(TextAttribute.NUMERIC_SHAPING) != null));
if (needsTextLayout) {
synchronized(charsBufferLock) {
int length = syncCharsBuffer(string);
needsTextLayout = isComplexLayout(charsBuffer, 0, length);
}
}
if (needsTextLayout) {
TextLayout layout = createTextLayout(c, string,
fm.getFont(), fm.getFontRenderContext());
return (int) layout.getAdvance();
} else {
return fm.stringWidth(string);
}
}
......@@ -394,21 +421,11 @@ public class SwingUtilities2 {
String string, int availTextWidth) {
// c may be null here.
String clipString = "...";
int stringLength = string.length();
availTextWidth -= SwingUtilities2.stringWidth(c, fm, clipString);
if (availTextWidth <= 0) {
//can not fit any characters
return clipString;
}
boolean needsTextLayout;
synchronized (charsBufferLock) {
if (charsBuffer == null || charsBuffer.length < stringLength) {
charsBuffer = string.toCharArray();
} else {
string.getChars(0, stringLength, charsBuffer, 0);
}
int stringLength = syncCharsBuffer(string);
needsTextLayout =
isComplexLayout(charsBuffer, 0, stringLength);
if (!needsTextLayout) {
......@@ -425,6 +442,10 @@ public class SwingUtilities2 {
if (needsTextLayout) {
FontRenderContext frc = getFontRenderContext(c, fm);
AttributedString aString = new AttributedString(string);
if (c != null) {
aString.addAttribute(TextAttribute.NUMERIC_SHAPING,
c.getClientProperty(TextAttribute.NUMERIC_SHAPING));
}
LineBreakMeasurer measurer =
new LineBreakMeasurer(aString.getIterator(), frc);
int nChars = measurer.nextOffset(availTextWidth);
......@@ -465,7 +486,7 @@ public class SwingUtilities2 {
*/
float screenWidth = (float)
g2d.getFont().getStringBounds(text, DEFAULT_FRC).getWidth();
TextLayout layout = new TextLayout(text, g2d.getFont(),
TextLayout layout = createTextLayout(c, text, g2d.getFont(),
g2d.getFontRenderContext());
layout = layout.getJustifiedLayout(screenWidth);
......@@ -505,7 +526,21 @@ public class SwingUtilities2 {
}
}
g.drawString(text, x, y);
boolean needsTextLayout = ((c != null) &&
(c.getClientProperty(TextAttribute.NUMERIC_SHAPING) != null));
if (needsTextLayout) {
synchronized(charsBufferLock) {
int length = syncCharsBuffer(text);
needsTextLayout = isComplexLayout(charsBuffer, 0, length);
}
}
if (needsTextLayout) {
TextLayout layout = createTextLayout(c, text, g2.getFont(),
g2.getFontRenderContext());
layout.draw(g2, x, y);
} else {
g.drawString(text, x, y);
}
if (oldAAValue != null) {
g2.setRenderingHint(KEY_TEXT_ANTIALIASING, oldAAValue);
......@@ -547,11 +582,7 @@ public class SwingUtilities2 {
boolean needsTextLayout = isPrinting;
if (!needsTextLayout) {
synchronized (charsBufferLock) {
if (charsBuffer == null || charsBuffer.length < textLength) {
charsBuffer = text.toCharArray();
} else {
text.getChars(0, textLength, charsBuffer, 0);
}
syncCharsBuffer(text);
needsTextLayout =
isComplexLayout(charsBuffer, 0, textLength);
}
......@@ -567,7 +598,7 @@ public class SwingUtilities2 {
Graphics2D g2d = getGraphics2D(g);
if (g2d != null) {
TextLayout layout =
new TextLayout(text, g2d.getFont(),
createTextLayout(c, text, g2d.getFont(),
g2d.getFontRenderContext());
if (isPrinting) {
float screenWidth = (float)g2d.getFont().
......@@ -728,7 +759,7 @@ public class SwingUtilities2 {
!isFontRenderContextPrintCompatible
(deviceFontRenderContext, frc)) {
TextLayout layout =
new TextLayout(new String(data,offset,length),
createTextLayout(c, new String(data, offset, length),
g2d.getFont(),
deviceFontRenderContext);
float screenWidth = (float)g2d.getFont().
......@@ -846,6 +877,20 @@ public class SwingUtilities2 {
return retVal;
}
private static TextLayout createTextLayout(JComponent c, String s,
Font f, FontRenderContext frc) {
Object shaper = (c == null ?
null : c.getClientProperty(TextAttribute.NUMERIC_SHAPING));
if (shaper == null) {
return new TextLayout(s, f, frc);
} else {
Map<TextAttribute, Object> a = new HashMap<TextAttribute, Object>();
a.put(TextAttribute.FONT, f);
a.put(TextAttribute.NUMERIC_SHAPING, shaper);
return new TextLayout(s, a, frc);
}
}
/*
* Checks if two given FontRenderContexts are compatible for printing.
* We can't just use equals as we want to exclude from the comparison :
......
/*
* @test
* @bug 4337267
* @summary test that numeric shaping works in Swing components
* @author Sergey Groznyh
* @run main bug4337267
*/
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.font.NumericShaper;
import java.awt.font.TextAttribute;
import java.awt.image.BufferedImage;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class bug4337267 {
TestJPanel p1, p2;
TestBufferedImage i1, i2;
JComponent[] printq;
JFrame window;
static boolean testFailed = false;
static boolean done = false;
String shaped =
"000 (E) 111 (A) \u0641\u0642\u0643 \u0662\u0662\u0662 (E) 333";
String text = "000 (E) 111 (A) \u0641\u0642\u0643 222 (E) 333";
void run() {
initUI();
testTextComponent();
testNonTextComponentHTML();
testNonTextComponentPlain();
doneTask();
}
void initUI() {
window = new JFrame("bug4337267");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(800, 600);
Component content = createContentPane();
window.add(content);
window.setVisible(true);
}
Runnable printComponents = new Runnable() {
public void run() {
printComponent(printq[0], i1);
printComponent(printq[1], i2);
}
};
Runnable compareRasters = new Runnable() {
public void run() {
assertEquals(p1.image, p2.image);
assertEquals(i1, i2);
}
};
void doneTask() {
final Object monitor = this;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
done = true;
synchronized(monitor) {
monitor.notify();
}
}
});
}
void fail(String message) {
testFailed = true;
throw new RuntimeException(message);
}
void assertEquals(Object o1, Object o2) {
if ((o1 == null) && (o2 != null)) {
fail("Expected null, got " + o2);
} else if ((o1 != null) && (o2 == null)) {
fail("Expected " + o1 + ", got null");
} else if (!o1.equals(o2)) {
fail("Expected " + o1 + ", got " + o2);
}
}
void testTextComponent() {
System.out.println("testTextComponent:");
JTextArea area1 = new JTextArea();
injectComponent(p1, area1, false);
area1.setText(shaped);
JTextArea area2 = new JTextArea();
injectComponent(p2, area2, true);
area2.setText(text);
window.repaint();
printq = new JComponent[] { area1, area2 };
SwingUtilities.invokeLater(printComponents);
SwingUtilities.invokeLater(compareRasters);
}
void testNonTextComponentHTML() {
System.out.println("testNonTextComponentHTML:");
JLabel label1 = new JLabel();
injectComponent(p1, label1, false);
label1.setText("<html>" + shaped);
JLabel label2 = new JLabel();
injectComponent(p2, label2, true);
label2.setText("<html>" + text);
window.repaint();
printq = new JComponent[] { label1, label2 };
SwingUtilities.invokeLater(printComponents);
SwingUtilities.invokeLater(compareRasters);
}
void testNonTextComponentPlain() {
System.out.println("testNonTextComponentHTML:");
JLabel label1 = new JLabel();
injectComponent(p1, label1, false);
label1.setText(shaped);
JLabel label2 = new JLabel();
injectComponent(p2, label2, true);
label2.setText(text);
window.repaint();
printq = new JComponent[] { label1, label2 };
SwingUtilities.invokeLater(printComponents);
SwingUtilities.invokeLater(compareRasters);
}
void setShaping(JComponent c) {
c.putClientProperty(TextAttribute.NUMERIC_SHAPING,
NumericShaper.getContextualShaper(NumericShaper.ARABIC));
}
void injectComponent(JComponent p, JComponent c, boolean shape) {
if (shape) {
setShaping(c);
}
p.removeAll();
p.add(c);
}
void printComponent(JComponent c, TestBufferedImage i) {
Graphics g = i.getGraphics();
g.setColor(c.getBackground());
g.fillRect(0, 0, i.getWidth(), i.getHeight());
c.print(g);
}
Component createContentPane() {
Dimension size = new Dimension(500, 100);
i1 = new TestBufferedImage(size.width, size.height,
BufferedImage.TYPE_INT_ARGB);
i2 = new TestBufferedImage(size.width, size.height,
BufferedImage.TYPE_INT_ARGB);
p1 = new TestJPanel();
p1.setPreferredSize(size);
p2 = new TestJPanel();
p2.setPreferredSize(size);
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(p1);
panel.add(p2);
return panel;
}
static class TestBufferedImage extends BufferedImage {
int MAX_GLITCHES = 0;
TestBufferedImage(int width, int height, int imageType) {
super(width, height, imageType);
}
@Override
public boolean equals(Object other) {
if (! (other instanceof TestBufferedImage)) {
return false;
}
TestBufferedImage image2 = (TestBufferedImage) other;
int width = getWidth();
int height = getHeight();
if ((image2.getWidth() != width) || (image2.getHeight() != height)) {
return false;
}
int glitches = 0;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int rgb1 = getRGB(x, y);
int rgb2 = image2.getRGB(x, y);
if (rgb1 != rgb2) {
//System.out.println(x+" "+y+" "+rgb1+" "+rgb2);
glitches++;
}
}
}
return glitches <= MAX_GLITCHES;
}
}
static class TestJPanel extends JPanel {
TestBufferedImage image = createImage(new Dimension(1, 1));
TestBufferedImage createImage(Dimension d) {
return new TestBufferedImage(d.width, d.height,
BufferedImage.TYPE_INT_ARGB);
}
public void setPreferredSize(Dimension size) {
super.setPreferredSize(size);
image = createImage(size);
}
public void paint(Graphics g) {
Graphics g0 = image.getGraphics();
super.paint(g0);
g.drawImage(image, 0, 0, this);
}
}
public static void main(String[] args) throws Throwable {
final bug4337267 test = new bug4337267();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
test.run();
}
});
synchronized(test) {
while (!done) {
try {
test.wait();
} catch (InterruptedException ex) {
// do nothing
}
}
}
if (testFailed) {
throw new RuntimeException("FAIL");
}
System.out.println("OK");
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册