LCOV - code coverage report
Current view: top level - sw/source/core/txtnode - ndhints.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 56 58 96.6 %
Date: 2014-04-11 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             : 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     1969837 : static bool lcl_IsLessStart( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
      40             : {
      41     1969837 :     if ( *rHt1.GetStart() == *rHt2.GetStart() )
      42             :     {
      43      101282 :         const sal_Int32 nHt1 = *rHt1.GetAnyEnd();
      44      101282 :         const sal_Int32 nHt2 = *rHt2.GetAnyEnd();
      45      101282 :         if ( nHt1 == nHt2 )
      46             :         {
      47       96196 :             const sal_uInt16 nWhich1 = rHt1.Which();
      48       96196 :             const sal_uInt16 nWhich2 = rHt2.Which();
      49       96196 :             if ( nWhich1 == nWhich2 )
      50             :             {
      51       64798 :                 if ( RES_TXTATR_CHARFMT == nWhich1 )
      52             :                 {
      53         678 :                     const sal_uInt16 nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
      54         678 :                     const sal_uInt16 nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
      55         678 :                     if ( nS1 != nS2 ) // robust
      56           0 :                         return nS1 < nS2;
      57             :                 }
      58             : 
      59       64798 :                 return (sal_IntPtr)&rHt1 < (sal_IntPtr)&rHt2;
      60             :             }
      61             :             // order is important! for requirements see hintids.hxx
      62       31398 :             return ( nWhich1 > nWhich2 );
      63             :         }
      64        5086 :         return ( nHt1 > nHt2 );
      65             :     }
      66     1868555 :     return ( *rHt1.GetStart() < *rHt2.GetStart() );
      67             : }
      68             : 
      69             : /*************************************************************************
      70             :  *                      inline IsLessEnd()
      71             :  *************************************************************************/
      72             : 
      73             : // Zuerst nach Ende danach nach Ptr
      74     2057205 : static bool lcl_IsLessEnd( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
      75             : {
      76     2057205 :     const sal_Int32 nHt1 = *rHt1.GetAnyEnd();
      77     2057205 :     const sal_Int32 nHt2 = *rHt2.GetAnyEnd();
      78     2057205 :     if ( nHt1 == nHt2 )
      79             :     {
      80      189697 :         if ( *rHt1.GetStart() == *rHt2.GetStart() )
      81             :         {
      82      103506 :             const sal_uInt16 nWhich1 = rHt1.Which();
      83      103506 :             const sal_uInt16 nWhich2 = rHt2.Which();
      84      103506 :             if ( nWhich1 == nWhich2 )
      85             :             {
      86       69536 :                 if ( RES_TXTATR_CHARFMT == nWhich1 )
      87             :                 {
      88         694 :                     const sal_uInt16 nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
      89         694 :                     const sal_uInt16 nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
      90         694 :                     if ( nS1 != nS2 ) // robust
      91           0 :                         return nS1 > nS2;
      92             :                 }
      93             : 
      94       69536 :                 return (sal_IntPtr)&rHt1 > (sal_IntPtr)&rHt2;
      95             :             }
      96             :             // order is important! for requirements see hintids.hxx
      97       33970 :             return ( nWhich1 < nWhich2 );
      98             :         }
      99             :         else
     100       86191 :             return ( *rHt1.GetStart() > *rHt2.GetStart() );
     101             :     }
     102     1867508 :     return ( nHt1 < nHt2 );
     103             : }
     104             : 
     105     1969837 : bool CompareSwpHtStart::operator()(SwTxtAttr* const lhs, SwTxtAttr* const rhs) const
     106             : {
     107     1969837 :   return lcl_IsLessStart( *lhs, *rhs );
     108             : }
     109             : 
     110     2057205 : bool CompareSwpHtEnd::operator()(SwTxtAttr* const lhs, SwTxtAttr* const rhs) const
     111             : {
     112     2057205 :   return lcl_IsLessEnd( *lhs, *rhs );
     113             : }
     114             : 
     115             : /*************************************************************************
     116             :  *                      class SwpHintsArr
     117             :  *************************************************************************/
     118             : 
     119       66109 : void SwpHintsArray::Insert( const SwTxtAttr *pHt )
     120             : {
     121       66109 :     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       66109 :     m_HintStarts.insert( const_cast<SwTxtAttr*>(pHt) );
     127       66109 :     m_HintEnds  .insert( const_cast<SwTxtAttr*>(pHt) );
     128       66109 : }
     129             : 
     130       34520 : void SwpHintsArray::DeleteAtPos( const sal_uInt16 nPos )
     131             : {
     132             :     // optimization: nPos is the position in the Starts array
     133       34520 :     SwTxtAttr *pHt = m_HintStarts[ nPos ];
     134       34520 :     m_HintStarts.erase( m_HintStarts.begin() + nPos );
     135             : 
     136       34520 :     Resort();
     137             : 
     138       34520 :     bool const done = m_HintEnds.erase(pHt);
     139             :     assert(done);
     140             :     (void) done; // unused in NDEBUG
     141       34520 : }
     142             : 
     143        4288 : 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        6189 :     for (size_t i = 0; i < m_HintStarts.size(); ++i)
     149             :     {
     150        6188 :         if (m_HintStarts[i] == pHt)
     151             :         {
     152        4287 :             return i;
     153             :         }
     154             :     }
     155           1 :     return USHRT_MAX;
     156             : }
     157             : 
     158             : #ifdef DBG_UTIL
     159             : 
     160             : /*************************************************************************
     161             :  *                      SwpHintsArray::Check()
     162             :  *************************************************************************/
     163             : 
     164             : #define CHECK_ERR(cond, text) \
     165             :         if(!(cond)) \
     166             :         { \
     167             :             SAL_WARN("sw.core", text); \
     168             :             DumpHints(m_HintStarts, m_HintEnds); \
     169             :             (const_cast<SwpHintsArray*>(this))->Resort(); \
     170             :             return false; \
     171             :         }
     172             : 
     173             : bool SwpHintsArray::Check(bool bPortionsMerged) const
     174             : {
     175             :     // 1) gleiche Anzahl in beiden Arrays
     176             :     CHECK_ERR( m_HintStarts.size() == m_HintEnds.size(),
     177             :         "HintsCheck: wrong sizes" );
     178             :     sal_Int32 nLastStart = 0;
     179             :     sal_Int32 nLastEnd   = 0;
     180             : 
     181             :     const SwTxtAttr *pLastStart = 0;
     182             :     const SwTxtAttr *pLastEnd = 0;
     183             :     std::set<SwTxtAttr const*> RsidOnlyAutoFmts;
     184             :     if (bPortionsMerged)
     185             :     {
     186             :         for (sal_uInt16 i = 0; i < Count(); ++i)
     187             :         {
     188             :             SwTxtAttr const*const pHint(m_HintStarts[i]);
     189             :             if (RES_TXTATR_AUTOFMT == pHint->Which())
     190             :             {
     191             :                 boost::shared_ptr<SfxItemSet> const pSet(
     192             :                         pHint->GetAutoFmt().GetStyleHandle());
     193             :                 if (pSet->Count() == 1 && pSet->GetItem(RES_CHRATR_RSID, false))
     194             :                 {
     195             :                     RsidOnlyAutoFmts.insert(pHint);
     196             :                 }
     197             :             }
     198             :         }
     199             :     }
     200             : 
     201             :     for( sal_uInt16 i = 0; i < Count(); ++i )
     202             :     {
     203             :         // --- Start-Kontrolle ---
     204             : 
     205             :         // 2a) gueltiger Pointer? vgl. DELETEFF
     206             :         const SwTxtAttr *pHt = m_HintStarts[i];
     207             :         CHECK_ERR( 0xFF != *(unsigned char*)pHt, "HintsCheck: start ptr was deleted" );
     208             : 
     209             :         // 3a) Stimmt die Start-Sortierung?
     210             :         sal_Int32 nIdx = *pHt->GetStart();
     211             :         CHECK_ERR( nIdx >= nLastStart, "HintsCheck: starts are unsorted" );
     212             : 
     213             :         // 4a) IsLessStart-Konsistenz
     214             :         if( pLastStart )
     215             :             CHECK_ERR( lcl_IsLessStart( *pLastStart, *pHt ), "HintsCheck: IsLastStart" );
     216             : 
     217             :         nLastStart = nIdx;
     218             :         pLastStart = pHt;
     219             : 
     220             :         // --- End-Kontrolle ---
     221             : 
     222             :         // 2b) gueltiger Pointer? vgl. DELETEFF
     223             :         const SwTxtAttr *pHtEnd = m_HintEnds[i];
     224             :         CHECK_ERR( 0xFF != *(unsigned char*)pHtEnd, "HintsCheck: end ptr was deleted" );
     225             : 
     226             :         // 3b) Stimmt die End-Sortierung?
     227             :         nIdx = *pHtEnd->GetAnyEnd();
     228             :         CHECK_ERR( nIdx >= nLastEnd, "HintsCheck: ends are unsorted" );
     229             :         nLastEnd = nIdx;
     230             : 
     231             :         // 4b) IsLessEnd-Konsistenz
     232             :         if( pLastEnd )
     233             :             CHECK_ERR( lcl_IsLessEnd( *pLastEnd, *pHtEnd ), "HintsCheck: IsLastEnd" );
     234             : 
     235             :         nLastEnd = nIdx;
     236             :         pLastEnd = pHtEnd;
     237             : 
     238             :         // --- Ueberkreuzungen ---
     239             : 
     240             :         // 5) gleiche Pointer in beiden Arrays
     241             :         if (m_HintStarts.find(const_cast<SwTxtAttr*>(pHt)) == m_HintStarts.end())
     242             :             nIdx = COMPLETE_STRING;
     243             : 
     244             :         CHECK_ERR( COMPLETE_STRING != nIdx, "HintsCheck: no GetStartOf" );
     245             : 
     246             :         // 6) gleiche Pointer in beiden Arrays
     247             :         if (m_HintEnds.find(const_cast<SwTxtAttr*>(pHt)) == m_HintEnds.end())
     248             :             nIdx = COMPLETE_STRING;
     249             : 
     250             :         CHECK_ERR( COMPLETE_STRING != nIdx, "HintsCheck: no GetEndOf" );
     251             : 
     252             :         // 7a) character attributes in array?
     253             :         sal_uInt16 nWhich = pHt->Which();
     254             :         CHECK_ERR( !isCHRATR(nWhich),
     255             :                    "HintsCheck: Character attribute in start array" );
     256             : 
     257             :         // 7b) character attributes in array?
     258             :         nWhich = pHtEnd->Which();
     259             :         CHECK_ERR( !isCHRATR(nWhich),
     260             :                    "HintsCheck: Character attribute in end array" );
     261             : 
     262             :         // 8) style portion check
     263             :         const SwTxtAttr* pHtThis = m_HintStarts[i];
     264             :         const SwTxtAttr* pHtLast = i > 0 ? m_HintStarts[i-1] : 0;
     265             :         CHECK_ERR( (0 == i)
     266             :             ||  (   (RES_TXTATR_CHARFMT != pHtLast->Which())
     267             :                 &&  (RES_TXTATR_AUTOFMT != pHtLast->Which()))
     268             :             ||  (   (RES_TXTATR_CHARFMT != pHtThis->Which())
     269             :                 &&  (RES_TXTATR_AUTOFMT != pHtThis->Which()))
     270             :             ||  (*pHtThis->GetStart() >= *pHtLast->End()) // no overlap
     271             :             ||  (   (   (*pHtThis->GetStart() == *pHtLast->GetStart())
     272             :                     &&  (*pHtThis->End()   == *pHtLast->End())
     273             :                     ) // same range
     274             :                 &&  (   (pHtThis->Which() != RES_TXTATR_AUTOFMT)
     275             :                     ||  (pHtLast->Which() != RES_TXTATR_AUTOFMT)
     276             :                     ) // never two AUTOFMT on same range
     277             :                 &&  (   (pHtThis->Which() != RES_TXTATR_CHARFMT)
     278             :                     ||  (pHtLast->Which() != RES_TXTATR_CHARFMT)
     279             :                     ||  (static_cast<const SwTxtCharFmt *>(pHtThis)
     280             :                                 ->GetSortNumber() !=
     281             :                          static_cast<const SwTxtCharFmt *>(pHtLast)
     282             :                                 ->GetSortNumber())
     283             :                     ) // multiple CHARFMT on same range need distinct sortnr
     284             :                 )
     285             :             ||  (*pHtThis->GetStart() == *pHtThis->End()), // this empty
     286             :                    "HintsCheck: Portion inconsistency. "
     287             :                    "This can be temporarily ok during undo operations" );
     288             : 
     289             :         // 8 1/2) format ignore start/end flag check
     290             :         // (problems because MergePortions buggy or not called)
     291             :         if (bPortionsMerged)
     292             :         {
     293             :             if (RES_TXTATR_AUTOFMT == pHt->Which() ||
     294             :                 RES_TXTATR_CHARFMT == pHt->Which())
     295             :             {
     296             :                 // mostly ignore the annoying no-length hints
     297             :                 // BuildPortions inserts these in the middle of an existing one
     298             :                 bool const bNoLength(*pHt->GetStart() == *pHt->End());
     299             :                 bool bNeedContinuation(!bNoLength && pHt->IsFormatIgnoreEnd());
     300             :                 bool bForbidContinuation(!bNoLength && !bNeedContinuation);
     301             :                 if (RES_TXTATR_AUTOFMT == pHt->Which())
     302             :                 {
     303             :                     if (RsidOnlyAutoFmts.find(pHt) != RsidOnlyAutoFmts.end())
     304             :                     {
     305             :                         assert(pHt->IsFormatIgnoreStart());
     306             :                         bNeedContinuation = false;
     307             :                         // don't forbid continuation - may be other hint here!
     308             :                     }
     309             :                 }
     310             :                 if (bNeedContinuation || bForbidContinuation)
     311             :                 {
     312             :                     bool bFound(false);
     313             :                     for (sal_uInt16 j = i + 1; j < Count(); ++j)
     314             :                     {
     315             :                         SwTxtAttr *const pOther(m_HintStarts[j]);
     316             :                         if (*pOther->GetStart() > *pHt->End())
     317             :                         {
     318             :                             break; // done
     319             :                         }
     320             :                         else if (*pOther->GetStart() == *pOther->GetAnyEnd())
     321             :                         {
     322             :                             continue; // empty hint: ignore
     323             :                         }
     324             :                         else if (*pOther->GetStart() == *pHt->End())
     325             :                         {
     326             :                             if (RES_TXTATR_AUTOFMT == pOther->Which() ||
     327             :                                 RES_TXTATR_CHARFMT == pOther->Which())
     328             :                             {   // multiple charfmt on same range must all match
     329             :                                 if (bNeedContinuation)
     330             :                                 {
     331             :                                     assert(pOther->IsFormatIgnoreStart());
     332             :                                     bFound = true;
     333             :                                 }
     334             :                                 else if (bForbidContinuation &&
     335             :                                          (RsidOnlyAutoFmts.find(pOther) ==
     336             :                                           RsidOnlyAutoFmts.end()))
     337             :                                 {
     338             :                                     assert(!pOther->IsFormatIgnoreStart());
     339             :                                 }
     340             :                             }
     341             :                         }
     342             :                     }
     343             :                     if (bNeedContinuation)
     344             :                     {
     345             :                         assert(bFound); // ? can this happen temp. during undo?
     346             :                     }
     347             :                 }
     348             :             }
     349             :             else
     350             :             {
     351             :                 assert(!pHt->IsFormatIgnoreStart());
     352             :                 assert(!pHt->IsFormatIgnoreEnd());
     353             :             }
     354             :         }
     355             : 
     356             :         // 9) nesting portion check
     357             :         if (pHtThis->IsNesting())
     358             :         {
     359             :             for ( sal_uInt16 j = 0; j < Count(); ++j )
     360             :             {
     361             :                 SwTxtAttr const * const pOther( m_HintStarts[j] );
     362             :                 if ( pOther->IsNesting() &&  (i != j) )
     363             :                 {
     364             :                     SwComparePosition cmp = ComparePosition(
     365             :                         *pHtThis->GetStart(), *pHtThis->End(),
     366             :                         *pOther->GetStart(), *pOther->End());
     367             :                     CHECK_ERR( (POS_OVERLAP_BEFORE != cmp) &&
     368             :                                (POS_OVERLAP_BEHIND != cmp),
     369             :                         "HintsCheck: overlapping nesting hints!!!" );
     370             :                 }
     371             :             }
     372             :         }
     373             : 
     374             :         // 10) dummy char check (unfortunately cannot check SwTxtNode::m_Text)
     375             :         if (pHtThis->HasDummyChar())
     376             :         {
     377             :             for ( sal_uInt16 j = 0; j < i; ++j )
     378             :             {
     379             :                 SwTxtAttr const * const pOther( m_HintStarts[j] );
     380             :                 if (pOther->HasDummyChar())
     381             :                 {
     382             :                     CHECK_ERR( (*pOther->GetStart() != *pHtThis->GetStart()),
     383             :                         "HintsCheck: multiple hints claim same CH_TXTATR!");
     384             :                 }
     385             :             }
     386             :         }
     387             :     }
     388             :     return true;
     389             : }
     390             : 
     391             : #endif      /* DBG_UTIL */
     392             : 
     393             : /*************************************************************************
     394             :  *                          SwpHintsArray::Resort()
     395             :  *************************************************************************/
     396             : 
     397             : // Resort() is called before every Insert and Delete.
     398             : // Various SwTxtNode methods modify hints in a way that violates the
     399             : // sort order of the m_HintStarts, m_HintEnds arrays, so this method is needed
     400             : // to restore the order.
     401             : 
     402      176639 : void SwpHintsArray::Resort()
     403             : {
     404      176639 :     m_HintStarts.Resort();
     405      176639 :     m_HintEnds.Resort();
     406      176639 : }
     407             : 
     408             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10