Added workarounds to tests for JDK 6 LineBreakMeasurer bug and handle it

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1644806 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2014-12-12 01:43:45 +00:00
parent dbfabda346
commit 1460fd33b2
6 changed files with 169 additions and 51 deletions

View 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){

View File

@ -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 <a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=54904">POI Bug #54904</a>
* @see <a href="http://bugs.java.com/view_bug.do?bug_id=6501991">JDK Bug #6501991</a>
* @see <a href="https://bitbucket.org/fakraemer/line-break-measurer-test">LineBreakMeasurerTest</a>
*/
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;
}
}

View File

@ -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<XSLFTextRun>{
// user can pass an custom object to convert fonts
String fontFamily = run.getFontFamily();
@SuppressWarnings("unchecked")
Map<String,String> fontMap = (Map<String,String>)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<XSLFTextRun>{
}
}
private boolean fetchParagraphProperty(ParagraphPropertyFetcher visitor){
private <T> boolean fetchParagraphProperty(ParagraphPropertyFetcher<T> visitor){
boolean ok = false;
if(_p.isSetPPr()) ok = visitor.fetch(_p.getPPr());

View File

@ -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<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(TextPainter.KEY_FONTMAP);
if (fontMap == null) fontMap = new HashMap<String,String>();
fontMap.put("Calibri", "Lucida Sans");
fontMap.put("Cambria", "Lucida Bright");
graphics.setRenderingHint(TextPainter.KEY_FONTMAP, fontMap);
}
}

View 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);

View File

@ -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,8 +174,10 @@ 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);
@ -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");
}
}
}
}