diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java
index 2d2eaa752..e7784ae42 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java
@@ -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
index 000000000..ecb7e3200
--- /dev/null
+++ b/src/java/org/apache/poi/util/JvmBugs.java
@@ -0,0 +1,51 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.util;
+
+public class JvmBugs {
+ private static final POILogger LOG = POILogFactory.getLogger(JvmBugs.class);
+
+ /**
+ * The LineBreakMeasurer is used for calculating text bounds.
+ * The last official JDK 6 version (1.6.0_45) and also JDK 7 (1.7.0_21)
+ * for Windows are affected. For JDK 7 - update to a more recent version.
+ * For JDK 6 - replace the fontmanager.dll with the previous release.
+ *
+ * For performance reasons, this method only checks for a windows jvm
+ * with version 1.6.0_45 and 1.7.0_21.
+ *
+ * Set system property "org.apache.poi.JvmBugs.LineBreakMeasurer.ignore" to "true"
+ * to bypass this check and use the normal fonts.
+ *
+ * @return true, if jvm is bugged, caller code should use Lucida Sans
+ * instead of Calibri and Lucida Bright instead of Cambria
+ *
+ * @see POI Bug #54904
+ * @see JDK Bug #6501991
+ * @see LineBreakMeasurerTest
+ */
+ public static boolean hasLineBreakMeasurerBug() {
+ String version = System.getProperty("java.version");
+ String os = System.getProperty("os.name").toLowerCase();
+ boolean ignore = Boolean.getBoolean("org.apache.poi.JvmBugs.LineBreakMeasurer.ignore");
+ boolean hasBug = (!ignore && (os.contains("win") && ("1.6.0_45".equals(version) || "1.7.0_21".equals(version))));
+ if (hasBug) {
+ LOG.log(POILogger.WARN, "JVM has LineBreakMeasurer bug - see POI bug #54904 - caller code might default to Lucida Sans");
+ }
+ return hasBug;
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
index 78efb49dd..e0b383a76 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
@@ -16,15 +16,6 @@
==================================================================== */
package org.apache.poi.xslf.usermodel;
-import org.apache.poi.util.Beta;
-import org.apache.poi.util.Internal;
-import org.apache.poi.util.Units;
-import org.apache.poi.xslf.model.ParagraphPropertyFetcher;
-import org.apache.xmlbeans.XmlObject;
-import org.openxmlformats.schemas.drawingml.x2006.main.*;
-import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
-import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
-
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.font.LineBreakMeasurer;
@@ -36,6 +27,35 @@ import java.text.AttributedString;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+
+import org.apache.poi.hslf.model.TextPainter;
+import org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.Units;
+import org.apache.poi.xslf.model.ParagraphPropertyFetcher;
+import org.apache.xmlbeans.XmlObject;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextAutonumberBullet;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePercent;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePoint;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharBullet;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextField;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStop;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStopList;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextAutonumberScheme;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
+import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
/**
* Represents a paragraph of text within the containing text body.
@@ -823,6 +843,11 @@ public class XSLFTextParagraph implements Iterable{
// user can pass an custom object to convert fonts
String fontFamily = run.getFontFamily();
+ @SuppressWarnings("unchecked")
+ Map fontMap = (Map)graphics.getRenderingHint(TextPainter.KEY_FONTMAP);
+ if (fontMap != null && fontMap.containsKey(fontFamily)) {
+ fontFamily = fontMap.get(fontFamily);
+ }
if(fontHandler != null) {
fontFamily = fontHandler.getRendererableFont(fontFamily, run.getPitchAndFamily());
}
@@ -1016,7 +1041,7 @@ public class XSLFTextParagraph implements Iterable{
}
}
- private boolean fetchParagraphProperty(ParagraphPropertyFetcher visitor){
+ private boolean fetchParagraphProperty(ParagraphPropertyFetcher visitor){
boolean ok = false;
if(_p.isSetPPr()) ok = visitor.fetch(_p.getPPr());
diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
index 948b792b8..5c616cd43 100644
--- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
+++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
@@ -19,20 +19,25 @@
package org.apache.poi.xslf.usermodel;
-import junit.framework.TestCase;
-import org.apache.poi.xslf.XSLFTestDataSamples;
-
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.hslf.model.TextPainter;
+import org.apache.poi.util.JvmBugs;
+import org.apache.poi.xslf.XSLFTestDataSamples;
+import org.junit.Test;
/**
* Date: 10/26/11
*
* @author Yegor Kozlov
*/
-public class TestPPTX2PNG extends TestCase {
- public void testRender(){
+public class TestPPTX2PNG {
+ @Test
+ public void render(){
String[] testFiles = {"layouts.pptx", "sample.pptx", "shapes.pptx",
"themes.pptx", "backgrounds.pptx"};
for(String sampleFile : testFiles){
@@ -41,10 +46,20 @@ public class TestPPTX2PNG extends TestCase {
for(XSLFSlide slide : pptx.getSlides()){
BufferedImage img = new BufferedImage(pg.width, pg.height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
-
+ fixFonts(graphics);
slide.draw(graphics);
}
}
}
+
+ @SuppressWarnings("unchecked")
+ private void fixFonts(Graphics2D graphics) {
+ if (!JvmBugs.hasLineBreakMeasurerBug()) return;
+ Map fontMap = (Map)graphics.getRenderingHint(TextPainter.KEY_FONTMAP);
+ if (fontMap == null) fontMap = new HashMap();
+ fontMap.put("Calibri", "Lucida Sans");
+ fontMap.put("Cambria", "Lucida Bright");
+ graphics.setRenderingHint(TextPainter.KEY_FONTMAP, fontMap);
+ }
}
diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java
index fb9dd8ea9..fe11df658 100644
--- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java
+++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java
@@ -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);
diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetAutosizeColumn.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetAutosizeColumn.java
index d4b68a0c8..b1aeb637c 100644
--- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetAutosizeColumn.java
+++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetAutosizeColumn.java
@@ -17,9 +17,12 @@
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