sw/qa/extras/htmlexport/data/clearing-break.html |    8 +
 sw/qa/extras/htmlexport/htmlexport.cxx           |   43 ++++++++++
 sw/source/filter/html/htmlatr.cxx                |    2 
 sw/source/filter/html/htmlftn.cxx                |   27 ++++++
 sw/source/filter/html/swhtml.cxx                 |   97 +++++------------------
 sw/source/filter/html/wrthtml.hxx                |    1 
 6 files changed, 105 insertions(+), 73 deletions(-)

New commits:
commit c4f7c4b884ab3f47ddebc04c4e31d36e0edcda88
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Mar 22 09:07:09 2022 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Mar 31 08:25:05 2022 +0200

    sw clearing breaks: add HTML filter
    
    Map between SwLineBreakClear and <br clear="...">.
    
    The import-time workaround with the anchor-only wrapping is no longer
    needed, the layout is now capable of doing this.
    
    (cherry picked from commit 66d1ea5915761f3550b39466db5d48eb723f0ccc)
    
    Conflicts:
            sw/qa/extras/htmlexport/htmlexport.cxx
    
    Change-Id: I53fa49f11e13fc3338b3cf70d8f87f3633c414c0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132294
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/extras/htmlexport/data/clearing-break.html 
b/sw/qa/extras/htmlexport/data/clearing-break.html
new file mode 100644
index 000000000000..9586cb3af8e8
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/clearing-break.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>
+<img 
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABlElEQVR4nKWSQasBURiGX91zk5KykUKysPEjlFhIVqNmMSmjUfY2lC1FNrKj1C13pS4rFsL8BvMDpkRZWCnTRN3mOkej696x4a05PdM55/3ezvcRwzDwiggv2l5yIHQZfgyfusyL/NWAajR6gyzLSCQScLvdUFUVHo8HTqfTklMp7ZqAVm82VfT7fSyXS9jtdpzPZ0SjUWy3W2YqiuI/HgxklpzQypVKBdlsFn6/H61WC4fDAbVajf3HYjFMp9NLxZQFKyDdbpdFURQF+/0epVKJJTBFTebz+UMmi8XiZpDP51EulxEKhdgBU4FA4CHfHpFqMpmwz+v1QpIkVKtVOBwOtqfruiWTeDyO2Wx2M/H5fNA0DfV6HZFIBIIgYLPZYDweWzIpFot3Bp1OB8fjEblcDuv1GrvdjrVttVpZMuG4bzQaDdYJqna7DTreNKLL5WKtKxQKrDt/WRDe6SjzrJ/h8Bd6vR7boEomkwgGg8hkMpacTuv3k0iTcJx0IenXs+o4nT4t2RQxZ/pZXUbZsD19+6IfJMHZoeveMPgAAAAASUVORK5CYII="
 name="Image1" align="left" width="68" height="68" border="0"/>
+foo<br clear="all"/>bar</p>
+</body>
+</html>
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx 
b/sw/qa/extras/htmlexport/htmlexport.cxx
index 7f64c835ce2d..9750555bf7f6 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -51,6 +51,7 @@
 #include <paratr.hxx>
 #include <docsh.hxx>
 #include <unotxdoc.hxx>
+#include <formatlinebreak.hxx>
 
 namespace
 {
@@ -2119,6 +2120,48 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, 
testTrailingLineBreak)
     CPPUNIT_ASSERT_EQUAL(OUString("test\n"), aActual);
 }
 
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testClearingBreak)
+{
+    auto verify = [this]() {
+        uno::Reference<container::XEnumerationAccess> 
xParagraph(getParagraph(1), uno::UNO_QUERY);
+        uno::Reference<container::XEnumeration> xPortions = 
xParagraph->createEnumeration();
+        uno::Reference<beans::XPropertySet> xPortion;
+        OUString aPortionType;
+        while (true)
+        {
+            // Ignore leading comments.
+            xPortion.set(xPortions->nextElement(), uno::UNO_QUERY);
+            xPortion->getPropertyValue("TextPortionType") >>= aPortionType;
+            if (aPortionType != "Annotation")
+            {
+                break;
+            }
+        }
+        // Skip "foo".
+        // Without the accompanying fix in place, this test would have failed 
with:
+        // An uncaught exception of type 
com.sun.star.container.NoSuchElementException
+        // i.e. the first para was just comments + text portion, the clearing 
break was lost.
+        xPortion.set(xPortions->nextElement(), uno::UNO_QUERY);
+        xPortion->getPropertyValue("TextPortionType") >>= aPortionType;
+        CPPUNIT_ASSERT_EQUAL(OUString("LineBreak"), aPortionType);
+        uno::Reference<text::XTextContent> xLineBreak;
+        xPortion->getPropertyValue("LineBreak") >>= xLineBreak;
+        sal_Int16 eClear{};
+        uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, 
uno::UNO_QUERY);
+        xLineBreakProps->getPropertyValue("Clear") >>= eClear;
+        CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(SwLineBreakClear::ALL), 
eClear);
+    };
+
+    // Given a document with an at-para anchored image + a clearing break:
+    // When loading that file:
+    load(mpTestDocumentPath, "clearing-break.html");
+    // Then make sure that the clear property of the break is not ignored:
+    verify();
+    reload(mpFilter, "clearing-break.html");
+    // Make sure that that the clear property of the break is not ignored 
during export:
+    verify();
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/htmlatr.cxx 
b/sw/source/filter/html/htmlatr.cxx
index 41e5fad5c193..b34eed5bd41b 100644
--- a/sw/source/filter/html/htmlatr.cxx
+++ b/sw/source/filter/html/htmlatr.cxx
@@ -3269,7 +3269,7 @@ SwAttrFnTab aHTMLAttrFnTab = {
 /* RES_TXTATR_FLYCNT */             OutHTML_SwFlyCnt,
 /* RES_TXTATR_FTN */                OutHTML_SwFormatFootnote,
 /* RES_TXTATR_ANNOTATION */         OutHTML_SwFormatField,
-/* RES_TXTATR_LINEBREAK */          nullptr,
+/* RES_TXTATR_LINEBREAK */          OutHTML_SwFormatLineBreak,
 /* RES_TXTATR_DUMMY1 */             nullptr, // Dummy:
 /* RES_TXTATR_DUMMY2 */             nullptr, // Dummy:
 
diff --git a/sw/source/filter/html/htmlftn.cxx 
b/sw/source/filter/html/htmlftn.cxx
index cfb6f59671c3..0020a4166eae 100644
--- a/sw/source/filter/html/htmlftn.cxx
+++ b/sw/source/filter/html/htmlftn.cxx
@@ -24,6 +24,7 @@
 #include <osl/diagnose.h>
 #include <svtools/htmlout.hxx>
 #include <svtools/htmlkywd.hxx>
+#include <svtools/HtmlWriter.hxx>
 #include <rtl/strbuf.hxx>
 #include <ndindex.hxx>
 #include <fmtftn.hxx>
@@ -244,6 +245,32 @@ SwNodeIndex *SwHTMLParser::GetFootEndNoteSection( const 
OUString& rName )
     return pStartNodeIdx;
 }
 
+Writer& OutHTML_SwFormatLineBreak(Writer& rWrt, const SfxPoolItem& rHt)
+{
+    SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
+    const auto& rLineBreak = static_cast<const SwFormatLineBreak&>(rHt);
+
+    HtmlWriter aWriter(rHTMLWrt.Strm(), rHTMLWrt.maNamespace);
+    aWriter.start(OOO_STRING_SVTOOLS_HTML_linebreak);
+    switch (rLineBreak.GetValue())
+    {
+        case SwLineBreakClear::NONE:
+            aWriter.attribute(OOO_STRING_SVTOOLS_HTML_O_clear, "none");
+            break;
+        case SwLineBreakClear::LEFT:
+            aWriter.attribute(OOO_STRING_SVTOOLS_HTML_O_clear, "left");
+            break;
+        case SwLineBreakClear::RIGHT:
+            aWriter.attribute(OOO_STRING_SVTOOLS_HTML_O_clear, "right");
+            break;
+        case SwLineBreakClear::ALL:
+            aWriter.attribute(OOO_STRING_SVTOOLS_HTML_O_clear, "all");
+            break;
+    }
+    aWriter.end();
+    return rWrt;
+}
+
 Writer& OutHTML_SwFormatFootnote( Writer& rWrt, const SfxPoolItem& rHt )
 {
     SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
diff --git a/sw/source/filter/html/swhtml.cxx b/sw/source/filter/html/swhtml.cxx
index 5212159ae012..f1e929e34ba9 100644
--- a/sw/source/filter/html/swhtml.cxx
+++ b/sw/source/filter/html/swhtml.cxx
@@ -5116,21 +5116,8 @@ void SwHTMLParser::InsertIDOption()
 
 void SwHTMLParser::InsertLineBreak()
 {
-    // <BR CLEAR=xxx> is handled as:
-    // 1.) Only regard the paragraph-bound frames anchored in current 
paragraph.
-    // 2.) For left-justified aligned frames, CLEAR=LEFT or ALL, and for right-
-    //     justified aligned frames, CLEAR=RIGHT or ALL, the wrap-through is
-    //     changed as following:
-    // 3.) If the paragraph contains no text, then the frames don't get a 
wrapping
-    // 4.) otherwise a left aligned frame gets a right "only anchor" wrapping
-    //     and a right aligned frame gets a left "only anchor" wrapping.
-    // 5.) if in a non-empty paragraph the wrapping of a frame is changed,
-    //     then a new paragraph is opened
-    // 6.) If no wrappings of frames are changed, a hard line break is 
inserted.
-
     OUString aId, aStyle, aClass;             // the id of bookmark
-    bool bClearLeft = false, bClearRight = false;
-    bool bCleared = false;  // Was a CLEAR executed?
+    SwLineBreakClear eClear = SwLineBreakClear::NONE;
 
     // then we fetch the options
     const HTMLOptions& rHTMLOptions = GetOptions();
@@ -5144,13 +5131,16 @@ void SwHTMLParser::InsertLineBreak()
                     const OUString &rClear = rOption.GetString();
                     if( rClear.equalsIgnoreAsciiCase( 
OOO_STRING_SVTOOLS_HTML_AL_all ) )
                     {
-                        bClearLeft = true;
-                        bClearRight = true;
+                        eClear = SwLineBreakClear::ALL;
                     }
                     else if( rClear.equalsIgnoreAsciiCase( 
OOO_STRING_SVTOOLS_HTML_AL_left ) )
-                        bClearLeft = true;
+                    {
+                        eClear = SwLineBreakClear::LEFT;
+                    }
                     else if( rClear.equalsIgnoreAsciiCase( 
OOO_STRING_SVTOOLS_HTML_AL_right ) )
-                        bClearRight = true;
+                    {
+                        eClear = SwLineBreakClear::LEFT;
+                    }
                 }
                 break;
             case HtmlOptionId::ID:
@@ -5166,57 +5156,6 @@ void SwHTMLParser::InsertLineBreak()
         }
     }
 
-    // CLEAR is only supported for the current paragraph
-    if( bClearLeft || bClearRight )
-    {
-        SwNodeIndex& rNodeIdx = m_pPam->GetPoint()->nNode;
-        SwTextNode* pTextNd = rNodeIdx.GetNode().GetTextNode();
-        if( pTextNd )
-        {
-            const SwFrameFormats& rFrameFormatTable = 
*m_xDoc->GetSpzFrameFormats();
-
-            for( size_t i=0; i<rFrameFormatTable.size(); i++ )
-            {
-                SwFrameFormat *const pFormat = rFrameFormatTable[i];
-                SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor();
-                SwPosition const*const pAPos = pAnchor->GetContentAnchor();
-                if (pAPos &&
-                    ((RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) ||
-                     (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
-                    pAPos->nNode == rNodeIdx &&
-                    pFormat->GetSurround().GetSurround() != 
css::text::WrapTextMode_NONE )
-                {
-                    sal_Int16 eHori = RES_DRAWFRMFMT == pFormat->Which()
-                        ? text::HoriOrientation::LEFT
-                        : pFormat->GetHoriOrient().GetHoriOrient();
-
-                    css::text::WrapTextMode eSurround = 
css::text::WrapTextMode_PARALLEL;
-                    if( m_pPam->GetPoint()->nContent.GetIndex() )
-                    {
-                        if( bClearLeft && text::HoriOrientation::LEFT==eHori )
-                            eSurround = css::text::WrapTextMode_RIGHT;
-                        else if( bClearRight && 
text::HoriOrientation::RIGHT==eHori )
-                            eSurround = css::text::WrapTextMode_LEFT;
-                    }
-                    else if( (bClearLeft && 
text::HoriOrientation::LEFT==eHori) ||
-                             (bClearRight && 
text::HoriOrientation::RIGHT==eHori) )
-                    {
-                        eSurround = css::text::WrapTextMode_NONE;
-                    }
-
-                    if( css::text::WrapTextMode_PARALLEL != eSurround )
-                    {
-                        SwFormatSurround aSurround( eSurround );
-                        if( css::text::WrapTextMode_NONE != eSurround )
-                            aSurround.SetAnchorOnly( true );
-                        pFormat->SetFormatAttr( aSurround );
-                        bCleared = true;
-                    }
-                }
-            }
-        }
-    }
-
     // parse styles
     std::shared_ptr<SvxFormatBreakItem> 
aBreakItem(std::make_shared<SvxFormatBreakItem>(SvxBreak::NONE, RES_BREAK));
     bool bBreakItem = false;
@@ -5243,10 +5182,24 @@ void SwHTMLParser::InsertLineBreak()
         EndAttr( m_xAttrTab->pBreak, false );
     }
 
-    if( !bCleared && !bBreakItem )
+    if (!bBreakItem)
     {
-        // If no CLEAR could or should be executed, a line break will be 
inserted
-        m_xDoc->getIDocumentContentOperations().InsertString( *m_pPam, "\x0A" 
);
+        if (eClear == SwLineBreakClear::NONE)
+        {
+            // If no CLEAR could or should be executed, a line break will be 
inserted
+            m_xDoc->getIDocumentContentOperations().InsertString(*m_pPam, 
"\x0A");
+        }
+        else
+        {
+            // <BR CLEAR=xxx> is mapped an SwFormatLineBreak.
+            SwTextNode* pTextNode = m_pPam->GetNode().GetTextNode();
+            if (pTextNode)
+            {
+                SwFormatLineBreak aLineBreak(eClear);
+                sal_Int32 nPos = m_pPam->GetPoint()->nContent.GetIndex();
+                pTextNode->InsertItem(aLineBreak, nPos, nPos);
+            }
+        }
     }
     else if( m_pPam->GetPoint()->nContent.GetIndex() )
     {
diff --git a/sw/source/filter/html/wrthtml.hxx 
b/sw/source/filter/html/wrthtml.hxx
index bf6806b1ae95..e2821b492762 100644
--- a/sw/source/filter/html/wrthtml.hxx
+++ b/sw/source/filter/html/wrthtml.hxx
@@ -685,6 +685,7 @@ Writer& OutHTML_BulletImage( Writer& rWrt, const char *pTag,
 
 Writer& OutHTML_SwFormatField( Writer& rWrt, const SfxPoolItem& rHt );
 Writer& OutHTML_SwFormatFootnote( Writer& rWrt, const SfxPoolItem& rHt );
+Writer& OutHTML_SwFormatLineBreak(Writer& rWrt, const SfxPoolItem& rHt);
 Writer& OutHTML_INetFormat( Writer&, const SwFormatINetFormat& rINetFormat, 
bool bOn );
 
 Writer& OutCSS1_BodyTagStyleOpt( Writer& rWrt, const SfxItemSet& rItemSet );

Reply via email to