Fabian Kraemer  committed dc8e619


  • Participants

Comments (0)

Files changed (5)

+# Eclipse
+# Intellij
+# Mac
+# Maven
+The ```LineBreakMeasurerTest``` application provokes a contract violation in the Oracle implementation of ```java.awt.font.TextMeasurer#getLineBreakIndex(int, float)```. The method escapes with a ```java.lang.ArrayIndexOutOfBoundsException``` where [the JavaDoc only mentions](, float\)) that it might escape with a ```java.lang.IllegalArgumentException```. The exception originates from ```sun.font.ExtendedTextSourceLabel.createCharinfo()```, and is only provoked for the ```Calibri```, ```Calibri Bold```, ```Calibri Bold Italic```, ```Calibri Italic``` and ```Cambria Bold``` fonts on the 1.6.0u45 and 1.7.0u21 JVMs for Windows.
+```LineBreakMeasurerTest``` will try to calculate a ```TextLayout``` on a given canvas for all available fonts, ```java.awt.GraphicsEnvironment#getLocalGraphicsEnvironment()#getAllFonts()```, thus provoking the issue for the above mentioned fonts. You can prepare it with ```mkdir -p target/classes;cp src/main/resources/run.bat target/classes;javac src/main/java/ -d target/classes``` or use [Maven 3](, e.g. ```mvn package```, and then execute it via ```java -cp target\classes LineBreakMeasurerTest``` with your default JVM. The script ```target\classes\run.bat jdk1.7.0_21``` makes it easier to run the program against several JVM installations, assuming that they are installed under ```C:\Program Files\Java\``` and where ```jdk1.7.0_21``` denotes the subdirectory of the JVM to be used.
+Unfortunately, 1.6.0u45 was the last public update since 6 is now EOL. I couldn't get hold off the [1.6.0u51]( JVM as it is only available through the Java SE Support program. Given that the issue is fixed in 1.7.0u25, I assume it's fixed in 1.6.0u51 as well as they [share the same baseline]( 1.6.0u45 and 1.7.0u21 were [both released on 2013-04-16](, so I assume that what has happened is that the regression was introduced on the 6 branch and then merged upstream for the 7 release. The issue must have been identified or fixed by accident internally given that I could not find any relevant bug report or public documentation for the involved frames.
+```LineBreakMeasurerTest``` succeeds in the ```TextLayout``` calculation for all fonts, including the above mentioned ones, on 
+java version "1.6.0_43"
+Java(TM) SE Runtime Environment (build 1.6.0_43-b01)
+Java HotSpot(TM) 64-Bit Server VM (build 20.14-b01, mixed mode)
+java version "1.7.0_25"
+Java(TM) SE Runtime Environment (build 1.7.0_25-b17)
+Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)
+It fails for the above mentioned fonts on
+java version "1.6.0_45"
+Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
+Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode)
+java version "1.7.0_21"
+Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
+Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)
+Note that I also tested this with the 32-Bit versions of those JVMs with the same results.
+The problem was originally hit by the viewfile macro from [Confluence's Office Connector]( using a PowerPoint presentation (.ppt) containing text in the Calibri font. The stack trace looked like this
+2013-07-23 11:02:05,493 ERROR [DefaultSlideCacheManager:thread-3] [com.benryan.conversion.AbstractSlideConversionTask] call problem while converting testing.pptx
+ -- url: /confluence/plugins/servlet/pptslide | userName: admin | referer: http://localhost:1990/confluence/s/en_GB/3280/1/2.1.4/_/download/resources/com.atlassian.confluence.extra.officeconnector:pptslideservlet/co
+java.lang.ArrayIndexOutOfBoundsException: 0
+	at sun.font.ExtendedTextSourceLabel.createCharinfo(
+	at sun.font.ExtendedTextSourceLabel.getCharinfo(
+	at sun.font.ExtendedTextSourceLabel.getLineBreakIndex(
+	at java.awt.font.TextMeasurer.calcLineBreak(
+	at java.awt.font.TextMeasurer.getLineBreakIndex(
+	at java.awt.font.LineBreakMeasurer.nextOffset(
+	at java.awt.font.LineBreakMeasurer.nextLayout(
+	at java.awt.font.LineBreakMeasurer.nextLayout(
+	at com.benryan.ppt.ParagraphLayout.layoutParagraph(
+	at com.benryan.escher.EscherRenderer.drawText(
+	at com.benryan.escher.EscherRenderer.renderAutoshape(
+	at com.benryan.escher.EscherRenderer.walkShapes(
+	at com.benryan.ppt.PptRenderer.render(
+	at com.benryan.conversion.PPtDocumentConversionTask.convertFile(
+	at com.benryan.conversion.PPtDocumentConversionTask.convertFile(
+	at
+	at java.util.concurrent.FutureTask$Sync.innerRun(
+	at
+	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(
+	at java.util.concurrent.ThreadPoolExecutor$
+	at
+<project xmlns="" xmlns:xsi="" xsi:schemaLocation="">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.atlassian.confluence.test</groupId>
+    <artifactId>line-break-measurer-test</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <parent>
+        <groupId>com.atlassian.pom</groupId>
+        <artifactId>atlassian-closedsource-pom</artifactId>
+        <version>38</version>
+    </parent>
+    <organization>
+        <name>Atlassian</name>
+        <url></url>
+    </organization>
+    <scm>
+        <connection>scm:git:ssh://</connection>
+        <developerConnection>scm:git:ssh://</developerConnection>
+        <url></url>
+    </scm>
+    <name>line-break-measurer-test</name>
+    <packaging>jar</packaging>
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.6</source>
+                    <target>1.6</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>

File src/main/java/

+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.font.LineBreakMeasurer;
+import java.awt.font.TextAttribute;
+import java.awt.font.TextLayout;
+import java.awt.image.BufferedImage;
+import java.text.AttributedString;
+public class LineBreakMeasurerTest
+    public static void main(String[] args)
+    {
+        Graphics2D canvas = (Graphics2D) new BufferedImage(960, 720, BufferedImage.TYPE_INT_RGB).getGraphics();
+        AttributedString testString = new AttributedString("testing");
+        GraphicsEnvironment localGraphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        Font[] fonts = localGraphicsEnvironment.getAllFonts();
+        for (Font font : fonts) {
+            testString.addAttribute(TextAttribute.FONT, font);
+            LineBreakMeasurer measurer = new LineBreakMeasurer(testString.getIterator(), canvas.getFontRenderContext());
+            try
+            {
+                TextLayout layout = measurer.nextLayout(798.0f);
+                System.out.println(String.format("SUCCESS: Calculated %s with font %s", layout, font));
+            }
+            catch(RuntimeException e)
+            {
+                System.err.println(String.format("ERROR: Layout calculation escaped with [%s] for font %s", e.getClass().getName(), font));
+            }
+        }
+    }

File src/main/resources/run.bat

+set JAVA_HOME=C:\Program Files\Java\%1
+set PATH=%JAVA_HOME%\bin;%PATH%
+java -version
+java -classpath %~dp0 LineBreakMeasurerTest