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

Michael Stahl (via logerrit) logerrit at kemper.freedesktop.org
Thu Jan 30 13:19:37 UTC 2020


 sw/source/core/inc/scriptinfo.hxx            |   11 +
 sw/source/core/text/porlay.cxx               |  225 ++++++++++++++++++++++++++-
 sw/source/core/txtnode/modeltoviewhelper.cxx |    2 
 3 files changed, 228 insertions(+), 10 deletions(-)

New commits:
commit 46e04a712e97f9095ef4da7f0e52f50cf2bfbb32
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Wed Jan 22 15:18:19 2020 +0100
Commit:     Michael Stahl <michael.stahl at cib.de>
CommitDate: Thu Jan 30 14:18:59 2020 +0100

    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 at cib.de>

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);


More information about the Libreoffice-commits mailing list