Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/inc/attarray.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
20
#pragma once
21
22
#include "global.hxx"
23
#include "attrib.hxx"
24
#include "document.hxx"
25
#include "patattr.hxx"
26
27
#include <algorithm>
28
#include <optional>
29
30
#include <svl/itemset.hxx>
31
32
class ScEditDataArray;
33
class ScMarkArray;
34
class ScStyleSheet;
35
class ScFlatBoolRowSegments;
36
37
class ScItemPoolCache;
38
class SfxStyleSheetBase;
39
class SvxBoxItem;
40
class SvxBoxInfoItem;
41
42
namespace editeng { class SvxBorderLine; }
43
44
0
#define SC_LINE_EMPTY           0
45
0
#define SC_LINE_SET             1
46
0
#define SC_LINE_DONTCARE        2
47
48
5.51M
#define SC_ATTRARRAY_DELTA      4
49
50
#define DEBUG_SC_TESTATTRARRAY 0
51
52
struct ScLineFlags
53
{
54
    sal_uInt8   nLeft;
55
    sal_uInt8   nRight;
56
    sal_uInt8   nTop;
57
    sal_uInt8   nBottom;
58
    sal_uInt8   nHori;
59
    sal_uInt8   nVert;
60
61
0
    ScLineFlags() : nLeft(SC_LINE_EMPTY),nRight(SC_LINE_EMPTY),nTop(SC_LINE_EMPTY),
62
0
                    nBottom(SC_LINE_EMPTY),nHori(SC_LINE_EMPTY),nVert(SC_LINE_EMPTY) {}
63
};
64
65
struct ScMergePatternState
66
{
67
    std::optional<SfxItemSet> pItemSet;
68
    CellAttributeHolder aOld1;     ///< existing objects, temporary
69
    CellAttributeHolder aOld2;
70
71
    bool mbValidPatternId;
72
    sal_uInt64 mnPatternId;
73
74
2.12k
    ScMergePatternState() : aOld1(), aOld2(),
75
2.12k
                        mbValidPatternId(true), mnPatternId(0) {}
76
};
77
78
// we store an array of these where the pattern applies to all rows up till nEndRow
79
class ScAttrEntry
80
{
81
    CellAttributeHolder     aPattern;
82
83
public:
84
    ScAttrEntry()
85
172M
    : aPattern()
86
172M
    , nEndRow(0)
87
172M
    {}
88
89
    SCROW                   nEndRow;
90
91
7.99M
    const CellAttributeHolder& getCellAttributeHolder() const { return aPattern; }
92
1.99M
    void setCellAttributeHolder(const CellAttributeHolder& rNew) { aPattern = rNew; }
93
94
336M
    const ScPatternAttr* getScPatternAttr() const { return aPattern.getScPatternAttr(); }
95
173M
    void setScPatternAttr(const ScPatternAttr* pNew, bool bPassingOwnership = false) { aPattern.setScPatternAttr(pNew, bPassingOwnership); }
96
97
    bool operator==( const ScAttrEntry& other ) const
98
144M
    {
99
144M
        return nEndRow == other.nEndRow && CellAttributeHolder::areSame(&aPattern, &other.aPattern);
100
144M
    }
101
};
102
103
class ScAttrArray
104
{
105
private:
106
    SCCOL           nCol;
107
    SCTAB           nTab;
108
    ScDocument&     rDocument;
109
110
    std::vector<ScAttrEntry> mvData;
111
112
friend class ScDocument;                // for FillInfo
113
friend class ScDocumentIterator;
114
friend class ScAttrIterator;
115
friend class ScHorizontalAttrIterator;
116
117
    bool    ApplyFrame( const SvxBoxItem& rLineOuter, const SvxBoxInfoItem* pLineInner,
118
                            SCROW nStartRow, SCROW nEndRow,
119
                            bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom );
120
121
    void RemoveCellCharAttribs( SCROW nStartRow, SCROW nEndRow,
122
                              const ScPatternAttr* pPattern, ScEditDataArray* pDataArray );
123
    void SetDefaultIfNotInit( SCSIZE nNeeded = 1 );
124
    bool HasAttrib_Impl(const ScPatternAttr* pPattern, HasAttrFlags nMask, SCROW nRow1, SCROW nRow2, SCSIZE i) const;
125
126
    ScAttrArray(const ScAttrArray&) = delete;
127
    ScAttrArray& operator=(const ScAttrArray&) = delete;
128
129
public:
130
            ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument& rDoc, ScAttrArray* pNextColAttrArray );
131
            ~ScAttrArray();
132
133
698M
    ScDocument& GetDoc() { return rDocument; }
134
2.21M
    const ScDocument& GetDoc() const { return rDocument; }
135
1.45M
    void    SetTab(SCTAB nNewTab)   { nTab = nNewTab; }
136
0
    void    SetCol(SCCOL nNewCol)   { nCol = nNewCol; }
137
#if DEBUG_SC_TESTATTRARRAY
138
    void    TestData() const;
139
#endif
140
    void    Reset(const CellAttributeHolder& rPattern);
141
    bool    Concat(SCSIZE nPos);
142
143
    const ScPatternAttr* GetPattern( SCROW nRow ) const;
144
145
    /** Returns if you search for attributes at nRow the range from rStartRow
146
        to rEndRow where that attribute combination (ScPatternAttr) is applied.
147
        The next ScPatternAttr different from this one starts at rEndRow+1
148
        (if that is <= MAXROW).
149
     */
150
    const ScPatternAttr* GetPatternRange( SCROW& rStartRow, SCROW& rEndRow, SCROW nRow ) const;
151
152
    void    MergePatternArea( SCROW nStartRow, SCROW nEndRow, ScMergePatternState& rState, bool bDeep ) const;
153
154
    void    MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, ScLineFlags& rFlags,
155
                            SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const;
156
    void    ApplyBlockFrame(const SvxBoxItem& rLineOuter, const SvxBoxInfoItem* pLineInner,
157
                            SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight);
158
159
    void    SetPattern( SCROW nRow, const CellAttributeHolder& rPattern )
160
3.45M
    { SetPatternAreaImpl(nRow, nRow, rPattern, nullptr); }
161
    void    SetPatternArea( SCROW nStartRow, SCROW nEndRow, const CellAttributeHolder& rPattern, ScEditDataArray* pDataArray = nullptr)
162
24.3M
    { SetPatternAreaImpl(nStartRow, nEndRow, rPattern, pDataArray); }
163
    void    ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle );
164
    void    ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, ScItemPoolCache& rCache,
165
                            ScEditDataArray* pDataArray = nullptr, bool* const pIsChanged = nullptr );
166
    void    SetAttrEntries(std::vector<ScAttrEntry> && vNewData);
167
    void    ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
168
                                const ::editeng::SvxBorderLine* pLine, bool bColorOnly );
169
170
    void    AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex );
171
    /// if nIndex == 0, remove all conditional format data
172
    void    RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex );
173
174
    void    ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich );
175
    void    ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement );
176
177
            /// Including current, may return -1
178
    SCROW  GetNextUnprotected( SCROW nRow, bool bUp ) const;
179
180
            /// May return -1 if not found
181
    SCROW SearchStyle(
182
        SCROW nRow, const ScStyleSheet* pSearchStyle, bool bUp,
183
        const ScMarkArray* pMarkArray = nullptr) const;
184
185
    bool SearchStyleRange(
186
        SCROW& rRow, SCROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp,
187
        const ScMarkArray* pMarkArray = nullptr) const;
188
189
    bool    ApplyFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags );
190
    bool    RemoveFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags );
191
192
    bool    Search( SCROW nRow, SCSIZE& nIndex, std::optional<SCROW> nIndexHint = {} ) const;
193
194
    bool    HasAttrib( SCROW nRow1, SCROW nRow2, HasAttrFlags nMask ) const;
195
    bool    HasAttrib( SCROW nRow, HasAttrFlags nMask, SCROW* nStartRow = nullptr, SCROW* nEndRow = nullptr ) const;
196
    bool    IsMerged( SCROW nRow ) const;
197
    bool    ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
198
                                SCCOL& rPaintCol, SCROW& rPaintRow,
199
                                bool bRefresh );
200
    void    RemoveAreaMerge( SCROW nStartRow, SCROW nEndRow );
201
202
    void    FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset );
203
    bool    IsStyleSheetUsed( const ScStyleSheet& rStyle ) const;
204
205
    void    SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow, const CellAttributeHolder& rWantedPattern );
206
    void    CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray& rAttrArray );
207
208
    bool    IsEmpty() const;
209
210
    bool    GetFirstVisibleAttr( SCROW& rFirstRow ) const;
211
    bool    GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData, bool bSkipEmpty ) const;
212
    bool    HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const;
213
    bool    IsVisibleEqual( const ScAttrArray& rOther,
214
                            SCROW nStartRow, SCROW nEndRow ) const;
215
    bool    IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const;
216
217
    bool    TestInsertCol( SCROW nStartRow, SCROW nEndRow) const;
218
    bool    TestInsertRow( SCSIZE nSize ) const;
219
    void    InsertRow( SCROW nStartRow, SCSIZE nSize );
220
    void    DeleteRow( SCROW nStartRow, SCSIZE nSize );
221
    void    DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex );
222
    void    DeleteArea( SCROW nStartRow, SCROW nEndRow );
223
    void    MoveTo( SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray );
224
    void    CopyArea(
225
        SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray& rAttrArray, ScMF nStripFlags = ScMF::NONE) const;
226
227
    void    DeleteHardAttr( SCROW nStartRow, SCROW nEndRow );
228
229
    /* i123909: Pre-calculate needed memory, and pre-reserve enough memory */
230
    bool    Reserve( SCSIZE nReserve );
231
28.3M
    SCSIZE  Count() const { return mvData.size(); }
232
    SCSIZE  Count( SCROW nRow1, SCROW nRow2 ) const;
233
234
private:
235
    const ScPatternAttr* SetPatternAreaImpl(
236
        SCROW nStartRow, SCROW nEndRow, const CellAttributeHolder& rPattern, ScEditDataArray* pDataArray = nullptr);
237
};
238
239
//                              Iterator for attributes
240
241
class ScAttrIterator
242
{
243
    const ScAttrArray*  pArray;
244
    const ScPatternAttr* pDefPattern;
245
    SCSIZE              nPos;
246
    SCROW               nRow;
247
    SCROW               nEndRow;
248
public:
249
    inline              ScAttrIterator( const ScAttrArray* pNewArray, SCROW nStart, SCROW nEnd, const ScPatternAttr* pDefaultPattern );
250
    inline const ScPatternAttr* Next( SCROW& rTop, SCROW& rBottom );
251
    inline const ScPatternAttr* Resync( SCROW nRow, SCROW& rTop, SCROW& rBottom );
252
0
    SCROW               GetNextRow() const { return nRow; }
253
};
254
255
inline ScAttrIterator::ScAttrIterator( const ScAttrArray* pNewArray, SCROW nStart, SCROW nEnd, const ScPatternAttr* pDefaultPattern ) :
256
2.08M
    pArray( pNewArray ),
257
2.08M
    pDefPattern( pDefaultPattern ),
258
2.08M
    nRow( nStart ),
259
2.08M
    nEndRow( nEnd )
260
2.08M
{
261
2.08M
    if ( pArray->Count() )
262
1.52M
    {
263
1.52M
        if ( nStart > 0 )
264
1.82k
            pArray->Search( nStart, nPos );
265
1.52M
        else
266
1.52M
            nPos = 0;
267
1.52M
    }
268
562k
    else
269
562k
        nPos = 0;
270
2.08M
}
271
272
inline const ScPatternAttr* ScAttrIterator::Next( SCROW& rTop, SCROW& rBottom )
273
9.51M
{
274
9.51M
    const ScPatternAttr* pRet;
275
9.51M
    if ( !pArray->Count() )
276
1.64M
    {
277
1.64M
        if ( !nPos )
278
1.10M
        {
279
1.10M
            ++nPos;
280
1.10M
            if ( nRow > pArray->GetDoc().MaxRow())
281
0
                return nullptr;
282
1.10M
            rTop = nRow;
283
1.10M
            rBottom = std::min( nEndRow, pArray->GetDoc().MaxRow());
284
1.10M
            nRow = rBottom + 1;
285
1.10M
            return pDefPattern;
286
1.10M
        }
287
535k
        return nullptr;
288
1.64M
    }
289
290
7.86M
    if ( nPos < pArray->Count() && nRow <= nEndRow )
291
6.31M
    {
292
6.31M
        rTop = nRow;
293
6.31M
        rBottom = std::min( pArray->mvData[nPos].nEndRow, nEndRow );
294
6.31M
        pRet = pArray->mvData[nPos].getScPatternAttr();
295
6.31M
        nRow = rBottom + 1;
296
6.31M
        ++nPos;
297
6.31M
    }
298
1.54M
    else
299
1.54M
        pRet = nullptr;
300
7.86M
    return pRet;
301
9.51M
}
302
303
inline const ScPatternAttr* ScAttrIterator::Resync( SCROW nRowP, SCROW& rTop, SCROW& rBottom )
304
3.46M
{
305
3.46M
    nRow = nRowP;
306
3.46M
    if ( !pArray->Count() )
307
545k
    {
308
545k
        nPos = 0;
309
545k
        return Next( rTop, rBottom );
310
545k
    }
311
    // Chances are high that the pattern changed on nRowP introduced a span
312
    // starting right there. Assume that Next() was called so nPos already
313
    // advanced. Another high chance is that the change extended a previous or
314
    // next pattern. In all these cases we don't need to search.
315
2.91M
    if (3 <= nPos && nPos <= pArray->Count() && pArray->mvData[nPos-3].nEndRow < nRowP &&
316
1.21M
            nRowP <= pArray->mvData[nPos-2].nEndRow)
317
44
        nPos -= 2;
318
2.91M
    else if (2 <= nPos && nPos <= pArray->Count() && pArray->mvData[nPos-2].nEndRow < nRowP &&
319
1.66M
            nRowP <= pArray->mvData[nPos-1].nEndRow)
320
1.66M
        --nPos;
321
1.24M
    else if (pArray->Count() > 0 && nRowP <= pArray->mvData[0].nEndRow)
322
1.24M
        nPos = 0;
323
134
    else
324
134
        pArray->Search( nRowP, nPos );
325
2.91M
    return Next( rTop, rBottom);
326
3.46M
}
327
328
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */