filter/source/xslt/odf2xhtml/export/common/body.xsl | 2 filter/source/xslt/odf2xhtml/export/common/styles/style_mapping_css.xsl | 2 filter/source/xslt/odf2xhtml/export/xhtml/body.xsl | 118 ++++++---- sd/qa/unit/HtmlExportTest.cxx | 30 ++ sd/qa/unit/data/tdf154989.odg |binary sw/qa/extras/htmlexport/xhtmlexport.cxx | 10 6 files changed, 110 insertions(+), 52 deletions(-)
New commits: commit cb27c6c1b82272e8812bcb446e7179cc4f32bf34 Author: Svante Schubert <svante.schub...@gmail.com> AuthorDate: Fri May 5 12:26:53 2023 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Mon May 8 17:21:42 2023 +0200 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.st...@allotropia.de> (cherry picked from commit b70e2ee3ec5bfd21f27597195b745171932032e8) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151510 diff --git a/filter/source/xslt/odf2xhtml/export/common/body.xsl b/filter/source/xslt/odf2xhtml/export/common/body.xsl index bcad3abd9ab3..8dfb78222186 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 c81cc9a1e0be..06e22d7e2fed 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 ca7a6906b82c..6f64b5a83d82 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"> @@ -251,20 +257,20 @@ <xsl:comment>Next 'div' was a 'draw:text-box'.</xsl:comment> <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> @@ -359,11 +365,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) --> @@ -415,7 +422,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. @@ -434,7 +441,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"> @@ -689,6 +696,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! --> @@ -698,7 +706,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, @@ -798,7 +809,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"> @@ -808,17 +819,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> @@ -839,7 +850,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> @@ -914,13 +925,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'"> @@ -964,7 +975,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> @@ -1042,15 +1053,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"> @@ -1084,18 +1088,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: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> + <!-- 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:value-of select="$svgY" /> <xsl:text>cm; </xsl:text> - </xsl:if> - </xsl:if> + </xsl:otherwise> + </xsl:choose> </xsl:attribute> <xsl:apply-templates select="@*"> <xsl:with-param name="globalData" select="$globalData"/> @@ -2572,7 +2591,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> @@ -2831,7 +2850,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 812757bc1761..a1afe6906ff4 100644 --- a/sd/qa/unit/HtmlExportTest.cxx +++ b/sd/qa/unit/HtmlExportTest.cxx @@ -20,6 +20,12 @@ public: { } + virtual void registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) override + { + xmlXPathRegisterNs(pXmlXPathCtx, BAD_CAST("xhtml"), + BAD_CAST("http://www.w3.org/1999/xhtml")); + } + void testHTMLExport() { loadFromURL(u"HtmlExportTestDocument.odp"); @@ -40,8 +46,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 000000000000..5bc7e83042dd Binary files /dev/null and b/sd/qa/unit/data/tdf154989.odg differ diff --git a/sw/qa/extras/htmlexport/xhtmlexport.cxx b/sw/qa/extras/htmlexport/xhtmlexport.cxx index 9f5b26745f5b..923c3fecda8a 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")