Avoid potential negative array index access to cached text.
[LibreOffice.git] / sc / inc / attarray.hxx
blob59279f95fbc3974ba20f1e023028e6210519d7f9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #pragma once
22 #include "global.hxx"
23 #include "attrib.hxx"
24 #include "document.hxx"
25 #include "patattr.hxx"
27 #include <algorithm>
28 #include <memory>
29 #include <optional>
31 #include <svl/itemset.hxx>
33 class ScDocument;
34 class ScEditDataArray;
35 class ScMarkArray;
36 class ScStyleSheet;
37 class ScFlatBoolRowSegments;
39 class ScItemPoolCache;
40 class SfxStyleSheetBase;
41 class SvxBoxItem;
42 class SvxBoxInfoItem;
44 namespace editeng { class SvxBorderLine; }
46 #define SC_LINE_EMPTY 0
47 #define SC_LINE_SET 1
48 #define SC_LINE_DONTCARE 2
50 #define SC_ATTRARRAY_DELTA 4
52 #define DEBUG_SC_TESTATTRARRAY 0
54 struct ScLineFlags
56 sal_uInt8 nLeft;
57 sal_uInt8 nRight;
58 sal_uInt8 nTop;
59 sal_uInt8 nBottom;
60 sal_uInt8 nHori;
61 sal_uInt8 nVert;
63 ScLineFlags() : nLeft(SC_LINE_EMPTY),nRight(SC_LINE_EMPTY),nTop(SC_LINE_EMPTY),
64 nBottom(SC_LINE_EMPTY),nHori(SC_LINE_EMPTY),nVert(SC_LINE_EMPTY) {}
67 struct ScMergePatternState
69 std::optional<SfxItemSet> pItemSet;
70 const ScPatternAttr* pOld1; ///< existing objects, temporary
71 const ScPatternAttr* pOld2;
73 bool mbValidPatternId;
74 sal_uInt64 mnPatternId;
76 ScMergePatternState() : pOld1(nullptr), pOld2(nullptr),
77 mbValidPatternId(true), mnPatternId(0) {}
80 // we store an array of these where the pattern applies to all rows up till nEndRow
81 struct ScAttrEntry
83 SCROW nEndRow;
84 const ScPatternAttr* pPattern;
85 bool operator==( const ScAttrEntry& other ) const
87 return nEndRow == other.nEndRow && SfxPoolItem::areSame(pPattern, other.pPattern);
91 class ScAttrArray
93 private:
94 SCCOL nCol;
95 SCTAB nTab;
96 ScDocument& rDocument;
98 std::vector<ScAttrEntry> mvData;
100 friend class ScDocument; // for FillInfo
101 friend class ScDocumentIterator;
102 friend class ScAttrIterator;
103 friend class ScHorizontalAttrIterator;
105 bool ApplyFrame( const SvxBoxItem& rLineOuter, const SvxBoxInfoItem* pLineInner,
106 SCROW nStartRow, SCROW nEndRow,
107 bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom );
109 void RemoveCellCharAttribs( SCROW nStartRow, SCROW nEndRow,
110 const ScPatternAttr* pPattern, ScEditDataArray* pDataArray );
111 void SetDefaultIfNotInit( SCSIZE nNeeded = 1 );
112 bool HasAttrib_Impl(const ScPatternAttr* pPattern, HasAttrFlags nMask, SCROW nRow1, SCROW nRow2, SCSIZE i) const;
114 ScAttrArray(const ScAttrArray&) = delete;
115 ScAttrArray& operator=(const ScAttrArray&) = delete;
117 public:
118 ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument& rDoc, ScAttrArray* pNextColAttrArray );
119 ~ScAttrArray();
121 ScDocument& GetDoc() { return rDocument; }
122 const ScDocument& GetDoc() const { return rDocument; }
123 void SetTab(SCTAB nNewTab) { nTab = nNewTab; }
124 void SetCol(SCCOL nNewCol) { nCol = nNewCol; }
125 #if DEBUG_SC_TESTATTRARRAY
126 void TestData() const;
127 #endif
128 void Reset( const ScPatternAttr* pPattern);
129 bool Concat(SCSIZE nPos);
131 const ScPatternAttr* GetPattern( SCROW nRow ) const;
133 /** Returns if you search for attributes at nRow the range from rStartRow
134 to rEndRow where that attribute combination (ScPatternAttr) is applied.
135 The next ScPatternAttr different from this one starts at rEndRow+1
136 (if that is <= MAXROW).
138 const ScPatternAttr* GetPatternRange( SCROW& rStartRow, SCROW& rEndRow, SCROW nRow ) const;
140 void MergePatternArea( SCROW nStartRow, SCROW nEndRow, ScMergePatternState& rState, bool bDeep ) const;
142 void MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, ScLineFlags& rFlags,
143 SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const;
144 void ApplyBlockFrame(const SvxBoxItem& rLineOuter, const SvxBoxInfoItem* pLineInner,
145 SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight);
147 void SetPattern( SCROW nRow, const ScPatternAttr* pPattern, bool bPutToPool = false )
148 { SetPatternAreaImpl(nRow, nRow, pPattern, bPutToPool, nullptr, /*bPassingOwnership*/false); }
149 const ScPatternAttr* SetPattern( SCROW nRow, std::unique_ptr<ScPatternAttr> pPattern, bool bPutToPool = false )
150 { return SetPatternAreaImpl(nRow, nRow, pPattern.release(), bPutToPool, nullptr, /*bPassingOwnership*/true); }
151 void SetPatternArea( SCROW nStartRow, SCROW nEndRow, std::unique_ptr<ScPatternAttr> pPattern,
152 bool bPutToPool = false, ScEditDataArray* pDataArray = nullptr)
153 { SetPatternAreaImpl(nStartRow, nEndRow, pPattern.release(), bPutToPool, pDataArray, /*bPassingOwnership*/true); }
154 void SetPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr* pPattern,
155 bool bPutToPool = false, ScEditDataArray* pDataArray = nullptr)
156 { SetPatternAreaImpl(nStartRow, nEndRow, pPattern, bPutToPool, pDataArray, /*bPassingOwnership*/false); }
157 void ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle );
158 void ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, ScItemPoolCache* pCache,
159 ScEditDataArray* pDataArray = nullptr, bool* const pIsChanged = nullptr );
160 void SetAttrEntries(std::vector<ScAttrEntry> && vNewData);
161 void ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
162 const ::editeng::SvxBorderLine* pLine, bool bColorOnly );
164 void AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex );
165 /// if nIndex == 0, remove all conditional format data
166 void RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex );
168 void ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich );
169 void ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement );
171 /// Including current, may return -1
172 SCROW GetNextUnprotected( SCROW nRow, bool bUp ) const;
174 /// May return -1 if not found
175 SCROW SearchStyle(
176 SCROW nRow, const ScStyleSheet* pSearchStyle, bool bUp,
177 const ScMarkArray* pMarkArray = nullptr) const;
179 bool SearchStyleRange(
180 SCROW& rRow, SCROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp,
181 const ScMarkArray* pMarkArray = nullptr) const;
183 bool ApplyFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags );
184 bool RemoveFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags );
186 bool Search( SCROW nRow, SCSIZE& nIndex, std::optional<SCROW> nIndexHint = {} ) const;
188 bool HasAttrib( SCROW nRow1, SCROW nRow2, HasAttrFlags nMask ) const;
189 bool HasAttrib( SCROW nRow, HasAttrFlags nMask, SCROW* nStartRow = nullptr, SCROW* nEndRow = nullptr ) const;
190 bool IsMerged( SCROW nRow ) const;
191 bool ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
192 SCCOL& rPaintCol, SCROW& rPaintRow,
193 bool bRefresh );
194 void RemoveAreaMerge( SCROW nStartRow, SCROW nEndRow );
196 void FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset );
197 bool IsStyleSheetUsed( const ScStyleSheet& rStyle ) const;
199 void SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
200 const ScPatternAttr* pWantedPattern, bool bDefault );
201 void CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray& rAttrArray );
203 bool IsEmpty() const;
205 bool GetFirstVisibleAttr( SCROW& rFirstRow ) const;
206 bool GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData, bool bSkipEmpty ) const;
207 bool HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const;
208 bool IsVisibleEqual( const ScAttrArray& rOther,
209 SCROW nStartRow, SCROW nEndRow ) const;
210 bool IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const;
212 bool TestInsertCol( SCROW nStartRow, SCROW nEndRow) const;
213 bool TestInsertRow( SCSIZE nSize ) const;
214 void InsertRow( SCROW nStartRow, SCSIZE nSize );
215 void DeleteRow( SCROW nStartRow, SCSIZE nSize );
216 void DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex );
217 void DeleteArea( SCROW nStartRow, SCROW nEndRow );
218 void MoveTo( SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray );
219 void CopyArea(
220 SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray& rAttrArray,
221 std::unordered_map<const ScPatternAttr*, const ScPatternAttr*>* pPatternPutCache = nullptr,
222 ScMF nStripFlags = ScMF::NONE) const;
224 void DeleteHardAttr( SCROW nStartRow, SCROW nEndRow );
226 /* i123909: Pre-calculate needed memory, and pre-reserve enough memory */
227 bool Reserve( SCSIZE nReserve );
228 SCSIZE Count() const { return mvData.size(); }
229 SCSIZE Count( SCROW nRow1, SCROW nRow2 ) const;
231 private:
232 const ScPatternAttr* SetPatternAreaImpl( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr* pPattern,
233 bool bPutToPool = false, ScEditDataArray* pDataArray = nullptr,
234 bool bPassingPatternOwnership = false );
237 // Iterator for attributes
239 class ScAttrIterator
241 const ScAttrArray* pArray;
242 const ScPatternAttr* pDefPattern;
243 SCSIZE nPos;
244 SCROW nRow;
245 SCROW nEndRow;
246 public:
247 inline ScAttrIterator( const ScAttrArray* pNewArray, SCROW nStart, SCROW nEnd, const ScPatternAttr* pDefaultPattern );
248 inline const ScPatternAttr* Next( SCROW& rTop, SCROW& rBottom );
249 inline const ScPatternAttr* Resync( SCROW nRow, SCROW& rTop, SCROW& rBottom );
250 SCROW GetNextRow() const { return nRow; }
253 inline ScAttrIterator::ScAttrIterator( const ScAttrArray* pNewArray, SCROW nStart, SCROW nEnd, const ScPatternAttr* pDefaultPattern ) :
254 pArray( pNewArray ),
255 pDefPattern( pDefaultPattern ),
256 nRow( nStart ),
257 nEndRow( nEnd )
259 if ( pArray->Count() )
261 if ( nStart > 0 )
262 pArray->Search( nStart, nPos );
263 else
264 nPos = 0;
266 else
267 nPos = 0;
270 inline const ScPatternAttr* ScAttrIterator::Next( SCROW& rTop, SCROW& rBottom )
272 const ScPatternAttr* pRet;
273 if ( !pArray->Count() )
275 if ( !nPos )
277 ++nPos;
278 if ( nRow > pArray->GetDoc().MaxRow())
279 return nullptr;
280 rTop = nRow;
281 rBottom = std::min( nEndRow, pArray->GetDoc().MaxRow());
282 nRow = rBottom + 1;
283 return pDefPattern;
285 return nullptr;
288 if ( nPos < pArray->Count() && nRow <= nEndRow )
290 rTop = nRow;
291 rBottom = std::min( pArray->mvData[nPos].nEndRow, nEndRow );
292 pRet = pArray->mvData[nPos].pPattern;
293 nRow = rBottom + 1;
294 ++nPos;
296 else
297 pRet = nullptr;
298 return pRet;
301 inline const ScPatternAttr* ScAttrIterator::Resync( SCROW nRowP, SCROW& rTop, SCROW& rBottom )
303 nRow = nRowP;
304 if ( !pArray->Count() )
306 nPos = 0;
307 return Next( rTop, rBottom );
309 // Chances are high that the pattern changed on nRowP introduced a span
310 // starting right there. Assume that Next() was called so nPos already
311 // advanced. Another high chance is that the change extended a previous or
312 // next pattern. In all these cases we don't need to search.
313 if (3 <= nPos && nPos <= pArray->Count() && pArray->mvData[nPos-3].nEndRow < nRowP &&
314 nRowP <= pArray->mvData[nPos-2].nEndRow)
315 nPos -= 2;
316 else if (2 <= nPos && nPos <= pArray->Count() && pArray->mvData[nPos-2].nEndRow < nRowP &&
317 nRowP <= pArray->mvData[nPos-1].nEndRow)
318 --nPos;
319 else if (pArray->Count() > 0 && nRowP <= pArray->mvData[0].nEndRow)
320 nPos = 0;
321 else
322 pArray->Search( nRowP, nPos );
323 return Next( rTop, rBottom);
326 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */