diff options
author | Michael Stahl <Michael.Stahl@cib.de> | 2020-01-22 15:18:19 +0100 |
---|---|---|
committer | Michael Stahl <michael.stahl@cib.de> | 2020-01-30 14:18:59 +0100 |
commit | 46e04a712e97f9095ef4da7f0e52f50cf2bfbb32 (patch) | |
tree | 7945d87699b3441d06737d9c4023ebfa624047f4 | |
parent | ef8427d12a63127a2eb867637699343d630545dd (diff) |
tdf#45589 sw: add bookmarks to SwScriptInfo
Add a list of bookmark positions in the text frame to SwScriptInfo.
Initialising this turned out to be more complicated than expected.
Change-Id: I1738186b057b0eece80177097a03826365107589
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/87202
Tested-by: Jenkins
Reviewed-by: Michael Stahl <michael.stahl@cib.de>
-rw-r--r-- | sw/source/core/inc/scriptinfo.hxx | 11 | ||||
-rw-r--r-- | sw/source/core/text/porlay.cxx | 225 | ||||
-rw-r--r-- | sw/source/core/txtnode/modeltoviewhelper.cxx | 2 |
3 files changed, 228 insertions, 10 deletions
diff --git a/sw/source/core/inc/scriptinfo.hxx b/sw/source/core/inc/scriptinfo.hxx index 31ff4a8a7e86..e70ded7166b0 100644 --- a/sw/source/core/inc/scriptinfo.hxx +++ b/sw/source/core/inc/scriptinfo.hxx @@ -33,6 +33,7 @@ class Point; class MultiSelection; enum class SwFontScript; namespace sw { struct MergedPara; } +namespace sw::mark { class IBookmark; } #define SPACING_PRECISION_FACTOR 100 @@ -41,6 +42,7 @@ class SwScriptInfo { public: enum CompType { KANA, SPECIAL_LEFT, SPECIAL_RIGHT, NONE, SPECIAL_MIDDLE}; + enum class MarkKind { Start, End, Point }; private: //! Records a single change in script type. @@ -67,6 +69,7 @@ private: std::deque<TextFrameIndex> m_NoKashidaLine; std::deque<TextFrameIndex> m_NoKashidaLineEnd; std::vector<TextFrameIndex> m_HiddenChg; + std::vector<std::pair<TextFrameIndex, MarkKind>> m_Bookmarks; //! Records a single change in compression. struct CompressionChangeInfo { @@ -178,8 +181,12 @@ public: return m_HiddenChg[ nCnt ]; } TextFrameIndex NextHiddenChg(TextFrameIndex nPos) const; - static void CalcHiddenRanges(const SwTextNode& rNode, MultiSelection& rHiddenMulti); - static void selectHiddenTextProperty(const SwTextNode& rNode, MultiSelection &rHiddenMulti); + static void CalcHiddenRanges(const SwTextNode& rNode, + MultiSelection& rHiddenMulti, + std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> * pBookmarks); + static void selectHiddenTextProperty(const SwTextNode& rNode, + MultiSelection &rHiddenMulti, + std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> * pBookmarks); static void selectRedLineDeleted(const SwTextNode& rNode, MultiSelection &rHiddenMulti, bool bSelect=true); // "high" level operations, nPos refers to string position diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx index f0fcbb1a48dd..b6f70e7da060 100644 --- a/sw/source/core/text/porlay.cxx +++ b/sw/source/core/text/porlay.cxx @@ -35,6 +35,7 @@ #include <com/sun/star/i18n/XBreakIterator.hpp> #include <paratr.hxx> #include <sal/log.hxx> +#include <o3tl/optional.hxx> #include <editeng/adjustitem.hxx> #include <editeng/charhiddenitem.hxx> #include <svl/asiancfg.hxx> @@ -727,6 +728,173 @@ SwFontScript SwScriptInfo::WhichFont(sal_Int32 nIdx, OUString const& rText) return lcl_ScriptToFont(nScript); } +static void InitBookmarks( + o3tl::optional<std::vector<sw::Extent>::const_iterator> oPrevIter, + std::vector<sw::Extent>::const_iterator iter, + std::vector<sw::Extent>::const_iterator const end, + TextFrameIndex nOffset, + std::vector<std::pair<sw::mark::IBookmark const*, SwScriptInfo::MarkKind>> & rBookmarks, + std::vector<std::pair<TextFrameIndex, SwScriptInfo::MarkKind>> & o_rBookmarks) +{ + SwTextNode const*const pNode(iter->pNode); + for (auto const& it : rBookmarks) + { + assert(iter->pNode == pNode || pNode->GetIndex() < iter->pNode->GetIndex()); + assert(!oPrevIter || (*oPrevIter)->pNode->GetIndex() <= pNode->GetIndex()); + switch (it.second) + { + case SwScriptInfo::MarkKind::Start: + { + // SwUndoSaveContent::DelContentIndex() is rather messy but + // apparently bookmarks "on the edge" are deleted if + // * point: equals start-of-selection (not end-of-selection) + // * expanded: one position equals edge of selection + // and other does not (is inside) + // interesting case: if end[/start] of the mark is on the + // start of first[/end of last] extent, and the other one + // is outside this merged paragraph, is it deleted or not? + // assume "no" because the line break it contains isn't deleted. + SwPosition const& rStart(it.first->GetMarkStart()); + SwPosition const& rEnd(it.first->GetMarkEnd()); + assert(&rStart.nNode.GetNode() == pNode); + while (iter != end) + { + if (&rStart.nNode.GetNode() != iter->pNode // iter moved to next node + || rStart.nContent.GetIndex() < iter->nStart) + { + if (rEnd.nNode.GetIndex() < iter->pNode->GetIndex() + || (&rEnd.nNode.GetNode() == iter->pNode && rEnd.nContent.GetIndex() <= iter->nStart)) + { + break; // deleted - skip it + } + else + { + o_rBookmarks.emplace_back(nOffset, it.second); + break; + } + } + else if (rStart.nContent.GetIndex() <= iter->nEnd) + { + auto const iterNext(iter + 1); + if (rStart.nContent.GetIndex() == iter->nEnd + && (iterNext == end + ? &rEnd.nNode.GetNode() == iter->pNode + : (rEnd.nNode.GetIndex() < iterNext->pNode->GetIndex() + || (&rEnd.nNode.GetNode() == iterNext->pNode && rEnd.nContent.GetIndex() < iterNext->nStart)))) + { + break; // deleted - skip it + } + else + { + o_rBookmarks.emplace_back( + nOffset + TextFrameIndex(rStart.nContent.GetIndex() - iter->nStart), + it.second); + break; + } + } + else + { + nOffset += TextFrameIndex(iter->nEnd - iter->nStart); + oPrevIter = iter; + ++iter; // bookmarks are sorted... + } + } + if (iter == end) + { + if (pNode->GetIndex() < rEnd.nNode.GetIndex()) // pNode is last node of merged + { + break; // deleted - skip it + } + else + { + o_rBookmarks.emplace_back(nOffset, it.second); + } + } + break; + } + case SwScriptInfo::MarkKind::End: + { + SwPosition const& rEnd(it.first->GetMarkEnd()); + assert(&rEnd.nNode.GetNode() == pNode); + while (true) + { + if (iter == end + || &rEnd.nNode.GetNode() != iter->pNode // iter moved to next node + || rEnd.nContent.GetIndex() <= iter->nStart) + { + SwPosition const& rStart(it.first->GetMarkStart()); + // oPrevIter may point to pNode or a preceding node + if (oPrevIter + ? ((*oPrevIter)->pNode->GetIndex() < rStart.nNode.GetIndex() + || ((*oPrevIter)->pNode == &rStart.nNode.GetNode() + && ((iter != end && &rEnd.nNode.GetNode() == iter->pNode && rEnd.nContent.GetIndex() == iter->nStart) + ? (*oPrevIter)->nEnd < rStart.nContent.GetIndex() + : (*oPrevIter)->nEnd <= rStart.nContent.GetIndex()))) + : rStart.nNode == rEnd.nNode) + { + break; // deleted - skip it + } + else + { + o_rBookmarks.emplace_back(nOffset, it.second); + break; + } + } + else if (rEnd.nContent.GetIndex() <= iter->nEnd) + { + o_rBookmarks.emplace_back( + nOffset + TextFrameIndex(rEnd.nContent.GetIndex() - iter->nStart), + it.second); + break; + } + else + { + nOffset += TextFrameIndex(iter->nEnd - iter->nStart); + oPrevIter = iter; + ++iter; + } + } + break; + } + case SwScriptInfo::MarkKind::Point: + { + SwPosition const& rPos(it.first->GetMarkPos()); + assert(&rPos.nNode.GetNode() == pNode); + while (iter != end) + { + if (&rPos.nNode.GetNode() != iter->pNode // iter moved to next node + || rPos.nContent.GetIndex() < iter->nStart) + { + break; // deleted - skip it + } + else if (rPos.nContent.GetIndex() <= iter->nEnd) + { + if (rPos.nContent.GetIndex() == iter->nEnd + && rPos.nContent.GetIndex() != iter->pNode->Len()) + { + break; // deleted - skip it + } + else + { + o_rBookmarks.emplace_back( + nOffset + TextFrameIndex(rPos.nContent.GetIndex() - iter->nStart), + it.second); + } + break; + } + else + { + nOffset += TextFrameIndex(iter->nEnd - iter->nStart); + oPrevIter = iter; + ++iter; + } + } + break; + } + } + } +} + // searches for script changes in rText and stores them void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode, sw::MergedPara const*const pMerged) @@ -743,12 +911,15 @@ void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode, // HIDDEN TEXT INFORMATION + m_Bookmarks.clear(); m_HiddenChg.clear(); if (pMerged) { SwTextNode const* pNode(nullptr); TextFrameIndex nOffset(0); - for (auto iter = pMerged->extents.begin(); iter != pMerged->extents.end(); ++iter) + o3tl::optional<std::vector<sw::Extent>::const_iterator> oPrevIter; + for (auto iter = pMerged->extents.begin(); iter != pMerged->extents.end(); + oPrevIter = iter, ++iter) { if (iter->pNode == pNode) { @@ -758,7 +929,10 @@ void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode, pNode = iter->pNode; Range aRange( 0, pNode->Len() > 0 ? pNode->Len() - 1 : 0 ); MultiSelection aHiddenMulti( aRange ); - CalcHiddenRanges( *pNode, aHiddenMulti ); + std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> bookmarks; + CalcHiddenRanges(*pNode, aHiddenMulti, &bookmarks); + + InitBookmarks(oPrevIter, iter, pMerged->extents.end(), nOffset, bookmarks, m_Bookmarks); for (sal_Int32 i = 0; i < aHiddenMulti.GetRangeCount(); ++i) { @@ -804,7 +978,24 @@ void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode, { Range aRange( 0, !rText.isEmpty() ? rText.getLength() - 1 : 0 ); MultiSelection aHiddenMulti( aRange ); - CalcHiddenRanges( rNode, aHiddenMulti ); + std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> bookmarks; + CalcHiddenRanges(rNode, aHiddenMulti, &bookmarks); + + for (auto const& it : bookmarks) + { + switch (it.second) + { + case MarkKind::Start: + m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkStart().nContent.GetIndex()), it.second); + break; + case MarkKind::End: + m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkEnd().nContent.GetIndex()), it.second); + break; + case MarkKind::Point: + m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkPos().nContent.GetIndex()), it.second); + break; + } + } for (sal_Int32 i = 0; i < aHiddenMulti.GetRangeCount(); ++i) { @@ -1593,7 +1784,7 @@ bool SwScriptInfo::GetBoundsOfHiddenRange( const SwTextNode& rNode, sal_Int32 nP ? rNode.GetText().getLength() - 1 : 0); MultiSelection aHiddenMulti( aRange ); - SwScriptInfo::CalcHiddenRanges( rNode, aHiddenMulti ); + SwScriptInfo::CalcHiddenRanges(rNode, aHiddenMulti, nullptr); for( sal_Int32 i = 0; i < aHiddenMulti.GetRangeCount(); ++i ) { const Range& rRange = aHiddenMulti.GetRange( i ); @@ -2240,7 +2431,9 @@ SwTwips SwTextFrame::HangingMargin() const return nRet; } -void SwScriptInfo::selectHiddenTextProperty(const SwTextNode& rNode, MultiSelection &rHiddenMulti) +void SwScriptInfo::selectHiddenTextProperty(const SwTextNode& rNode, + MultiSelection & rHiddenMulti, + std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> *const pBookmarks) { assert((rNode.GetText().isEmpty() && rHiddenMulti.GetTotalRange().Len() == 1) || (rNode.GetText().getLength() == rHiddenMulti.GetTotalRange().Len())); @@ -2277,6 +2470,22 @@ void SwScriptInfo::selectHiddenTextProperty(const SwTextNode& rNode, MultiSelect { const sw::mark::IMark* pMark = pIndex->GetMark(); const sw::mark::IBookmark* pBookmark = dynamic_cast<const sw::mark::IBookmark*>(pMark); + if (pBookmarks && pBookmark) + { + if (!pBookmark->IsExpanded()) + { + pBookmarks->emplace_back(pBookmark, MarkKind::Point); + } + else if (pIndex == &pBookmark->GetMarkStart().nContent) + { + pBookmarks->emplace_back(pBookmark, MarkKind::Start); + } + else + { + assert(pIndex == &pBookmark->GetMarkEnd().nContent); + pBookmarks->emplace_back(pBookmark, MarkKind::End); + } + } if (pBookmark && pBookmark->IsHidden()) { // intersect bookmark range with textnode range and add the intersection to rHiddenMulti @@ -2328,9 +2537,11 @@ void SwScriptInfo::selectRedLineDeleted(const SwTextNode& rNode, MultiSelection } // Returns a MultiSection indicating the hidden ranges. -void SwScriptInfo::CalcHiddenRanges( const SwTextNode& rNode, MultiSelection& rHiddenMulti ) +void SwScriptInfo::CalcHiddenRanges( const SwTextNode& rNode, + MultiSelection & rHiddenMulti, + std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> *const pBookmarks) { - selectHiddenTextProperty(rNode, rHiddenMulti); + selectHiddenTextProperty(rNode, rHiddenMulti, pBookmarks); // If there are any hidden ranges in the current text node, we have // to unhide the redlining ranges: diff --git a/sw/source/core/txtnode/modeltoviewhelper.cxx b/sw/source/core/txtnode/modeltoviewhelper.cxx index c8c9726c9a6c..f7be7f8a98bb 100644 --- a/sw/source/core/txtnode/modeltoviewhelper.cxx +++ b/sw/source/core/txtnode/modeltoviewhelper.cxx @@ -101,7 +101,7 @@ ModelToViewHelper::ModelToViewHelper(const SwTextNode &rNode, MultiSelection aHiddenMulti(aRange); if (eMode & ExpandMode::HideInvisible) - SwScriptInfo::selectHiddenTextProperty(rNode, aHiddenMulti); + SwScriptInfo::selectHiddenTextProperty(rNode, aHiddenMulti, nullptr); if (eMode & ExpandMode::HideDeletions) SwScriptInfo::selectRedLineDeleted(rNode, aHiddenMulti); |