Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sw/inc/ndhints.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_NDHINTS_HXX
20
#define INCLUDED_SW_INC_NDHINTS_HXX
21
22
#include "swtypes.hxx"
23
24
class SwTextNode;
25
class SwRegHistory;                 // Is in RolBck.hxx.
26
class SwTextAttr;
27
class SwTextAttrNesting;
28
29
class SfxPoolItem;
30
class SfxItemSet;
31
class SwDoc;
32
33
enum class CopyOrNewType { Copy, New };
34
35
/// if COPY then pTextNode must be given!
36
SwTextAttr * MakeTextAttr(
37
    SwDoc & rDoc,
38
    SfxPoolItem & rNew,
39
    sal_Int32 const nStt,
40
    sal_Int32 const nEnd,
41
    CopyOrNewType const bIsCopy = CopyOrNewType::New,
42
    SwTextNode *const pTextNode = nullptr );
43
44
SwTextAttr * MakeTextAttr(
45
    SwDoc & rDoc,
46
    const SfxItemSet & rSet,
47
    sal_Int32 nStt,
48
    sal_Int32 nEnd );
49
50
/// create redline dummy text hint that must not be inserted into hints array
51
SwTextAttr* MakeRedlineTextAttr(
52
    SwDoc & rDoc,
53
    SfxPoolItem const & rAttr );
54
55
struct CompareSwpHtEnd
56
{
57
    bool operator()( sal_Int32 nEndPos, const SwTextAttr* rhs ) const;
58
    bool operator()( const SwTextAttr* lhs, const SwTextAttr* rhs ) const;
59
};
60
typedef std::pair<sal_Int32, sal_Int32> WhichStartPair;
61
struct CompareSwpHtWhichStart
62
{
63
    bool operator()( const SwTextAttr* lhs, const sal_uInt16 nWhich ) const;
64
    bool operator()( const SwTextAttr* lhs, const SwTextAttr* rhs ) const;
65
    // used when we sort only a partial range of the map
66
    bool operator()( const SwTextAttr* lhs, const WhichStartPair nWhich ) const;
67
    bool operator()( const WhichStartPair nWhich, const SwTextAttr* lhs ) const;
68
};
69
70
/// An SwTextAttr container, stores all directly formatted text portions for a text node.
71
class SwpHints
72
{
73
private:
74
    const SwTextNode& m_rParent;
75
76
    // SAL_MAX_SIZE is used by GetStartOf to return
77
    // failure, so just allow SAL_MAX_SIZE-1 hints
78
    static const size_t MAX_HINTS = SAL_MAX_SIZE-1;
79
80
    std::vector<SwTextAttr*> m_HintsByStart;
81
    std::vector<SwTextAttr*> m_HintsByEnd;
82
    std::vector<SwTextAttr*> m_HintsByWhichAndStart;
83
84
    SwRegHistory* m_pHistory;                   ///< for Undo
85
86
    /// true: the Node is in Split and Frames are moved
87
    bool          m_bInSplitNode         : 1;
88
    // m_bHiddenByParaField is invalid, call CalcHiddenParaField()
89
    mutable bool  m_bCalcHiddenParaField : 1;
90
    // if all fields controlling visibility of the paragraph require to hide it
91
    // (if there's no such fields, or if any field requires to show, then this is false)
92
    mutable bool  m_bHiddenByParaField   : 1;
93
    bool          m_bFootnote            : 1;   ///< footnotes
94
    bool          m_bDDEFields           : 1;   ///< the TextNode has DDE fields
95
    // Sort on demand to avoid O(n^2) behaviour
96
    // SAL_MAX_INT32 means nothing needs sorting, -1 means everything needs sorting
97
    mutable std::pair<sal_Int32, sal_Int32> m_StartMapNeedsSortingRange { SAL_MAX_INT32, -1 };
98
    mutable std::pair<sal_Int32, sal_Int32> m_EndMapNeedsSortingRange { SAL_MAX_INT32, -1 };
99
    // we are storing pairs of { Which, Start } here
100
    mutable std::pair<WhichStartPair, WhichStartPair> m_WhichMapNeedsSortingRange { { SAL_MAX_INT32, -1 }, { -1, -1 } };
101
102
    /// records a new attribute in m_pHistory.
103
    void NoteInHistory( SwTextAttr *pAttr, const bool bNew = false );
104
105
    void CalcFlags( );
106
107
    /** Delete methods may only be called by the TextNode!
108
       Because the TextNode also guarantees removal of the Character for
109
       attributes without an end. */
110
    friend class SwTextNode;
111
    void DeleteAtPos( size_t nPos );
112
    /// Delete the given Hint. The Hint must actually be in the array!
113
    void Delete( SwTextAttr const * pTextHt );
114
115
2
    void SetInSplitNode(bool bInSplit) { m_bInSplitNode = bInSplit; }
116
547
    void SetCalcHiddenParaField() const { m_bCalcHiddenParaField = true; }
117
23.5k
    void SetHiddenByParaField( const bool bNew ) const { m_bHiddenByParaField = bNew; }
118
    bool IsHiddenByParaField() const
119
321k
    {
120
321k
        if ( m_bCalcHiddenParaField )
121
36
        {
122
36
            CalcHiddenParaField();
123
36
        }
124
321k
        return m_bHiddenByParaField;
125
321k
    }
126
127
    void InsertNesting(SwTextAttrNesting & rNewHint);
128
    bool TryInsertNesting(SwTextNode & rNode, SwTextAttrNesting & rNewHint);
129
    void BuildPortions( SwTextNode& rNode, SwTextAttr& rNewHint,
130
            const SetAttrMode nMode );
131
    bool MergePortions( SwTextNode& rNode );
132
133
    void Insert(SwTextAttr* pHt);
134
    SW_DLLPUBLIC void Resort() const;
135
    SW_DLLPUBLIC void ResortStartMap() const;
136
    SW_DLLPUBLIC void ResortEndMap() const;
137
    SW_DLLPUBLIC void ResortWhichMap() const;
138
139
    size_t GetIndexOf( const SwTextAttr *pHt ) const;
140
141
#ifdef DBG_UTIL
142
    bool Check(bool) const;
143
#endif
144
145
public:
146
    SwpHints(const SwTextNode& rParent);
147
148
241M
    size_t Count() const { return m_HintsByStart.size(); }
149
    bool Contains( const SwTextAttr *pHt ) const;
150
    SwTextAttr * Get( size_t nPos ) const
151
250M
    {
152
250M
        assert( !(nPos != 0 && m_StartMapNeedsSortingRange.first != SAL_MAX_INT32) && "going to trigger a resort in the middle of an iteration, that's bad" );
153
250M
        if (m_StartMapNeedsSortingRange.first != SAL_MAX_INT32)
154
74
            ResortStartMap();
155
250M
        return m_HintsByStart[nPos];
156
250M
    }
157
    // Get without triggering resorting - useful if we are modifying start/end pos while iterating
158
    SwTextAttr * GetWithoutResorting( size_t nPos ) const
159
188M
    {
160
188M
        return m_HintsByStart[nPos];
161
188M
    }
162
163
    int GetLastPosSortedByEnd(sal_Int32 nEndPos) const;
164
    SwTextAttr * GetSortedByEnd( size_t nPos ) const
165
1.27M
    {
166
1.27M
        assert( !(nPos != 0 && m_EndMapNeedsSortingRange.first != SAL_MAX_INT32) && "going to trigger a resort in the middle of an iteration, that's bad" );
167
1.27M
        if (m_EndMapNeedsSortingRange.first != SAL_MAX_INT32)
168
0
            ResortEndMap();
169
1.27M
        return m_HintsByEnd[nPos];
170
1.27M
    }
171
172
    size_t GetFirstPosSortedByWhichAndStart(sal_uInt16 nWhich) const;
173
    SwTextAttr * GetSortedByWhichAndStart( size_t nPos ) const
174
1.86M
    {
175
1.86M
        assert( !(nPos != 0 && m_WhichMapNeedsSortingRange.first.first != SAL_MAX_INT32) && "going to trigger a resort in the middle of an iteration, that's bad" );
176
1.86M
        if (m_WhichMapNeedsSortingRange.first.first != SAL_MAX_INT32)
177
0
            ResortWhichMap();
178
1.86M
        return m_HintsByWhichAndStart[nPos];
179
1.86M
    }
180
181
    /// Trigger the sorting if necessary
182
    void SortIfNeedBe() const
183
2.99M
    {
184
2.99M
        if (m_StartMapNeedsSortingRange.first != SAL_MAX_INT32)
185
132k
            ResortStartMap();
186
2.99M
        if (m_EndMapNeedsSortingRange.first != SAL_MAX_INT32)
187
132k
            ResortEndMap();
188
2.99M
        if (m_WhichMapNeedsSortingRange.first.first != SAL_MAX_INT32)
189
132k
            ResortWhichMap();
190
2.99M
    }
191
    SwTextAttr * Cut( const size_t nPosInStart )
192
2.40k
    {
193
2.40k
        SwTextAttr *pHt = m_HintsByStart[nPosInStart];
194
2.40k
        DeleteAtPos( nPosInStart );
195
2.40k
        return pHt;
196
2.40k
    }
197
198
5.16M
    bool CanBeDeleted() const    { return m_HintsByStart.empty(); }
199
200
    /// register a History, which receives all attribute changes (for Undo)
201
0
    void Register( SwRegHistory* pHist ) { m_pHistory = pHist; }
202
    /// deregister the currently registered History
203
0
    void DeRegister() { Register(nullptr); }
204
20.1k
    SwRegHistory* GetHistory() const    { return m_pHistory; }
205
206
    /// try to insert the hint
207
    /// @return true iff hint successfully inserted
208
    bool TryInsertHint( SwTextAttr * const pHint, SwTextNode & rNode,
209
            const SetAttrMode nMode = SetAttrMode::DEFAULT );
210
211
1.70k
    bool HasFootnote() const          { return m_bFootnote; }
212
603k
    bool IsInSplitNode() const   { return m_bInSplitNode; }
213
214
    // calc current value of m_bHiddenByParaField, returns true iff changed
215
    bool CalcHiddenParaField() const; // changes mutable state
216
217
    // Marks the hint-maps as needing sorting because the position of something has changed
218
    void StartPosChanged() const
219
29.8M
    {
220
29.8M
        m_StartMapNeedsSortingRange = { -1, -1 };
221
29.8M
        m_EndMapNeedsSortingRange = { -1, -1 };
222
29.8M
        m_WhichMapNeedsSortingRange = { { -1, -1 }, { -1, -1 } };
223
29.8M
    }
224
    void EndPosChanged(sal_uInt16 nWhich, sal_Int32 nStartPos, sal_Int32 nOldEndPos, sal_Int32 nNewEndPos) const
225
930k
    {
226
930k
        m_StartMapNeedsSortingRange = { std::min(nStartPos, m_StartMapNeedsSortingRange.first),
227
930k
                                        std::max(nStartPos, m_StartMapNeedsSortingRange.second) };
228
930k
        m_EndMapNeedsSortingRange = { std::min(std::min(nOldEndPos, nNewEndPos), m_EndMapNeedsSortingRange.first),
229
930k
                                      std::max(std::max(nOldEndPos, nNewEndPos), m_EndMapNeedsSortingRange.second) };
230
930k
        WhichStartPair aPair { sal_Int32(nWhich), nStartPos };
231
930k
        m_WhichMapNeedsSortingRange = { std::min(aPair, m_WhichMapNeedsSortingRange.first),
232
930k
                                        std::max(aPair, m_WhichMapNeedsSortingRange.second) };
233
930k
    }
234
};
235
236
#endif
237
238
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */