summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2014-10-30 11:59:17 +0100
committerMiklos Vajna <vmiklos@collabora.co.uk>2014-10-30 12:14:31 +0100
commitcb46aaf2d7240dfe3ac080fe086a9f70c4c91ab5 (patch)
tree0ef75047276a0dd633ea1279396addf07f9bd3e7
parent3f9872185efb1c5cf2362288f440971137df3c58 (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
-rw-r--r--sw/source/core/unocore/unoportenum.cxx131
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);
}
}
}