tdf#154989 filter: XHTML export: avoid duplicated frames
Various updates on XSLT ODF2HTML triggered by TDF issue 154989 - esp. image/frame positioning by CSS position
(regression from commit f680b6d74209fd78c547201b2f14c6547e55c81b)
Change-Id: I4d08a67ebca7ae3808db07c828488bb9284623a3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151094
Tested-by: Jenkins
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
diff --git a/filter/source/xslt/odf2xhtml/export/common/body.xsl b/filter/source/xslt/odf2xhtml/export/common/body.xsl
index bcad3ab..8dfb782 100644
--- a/filter/source/xslt/odf2xhtml/export/common/body.xsl
+++ b/filter/source/xslt/odf2xhtml/export/common/body.xsl
@@ -81,7 +81,7 @@
<!-- *************** -->
<!-- ID / NAME of text-box -->
<xsl:template match="@draw:name">
<xsl:template match="@draw:name | @text:id | @xml:id">
<xsl:attribute name="id">
<xsl:choose>
<xsl:when test="number(substring(.,1,1))">
diff --git a/filter/source/xslt/odf2xhtml/export/common/styles/style_mapping_css.xsl b/filter/source/xslt/odf2xhtml/export/common/styles/style_mapping_css.xsl
index c81cc9a..06e22d7 100644
--- a/filter/source/xslt/odf2xhtml/export/common/styles/style_mapping_css.xsl
+++ b/filter/source/xslt/odf2xhtml/export/common/styles/style_mapping_css.xsl
@@ -23,7 +23,7 @@
<!-- *** Properties with a 'fo:' prefix *** -->
<xsl:template match="@fo:background-color">
<xsl:template match="@fo:background-color | @draw:fill-color">
<xsl:text>background-color:</xsl:text>
<xsl:value-of select="."/>
<xsl:text>; </xsl:text>
diff --git a/filter/source/xslt/odf2xhtml/export/xhtml/body.xsl b/filter/source/xslt/odf2xhtml/export/xhtml/body.xsl
index fca8d9a..6ad03e2 100644
--- a/filter/source/xslt/odf2xhtml/export/xhtml/body.xsl
+++ b/filter/source/xslt/odf2xhtml/export/xhtml/body.xsl
@@ -141,15 +141,21 @@
</xsl:choose>
<!-- adapt page size -->
<xsl:variable name="pageWidth" select="$pageProperties/style:page-layout-properties/@fo:page-width"/>
<xsl:variable name="pageHeight" select="$pageProperties/style:page-layout-properties/@fo:height"/>
<!-- multiple backgroundimages for different page styles (never used in html) -->
<xsl:variable name="backgroundImage" select="$pageProperties/style:page-layout-properties/style:background-image"/>
<!-- page margins & background image -->
<xsl:if test="$pageWidth or $pageProperties/style:page-layout-properties/@fo:* or $backgroundImage/@xlink:href">
<xsl:if test="$pageWidth or $pageHeight or $pageProperties/style:page-layout-properties/@fo:* or $backgroundImage/@xlink:href">
<xsl:attribute name="style">
<xsl:if test="$pageWidth">
<xsl:text>max-width:</xsl:text>
<xsl:value-of select="$pageWidth"/>
<xsl:value-of select="$pageWidth" />
<xsl:text>;</xsl:text>
</xsl:if>
<xsl:if test="$pageHeight">
<xsl:text>max-height:</xsl:text>
<xsl:value-of select="$pageHeight" />
<xsl:text>;</xsl:text>
</xsl:if>
<xsl:if test="$pageProperties/style:page-layout-properties/@fo:* or $backgroundImage/@xlink:href">
@@ -253,20 +259,20 @@
<xsl:text>
</xsl:text>
<xsl:element name="div">
<xsl:variable name="dimension">
<xsl:apply-templates select="@fo:min-width"/>
<xsl:apply-templates select="@fo:max-width"/>
<xsl:apply-templates select="@fo:min-height"/>
<xsl:apply-templates select="@fo:max-height"/>
<xsl:apply-templates select="@fo:min-width" />
<xsl:apply-templates select="@fo:max-width" />
<xsl:apply-templates select="@fo:min-height" />
<xsl:apply-templates select="@fo:max-height" />
</xsl:variable>
<xsl:if test="$dimension">
<xsl:if test="normalize-space($dimension)!=''">
<xsl:attribute name="style">
<xsl:value-of select="$dimension"/>
<xsl:value-of select="$dimension" />
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="@draw:name">
<xsl:with-param name="globalData" select="$globalData"/>
</xsl:apply-templates>
<xsl:apply-templates select="@xml:id">
<xsl:with-param name="globalData" select="$globalData" />
</xsl:apply-templates>
<xsl:apply-templates select="node()">
<xsl:with-param name="globalData" select="$globalData"/>
</xsl:apply-templates>
@@ -361,11 +367,12 @@
<xsl:call-template name="create-paragraph">
<xsl:with-param name="globalData" select="$globalData" />
<xsl:with-param name="footnotePrefix" select="$footnotePrefix" />
<xsl:with-param name="frameFloating" select="true()"/>
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:when test="draw:frame and ((normalize-space($childText) != '') or (((count(*) - count(text:soft-page-break)) > 1)))">
<xsl:when test="name() = 'draw:frame' and ((normalize-space($childText) != '') or (((count(*) - count(text:soft-page-break)) > 1)))">
<!-- If there is a 'draw:frame' child with text (not being whitespace alone) and more than the draw:frame alone and
not the draw:frame and a soft-page-break alone (which is quite often) -->
@@ -421,7 +428,7 @@
  is an unbreakable whitespace to give content to the element and force a browser not to ignore the element -->
<div style="clear:both; line-height:0; width:0; height:0; margin:0; padding:0;"> </div>
</xsl:when>
<xsl:when test="text:tab and not(ancestor::text:index-body)">
<xsl:when test="text:tab and not(ancestor::text:index-body)">
<!-- If there is a tabulator (ie. text:tab) within a paragraph, a heuristic for ODF tabulators creates a
span for every text:tab embracing the following text nodes aligning them according to the tabulator.
A line break or another text:tab starts a new text:span, line break even the tab counter for the line.
@@ -440,7 +447,7 @@
<xsl:variable name="paragraphName" select="@text:style-name" />
<xsl:variable name="imageParagraphStyle" select="$globalData/all-styles/style[@style:name = $paragraphName]/final-properties"/>
<!-- Only the left margin of the first paragraph of a list item will be added to the margin of the complete list (all levels)-->
<!-- TODO: left-margin in order with bidirectional -->
<!-- TODO: left-margin in order with bidirectional -->
<xsl:choose>
<xsl:when test="contains($imageParagraphStyle, 'margin-left:')">
<xsl:call-template name="convert2cm">
@@ -695,6 +702,7 @@
<xsl:param name="globalData"/>
<!-- the footnote symbol is the prefix for a footnote in the footer -->
<xsl:param name="footnotePrefix"/>
<xsl:param name="frameFloating"/>
<!-- xhtml:p may only contain inline elements.
If there is one frame beyond, div must be used! -->
@@ -704,7 +712,10 @@
<xsl:otherwise>p</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:if test="name() = 'text:p' and $elementName = 'div'">
<xsl:comment>Next 'div' was a 'text:p'.</xsl:comment>
<xsl:text>
</xsl:text>
</xsl:if>
<xsl:element name="{$elementName}">
<xsl:choose>
<!-- in ODF borders of paragraphs will be merged by default. Merging means the adjacent paragraphs are building a unit,
@@ -804,7 +815,7 @@
<xsl:text>;</xsl:text>
</xsl:template>
<!-- As soon a frame is within a paragraph (text:p) or page:frame, every child element is floating (CSS) and worked out in sequence.
<!-- As soon a frame is within a paragraph (text:p) or page:frame, every child element is floating (CSS) and worked out in sequence.
Accumulating prior frame width and adding parent's left margin -->
<!-- Matching all elements and text beyond a paragraph/text:page which are sibling of a draw:frame -->
<xsl:template match="* | text()" mode="frameFloating">
@@ -814,17 +825,17 @@
<xsl:param name="leftPosition" select="0" />
<xsl:param name="parentMarginLeft" />
<xsl:param name="stopAtFirstFrame" select="false()" />
<xsl:param name="tdf146264hack" select="false()" />
<xsl:param name="frameFloating" select="false()" />
<xsl:choose>
<xsl:when test="name() = 'draw:frame' and not($stopAtFirstFrame)">
<!-- if the first node is a draw:frame create a div -->
<xsl:call-template name="createDrawFrame">
<xsl:with-param name="globalData" select="$globalData"/>
<xsl:with-param name="previousFrameWidths" select="$previousFrameWidths"/>
<xsl:with-param name="previousFrameHeights" select="$previousFrameHeights"/>
<xsl:with-param name="parentMarginLeft" select="$parentMarginLeft"/>
<xsl:with-param name="frameFloating" select="true()"/>
</xsl:call-template>
<!-- next elements will be called after the creation with the new indent (plus width of frame) -->
</xsl:when>
@@ -847,7 +858,7 @@
<!-- This xsl:if is the meat of the extremely ugly "fix" to tdf#146264. It probably has unintended
bad side-effects.
-->
<xsl:if test="not($tdf146264hack)">
<xsl:if test="not($frameFloating)">
<xsl:apply-templates select=".">
<xsl:with-param name="globalData" select="$globalData"/>
</xsl:apply-templates>
@@ -922,13 +933,13 @@
<xsl:param name="globalData"/>
<xsl:param name="previousFrameWidths" select="0"/>
<xsl:param name="previousFrameHeights" select="0" />
<xsl:param name="tdf146264hack" select="false()" />
<xsl:param name="frameFloating" select="false()" />
<xsl:call-template name="createDrawFrame">
<xsl:with-param name="globalData" select="$globalData" />
<xsl:with-param name="previousFrameWidths" select="$previousFrameWidths"/>
<xsl:with-param name="previousFrameHeights" select="$previousFrameHeights"/>
<xsl:with-param name="tdf146264hack" select="$tdf146264hack"/>
<xsl:with-param name="frameFloating" select="$frameFloating"/>
</xsl:call-template>
<!-- after the last draw:frame sibling the CSS float is disabled -->
<xsl:if test="@text:anchor-type!='as-char'">
@@ -972,7 +983,7 @@
<xsl:param name="previousFrameHeights" select="0" />
<xsl:param name="parentMarginLeft"/>
<xsl:param name="stopAtFirstFrame" select="false()" />
<xsl:param name="tdf146264hack" select="false()" />
<xsl:param name="frameFloating" select="false()" />
<xsl:variable name="parentMarginLeftNew">
<xsl:choose>
@@ -1052,15 +1063,8 @@
<xsl:with-param name="parentMarginLeftNew" select="$parentMarginLeftNew"/>
<xsl:with-param name="leftPosition" select="$leftPosition"/>
<xsl:with-param name="svgY" select="$svgY"/>
<xsl:with-param name="frameFloating" select="$frameFloating"/>
</xsl:call-template>
<xsl:apply-templates select="following-sibling::node()[1]" mode="frameFloating">
<xsl:with-param name="globalData" select="$globalData"/>
<xsl:with-param name="previousFrameWidths" select="$previousFrameWidths + $svgWidth"/>
<xsl:with-param name="parentMarginLeft" select="$parentMarginLeftNew"/>
<xsl:with-param name="leftPosition" select="$leftPosition"/>
<xsl:with-param name="stopAtFirstFrame" select="$stopAtFirstFrame" />
<xsl:with-param name="tdf146264hack" select="$tdf146264hack" />
</xsl:apply-templates>
</xsl:template>
<xsl:template name="createDrawFrame2">
@@ -1094,18 +1098,33 @@
<xsl:attribute name="style">
<xsl:call-template name="widthAndHeight"/>
<xsl:text> padding:0; </xsl:text>
<xsl:if test="@text:anchor-type!='as-char'">
<!-- all images float (CSS float relative) with a left position calculated by svg:x - parentMarginLeft - previousFrameWidths -->
<xsl:text> float:left; position:relative; left:</xsl:text>
<xsl:value-of select="$leftPosition"/>
<xsl:text>cm; </xsl:text>
<!-- if the frame is anchored on a char -->
<xsl:if test="@text:anchor-type='char'">
<xsl:text>top:</xsl:text>
<xsl:value-of select="$svgY"/>
<xsl:choose>
<xsl:when test="@text:anchor-type='as-char'">
<!-- images being used as character are not floating and ar not positioned (CSS position:static being the default)-->
<!--<xsl:text> position:static;</xsl:text>-->
</xsl:when>
<xsl:when test="@text:anchor-type!='as-char'">
<!-- all images float (CSS float relative) with a left position calculated by svg:x - parentMarginLeft - previousFrameWidths -->
<xsl:text> float:left; position:relative; left:</xsl:text>
<xsl:value-of select="$leftPosition" />
<xsl:text>cm; </xsl:text>
</xsl:if>
</xsl:if>
<!-- if the frame is anchored on a char -->
<xsl:if test="@text:anchor-type='char'">
<xsl:text>top:</xsl:text>
<xsl:value-of select="$svgY" />
<xsl:text>cm; </xsl:text>
</xsl:if>
</xsl:when>
<!-- @text:anchor-type='' -->
<xsl:otherwise>
<xsl:text> position:absolute; left:</xsl:text>
<xsl:value-of select="$leftPosition" />
<xsl:text>cm; </xsl:text>
<xsl:text>top:</xsl:text>
<xsl:value-of select="$svgY" />
<xsl:text>cm; </xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates select="@*">
<xsl:with-param name="globalData" select="$globalData"/>
@@ -2582,7 +2601,7 @@
<xsl:apply-templates>
<xsl:with-param name="globalData" select="$globalData"/>
<xsl:with-param name="listIndent" select="$minLabelWidth"/>
<xsl:with-param name="tdf146264hack" select="true()"/>
<xsl:with-param name="frameFloating" select="true()"/>
</xsl:apply-templates>
<!-- this span disables the float necessary to bring two block elements on one line. It contains a space as IE6 bug workaround -->
<span class="odfLiEnd"></span>
@@ -2844,7 +2863,22 @@
<xsl:param name="globalData"/>
<xsl:attribute name="class">
<xsl:value-of select="translate(., '.,;: %()[]/\+', '_____________')"/>
<xsl:choose>
<xsl:when test="name() = 'draw:text-style-name' or name() = 'draw:style-name'">
<xsl:choose>
<xsl:when test="parent::*/@draw:text-style-name and parent::*/@draw:style-name">
<xsl:value-of select="translate(parent::*/@draw:style-name, '.,;: %()[]/\+', '_____________')" /><xsl:text> </xsl:text>
<xsl:value-of select="translate(parent::*/@draw:text-style-name, '.,;: %()[]/\+', '_____________')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="translate(., '.,;: %()[]/\+', '_____________')" />
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="translate(., '.,;: %()[]/\+', '_____________')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:template>
diff --git a/sd/qa/unit/HtmlExportTest.cxx b/sd/qa/unit/HtmlExportTest.cxx
index 812757b..93c1a21 100644
--- a/sd/qa/unit/HtmlExportTest.cxx
+++ b/sd/qa/unit/HtmlExportTest.cxx
@@ -40,8 +40,32 @@ public:
assertXPath(htmlDoc, "/html/head/meta[3]", "content", "2014-04-09T17:05:41.987922038");
}
void testTdf154989()
{
loadFromURL(u"tdf154989.odg");
save("XHTML Draw File");
xmlDocUniquePtr pXmlDoc = parseXml(maTempFile);
assertXPath(pXmlDoc, "/xhtml:html", 1);
// 1 page
assertXPath(pXmlDoc, "/xhtml:html/xhtml:body/xhtml:div", 1);
// 4 shapes
assertXPath(pXmlDoc, "/xhtml:html/xhtml:body/xhtml:div[1]/xhtml:div", 4);
// 3 of them are text boxes
assertXPath(pXmlDoc, "/xhtml:html/xhtml:body/xhtml:div[1]/xhtml:div/xhtml:div", 3);
// not sure if the order of these is stable?
assertXPathContent(pXmlDoc,
"/xhtml:html/xhtml:body/xhtml:div[1]/xhtml:div[2]/xhtml:div/xhtml:p",
"before");
assertXPathContent(
pXmlDoc, "/xhtml:html/xhtml:body/xhtml:div[1]/xhtml:div[3]/xhtml:div/xhtml:p", "above");
assertXPathContent(
pXmlDoc, "/xhtml:html/xhtml:body/xhtml:div[1]/xhtml:div[4]/xhtml:div/xhtml:p", "below");
}
CPPUNIT_TEST_SUITE(SdHTMLFilterTest);
CPPUNIT_TEST(testHTMLExport);
CPPUNIT_TEST(testTdf154989);
CPPUNIT_TEST_SUITE_END();
};
diff --git a/sd/qa/unit/data/tdf154989.odg b/sd/qa/unit/data/tdf154989.odg
new file mode 100644
index 0000000..5bc7e83
--- /dev/null
+++ b/sd/qa/unit/data/tdf154989.odg
Binary files differ
diff --git a/sw/qa/extras/htmlexport/xhtmlexport.cxx b/sw/qa/extras/htmlexport/xhtmlexport.cxx
index 9f5b267..923c3fe 100644
--- a/sw/qa/extras/htmlexport/xhtmlexport.cxx
+++ b/sw/qa/extras/htmlexport/xhtmlexport.cxx
@@ -76,14 +76,8 @@ DECLARE_HTMLEXPORT_TEST(testTdf118637, "tdf118637.odt")
CPPUNIT_ASSERT(pStream);
sal_uInt64 nLength = pStream->TellEnd();
OString aStream(read_uInt8s_ToOString(*pStream, nLength));
CPPUNIT_ASSERT(
aStream.indexOf(
"<div style=\"display:inline; position:relative; left:0cm;\">The formula </div>")
!= -1);
CPPUNIT_ASSERT(
aStream.indexOf(
"<div style=\"display:inline; position:relative; left:0cm;\">should be inline.</div>")
!= -1);
CPPUNIT_ASSERT(aStream.indexOf("The formula ") != -1);
CPPUNIT_ASSERT(aStream.indexOf("should be inline.</div>") != -1);
}
DECLARE_HTMLEXPORT_TEST(testTdf145361, "tdf145361.odt")