Line data Source code
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 :
21 : #include "txatbase.hxx"
22 : #include "ndhints.hxx"
23 : #include <txtatr.hxx>
24 :
25 : #ifdef DBG_UTIL
26 : #include <pam.hxx>
27 : #endif
28 :
29 :
30 : inline void DumpHints(const SwpHtStart &, const SwpHtEnd &) { }
31 :
32 : /*************************************************************************
33 : * IsLessStart()
34 : *************************************************************************/
35 :
36 : // Sortierreihenfolge: Start, Ende (umgekehrt!), Which-Wert (umgekehrt!),
37 : // als letztes die Adresse selbst
38 :
39 765150 : static bool lcl_IsLessStart( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
40 : {
41 765150 : if ( *rHt1.GetStart() == *rHt2.GetStart() )
42 : {
43 36058 : const xub_StrLen nHt1 = *rHt1.GetAnyEnd();
44 36058 : const xub_StrLen nHt2 = *rHt2.GetAnyEnd();
45 36058 : if ( nHt1 == nHt2 )
46 : {
47 35132 : const sal_uInt16 nWhich1 = rHt1.Which();
48 35132 : const sal_uInt16 nWhich2 = rHt2.Which();
49 35132 : if ( nWhich1 == nWhich2 )
50 : {
51 35030 : if ( RES_TXTATR_CHARFMT == nWhich1 )
52 : {
53 0 : const sal_uInt16 nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
54 0 : const sal_uInt16 nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
55 0 : if ( nS1 != nS2 ) // robust
56 0 : return nS1 < nS2;
57 : }
58 :
59 35030 : return (long)&rHt1 < (long)&rHt2;
60 : }
61 : // order is important! for requirements see hintids.hxx
62 102 : return ( nWhich1 > nWhich2 );
63 : }
64 926 : return ( nHt1 > nHt2 );
65 : }
66 729092 : return ( *rHt1.GetStart() < *rHt2.GetStart() );
67 : }
68 :
69 : /*************************************************************************
70 : * inline IsLessEnd()
71 : *************************************************************************/
72 :
73 : // Zuerst nach Ende danach nach Ptr
74 781774 : static bool lcl_IsLessEnd( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
75 : {
76 781774 : const xub_StrLen nHt1 = *rHt1.GetAnyEnd();
77 781774 : const xub_StrLen nHt2 = *rHt2.GetAnyEnd();
78 781774 : if ( nHt1 == nHt2 )
79 : {
80 39968 : if ( *rHt1.GetStart() == *rHt2.GetStart() )
81 : {
82 38260 : const sal_uInt16 nWhich1 = rHt1.Which();
83 38260 : const sal_uInt16 nWhich2 = rHt2.Which();
84 38260 : if ( nWhich1 == nWhich2 )
85 : {
86 38086 : if ( RES_TXTATR_CHARFMT == nWhich1 )
87 : {
88 16 : const sal_uInt16 nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
89 16 : const sal_uInt16 nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
90 16 : if ( nS1 != nS2 ) // robust
91 0 : return nS1 > nS2;
92 : }
93 :
94 38086 : return (long)&rHt1 > (long)&rHt2;
95 : }
96 : // order is important! for requirements see hintids.hxx
97 174 : return ( nWhich1 < nWhich2 );
98 : }
99 : else
100 1708 : return ( *rHt1.GetStart() > *rHt2.GetStart() );
101 : }
102 741806 : return ( nHt1 < nHt2 );
103 : }
104 :
105 117342 : bool CompareSwpHtStart::operator()(SwTxtAttr* const lhs, SwTxtAttr* const rhs) const
106 : {
107 117342 : return lcl_IsLessStart( *lhs, *rhs );
108 : }
109 :
110 120666 : bool CompareSwpHtEnd::operator()(SwTxtAttr* const lhs, SwTxtAttr* const rhs) const
111 : {
112 120666 : return lcl_IsLessEnd( *lhs, *rhs );
113 : }
114 :
115 : /*************************************************************************
116 : * class SwpHintsArr
117 : *************************************************************************/
118 :
119 25485 : void SwpHintsArray::Insert( const SwTxtAttr *pHt )
120 : {
121 25485 : Resort();
122 : assert(m_HintStarts.find(const_cast<SwTxtAttr*>(pHt))
123 : == m_HintStarts.end()); // "Insert: hint already in HtStart"
124 : assert(m_HintEnds.find(const_cast<SwTxtAttr*>(pHt))
125 : == m_HintEnds.end()); // "Insert: hint already in HtEnd"
126 25485 : m_HintStarts.insert( const_cast<SwTxtAttr*>(pHt) );
127 25485 : m_HintEnds .insert( const_cast<SwTxtAttr*>(pHt) );
128 25485 : }
129 :
130 19038 : void SwpHintsArray::DeleteAtPos( const sal_uInt16 nPos )
131 : {
132 : // optimization: nPos is the position in the Starts array
133 19038 : SwTxtAttr *pHt = m_HintStarts[ nPos ];
134 19038 : m_HintStarts.erase( m_HintStarts.begin() + nPos );
135 :
136 19038 : Resort();
137 :
138 19038 : bool const done = m_HintEnds.erase(pHt);
139 : assert(done);
140 : (void) done; // unused in NDEBUG
141 19038 : }
142 :
143 442 : sal_uInt16 SwpHintsArray::GetPos( const SwTxtAttr *pHt ) const
144 : {
145 : // DO NOT use find() here!
146 : // if called from SwTxtNode::InsertItem, pHt has already been deleted,
147 : // so it cannot be dereferenced
148 686 : for (size_t i = 0; i < m_HintStarts.size(); ++i)
149 : {
150 684 : if (m_HintStarts[i] == pHt)
151 : {
152 440 : return i;
153 : }
154 : }
155 2 : return USHRT_MAX;
156 : }
157 :
158 : #ifdef DBG_UTIL
159 :
160 : /*************************************************************************
161 : * SwpHintsArray::Check()
162 : *************************************************************************/
163 :
164 :
165 : #define CHECK_ERR(cond, text) \
166 : if(!(cond)) \
167 : { \
168 : SAL_WARN("sw.core", text); \
169 : DumpHints(m_HintStarts, m_HintEnds); \
170 : return !(const_cast<SwpHintsArray*>(this))->Resort(); \
171 : }
172 :
173 : bool SwpHintsArray::Check() const
174 : {
175 : // 1) gleiche Anzahl in beiden Arrays
176 : CHECK_ERR( m_HintStarts.size() == m_HintEnds.size(),
177 : "HintsCheck: wrong sizes" );
178 : xub_StrLen nLastStart = 0;
179 : xub_StrLen nLastEnd = 0;
180 :
181 : const SwTxtAttr *pLastStart = 0;
182 : const SwTxtAttr *pLastEnd = 0;
183 :
184 : for( sal_uInt16 i = 0; i < Count(); ++i )
185 : {
186 : // --- Start-Kontrolle ---
187 :
188 : // 2a) gueltiger Pointer? vgl. DELETEFF
189 : const SwTxtAttr *pHt = m_HintStarts[i];
190 : CHECK_ERR( 0xFF != *(unsigned char*)pHt, "HintsCheck: start ptr was deleted" );
191 :
192 : // 3a) Stimmt die Start-Sortierung?
193 : xub_StrLen nIdx = *pHt->GetStart();
194 : CHECK_ERR( nIdx >= nLastStart, "HintsCheck: starts are unsorted" );
195 :
196 : // 4a) IsLessStart-Konsistenz
197 : if( pLastStart )
198 : CHECK_ERR( lcl_IsLessStart( *pLastStart, *pHt ), "HintsCheck: IsLastStart" );
199 :
200 : nLastStart = nIdx;
201 : pLastStart = pHt;
202 :
203 : // --- End-Kontrolle ---
204 :
205 : // 2b) gueltiger Pointer? vgl. DELETEFF
206 : const SwTxtAttr *pHtEnd = m_HintEnds[i];
207 : CHECK_ERR( 0xFF != *(unsigned char*)pHtEnd, "HintsCheck: end ptr was deleted" );
208 :
209 : // 3b) Stimmt die End-Sortierung?
210 : nIdx = *pHtEnd->GetAnyEnd();
211 : CHECK_ERR( nIdx >= nLastEnd, "HintsCheck: ends are unsorted" );
212 : nLastEnd = nIdx;
213 :
214 : // 4b) IsLessEnd-Konsistenz
215 : if( pLastEnd )
216 : CHECK_ERR( lcl_IsLessEnd( *pLastEnd, *pHtEnd ), "HintsCheck: IsLastEnd" );
217 :
218 : nLastEnd = nIdx;
219 : pLastEnd = pHtEnd;
220 :
221 : // --- Ueberkreuzungen ---
222 :
223 : // 5) gleiche Pointer in beiden Arrays
224 : if (m_HintStarts.find(const_cast<SwTxtAttr*>(pHt)) == m_HintStarts.end())
225 : nIdx = STRING_LEN;
226 :
227 : CHECK_ERR( STRING_LEN != nIdx, "HintsCheck: no GetStartOf" );
228 :
229 : // 6) gleiche Pointer in beiden Arrays
230 : if (m_HintEnds.find(const_cast<SwTxtAttr*>(pHt)) == m_HintEnds.end())
231 : nIdx = STRING_LEN;
232 :
233 : CHECK_ERR( STRING_LEN != nIdx, "HintsCheck: no GetEndOf" );
234 :
235 : // 7a) character attributes in array?
236 : sal_uInt16 nWhich = pHt->Which();
237 : CHECK_ERR( !isCHRATR(nWhich),
238 : "HintsCheck: Character attribute in start array" );
239 :
240 : // 7b) character attributes in array?
241 : nWhich = pHtEnd->Which();
242 : CHECK_ERR( !isCHRATR(nWhich),
243 : "HintsCheck: Character attribute in end array" );
244 :
245 : // 8) style portion check
246 : const SwTxtAttr* pHtThis = m_HintStarts[i];
247 : const SwTxtAttr* pHtLast = i > 0 ? m_HintStarts[i-1] : 0;
248 : CHECK_ERR( (0 == i)
249 : || ( (RES_TXTATR_CHARFMT != pHtLast->Which())
250 : && (RES_TXTATR_AUTOFMT != pHtLast->Which()))
251 : || ( (RES_TXTATR_CHARFMT != pHtThis->Which())
252 : && (RES_TXTATR_AUTOFMT != pHtThis->Which()))
253 : || (*pHtThis->GetStart() >= *pHtLast->GetEnd()) // no overlap
254 : || ( ( (*pHtThis->GetStart() == *pHtLast->GetStart())
255 : && (*pHtThis->GetEnd() == *pHtLast->GetEnd())
256 : ) // same range
257 : && ( (pHtThis->Which() != RES_TXTATR_AUTOFMT)
258 : || (pHtLast->Which() != RES_TXTATR_AUTOFMT)
259 : ) // never two AUTOFMT on same range
260 : && ( (pHtThis->Which() != RES_TXTATR_CHARFMT)
261 : || (pHtLast->Which() != RES_TXTATR_CHARFMT)
262 : || (static_cast<const SwTxtCharFmt *>(pHtThis)
263 : ->GetSortNumber() !=
264 : static_cast<const SwTxtCharFmt *>(pHtLast)
265 : ->GetSortNumber())
266 : ) // multiple CHARFMT on same range need distinct sortnr
267 : )
268 : || (*pHtThis->GetStart() == *pHtThis->GetEnd()), // this empty
269 : "HintsCheck: Portion inconsistency. "
270 : "This can be temporarily ok during undo operations" );
271 :
272 : // 9) nesting portion check
273 : if (pHtThis->IsNesting())
274 : {
275 : for ( sal_uInt16 j = 0; j < Count(); ++j )
276 : {
277 : SwTxtAttr const * const pOther( m_HintStarts[j] );
278 : if ( pOther->IsNesting() && (i != j) )
279 : {
280 : SwComparePosition cmp = ComparePosition(
281 : *pHtThis->GetStart(), *pHtThis->GetEnd(),
282 : *pOther->GetStart(), *pOther->GetEnd());
283 : CHECK_ERR( (POS_OVERLAP_BEFORE != cmp) &&
284 : (POS_OVERLAP_BEHIND != cmp),
285 : "HintsCheck: overlapping nesting hints!!!" );
286 : }
287 : }
288 : }
289 :
290 : // 10) dummy char check (unfortunately cannot check SwTxtNode::m_Text)
291 : if (pHtThis->HasDummyChar())
292 : {
293 : for ( sal_uInt16 j = 0; j < i; ++j )
294 : {
295 : SwTxtAttr const * const pOther( m_HintStarts[j] );
296 : if (pOther->HasDummyChar())
297 : {
298 : CHECK_ERR( (*pOther->GetStart() != *pHtThis->GetStart()),
299 : "HintsCheck: multiple hints claim same CH_TXTATR!");
300 : }
301 : }
302 : }
303 : }
304 : return true;
305 : }
306 :
307 : #endif /* DBG_UTIL */
308 :
309 : /*************************************************************************
310 : * SwpHintsArray::Resort()
311 : *************************************************************************/
312 :
313 : // Resort() wird vor jedem Insert und Delete gerufen.
314 : // Wenn Textmasse geloescht wird, so werden die Indizes in
315 : // ndtxt.cxx angepasst. Leider erfolgt noch keine Neusortierung
316 : // auf gleichen Positionen.
317 :
318 66753 : bool SwpHintsArray::Resort()
319 : {
320 66753 : bool bResort = false;
321 66753 : const SwTxtAttr *pLast = 0;
322 : sal_uInt16 i;
323 :
324 767901 : for ( i = 0; i < m_HintStarts.size(); ++i )
325 : {
326 701148 : SwTxtAttr *pHt = m_HintStarts[i];
327 701148 : if( pLast && !lcl_IsLessStart( *pLast, *pHt ) )
328 : {
329 4 : m_HintStarts.erase( m_HintStarts.begin() + i );
330 4 : m_HintStarts.insert( pHt );
331 4 : pHt = m_HintStarts[i];
332 4 : if ( pHt != pLast )
333 0 : --i;
334 4 : bResort = true;
335 : }
336 701148 : pLast = pHt;
337 : }
338 :
339 66753 : pLast = 0;
340 786939 : for ( i = 0; i < m_HintEnds.size(); ++i )
341 : {
342 720186 : SwTxtAttr *pHt = m_HintEnds[i];
343 720186 : if( pLast && !lcl_IsLessEnd( *pLast, *pHt ) )
344 : {
345 4 : m_HintEnds.erase( m_HintEnds.begin() + i );
346 4 : m_HintEnds.insert( pHt );
347 4 : pHt = m_HintEnds[i]; // normalerweise == pLast
348 : // Wenn die Unordnung etwas groesser ist (24200),
349 : // muessen wir Position i erneut vergleichen.
350 4 : if ( pLast != pHt )
351 0 : --i;
352 4 : bResort = true;
353 : }
354 720186 : pLast = pHt;
355 : }
356 66753 : return bResort;
357 : }
358 :
359 :
360 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|