diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2014-10-30 11:59:17 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2014-10-30 12:14:31 +0100 |
commit | cb46aaf2d7240dfe3ac080fe086a9f70c4c91ab5 (patch) | |
tree | 0ef75047276a0dd633ea1279396addf07f9bd3e7 /sw | |
parent | 3f9872185efb1c5cf2362288f440971137df3c58 (diff) |
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
Diffstat (limited to 'sw')
-rw-r--r-- | sw/source/core/unocore/unoportenum.cxx | 131 |
1 files changed, 81 insertions, 50 deletions
diff --git a/sw/source/core/unocore/unoportenum.cxx b/sw/source/core/unocore/unoportenum.cxx index 7f70bc55f48a..e079b9cc75a5 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); } } } |