Commits

Fabian Kraemer  committed dc8e619

init

  • Participants

Comments (0)

Files changed (5)

+# Eclipse
+.classpath
+.project
+.settings/
+
+# Intellij
+.idea/
+*.iml
+*.iws
+
+# Mac
+.DS_Store
+
+# Maven
+log/
+target/
+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](http://docs.oracle.com/javase/6/docs/api/java/awt/font/TextMeasurer.html#getLineBreakIndex(int, 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/LineBreakMeasurerTest.java -d target/classes``` or use [Maven 3](http://maven.apache.org/download.cgi), 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](http://en.wikipedia.org/wiki/Java_version_history#cite_ref-6u51_79-0) 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](http://www.oracle.com/technetwork/java/javase/7u25-relnotes-1955741.html). 1.6.0u45 and 1.7.0u21 were [both released on 2013-04-16](http://en.wikipedia.org/wiki/Java_version_history#Java_SE_6_.28December_11.2C_2006.29), 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)
+```
+
+and
+
+```
+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)
+```
+
+and
+
+```
+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](https://confluence.atlassian.com/display/DOC/Embedding+PowerPoint+Presentations+in+a+Page) 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(ExtendedTextSourceLabel.java:592)
+	at sun.font.ExtendedTextSourceLabel.getCharinfo(ExtendedTextSourceLabel.java:492)
+	at sun.font.ExtendedTextSourceLabel.getLineBreakIndex(ExtendedTextSourceLabel.java:438)
+	at java.awt.font.TextMeasurer.calcLineBreak(TextMeasurer.java:308)
+	at java.awt.font.TextMeasurer.getLineBreakIndex(TextMeasurer.java:544)
+	at java.awt.font.LineBreakMeasurer.nextOffset(LineBreakMeasurer.java:340)
+	at java.awt.font.LineBreakMeasurer.nextLayout(LineBreakMeasurer.java:422)
+	at java.awt.font.LineBreakMeasurer.nextLayout(LineBreakMeasurer.java:395)
+	at com.benryan.ppt.ParagraphLayout.layoutParagraph(ParagraphLayout.java:236)
+	at com.benryan.escher.EscherRenderer.drawText(EscherRenderer.java:361)
+	at com.benryan.escher.EscherRenderer.renderAutoshape(EscherRenderer.java:596)
+	at com.benryan.escher.EscherRenderer.walkShapes(EscherRenderer.java:233)
+	at com.benryan.ppt.PptRenderer.render(PptRenderer.java:128)
+	at com.benryan.conversion.PPtDocumentConversionTask.convertFile(PPtDocumentConversionTask.java:54)
+	at com.benryan.conversion.PPtDocumentConversionTask.convertFile(PPtDocumentConversionTask.java:15)
+	at com.benryan.conversion.AbstractSlideConversionTask.call(AbstractSlideConversionTask.java:44)
+	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
+	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
+	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
+	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
+	at java.lang.Thread.run(Thread.java:662)
+```
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <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>http://www.atlassian.com/</url>
+    </organization>
+
+    <scm>
+        <connection>scm:git:ssh://git@bitbucket.org/fakraemer/line-break-measurer-test.git</connection>
+        <developerConnection>scm:git:ssh://git@bitbucket.org/fakraemer/line-break-measurer-test.git</developerConnection>
+        <url>https://bitbucket.org/fakraemer/line-break-measurer-test</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>
+
+</project>

File src/main/java/LineBreakMeasurerTest.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