]> source.dussan.org Git - poi.git/commitdiff
#61169 - Text with Japanese characters overflows textbox
authorAndreas Beeker <kiwiwings@apache.org>
Sat, 8 Jul 2017 22:20:55 +0000 (22:20 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sat, 8 Jul 2017 22:20:55 +0000 (22:20 +0000)
- add resize methods with Graphics argument

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1801329 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/sl/draw/DrawTextShape.java
src/java/org/apache/poi/sl/usermodel/TextShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java
src/ooxml/testcases/org/apache/poi/sl/SLCommonUtils.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/sl/TestFonts.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/sl/TestHeadersFooters.java
src/ooxml/testcases/org/apache/poi/sl/TestTable.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java
test-data/slideshow/mona.ttf [new file with mode: 0644]

index cffffb4a88ad8c671006d9d9b12db254cd7882a2..ed146538148b5c95df23ed1a59509024ba667491 100644 (file)
@@ -207,7 +207,7 @@ public class DrawTextShape extends DrawSimpleShape {
      * @param oldGraphics the graphics context, which properties are to be copied, may be null
      * @return the height in points
      */
-    protected double getTextHeight(Graphics2D oldGraphics) {
+    public double getTextHeight(Graphics2D oldGraphics) {
         // dry-run in a 1x1 image and return the vertical advance
         BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
         Graphics2D graphics = img.createGraphics();
index a26db81cc4f258c1a91802096951191e31f20a76..e480e5645ef2cf0ad142286f37e04a2a95600a4b 100644 (file)
@@ -17,6 +17,8 @@
 
 package org.apache.poi.sl.usermodel;
 
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
 import java.util.List;
 
 public interface TextShape<
@@ -173,8 +175,21 @@ public interface TextShape<
 
     /**
      * Compute the cumulative height occupied by the text
+     * 
+     * @return the cumulative height occupied by the text
      */
     double getTextHeight();
+
+    /**
+     * Compute the cumulative height occupied by the text
+     * 
+     * @param graphics a customized graphics context, e.g. which contains font mappings
+     * 
+     * @return the cumulative height occupied by the text
+     * 
+     * @since POI 3.17-beta2
+     */
+    double getTextHeight(Graphics2D graphics);
     
     /**
      * Returns the type of vertical alignment for the text.
@@ -255,4 +270,25 @@ public interface TextShape<
      * @return the text placeholder
      */
     TextPlaceholder getTextPlaceholder();
+    
+    /**
+     * Adjust the size of the shape so it encompasses the text inside it.
+     *
+     * @return a {@code Rectangle2D} that is the bounds of this shape.
+     * 
+     * @since POI 3.17-beta2
+     */
+    Rectangle2D resizeToFitText();
+
+    /**
+     * Adjust the size of the shape so it encompasses the text inside it.
+     *
+     * @param graphics a customized graphics context, e.g. which contains font mappings
+     *
+     * @return a {@code Rectangle2D} that is the bounds of this shape.
+     * 
+     * @since POI 3.17-beta2
+     */
+    Rectangle2D resizeToFitText(Graphics2D graphics);
+
 }
\ No newline at end of file
index 8048e59b559f6dbac933de30388f3606656abdb4..353bbbf2b6a7967ff6a2580f00c8d8d35b3c3316 100644 (file)
@@ -64,6 +64,7 @@ public class XSLFTextRun implements TextRun {
         return _p;
     }
 
+    @Override
     public String getRawText(){
         if (_r instanceof CTTextField) {
             return ((CTTextField)_r).getT();
@@ -111,6 +112,7 @@ public class XSLFTextRun implements TextRun {
         return buf.toString();
     }
 
+    @Override
     public void setText(String text){
         if (_r instanceof CTTextField) {
             ((CTTextField)_r).setT(text);
@@ -157,6 +159,7 @@ public class XSLFTextRun implements TextRun {
     public PaintStyle getFontColor(){
         final boolean hasPlaceholder = getParentParagraph().getParentShape().getPlaceholder() != null;
         CharacterPropertyFetcher<PaintStyle> fetcher = new CharacterPropertyFetcher<PaintStyle>(_p.getIndentLevel()){
+            @Override
             public boolean fetch(CTTextCharacterProperties props){
                 if (props == null) {
                     return false;
@@ -191,7 +194,9 @@ public class XSLFTextRun implements TextRun {
     public void setFontSize(Double fontSize){
         CTTextCharacterProperties rPr = getRPr(true);
         if(fontSize == null) {
-            if (rPr.isSetSz()) rPr.unsetSz();
+            if (rPr.isSetSz()) {
+                rPr.unsetSz();
+            }
         } else {
             if (fontSize < 1.0) {
                 throw new IllegalArgumentException("Minimum font size is 1pt but was " + fontSize);
@@ -205,9 +210,12 @@ public class XSLFTextRun implements TextRun {
     public Double getFontSize(){
         double scale = 1;
         CTTextNormalAutofit afit = getParentParagraph().getParentShape().getTextBodyPr().getNormAutofit();
-        if(afit != null) scale = (double)afit.getFontScale() / 100000;
+        if(afit != null) {
+            scale = (double)afit.getFontScale() / 100000;
+        }
 
         CharacterPropertyFetcher<Double> fetcher = new CharacterPropertyFetcher<Double>(_p.getIndentLevel()){
+            @Override
             public boolean fetch(CTTextCharacterProperties props){
                 if (props != null && props.isSetSz()) {
                     setValue(props.getSz()*0.01);
@@ -228,6 +236,7 @@ public class XSLFTextRun implements TextRun {
     public double getCharacterSpacing(){
 
         CharacterPropertyFetcher<Double> fetcher = new CharacterPropertyFetcher<Double>(_p.getIndentLevel()){
+            @Override
             public boolean fetch(CTTextCharacterProperties props){
                 if (props != null && props.isSetSpc()) {
                     setValue(props.getSpc()*0.01);
@@ -252,7 +261,9 @@ public class XSLFTextRun implements TextRun {
     public void setCharacterSpacing(double spc){
         CTTextCharacterProperties rPr = getRPr(true);
         if(spc == 0.0) {
-            if(rPr.isSetSpc()) rPr.unsetSpc();
+            if(rPr.isSetSpc()) {
+                rPr.unsetSpc();
+            }
         } else {
             rPr.setSpc((int)(100*spc));
         }
@@ -267,9 +278,15 @@ public class XSLFTextRun implements TextRun {
         CTTextCharacterProperties rPr = getRPr(true);
 
         if(typeface == null){
-            if(rPr.isSetLatin()) rPr.unsetLatin();
-            if(rPr.isSetCs()) rPr.unsetCs();
-            if(rPr.isSetSym()) rPr.unsetSym();
+            if(rPr.isSetLatin()) {
+                rPr.unsetLatin();
+            }
+            if(rPr.isSetCs()) {
+                rPr.unsetCs();
+            }
+            if(rPr.isSetSym()) {
+                rPr.unsetSym();
+            }
         } else {
             if(isSymbol){
                 CTTextFont font = rPr.isSetSym() ? rPr.getSym() : rPr.addNewSym();
@@ -277,8 +294,12 @@ public class XSLFTextRun implements TextRun {
             } else {
                 CTTextFont latin = rPr.isSetLatin() ? rPr.getLatin() : rPr.addNewLatin();
                 latin.setTypeface(typeface);
-                if(charset != -1) latin.setCharset(charset);
-                if(pictAndFamily != -1) latin.setPitchFamily(pictAndFamily);
+                if(charset != -1) {
+                    latin.setCharset(charset);
+                }
+                if(pictAndFamily != -1) {
+                    latin.setPitchFamily(pictAndFamily);
+                }
             }
         }
     }
@@ -288,6 +309,7 @@ public class XSLFTextRun implements TextRun {
         final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
 
         CharacterPropertyFetcher<String> visitor = new CharacterPropertyFetcher<String>(_p.getIndentLevel()){
+            @Override
             public boolean fetch(CTTextCharacterProperties props){
                 if (props != null) {
                     CTTextFont font = props.getLatin();
@@ -310,10 +332,12 @@ public class XSLFTextRun implements TextRun {
         return  visitor.getValue();
     }
 
+    @Override
     public byte getPitchAndFamily(){
         // final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
 
         CharacterPropertyFetcher<Byte> visitor = new CharacterPropertyFetcher<Byte>(_p.getIndentLevel()){
+            @Override
             public boolean fetch(CTTextCharacterProperties props){
                 if (props != null) {
                     CTTextFont font = props.getLatin();
@@ -338,6 +362,7 @@ public class XSLFTextRun implements TextRun {
     @Override
     public boolean isStrikethrough() {
         CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){
+            @Override
             public boolean fetch(CTTextCharacterProperties props){
                 if(props != null && props.isSetStrike()) {
                     setValue(props.getStrike() != STTextStrikeType.NO_STRIKE);
@@ -353,6 +378,7 @@ public class XSLFTextRun implements TextRun {
     @Override
     public boolean isSuperscript() {
         CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){
+            @Override
             public boolean fetch(CTTextCharacterProperties props){
                 if (props != null && props.isSetBaseline()) {
                     setValue(props.getBaseline() > 0);
@@ -401,6 +427,7 @@ public class XSLFTextRun implements TextRun {
     @Override
     public boolean isSubscript() {
         CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){
+            @Override
             public boolean fetch(CTTextCharacterProperties props){
                 if (props != null && props.isSetBaseline()) {
                     setValue(props.getBaseline() < 0);
@@ -416,8 +443,10 @@ public class XSLFTextRun implements TextRun {
     /**
      * @return whether a run of text will be formatted as a superscript text. Default is false.
      */
+    @Override
     public TextCap getTextCap() {
         CharacterPropertyFetcher<TextCap> fetcher = new CharacterPropertyFetcher<TextCap>(_p.getIndentLevel()){
+            @Override
             public boolean fetch(CTTextCharacterProperties props){
                 if (props != null && props.isSetCap()) {
                     int idx = props.getCap().intValue() - 1;
@@ -439,6 +468,7 @@ public class XSLFTextRun implements TextRun {
     @Override
     public boolean isBold(){
         CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){
+            @Override
             public boolean fetch(CTTextCharacterProperties props){
                 if (props != null && props.isSetB()) {
                     setValue(props.getB());
@@ -459,6 +489,7 @@ public class XSLFTextRun implements TextRun {
     @Override
     public boolean isItalic(){
         CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){
+            @Override
             public boolean fetch(CTTextCharacterProperties props){
                 if (props != null && props.isSetI()) {
                     setValue(props.getI());
@@ -479,6 +510,7 @@ public class XSLFTextRun implements TextRun {
     @Override
     public boolean isUnderlined(){
         CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){
+            @Override
             public boolean fetch(CTTextCharacterProperties props){
                 if (props != null && props.isSetU()) {
                     setValue(props.getU() != STTextUnderlineType.NONE);
@@ -603,16 +635,24 @@ public class XSLFTextRun implements TextRun {
         }
 
         boolean bold = r.isBold();
-        if(bold != isBold()) setBold(bold);
+        if(bold != isBold()) {
+            setBold(bold);
+        }
 
         boolean italic = r.isItalic();
-        if(italic != isItalic()) setItalic(italic);
+        if(italic != isItalic()) {
+            setItalic(italic);
+        }
 
         boolean underline = r.isUnderlined();
-        if(underline != isUnderlined()) setUnderlined(underline);
+        if(underline != isUnderlined()) {
+            setUnderlined(underline);
+        }
 
         boolean strike = r.isStrikethrough();
-        if(strike != isStrikethrough()) setStrikethrough(strike);
+        if(strike != isStrikethrough()) {
+            setStrikethrough(strike);
+        }
     }
     
     
index ad979f1d6d412a36f00a76d8e5d14f30c48e56d1..502d2b6d045ebca43fc33a768d856eb2c4299bd7 100644 (file)
@@ -19,6 +19,7 @@
 
 package org.apache.poi.xslf.usermodel;
 
+import java.awt.Graphics2D;
 import java.awt.geom.Rectangle2D;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -601,23 +602,29 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
 
     @Override
     public double getTextHeight(){
-        DrawFactory drawFact = DrawFactory.getInstance(null);
+        return getTextHeight(null);
+    }
+    
+    @Override
+    public double getTextHeight(Graphics2D graphics){
+        DrawFactory drawFact = DrawFactory.getInstance(graphics);
         DrawTextShape dts = drawFact.getDrawable(this);
-        return dts.getTextHeight();
+        return dts.getTextHeight(graphics);
     }
 
-    /**
-     * Adjust the size of the shape so it encompasses the text inside it.
-     *
-     * @return a <code>Rectangle2D</code> that is the bounds of this shape.
-     */
+    @Override
     public Rectangle2D resizeToFitText(){
+        return resizeToFitText(null);
+    }
+    
+    @Override
+    public Rectangle2D resizeToFitText(Graphics2D graphics) {
         Rectangle2D anchor = getAnchor();
 
         if(anchor.getWidth() == 0.) {
             throw new POIXMLException("Anchor of the shape was not set.");
         }
-        double height = getTextHeight();
+        double height = getTextHeight(graphics);
         height += 1; // add a pixel to compensate rounding errors
 
         Insets2D insets = getInsets();
diff --git a/src/ooxml/testcases/org/apache/poi/sl/SLCommonUtils.java b/src/ooxml/testcases/org/apache/poi/sl/SLCommonUtils.java
new file mode 100644 (file)
index 0000000..7fdbaa2
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  ====================================================================
+ *    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.sl;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.sl.usermodel.SlideShowFactory;
+
+public class SLCommonUtils {
+    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
+    
+    /** a generic way to open a sample slideshow document **/
+    public static SlideShow<?,?> openSampleSlideshow(String sampleName) throws IOException {
+        InputStream is = _slTests.openResourceAsStream(sampleName);
+        try {
+            return SlideShowFactory.create(is);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        } finally {
+            is.close();
+        }
+    }
+
+    /**
+     * Tests, if the scratchpad classes are on the classpath
+     * 
+     * @return true, if only xslf is on the classpath, and false, if both classpaths
+     *    (XSLF and HSLF) can be used/referenced 
+     */
+    public static boolean xslfOnly() {
+        try {
+            Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow");
+            return false;
+        } catch (Exception e) {
+            return true;
+        }
+    }
+
+}
diff --git a/src/ooxml/testcases/org/apache/poi/sl/TestFonts.java b/src/ooxml/testcases/org/apache/poi/sl/TestFonts.java
new file mode 100644 (file)
index 0000000..7d3872a
--- /dev/null
@@ -0,0 +1,158 @@
+/* ====================================================================
+   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.sl;
+
+import static org.apache.poi.sl.SLCommonUtils.xslfOnly;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeFalse;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontFormatException;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.sl.draw.DrawFactory;
+import org.apache.poi.sl.draw.Drawable;
+import org.apache.poi.sl.usermodel.Slide;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
+import org.apache.poi.sl.usermodel.TextBox;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.sl.usermodel.TextRun;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
+
+
+/**
+ * Test rendering - specific to font handling
+ */
+public class TestFonts {
+    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
+
+    private static final String JPTEXT =
+        "\u3061\u3087\u3063\u3068\u65E9\u3044\u3051\u3069T\u30B7\u30E3\u30C4\u304C\u7740\u305F\u304F\u306A" +
+        "\u308B\u5B63\u7BC0\u2661\u304A\u6BCD\u3055\u3093\u306E\u5F71\u97FF\u304B\u3001\u975E\u5E38\u306B" +
+        "\u6050\u7ADC\u304C\u5927\u597D\u304D\u3067\u3059\u3002\u3082\u3046\u98FC\u3044\u305F\u3044\u304F" +
+        "\u3089\u3044\u5927\u597D\u304D\u3067\u3059\u3002#\u30B8\u30E5\u30E9\u30B7\u30C3\u30AF\u30EF\u30FC" +
+        "\u30EB\u30C9 \u306E\u30E9\u30D7\u30C8\u30EB4\u59C9\u59B9\u3068\u304B\u6FC0\u7684\u306B\u53EF\u611B" +
+        "\u304F\u3066\u53EF\u611B\u304F\u3066\u53EF\u611B\u304F\u3066\u53EF\u611B\u3044\u3067\u3059\u3002" +
+        "\u3081\u308D\u3081\u308D\u3001\u5927\u597D\u304D\u2661\u304A\u6BCD\u3055\u3093\u3082\u6050\u7ADC" +
+        "\u304C\u597D\u304D\u3067\u3001\u5C0F\u3055\u3044\u9803\u3001\u53E4\u4EE3\u751F\u7269\u306E\u56F3" +
+        "\u9451\u3092\u4E00\u7DD2\u306B\u898B\u3066\u305F\u306E\u601D\u3044\u51FA\u3059\u301C\u3068\u3044";
+
+    private static final String INIT_FONTS[] = { "mona.ttf" };
+    
+    @BeforeClass
+    public static void initGE() throws FontFormatException, IOException {
+        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        for (String s : INIT_FONTS) {
+            Font font = Font.createFont(Font.TRUETYPE_FONT, _slTests.getFile(s));
+            ge.registerFont(font);
+        }
+    }
+    
+    @Test
+    public void resizeToFitTextHSLF() throws IOException {
+        assumeFalse(xslfOnly());
+        SlideShow<?,?> ppt = new HSLFSlideShow();
+        TextBox<?,?> tb = resizeToFitText(ppt);
+        Rectangle2D anc = tb.getAnchor();
+        // ignore font metrics differences on windows / linux (... hopefully ...)
+        assertEquals(anc.getHeight(), 312d, 5);
+//        setFont(tb, "Mona");
+//        FileOutputStream fos = new FileOutputStream("bla-hslf.ppt");
+//        ppt.write(fos);
+//        fos.close();
+        ppt.close();
+    }
+
+    @Test
+    public void resizeToFitTextXSLF() throws IOException {
+        SlideShow<?,?> ppt = new XMLSlideShow();
+        TextBox<?,?> tb = resizeToFitText(ppt);
+        Rectangle2D anc = tb.getAnchor();
+        // ignore font metrics differences on windows / linux (... hopefully ...)
+        assertEquals(anc.getHeight(), 312d, 5);
+//        setFont(tb, "Mona");
+//        FileOutputStream fos = new FileOutputStream("bla-xslf.ppt");
+//        ppt.write(fos);
+//        fos.close();
+        ppt.close();
+    }
+
+    private TextBox<?,?> resizeToFitText(SlideShow<?,?> slideshow) throws IOException {
+        Slide<?,?> sld = slideshow.createSlide();
+        TextBox<?,?> tb = sld.createTextBox();
+        tb.setAnchor(new Rectangle(50, 50, 200, 50));
+        tb.setStrokeStyle(Color.black, LineDash.SOLID, 3);
+        tb.setText(JPTEXT);
+        
+        setFont(tb, "NoSuchFont");
+
+        Dimension pgsize = slideshow.getPageSize();
+        int width = (int)pgsize.getWidth();
+        int height = (int)pgsize.getHeight();
+        
+        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+        Graphics2D graphics = img.createGraphics();
+
+        Map<String,String> fallbackMap = new HashMap<String,String>();
+        fallbackMap.put("NoSuchFont", "Mona");
+        graphics.setRenderingHint(Drawable.FONT_FALLBACK, fallbackMap);
+        graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+        
+        DrawFactory.getInstance(graphics).fixFonts(graphics);
+        
+        tb.resizeToFitText(graphics);
+        graphics.dispose();
+        
+        return tb;
+    }
+    
+    private void setFont(TextBox<?,?> tb, String fontFamily) {
+        // TODO: set east asian font family - MS Office uses "MS Mincho" or "MS Gothic" as a fallback
+        // see https://stackoverflow.com/questions/26063828 for good explanation about the font metrics
+        // differences on different environments
+        for (TextParagraph<?,?,? extends TextRun> p : tb.getTextParagraphs()) {
+            for (TextRun r : p.getTextRuns()) {
+                r.setFontFamily(fontFamily);
+                if (r instanceof XSLFTextRun) {
+                    // TODO: provide API for HSLF
+                    XSLFTextRun xr = (XSLFTextRun)r;
+                    CTRegularTextRun tr = (CTRegularTextRun)xr.getXmlObject();
+                    tr.getRPr().addNewEa().setTypeface(fontFamily);
+     
+                }
+            }
+        }
+    }
+}
index c51652ff5e515f5263e1d21876efb3a67d099ec5..910e153e4511b71a8c80ee479818ba05d8047505 100644 (file)
@@ -19,7 +19,8 @@
 
 package org.apache.poi.sl;
 
-import static org.apache.poi.sl.TestTable.openSampleSlideshow;
+import static org.apache.poi.sl.SLCommonUtils.openSampleSlideshow;
+import static org.apache.poi.sl.SLCommonUtils.xslfOnly;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
@@ -37,25 +38,12 @@ import org.apache.poi.sl.usermodel.Slide;
 import org.apache.poi.sl.usermodel.SlideShow;
 import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextShape;
-import org.junit.BeforeClass;
 import org.junit.Test;
 
 public class TestHeadersFooters {
-    private static boolean xslfOnly = false;
-
-    @BeforeClass
-    public static void checkHslf() {
-        try {
-            Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow");
-        } catch (Exception e) {
-            xslfOnly = true;
-        }
-    }
-
-    
     @Test
     public void bug58144a() throws IOException {
-        assumeFalse(xslfOnly);
+        assumeFalse(xslfOnly());
         SlideShow<?,?> ppt = openSampleSlideshow("bug58144-headers-footers-2003.ppt");
         HSLFSlide sl = (HSLFSlide)ppt.getSlides().get(0);
         HeadersFooters hfs = sl.getHeadersFooters();
@@ -69,7 +57,7 @@ public class TestHeadersFooters {
     
     @Test
     public void bug58144b() throws IOException {
-        assumeFalse(xslfOnly);
+        assumeFalse(xslfOnly());
         SlideShow<?,?> ppt = openSampleSlideshow("bug58144-headers-footers-2007.ppt");
         Slide<?,?> sl =  ppt.getSlides().get(0);
         HeadersFooters hfs2 = ((HSLFSlide)sl).getHeadersFooters();
index 6028756626d89de93e9c2d755947d624dd84a634..f55a8a7cbcf45ef0ef91aa3310116558485f5cca 100644 (file)
@@ -19,6 +19,8 @@
 
 package org.apache.poi.sl;
 
+import static org.apache.poi.sl.SLCommonUtils.openSampleSlideshow;
+import static org.apache.poi.sl.SLCommonUtils.xslfOnly;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -32,7 +34,6 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
-import org.apache.poi.POIDataSamples;
 import org.apache.poi.hslf.usermodel.HSLFSlideShow;
 import org.apache.poi.sl.usermodel.Slide;
 import org.apache.poi.sl.usermodel.SlideShow;
@@ -41,38 +42,13 @@ import org.apache.poi.sl.usermodel.TableCell;
 import org.apache.poi.sl.usermodel.TableShape;
 import org.apache.poi.sl.usermodel.TextShape.TextDirection;
 import org.apache.poi.xslf.usermodel.XMLSlideShow;
-import org.junit.BeforeClass;
 import org.junit.Test;
 
 public class TestTable {
-    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
-    private static boolean xslfOnly = false;
-
-    @BeforeClass
-    public static void checkHslf() {
-        try {
-            Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow");
-        } catch (Exception e) {
-            xslfOnly = true;
-        }
-    }
-    
-    
-    /** a generic way to open a sample slideshow document **/
-    public static SlideShow<?,?> openSampleSlideshow(String sampleName) throws IOException {
-        InputStream is = _slTests.openResourceAsStream(sampleName);
-        try {
-            return SlideShowFactory.create(is);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        } finally {
-            is.close();
-        }
-    }
     
     @Test
     public void colWidthRowHeight() throws IOException {
-        assumeFalse(xslfOnly);
+        assumeFalse(xslfOnly());
 
         // Test of table dimensions of same slideshow saved as ppt/x
         // to check if both return similar (points) value
@@ -121,7 +97,7 @@ public class TestTable {
 
     @Test
     public void directionHSLF() throws IOException {
-        assumeFalse(xslfOnly);
+        assumeFalse(xslfOnly());
         SlideShow<?,?> ppt1 = new HSLFSlideShow();
         testTextDirection(ppt1);
         ppt1.close();
@@ -173,7 +149,7 @@ public class TestTable {
     
     @Test
     public void tableSpan() throws IOException {
-        String files[] = (xslfOnly) ? new String[]{ "bug60993.pptx" } : new String[]{ "bug60993.pptx", "bug60993.ppt" };
+        String files[] = (xslfOnly()) ? new String[]{ "bug60993.pptx" } : new String[]{ "bug60993.pptx", "bug60993.ppt" };
         for (String f : files) {
             SlideShow<?,?> ppt = openSampleSlideshow(f);
             Slide<?,?> slide = ppt.getSlides().get(0);
index 96cea8034977036e9607f207bc3dfba342c6c534..9db4afbd900b45abc96ae75a1bfd1a75383da7ce 100644 (file)
@@ -20,6 +20,7 @@ package org.apache.poi.hslf.usermodel;
 import static org.apache.poi.hslf.record.RecordTypes.OEPlaceholderAtom;
 import static org.apache.poi.hslf.record.RecordTypes.RoundTripHFPlaceholder12;
 
+import java.awt.Graphics2D;
 import java.awt.geom.Rectangle2D;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -312,21 +313,20 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
         }
     }
 
-
+    @Override
+    public Rectangle2D resizeToFitText() {
+        return resizeToFitText(null);
+    }
     
-    /**
-     * Adjust the size of the shape so it encompasses the text inside it.
-     *
-     * @return a <code>Rectangle2D</code> that is the bounds of this shape.
-     */
-    public Rectangle2D resizeToFitText(){
+    @Override
+    public Rectangle2D resizeToFitText(Graphics2D graphics) {
         Rectangle2D anchor = getAnchor();
         if(anchor.getWidth() == 0.) {
             LOG.log(POILogger.WARN, "Width of shape wasn't set. Defaulting to 200px");
             anchor.setRect(anchor.getX(), anchor.getY(), 200., anchor.getHeight());
             setAnchor(anchor);
         }
-        double height = getTextHeight();
+        double height = getTextHeight(graphics);
         height += 1; // add a pixel to compensate rounding errors
 
         Insets2D insets = getInsets();
@@ -736,10 +736,15 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
     }
 
     @Override
-    public double getTextHeight(){
-        DrawFactory drawFact = DrawFactory.getInstance(null);
+    public double getTextHeight() {
+        return getTextHeight(null);
+    }
+    
+    @Override
+    public double getTextHeight(Graphics2D graphics) {
+        DrawFactory drawFact = DrawFactory.getInstance(graphics);
         DrawTextShape dts = drawFact.getDrawable(this);
-        return dts.getTextHeight();
+        return dts.getTextHeight(graphics);
     }
 
     @Override
diff --git a/test-data/slideshow/mona.ttf b/test-data/slideshow/mona.ttf
new file mode 100644 (file)
index 0000000..d19a9ec
Binary files /dev/null and b/test-data/slideshow/mona.ttf differ