sw/inc/unotextbodyhf.hxx                                                 |    
2 
 sw/inc/unotextrange.hxx                                                  |    
3 
 sw/qa/extras/ooxmlexport/data/tdf143384_tableInFoot_negativeMargins.docx 
|binary
 sw/qa/extras/ooxmlexport/ooxmlexport11.cxx                               |    
7 +
 sw/source/core/unocore/unoframe.cxx                                      |    
8 +
 sw/source/core/unocore/unoobj2.cxx                                       |   
15 ++
 sw/source/core/unocore/unotext.cxx                                       |   
56 +++++++---
 writerfilter/source/dmapper/DomainMapper_Impl.cxx                        |    
8 +
 writerfilter/source/dmapper/PropertyIds.cxx                              |    
1 
 writerfilter/source/dmapper/PropertyIds.hxx                              |    
1 
 10 files changed, 83 insertions(+), 18 deletions(-)

New commits:
commit c1ad429d925855c1baacbdeca1ef42f4486eb9c2
Author:     Attila Szűcs <szucs.atti...@nisz.hu>
AuthorDate: Tue Jul 27 11:45:58 2021 +0200
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Wed Aug 25 13:45:23 2021 +0200

    tdf#143384 DOCX import: fix SAXException at header with table
    
    Regression from commit d656191ec308d4280b93c7169372e543a255d108
    "tdf#119952 DOCX import: fix negative page margins".
    
    Add SwXHeadFootText::CreateTextCursor(bool bIgnoreTables = false)
    (modeled after SwXBodyText::CreateTextCursor) to create text cursor
    for copying the header/footer also started with table during
    fly frame creation in convertoToTextFrame().
    
    Note: add hidden property PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF
    to use the new feature in domainmapper (followed
    commit af4e5ee0f93c1ff442d08caed5c875f2b2c1fd43
    "tdf#97128 DOCX import: fix frame direction").
    
    Co-authored-by: Tibor Nagy (NISZ)
    
    Change-Id: I96e2cf2dddcecd146c53c12d7fdb44fc4d90fa0d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119549
    Tested-by: László Németh <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>

diff --git a/sw/inc/unotextbodyhf.hxx b/sw/inc/unotextbodyhf.hxx
index fbccc982ef04..99887c6beb5c 100644
--- a/sw/inc/unotextbodyhf.hxx
+++ b/sw/inc/unotextbodyhf.hxx
@@ -115,6 +115,8 @@ public:
     static css::uno::Reference< css::text::XText >
         CreateXHeadFootText(SwFrameFormat & rHeadFootFormat, const bool 
bIsHeader);
 
+    css::uno::Reference<css::text::XTextCursor> CreateTextCursor(const bool 
bIgnoreTables = false);
+
     // XInterface
     virtual css::uno::Any SAL_CALL queryInterface(
             const css::uno::Type& rType) override;
diff --git a/sw/inc/unotextrange.hxx b/sw/inc/unotextrange.hxx
index f3ed06fb4a06..4d8ed2df2c06 100644
--- a/sw/inc/unotextrange.hxx
+++ b/sw/inc/unotextrange.hxx
@@ -57,7 +57,8 @@ namespace sw {
 
     enum class TextRangeMode {
         RequireTextNode,
-        AllowNonTextNode
+        AllowNonTextNode,
+        AllowTableNode
     };
 
     void DeepCopyPaM(SwPaM const & rSource, SwPaM & rTarget);
diff --git 
a/sw/qa/extras/ooxmlexport/data/tdf143384_tableInFoot_negativeMargins.docx 
b/sw/qa/extras/ooxmlexport/data/tdf143384_tableInFoot_negativeMargins.docx
new file mode 100644
index 000000000000..918c1029fb4a
Binary files /dev/null and 
b/sw/qa/extras/ooxmlexport/data/tdf143384_tableInFoot_negativeMargins.docx 
differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
index de3eea4c0659..08e0cbd9f8f7 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
@@ -1618,6 +1618,13 @@ DECLARE_OOXMLEXPORT_TEST(testTdf119952_negativeMargins, 
"tdf119952_negativeMargi
     CPPUNIT_ASSERT_EQUAL(OUString("  aaaa   bbbb    cccc     dddd      eeee"), 
parseDump("/root/page[3]/header/txt/anchored/fly"));
 }
 
+DECLARE_OOXMLEXPORT_TEST(testTdf143384_tableInFoot_negativeMargins, 
"tdf143384_tableInFoot_negativeMargins.docx")
+{
+    // There should be no crash during loading of the document
+    // so, let's check just how much pages we have
+    CPPUNIT_ASSERT_EQUAL(1, getPages());
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/unocore/unoframe.cxx 
b/sw/source/core/unocore/unoframe.cxx
index 74d366d9961d..8b9250671d78 100644
--- a/sw/source/core/unocore/unoframe.cxx
+++ b/sw/source/core/unocore/unoframe.cxx
@@ -1418,7 +1418,13 @@ void SwXFrame::setPropertyValue(const OUString& 
rPropertyName, const ::uno::Any&
     const ::SfxItemPropertyMapEntry* pEntry = 
m_pPropSet->getPropertyMap().getByName(rPropertyName);
 
     if (!pEntry)
-        throw beans::UnknownPropertyException( "Unknown property: " + 
rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
+    {
+        // Hack to skip the dummy CursorNotIgnoreTables property
+        if (rPropertyName == "CursorNotIgnoreTables")
+            return;
+        else
+            throw beans::UnknownPropertyException("Unknown property: " + 
rPropertyName, static_cast <cppu::OWeakObject*> (this));
+    }
 
     const sal_uInt8 nMemberId(pEntry->nMemberId);
     uno::Any aValue(_rValue);
diff --git a/sw/source/core/unocore/unoobj2.cxx 
b/sw/source/core/unocore/unoobj2.cxx
index 2103220de62b..e99450378bac 100644
--- a/sw/source/core/unocore/unoobj2.cxx
+++ b/sw/source/core/unocore/unoobj2.cxx
@@ -1116,6 +1116,7 @@ bool XTextRangeToSwPaM( SwUnoInternalPaM & rToFill,
     SwXTextPortion* pPortion = nullptr;
     SwXText* pText = nullptr;
     SwXParagraph* pPara = nullptr;
+    SwXHeadFootText* pHeadText = nullptr;
     if(xRangeTunnel.is())
     {
         pRange  = ::sw::UnoTunnelGetImplementation<SwXTextRange>(xRangeTunnel);
@@ -1125,12 +1126,26 @@ bool XTextRangeToSwPaM( SwUnoInternalPaM & rToFill,
             ::sw::UnoTunnelGetImplementation<SwXTextPortion>(xRangeTunnel);
         pText   = ::sw::UnoTunnelGetImplementation<SwXText>(xRangeTunnel);
         pPara   = ::sw::UnoTunnelGetImplementation<SwXParagraph>(xRangeTunnel);
+        if (eMode == TextRangeMode::AllowTableNode)
+            pHeadText = dynamic_cast<SwXHeadFootText*>(pText);
     }
 
     // if it's a text then create a temporary cursor there and re-use
     // the pCursor variable
     // #i108489#: Reference in outside scope to keep cursor alive
     uno::Reference< text::XTextCursor > xTextCursor;
+    if (pHeadText)
+    {
+        // if it is a header / footer text, and eMode == 
TextRangeMode::AllowTableNode
+        // then set the cursor to the beginning of the text
+        // if it is started with a table then set into the table
+        xTextCursor.set(pHeadText->CreateTextCursor(true));
+        xTextCursor->gotoEnd(true);
+        pCursor =
+            
comphelper::getUnoTunnelImplementation<OTextCursorHelper>(xTextCursor);
+        pCursor->GetPaM()->Normalize();
+    }
+    else
     if (pText)
     {
         xTextCursor.set( pText->CreateCursor() );
diff --git a/sw/source/core/unocore/unotext.cxx 
b/sw/source/core/unocore/unotext.cxx
index 7e0c73d8c778..fa779d95abd8 100644
--- a/sw/source/core/unocore/unotext.cxx
+++ b/sw/source/core/unocore/unotext.cxx
@@ -1537,14 +1537,31 @@ SwXText::convertToTextFrame(
     {
         throw  uno::RuntimeException();
     }
+    // tdf#143384 recognize dummy property, that was set to make 
createTextCursor
+    // to not ignore tables.
+    // It is enough to use this hack only for the range start,
+    // because as far as I know, the range cannot end with table when this 
property is set.
+    ::sw::TextRangeMode eMode = ::sw::TextRangeMode::RequireTextNode;
+    for (const auto& rCellProperty : rFrameProperties)
+    {
+        if (rCellProperty.Name == "CursorNotIgnoreTables")
+        {
+            bool bAllowNonTextNode = false;
+            rCellProperty.Value >>= bAllowNonTextNode;
+            if (bAllowNonTextNode)
+                eMode = ::sw::TextRangeMode::AllowTableNode;
+            break;
+        }
+    }
     uno::Reference< text::XTextContent > xRet;
     std::optional<SwUnoInternalPaM> pTempStartPam(*GetDoc());
     std::optional<SwUnoInternalPaM> pEndPam(*GetDoc());
-    if (!::sw::XTextRangeToSwPaM(*pTempStartPam, xStart) ||
-        !::sw::XTextRangeToSwPaM(*pEndPam, xEnd))
+    if (!::sw::XTextRangeToSwPaM(*pTempStartPam, xStart, eMode)
+        || !::sw::XTextRangeToSwPaM(*pEndPam, xEnd))
     {
         throw lang::IllegalArgumentException();
     }
+
     auto pStartPam(GetDoc()->CreateUnoCursor(*pTempStartPam->GetPoint()));
     if (pTempStartPam->HasMark())
     {
@@ -2613,8 +2630,7 @@ uno::Any SAL_CALL SwXHeadFootText::queryInterface(const 
uno::Type& rType)
         : ret;
 }
 
-uno::Reference<text::XTextCursor> SAL_CALL
-SwXHeadFootText::createTextCursor()
+uno::Reference<text::XTextCursor> SwXHeadFootText::CreateTextCursor(const bool 
bIgnoreTables)
 {
     SolarMutexGuard aGuard;
 
@@ -2632,18 +2648,22 @@ SwXHeadFootText::createTextCursor()
     // after the table - otherwise the cursor would be in the body text!
     SwStartNode const*const pOwnStartNode = rNode.FindSttNodeByType(
             (m_pImpl->m_bIsHeader) ? SwHeaderStartNode : SwFooterStartNode);
-    // is there a table here?
-    SwTableNode* pTableNode = rUnoCursor.GetNode().FindTableNode();
-    SwContentNode* pCont = nullptr;
-    while (pTableNode)
-    {
-        rUnoCursor.GetPoint()->nNode = *pTableNode->EndOfSectionNode();
-        pCont = GetDoc()->GetNodes().GoNext(&rUnoCursor.GetPoint()->nNode);
-        pTableNode = pCont->FindTableNode();
-    }
-    if (pCont)
+
+    if (!bIgnoreTables)
     {
-        rUnoCursor.GetPoint()->nContent.Assign(pCont, 0);
+        // is there a table here?
+        SwTableNode* pTableNode = rUnoCursor.GetNode().FindTableNode();
+        SwContentNode* pCont = nullptr;
+        while (pTableNode)
+        {
+            rUnoCursor.GetPoint()->nNode = *pTableNode->EndOfSectionNode();
+            pCont = GetDoc()->GetNodes().GoNext(&rUnoCursor.GetPoint()->nNode);
+            pTableNode = pCont->FindTableNode();
+        }
+        if (pCont)
+        {
+            rUnoCursor.GetPoint()->nContent.Assign(pCont, 0);
+        }
     }
     SwStartNode const*const pNewStartNode = 
rUnoCursor.GetNode().FindSttNodeByType(
             (m_pImpl->m_bIsHeader) ? SwHeaderStartNode : SwFooterStartNode);
@@ -2656,6 +2676,12 @@ SwXHeadFootText::createTextCursor()
     return static_cast<text::XWordCursor*>(pXCursor.get());
 }
 
+uno::Reference<text::XTextCursor> SAL_CALL
+SwXHeadFootText::createTextCursor()
+{
+    return CreateTextCursor(false);
+}
+
 uno::Reference<text::XTextCursor> SAL_CALL 
SwXHeadFootText::createTextCursorByRange(
     const uno::Reference<text::XTextRange>& xTextPosition)
 {
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 8fffee9d32e4..c6c423ea6517 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -2742,6 +2742,12 @@ void 
DomainMapper_Impl::ConvertHeaderFooterToTextFrame(bool bDynamicHeightTop, b
             
aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_OPAQUE),
 false));
             
aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_WIDTH_TYPE),
 text::SizeType::MIN));
             
aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_SIZE_TYPE),
 text::SizeType::MIN));
+            // tdf#143384 If the header/footer started with a table, 
convertToTextFrame could not
+            // convert the table, because it used createTextCursor() -which 
ignore tables-
+            // to set the conversion range.
+            // This dummy property is set to make convertToTextFrame to use an 
other CreateTextCursor
+            // method that can be parameterized to not ignore tables.
+            
aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF),
 true));
 
             fillEmptyFrameProperties(aFrameProperties, false);
 
@@ -2751,7 +2757,7 @@ void 
DomainMapper_Impl::ConvertHeaderFooterToTextFrame(bool bDynamicHeightTop, b
 
             uno::Reference<text::XTextAppendAndConvert> xBodyText(
                 xRangeStart->getText(), uno::UNO_QUERY);
-            xBodyText->convertToTextFrame(xRangeStart, xRangeEnd,
+            xBodyText->convertToTextFrame(xTextAppend, xRangeEnd,
                 comphelper::containerToSequence(aFrameProperties));
         }
         m_aHeaderFooterTextAppendStack.pop();
diff --git a/writerfilter/source/dmapper/PropertyIds.cxx 
b/writerfilter/source/dmapper/PropertyIds.cxx
index c3e7cbaa2de9..00d5b795b132 100644
--- a/writerfilter/source/dmapper/PropertyIds.cxx
+++ b/writerfilter/source/dmapper/PropertyIds.cxx
@@ -364,6 +364,7 @@ OUString getPropertyName( PropertyIds eId )
         case PROP_RTL_GUTTER:
             sName = "RtlGutter";
             break;
+        case PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF: sName = 
"CursorNotIgnoreTables"; break;
     }
     assert(sName.getLength()>0);
     return sName;
diff --git a/writerfilter/source/dmapper/PropertyIds.hxx 
b/writerfilter/source/dmapper/PropertyIds.hxx
index f1bef16da581..8e23533c57ba 100644
--- a/writerfilter/source/dmapper/PropertyIds.hxx
+++ b/writerfilter/source/dmapper/PropertyIds.hxx
@@ -361,6 +361,7 @@ enum PropertyIds
         ,PROP_CELL_FORMULA_CONVERTED
         ,PROP_GUTTER_MARGIN
         ,PROP_RTL_GUTTER
+        ,PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF
     };
 
 //Returns the UNO string equivalent to eId.

Reply via email to