[Libreoffice-commits] core.git: 2 commits - include/xmloff sw/source xmloff/source

Michael Stahl (via logerrit) logerrit at kemper.freedesktop.org
Wed Oct 23 11:08:58 UTC 2019


 include/xmloff/txtimp.hxx                       |    2 
 sw/source/core/unocore/unobkm.cxx               |    2 
 xmloff/source/text/XMLTextMarkImportContext.cxx |  179 +++++++++++++-----------
 xmloff/source/text/txtimp.cxx                   |   23 ++-
 4 files changed, 120 insertions(+), 86 deletions(-)

New commits:
commit 6eb1c2304d257d16858b7b51cad63f1dc2bde88b
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Oct 18 16:21:00 2019 +0200
Commit:     Michael Stahl <michael.stahl at cib.de>
CommitDate: Wed Oct 23 13:07:52 2019 +0200

    xmloff: ODF import: reimplement fieldmark-start/fieldmark-end
    
    This needs to work in a similar way to writerfilter, because it has the
    same problem: fieldmark has 3 positions but attach() only recieves 2
    positions.
    
    Insert the fieldmark at the fieldmark-start and move the cursor before
    the CH_TXT_ATR_FIELDEND character, and when the fieldmark-end arrives,
    move the cursor forward again.
    
    This will slightly change the import of invalid documents, e.g.
    when a fieldmark-end is missing, but that seems not so important and
    without a name attribute on the fieldmark-end we can't do any better.
    
    Change-Id: I3f0bd738277f56a999e79e4def911101b64b07e7
    Reviewed-on: https://gerrit.libreoffice.org/81082
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.stahl at cib.de>

diff --git a/include/xmloff/txtimp.hxx b/include/xmloff/txtimp.hxx
index f2db2826cf2d..db79f9c24dbd 100644
--- a/include/xmloff/txtimp.hxx
+++ b/include/xmloff/txtimp.hxx
@@ -566,7 +566,7 @@ public:
     OUString FindActiveBookmarkName();
 
     void pushFieldCtx( const OUString& name, const OUString& type );
-    void popFieldCtx();
+    css::uno::Reference<css::text::XFormField> popFieldCtx();
     void addFieldParam( const OUString& name, const OUString& value );
     void setCurrentFieldParamsTo(css::uno::Reference< css::text::XFormField> const &xFormField);
     OUString getCurrentFieldType();
diff --git a/xmloff/source/text/XMLTextMarkImportContext.cxx b/xmloff/source/text/XMLTextMarkImportContext.cxx
index f3346887dc09..9d13c810b240 100644
--- a/xmloff/source/text/XMLTextMarkImportContext.cxx
+++ b/xmloff/source/text/XMLTextMarkImportContext.cxx
@@ -158,11 +158,6 @@ void XMLTextMarkImportContext::StartElement(
         m_sBookmarkName.clear();
     }
 
-    if (IsXMLToken(GetLocalName(), XML_FIELDMARK_END))
-    {
-        m_sBookmarkName = m_rHelper.FindActiveBookmarkName();
-    }
-
     if (IsXMLToken(GetLocalName(), XML_FIELDMARK_START) || IsXMLToken(GetLocalName(), XML_FIELDMARK))
     {
         if (m_sBookmarkName.isEmpty())
@@ -180,17 +175,75 @@ void XMLTextMarkImportContext::StartElement(
     }
 }
 
+static auto InsertFieldmark(SvXMLImport & rImport,
+        XMLTextImportHelper & rHelper, OUString const& rName) -> void
+{
+    assert(rHelper.hasCurrentFieldCtx()); // was set up in StartElement()
+
+    // fdo#86795 check if it's actually a checkbox first
+    OUString const type(rHelper.getCurrentFieldType());
+    OUString const fieldmarkTypeName = lcl_getFieldmarkName(type);
+    if (fieldmarkTypeName == ODF_FORMCHECKBOX ||
+        fieldmarkTypeName == ODF_FORMDROPDOWN)
+    {   // sw can't handle checkbox with start+end
+        SAL_INFO("xmloff.text", "invalid fieldmark-start/fieldmark-end ignored");
+        return;
+    }
+
+    Reference<XTextContent> const xContent = XMLTextMarkImportContext::CreateAndInsertMark(
+            rImport, "com.sun.star.text.Fieldmark",
+            rName, rHelper.GetCursorAsRange());
+
+    if (xContent.is())
+    {
+        // setup fieldmark...
+        Reference<text::XFormField> const xFormField(xContent, UNO_QUERY);
+        assert(xFormField.is());
+        xFormField->setFieldType(fieldmarkTypeName);
+        rHelper.setCurrentFieldParamsTo(xFormField);
+        // move cursor after setFieldType as that may delete/re-insert
+        rHelper.GetCursor()->gotoRange(xContent->getAnchor()->getEnd(), false);
+        rHelper.GetCursor()->goLeft(1, false); // move before CH_TXT_ATR_FIELDEND
+    }
+}
+
+static auto PopFieldmark(XMLTextImportHelper & rHelper) -> void
+{
+    // can't verify name because it's not written as an attribute...
+    uno::Reference<text::XTextContent> const xField(rHelper.popFieldCtx(),
+            uno::UNO_QUERY);
+    if (xField.is())
+    {
+        if (rHelper.GetText() == xField->getAnchor()->getText())
+        {
+            try
+            {   // skip CH_TXT_ATR_FIELDEND
+                rHelper.GetCursor()->gotoRange(xField->getAnchor()->getEnd(), false);
+            }
+            catch (uno::Exception const&)
+            {
+                assert(false); // must succeed
+            }
+        }
+        else
+        {
+            SAL_INFO("xmloff.text", "fieldmark has invalid positions");
+            // could either dispose it or leave it to end at the end of the document?
+            xField->dispose();
+        }
+    }
+}
+
 void XMLTextMarkImportContext::EndElement()
 {
     SvXMLImportContext::EndElement();
 
     static const char sAPI_bookmark[] = "com.sun.star.text.Bookmark";
 
-    if (!m_sBookmarkName.isEmpty())
+    lcl_MarkType nTmp{};
+    if (SvXMLUnitConverter::convertEnum(nTmp, GetLocalName(), lcl_aMarkTypeMap))
     {
-        lcl_MarkType nTmp{};
-        if (SvXMLUnitConverter::convertEnum(nTmp, GetLocalName(),
-                                            lcl_aMarkTypeMap))
+        if (!m_sBookmarkName.isEmpty() || TypeFieldmarkEnd == nTmp)
         {
             switch (nTmp)
             {
@@ -249,7 +302,6 @@ void XMLTextMarkImportContext::EndElement()
                     }
                     break;
 
-                case TypeFieldmarkStart:
                 case TypeBookmarkStart:
                     // save XTextRange for later construction of bookmark
                     {
@@ -270,23 +322,20 @@ void XMLTextMarkImportContext::EndElement()
                     break;
 
                 case TypeBookmarkEnd:
+                {
+                    // tdf#94804: detect duplicate heading cross reference bookmarks
+                    if (m_sBookmarkName.startsWith("__RefHeading__"))
                     {
-                        // tdf#94804: detect duplicate heading cross reference bookmarks
-                        if (m_sBookmarkName.startsWith("__RefHeading__"))
+                        if (m_rxCrossRefHeadingBookmark.is())
                         {
-                            if (m_rxCrossRefHeadingBookmark.is())
-                            {
-                                uno::Reference<container::XNamed> const xNamed(
-                                    m_rxCrossRefHeadingBookmark, uno::UNO_QUERY);
-                                m_rHelper.AddCrossRefHeadingMapping(
-                                    m_sBookmarkName, xNamed->getName());
-                                break; // don't insert
-                            }
+                            uno::Reference<container::XNamed> const xNamed(
+                                m_rxCrossRefHeadingBookmark, uno::UNO_QUERY);
+                            m_rHelper.AddCrossRefHeadingMapping(
+                                m_sBookmarkName, xNamed->getName());
+                            break; // don't insert
                         }
                     }
-                    [[fallthrough]];
-                case TypeFieldmarkEnd:
-                {
+
                     // get old range, and construct
                     Reference<XTextRange> xStartRange;
                     std::shared_ptr< ::xmloff::ParsedRDFaAttributes >
@@ -306,7 +355,7 @@ void XMLTextMarkImportContext::EndElement()
                                 m_rHelper.GetText()->createTextCursorByRange(
                                     xEndRange);
                             try {
-                            xInsertionCursor->gotoRange(xStartRange, true);
+                                xInsertionCursor->gotoRange(xStartRange, true);
                             } catch (uno::Exception&) {
                                 OSL_ENSURE(false,
                                     "cannot go to end position of bookmark");
@@ -318,64 +367,27 @@ void XMLTextMarkImportContext::EndElement()
                             // create a file with subsequence
                             // start/end elements
 
-                            bool bImportAsField = (nTmp==TypeFieldmarkEnd && m_rHelper.hasCurrentFieldCtx());
-
-                            // fdo#86795 check if it's actually a checkbox first
-                            bool isInvalid(false);
-                            OUString fieldmarkTypeName;
-                            if (bImportAsField && m_rHelper.hasCurrentFieldCtx())
-                            {
-
-                                OUString const type(m_rHelper.getCurrentFieldType());
-                                fieldmarkTypeName = lcl_getFieldmarkName(type);
-                                if (fieldmarkTypeName == ODF_FORMCHECKBOX ||
-                                    fieldmarkTypeName == ODF_FORMDROPDOWN)
-                                {   // sw can't handle checkbox with start+end
-                                    SAL_INFO("xmloff.text", "invalid fieldmark-start/fieldmark-end ignored");
-                                    isInvalid = true;
-                                }
-                            }
-
                             Reference<XInterface> xContent;
-                            if (!isInvalid)
+                            // insert reference
+                            xContent = CreateAndInsertMark(GetImport(),
+                                    sAPI_bookmark,
+                                    m_sBookmarkName,
+                                    xInsertionCursor,
+                                    m_sXmlId);
+                            if (xRDFaAttributes)
                             {
-                                // insert reference
-                                xContent = CreateAndInsertMark(GetImport(),
-                                        (bImportAsField
-                                            ? OUString("com.sun.star.text.Fieldmark")
-                                            : sAPI_bookmark),
-                                        m_sBookmarkName,
-                                        xInsertionCursor,
-                                        m_sXmlId);
-                                if (xRDFaAttributes)
-                                {
-                                    const Reference<rdf::XMetadatable>
-                                        xMeta(xContent, UNO_QUERY);
-                                    GetImport().GetRDFaImportHelper().AddRDFa(
-                                        xMeta, xRDFaAttributes);
-                                }
-                                const Reference<XPropertySet> xPropertySet(xContent, UNO_QUERY);
-                                if (xPropertySet.is())
-                                {
-                                    xPropertySet->setPropertyValue("BookmarkHidden",    uno::Any(m_rHelper.getBookmarkHidden(m_sBookmarkName)));
-                                    xPropertySet->setPropertyValue("BookmarkCondition", uno::Any(m_rHelper.getBookmarkCondition(m_sBookmarkName)));
-                                }
+                                const Reference<rdf::XMetadatable>
+                                    xMeta(xContent, UNO_QUERY);
+                                GetImport().GetRDFaImportHelper().AddRDFa(
+                                    xMeta, xRDFaAttributes);
                             }
-
-                            if (nTmp==TypeFieldmarkEnd) {
-                                if (xContent.is() && bImportAsField) {
-                                    // setup fieldmark...
-                                    Reference< css::text::XFormField> xFormField(xContent, UNO_QUERY);
-                                    if (xFormField.is() && m_rHelper.hasCurrentFieldCtx()) {
-
-                                        xFormField->setFieldType(fieldmarkTypeName);
-                                        m_rHelper.setCurrentFieldParamsTo(xFormField);
-                                    }
-                                }
-                                m_rHelper.popFieldCtx();
+                            const Reference<XPropertySet> xPropertySet(xContent, UNO_QUERY);
+                            if (xPropertySet.is())
+                            {
+                                xPropertySet->setPropertyValue("BookmarkHidden",    uno::Any(m_rHelper.getBookmarkHidden(m_sBookmarkName)));
+                                xPropertySet->setPropertyValue("BookmarkCondition", uno::Any(m_rHelper.getBookmarkCondition(m_sBookmarkName)));
                             }
-                            if (TypeBookmarkEnd == nTmp
-                                && m_sBookmarkName.startsWith("__RefHeading__"))
+                            if (m_sBookmarkName.startsWith("__RefHeading__"))
                             {
                                 assert(xContent.is());
                                 m_rxCrossRefHeadingBookmark = xContent;
@@ -386,7 +398,16 @@ void XMLTextMarkImportContext::EndElement()
                     // else: no start found -> ignore!
                     break;
                 }
-
+                case TypeFieldmarkStart: // no separator, so insert at start
+                {
+                    InsertFieldmark(GetImport(), m_rHelper, m_sBookmarkName);
+                    break;
+                }
+                case TypeFieldmarkEnd:
+                {
+                    PopFieldmark(m_rHelper);
+                    break;
+                }
                 case TypeReferenceStart:
                 case TypeReferenceEnd:
                     OSL_FAIL("reference start/end are handled in txtparai !");
diff --git a/xmloff/source/text/txtimp.cxx b/xmloff/source/text/txtimp.cxx
index 7dc6152ae6d8..ab1500fc76e5 100644
--- a/xmloff/source/text/txtimp.cxx
+++ b/xmloff/source/text/txtimp.cxx
@@ -585,7 +585,7 @@ struct XMLTextImportHelper::Impl
     typedef ::std::pair< OUString, OUString> field_name_type_t;
     typedef ::std::pair< OUString, OUString > field_param_t;
     typedef ::std::vector< field_param_t > field_params_t;
-    typedef ::std::pair< field_name_type_t, field_params_t > field_stack_item_t;
+    typedef ::std::tuple<field_name_type_t, field_params_t, uno::Reference<text::XFormField>> field_stack_item_t;
     typedef ::std::stack< field_stack_item_t > field_stack_t;
 
     field_stack_t m_FieldStack;
@@ -2632,13 +2632,23 @@ OUString XMLTextImportHelper::FindActiveBookmarkName()
 void XMLTextImportHelper::pushFieldCtx( const OUString& name, const OUString& type )
 {
     m_xImpl->m_FieldStack.push(Impl::field_stack_item_t(
-        Impl::field_name_type_t(name, type), Impl::field_params_t()));
+        Impl::field_name_type_t(name, type), Impl::field_params_t(), uno::Reference<text::XFormField>{}));
 }
 
-void XMLTextImportHelper::popFieldCtx()
+uno::Reference<text::XFormField>
+XMLTextImportHelper::popFieldCtx()
 {
+    uno::Reference<text::XFormField> xRet;
     if ( !m_xImpl->m_FieldStack.empty() )
+    {
+        xRet = std::get<2>(m_xImpl->m_FieldStack.top());
         m_xImpl->m_FieldStack.pop();
+    }
+    else
+    {
+        SAL_INFO("xmloff.text", "unexpected fieldmark end");
+    }
+    return xRet;
 }
 
 void XMLTextImportHelper::addFieldParam( const OUString& name, const OUString& value )
@@ -2646,7 +2656,7 @@ void XMLTextImportHelper::addFieldParam( const OUString& name, const OUString& v
     assert(!m_xImpl->m_FieldStack.empty());
     if (!m_xImpl->m_FieldStack.empty()) {
         Impl::field_stack_item_t & FieldStackItem(m_xImpl->m_FieldStack.top());
-        FieldStackItem.second.emplace_back( name, value );
+        std::get<1>(FieldStackItem).emplace_back( name, value );
     }
 }
 
@@ -2655,7 +2665,7 @@ OUString XMLTextImportHelper::getCurrentFieldType()
     assert(!m_xImpl->m_FieldStack.empty());
     if (!m_xImpl->m_FieldStack.empty())
     {
-        return m_xImpl->m_FieldStack.top().first.second;
+        return std::get<0>(m_xImpl->m_FieldStack.top()).second;
     }
     else
     {
@@ -2673,8 +2683,9 @@ void XMLTextImportHelper::setCurrentFieldParamsTo(css::uno::Reference< css::text
     assert(!m_xImpl->m_FieldStack.empty());
     if (!m_xImpl->m_FieldStack.empty() && xFormField.is())
     {
-        FieldParamImporter(&m_xImpl->m_FieldStack.top().second,
+        FieldParamImporter(&std::get<1>(m_xImpl->m_FieldStack.top()),
             xFormField->getParameters()).Import();
+        std::get<2>(m_xImpl->m_FieldStack.top()) = xFormField;
     }
 }
 
commit 26599f049df7c52eca001ba52a0684888201e1ba
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Oct 18 14:03:03 2019 +0200
Commit:     Michael Stahl <michael.stahl at cib.de>
CommitDate: Wed Oct 23 13:07:23 2019 +0200

    sw: fix crash after SwXFieldmark::SetFieldType()
    
    It deletes the existing IFieldmark and creates a new one; meanwhile the
    SwXFieldmark is disposed and its m_pImpl->m_pDoc is cleared but then
    it's not initialised again by registerInMark().
    
    (regression from f66a83c95c21b4311918a64bb85016857b49f4d4)
    
    Change-Id: I8c4d9b829f68b9e5bd714bcad2061d0ff95bfb82
    Reviewed-on: https://gerrit.libreoffice.org/81081
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.stahl at cib.de>

diff --git a/sw/source/core/unocore/unobkm.cxx b/sw/source/core/unocore/unobkm.cxx
index 28af288deef4..ddeaccf1966b 100644
--- a/sw/source/core/unocore/unobkm.cxx
+++ b/sw/source/core/unocore/unobkm.cxx
@@ -104,6 +104,8 @@ void SwXBookmark::Impl::registerInMark(SwXBookmark& rThis,
         {
             pMarkBase->SetXBookmark(xBookmark);
         }
+        assert(m_pDoc == nullptr || m_pDoc == pBkmk->GetMarkPos().GetDoc());
+        m_pDoc = pBkmk->GetMarkPos().GetDoc();
     }
     else if (m_pRegisteredBookmark)
     {


More information about the Libreoffice-commits mailing list