]> source.dussan.org Git - poi.git/commitdiff
Added workarounds to tests for JDK 6 LineBreakMeasurer bug and handle it
authorAndreas Beeker <kiwiwings@apache.org>
Fri, 12 Dec 2014 01:43:45 +0000 (01:43 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Fri, 12 Dec 2014 01:43:45 +0000 (01:43 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1644806 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java
src/java/org/apache/poi/util/JvmBugs.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java
src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetAutosizeColumn.java

index 2d2eaa752eecb1d96b085a67ff695141b49c8029..e7784ae427a58948715ed7f38cbc351f44938560 100644 (file)
@@ -20,6 +20,7 @@ package org.apache.poi.hssf.usermodel;
 import java.awt.Dimension;
 import java.io.ByteArrayInputStream;
 import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
 
 import org.apache.poi.ddf.DefaultEscherRecordFactory;
 import org.apache.poi.ddf.EscherBSERecord;
@@ -218,19 +219,14 @@ public class HSSFPicture extends HSSFSimpleShape implements Picture {
     }
 
     /**
-     * The color applied to the lines of this shape.
+     * The filename of the embedded image
      */
     public String getFileName() {
         EscherComplexProperty propFile = (EscherComplexProperty) getOptRecord().lookup(
                       EscherProperties.BLIP__BLIPFILENAME);
-        try {
-            if (null == propFile){
-                return "";
-            }
-            return new String(propFile.getComplexData(), "UTF-16LE").trim();
-        } catch (UnsupportedEncodingException e) {
-            return "";
-        }
+        return (null == propFile)
+            ? ""
+            : new String(propFile.getComplexData(), Charset.forName("UTF-16LE")).trim();
     }
     
     public void setFileName(String data){
diff --git a/src/java/org/apache/poi/util/JvmBugs.java b/src/java/org/apache/poi/util/JvmBugs.java
new file mode 100644 (file)
index 0000000..ecb7e32
--- /dev/null
@@ -0,0 +1,51 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.util;\r
+\r
+public class JvmBugs {\r
+    private static final POILogger LOG = POILogFactory.getLogger(JvmBugs.class);\r
+    \r
+    /**\r
+     * The LineBreakMeasurer is used for calculating text bounds.\r
+     * The last official JDK 6 version (1.6.0_45) and also JDK 7 (1.7.0_21)\r
+     * for Windows are affected. For JDK 7 - update to a more recent version.\r
+     * For JDK 6 - replace the fontmanager.dll with the previous release.\r
+     * \r
+     * For performance reasons, this method only checks for a windows jvm\r
+     * with version 1.6.0_45 and 1.7.0_21.\r
+     * \r
+     * Set system property "org.apache.poi.JvmBugs.LineBreakMeasurer.ignore" to "true"\r
+     * to bypass this check and use the normal fonts.\r
+     * \r
+     * @return true, if jvm is bugged, caller code should use Lucida Sans\r
+     * instead of Calibri and Lucida Bright instead of Cambria\r
+     * \r
+     * @see <a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=54904">POI Bug #54904</a>\r
+     * @see <a href="http://bugs.java.com/view_bug.do?bug_id=6501991">JDK Bug #6501991</a>\r
+     * @see <a href="https://bitbucket.org/fakraemer/line-break-measurer-test">LineBreakMeasurerTest</a>\r
+     */\r
+    public static boolean hasLineBreakMeasurerBug() {\r
+        String version = System.getProperty("java.version");\r
+        String os = System.getProperty("os.name").toLowerCase();\r
+        boolean ignore = Boolean.getBoolean("org.apache.poi.JvmBugs.LineBreakMeasurer.ignore");\r
+        boolean hasBug = (!ignore && (os.contains("win") && ("1.6.0_45".equals(version) || "1.7.0_21".equals(version))));\r
+        if (hasBug) {\r
+            LOG.log(POILogger.WARN, "JVM has LineBreakMeasurer bug - see POI bug #54904 - caller code might default to Lucida Sans");\r
+        }\r
+        return hasBug;\r
+    }\r
+}\r
index 78efb49dd14efacb02da5c5bba6e865335259f28..e0b383a76bf7ea9a1b9f0a6b391115667ae69216 100644 (file)
 ==================================================================== */\r
 package org.apache.poi.xslf.usermodel;\r
 \r
-import org.apache.poi.util.Beta;\r
-import org.apache.poi.util.Internal;\r
-import org.apache.poi.util.Units;\r
-import org.apache.poi.xslf.model.ParagraphPropertyFetcher;\r
-import org.apache.xmlbeans.XmlObject;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.*;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;\r
-\r
 import java.awt.Color;\r
 import java.awt.Graphics2D;\r
 import java.awt.font.LineBreakMeasurer;\r
@@ -36,6 +27,35 @@ import java.text.AttributedString;
 import java.util.ArrayList;\r
 import java.util.Iterator;\r
 import java.util.List;\r
+import java.util.Map;\r
+\r
+import org.apache.poi.hslf.model.TextPainter;\r
+import org.apache.poi.util.Beta;\r
+import org.apache.poi.util.Internal;\r
+import org.apache.poi.util.Units;\r
+import org.apache.poi.xslf.model.ParagraphPropertyFetcher;\r
+import org.apache.xmlbeans.XmlObject;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextAutonumberBullet;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePercent;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePoint;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharBullet;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextField;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStop;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStopList;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextAutonumberScheme;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;\r
 \r
 /**\r
  * Represents a paragraph of text within the containing text body.\r
@@ -823,6 +843,11 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
 \r
             // user can pass an custom object to convert fonts\r
             String fontFamily = run.getFontFamily();\r
+            @SuppressWarnings("unchecked")\r
+            Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(TextPainter.KEY_FONTMAP);\r
+            if (fontMap != null && fontMap.containsKey(fontFamily)) {\r
+                fontFamily = fontMap.get(fontFamily);\r
+            }\r
             if(fontHandler != null) {\r
                 fontFamily = fontHandler.getRendererableFont(fontFamily, run.getPitchAndFamily());\r
             }\r
@@ -1016,7 +1041,7 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
         }\r
     }\r
 \r
-    private boolean fetchParagraphProperty(ParagraphPropertyFetcher visitor){\r
+    private <T> boolean fetchParagraphProperty(ParagraphPropertyFetcher<T> visitor){\r
         boolean ok = false;\r
 \r
         if(_p.isSetPPr()) ok = visitor.fetch(_p.getPPr());\r
index 948b792b8b2ab89243377ac203a6054aefff0e6d..5c616cd43a370a2337545ee4a868ebf237ba0604 100644 (file)
 \r
 package org.apache.poi.xslf.usermodel;\r
 \r
-import junit.framework.TestCase;\r
-import org.apache.poi.xslf.XSLFTestDataSamples;\r
-\r
 import java.awt.Dimension;\r
 import java.awt.Graphics2D;\r
 import java.awt.image.BufferedImage;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import org.apache.poi.hslf.model.TextPainter;\r
+import org.apache.poi.util.JvmBugs;\r
+import org.apache.poi.xslf.XSLFTestDataSamples;\r
+import org.junit.Test;\r
 \r
 /**\r
  * Date: 10/26/11\r
  *\r
  * @author Yegor Kozlov\r
  */\r
-public class TestPPTX2PNG extends TestCase {\r
-    public void testRender(){\r
+public class TestPPTX2PNG {\r
+    @Test\r
+    public void render(){\r
         String[] testFiles = {"layouts.pptx", "sample.pptx", "shapes.pptx",\r
                 "themes.pptx", "backgrounds.pptx"};\r
         for(String sampleFile : testFiles){\r
@@ -41,10 +46,20 @@ public class TestPPTX2PNG extends TestCase {
             for(XSLFSlide slide : pptx.getSlides()){\r
                 BufferedImage img = new BufferedImage(pg.width, pg.height, BufferedImage.TYPE_INT_RGB);\r
                 Graphics2D graphics = img.createGraphics();\r
-\r
+                fixFonts(graphics);\r
                 slide.draw(graphics);\r
 \r
             }\r
         }\r
     }\r
+    \r
+    @SuppressWarnings("unchecked")\r
+    private void fixFonts(Graphics2D graphics) {\r
+        if (!JvmBugs.hasLineBreakMeasurerBug()) return;\r
+        Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(TextPainter.KEY_FONTMAP);\r
+        if (fontMap == null) fontMap = new HashMap<String,String>();\r
+        fontMap.put("Calibri", "Lucida Sans");\r
+        fontMap.put("Cambria", "Lucida Bright");\r
+        graphics.setRenderingHint(TextPainter.KEY_FONTMAP, fontMap);        \r
+    }\r
 }\r
index fb9dd8ea906eb267beccdd596437110e26d017fc..fe11df6589d7ee42a81b2aff37105c98147e2314 100644 (file)
@@ -334,6 +334,7 @@ public abstract class BaseTestBugzillaIssues {
     @Test
     public final void bug506819_testAutoSize() {
         Workbook wb = _testDataProvider.createWorkbook();
+        BaseTestSheetAutosizeColumn.fixFonts(wb);
         Sheet sheet = wb.createSheet("Sheet1");
         Row row = sheet.createRow(0);
         Cell cell0 = row.createCell(0);
index d4b68a0c8ceac771679ab535cdbb9571b8082215..b1aeb637c32631623852ba488805264fc147b388 100644 (file)
 
 package org.apache.poi.ss.usermodel;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.*;
+
 import org.apache.poi.ss.ITestDataProvider;
 import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.util.JvmBugs;
+import org.junit.Test;
 
 import java.util.Calendar;
 
@@ -28,7 +31,7 @@ import java.util.Calendar;
  *
  * @author Yegor Kozlov
  */
-public abstract class BaseTestSheetAutosizeColumn extends TestCase {
+public abstract class BaseTestSheetAutosizeColumn {
 
     private final ITestDataProvider _testDataProvider;
 
@@ -36,23 +39,10 @@ public abstract class BaseTestSheetAutosizeColumn extends TestCase {
         _testDataProvider = testDataProvider;
     }
 
-    // TODO should we have this stuff in the FormulaEvaluator?
-    private void evaluateWorkbook(Workbook workbook){
-        FormulaEvaluator eval = workbook.getCreationHelper().createFormulaEvaluator();
-        for(int i=0; i < workbook.getNumberOfSheets(); i++) {
-            Sheet sheet = workbook.getSheetAt(i);
-            for (Row r : sheet) {
-                for (Cell c : r) {
-                    if (c.getCellType() == Cell.CELL_TYPE_FORMULA){
-                        eval.evaluateFormulaCell(c);
-                    }
-                }
-            }
-        }
-    }
-
-    public void testNumericCells(){
+    @Test
+    public void numericCells(){
         Workbook workbook = _testDataProvider.createWorkbook();
+        fixFonts(workbook);
         DataFormat df = workbook.getCreationHelper().createDataFormat();
         Sheet sheet = workbook.createSheet();
 
@@ -89,8 +79,10 @@ public abstract class BaseTestSheetAutosizeColumn extends TestCase {
         assertEquals(sheet.getColumnWidth(4), sheet.getColumnWidth(5)); // 10.0000 and '10.0000'
     }
 
-    public void testBooleanCells(){
+    @Test
+    public void booleanCells(){
         Workbook workbook = _testDataProvider.createWorkbook();
+        fixFonts(workbook);
         Sheet sheet = workbook.createSheet();
 
         Row row = sheet.createRow(0);
@@ -116,8 +108,10 @@ public abstract class BaseTestSheetAutosizeColumn extends TestCase {
         assertEquals(sheet.getColumnWidth(2), sheet.getColumnWidth(3));  // columns 1, 2 and 3 should have the same width
     }
 
-    public void testDateCells(){
+    @Test
+    public void dateCells(){
         Workbook workbook = _testDataProvider.createWorkbook();
+        fixFonts(workbook);
         Sheet sheet = workbook.createSheet();
         DataFormat df = workbook.getCreationHelper().createDataFormat();
 
@@ -180,11 +174,13 @@ public abstract class BaseTestSheetAutosizeColumn extends TestCase {
         assertEquals(sheet.getColumnWidth(4), sheet.getColumnWidth(7)); // date formula formatted as 'mmm'
     }
 
-    public void testStringCells(){
+    @Test
+    public void stringCells(){
         Workbook workbook = _testDataProvider.createWorkbook();
+        fixFonts(workbook);
         Sheet sheet = workbook.createSheet();
         Row row = sheet.createRow(0);
-
+        
         Font defaultFont = workbook.getFontAt((short)0);
 
         CellStyle style1 = workbook.createCellStyle();
@@ -207,11 +203,14 @@ public abstract class BaseTestSheetAutosizeColumn extends TestCase {
         assertTrue(2*sheet.getColumnWidth(0) < sheet.getColumnWidth(1)); // width is roughly proportional to the number of characters
         assertTrue(2*sheet.getColumnWidth(1) < sheet.getColumnWidth(2));
         assertEquals(sheet.getColumnWidth(4), sheet.getColumnWidth(3));
-        assertTrue(sheet.getColumnWidth(5) > sheet.getColumnWidth(4)); //larger font results in a wider column width
+        boolean ignoreFontSizeX2 = JvmBugs.hasLineBreakMeasurerBug();
+        assertTrue(ignoreFontSizeX2 || sheet.getColumnWidth(5) > sheet.getColumnWidth(4)); //larger font results in a wider column width
     }
 
-    public void testRotatedText(){
+    @Test
+    public void rotatedText(){
         Workbook workbook = _testDataProvider.createWorkbook();
+        fixFonts(workbook);
         Sheet sheet = workbook.createSheet();
         Row row = sheet.createRow(0);
 
@@ -233,8 +232,10 @@ public abstract class BaseTestSheetAutosizeColumn extends TestCase {
         assertTrue(w0*5 < w1); // rotated text occupies at least five times less horizontal space than normal text
     }
 
-    public void testMergedCells(){
+    @Test
+    public void mergedCells(){
         Workbook workbook = _testDataProvider.createWorkbook();
+        fixFonts(workbook);
         Sheet sheet = workbook.createSheet();
 
         Row row = sheet.createRow(0);
@@ -257,8 +258,10 @@ public abstract class BaseTestSheetAutosizeColumn extends TestCase {
      * Auto-Sizing a column needs to work when we have rows
      *  passed the 32767 boundary. See bug #48079
      */
-    public void testLargeRowNumbers() throws Exception {
+    @Test
+    public void largeRowNumbers() throws Exception {
        Workbook workbook = _testDataProvider.createWorkbook();
+       fixFonts(workbook);
        Sheet sheet = workbook.createSheet();
        
        Row r0 = sheet.createRow(0);
@@ -291,4 +294,31 @@ public abstract class BaseTestSheetAutosizeColumn extends TestCase {
        r60708.createCell(0).setCellValue("Near the end");
        sheet.autoSizeColumn(0);
     }
+    
+    // TODO should we have this stuff in the FormulaEvaluator?
+    private void evaluateWorkbook(Workbook workbook){
+        FormulaEvaluator eval = workbook.getCreationHelper().createFormulaEvaluator();
+        for(int i=0; i < workbook.getNumberOfSheets(); i++) {
+            Sheet sheet = workbook.getSheetAt(i);
+            for (Row r : sheet) {
+                for (Cell c : r) {
+                    if (c.getCellType() == Cell.CELL_TYPE_FORMULA){
+                        eval.evaluateFormulaCell(c);
+                    }
+                }
+            }
+        }
+    }
+
+    protected static void fixFonts(Workbook workbook) {
+        if (!JvmBugs.hasLineBreakMeasurerBug()) return;
+        for (int i=workbook.getNumberOfFonts()-1; i>=0; i--) {
+            Font f = workbook.getFontAt((short)0);
+            if ("Calibri".equals(f.getFontName())) {
+                f.setFontName("Lucida Sans");
+            } else if ("Cambria".equals(f.getFontName())) {
+                f.setFontName("Lucida Bright");
+            }
+        }
+    }
 }
\ No newline at end of file