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

Generated by: LCOV version 1.10