sw/qa/extras/htmlexport/htmlexport.cxx | 13 ++++-- sw/source/filter/html/css1atr.cxx | 64 +++++++++++++++++++-------------- sw/source/filter/html/htmltabw.cxx | 9 +++- sw/source/filter/html/wrthtml.hxx | 26 +++++++++++-- 4 files changed, 76 insertions(+), 36 deletions(-)
New commits: commit bd1d738e78e5287b35e2d17f84971d44b384425b Author: Miklos Vajna <[email protected]> AuthorDate: Fri Jun 10 09:12:33 2022 +0200 Commit: Miklos Vajna <[email protected]> CommitDate: Fri Jun 10 14:58:31 2022 +0200 sw XHTML export: avoid writing default transparent background for ReqIF We started writing properties of tables and rows since commit c3c3303516c3da9372dce3f05f38f15a104e961c (sw XHTML export: output table / table row background format using CSS, 2022-05-10). In case the SwTableLine has an explicit SvxBrushItem with its color set to COL_TRANSPARENT, we turn that into a "background: transparent" CSS by default. This is a 1:1 mapping from the doc model, but HTML defaults to this already, so this is considered as noise. Extend IgnorePropertyForReqIF() to filter out these unwanted defaults, and fix SwHTMLWriter::OutCSS1_Property(), because it used to not pass the CSS value for the filter function. The behavior for table cells is unchanged, we continue to not export cell properties (in the ReqIF case) at all. (cherry picked from commit 04cc6e079e3122c183054fde046c054ed6c7b737) Conflicts: sw/source/filter/html/css1atr.cxx Change-Id: Idbcd07809e159def694f4de017eebc7ad4104575 diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index f938ee6bcdcd..7b9128e8d32a 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -2183,10 +2183,14 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTableBackground) pWrtShell->SetTabBackground(aBrush); pWrtShell->Down(/*bSelect=*/false); pWrtShell->SplitNode(); - pWrtShell->InsertTable(aInsertTableOptions, /*nRows=*/1, /*nCols=*/1); + pWrtShell->InsertTable(aInsertTableOptions, /*nRows=*/2, /*nCols=*/1); pWrtShell->MoveTable(GotoPrevTable, fnTableStart); aBrush.SetColor(0x00ff00); pWrtShell->SetRowBackground(aBrush); + pWrtShell->Down(/*bSelect=*/false); + // Second row has an explicit transparent background. + aBrush.SetColor(COL_TRANSPARENT); + pWrtShell->SetRowBackground(aBrush); // When exporting to reqif-xhtml: ExportToReqif(); @@ -2203,6 +2207,8 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTableBackground) assertXPath(pXmlDoc, "//reqif-xhtml:table[2]/reqif-xhtml:tr[1]", "style", "background: #00ff00"); assertXPathNoAttribute(pXmlDoc, "//reqif-xhtml:table[2]/reqif-xhtml:tr[1]", "bgcolor"); + // Second row has no explicit style, the default is not written. + assertXPathNoAttribute(pXmlDoc, "//reqif-xhtml:table[2]/reqif-xhtml:tr[2]", "style"); } CPPUNIT_TEST_FIXTURE(HtmlExportTest, testImageKeepRatio) diff --git a/sw/source/filter/html/css1atr.cxx b/sw/source/filter/html/css1atr.cxx index eccbbdae4f3d..18ee264324f6 100644 --- a/sw/source/filter/html/css1atr.cxx +++ b/sw/source/filter/html/css1atr.cxx @@ -180,9 +180,21 @@ OString lclConvToHex(sal_uInt16 nHex) bool IgnorePropertyForReqIF(bool bReqIF, const OString& rProperty, const OString& rValue, std::optional<sw::Css1Background> oMode) { - if (!bReqIF || (oMode.has_value() && *oMode != sw::Css1Background::TableCell)) + if (!bReqIF) return false; + if (oMode.has_value() && *oMode != sw::Css1Background::TableCell) + { + // Table or row. + if (rProperty == sCSS1_P_background && rValue == "transparent") + { + // This is the default already. + return true; + } + + return false; + } + // Only allow these two keys, nothing else in ReqIF mode. if (rProperty == sCSS1_P_text_decoration) { @@ -239,7 +251,12 @@ void SwHTMLWriter::OutCSS1_Property( const char *pProp, const OUString *pSVal, std::optional<sw::Css1Background> oMode ) { - if (IgnorePropertyForReqIF(mbReqIF, pProp, pVal, oMode)) + OString aPropertyValue(pVal); + if (aPropertyValue.isEmpty() && pSVal) + { + aPropertyValue = pSVal->toUtf8(); + } + if (IgnorePropertyForReqIF(mbReqIF, pProp, aPropertyValue, oMode)) return; OStringBuffer sOut; commit 35b05d6d2dcbae2fc10f979fe7d8a43b3686a26e Author: Miklos Vajna <[email protected]> AuthorDate: Fri Jun 10 08:08:52 2022 +0200 Commit: Miklos Vajna <[email protected]> CommitDate: Fri Jun 10 09:20:48 2022 +0200 sw XHTML export: avoid writing background of table cells in ReqIF mode ReqIF mostly forbids using CSS styling on elements: IgnorePropertyForReqIF() only allows 2 CSS keys by default. This restriction was relaxed in commit c3c3303516c3da9372dce3f05f38f15a104e961c (sw XHTML export: output table / table row background format using CSS, 2022-05-10), to allow background for tables and table rows, using CSS markup. An unwanted side effect of this is background for table cells, which is still considered invalid. To make this nontrivial to fix, Css1Background::Table is used to track formatting for all of tables, rows and cells. Fix the problem by extending Css1Background with a TableRow and TableCell and then audit all uses of Css1Background::Table to explicitly say if they mean table, row or cell. This keeps table and row backgrounds, but fixes the unwanted cell background. Also document the 3 functions doing the export of table / row / cell background export to improve readability. (cherry picked from commit d701eff3519287db599a2612a635bc5f610ba082) Conflicts: sw/source/filter/html/css1atr.cxx sw/source/filter/html/wrthtml.hxx Change-Id: I03301b1fd25593cbe83489dbf140e80138d4a0de diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index 42c13ccac3f6..f938ee6bcdcd 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -745,9 +745,8 @@ DECLARE_HTMLEXPORT_TEST(testReqIfTable, "reqif-table.xhtml") // <div> was missing, so the XHTML fragment wasn't a valid // xhtml.BlkStruct.class type anymore. assertXPath(pDoc, "/html/body/div/table/tr/th", 1); - // Make sure that row background is written using CSS. - OUString aStyle = getXPath(pDoc, "/html/body/div/table/tr/th", "style"); - CPPUNIT_ASSERT(aStyle.startsWith("background: ")); + // Make sure that the cell background is not written using CSS. + assertXPathNoAttribute(pDoc, "/html/body/div/table/tr/th", "style"); // The attribute was present, which is not valid in reqif-xhtml. assertXPathNoAttribute(pDoc, "/html/body/div/table/tr/th", "bgcolor"); } diff --git a/sw/source/filter/html/css1atr.cxx b/sw/source/filter/html/css1atr.cxx index 368f97926656..eccbbdae4f3d 100644 --- a/sw/source/filter/html/css1atr.cxx +++ b/sw/source/filter/html/css1atr.cxx @@ -97,14 +97,6 @@ using editeng::SvxBorderLine; namespace { -enum class Css1Background { - Attr = 1, - Page = 2, - Table = 3, - Fly = 4, - Section = 5 -}; - enum class Css1FrameSize { NONE = 0x00, Width = 0x01, @@ -148,7 +140,7 @@ static Writer& OutCSS1_SvxULSpace_SvxLRSpace( Writer& rWrt, static Writer& OutCSS1_SvxULSpace_SvxLRSpace( Writer& rWrt, const SfxItemSet& rItemSet ); static Writer& OutCSS1_SvxBrush( Writer& rWrt, const SfxPoolItem& rHt, - Css1Background nMode, + sw::Css1Background nMode, const OUString *pGraphicName ); static Writer& OutCSS1_SvxBrush( Writer& rWrt, const SfxPoolItem& rHt ); static Writer& OutCSS1_SwFormatFrameSize( Writer& rWrt, const SfxPoolItem& rHt, @@ -186,9 +178,9 @@ OString lclConvToHex(sal_uInt16 nHex) } bool IgnorePropertyForReqIF(bool bReqIF, const OString& rProperty, const OString& rValue, - bool bTable) + std::optional<sw::Css1Background> oMode) { - if (!bReqIF || bTable) + if (!bReqIF || (oMode.has_value() && *oMode != sw::Css1Background::TableCell)) return false; // Only allow these two keys, nothing else in ReqIF mode. @@ -245,9 +237,9 @@ public: void SwHTMLWriter::OutCSS1_Property( const char *pProp, const char *pVal, const OUString *pSVal, - bool bTable ) + std::optional<sw::Css1Background> oMode ) { - if (IgnorePropertyForReqIF(mbReqIF, pProp, pVal, bTable)) + if (IgnorePropertyForReqIF(mbReqIF, pProp, pVal, oMode)) return; OStringBuffer sOut; @@ -1813,7 +1805,7 @@ Writer& OutCSS1_BodyTagStyleOpt( Writer& rWrt, const SfxItemSet& rItemSet ) &pItem ) ) { OUString rEmbeddedGraphicName; - OutCSS1_SvxBrush( rWrt, *pItem, Css1Background::Page, &rEmbeddedGraphicName ); + OutCSS1_SvxBrush( rWrt, *pItem, sw::Css1Background::Page, &rEmbeddedGraphicName ); } if( SfxItemState::SET == rItemSet.GetItemState( RES_BOX, false, @@ -1843,7 +1835,6 @@ Writer& OutCSS1_ParaTagStyleOpt( Writer& rWrt, const SfxItemSet& rItemSet ) return rWrt; } -// Wrapper for Table background Writer& OutCSS1_TableBGStyleOpt( Writer& rWrt, const SfxPoolItem& rHt ) { SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt); @@ -1851,7 +1842,7 @@ Writer& OutCSS1_TableBGStyleOpt( Writer& rWrt, const SfxPoolItem& rHt ) SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_STYLE_OPT_ON | CSS1_OUTMODE_ENCODE| CSS1_OUTMODE_TABLEBOX, nullptr ); - OutCSS1_SvxBrush( rWrt, rHt, Css1Background::Table, nullptr ); + OutCSS1_SvxBrush( rWrt, rHt, sw::Css1Background::TableRow, nullptr ); if( !rHTMLWrt.m_bFirstCSS1Property ) rWrt.Strm().WriteChar( '\"' ); @@ -2099,7 +2090,7 @@ void SwHTMLWriter::OutCSS1_TableFrameFormatOptions( const SwFrameFormat& rFrameF const SfxPoolItem *pItem; const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet(); if( SfxItemState::SET==rItemSet.GetItemState( RES_BACKGROUND, false, &pItem ) ) - OutCSS1_SvxBrush( *this, *pItem, Css1Background::Table, nullptr ); + OutCSS1_SvxBrush( *this, *pItem, sw::Css1Background::Table, nullptr ); if( IsHTMLMode( HTMLMODE_PRINT_EXT ) ) OutCSS1_SvxFormatBreak_SwFormatPDesc_SvxFormatKeep( *this, rItemSet, false ); @@ -2116,7 +2107,7 @@ void SwHTMLWriter::OutCSS1_TableCellBordersAndBG(SwFrameFormat const& rFrameForm SwCSS1OutMode const aMode( *this, CSS1_OUTMODE_STYLE_OPT_ON|CSS1_OUTMODE_ENCODE|CSS1_OUTMODE_TABLEBOX, nullptr ); if (pBrushItem) - OutCSS1_SvxBrush(*this, *pBrushItem, Css1Background::Table, nullptr); + OutCSS1_SvxBrush(*this, *pBrushItem, sw::Css1Background::TableCell, nullptr); OutCSS1_SvxBox(*this, rFrameFormat.GetBox()); if (!m_bFirstCSS1Property) { @@ -2133,7 +2124,7 @@ void SwHTMLWriter::OutCSS1_SectionFormatOptions( const SwFrameFormat& rFrameForm const SfxPoolItem *pItem; const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet(); if( SfxItemState::SET==rItemSet.GetItemState( RES_BACKGROUND, false, &pItem ) ) - OutCSS1_SvxBrush( *this, *pItem, Css1Background::Section, nullptr ); + OutCSS1_SvxBrush( *this, *pItem, sw::Css1Background::Section, nullptr ); if (pCol) { @@ -2155,7 +2146,7 @@ static bool OutCSS1_FrameFormatBrush( SwHTMLWriter& rWrt, !rBrushItem.GetGraphicLink().isEmpty() || 0 != rBrushItem.GetGraphicPos() ) { - OutCSS1_SvxBrush( rWrt, rBrushItem, Css1Background::Fly, nullptr ); + OutCSS1_SvxBrush( rWrt, rBrushItem, sw::Css1Background::Fly, nullptr ); bWritten = true; } return bWritten; @@ -3132,12 +3123,12 @@ static Writer& OutCSS1_SvxFormatBreak_SwFormatPDesc_SvxFormatKeep( Writer& rWrt, // Wrapper for OutCSS1_SfxItemSet etc. static Writer& OutCSS1_SvxBrush( Writer& rWrt, const SfxPoolItem& rHt ) { - OutCSS1_SvxBrush( rWrt, rHt, Css1Background::Attr, nullptr ); + OutCSS1_SvxBrush( rWrt, rHt, sw::Css1Background::Attr, nullptr ); return rWrt; } static Writer& OutCSS1_SvxBrush( Writer& rWrt, const SfxPoolItem& rHt, - Css1Background nMode, + sw::Css1Background nMode, const OUString* pGraphicName) { SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt); @@ -3154,7 +3145,7 @@ static Writer& OutCSS1_SvxBrush( Writer& rWrt, const SfxPoolItem& rHt, OUString aLink = pGraphicName ? *pGraphicName : static_cast<const SvxBrushItem &>(rHt).GetGraphicLink(); SvxGraphicPosition ePos = static_cast<const SvxBrushItem &>(rHt).GetGraphicPos(); - if( Css1Background::Page == nMode && !rHTMLWrt.mbEmbedImages ) + if( sw::Css1Background::Page == nMode && !rHTMLWrt.mbEmbedImages ) { // page style images are exported if not tiled if( aLink.isEmpty() || GPOS_TILED==ePos ) @@ -3197,7 +3188,7 @@ static Writer& OutCSS1_SvxBrush( Writer& rWrt, const SfxPoolItem& rHt, aLink = aGraphicAsLink; } // In tables we only export something if there is a Graphic - if( Css1Background::Table==nMode && !pGrf && !aLink.isEmpty()) + if( (nMode == sw::Css1Background::Table || nMode == sw::Css1Background::TableRow) && !pGrf && !aLink.isEmpty()) return rWrt; // if necessary, add the orientation of the Graphic @@ -3268,7 +3259,7 @@ static Writer& OutCSS1_SvxBrush( Writer& rWrt, const SfxPoolItem& rHt, if( !pGrf && aLink.isEmpty() && !bColor ) { // no color and no Link, but a transparent Brush - if( bTransparent && Css1Background::Fly != nMode ) + if( bTransparent && sw::Css1Background::Fly != nMode ) sOut += OStringToOUString(sCSS1_PV_transparent, RTL_TEXTENCODING_ASCII_US); } else @@ -3315,8 +3306,10 @@ static Writer& OutCSS1_SvxBrush( Writer& rWrt, const SfxPoolItem& rHt, } if( !sOut.isEmpty() ) + { rHTMLWrt.OutCSS1_Property(sCSS1_P_background, nullptr, &sOut, - nMode == Css1Background::Table); + nMode); + } return rWrt; } diff --git a/sw/source/filter/html/wrthtml.hxx b/sw/source/filter/html/wrthtml.hxx index a19fcfc9cd3b..52ab53205165 100644 --- a/sw/source/filter/html/wrthtml.hxx +++ b/sw/source/filter/html/wrthtml.hxx @@ -253,6 +253,20 @@ typedef std::set<std::unique_ptr<SwHTMLFormatInfo>, class IDocumentStylePoolAccess; +namespace sw +{ +enum class Css1Background +{ + Attr = 1, + Page = 2, + Table = 3, + Fly = 4, + Section = 5, + TableRow = 6, + TableCell = 7, +}; +} + class SW_DLLPUBLIC SwHTMLWriter : public Writer { std::unique_ptr<SwHTMLPosFlyFrames> m_pHTMLPosFlyFrames; @@ -468,7 +482,7 @@ public: const OString& rVal ); inline void OutCSS1_Property( const char *pProp, const OUString& rVal ); void OutCSS1_Property( const char *pProp, const char *pVal, - const OUString *pSVal, bool bTable = false ); + const OUString *pSVal, std::optional<sw::Css1Background> oBackground = std::nullopt ); void OutCSS1_UnitProperty( const char *pProp, long nVal ); void OutCSS1_PixelProperty( const char *pProp, long nVal, bool bVert ); void OutCSS1_SfxItemSet( const SfxItemSet& rItemSet, bool bDeep=true ); @@ -494,8 +508,12 @@ public: void writeFrameFormatOptions(HtmlWriter& aHtml, const SwFrameFormat& rFrameFormat, const OUString& rAltText, HtmlFrmOpts nFrameOpts); + /// Writes the formatting for tables. void OutCSS1_TableFrameFormatOptions( const SwFrameFormat& rFrameFormat ); + + /// Writes the borders and background for table cells. void OutCSS1_TableCellBordersAndBG(const SwFrameFormat& rFrameFormat, const SvxBrushItem *pBrushItem); + void OutCSS1_SectionFormatOptions( const SwFrameFormat& rFrameFormat, const SwFormatCol *pCol ); void OutCSS1_FrameFormatOptions( const SwFrameFormat& rFrameFormat, HtmlFrmOpts nFrameOpts, const SdrObject *pSdrObj=nullptr, @@ -696,7 +714,9 @@ Writer& OutCSS1_ParaTagStyleOpt( Writer& rWrt, const SfxItemSet& rItemSet ); Writer& OutCSS1_HintSpanTag( Writer& rWrt, const SfxPoolItem& rHt ); Writer& OutCSS1_HintStyleOpt( Writer& rWrt, const SfxPoolItem& rHt ); +/// Writes the background of table rows. Writer& OutCSS1_TableBGStyleOpt( Writer& rWrt, const SfxPoolItem& rHt ); + Writer& OutCSS1_NumberBulletListStyleOpt( Writer& rWrt, const SwNumRule& rNumRule, sal_uInt8 nLevel ); @@ -711,7 +731,7 @@ OString GetCSS1_Color(const Color& rColor); /// Determines if rProperty with a given rValue has to be suppressed due to ReqIF mode. bool IgnorePropertyForReqIF(bool bReqIF, const OString& rProperty, const OString& rValue, - bool bTable = false); + std::optional<sw::Css1Background> oBackground = std::nullopt); #endif // INCLUDED_SW_SOURCE_FILTER_HTML_WRTHTML_HXX commit 766b501cf48440d042b598215e101e5851743b09 Author: Caolán McNamara <[email protected]> AuthorDate: Thu Aug 12 12:55:30 2021 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Fri Jun 10 09:17:41 2022 +0200 Resolves: tdf#132739 two style tags where there should be just one (cherry picked from commit 6833e0c0af09637bb410dc800435dcc6c8333680) Change-Id: Id9c8c8cc8c5ffdd21ba79ff39a6279cf2ddc8025 diff --git a/sw/source/filter/html/css1atr.cxx b/sw/source/filter/html/css1atr.cxx index b2d5aecb9e78..368f97926656 100644 --- a/sw/source/filter/html/css1atr.cxx +++ b/sw/source/filter/html/css1atr.cxx @@ -2111,10 +2111,12 @@ void SwHTMLWriter::OutCSS1_TableFrameFormatOptions( const SwFrameFormat& rFrameF Strm().WriteChar( '\"' ); } -void SwHTMLWriter::OutCSS1_TableCellBorderHack(SwFrameFormat const& rFrameFormat) +void SwHTMLWriter::OutCSS1_TableCellBordersAndBG(SwFrameFormat const& rFrameFormat, const SvxBrushItem *pBrushItem) { SwCSS1OutMode const aMode( *this, CSS1_OUTMODE_STYLE_OPT_ON|CSS1_OUTMODE_ENCODE|CSS1_OUTMODE_TABLEBOX, nullptr ); + if (pBrushItem) + OutCSS1_SvxBrush(*this, *pBrushItem, Css1Background::Table, nullptr); OutCSS1_SvxBox(*this, rFrameFormat.GetBox()); if (!m_bFirstCSS1Property) { diff --git a/sw/source/filter/html/htmltabw.cxx b/sw/source/filter/html/htmltabw.cxx index 46632157af43..dea6d9d01b62 100644 --- a/sw/source/filter/html/htmltabw.cxx +++ b/sw/source/filter/html/htmltabw.cxx @@ -430,11 +430,14 @@ void SwHTMLWrtTable::OutTableCell( SwHTMLWriter& rWrt, // Avoid non-CSS version in the ReqIF case. rWrt.OutBackground( pBrushItem, false ); - if( rWrt.m_bCfgOutStyles ) - OutCSS1_TableBGStyleOpt( rWrt, *pBrushItem ); + if (!rWrt.m_bCfgOutStyles) + pBrushItem = nullptr; } - rWrt.OutCSS1_TableCellBorderHack(*pBox->GetFrameFormat()); + // tdf#132739 with rWrt.m_bCfgOutStyles of true bundle the brush item css + // properties into the same "style" tag as the borders so there is only one + // style tag + rWrt.OutCSS1_TableCellBordersAndBG(*pBox->GetFrameFormat(), pBrushItem); sal_uInt32 nNumFormat = 0; double nValue = 0.0; diff --git a/sw/source/filter/html/wrthtml.hxx b/sw/source/filter/html/wrthtml.hxx index 3600124ceece..a19fcfc9cd3b 100644 --- a/sw/source/filter/html/wrthtml.hxx +++ b/sw/source/filter/html/wrthtml.hxx @@ -495,7 +495,7 @@ public: void writeFrameFormatOptions(HtmlWriter& aHtml, const SwFrameFormat& rFrameFormat, const OUString& rAltText, HtmlFrmOpts nFrameOpts); void OutCSS1_TableFrameFormatOptions( const SwFrameFormat& rFrameFormat ); - void OutCSS1_TableCellBorderHack(const SwFrameFormat& rFrameFormat); + void OutCSS1_TableCellBordersAndBG(const SwFrameFormat& rFrameFormat, const SvxBrushItem *pBrushItem); void OutCSS1_SectionFormatOptions( const SwFrameFormat& rFrameFormat, const SwFormatCol *pCol ); void OutCSS1_FrameFormatOptions( const SwFrameFormat& rFrameFormat, HtmlFrmOpts nFrameOpts, const SdrObject *pSdrObj=nullptr,
