]> source.dussan.org Git - poi.git/commitdiff
regression #55902 - Mixed fonts issue with Chinese characters (unable to form images...
authorAndreas Beeker <kiwiwings@apache.org>
Sat, 3 Dec 2016 20:32:08 +0000 (20:32 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sat, 3 Dec 2016 20:32:08 +0000 (20:32 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1772485 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/sl/draw/DrawFontManager.java
src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
src/java/org/apache/poi/sl/draw/Drawable.java

index 9c49489ffc4a05762759c7908673755c75c768f1..2416837b0907ca1cb97926027030fc4448b91e32 100644 (file)
@@ -31,8 +31,26 @@ public interface DrawFontManager {
      *\r
      * @param typeface the font family as defined in the .pptx file.\r
      * This can be unknown or missing in the graphic environment.\r
+     * @param pitchFamily a pitch-and-family,\r
+     * see {@link org.apache.poi.hwmf.record.HwmfFont#getFamily()} and\r
+     * {@link org.apache.poi.hwmf.record.HwmfFont#getPitch()}\r
+     * for how to calculate those (ancient) values\r
      *\r
      * @return the font to be used to paint text\r
      */\r
     String getRendererableFont(String typeface, int pitchFamily);\r
+\r
+    /**\r
+     * In case the original font doesn't contain a glyph, use the\r
+     * returned fallback font as an alternative\r
+     *\r
+     * @param typeface the font family as defined in the .pptx file.\r
+     * @param pitchFamily a pitch-and-family,\r
+     * see {@link org.apache.poi.hwmf.record.HwmfFont#getFamily()} and\r
+     * {@link org.apache.poi.hwmf.record.HwmfFont#getPitch()}\r
+     * for how to calculate those (ancient) values\r
+     * \r
+     * @return the font to be used as a fallback for the original typeface\r
+     */\r
+    String getFallbackFont(String typeface, int pitchFamily);\r
 }\r
index efdd7f4dae8a1a31631cdb03bc8126cdae3ff752..751e08985f250c72720fd9e5a0a02928b4075b81 100644 (file)
@@ -18,6 +18,7 @@
 package org.apache.poi.sl.draw;\r
 \r
 import java.awt.Dimension;\r
+import java.awt.Font;\r
 import java.awt.Graphics2D;\r
 import java.awt.Paint;\r
 import java.awt.font.FontRenderContext;\r
@@ -500,6 +501,10 @@ public class DrawTextParagraph implements Drawable {
         PlaceableShape<?,?> ps = getParagraphShape();\r
 \r
         DrawFontManager fontHandler = (DrawFontManager)graphics.getRenderingHint(Drawable.FONT_HANDLER);\r
+        @SuppressWarnings("unchecked")\r
+        Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_MAP);\r
+        @SuppressWarnings("unchecked")\r
+        Map<String,String> fallbackMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_FALLBACK);\r
 \r
         for (TextRun run : paragraph){\r
             String runText = getRenderableText(run);\r
@@ -507,31 +512,48 @@ public class DrawTextParagraph implements Drawable {
             if (runText.isEmpty()) continue;\r
 \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(Drawable.FONT_MAP);\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
+            String mappedFont = run.getFontFamily();\r
+            String fallbackFont = Font.SANS_SERIF;\r
+\r
+            if (mappedFont == null) {\r
+                mappedFont = paragraph.getDefaultFontFamily();\r
             }\r
-            if (fontFamily == null) {\r
-                fontFamily = paragraph.getDefaultFontFamily();\r
+            if (mappedFont == null) {\r
+                mappedFont = Font.SANS_SERIF;\r
+            }            \r
+            if (fontHandler != null) {\r
+                String font = fontHandler.getRendererableFont(mappedFont, run.getPitchAndFamily());\r
+                if (font != null) {\r
+                    mappedFont = font;\r
+                }\r
+                font = fontHandler.getFallbackFont(mappedFont, run.getPitchAndFamily());\r
+                if (font != null) {\r
+                    fallbackFont = font;\r
+                }\r
+            } else {\r
+                if (fontMap != null && fontMap.containsKey(mappedFont)) {\r
+                    mappedFont = fontMap.get(mappedFont);\r
+                }\r
+                if (fallbackMap != null && fallbackMap.containsKey(mappedFont)) {\r
+                    fallbackFont = fallbackMap.get(mappedFont);\r
+                }\r
             }\r
-\r
+            \r
+            runText = mapFontCharset(runText,mappedFont);\r
             int beginIndex = text.length();\r
-            text.append(mapFontCharset(runText,fontFamily));\r
+            text.append(runText);\r
             int endIndex = text.length();\r
 \r
-            attList.add(new AttributedStringData(TextAttribute.FAMILY, fontFamily, beginIndex, endIndex));\r
+            attList.add(new AttributedStringData(TextAttribute.FAMILY, mappedFont, beginIndex, endIndex));\r
 \r
             PaintStyle fgPaintStyle = run.getFontColor();\r
             Paint fgPaint = new DrawPaint(ps).getPaint(graphics, fgPaintStyle);\r
             attList.add(new AttributedStringData(TextAttribute.FOREGROUND, fgPaint, beginIndex, endIndex));\r
 \r
             Double fontSz = run.getFontSize();\r
-            if (fontSz == null) fontSz = paragraph.getDefaultFontSize();\r
+            if (fontSz == null) {\r
+                fontSz = paragraph.getDefaultFontSize();\r
+            }\r
             attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz.floatValue(), beginIndex, endIndex));\r
 \r
             if(run.isBold()) {\r
@@ -559,6 +581,33 @@ public class DrawTextParagraph implements Drawable {
                 attList.add(new AttributedStringData(HYPERLINK_HREF, hl.getAddress(), beginIndex, endIndex));\r
                 attList.add(new AttributedStringData(HYPERLINK_LABEL, hl.getLabel(), beginIndex, endIndex));\r
             }\r
+            \r
+            int style = (run.isBold() ? Font.BOLD : 0) | (run.isItalic() ? Font.ITALIC : 0);\r
+            Font f = new Font(mappedFont, style, (int)Math.rint(fontSz));\r
+            \r
+            // check for unsupported characters and add a fallback font for these\r
+            char textChr[] = runText.toCharArray();\r
+            int nextEnd = f.canDisplayUpTo(textChr, 0, textChr.length);\r
+            int last = nextEnd;\r
+            boolean isNextValid = (nextEnd == 0);\r
+            while ( nextEnd != -1 && nextEnd <= textChr.length ) {\r
+                if (isNextValid) {\r
+                    nextEnd = f.canDisplayUpTo(textChr, nextEnd, textChr.length);\r
+                    isNextValid = false;\r
+                } else {\r
+                    if (nextEnd >= textChr.length || f.canDisplay(Character.codePointAt(textChr, nextEnd, textChr.length)) ) {\r
+                        attList.add(new AttributedStringData(TextAttribute.FAMILY, fallbackFont, beginIndex+last, beginIndex+Math.min(nextEnd,textChr.length)));\r
+                        if (nextEnd >= textChr.length) {\r
+                            break;\r
+                        }\r
+                        last = nextEnd;\r
+                        isNextValid = true;\r
+                    } else {\r
+                        boolean isHS = Character.isHighSurrogate(textChr[nextEnd]);\r
+                        nextEnd+=(isHS?2:1);\r
+                    }\r
+                }\r
+            } \r
         }\r
 \r
         // ensure that the paragraph contains at least one character\r
@@ -576,7 +625,7 @@ public class DrawTextParagraph implements Drawable {
 \r
         return string;\r
     }\r
-\r
+    \r
     protected boolean isHSLF() {\r
         return paragraph.getClass().getName().contains("HSLF");\r
     }\r
index 54128b82c6c72b9fb3b93e9ff1eb290e393f73c8..7df8533b5629d0fc83a7718c991df5ec2afd2ce9 100644 (file)
@@ -106,10 +106,25 @@ public interface Drawable {
     int TEXT_AS_SHAPES = 2;\r
 \r
     /**\r
-     * Use this object to resolve unknown / missing fonts when rendering slides\r
+     * Use this object to resolve unknown / missing fonts when rendering slides.\r
+     * The font handler must be of type {@link DrawFontManager}.<p>\r
+     * \r
+     * In case a {@code FONT_HANDLER} is register, {@code FONT_FALLBACK} and {@code FONT_MAP} are ignored \r
      */\r
     DrawableHint FONT_HANDLER = new DrawableHint(7);\r
+    \r
+    /**\r
+     * Key for a font fallback map of type {@code Map<String,String>} which maps\r
+     * the original font family (key) to the fallback font family (value).\r
+     * In case there is also a {@code FONT_MAP} registered, the original font\r
+     * is first mapped via the font_map and then the fallback font is determined\r
+     */\r
     DrawableHint FONT_FALLBACK = new DrawableHint(8);\r
+\r
+    /**\r
+     * Key for a font map of type {@code Map<String,String>} which maps\r
+     * the original font family (key) to the mapped font family (value)\r
+     */\r
     DrawableHint FONT_MAP = new DrawableHint(9);\r
     \r
     DrawableHint GSAVE = new DrawableHint(10);\r