Skip to content

Commit

Permalink
Optimization of docx emitter output (eclipse-birt#1957)
Browse files Browse the repository at this point in the history
  • Loading branch information
speckyspooky committed Nov 4, 2024
1 parent 0477d48 commit 37f30ba
Show file tree
Hide file tree
Showing 9 changed files with 710 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2013 Actuate Corporation.
* Copyright (c) 2013, 2024 Actuate Corporation and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
Expand Down Expand Up @@ -71,7 +71,8 @@ public void initialize(IEmitterServices service) throws EngineException {
this.embedHtml = (Boolean) value;
}

wordWriter = new DocxWriter(out, tempFileDir, getCompressionMode(service).getValue(), getWordVersion());
wordWriter = new DocxWriter(out, tempFileDir, getCompressionMode(service).getValue(), getWordVersion(),
wrappedTableHeaderFooter);
}

private CompressionMode getCompressionMode(IEmitterServices service) {
Expand Down Expand Up @@ -102,14 +103,21 @@ public void startForeign(IForeignContent foreign) throws BirtException {
wordWriter.insertHiddenParagraph();
context.setIsAfterTable(false);
}
if (embedHtml) {
if (embedHtml && !wrappedTableForMarginPadding) {
writeBookmark(foreign);
writeToc(foreign);
wordWriter.writeForeign(foreign, false, combineMarginPadding);
adjustInline();
context.setIsAfterTable(false);
context.addContainer(true);
} else if (embedHtml) {
writeBookmark(foreign);
int width = WordUtil.convertTo(foreign.getWidth(), context.getCurrentWidth(), reportDpi);
width = Math.min(width, context.getCurrentWidth());
wordWriter.startTable(foreign.getComputedStyle(), width, true);
wordWriter.startTableRow(-1);
wordWriter.startTableCell(width, foreign.getComputedStyle(), null, null);
// TODO:need text paser for foreign raw value
// TODO:need text parser for foreign raw value
wordWriter.writeForeign(foreign, true);
if (isInSpannedCell(foreign)) {
// insert empty line after embed html
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2013 Actuate Corporation.
* Copyright (c) 2013, 2024 Actuate Corporation and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
Expand Down Expand Up @@ -36,6 +36,7 @@
import org.eclipse.birt.report.engine.content.IStyle;
import org.eclipse.birt.report.engine.css.engine.StyleConstants;
import org.eclipse.birt.report.engine.css.engine.value.css.CSSConstants;
import org.eclipse.birt.report.engine.css.engine.value.css.CSSValueConstants;
import org.eclipse.birt.report.engine.emitter.EmitterUtil;
import org.eclipse.birt.report.engine.emitter.HTMLTags;
import org.eclipse.birt.report.engine.emitter.HTMLWriter;
Expand All @@ -46,7 +47,6 @@
import org.eclipse.birt.report.engine.emitter.wpml.writer.AbstractWordXmlWriter;
import org.eclipse.birt.report.engine.executor.css.HTMLProcessor;
import org.eclipse.birt.report.engine.ir.DimensionType;
import org.eclipse.birt.report.engine.ir.EngineIRConstants;
import org.eclipse.birt.report.engine.layout.pdf.util.PropertyUtil;
import org.eclipse.birt.report.engine.ooxml.IPart;
import org.eclipse.birt.report.engine.ooxml.ImageManager;
Expand All @@ -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.eclipse.birt.report.model.api.elements.DesignChoiceConstants;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
Expand Down Expand Up @@ -105,6 +106,10 @@ public abstract class BasicComponent extends AbstractWordXmlWriter {

protected boolean wrappedTable = true;

protected boolean combineMarginPadding = true;

protected boolean wrappedTableHeaderFooter = true;

protected BasicComponent(IPart part) throws IOException {
this.part = part;
this.imageManager = (ImageManager) part.getPackage().getExtensionData();
Expand Down Expand Up @@ -316,8 +321,9 @@ protected void writeBookmark(String bm) {
bookmarkId++;
}

protected void writeForeign(IForeignContent foreignContent, boolean wrappedTable) {
protected void writeForeign(IForeignContent foreignContent, boolean wrappedTable, boolean combineMarginPadding) {
this.wrappedTable = wrappedTable;
this.combineMarginPadding = combineMarginPadding;
writeForeign(foreignContent);
}

Expand Down Expand Up @@ -469,13 +475,13 @@ private int getElementType(DimensionType x, DimensionType y, DimensionType width
display = style.getDisplay();
}

if (EngineIRConstants.DISPLAY_NONE.equalsIgnoreCase(display)) {
if (DesignChoiceConstants.DISPLAY_NONE.equalsIgnoreCase(display)) {
type |= DISPLAY_NONE;
}

if (x != null || y != null) {
return type | DISPLAY_BLOCK;
} else if (EngineIRConstants.DISPLAY_INLINE.equalsIgnoreCase(display)) {
} else if (DesignChoiceConstants.DISPLAY_INLINE.equalsIgnoreCase(display)) {
type |= DISPLAY_INLINE;
if (width != null || height != null) {
type |= DISPLAY_INLINE_BLOCK;
Expand All @@ -499,6 +505,7 @@ private String getTagByType(int display, int mask) {
return tag;
}

@SuppressWarnings("unused")
private void buildForeignStyles(IForeignContent foreignContent, StringBuffer foreignStyles, int display) {
IStyle style = foreignContent.getComputedStyle();
foreignStyles.setLength(0);
Expand Down Expand Up @@ -590,43 +597,104 @@ private void buildMargins(StringBuffer styleBuffer, IStyle style) {
leftMargin = style.getMarginLeft();
}

if (null != topMargin && null != rightMargin && null != bottomMargin && null != leftMargin) {
if (rightMargin.equals(leftMargin)) {
if (topMargin.equals(bottomMargin)) {
if (topMargin.equals(rightMargin)) {
// The four margins have the same value
buildProperty(styleBuffer, HTMLTags.ATTR_MARGIN, topMargin);
// MHT-files for DOCX needs for each margin-attribute an own style tag to be
// displayed correctly
boolean marginStyleMultipleAttr = !wrappedTable;
if (marginStyleMultipleAttr) {
if (null != topMargin) {
if (combineMarginPadding) {
int marginTopPt = WordUtil.convertToPt(topMargin);
String topPadding = style.getPaddingTop();
if (topPadding != null) {
marginTopPt += WordUtil.convertToPt(topPadding);
topMargin = marginTopPt + "pt";
}
}
addPropName(styleBuffer, HTMLTags.ATTR_MARGIN_TOP);
addPropValue(styleBuffer, topMargin);
styleBuffer.append(';');
}

if (null != rightMargin) {
if (combineMarginPadding) {
int marginRightPt = WordUtil.convertToPt(rightMargin);
String rightPadding = style.getPaddingRight();
if (rightPadding != null) {
marginRightPt += WordUtil.convertToPt(rightPadding);
rightMargin = marginRightPt + "pt";
}
}
addPropName(styleBuffer, HTMLTags.ATTR_MARGIN_RIGHT);
addPropValue(styleBuffer, rightMargin);
styleBuffer.append(';');
}

if (null != bottomMargin) {
if (combineMarginPadding) {
int marginBottomPt = WordUtil.convertToPt(bottomMargin);
String bottomPadding = style.getPaddingBottom();
if (bottomPadding != null) {
marginBottomPt += WordUtil.convertToPt(bottomPadding);
bottomMargin = marginBottomPt + "pt";
}
}
addPropName(styleBuffer, HTMLTags.ATTR_MARGIN_BOTTOM);
addPropValue(styleBuffer, bottomMargin);
styleBuffer.append(';');
}

if (null != leftMargin) {
if (combineMarginPadding) {
int marginLeftPt = WordUtil.convertToPt(leftMargin);
String leftPadding = style.getPaddingLeft();
if (leftPadding != null) {
marginLeftPt += WordUtil.convertToPt(leftPadding);
leftMargin = marginLeftPt + "pt";
}
}
addPropName(styleBuffer, HTMLTags.ATTR_MARGIN_LEFT);
addPropValue(styleBuffer, leftMargin);
styleBuffer.append(';');
}
} else {
if (null != topMargin && null != rightMargin && null != bottomMargin && null != leftMargin) {
if (rightMargin.equals(leftMargin)) {
if (topMargin.equals(bottomMargin)) {
if (topMargin.equals(rightMargin)) {
// The four margins have the same value
buildProperty(styleBuffer, HTMLTags.ATTR_MARGIN, topMargin);
} else {
// The top & bottom margins have the same value. The
// right & left margins have the same value.
addPropName(styleBuffer, HTMLTags.ATTR_MARGIN);
addPropValue(styleBuffer, topMargin);
addPropValue(styleBuffer, rightMargin);
styleBuffer.append(';');
}
} else {
// The top & bottom margins have the same value. The
// right & left margins have the same value.
// only the right & left margins have the same value.
addPropName(styleBuffer, HTMLTags.ATTR_MARGIN);
addPropValue(styleBuffer, topMargin);
addPropValue(styleBuffer, rightMargin);
addPropValue(styleBuffer, bottomMargin);
styleBuffer.append(';');
}
} else {
// only the right & left margins have the same value.
// four margins have different values.
addPropName(styleBuffer, HTMLTags.ATTR_MARGIN);
addPropValue(styleBuffer, topMargin);
addPropValue(styleBuffer, rightMargin);
addPropValue(styleBuffer, bottomMargin);
addPropValue(styleBuffer, leftMargin);
styleBuffer.append(';');
}
} else {
// four margins have different values.
addPropName(styleBuffer, HTMLTags.ATTR_MARGIN);
addPropValue(styleBuffer, topMargin);
addPropValue(styleBuffer, rightMargin);
addPropValue(styleBuffer, bottomMargin);
addPropValue(styleBuffer, leftMargin);
styleBuffer.append(';');
// At least one margin has null value.
buildProperty(styleBuffer, HTMLTags.ATTR_MARGIN_TOP, topMargin);
buildProperty(styleBuffer, HTMLTags.ATTR_MARGIN_RIGHT, rightMargin);
buildProperty(styleBuffer, HTMLTags.ATTR_MARGIN_BOTTOM, bottomMargin);
buildProperty(styleBuffer, HTMLTags.ATTR_MARGIN_LEFT, leftMargin);
}
} else {
// At least one margin has null value.
buildProperty(styleBuffer, HTMLTags.ATTR_MARGIN_TOP, topMargin);
buildProperty(styleBuffer, HTMLTags.ATTR_MARGIN_RIGHT, rightMargin);
buildProperty(styleBuffer, HTMLTags.ATTR_MARGIN_BOTTOM, bottomMargin);
buildProperty(styleBuffer, HTMLTags.ATTR_MARGIN_LEFT, leftMargin);
}
}

Expand Down Expand Up @@ -696,20 +764,20 @@ private void buildVisual(StringBuffer styleBuffer, IStyle style) {
}

private void buildTextDecoration(StringBuffer styleBuffer, IStyle style) {
CSSValue linethrough = style.getProperty(IStyle.STYLE_TEXT_LINETHROUGH);
CSSValue underline = style.getProperty(IStyle.STYLE_TEXT_UNDERLINE);
CSSValue overline = style.getProperty(IStyle.STYLE_TEXT_OVERLINE);
CSSValue linethrough = style.getProperty(StyleConstants.STYLE_TEXT_LINETHROUGH);
CSSValue underline = style.getProperty(StyleConstants.STYLE_TEXT_UNDERLINE);
CSSValue overline = style.getProperty(StyleConstants.STYLE_TEXT_OVERLINE);

if (linethrough == IStyle.LINE_THROUGH_VALUE || underline == IStyle.UNDERLINE_VALUE
|| overline == IStyle.OVERLINE_VALUE) {
if (linethrough == CSSValueConstants.LINE_THROUGH_VALUE || underline == CSSValueConstants.UNDERLINE_VALUE
|| overline == CSSValueConstants.OVERLINE_VALUE) {
styleBuffer.append(" text-decoration:"); //$NON-NLS-1$
if (IStyle.LINE_THROUGH_VALUE == linethrough) {
if (CSSValueConstants.LINE_THROUGH_VALUE == linethrough) {
addPropValue(styleBuffer, "line-through");
}
if (IStyle.UNDERLINE_VALUE == underline) {
if (CSSValueConstants.UNDERLINE_VALUE == underline) {
addPropValue(styleBuffer, "underline");
}
if (IStyle.OVERLINE_VALUE == overline) {
if (CSSValueConstants.OVERLINE_VALUE == overline) {
addPropValue(styleBuffer, "overline");
}
styleBuffer.append(';');
Expand Down Expand Up @@ -915,9 +983,8 @@ public String validHtmlText(String foreignText) {
Matcher matcher = pattern.matcher(foreignText);
if (matcher.matches()) {
return foreignText;
} else {
return "<html>" + foreignText + "</html>";
}
return "<html>" + foreignText + "</html>";
}

protected String getRelationshipId() {
Expand Down Expand Up @@ -1078,7 +1145,7 @@ private Node convertFontTagToSpanTag(Node nodeFont, HashMap<Node, Object> cssSty

/**
* 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
* MHT font size 12pt will be changed at MS Word side to font size 10pt
*
* @param nodeTag html tag to validate the font size
* @param cssStyles CSS style around the tag
Expand All @@ -1094,4 +1161,17 @@ private void getCorrectFontSize(Node nodeTag, HashMap<Node, Object> cssStyles) {
}
}
}

protected void startHeaderFooterContainer(int headerHeight, int headerWidth, boolean writeColumns) {
if (wrappedTableHeaderFooter) {
super.startHeaderFooterContainer(headerHeight, headerWidth, writeColumns);
}
}

@Override
protected void endHeaderFooterContainer() {
if (wrappedTableHeaderFooter) {
super.endHeaderFooterContainer();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2013 Actuate Corporation.
* Copyright (c) 2013, 2024 Actuate Corporation and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
Expand Down Expand Up @@ -56,6 +56,8 @@ public class DocxWriter implements IWordWriter {

private String documentLanguage = "en";

private boolean wrappedTableHeaderFooter = false;

/**
* Constructor
*
Expand All @@ -64,10 +66,12 @@ public class DocxWriter implements IWordWriter {
* @param compressionMode compression mode
* @param wordVersion word version
*/
public DocxWriter(OutputStream out, String tempFileDir, int compressionMode, int wordVersion) {
public DocxWriter(OutputStream out, String tempFileDir, int compressionMode, int wordVersion,
boolean wrappedTableHeaderFooter) {
pkg = Package.createInstance(out, tempFileDir, compressionMode);
pkg.setExtensionData(new ImageManager());
this.wordVersion = wordVersion;
this.wrappedTableHeaderFooter = wrappedTableHeaderFooter;
}

@Override
Expand Down Expand Up @@ -133,6 +137,7 @@ private void initializeDocumentPart(String backgroundColor, String backgroundIma
rtl, wordVersion, this.getDocumentLanguage());
document.start();
currentComponent = document;
currentComponent.wrappedTableHeaderFooter = this.wrappedTableHeaderFooter;
}

@Override
Expand Down Expand Up @@ -313,7 +318,12 @@ public void writeForeign(IForeignContent foreignContent) {

@Override
public void writeForeign(IForeignContent foreignContent, boolean embedHTML) {
currentComponent.writeForeign(foreignContent, embedHTML);
currentComponent.writeForeign(foreignContent, embedHTML, true);
}

@Override
public void writeForeign(IForeignContent foreignContent, boolean embedHTML, boolean combineMarginPadding) {
currentComponent.writeForeign(foreignContent, embedHTML, combineMarginPadding);
}

@Override
Expand Down
Loading

0 comments on commit 37f30ba

Please sign in to comment.