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$ }