1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26
27
28
29 #include "txatbase.hxx"
30 #include "ndhints.hxx"
31 #include <txtatr.hxx>
32
33 #ifndef PRODUCT
34 #include <pam.hxx>
35 #endif
36
37
_SV_IMPL_SORTAR_ALG(SwpHtStart,SwTxtAttr *)38 _SV_IMPL_SORTAR_ALG( SwpHtStart, SwTxtAttr* )
39 _SV_IMPL_SORTAR_ALG( SwpHtEnd, SwTxtAttr* )
40
41 #ifdef NIE
42
43 void DumpHints( const SwpHtStart &rHtStart,
44 const SwpHtEnd &rHtEnd )
45 {
46 #ifdef DBG_UTIL
47 aDbstream << "DumpHints:" << endl;
48 (aDbstream << "\tStarts:" ).WriteNumber(rHtStart.Count()) << endl;
49 for( sal_uInt16 i = 0; i < rHtStart.Count(); ++i )
50 {
51 const SwTxtAttr *pHt = rHtStart[i];
52 ((((aDbstream << '\t').WriteNumber( i )<< " [").WriteNumber( pHt->Which() )
53 << ']' << '\t').WriteNumber( long( pHt ) )
54 << '\t').WriteNumber( *pHt->GetStart() );
55 if( pHt->End() )
56 (aDbstream << " -> " ).WriteNumber( *pHt->End() );
57 aDbstream << endl;
58 }
59 (aDbstream << "\tEnds:").WriteNumber( rHtEnd.Count() )<< endl;
60 for( i = 0; i < rHtEnd.Count(); ++i )
61 {
62 const SwTxtAttr *pHt = rHtEnd[i];
63 (((aDbstream << '\t').WriteNumber( i )<< " [").WriteNumber( pHt->Which() )
64 << ']' << '\t' ).WriteNumber( long( pHt ) );
65 if( pHt->End() )
66 (aDbstream << '\t').WriteNumber( *pHt->End() )<< " <- ";
67 aDbstream.WriteNumber( *pHt->GetStart() )<< endl;
68 }
69 aDbstream << endl;
70 #endif
71 }
72 #else
73 inline void DumpHints(const SwpHtStart &, const SwpHtEnd &) { }
74 #endif
75
76 /*************************************************************************
77 * inline IsEqual()
78 *************************************************************************/
79
IsEqual(const SwTxtAttr & rHt1,const SwTxtAttr & rHt2)80 inline sal_Bool IsEqual( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
81 {
82 return (long)(&rHt1) == (long)(&rHt2);
83 }
84
85 /*************************************************************************
86 * IsLessStart()
87 *************************************************************************/
88
89 // SV_IMPL_OP_PTRARR_SORT( SwpHtStart, SwTxtAttr* )
90 // kein SV_IMPL_PTRARR_SORT( name,ArrElement )
91 // unser SEEK_PTR_TO_OBJECT_NOTL( name,ArrElement )
92
93 // Sortierreihenfolge: Start, Ende (umgekehrt!), Which-Wert (umgekehrt!),
94 // als letztes die Adresse selbst
95
lcl_IsLessStart(const SwTxtAttr & rHt1,const SwTxtAttr & rHt2)96 static sal_Bool lcl_IsLessStart( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
97 {
98 if ( *rHt1.GetStart() == *rHt2.GetStart() )
99 {
100 const xub_StrLen nHt1 = *rHt1.GetAnyEnd();
101 const xub_StrLen nHt2 = *rHt2.GetAnyEnd();
102 if ( nHt1 == nHt2 )
103 {
104 const sal_uInt16 nWhich1 = rHt1.Which();
105 const sal_uInt16 nWhich2 = rHt2.Which();
106 if ( nWhich1 == nWhich2 )
107 {
108 if ( RES_TXTATR_CHARFMT == nWhich1 )
109 {
110 const sal_uInt16 nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
111 const sal_uInt16 nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
112 ASSERT( nS1 != nS2, "AUTOSTYLES: lcl_IsLessStart trouble" )
113 if ( nS1 != nS2 ) // robust
114 return nS1 < nS2;
115 }
116
117 return (long)&rHt1 < (long)&rHt2;
118 }
119 // order is important! for requirements see hintids.hxx
120 return ( nWhich1 > nWhich2 );
121 }
122 return ( nHt1 > nHt2 );
123 }
124 return ( *rHt1.GetStart() < *rHt2.GetStart() );
125 }
126
127 /*************************************************************************
128 * inline IsLessEnd()
129 *************************************************************************/
130
131 // Zuerst nach Ende danach nach Ptr
lcl_IsLessEnd(const SwTxtAttr & rHt1,const SwTxtAttr & rHt2)132 static sal_Bool lcl_IsLessEnd( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
133 {
134 const xub_StrLen nHt1 = *rHt1.GetAnyEnd();
135 const xub_StrLen nHt2 = *rHt2.GetAnyEnd();
136 if ( nHt1 == nHt2 )
137 {
138 if ( *rHt1.GetStart() == *rHt2.GetStart() )
139 {
140 const sal_uInt16 nWhich1 = rHt1.Which();
141 const sal_uInt16 nWhich2 = rHt2.Which();
142 if ( nWhich1 == nWhich2 )
143 {
144 if ( RES_TXTATR_CHARFMT == nWhich1 )
145 {
146 const sal_uInt16 nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
147 const sal_uInt16 nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
148 ASSERT( nS1 != nS2, "AUTOSTYLES: lcl_IsLessEnd trouble" )
149 if ( nS1 != nS2 ) // robust
150 return nS1 > nS2;
151 }
152
153 return (long)&rHt1 > (long)&rHt2;
154 }
155 // order is important! for requirements see hintids.hxx
156 return ( nWhich1 < nWhich2 );
157 }
158 else
159 return ( *rHt1.GetStart() > *rHt2.GetStart() );
160 }
161 return ( nHt1 < nHt2 );
162 }
163
164 /*************************************************************************
165 * SwpHtStart::Seek_Entry()
166 *************************************************************************/
167
Seek_Entry(const SwTxtAttr * pElement,sal_uInt16 * pPos) const168 sal_Bool SwpHtStart::Seek_Entry( const SwTxtAttr *pElement, sal_uInt16 *pPos ) const
169 {
170 sal_uInt16 nOben = Count(), nMitte, nUnten = 0;
171 if( nOben > 0 )
172 {
173 nOben--;
174 while( nUnten <= nOben )
175 {
176 nMitte = nUnten + ( nOben - nUnten ) / 2;
177 const SwTxtAttr *pMitte = (*this)[nMitte];
178 if( IsEqual( *pMitte, *pElement ) )
179 {
180 *pPos = nMitte;
181 return sal_True;
182 }
183 else
184 if( lcl_IsLessStart( *pMitte, *pElement ) )
185 nUnten = nMitte + 1;
186 else
187 if( nMitte == 0 )
188 {
189 *pPos = nUnten;
190 return sal_False;
191 }
192 else
193 nOben = nMitte - 1;
194 }
195 }
196 *pPos = nUnten;
197 return sal_False;
198 }
199
200 /*************************************************************************
201 * SwpHtEnd::Seek_Entry()
202 *************************************************************************/
203
Seek_Entry(const SwTxtAttr * pElement,sal_uInt16 * pPos) const204 sal_Bool SwpHtEnd::Seek_Entry( const SwTxtAttr *pElement, sal_uInt16 *pPos ) const
205 {
206 sal_uInt16 nOben = Count(), nMitte, nUnten = 0;
207 if( nOben > 0 )
208 {
209 nOben--;
210 while( nUnten <= nOben )
211 {
212 nMitte = nUnten + ( nOben - nUnten ) / 2;
213 const SwTxtAttr *pMitte = (*this)[nMitte];
214 if( IsEqual( *pMitte, *pElement ) )
215 {
216 *pPos = nMitte;
217 return sal_True;
218 }
219 else
220 if( lcl_IsLessEnd( *pMitte, *pElement ) )
221 nUnten = nMitte + 1;
222 else
223 if( nMitte == 0 )
224 {
225 *pPos = nUnten;
226 return sal_False;
227 }
228 else
229 nOben = nMitte - 1;
230 }
231 }
232 *pPos = nUnten;
233 return sal_False;
234 }
235
236 /*************************************************************************
237 * class SwpHintsArr
238 *************************************************************************/
239
Insert(const SwTxtAttr * pHt)240 void SwpHintsArray::Insert( const SwTxtAttr *pHt )
241 {
242 Resort();
243 #ifdef DBG_UTIL
244 sal_uInt16 nPos;
245 ASSERT(!m_HintStarts.Seek_Entry( pHt, &nPos ),
246 "Insert: hint already in HtStart");
247 ASSERT(!m_HintEnds.Seek_Entry( pHt, &nPos ),
248 "Insert: hint already in HtEnd");
249 #endif
250 m_HintStarts.Insert( pHt );
251 m_HintEnds.Insert( pHt );
252 #ifdef DBG_UTIL
253 #ifdef NIE
254 (aDbstream << "Insert: " ).WriteNumber( long( pHt ) ) << endl;
255 DumpHints( m_HintStarts, m_HintEnds );
256 #endif
257 #endif
258 }
259
DeleteAtPos(const sal_uInt16 nPos)260 void SwpHintsArray::DeleteAtPos( const sal_uInt16 nPos )
261 {
262 // optimization: nPos is the position in the Starts array
263 const SwTxtAttr *pHt = m_HintStarts[ nPos ];
264 m_HintStarts.Remove( nPos );
265
266 Resort();
267
268 sal_uInt16 nEndPos;
269 m_HintEnds.Seek_Entry( pHt, &nEndPos );
270 m_HintEnds.Remove( nEndPos );
271 #ifdef DBG_UTIL
272 #ifdef NIE
273 (aDbstream << "DeleteAtPos: " ).WriteNumber( long( pHt ) ) << endl;
274 DumpHints( m_HintStarts, m_HintEnds );
275 #endif
276 #endif
277 }
278
279 #ifdef DBG_UTIL
280
281 /*************************************************************************
282 * SwpHintsArray::Check()
283 *************************************************************************/
284
285
286 #define CHECK_ERR(cond, text) \
287 if(!(cond)) \
288 { \
289 ASSERT(!this, text); \
290 DumpHints(m_HintStarts, m_HintEnds); \
291 return !(const_cast<SwpHintsArray*>(this))->Resort(); \
292 }
293
Check() const294 bool SwpHintsArray::Check() const
295 {
296 // 1) gleiche Anzahl in beiden Arrays
297 CHECK_ERR( m_HintStarts.Count() == m_HintEnds.Count(),
298 "HintsCheck: wrong sizes" );
299 xub_StrLen nLastStart = 0;
300 xub_StrLen nLastEnd = 0;
301
302 const SwTxtAttr *pLastStart = 0;
303 const SwTxtAttr *pLastEnd = 0;
304
305 for( sal_uInt16 i = 0; i < Count(); ++i )
306 {
307 // --- Start-Kontrolle ---
308
309 // 2a) gueltiger Pointer? vgl. DELETEFF
310 const SwTxtAttr *pHt = m_HintStarts[i];
311 CHECK_ERR( 0xFF != *(unsigned char*)pHt, "HintsCheck: start ptr was deleted" );
312
313 // 3a) Stimmt die Start-Sortierung?
314 xub_StrLen nIdx = *pHt->GetStart();
315 CHECK_ERR( nIdx >= nLastStart, "HintsCheck: starts are unsorted" );
316
317 // 4a) IsLessStart-Konsistenz
318 if( pLastStart )
319 CHECK_ERR( lcl_IsLessStart( *pLastStart, *pHt ), "HintsCheck: IsLastStart" );
320
321 nLastStart = nIdx;
322 pLastStart = pHt;
323
324 // --- End-Kontrolle ---
325
326 // 2b) gueltiger Pointer? vgl. DELETEFF
327 const SwTxtAttr *pHtEnd = m_HintEnds[i];
328 CHECK_ERR( 0xFF != *(unsigned char*)pHtEnd, "HintsCheck: end ptr was deleted" );
329
330 // 3b) Stimmt die End-Sortierung?
331 nIdx = *pHtEnd->GetAnyEnd();
332 CHECK_ERR( nIdx >= nLastEnd, "HintsCheck: ends are unsorted" );
333 nLastEnd = nIdx;
334
335 // 4b) IsLessEnd-Konsistenz
336 if( pLastEnd )
337 CHECK_ERR( lcl_IsLessEnd( *pLastEnd, *pHtEnd ), "HintsCheck: IsLastEnd" );
338
339 nLastEnd = nIdx;
340 pLastEnd = pHtEnd;
341
342 // --- Ueberkreuzungen ---
343
344 // 5) gleiche Pointer in beiden Arrays
345 if( !m_HintStarts.Seek_Entry( pHt, &nIdx ) )
346 nIdx = STRING_LEN;
347
348 CHECK_ERR( STRING_LEN != nIdx, "HintsCheck: no GetStartOf" );
349
350 // 6) gleiche Pointer in beiden Arrays
351 if( !m_HintEnds.Seek_Entry( pHt, &nIdx ) )
352 nIdx = STRING_LEN;
353
354 CHECK_ERR( STRING_LEN != nIdx, "HintsCheck: no GetEndOf" );
355
356 // 7a) character attributes in array?
357 sal_uInt16 nWhich = pHt->Which();
358 CHECK_ERR( !isCHRATR(nWhich),
359 "HintsCheck: Character attribute in start array" );
360
361 // 7b) character attributes in array?
362 nWhich = pHtEnd->Which();
363 CHECK_ERR( !isCHRATR(nWhich),
364 "HintsCheck: Character attribute in end array" );
365
366 // 8) style portion check
367 #if OSL_DEBUG_LEVEL > 1
368 const SwTxtAttr* pHtThis = m_HintStarts[i];
369 const SwTxtAttr* pHtLast = i > 0 ? m_HintStarts[i-1] : 0;
370 CHECK_ERR( 0 == i ||
371 ( RES_TXTATR_CHARFMT != pHtLast->Which() && RES_TXTATR_AUTOFMT != pHtLast->Which() ) ||
372 ( RES_TXTATR_CHARFMT != pHtThis->Which() && RES_TXTATR_AUTOFMT != pHtThis->Which() ) ||
373 ( *pHtThis->GetStart() >= *pHtLast->End() ) ||
374 ( ( ( (*pHtThis->GetStart() == *pHtLast->GetStart())
375 && (*pHtThis->End() == *pHtLast->End())
376 ) // same range
377 || (*pHtThis->GetStart() == *pHtThis->End())
378 )
379 && ( (pHtThis->Which() != RES_TXTATR_AUTOFMT)
380 || (pHtLast->Which() != RES_TXTATR_AUTOFMT)
381 ) // never two AUTOFMT on same range
382 ),
383 "HintsCheck: Portion inconsistency. "
384 "This can be temporarily ok during undo operations" );
385
386 // 9) nesting portion check
387 if (pHtThis->IsNesting())
388 {
389 for ( sal_uInt16 j = 0; j < Count(); ++j )
390 {
391 SwTxtAttr const * const pOther( m_HintStarts[j] );
392 if ( pOther->IsNesting() && (i != j) )
393 {
394 SwComparePosition cmp = ComparePosition(
395 *pHtThis->GetStart(), *pHtThis->End(),
396 *pOther->GetStart(), *pOther->End());
397 CHECK_ERR( (POS_OVERLAP_BEFORE != cmp) &&
398 (POS_OVERLAP_BEHIND != cmp),
399 "HintsCheck: overlapping nesting hints!!!" );
400 }
401 }
402 }
403
404 // 10) dummy char check (unfortunately cannot check SwTxtNode::m_Text)
405 if (pHtThis->HasDummyChar())
406 {
407 for ( sal_uInt16 j = 0; j < i; ++j )
408 {
409 SwTxtAttr const * const pOther( m_HintStarts[j] );
410 if (pOther->HasDummyChar())
411 {
412 CHECK_ERR( (*pOther->GetStart() != *pHtThis->GetStart()),
413 "HintsCheck: multiple hints claim same CH_TXTATR!");
414 }
415 }
416 }
417 #endif
418 }
419 return true;
420 }
421
422 #endif /* PRODUCT */
423
424 /*************************************************************************
425 * SwpHintsArray::Resort()
426 *************************************************************************/
427
428 // Resort() wird vor jedem Insert und Delete gerufen.
429 // Wenn Textmasse geloescht wird, so werden die Indizes in
430 // ndtxt.cxx angepasst. Leider erfolgt noch keine Neusortierung
431 // auf gleichen Positionen.
432
Resort()433 bool SwpHintsArray::Resort()
434 {
435 bool bResort = false;
436 const SwTxtAttr *pLast = 0;
437 sal_uInt16 i;
438
439 for ( i = 0; i < m_HintStarts.Count(); ++i )
440 {
441 const SwTxtAttr *pHt = m_HintStarts[i];
442 if( pLast && !lcl_IsLessStart( *pLast, *pHt ) )
443 {
444 #ifdef NIE
445 #ifdef DBG_UTIL
446 // ASSERT( bResort, "!Resort/Start: correcting hints-array" );
447 aDbstream << "Resort: Starts" << endl;
448 DumpHints( m_HintStarts, m_HintEnds );
449 #endif
450 #endif
451 m_HintStarts.Remove( i );
452 m_HintStarts.Insert( pHt );
453 pHt = m_HintStarts[i];
454 if ( pHt != pLast )
455 --i;
456 bResort = true;
457 }
458 pLast = pHt;
459 }
460
461 pLast = 0;
462 for ( i = 0; i < m_HintEnds.Count(); ++i )
463 {
464 const SwTxtAttr *pHt = m_HintEnds[i];
465 if( pLast && !lcl_IsLessEnd( *pLast, *pHt ) )
466 {
467 #ifdef NIE
468 #ifdef DBG_UTIL
469 aDbstream << "Resort: Ends" << endl;
470 DumpHints( m_HintStarts, m_HintEnds );
471 #endif
472 #endif
473 m_HintEnds.Remove( i );
474 m_HintEnds.Insert( pHt );
475 pHt = m_HintEnds[i]; // normalerweise == pLast
476 // Wenn die Unordnung etwas groesser ist (24200),
477 // muessen wir Position i erneut vergleichen.
478 if ( pLast != pHt )
479 --i;
480 bResort = true;
481 }
482 pLast = pHt;
483 }
484 #ifdef DBG_UTIL
485 #ifdef NIE
486 aDbstream << "Resorted:" << endl;
487 DumpHints( m_HintStarts, m_HintEnds );
488 #endif
489 #endif
490 return bResort;
491 }
492
493
494