LCOV - code coverage report
Current view: top level - sw/source/core/txtnode - ndhints.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 56 58 96.6 %
Date: 2015-06-13 12:38:46 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          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             : #include "txatbase.hxx"
      21             : #include "ndhints.hxx"
      22             : #include <txtatr.hxx>
      23             : 
      24             : #ifdef DBG_UTIL
      25             : #include <pam.hxx>
      26             : #include <fmtautofmt.hxx>
      27             : #include <set>
      28             : #endif
      29             : 
      30             : // Sortierreihenfolge: Start, Ende (umgekehrt!), Which-Wert (umgekehrt!),
      31             : //                     als letztes die Adresse selbst
      32             : 
      33     2445875 : static bool lcl_IsLessStart( const SwTextAttr &rHt1, const SwTextAttr &rHt2 )
      34             : {
      35     2445875 :     if ( rHt1.GetStart() == rHt2.GetStart() )
      36             :     {
      37      186874 :         const sal_Int32 nHt1 = *rHt1.GetAnyEnd();
      38      186874 :         const sal_Int32 nHt2 = *rHt2.GetAnyEnd();
      39      186874 :         if ( nHt1 == nHt2 )
      40             :         {
      41      137306 :             const sal_uInt16 nWhich1 = rHt1.Which();
      42      137306 :             const sal_uInt16 nWhich2 = rHt2.Which();
      43      137306 :             if ( nWhich1 == nWhich2 )
      44             :             {
      45       83478 :                 if ( RES_TXTATR_CHARFMT == nWhich1 )
      46             :                 {
      47             :                     const sal_uInt16 nS1 =
      48        3131 :                         static_txtattr_cast<const SwTextCharFormat&>(rHt1).GetSortNumber();
      49             :                     const sal_uInt16 nS2 =
      50        3131 :                         static_txtattr_cast<const SwTextCharFormat&>(rHt2).GetSortNumber();
      51        3131 :                     if ( nS1 != nS2 ) // robust
      52           0 :                         return nS1 < nS2;
      53             :                 }
      54             : 
      55       83478 :                 return reinterpret_cast<sal_IntPtr>(&rHt1) < reinterpret_cast<sal_IntPtr>(&rHt2);
      56             :             }
      57             :             // order is important! for requirements see hintids.hxx
      58       53828 :             return ( nWhich1 > nWhich2 );
      59             :         }
      60       49568 :         return ( nHt1 > nHt2 );
      61             :     }
      62     2259001 :     return ( rHt1.GetStart() < rHt2.GetStart() );
      63             : }
      64             : 
      65             : // Zuerst nach Ende danach nach Ptr
      66     2553747 : static bool lcl_IsLessEnd( const SwTextAttr &rHt1, const SwTextAttr &rHt2 )
      67             : {
      68     2553747 :     const sal_Int32 nHt1 = *rHt1.GetAnyEnd();
      69     2553747 :     const sal_Int32 nHt2 = *rHt2.GetAnyEnd();
      70     2553747 :     if ( nHt1 == nHt2 )
      71             :     {
      72      247876 :         if ( rHt1.GetStart() == rHt2.GetStart() )
      73             :         {
      74      150165 :             const sal_uInt16 nWhich1 = rHt1.Which();
      75      150165 :             const sal_uInt16 nWhich2 = rHt2.Which();
      76      150165 :             if ( nWhich1 == nWhich2 )
      77             :             {
      78       92879 :                 if ( RES_TXTATR_CHARFMT == nWhich1 )
      79             :                 {
      80             :                     const sal_uInt16 nS1 =
      81        3252 :                         static_txtattr_cast<const SwTextCharFormat&>(rHt1).GetSortNumber();
      82             :                     const sal_uInt16 nS2 =
      83        3252 :                         static_txtattr_cast<const SwTextCharFormat&>(rHt2).GetSortNumber();
      84        3252 :                     if ( nS1 != nS2 ) // robust
      85           0 :                         return nS1 > nS2;
      86             :                 }
      87             : 
      88       92879 :                 return reinterpret_cast<sal_IntPtr>(&rHt1) > reinterpret_cast<sal_IntPtr>(&rHt2);
      89             :             }
      90             :             // order is important! for requirements see hintids.hxx
      91       57286 :             return ( nWhich1 < nWhich2 );
      92             :         }
      93             :         else
      94       97711 :             return ( rHt1.GetStart() > rHt2.GetStart() );
      95             :     }
      96     2305871 :     return ( nHt1 < nHt2 );
      97             : }
      98             : 
      99     2445875 : bool CompareSwpHtStart::operator()(SwTextAttr* const lhs, SwTextAttr* const rhs) const
     100             : {
     101     2445875 :   return lcl_IsLessStart( *lhs, *rhs );
     102             : }
     103             : 
     104     2553747 : bool CompareSwpHtEnd::operator()(SwTextAttr* const lhs, SwTextAttr* const rhs) const
     105             : {
     106     2553747 :   return lcl_IsLessEnd( *lhs, *rhs );
     107             : }
     108             : 
     109       84857 : void SwpHintsArray::Insert( const SwTextAttr *pHt )
     110             : {
     111       84857 :     Resort();
     112             :     assert(m_HintStarts.find(const_cast<SwTextAttr*>(pHt))
     113             :             == m_HintStarts.end()); // "Insert: hint already in HtStart"
     114             :     assert(m_HintEnds.find(const_cast<SwTextAttr*>(pHt))
     115             :             == m_HintEnds.end());   // "Insert: hint already in HtEnd"
     116       84857 :     m_HintStarts.insert( const_cast<SwTextAttr*>(pHt) );
     117       84857 :     m_HintEnds  .insert( const_cast<SwTextAttr*>(pHt) );
     118       84857 : }
     119             : 
     120       45777 : void SwpHintsArray::DeleteAtPos( const size_t nPos )
     121             : {
     122             :     // optimization: nPos is the position in the Starts array
     123       45777 :     SwTextAttr *pHt = m_HintStarts[ nPos ];
     124       45777 :     m_HintStarts.erase( m_HintStarts.begin() + nPos );
     125             : 
     126       45777 :     Resort();
     127             : 
     128       45777 :     bool const done = m_HintEnds.erase(pHt);
     129             :     assert(done);
     130             :     (void) done; // unused in NDEBUG
     131       45777 : }
     132             : 
     133        6807 : bool SwpHintsArray::Contains( const SwTextAttr *pHt ) const
     134             : {
     135             :     // DO NOT use find() or CHECK here!
     136             :     // if called from SwTextNode::InsertItem, pHt has already been deleted,
     137             :     // so it cannot be dereferenced
     138        9599 :     for (size_t i = 0; i < m_HintStarts.size(); ++i)
     139             :     {
     140        9589 :         if (m_HintStarts[i] == pHt)
     141             :         {
     142        6797 :             return true;
     143             :         }
     144             :     }
     145          10 :     return false;
     146             : }
     147             : 
     148             : #ifdef DBG_UTIL
     149             : 
     150             : #define CHECK_ERR(cond, text) \
     151             :         if(!(cond)) \
     152             :         { \
     153             :             SAL_WARN("sw.core", text); \
     154             :             (const_cast<SwpHintsArray*>(this))->Resort(); \
     155             :             return false; \
     156             :         }
     157             : 
     158             : bool SwpHintsArray::Check(bool bPortionsMerged) const
     159             : {
     160             :     // 1) gleiche Anzahl in beiden Arrays
     161             :     CHECK_ERR( m_HintStarts.size() == m_HintEnds.size(),
     162             :         "HintsCheck: wrong sizes" );
     163             :     sal_Int32 nLastStart = 0;
     164             :     sal_Int32 nLastEnd   = 0;
     165             : 
     166             :     const SwTextAttr *pLastStart = 0;
     167             :     const SwTextAttr *pLastEnd = 0;
     168             :     std::set<SwTextAttr const*> RsidOnlyAutoFormats;
     169             :     if (bPortionsMerged)
     170             :     {
     171             :         for (size_t i = 0; i < Count(); ++i)
     172             :         {
     173             :             SwTextAttr const*const pHint(m_HintStarts[i]);
     174             :             if (RES_TXTATR_AUTOFMT == pHint->Which())
     175             :             {
     176             :                 std::shared_ptr<SfxItemSet> const pSet(
     177             :                         pHint->GetAutoFormat().GetStyleHandle());
     178             :                 if (pSet->Count() == 1 && pSet->GetItem(RES_CHRATR_RSID, false))
     179             :                 {
     180             :                     RsidOnlyAutoFormats.insert(pHint);
     181             :                 }
     182             :             }
     183             :         }
     184             :     }
     185             : 
     186             :     for( size_t i = 0; i < Count(); ++i )
     187             :     {
     188             :         // --- Start-Kontrolle ---
     189             : 
     190             :         // 2a) gueltiger Pointer? vgl. DELETEFF
     191             :         const SwTextAttr *pHt = m_HintStarts[i];
     192             :         CHECK_ERR( 0xFF != *reinterpret_cast<unsigned char const *>(pHt), "HintsCheck: start ptr was deleted" );
     193             : 
     194             :         // 3a) Stimmt die Start-Sortierung?
     195             :         sal_Int32 nIdx = pHt->GetStart();
     196             :         CHECK_ERR( nIdx >= nLastStart, "HintsCheck: starts are unsorted" );
     197             : 
     198             :         // 4a) IsLessStart-Konsistenz
     199             :         if( pLastStart )
     200             :             CHECK_ERR( lcl_IsLessStart( *pLastStart, *pHt ), "HintsCheck: IsLastStart" );
     201             : 
     202             :         nLastStart = nIdx;
     203             :         pLastStart = pHt;
     204             : 
     205             :         // --- End-Kontrolle ---
     206             : 
     207             :         // 2b) gueltiger Pointer? vgl. DELETEFF
     208             :         const SwTextAttr *pHtEnd = m_HintEnds[i];
     209             :         CHECK_ERR( 0xFF != *reinterpret_cast<unsigned char const *>(pHtEnd), "HintsCheck: end ptr was deleted" );
     210             : 
     211             :         // 3b) Stimmt die End-Sortierung?
     212             :         nIdx = *pHtEnd->GetAnyEnd();
     213             :         CHECK_ERR( nIdx >= nLastEnd, "HintsCheck: ends are unsorted" );
     214             :         nLastEnd = nIdx;
     215             : 
     216             :         // 4b) IsLessEnd-Konsistenz
     217             :         if( pLastEnd )
     218             :             CHECK_ERR( lcl_IsLessEnd( *pLastEnd, *pHtEnd ), "HintsCheck: IsLastEnd" );
     219             : 
     220             :         nLastEnd = nIdx;
     221             :         pLastEnd = pHtEnd;
     222             : 
     223             :         // --- Ueberkreuzungen ---
     224             : 
     225             :         // 5) gleiche Pointer in beiden Arrays
     226             :         if (m_HintStarts.find(const_cast<SwTextAttr*>(pHt)) == m_HintStarts.end())
     227             :             nIdx = COMPLETE_STRING;
     228             : 
     229             :         CHECK_ERR( COMPLETE_STRING != nIdx, "HintsCheck: no GetStartOf" );
     230             : 
     231             :         // 6) gleiche Pointer in beiden Arrays
     232             :         if (m_HintEnds.find(const_cast<SwTextAttr*>(pHt)) == m_HintEnds.end())
     233             :             nIdx = COMPLETE_STRING;
     234             : 
     235             :         CHECK_ERR( COMPLETE_STRING != nIdx, "HintsCheck: no GetEndOf" );
     236             : 
     237             :         // 7a) character attributes in array?
     238             :         sal_uInt16 nWhich = pHt->Which();
     239             :         CHECK_ERR( !isCHRATR(nWhich),
     240             :                    "HintsCheck: Character attribute in start array" );
     241             : 
     242             :         // 7b) character attributes in array?
     243             :         nWhich = pHtEnd->Which();
     244             :         CHECK_ERR( !isCHRATR(nWhich),
     245             :                    "HintsCheck: Character attribute in end array" );
     246             : 
     247             :         // 8) style portion check
     248             :         const SwTextAttr* pHtThis = m_HintStarts[i];
     249             :         const SwTextAttr* pHtLast = i > 0 ? m_HintStarts[i-1] : 0;
     250             :         CHECK_ERR( (0 == i)
     251             :             ||  (   (RES_TXTATR_CHARFMT != pHtLast->Which())
     252             :                 &&  (RES_TXTATR_AUTOFMT != pHtLast->Which()))
     253             :             ||  (   (RES_TXTATR_CHARFMT != pHtThis->Which())
     254             :                 &&  (RES_TXTATR_AUTOFMT != pHtThis->Which()))
     255             :             ||  (pHtThis->GetStart() >= *pHtLast->End()) // no overlap
     256             :             ||  (   (   (pHtThis->GetStart() == pHtLast->GetStart())
     257             :                     &&  (*pHtThis->End()   == *pHtLast->End())
     258             :                     ) // same range
     259             :                 &&  (   (pHtThis->Which() != RES_TXTATR_AUTOFMT)
     260             :                     ||  (pHtLast->Which() != RES_TXTATR_AUTOFMT)
     261             :                     ) // never two AUTOFMT on same range
     262             :                 &&  (   (pHtThis->Which() != RES_TXTATR_CHARFMT)
     263             :                     ||  (pHtLast->Which() != RES_TXTATR_CHARFMT)
     264             :                     ||  (static_txtattr_cast<const SwTextCharFormat *>(pHtThis)
     265             :                                 ->GetSortNumber() !=
     266             :                          static_txtattr_cast<const SwTextCharFormat *>(pHtLast)
     267             :                                 ->GetSortNumber())
     268             :                     ) // multiple CHARFMT on same range need distinct sortnr
     269             :                 )
     270             :             ||  (pHtThis->GetStart() == *pHtThis->End()), // this empty
     271             :                    "HintsCheck: Portion inconsistency. "
     272             :                    "This can be temporarily ok during undo operations" );
     273             : 
     274             :         // 8 1/2) format ignore start/end flag check
     275             :         // (problems because MergePortions buggy or not called)
     276             :         if (bPortionsMerged)
     277             :         {
     278             :             if (RES_TXTATR_AUTOFMT == pHt->Which() ||
     279             :                 RES_TXTATR_CHARFMT == pHt->Which())
     280             :             {
     281             :                 // mostly ignore the annoying no-length hints
     282             :                 // BuildPortions inserts these in the middle of an existing one
     283             :                 bool const bNoLength(pHt->GetStart() == *pHt->End());
     284             :                 bool bNeedContinuation(!bNoLength && pHt->IsFormatIgnoreEnd());
     285             :                 bool bForbidContinuation(!bNoLength && !bNeedContinuation);
     286             :                 if (RES_TXTATR_AUTOFMT == pHt->Which())
     287             :                 {
     288             :                     if (RsidOnlyAutoFormats.find(pHt) != RsidOnlyAutoFormats.end())
     289             :                     {
     290             :                         assert(pHt->IsFormatIgnoreStart());
     291             :                         bNeedContinuation = false;
     292             :                         // don't forbid continuation - may be other hint here!
     293             :                     }
     294             :                 }
     295             :                 if (bNeedContinuation || bForbidContinuation)
     296             :                 {
     297             :                     bool bFound(false);
     298             :                     for (size_t j = i + 1; j < Count(); ++j)
     299             :                     {
     300             :                         SwTextAttr *const pOther(m_HintStarts[j]);
     301             :                         if (pOther->GetStart() > *pHt->End())
     302             :                         {
     303             :                             break; // done
     304             :                         }
     305             :                         else if (pOther->GetStart() == *pOther->GetAnyEnd())
     306             :                         {
     307             :                             continue; // empty hint: ignore
     308             :                         }
     309             :                         else if (pOther->GetStart() == *pHt->End())
     310             :                         {
     311             :                             if (RES_TXTATR_AUTOFMT == pOther->Which() ||
     312             :                                 RES_TXTATR_CHARFMT == pOther->Which())
     313             :                             {   // multiple charfmt on same range must all match
     314             :                                 if (bNeedContinuation)
     315             :                                 {
     316             :                                     assert(pOther->IsFormatIgnoreStart());
     317             :                                     bFound = true;
     318             :                                 }
     319             :                                 else if (bForbidContinuation &&
     320             :                                          (RsidOnlyAutoFormats.find(pOther) ==
     321             :                                           RsidOnlyAutoFormats.end()))
     322             :                                 {
     323             :                                     assert(!pOther->IsFormatIgnoreStart());
     324             :                                 }
     325             :                             }
     326             :                         }
     327             :                     }
     328             :                     if (bNeedContinuation)
     329             :                     {
     330             :                         assert(bFound); // ? can this happen temp. during undo?
     331             :                     }
     332             :                 }
     333             :             }
     334             :             else
     335             :             {
     336             :                 assert(!pHt->IsFormatIgnoreStart());
     337             :                 assert(!pHt->IsFormatIgnoreEnd());
     338             :             }
     339             :         }
     340             : 
     341             :         // 9) nesting portion check
     342             :         if (pHtThis->IsNesting())
     343             :         {
     344             :             for ( size_t j = 0; j < Count(); ++j )
     345             :             {
     346             :                 SwTextAttr const * const pOther( m_HintStarts[j] );
     347             :                 if ( pOther->IsNesting() &&  (i != j) )
     348             :                 {
     349             :                     SwComparePosition cmp = ComparePosition(
     350             :                         pHtThis->GetStart(), *pHtThis->End(),
     351             :                         pOther->GetStart(), *pOther->End());
     352             :                     CHECK_ERR( (POS_OVERLAP_BEFORE != cmp) &&
     353             :                                (POS_OVERLAP_BEHIND != cmp),
     354             :                         "HintsCheck: overlapping nesting hints!!!" );
     355             :                 }
     356             :             }
     357             :         }
     358             : 
     359             :         // 10) dummy char check (unfortunately cannot check SwTextNode::m_Text)
     360             :         if (pHtThis->HasDummyChar())
     361             :         {
     362             :             for ( size_t j = 0; j < i; ++j )
     363             :             {
     364             :                 SwTextAttr const * const pOther( m_HintStarts[j] );
     365             :                 if (pOther->HasDummyChar())
     366             :                 {
     367             :                     CHECK_ERR( (pOther->GetStart() != pHtThis->GetStart()),
     368             :                         "HintsCheck: multiple hints claim same CH_TXTATR!");
     369             :                 }
     370             :             }
     371             :         }
     372             :     }
     373             :     return true;
     374             : }
     375             : 
     376             : #endif      /* DBG_UTIL */
     377             : 
     378             : // Resort() is called before every Insert and Delete.
     379             : // Various SwTextNode methods modify hints in a way that violates the
     380             : // sort order of the m_HintStarts, m_HintEnds arrays, so this method is needed
     381             : // to restore the order.
     382             : 
     383      231084 : void SwpHintsArray::Resort()
     384             : {
     385      231084 :     m_HintStarts.Resort();
     386      231084 :     m_HintEnds.Resort();
     387      231084 : }
     388             : 
     389             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11