Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sw/inc/pam.hxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
#ifndef INCLUDED_SW_INC_PAM_HXX
20
#define INCLUDED_SW_INC_PAM_HXX
21
22
#include <sal/types.h>
23
#include "ring.hxx"
24
#include "contentindex.hxx"
25
#include "ndindex.hxx"
26
#include "swdllapi.h"
27
#include "nodeoffset.hxx"
28
29
#include <iostream>
30
#include <utility>
31
32
class SwDoc;
33
class SwPaM;
34
class Point;
35
36
/// Marks a position in the document model.
37
struct SAL_WARN_UNUSED SW_DLLPUBLIC SwPosition
38
{
39
    SwNodeIndex nNode;
40
    SwContentIndex nContent;
41
42
    SwPosition( const SwNodeIndex &rNode, const SwContentIndex &rContent );
43
    SwPosition( const SwNode &rNode, const SwContentIndex &rContent );
44
    explicit SwPosition( const SwNodes& rNodes, SwNodeOffset nIndex = SwNodeOffset(0) );
45
    explicit SwPosition( const SwNodeIndex &rNode, SwNodeOffset nDiff = SwNodeOffset(0) );
46
    explicit SwPosition( const SwNode& rNode, SwNodeOffset nDiff = SwNodeOffset(0) );
47
    explicit SwPosition( const SwContentNode& rNode, sal_Int32 nContentOffset = 0 );
48
    SwPosition( const SwNodeIndex &rNode, const SwContentNode*, sal_Int32 nContentOffset );
49
    SwPosition( const SwNode &rNode, const SwContentNode*, sal_Int32 nContentOffset );
50
    SwPosition( const SwNodeIndex &rNode, SwNodeOffset nDiff, const SwContentNode*, sal_Int32 nContentOffset );
51
    SwPosition( const SwNode &rNode, SwNodeOffset nDiff, const SwContentNode*, sal_Int32 nContentOffset );
52
    SwPosition( const SwContentIndex &, short nDiff );
53
54
    // callers should be using one of the other constructors to avoid creating a temporary
55
    SwPosition( SwNodeIndex && ) = delete;
56
    SwPosition( const SwNodeIndex &, SwContentIndex && ) = delete;
57
    SwPosition( SwNodeIndex &&, SwContentIndex && ) = delete;
58
    SwPosition( SwNodeIndex &&, const SwContentNode*, sal_Int32 ) = delete;
59
    SwPosition( SwNodeIndex &&, SwNodeOffset ) = delete;
60
    SwPosition( SwContentIndex &&, short ) = delete;
61
62
    /**
63
       Returns the document this position is in.
64
65
       @return the document this position is in.
66
    */
67
    SwDoc& GetDoc() const;
68
69
    bool operator < (const SwPosition &) const;
70
    bool operator > (const SwPosition &) const;
71
    bool operator <=(const SwPosition &) const;
72
    bool operator >=(const SwPosition &) const;
73
    bool operator ==(const SwPosition &) const;
74
    bool operator !=(const SwPosition &) const;
75
    void dumpAsXml(xmlTextWriterPtr pWriter) const;
76
77
78
174M
    SwNodeOffset GetNodeIndex() const { return nNode.GetIndex(); }
79
3.51M
    const SwNodes& GetNodes() const { return nNode.GetNodes(); }
80
1.59M
    SwNodes& GetNodes() { return nNode.GetNodes(); }
81
417M
    SwNode& GetNode() const { return nNode.GetNode(); }
82
83
84
75.1M
    const SwContentNode* GetContentNode() const { return nContent.GetContentNode(); }
85
268M
    sal_Int32 GetContentIndex() const { return nContent.GetIndex(); }
86
1.99M
    void SetOwner(ISwContentIndexOwner* pOwner) { nContent.SetOwner(pOwner); }
87
88
    /// These all set both nNode and nContent
89
    void Assign( const SwNode& rNd, SwNodeOffset nDelta, sal_Int32 nContentOffset = 0 );
90
    void Assign( SwNodeOffset nNodeOffset, sal_Int32 nContentOffset = 0 );
91
    void Assign( const SwContentNode& rNode, sal_Int32 nContentOffset = 0 );
92
    void Assign( const SwNode& rNd, sal_Int32 nContentOffset = 0 );
93
    void Assign( const SwNodeIndex& rNdIdx, sal_Int32 nContentOffset = 0 );
94
    /// Set nNode to rNd, and nContent to the beginning of rNd
95
    void AssignStartIndex( const SwContentNode& rNd );
96
    /// Set nNode to rNd, and nContent to the end of rNd
97
    void AssignEndIndex( const SwContentNode& rNd );
98
    /// Adjust node position, and resets content position to zero
99
    void Adjust( SwNodeOffset nDelta );
100
    /// Adjust content index, only valid to call this if the position points to a SwContentNode subclass
101
    void AdjustContent( sal_Int32 nDelta );
102
    /// Set content index, only valid to call this if the position points to a SwContentNode subclass
103
    void SetContent( sal_Int32 nContentIndex );
104
};
105
106
SW_DLLPUBLIC std::ostream &operator <<(std::ostream& s, const SwPosition& position);
107
108
// Result of comparing positions.
109
enum class SwComparePosition {
110
    Before,             ///< Pos1 before Pos2.
111
    Behind,             ///< Pos1 behind Pos2.
112
    Inside,             ///< Pos1 completely contained in Pos2.
113
    Outside,            ///< Pos2 completely contained in Pos1.
114
    Equal,              ///< Pos1 is as large as Pos2.
115
    OverlapBefore,      ///< Pos1 overlaps Pos2 at the beginning.
116
    OverlapBehind,      ///< Pos1 overlaps Pos2 at the end.
117
    CollideStart,       ///< Pos1 start touches at Pos2 end.
118
    CollideEnd          ///< Pos1 end touches at Pos2 start.
119
};
120
121
template<typename T>
122
SwComparePosition ComparePosition(
123
            const T& rStt1, const T& rEnd1,
124
            const T& rStt2, const T& rEnd2 )
125
884k
{
126
884k
    SwComparePosition nRet;
127
884k
    if( rStt1 < rStt2 )
128
67.2k
    {
129
67.2k
        if( rEnd1 > rStt2 )
130
8.03k
        {
131
8.03k
            if( rEnd1 >= rEnd2 )
132
5.15k
                nRet = SwComparePosition::Outside;
133
2.88k
            else
134
2.88k
                nRet = SwComparePosition::OverlapBefore;
135
136
8.03k
        }
137
59.2k
        else if( rEnd1 == rStt2 )
138
33.3k
            nRet = SwComparePosition::CollideEnd;
139
25.8k
        else
140
25.8k
            nRet = SwComparePosition::Before;
141
67.2k
    }
142
816k
    else if( rEnd2 > rStt1 )
143
330k
    {
144
330k
        if( rEnd2 >= rEnd1 )
145
313k
        {
146
313k
            if( rEnd2 == rEnd1 && rStt2 == rStt1 )
147
215k
                nRet = SwComparePosition::Equal;
148
98.0k
            else
149
98.0k
                nRet = SwComparePosition::Inside;
150
313k
        }
151
16.9k
        else
152
16.9k
        {
153
16.9k
            if (rStt1 == rStt2)
154
12.5k
                nRet = SwComparePosition::Outside;
155
4.41k
            else
156
4.41k
                nRet = SwComparePosition::OverlapBehind;
157
16.9k
        }
158
330k
    }
159
486k
    else if( rEnd2 == rStt1 )
160
23.6k
        nRet = SwComparePosition::CollideStart;
161
463k
    else
162
463k
        nRet = SwComparePosition::Behind;
163
884k
    return nRet;
164
884k
}
SwComparePosition ComparePosition<SwPosition>(SwPosition const&, SwPosition const&, SwPosition const&, SwPosition const&)
Line
Count
Source
125
884k
{
126
884k
    SwComparePosition nRet;
127
884k
    if( rStt1 < rStt2 )
128
67.2k
    {
129
67.2k
        if( rEnd1 > rStt2 )
130
8.03k
        {
131
8.03k
            if( rEnd1 >= rEnd2 )
132
5.15k
                nRet = SwComparePosition::Outside;
133
2.88k
            else
134
2.88k
                nRet = SwComparePosition::OverlapBefore;
135
136
8.03k
        }
137
59.2k
        else if( rEnd1 == rStt2 )
138
33.3k
            nRet = SwComparePosition::CollideEnd;
139
25.8k
        else
140
25.8k
            nRet = SwComparePosition::Before;
141
67.2k
    }
142
816k
    else if( rEnd2 > rStt1 )
143
330k
    {
144
330k
        if( rEnd2 >= rEnd1 )
145
313k
        {
146
313k
            if( rEnd2 == rEnd1 && rStt2 == rStt1 )
147
215k
                nRet = SwComparePosition::Equal;
148
98.0k
            else
149
98.0k
                nRet = SwComparePosition::Inside;
150
313k
        }
151
16.9k
        else
152
16.9k
        {
153
16.9k
            if (rStt1 == rStt2)
154
12.5k
                nRet = SwComparePosition::Outside;
155
4.39k
            else
156
4.39k
                nRet = SwComparePosition::OverlapBehind;
157
16.9k
        }
158
330k
    }
159
486k
    else if( rEnd2 == rStt1 )
160
23.6k
        nRet = SwComparePosition::CollideStart;
161
463k
    else
162
463k
        nRet = SwComparePosition::Behind;
163
884k
    return nRet;
164
884k
}
SwComparePosition ComparePosition<int>(int const&, int const&, int const&, int const&)
Line
Count
Source
125
21
{
126
21
    SwComparePosition nRet;
127
21
    if( rStt1 < rStt2 )
128
0
    {
129
0
        if( rEnd1 > rStt2 )
130
0
        {
131
0
            if( rEnd1 >= rEnd2 )
132
0
                nRet = SwComparePosition::Outside;
133
0
            else
134
0
                nRet = SwComparePosition::OverlapBefore;
135
136
0
        }
137
0
        else if( rEnd1 == rStt2 )
138
0
            nRet = SwComparePosition::CollideEnd;
139
0
        else
140
0
            nRet = SwComparePosition::Before;
141
0
    }
142
21
    else if( rEnd2 > rStt1 )
143
21
    {
144
21
        if( rEnd2 >= rEnd1 )
145
0
        {
146
0
            if( rEnd2 == rEnd1 && rStt2 == rStt1 )
147
0
                nRet = SwComparePosition::Equal;
148
0
            else
149
0
                nRet = SwComparePosition::Inside;
150
0
        }
151
21
        else
152
21
        {
153
21
            if (rStt1 == rStt2)
154
0
                nRet = SwComparePosition::Outside;
155
21
            else
156
21
                nRet = SwComparePosition::OverlapBehind;
157
21
        }
158
21
    }
159
0
    else if( rEnd2 == rStt1 )
160
0
        nRet = SwComparePosition::CollideStart;
161
0
    else
162
0
        nRet = SwComparePosition::Behind;
163
21
    return nRet;
164
21
}
165
166
/// SwPointAndMark / SwPaM
167
struct SwMoveFnCollection;
168
SW_DLLPUBLIC extern SwMoveFnCollection const & fnMoveForward; ///< SwPam::Move()/Find() default argument.
169
SW_DLLPUBLIC extern SwMoveFnCollection const & fnMoveBackward;
170
171
using SwGoInDoc = auto (*)(SwPaM& rPam, SwMoveFnCollection const & fnMove) -> bool;
172
SW_DLLPUBLIC bool GoInDoc( SwPaM&, SwMoveFnCollection const &);
173
bool GoInSection( SwPaM&, SwMoveFnCollection const &);
174
SW_DLLPUBLIC bool GoInNode( SwPaM&, SwMoveFnCollection const &);
175
SW_DLLPUBLIC bool GoInContent( SwPaM&, SwMoveFnCollection const &);
176
bool GoInContentCells( SwPaM&, SwMoveFnCollection const &);
177
bool GoInContentSkipHidden( SwPaM&, SwMoveFnCollection const &);
178
bool GoInContentCellsSkipHidden( SwPaM&, SwMoveFnCollection const &);
179
180
/**
181
 * PaM is Point and Mark: a selection of the document model.
182
 *
183
 * The reason for the distinction is that the point moves around during adjusting the selection with
184
 * shift-arrow keys, while the mark remains where it is.
185
 */
186
class SAL_WARN_UNUSED SW_DLLPUBLIC SwPaM : public sw::Ring<SwPaM>
187
{
188
    SwPosition   m_Bound1;
189
    SwPosition   m_Bound2;
190
    SwPosition * m_pPoint; ///< points at either m_Bound1 or m_Bound2
191
    SwPosition * m_pMark;  ///< points at either m_Bound1 or m_Bound2
192
    bool m_bIsInFrontOfLabel;
193
194
    SwPaM(SwPaM const& rPaM) = delete;
195
196
public:
197
    explicit SwPaM( const SwPosition& rPos, SwPaM* pRing = nullptr );
198
    SwPaM( const SwPosition& rMk, const SwPosition& rPt, SwPaM* pRing = nullptr );
199
    SwPaM( const SwNodeIndex& rMk, const SwNodeIndex& rPt,
200
           SwNodeOffset nMkOffset = SwNodeOffset(0), SwNodeOffset nPtOffset = SwNodeOffset(0), SwPaM* pRing = nullptr );
201
    SwPaM( const SwNode& rMk, const SwNode& rPt,
202
           SwNodeOffset nMkOffset = SwNodeOffset(0), SwNodeOffset nPtOffset = SwNodeOffset(0), SwPaM* pRing = nullptr );
203
    SwPaM(  const SwNodeIndex& rMk, sal_Int32 nMkContent,
204
            const SwNodeIndex& rPt, sal_Int32 nPtContent, SwPaM* pRing = nullptr );
205
    SwPaM(  const SwNode& rMk, sal_Int32 nMkContent,
206
            const SwNode& rPt, sal_Int32 nPtContent, SwPaM* pRing = nullptr );
207
    SwPaM(  const SwNode& rMk, SwNodeOffset nMkOffset, sal_Int32 nMkContent,
208
            const SwNode& rPt, SwNodeOffset nPtOffset, sal_Int32 nPtContent, SwPaM* pRing = nullptr );
209
    SwPaM( const SwNode& rNd, SwNodeOffset nNdOffset, sal_Int32 nContent = 0, SwPaM* pRing = nullptr );
210
    explicit SwPaM( const SwNode& rNd, sal_Int32 nContent = 0, SwPaM* pRing = nullptr );
211
    explicit SwPaM( const SwNodeIndex& rNd, sal_Int32 nContent = 0, SwPaM* pRing = nullptr );
212
    explicit SwPaM( const SwNodes& rNds, SwNodeOffset nMkOffset = SwNodeOffset(0), SwPaM* pRing = nullptr );
213
    virtual ~SwPaM() override;
214
215
    /// this takes a second parameter, which indicates the Ring that
216
    /// the new PaM should be part of (may be null)
217
    SwPaM(SwPaM const& rPaM, SwPaM * pRing);
218
    /// @@@ semantic: no copy assignment for super class Ring.
219
    SwPaM& operator=( const SwPaM & );
220
221
    /// Movement of cursor.
222
    bool Move( SwMoveFnCollection const & fnMove = fnMoveForward,
223
                SwGoInDoc fnGo = GoInContent );
224
225
4.59M
    bool IsInFrontOfLabel() const        { return m_bIsInFrontOfLabel; }
226
0
    void SetInFrontOfLabel_( bool bNew ) { m_bIsInFrontOfLabel = bNew; }
227
228
    /// Unless this is called, the getter method of Mark will return Point.
229
    virtual void SetMark();
230
231
    void DeleteMark()
232
3.93M
    {
233
3.93M
        if (HasMark())
234
2.54M
        {
235
            /** clear the mark position; this helps if mark's SwContentIndex is
236
               registered at some node, and that node is then deleted */
237
2.54M
            m_pMark->Assign( *GetPointNode().GetNodes()[SwNodeOffset(0)] );
238
2.54M
            m_pMark = m_pPoint;
239
2.54M
        }
240
3.93M
    }
241
    void Exchange()
242
27.8k
    {
243
27.8k
        if (HasMark())
244
7.17k
            std::swap(m_pPoint, m_pMark);
245
27.8k
    }
246
247
    /** A PaM marks a selection if Point and Mark are distinct positions.
248
        @return     true if the PaM spans a selection
249
     */
250
13.1M
    bool HasMark() const { return m_pPoint != m_pMark; }
251
252
81.3M
    const SwPosition *GetPoint() const { return m_pPoint; }
253
130M
          SwPosition *GetPoint()       { return m_pPoint; }
254
3.93M
    const SwPosition *GetMark()  const { return m_pMark; }
255
3.19M
          SwPosition *GetMark()        { return m_pMark; }
256
257
    const SwPosition *Start() const
258
13.5M
                { return (*m_pPoint) <= (*m_pMark) ? m_pPoint : m_pMark; }
259
          SwPosition *Start()
260
5.33M
                { return (*m_pPoint) <= (*m_pMark) ? m_pPoint : m_pMark; }
261
262
    const SwPosition *End()   const
263
23.7M
                { return (*m_pPoint) >  (*m_pMark) ? m_pPoint : m_pMark; }
264
          SwPosition *End()
265
4.43M
                { return (*m_pPoint) >  (*m_pMark) ? m_pPoint : m_pMark; }
266
267
    /// Because sometimes the cost of the operator<= can add up
268
    std::pair<const SwPosition *, const SwPosition *> StartEnd() const
269
3.08M
                { if ((*m_pPoint) <= (*m_pMark)) return { m_pPoint, m_pMark }; else return { m_pMark, m_pPoint }; }
270
    std::pair<SwPosition *, SwPosition *> StartEnd()
271
29.0M
                { if ((*m_pPoint) <= (*m_pMark)) return { m_pPoint, m_pMark }; else return { m_pMark, m_pPoint }; }
272
273
    /// @return current Node at Point/Mark
274
10.1M
    SwNode& GetPointNode() const { return m_pPoint->nNode.GetNode(); }
275
19
    SwNode& GetMarkNode() const { return m_pMark->nNode.GetNode(); }
276
277
    /// @return current ContentNode at Point/Mark
278
33.4M
    SwContentNode* GetPointContentNode() const { return m_pPoint->nNode.GetNode().GetContentNode(); }
279
0
    SwContentNode* GetMarkContentNode() const { return m_pMark->nNode.GetNode().GetContentNode(); }
280
281
    /**
282
       Normalizes PaM, i.e. sort point and mark.
283
284
       @param bPointFirst true: If the point is behind the mark then swap.
285
                          false: If the mark is behind the point then swap.
286
    */
287
    void Normalize(bool bPointFirst = true);
288
289
    /// @return the document (SwDoc) at which the PaM is registered
290
48.1M
    SwDoc& GetDoc() const   { return m_pPoint->nNode.GetNode().GetDoc(); }
291
292
          SwPosition& GetBound( bool bOne = true )
293
2.83M
                            { return bOne ? m_Bound1 : m_Bound2; }
294
    const SwPosition& GetBound( bool bOne = true ) const
295
0
                            { return bOne ? m_Bound1 : m_Bound2; }
296
297
    /// Get number of page which contains cursor.
298
    sal_uInt16 GetPageNum( bool bAtPoint = true, const Point* pLayPos = nullptr );
299
300
    /** Is in something protected (readonly) or selection contains
301
       something protected. */
302
    bool HasReadonlySel(bool bFormView, bool isReplace) const;
303
    /** Is there hidden sections in the selected area. */
304
    bool HasHiddenSections() const;
305
306
    bool ContainsPosition(const SwPosition & rPos) const
307
4.97M
    {
308
4.97M
        return *Start() <= rPos && rPos <= *End();
309
4.97M
    }
310
311
    OUString GetText() const;
312
    // copy text into buffer
313
    void AppendTextTo(rtl::OUStringBuffer& rBuffer) const;
314
    void InvalidatePaM();
315
    SwPaM* GetNext()
316
1.67M
        { return GetNextInRing(); }
317
    const SwPaM* GetNext() const
318
36
        { return GetNextInRing(); }
319
    SwPaM* GetPrev()
320
0
        { return GetPrevInRing(); }
321
    const SwPaM* GetPrev() const
322
0
        { return GetPrevInRing(); }
323
    bool IsMultiSelection() const
324
0
        { return !unique(); }
325
326
    void dumpAsXml(xmlTextWriterPtr pWriter) const;
327
};
328
329
SW_DLLPUBLIC std::ostream &operator <<(std::ostream& s, const SwPaM& pam);
330
331
bool CheckNodesRange(const SwNode&, const SwNode&, bool bChkSection);
332
333
#endif // INCLUDED_SW_INC_PAM_HXX
334
335
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */