LCOV - code coverage report
Current view: top level - sw/source/core/txtnode - ndhints.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 55 58 94.8 %
Date: 2014-11-03 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     4837646 : static bool lcl_IsLessStart( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
      34             : {
      35     4837646 :     if ( rHt1.GetStart() == rHt2.GetStart() )
      36             :     {
      37      359240 :         const sal_Int32 nHt1 = *rHt1.GetAnyEnd();
      38      359240 :         const sal_Int32 nHt2 = *rHt2.GetAnyEnd();
      39      359240 :         if ( nHt1 == nHt2 )
      40             :         {
      41      262542 :             const sal_uInt16 nWhich1 = rHt1.Which();
      42      262542 :             const sal_uInt16 nWhich2 = rHt2.Which();
      43      262542 :             if ( nWhich1 == nWhich2 )
      44             :             {
      45      155354 :                 if ( RES_TXTATR_CHARFMT == nWhich1 )
      46             :                 {
      47             :                     const sal_uInt16 nS1 =
      48        6590 :                         static_txtattr_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
      49             :                     const sal_uInt16 nS2 =
      50        6590 :                         static_txtattr_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
      51        6590 :                     if ( nS1 != nS2 ) // robust
      52           0 :                         return nS1 < nS2;
      53             :                 }
      54             : 
      55      155354 :                 return (sal_IntPtr)&rHt1 < (sal_IntPtr)&rHt2;
      56             :             }
      57             :             // order is important! for requirements see hintids.hxx
      58      107188 :             return ( nWhich1 > nWhich2 );
      59             :         }
      60       96698 :         return ( nHt1 > nHt2 );
      61             :     }
      62     4478406 :     return ( rHt1.GetStart() < rHt2.GetStart() );
      63             : }
      64             : 
      65             : // Zuerst nach Ende danach nach Ptr
      66     5055167 : static bool lcl_IsLessEnd( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
      67             : {
      68     5055167 :     const sal_Int32 nHt1 = *rHt1.GetAnyEnd();
      69     5055167 :     const sal_Int32 nHt2 = *rHt2.GetAnyEnd();
      70     5055167 :     if ( nHt1 == nHt2 )
      71             :     {
      72      480403 :         if ( rHt1.GetStart() == rHt2.GetStart() )
      73             :         {
      74      291327 :             const sal_uInt16 nWhich1 = rHt1.Which();
      75      291327 :             const sal_uInt16 nWhich2 = rHt2.Which();
      76      291327 :             if ( nWhich1 == nWhich2 )
      77             :             {
      78      176319 :                 if ( RES_TXTATR_CHARFMT == nWhich1 )
      79             :                 {
      80             :                     const sal_uInt16 nS1 =
      81        6762 :                         static_txtattr_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
      82             :                     const sal_uInt16 nS2 =
      83        6762 :                         static_txtattr_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
      84        6762 :                     if ( nS1 != nS2 ) // robust
      85           0 :                         return nS1 > nS2;
      86             :                 }
      87             : 
      88      176319 :                 return (sal_IntPtr)&rHt1 > (sal_IntPtr)&rHt2;
      89             :             }
      90             :             // order is important! for requirements see hintids.hxx
      91      115008 :             return ( nWhich1 < nWhich2 );
      92             :         }
      93             :         else
      94      189076 :             return ( rHt1.GetStart() > rHt2.GetStart() );
      95             :     }
      96     4574764 :     return ( nHt1 < nHt2 );
      97             : }
      98             : 
      99     4837646 : bool CompareSwpHtStart::operator()(SwTxtAttr* const lhs, SwTxtAttr* const rhs) const
     100             : {
     101     4837646 :   return lcl_IsLessStart( *lhs, *rhs );
     102             : }
     103             : 
     104     5055167 : bool CompareSwpHtEnd::operator()(SwTxtAttr* const lhs, SwTxtAttr* const rhs) const
     105             : {
     106     5055167 :   return lcl_IsLessEnd( *lhs, *rhs );
     107             : }
     108             : 
     109      162470 : void SwpHintsArray::Insert( const SwTxtAttr *pHt )
     110             : {
     111      162470 :     Resort();
     112             :     assert(m_HintStarts.find(const_cast<SwTxtAttr*>(pHt))
     113             :             == m_HintStarts.end()); // "Insert: hint already in HtStart"
     114             :     assert(m_HintEnds.find(const_cast<SwTxtAttr*>(pHt))
     115             :             == m_HintEnds.end());   // "Insert: hint already in HtEnd"
     116      162470 :     m_HintStarts.insert( const_cast<SwTxtAttr*>(pHt) );
     117      162470 :     m_HintEnds  .insert( const_cast<SwTxtAttr*>(pHt) );
     118      162470 : }
     119             : 
     120       87652 : void SwpHintsArray::DeleteAtPos( const size_t nPos )
     121             : {
     122             :     // optimization: nPos is the position in the Starts array
     123       87652 :     SwTxtAttr *pHt = m_HintStarts[ nPos ];
     124       87652 :     m_HintStarts.erase( m_HintStarts.begin() + nPos );
     125             : 
     126       87652 :     Resort();
     127             : 
     128       87652 :     bool const done = m_HintEnds.erase(pHt);
     129             :     assert(done);
     130             :     (void) done; // unused in NDEBUG
     131       87652 : }
     132             : 
     133       11338 : bool SwpHintsArray::Contains( const SwTxtAttr *pHt ) const
     134             : {
     135             :     // DO NOT use find() here!
     136             :     // if called from SwTxtNode::InsertItem, pHt has already been deleted,
     137             :     // so it cannot be dereferenced
     138       15872 :     for (size_t i = 0; i < m_HintStarts.size(); ++i)
     139             :     {
     140       15872 :         if (m_HintStarts[i] == pHt)
     141             :         {
     142       11338 :             return true;
     143             :         }
     144             :     }
     145           0 :     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 SwTxtAttr *pLastStart = 0;
     167             :     const SwTxtAttr *pLastEnd = 0;
     168             :     std::set<SwTxtAttr const*> RsidOnlyAutoFmts;
     169             :     if (bPortionsMerged)
     170             :     {
     171             :         for (size_t i = 0; i < Count(); ++i)
     172             :         {
     173             :             SwTxtAttr const*const pHint(m_HintStarts[i]);
     174             :             if (RES_TXTATR_AUTOFMT == pHint->Which())
     175             :             {
     176             :                 boost::shared_ptr<SfxItemSet> const pSet(
     177             :                         pHint->GetAutoFmt().GetStyleHandle());
     178             :                 if (pSet->Count() == 1 && pSet->GetItem(RES_CHRATR_RSID, false))
     179             :                 {
     180             :                     RsidOnlyAutoFmts.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 SwTxtAttr *pHt = m_HintStarts[i];
     192             :         CHECK_ERR( 0xFF != *(unsigned char*)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 SwTxtAttr *pHtEnd = m_HintEnds[i];
     209             :         CHECK_ERR( 0xFF != *(unsigned char*)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<SwTxtAttr*>(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<SwTxtAttr*>(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 SwTxtAttr* pHtThis = m_HintStarts[i];
     249             :         const SwTxtAttr* 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 SwTxtCharFmt *>(pHtThis)
     265             :                                 ->GetSortNumber() !=
     266             :                          static_txtattr_cast<const SwTxtCharFmt *>(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 (RsidOnlyAutoFmts.find(pHt) != RsidOnlyAutoFmts.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             :                         SwTxtAttr *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             :                                          (RsidOnlyAutoFmts.find(pOther) ==
     321             :                                           RsidOnlyAutoFmts.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             :                 SwTxtAttr 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 SwTxtNode::m_Text)
     360             :         if (pHtThis->HasDummyChar())
     361             :         {
     362             :             for ( sal_uInt16 j = 0; j < i; ++j )
     363             :             {
     364             :                 SwTxtAttr 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 SwTxtNode 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      440758 : void SwpHintsArray::Resort()
     384             : {
     385      440758 :     m_HintStarts.Resort();
     386      440758 :     m_HintEnds.Resort();
     387      440758 : }
     388             : 
     389             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10