From 0ae7df0fec104086ba7695f44316e8bf4d35fe77 Mon Sep 17 00:00:00 2001
From: Thomas Gutmann <41593722+speckyspooky@users.noreply.github.com>
Date: Fri, 13 Sep 2024 09:53:38 +0200
Subject: [PATCH] Fix DOCX font size converting issue (#1905)
---
.../emitter/docx/writer/BasicComponent.java | 152 +++++++++++++++++-
.../birt/report/engine/emitter/HTMLTags.java | 11 ++
2 files changed, 155 insertions(+), 8 deletions(-)
diff --git a/engine/org.eclipse.birt.report.engine.emitter.docx/src/org/eclipse/birt/report/engine/emitter/docx/writer/BasicComponent.java b/engine/org.eclipse.birt.report.engine.emitter.docx/src/org/eclipse/birt/report/engine/emitter/docx/writer/BasicComponent.java
index 97d64c3493f..58d023a81b6 100644
--- a/engine/org.eclipse.birt.report.engine.emitter.docx/src/org/eclipse/birt/report/engine/emitter/docx/writer/BasicComponent.java
+++ b/engine/org.eclipse.birt.report.engine.emitter.docx/src/org/eclipse/birt/report/engine/emitter/docx/writer/BasicComponent.java
@@ -59,6 +59,7 @@
import org.eclipse.birt.report.engine.util.FileUtil;
import org.eclipse.birt.report.model.api.IResourceLocator;
import org.eclipse.birt.report.model.api.ReportDesignHandle;
+import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
@@ -70,6 +71,12 @@ public abstract class BasicComponent extends AbstractWordXmlWriter {
private static Logger logger = Logger.getLogger(BasicComponent.class.getName());
+ // MS Word (DOCX), MHT-file: font size 12pt won't be correct converted
+ private static String DOCX_MHT_FONT_SIZE_ISSUE = "12pt";
+
+ // MS Word (DOCX), MHT-file: replacement font size
+ private static String DOCX_MHT_FONT_SIZE_REPLACEMENT = "12.5pt";
+
protected ImageManager imageManager;
protected IPart part;
@@ -358,8 +365,12 @@ private void buildHtmlBody(IForeignContent foreignContent, String foreignText, I
int display = getElementType(x, y, width, height, style);
String tagName = getTagByType(display, DISPLAY_FLAG_ALL);
if (null != tagName) {
- htmlBuffer.append("
0) {
body = (Element) bodys.item(0);
}
@@ -418,9 +429,9 @@ private void buildStyleClass(IStyle style, StringBuffer htmlBuffer) {
htmlBuffer.append("");
htmlBuffer.append("");
htmlBuffer.append("");
}
@@ -778,9 +789,8 @@ private void processNodes(Element ele, HashMap cssStyles, HTMLWriter writer, Map
} else if (nodeType == Node.COMMENT_NODE) {
writer.comment(node.getNodeValue());
} else if (nodeType == Node.ELEMENT_NODE) {
- Element element = (Element) node;
- if ("br".equalsIgnoreCase(node.getNodeName())) {
- //
is correct.
is not correct. The brower
+ if (HTMLTags.TAG_BR.equalsIgnoreCase(node.getNodeName())) {
+ //
is correct.
is not correct. The browser
// will treat the
as
boolean bImplicitCloseTag = writer.isImplicitCloseTag();
writer.setImplicitCloseTag(true);
@@ -788,7 +798,19 @@ private void processNodes(Element ele, HashMap cssStyles, HTMLWriter writer, Map
processNodes((Element) node, cssStyles, writer, appContext);
endNode(node, writer);
writer.setImplicitCloseTag(bImplicitCloseTag);
+ } else if (HTMLTags.TAG_FONT.equalsIgnoreCase(node.getNodeName())) {
+ // will be replaced to span-tag to correct font-size behavior
+ Node fontNode = convertFontTagToSpanTag(node, cssStyles);
+ startNode(fontNode, cssStyles, writer, appContext);
+ processNodes((Element) fontNode, cssStyles, writer, appContext);
+ endNode(fontNode, writer);
+
} else {
+ // solve MS Word/MHT font-size issue
+ if (HTMLTags.TAG_DIV.equalsIgnoreCase(node.getNodeName())
+ || HTMLTags.TAG_SPAN.equalsIgnoreCase(node.getNodeName())) {
+ getCorrectFontSize(node, cssStyles);
+ }
startNode(node, cssStyles, writer, appContext);
processNodes((Element) node, cssStyles, writer, appContext);
endNode(node, writer);
@@ -958,4 +980,118 @@ protected void writeIndent(int leftMargin, int rightMargin, int textIndent) {
abstract void end();
abstract protected int getMhtTextId();
+
+ /**
+ * Get the replaced span tag for the font tag to support correct styles
+ *
+ * @param nodeFont html tag font which will be replaced
+ * @param cssStyles CSS style around the font tag
+ *
+ * @return the alternative node of the font tag
+ */
+ private Node convertFontTagToSpanTag(Node nodeFont, HashMap cssStyles) {
+ String fontSize = null;
+ String fontColor = null;
+ String fontFamily = null;
+
+ // create new span-tag
+ Document doc = nodeFont.getOwnerDocument();
+ Element spanTag = doc.createElement(HTMLTags.TAG_SPAN);
+
+ NamedNodeMap nodeAttributes = nodeFont.getAttributes();
+ if (nodeAttributes != null && nodeAttributes.getNamedItem(HTMLTags.ATTR_TAG_FONT_SIZE) != null) {
+ String size = nodeAttributes.getNamedItem(HTMLTags.ATTR_TAG_FONT_SIZE).getNodeValue().trim();
+ // size: absolute value converting
+ if (size.equals("0") || size.equals("1")) {
+ fontSize = "8pt";
+ } else if (size.equals("2")) {
+ fontSize = "10pt";
+ } else if (size.equals("3")) {
+ // MS Word, MHT-file: font size 12pt won't be correct converted
+ fontSize = DOCX_MHT_FONT_SIZE_REPLACEMENT;
+ } else if (size.equals("4")) {
+ fontSize = "14pt";
+ } else if (size.equals("5")) {
+ fontSize = "18pt";
+ } else if (size.equals("6")) {
+ fontSize = "24pt";
+ } else if (size.equals("7")) {
+ fontSize = "36pt";
+ }
+ // size: relative value converting
+ if (fontSize == null) {
+ if (size.length() > 2) {
+ size = size.substring(0, 2);
+ }
+ if (size.equals("-2")) {
+ fontSize = "0.75em";
+ } else if (size.equals("-1")) {
+ fontSize = "1.0em";
+ } else if (size.equals("-0") || size.equals("+0")) {
+ fontSize = "1.25em";
+ } else if (size.equals("+1")) {
+ fontSize = "1.35em";
+ } else if (size.equals("+2")) {
+ fontSize = "1.8em";
+ } else if (size.equals("+3")) {
+ fontSize = "2.4em";
+ } else if (size.equals("+4")) {
+ fontSize = "3.6em";
+ } else {
+ fontSize = "10pt";
+ }
+ }
+ Node colorNode = nodeAttributes.getNamedItem(HTMLTags.ATTR_TAG_FONT_COLOR);
+ if (colorNode != null && colorNode.getNodeValue().trim().length() > 0) {
+ fontColor = colorNode.getNodeValue().trim();
+ }
+ Node fontNode = nodeAttributes.getNamedItem(HTMLTags.ATTR_TAG_FONT_FACE);
+ if (fontNode != null && fontNode.getNodeValue().trim().length() > 0) {
+ fontFamily = fontNode.getNodeValue().trim();
+ }
+ }
+ String styleValues = "";
+ if (fontSize != null && fontSize.length() > 0) {
+ styleValues += HTMLTags.ATTR_FONT_SIZE + ":" + fontSize + ";";
+ }
+ if (fontColor != null && fontSize.length() > 0) {
+ styleValues += HTMLTags.ATTR_COLOR + ":" + fontColor + ";";
+ }
+ if (fontFamily != null && fontSize.length() > 0) {
+ styleValues += HTMLTags.ATTR_FONT_FAMILY + ":" + fontFamily + ";";
+ }
+ if (styleValues != null && styleValues.trim().length() > 0) {
+ Attr spanAttr = doc.createAttribute(HTMLTags.ATTR_STYLE);
+ spanAttr.setNodeValue(styleValues);
+ spanTag.setAttributeNode(spanAttr);
+ }
+ NodeList fontContentChildren = nodeFont.getChildNodes();
+ for (int i = 0; i < fontContentChildren.getLength(); i++) {
+ Node child = fontContentChildren.item(i).cloneNode(true);
+ spanTag.appendChild(child);
+ }
+ HashMap nodeStyle = (HashMap) cssStyles.get(nodeFont);
+ cssStyles.remove(nodeFont);
+ cssStyles.put(spanTag, nodeStyle);
+ return spanTag;
+ }
+
+ /**
+ * Get the corrected font size to solve the MS Word (DOCX) / MHT font size issue
+ * MHT font size 12pt will be changed to at MS Word side to font size 10pt
+ *
+ * @param nodeTag html tag to validate the font size
+ * @param cssStyles CSS style around the tag
+ *
+ */
+ private void getCorrectFontSize(Node nodeTag, HashMap cssStyles) {
+ HashMap nodeStyle = (HashMap) cssStyles.get(nodeTag);
+ for (Object key : nodeStyle.keySet()) {
+ if (((String) key).contains(HTMLTags.ATTR_FONT_SIZE) && nodeStyle.get(key) != null
+ && ((String) nodeStyle.get(key)).equalsIgnoreCase(DOCX_MHT_FONT_SIZE_ISSUE)) {
+ nodeStyle.replace((String) key, DOCX_MHT_FONT_SIZE_REPLACEMENT);
+ break;
+ }
+ }
+ }
}
diff --git a/engine/org.eclipse.birt.report.engine/src/org/eclipse/birt/report/engine/emitter/HTMLTags.java b/engine/org.eclipse.birt.report.engine/src/org/eclipse/birt/report/engine/emitter/HTMLTags.java
index b1daa954960..b23aa2c8286 100644
--- a/engine/org.eclipse.birt.report.engine/src/org/eclipse/birt/report/engine/emitter/HTMLTags.java
+++ b/engine/org.eclipse.birt.report.engine/src/org/eclipse/birt/report/engine/emitter/HTMLTags.java
@@ -76,6 +76,7 @@ public class HTMLTags {
public static final String ATTR_BACKGROUND_ATTACHEMNT = "background-attachment"; //$NON-NLS-1$
/** html tag attribute: background-position */
public static final String ATTR_BACKGROUND_POSITION = "background-position"; //$NON-NLS-1$
+ /** html tag attribute: background-size */
public static final String ATTR_BACKGROUND_SIZE = "background-size"; //$NON-NLS-1$
/** html tag attribute: padding */
@@ -147,6 +148,12 @@ public class HTMLTags {
public static final String ATTR_FONT_VARIANT = "font-variant"; //$NON-NLS-1$
/** html tag attribute: font-weight */
public static final String ATTR_FONT_WEIGTH = "font-weight"; //$NON-NLS-1$
+ /** html tag attribute: (font) size of tag font */
+ public static final String ATTR_TAG_FONT_SIZE = "size"; //$NON-NLS-1$
+ /** html tag attribute: (font) color of tag font */
+ public static final String ATTR_TAG_FONT_COLOR = "color"; //$NON-NLS-1$
+ /** html tag attribute: (font) face of tag font */
+ public static final String ATTR_TAG_FONT_FACE = "face"; //$NON-NLS-1$
/** html tag attribute: id */
public static final String ATTR_ID = "id"; //$NON-NLS-1$
@@ -260,4 +267,8 @@ public class HTMLTags {
public static final String TAG_SCRIPT = "script"; //$NON-NLS-1$
/** html tag: link */
public static final String TAG_LINK = "link";//$NON-NLS-1$
+ /** html tag: font paragraph */
+ public static final String TAG_P = "p";//$NON-NLS-1$
+ /** html tag: font (HTML 4.01) */
+ public static final String TAG_FONT = "font";//$NON-NLS-1$
}