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

Miklos Vajna vmiklos at collabora.co.uk
Thu Oct 30 04:15:35 PDT 2014


 sw/inc/index.hxx                       |   14 +++
 sw/source/core/bastyp/index.cxx        |    8 ++
 sw/source/core/crsr/bookmrk.cxx        |    3 
 sw/source/core/unocore/unoportenum.cxx |  131 ++++++++++++++++++++-------------
 4 files changed, 106 insertions(+), 50 deletions(-)

New commits:
commit cb46aaf2d7240dfe3ac080fe086a9f70c4c91ab5
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Thu Oct 30 11:59:17 2014 +0100

    sw: use new bookmark API in lcl_FillBookmarkArray() for text nodes
    
    For a document of 1000 pages and having 13000 bookmarks, this helps a
    lot on ODF export: 2m51.565s -> 2m23.412s on my machine.
    
    Change-Id: I8c8a7cd2b83a94ab7f2de17e0b4cb449fc4c0e1a

diff --git a/sw/source/core/unocore/unoportenum.cxx b/sw/source/core/unocore/unoportenum.cxx
index 7f70bc5..e079b9c 100644
--- a/sw/source/core/unocore/unoportenum.cxx
+++ b/sw/source/core/unocore/unoportenum.cxx
@@ -131,67 +131,98 @@ namespace
     };
     typedef std::multiset < SwXBookmarkPortion_ImplSharedPtr, BookmarkCompareStruct > SwXBookmarkPortion_ImplList;
 
-    static void lcl_FillBookmarkArray(SwDoc& rDoc, SwUnoCrsr& rUnoCrsr, SwXBookmarkPortion_ImplList& rBkmArr)
+    /// Inserts pBkmk to rBkmArr in case it starts or ends at nOwnNode
+    static void lcl_FillBookmark(sw::mark::IMark* const pBkmk, const SwNodeIndex& nOwnNode, SwDoc& rDoc, SwXBookmarkPortion_ImplList& rBkmArr)
     {
-        IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess();
-        if(!pMarkAccess->getBookmarksCount())
-            return;
-
-        // no need to consider marks starting after aEndOfPara
-        SwPosition aEndOfPara(*rUnoCrsr.GetPoint());
-        aEndOfPara.nContent = aEndOfPara.nNode.GetNode().GetTxtNode()->Len();
-        const IDocumentMarkAccess::const_iterator_t pCandidatesEnd = upper_bound(
-            pMarkAccess->getBookmarksBegin(),
-            pMarkAccess->getBookmarksEnd(),
-            aEndOfPara,
-            sw::mark::CompareIMarkStartsAfter()); // finds the first that starts after
+        bool const hasOther = pBkmk->IsExpanded();
 
-        // search for all bookmarks that start or end in this paragraph
-        const SwNodeIndex nOwnNode = rUnoCrsr.GetPoint()->nNode;
-        for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getBookmarksBegin();
-            ppMark != pCandidatesEnd;
-            ++ppMark)
+        const SwPosition& rStartPos = pBkmk->GetMarkStart();
+        if(rStartPos.nNode == nOwnNode)
         {
-            ::sw::mark::IMark* const pBkmk = ppMark->get();
-            bool const hasOther = pBkmk->IsExpanded();
+            // #i109272#: cross reference marks: need special handling!
+            ::sw::mark::CrossRefBookmark *const pCrossRefMark(dynamic_cast< ::sw::mark::CrossRefBookmark*>(pBkmk));
+            sal_uInt8 const nType = (hasOther || pCrossRefMark)
+                ? BKM_TYPE_START : BKM_TYPE_START_END;
+            rBkmArr.insert(SwXBookmarkPortion_ImplSharedPtr(
+                new SwXBookmarkPortion_Impl(
+                        SwXBookmark::CreateXBookmark(rDoc, pBkmk),
+                        nType, rStartPos)));
+        }
 
-            const SwPosition& rStartPos = pBkmk->GetMarkStart();
-            if(rStartPos.nNode == nOwnNode)
+        const SwPosition& rEndPos = pBkmk->GetMarkEnd();
+        if(rEndPos.nNode == nOwnNode)
+        {
+            unique_ptr<SwPosition> pCrossRefEndPos;
+            const SwPosition* pEndPos = NULL;
+            ::sw::mark::CrossRefBookmark *const pCrossRefMark(dynamic_cast< ::sw::mark::CrossRefBookmark*>(pBkmk));
+            if(hasOther)
+            {
+                pEndPos = &rEndPos;
+            }
+            else if (pCrossRefMark)
+            {
+                // Crossrefbookmarks only remember the start position but have to span the whole paragraph
+                pCrossRefEndPos = unique_ptr<SwPosition>(new SwPosition(rEndPos));
+                pCrossRefEndPos->nContent = pCrossRefEndPos->nNode.GetNode().GetTxtNode()->Len();
+                pEndPos = pCrossRefEndPos.get();
+            }
+            if(pEndPos)
             {
-                // #i109272#: cross reference marks: need special handling!
-                ::sw::mark::CrossRefBookmark *const pCrossRefMark(dynamic_cast< ::sw::mark::CrossRefBookmark*>(pBkmk));
-                sal_uInt8 const nType = (hasOther || pCrossRefMark)
-                    ? BKM_TYPE_START : BKM_TYPE_START_END;
                 rBkmArr.insert(SwXBookmarkPortion_ImplSharedPtr(
                     new SwXBookmarkPortion_Impl(
                             SwXBookmark::CreateXBookmark(rDoc, pBkmk),
-                            nType, rStartPos)));
+                            BKM_TYPE_END, *pEndPos)));
             }
+        }
+    }
 
-            const SwPosition& rEndPos = pBkmk->GetMarkEnd();
-            if(rEndPos.nNode == nOwnNode)
+    static void lcl_FillBookmarkArray(SwDoc& rDoc, SwUnoCrsr& rUnoCrsr, SwXBookmarkPortion_ImplList& rBkmArr)
+    {
+        IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess();
+        if(!pMarkAccess->getBookmarksCount())
+            return;
+
+        const SwNodeIndex nOwnNode = rUnoCrsr.GetPoint()->nNode;
+        SwTxtNode* pTxtNode = nOwnNode.GetNode().GetTxtNode();
+        if (!pTxtNode)
+        {
+            // no need to consider marks starting after aEndOfPara
+            SwPosition aEndOfPara(*rUnoCrsr.GetPoint());
+            aEndOfPara.nContent = aEndOfPara.nNode.GetNode().GetTxtNode()->Len();
+            const IDocumentMarkAccess::const_iterator_t pCandidatesEnd = upper_bound(
+                pMarkAccess->getBookmarksBegin(),
+                pMarkAccess->getBookmarksEnd(),
+                aEndOfPara,
+                sw::mark::CompareIMarkStartsAfter()); // finds the first that starts after
+
+            // search for all bookmarks that start or end in this paragraph
+            for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getBookmarksBegin();
+                ppMark != pCandidatesEnd;
+                ++ppMark)
             {
-                unique_ptr<SwPosition> pCrossRefEndPos;
-                const SwPosition* pEndPos = NULL;
-                ::sw::mark::CrossRefBookmark *const pCrossRefMark(dynamic_cast< ::sw::mark::CrossRefBookmark*>(pBkmk));
-                if(hasOther)
-                {
-                    pEndPos = &rEndPos;
-                }
-                else if (pCrossRefMark)
-                {
-                    // Crossrefbookmarks only remember the start position but have to span the whole paragraph
-                    pCrossRefEndPos = unique_ptr<SwPosition>(new SwPosition(rEndPos));
-                    pCrossRefEndPos->nContent = pCrossRefEndPos->nNode.GetNode().GetTxtNode()->Len();
-                    pEndPos = pCrossRefEndPos.get();
-                }
-                if(pEndPos)
-                {
-                    rBkmArr.insert(SwXBookmarkPortion_ImplSharedPtr(
-                        new SwXBookmarkPortion_Impl(
-                                SwXBookmark::CreateXBookmark(rDoc, pBkmk),
-                                BKM_TYPE_END, *pEndPos)));
-                }
+                ::sw::mark::IMark* const pBkmk = ppMark->get();
+                lcl_FillBookmark(pBkmk, nOwnNode, rDoc, rBkmArr);
+            }
+        }
+        else
+        {
+            // A text node already knows its marks via its SwIndexes.
+            std::set<sw::mark::IMark*> aSeenMarks;
+            for (const SwIndex* pIndex = pTxtNode->GetFirstIndex(); pIndex; pIndex = pIndex->GetNext())
+            {
+                // Need a non-cost mark here, as we'll create an UNO wrapper around it.
+                sw::mark::IMark* pBkmk = const_cast<sw::mark::IMark*>(pIndex->GetMark());
+                if (!pBkmk)
+                    continue;
+                IDocumentMarkAccess::MarkType eType = pMarkAccess->GetType(*pBkmk);
+                // These are the types stored in the container otherwise accessible via getBookmarks*()
+                if (eType != IDocumentMarkAccess::BOOKMARK && eType != IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK && eType != IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK)
+                    continue;
+                // Only handle bookmarks once, if they start and end at this node as well.
+                if (aSeenMarks.find(pBkmk) != aSeenMarks.end())
+                    continue;
+                aSeenMarks.insert(pBkmk);
+                lcl_FillBookmark(pBkmk, nOwnNode, rDoc, rBkmArr);
             }
         }
     }
commit 3f9872185efb1c5cf2362288f440971137df3c58
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Thu Oct 30 11:06:52 2014 +0100

    sw: add API that provides fast access to marks of a text node
    
    sw::mark::MarkManager already provides two methods to provide not so slow mark
    access:
    
    - some marks (bookmarks, annotation marks) have their own container, so it's
      possible to iterate over only those types, not all of them
    - the containers are sorted by the start position of the marks, so it's easy to
      ignore marks that are after the current text node
    
    However, it's not possible to ignore marks ending before the current text node.
    This is a problem, as e.g. during ODF export, we have to iterate over every
    bookmark for each paragraph, so the operation is not linear.
    
    On the other hand, the start and end position of bookmarks are stored using
    SwPosition, and the SwIndex of the SwPosition is already registered in the
    SwIndexReg of the SwTxtNode, so the text node sort of already knows what
    bookmarks start/end at the current paragraph, it just doesn't known which
    position belongs to what mark (if it belongs to a mark).
    
    Fix the problem by adding a pointer to SwIndex that can optionally point back
    to the mark that owns it. Also, in the sw::mark::MarkBase methods (which are
    the only ones allowed to touch those positions) always set that pointer. With
    this, it's possible to get the bookmarks of a node (list of bookmarks which
    start or end in the current node) in a much faster way for text nodes.
    
    Change-Id: I7ceeff4dce852b4d72f2a73ae6a2423c7a781e41

diff --git a/sw/inc/index.hxx b/sw/inc/index.hxx
index 9f9c600..e364853 100644
--- a/sw/inc/index.hxx
+++ b/sw/inc/index.hxx
@@ -26,6 +26,12 @@
 class SwIndexReg;
 struct SwPosition;
 
+namespace sw {
+namespace mark {
+class IMark;
+}
+}
+
 /// Marks a character position inside a document model node.
 class SW_DLLPUBLIC SwIndex
 {
@@ -38,6 +44,9 @@ private:
     SwIndex * m_pNext;
     SwIndex * m_pPrev;
 
+    /// Pointer to a mark that owns this position to allow fast lookup of marks of an SwIndexReg.
+    const sw::mark::IMark* m_pMark;
+
     SwIndex& ChgValue( const SwIndex& rIdx, sal_Int32 nNewValue );
     void Init(sal_Int32 const nIdx);
     void Remove();
@@ -92,6 +101,10 @@ public:
 
     // Returns pointer to IndexArray (for RTTI at SwIndexReg).
     const SwIndexReg* GetIdxReg() const { return m_pIndexReg; }
+    const SwIndex* GetNext() const { return m_pNext; }
+
+    const sw::mark::IMark* GetMark() const { return m_pMark; }
+    void SetMark(const sw::mark::IMark* pMark);
 };
 
 class SwIndexReg
@@ -119,6 +132,7 @@ public:
     TYPEINFO();
 
     void MoveTo( SwIndexReg& rArr );
+    const SwIndex* GetFirstIndex() const { return m_pFirst; }
 };
 
 #ifndef DBG_UTIL
diff --git a/sw/source/core/bastyp/index.cxx b/sw/source/core/bastyp/index.cxx
index cdf89e1..b6f7632 100644
--- a/sw/source/core/bastyp/index.cxx
+++ b/sw/source/core/bastyp/index.cxx
@@ -29,6 +29,7 @@ SwIndex::SwIndex(SwIndexReg *const pReg, sal_Int32 const nIdx)
     , m_pIndexReg( pReg )
     , m_pNext( 0 )
     , m_pPrev( 0 )
+    , m_pMark( 0 )
 {
     Init(m_nIndex);
 }
@@ -37,6 +38,7 @@ SwIndex::SwIndex( const SwIndex& rIdx, short nDiff )
     : m_pIndexReg( rIdx.m_pIndexReg )
     , m_pNext( 0 )
     , m_pPrev( 0 )
+    , m_pMark( 0 )
 {
     ChgValue( rIdx, rIdx.m_nIndex + nDiff );
 }
@@ -46,6 +48,7 @@ SwIndex::SwIndex( const SwIndex& rIdx )
     , m_pIndexReg( rIdx.m_pIndexReg )
     , m_pNext( 0 )
     , m_pPrev( 0 )
+    , m_pMark( 0 )
 {
     ChgValue( rIdx, rIdx.m_nIndex );
 }
@@ -207,6 +210,11 @@ SwIndex& SwIndex::Assign( SwIndexReg* pArr, sal_Int32 nIdx )
     return *this;
 }
 
+void SwIndex::SetMark(const sw::mark::IMark* pMark)
+{
+    m_pMark = pMark;
+}
+
 SwIndexReg::SwIndexReg()
     : m_pFirst( 0 ), m_pLast( 0 )
 {
diff --git a/sw/source/core/crsr/bookmrk.cxx b/sw/source/core/crsr/bookmrk.cxx
index 588283e..ed487f7 100644
--- a/sw/source/core/crsr/bookmrk.cxx
+++ b/sw/source/core/crsr/bookmrk.cxx
@@ -137,6 +137,7 @@ namespace sw { namespace mark
         , m_pPos1(new SwPosition(*(aPaM.GetPoint())))
         , m_aName(rName)
     {
+        m_pPos1->nContent.SetMark(this);
         lcl_FixPosition(*m_pPos1);
         if (aPaM.HasMark() && (*aPaM.GetMark() != *aPaM.GetPoint()))
         {
@@ -156,11 +157,13 @@ namespace sw { namespace mark
     void MarkBase::SetMarkPos(const SwPosition& rNewPos)
     {
         ::boost::scoped_ptr<SwPosition>(new SwPosition(rNewPos)).swap(m_pPos1);
+        m_pPos1->nContent.SetMark(this);
     }
 
     void MarkBase::SetOtherMarkPos(const SwPosition& rNewPos)
     {
         ::boost::scoped_ptr<SwPosition>(new SwPosition(rNewPos)).swap(m_pPos2);
+        m_pPos2->nContent.SetMark(this);
     }
 
     OUString MarkBase::ToString( ) const


More information about the Libreoffice-commits mailing list