LCOV - code coverage report
Current view: top level - sw/source/core/text - porfld.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 330 672 49.1 %
Date: 2015-06-13 12:38:46 Functions: 27 41 65.9 %
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 <hintids.hxx>
      21             : 
      22             : #include <com/sun/star/i18n/ScriptType.hpp>
      23             : #include <vcl/graph.hxx>
      24             : #include <editeng/brushitem.hxx>
      25             : #include <vcl/metric.hxx>
      26             : #include <vcl/outdev.hxx>
      27             : #include <viewopt.hxx>
      28             : #include <SwPortionHandler.hxx>
      29             : #include <porlay.hxx>
      30             : #include <porfld.hxx>
      31             : #include <inftxt.hxx>
      32             : #include <blink.hxx>
      33             : #include <frmtool.hxx>
      34             : #include <viewsh.hxx>
      35             : #include <docsh.hxx>
      36             : #include <doc.hxx>
      37             : #include <IDocumentSettingAccess.hxx>
      38             : #include "rootfrm.hxx"
      39             : #include <breakit.hxx>
      40             : #include <porrst.hxx>
      41             : #include <porftn.hxx>
      42             : #include <accessibilityoptions.hxx>
      43             : #include <editeng/lrspitem.hxx>
      44             : #include <unicode/ubidi.h>
      45             : 
      46             : using namespace ::com::sun::star;
      47             : 
      48       20741 : SwLinePortion *SwFieldPortion::Compress()
      49       20741 : { return (GetLen() || !aExpand.isEmpty() || SwLinePortion::Compress()) ? this : 0; }
      50             : 
      51         180 : SwFieldPortion *SwFieldPortion::Clone( const OUString &rExpand ) const
      52             : {
      53             :     SwFont *pNewFnt;
      54         180 :     if( 0 != ( pNewFnt = pFnt ) )
      55             :     {
      56         157 :         pNewFnt = new SwFont( *pFnt );
      57             :     }
      58             :     // #i107143#
      59             :     // pass placeholder property to created <SwFieldPortion> instance.
      60         180 :     SwFieldPortion* pClone = new SwFieldPortion( rExpand, pNewFnt, bPlaceHolder );
      61         180 :     pClone->SetNextOffset( nNextOffset );
      62         180 :     pClone->m_bNoLength = this->m_bNoLength;
      63         180 :     return pClone;
      64             : }
      65             : 
      66           0 : void SwFieldPortion::TakeNextOffset( const SwFieldPortion* pField )
      67             : {
      68             :     OSL_ENSURE( pField, "TakeNextOffset: Missing Source" );
      69           0 :     nNextOffset = pField->GetNextOffset();
      70           0 :     aExpand = aExpand.replaceAt( 0, nNextOffset, "" );
      71           0 :     bFollow = true;
      72           0 : }
      73             : 
      74       20738 : SwFieldPortion::SwFieldPortion( const OUString &rExpand, SwFont *pFont, bool bPlaceHold )
      75             :     : aExpand(rExpand), pFnt(pFont), nNextOffset(0), nNextScriptChg(COMPLETE_STRING), nViewWidth(0)
      76             :     , bFollow( false ), bLeft( false), bHide( false)
      77             :     , bCenter (false), bHasFollow( false )
      78             :     , bAnimated( false), bNoPaint( false)
      79             :     , bReplace( false), bPlaceHolder( bPlaceHold )
      80             :     , m_bNoLength( false )
      81       20738 :     , m_nAttrFieldType(0)
      82             : {
      83       20738 :     SetWhichPor( POR_FLD );
      84       20738 : }
      85             : 
      86          13 : SwFieldPortion::SwFieldPortion( const SwFieldPortion& rField )
      87             :     : SwExpandPortion( rField )
      88             :     , aExpand( rField.GetExp() )
      89          13 :     , nNextOffset( rField.GetNextOffset() )
      90          13 :     , nNextScriptChg( rField.GetNextScriptChg() )
      91             :     , nViewWidth( rField.nViewWidth )
      92          13 :     , bFollow( rField.IsFollow() )
      93          13 :     , bLeft( rField.IsLeft() )
      94          13 :     , bHide( rField.IsHide() )
      95          13 :     , bCenter( rField.IsCenter() )
      96          13 :     , bHasFollow( rField.HasFollow() )
      97             :     , bAnimated ( rField.bAnimated )
      98             :     , bNoPaint( rField.bNoPaint)
      99             :     , bReplace( rField.bReplace )
     100             :     , bPlaceHolder( rField.bPlaceHolder )
     101             :     , m_bNoLength( rField.m_bNoLength )
     102         104 :     , m_nAttrFieldType( rField.m_nAttrFieldType)
     103             : {
     104          13 :     if ( rField.HasFont() )
     105          13 :         pFnt = new SwFont( *rField.GetFont() );
     106             :     else
     107           0 :         pFnt = 0;
     108             : 
     109          13 :     SetWhichPor( POR_FLD );
     110          13 : }
     111             : 
     112       46230 : SwFieldPortion::~SwFieldPortion()
     113             : {
     114       20751 :     delete pFnt;
     115       20751 :     if( pBlink )
     116          34 :         pBlink->Delete( this );
     117       25479 : }
     118             : 
     119         518 : sal_uInt16 SwFieldPortion::GetViewWidth( const SwTextSizeInfo &rInf ) const
     120             : {
     121             :     // even though this is const, nViewWidth should be computed at the very end:
     122         518 :     SwFieldPortion* pThis = const_cast<SwFieldPortion*>(this);
     123        2072 :     if( !Width() && rInf.OnWin() && !rInf.GetOpt().IsPagePreview() &&
     124        1554 :             !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
     125             :     {
     126         518 :         if( !nViewWidth )
     127         242 :             pThis->nViewWidth = rInf.GetTextSize(OUString(' ')).Width();
     128             :     }
     129             :     else
     130           0 :         pThis->nViewWidth = 0;
     131         518 :     return nViewWidth;
     132             : }
     133             : 
     134             : /**
     135             :  * Never just use SetLen(0)
     136             :  */
     137             : class SwFieldSlot
     138             : {
     139             :     std::shared_ptr<vcl::TextLayoutCache> m_pOldCachedVclData;
     140             :     const OUString *pOldText;
     141             :     OUString aText;
     142             :     sal_Int32 nIdx;
     143             :     sal_Int32 nLen;
     144             :     SwTextFormatInfo *pInf;
     145             :     bool bOn;
     146             : public:
     147             :     SwFieldSlot( const SwTextFormatInfo* pNew, const SwFieldPortion *pPor );
     148             :     ~SwFieldSlot();
     149             : };
     150             : 
     151       20565 : SwFieldSlot::SwFieldSlot( const SwTextFormatInfo* pNew, const SwFieldPortion *pPor )
     152             :     : pOldText(NULL)
     153             :     , nIdx(0)
     154             :     , nLen(0)
     155       20565 :     , pInf(NULL)
     156             : {
     157       20565 :     bOn = pPor->GetExpText( *pNew, aText );
     158             : 
     159             :     // The text will be replaced ...
     160       20565 :     if( bOn )
     161             :     {
     162       20565 :         pInf = const_cast<SwTextFormatInfo*>(pNew);
     163       20565 :         nIdx = pInf->GetIdx();
     164       20565 :         nLen = pInf->GetLen();
     165       20565 :         pOldText = &(pInf->GetText());
     166       20565 :         m_pOldCachedVclData = pInf->GetCachedVclData();
     167       20565 :         pInf->SetLen( aText.getLength() );
     168       20565 :         pInf->SetCachedVclData(nullptr);
     169       20565 :         if( pPor->IsFollow() )
     170             :         {
     171        8904 :             pInf->SetFakeLineStart( nIdx > pInf->GetLineStart() );
     172        8904 :             pInf->SetIdx( 0 );
     173             :         }
     174             :         else
     175             :         {
     176       11661 :             aText = (*pOldText).replaceAt(nIdx, 1, aText);
     177             :         }
     178       20565 :         pInf->SetText( aText );
     179             :     }
     180       20565 : }
     181             : 
     182       41130 : SwFieldSlot::~SwFieldSlot()
     183             : {
     184       20565 :     if( bOn )
     185             :     {
     186       20565 :         pInf->SetCachedVclData(m_pOldCachedVclData);
     187       20565 :         pInf->SetText( *pOldText );
     188       20565 :         pInf->SetIdx( nIdx );
     189       20565 :         pInf->SetLen( nLen );
     190       20565 :         pInf->SetFakeLineStart( false );
     191             :     }
     192       20565 : }
     193             : 
     194       20565 : void SwFieldPortion::CheckScript( const SwTextSizeInfo &rInf )
     195             : {
     196       20565 :     OUString aText;
     197       20565 :     if( GetExpText( rInf, aText ) && !aText.isEmpty() && g_pBreakIt->GetBreakIter().is() )
     198             :     {
     199       13767 :         sal_uInt8 nActual = pFnt ? pFnt->GetActual() : rInf.GetFont()->GetActual();
     200       13767 :         sal_uInt16 nScript = g_pBreakIt->GetBreakIter()->getScriptType( aText, 0 );
     201       13767 :         sal_Int32 nChg = 0;
     202       13767 :         if( i18n::ScriptType::WEAK == nScript )
     203             :         {
     204        2765 :             nChg = g_pBreakIt->GetBreakIter()->endOfScript(aText,0,nScript);
     205        2765 :             if (nChg < aText.getLength() && nChg >= 0)
     206        2365 :                 nScript = g_pBreakIt->GetBreakIter()->getScriptType( aText, nChg );
     207             :         }
     208             : 
     209             :         // nNextScriptChg will be evaluated during SwFieldPortion::Format()
     210             : 
     211       13767 :         if (nChg < aText.getLength() && nChg >= 0)
     212       13367 :             nNextScriptChg = g_pBreakIt->GetBreakIter()->endOfScript( aText, nChg, nScript );
     213             :         else
     214         400 :             nNextScriptChg = aText.getLength();
     215             : 
     216             :         sal_uInt8 nTmp;
     217       13767 :         switch ( nScript ) {
     218       11133 :             case i18n::ScriptType::LATIN : nTmp = SW_LATIN; break;
     219        2216 :             case i18n::ScriptType::ASIAN : nTmp = SW_CJK; break;
     220          18 :             case i18n::ScriptType::COMPLEX : nTmp = SW_CTL; break;
     221         400 :             default: nTmp = nActual;
     222             :         }
     223             : 
     224             :         // #i16354# Change script type for RTL text to CTL.
     225       13767 :         const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo();
     226             :         // #i98418#
     227       20811 :         const sal_uInt8 nFieldDir = ( IsNumberPortion() || IsFootnoteNumPortion() ) ?
     228             :                              rSI.GetDefaultDir() :
     229       20636 :                              rSI.DirType( IsFollow() ? rInf.GetIdx() - 1 : rInf.GetIdx() );
     230             : 
     231       13767 :         bool bPerformUBA = UBIDI_LTR != nFieldDir || i18n::ScriptType::COMPLEX == nScript;
     232       13767 :         if (bPerformUBA)
     233             :         {
     234          18 :             UErrorCode nError = U_ZERO_ERROR;
     235          18 :             UBiDi* pBidi = ubidi_openSized( aText.getLength(), 0, &nError );
     236          18 :             ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(aText.getStr()), aText.getLength(), nFieldDir, NULL, &nError );
     237             :             int32_t nEnd;
     238             :             UBiDiLevel nCurrDir;
     239          18 :             ubidi_getLogicalRun( pBidi, 0, &nEnd, &nCurrDir );
     240          18 :             ubidi_close( pBidi );
     241          18 :             const sal_Int32 nNextDirChg = nEnd;
     242          18 :             nNextScriptChg = std::min( nNextScriptChg, nNextDirChg );
     243             : 
     244             :             // #i89825# change the script type also to CTL
     245             :             // if there is no strong LTR char in the LTR run (numbers)
     246          18 :             if ( nCurrDir != UBIDI_RTL )
     247             :             {
     248           0 :                 nCurrDir = UBIDI_RTL;
     249           0 :                 for( sal_Int32 nCharIdx = 0; nCharIdx < nEnd; ++nCharIdx )
     250             :                 {
     251           0 :                     UCharDirection nCharDir = u_charDirection ( aText[ nCharIdx ]);
     252           0 :                     if ( nCharDir == U_LEFT_TO_RIGHT ||
     253           0 :                          nCharDir == U_LEFT_TO_RIGHT_EMBEDDING ||
     254             :                          nCharDir == U_LEFT_TO_RIGHT_OVERRIDE )
     255             :                     {
     256           0 :                         nCurrDir = UBIDI_LTR;
     257           0 :                         break;
     258             :                     }
     259             :                 }
     260             :             }
     261             : 
     262          18 :             if (nCurrDir == UBIDI_RTL)
     263             :             {
     264          18 :                 nTmp = SW_CTL;
     265             :                 // If we decided that this range was RTL after all and the
     266             :                 // previous range was complex but clipped to the start of this
     267             :                 // range, then extend it to be complex over the additional RTL range
     268          18 :                 if (nScript == i18n::ScriptType::COMPLEX)
     269          18 :                     nNextScriptChg = nNextDirChg;
     270             :             }
     271             :         }
     272             : 
     273             :         // #i98418#
     274             :         // keep determined script type for footnote portions as preferred script type.
     275             :         // For footnote portions a font can not be created directly - see footnote
     276             :         // portion format method.
     277       13767 :         if ( IsFootnotePortion() )
     278             :         {
     279         145 :             static_cast<SwFootnotePortion*>(this)->SetPreferredScriptType( nTmp );
     280             :         }
     281       13622 :         else if ( nTmp != nActual )
     282             :         {
     283        4450 :             if( !pFnt )
     284           0 :                 pFnt = new SwFont( *rInf.GetFont() );
     285        4450 :             pFnt->SetActual( nTmp );
     286             :         }
     287       20565 :     }
     288       20565 : }
     289             : 
     290       20565 : bool SwFieldPortion::Format( SwTextFormatInfo &rInf )
     291             : {
     292             :     // Scope wegen aDiffText::DTOR!
     293             :     sal_Int32 nRest;
     294       20565 :     bool bFull = false;
     295       20565 :     bool bEOL = false;
     296       20565 :     const sal_Int32 nTextRest = rInf.GetText().getLength() - rInf.GetIdx();
     297             :     {
     298       20565 :         SwFieldSlot aDiffText( &rInf, this );
     299       41130 :         SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
     300       20565 :         aLayoutModeModifier.SetAuto();
     301             : 
     302             :         // Field portion has to be split in several parts if
     303             :         // 1. There are script/direction changes inside the field
     304             :         // 2. There are portion breaks (tab, break) inside the field:
     305       20565 :         const sal_Int32 nOldFullLen = rInf.GetLen();
     306       20565 :         sal_Int32 nFullLen = rInf.ScanPortionEnd( rInf.GetIdx(), rInf.GetIdx() + nOldFullLen ) - rInf.GetIdx();
     307       20565 :         if ( nNextScriptChg < nFullLen )
     308             :         {
     309        2244 :             nFullLen = nNextScriptChg;
     310        2244 :             rInf.SetHookChar( 0 );
     311             :         }
     312       20565 :         rInf.SetLen( nFullLen );
     313             : 
     314       20624 :         if ( COMPLETE_STRING != rInf.GetUnderScorePos() &&
     315          59 :              rInf.GetUnderScorePos() > rInf.GetIdx() )
     316           0 :              rInf.SetUnderScorePos( rInf.GetIdx() );
     317             : 
     318       20565 :         if( pFnt )
     319       15910 :             pFnt->GoMagic( rInf.GetVsh(), pFnt->GetActual() );
     320             : 
     321       41130 :         SwFontSave aSave( rInf, pFnt );
     322             : 
     323             :         // Length must be 0: the length is set for bFull after format
     324             :         // and passed along in nRest. Or else the old length would be
     325             :         // retained and be used for nRest!
     326       20565 :         SetLen(0);
     327       20565 :         const sal_Int32 nFollow = IsFollow() ? 0 : 1;
     328             : 
     329             :         // As odd is may seem: the query for GetLen() must return false due
     330             :         // to the ExpandPortions _after_ aDiffText (see SoftHyphs), caused
     331             :         // by SetFull.
     332       20565 :         if( !nFullLen )
     333             :         {
     334             :             // Don't Init(), as we need height and ascent
     335        7154 :             Width(0);
     336        7154 :             bFull = rInf.Width() <= rInf.GetPos().X();
     337             :         }
     338             :         else
     339             :         {
     340       13411 :             sal_Int32 nOldLineStart = rInf.GetLineStart();
     341       13411 :             if( IsFollow() )
     342        2414 :                 rInf.SetLineStart( 0 );
     343       13411 :             rInf.SetNotEOL( nFullLen == nOldFullLen && nTextRest > nFollow );
     344             : 
     345             :             // the height depending on the fields font is set,
     346             :             // this is required for SwTextGuess::Guess
     347       13411 :             Height( rInf.GetTextHeight() + rInf.GetFont()->GetTopBorderSpace() +
     348       13411 :                     rInf.GetFont()->GetBottomBorderSpace() );
     349             :             // If a kerning portion is inserted after our field portion,
     350             :             // the ascent and height must be known
     351       13411 :             SetAscent( rInf.GetAscent() + rInf.GetFont()->GetTopBorderSpace() );
     352       13411 :             bFull = SwTextPortion::Format( rInf );
     353       13411 :             rInf.SetNotEOL( false );
     354       13411 :             rInf.SetLineStart( nOldLineStart );
     355             :         }
     356       20565 :         sal_Int32 nTmpLen = GetLen();
     357       20565 :         bEOL = !nTmpLen && nFollow && bFull;
     358       20565 :         nRest = nOldFullLen - nTmpLen;
     359             : 
     360             :         // The char is held in the first position
     361             :         // Unconditionally after format!
     362       20565 :         SetLen( (m_bNoLength) ? 0 : nFollow );
     363             : 
     364       20565 :         if( nRest )
     365             :         {
     366             :             // aExpand has not yet been shortened; the new Ofst is a
     367             :             // result of nRest
     368        8757 :             sal_Int32 nNextOfst = aExpand.getLength() - nRest;
     369             : 
     370        8757 :             if ( IsQuoVadisPortion() )
     371           0 :                 nNextOfst = nNextOfst + static_cast<SwQuoVadisPortion*>(this)->GetContText().getLength();
     372             : 
     373        8757 :             OUString aNew( aExpand.copy( nNextOfst ) );
     374        8757 :             aExpand = aExpand.copy( 0, nNextOfst );
     375             : 
     376             :             // These characters should not be contained in the follow
     377             :             // field portion. They are handled via the HookChar mechanism.
     378        8757 :             switch( aNew[0] )
     379             :             {
     380           0 :                 case CH_BREAK  : bFull = true;
     381             :                             // no break
     382             :                 case ' ' :
     383             :                 case CH_TAB    :
     384             :                 case CHAR_HARDHYPHEN:               // non-breaking hyphen
     385             :                 case CHAR_SOFTHYPHEN:
     386             :                 case CHAR_HARDBLANK:
     387             :                 case CHAR_ZWSP :
     388             :                 case CHAR_ZWNBSP :
     389             :                 case CH_TXTATR_BREAKWORD:
     390             :                 case CH_TXTATR_INWORD:
     391             :                 {
     392        6490 :                     aNew = aNew.copy( 1 );
     393        6490 :                     ++nNextOfst;
     394        6490 :                     break;
     395             :                 }
     396             :                 default: ;
     397             :             }
     398             : 
     399             :             // Even if there is no more text left for a follow field,
     400             :             // we have to build a follow field portion (without font),
     401             :             // otherwise the HookChar mechanism would not work.
     402        8757 :             SwFieldPortion *pField = Clone( aNew );
     403        8757 :             if( !aNew.isEmpty() && !pField->GetFont() )
     404             :             {
     405          23 :                 SwFont *pNewFnt = new SwFont( *rInf.GetFont() );
     406          23 :                 pField->SetFont( pNewFnt );
     407             :             }
     408        8757 :             pField->SetFollow( true );
     409        8757 :             SetHasFollow( true );
     410             : 
     411             :             // For a newly created field, nNextOffset contains the Offset
     412             :             // of it's start of the original string
     413             :             // If a FollowField is created when formatting, this FollowField's
     414             :             // Offset is being held in nNextOffset
     415        8757 :             nNextOffset = nNextOffset + nNextOfst;
     416        8757 :             pField->SetNextOffset( nNextOffset );
     417        8757 :             rInf.SetRest( pField );
     418       20565 :         }
     419             :     }
     420             : 
     421       20565 :     if( bEOL && rInf.GetLast() && !rInf.GetUnderflow() )
     422          11 :         rInf.GetLast()->FormatEOL( rInf );
     423       20565 :     return bFull;
     424             : }
     425             : 
     426        1479 : void SwFieldPortion::Paint( const SwTextPaintInfo &rInf ) const
     427             : {
     428        1479 :     SwFontSave aSave( rInf, pFnt );
     429             : 
     430             :     OSL_ENSURE( GetLen() <= 1, "SwFieldPortion::Paint: rest-portion pollution?" );
     431        1479 :     if( Width() && ( !bPlaceHolder || rInf.GetOpt().IsShowPlaceHolderFields() ) )
     432             :     {
     433             :         // A very liberal use of the background
     434        1193 :         rInf.DrawViewOpt( *this, POR_FLD );
     435        1193 :         SwExpandPortion::Paint( rInf );
     436        1479 :     }
     437        1479 : }
     438             : 
     439       47465 : bool SwFieldPortion::GetExpText( const SwTextSizeInfo &rInf, OUString &rText ) const
     440             : {
     441       47465 :     rText = aExpand;
     442      109851 :     if( rText.isEmpty() && rInf.OnWin() &&
     443        1554 :         !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() &&
     444       48501 :             SwViewOption::IsFieldShadings() &&
     445         518 :             !HasFollow() )
     446         518 :         rText = " ";
     447       47465 :     return true;
     448             : }
     449             : 
     450         102 : void SwFieldPortion::HandlePortion( SwPortionHandler& rPH ) const
     451             : {
     452         102 :     sal_Int32 nH = 0;
     453         102 :     sal_Int32 nW = 0;
     454         102 :     if (pFnt)
     455             :     {
     456          57 :         nH = pFnt->GetSize(pFnt->GetActual()).Height();
     457          57 :         nW = pFnt->GetSize(pFnt->GetActual()).Width();
     458             :     }
     459         102 :     rPH.Special( GetLen(), aExpand, GetWhichPor(), nH, nW, pFnt );
     460         102 :     if( GetWhichPor() == POR_FLD )
     461             :     {
     462          36 :         rPH.SetAttrFieldType(m_nAttrFieldType);
     463             :     }
     464         102 : }
     465             : 
     466           0 : SwPosSize SwFieldPortion::GetTextSize( const SwTextSizeInfo &rInf ) const
     467             : {
     468           0 :     SwFontSave aSave( rInf, pFnt );
     469           0 :     SwPosSize aSize( SwExpandPortion::GetTextSize( rInf ) );
     470           0 :     return aSize;
     471             : }
     472             : 
     473           0 : SwFieldPortion *SwHiddenPortion::Clone(const OUString &rExpand ) const
     474             : {
     475             :     SwFont *pNewFnt;
     476           0 :     if( 0 != ( pNewFnt = pFnt ) )
     477           0 :         pNewFnt = new SwFont( *pFnt );
     478           0 :     return new SwHiddenPortion( rExpand, pNewFnt );
     479             : }
     480             : 
     481           0 : void SwHiddenPortion::Paint( const SwTextPaintInfo &rInf ) const
     482             : {
     483           0 :     if( Width() )
     484             :     {
     485           0 :         SwFontSave aSave( rInf, pFnt );
     486           0 :         rInf.DrawViewOpt( *this, POR_HIDDEN );
     487           0 :         SwExpandPortion::Paint( rInf );
     488             :     }
     489           0 : }
     490             : 
     491           0 : bool SwHiddenPortion::GetExpText( const SwTextSizeInfo &rInf, OUString &rText ) const
     492             : {
     493             :     // Do not query for IsHidden()!
     494           0 :     return SwFieldPortion::GetExpText( rInf, rText );
     495             : }
     496             : 
     497       15878 : SwNumberPortion::SwNumberPortion( const OUString &rExpand,
     498             :                                   SwFont *pFont,
     499             :                                   const bool bLft,
     500             :                                   const bool bCntr,
     501             :                                   const sal_uInt16 nMinDst,
     502             :                                   const bool bLabelAlignmentPosAndSpaceModeActive )
     503             :         : SwFieldPortion( rExpand, pFont ),
     504             :           nFixWidth(0),
     505             :           nMinDist( nMinDst ),
     506       15878 :           mbLabelAlignmentPosAndSpaceModeActive( bLabelAlignmentPosAndSpaceModeActive )
     507             : {
     508       15878 :     SetWhichPor( POR_NUMBER );
     509       15878 :     SetLeft( bLft );
     510       15878 :     SetHide( false );
     511       15878 :     SetCenter( bCntr );
     512       15878 : }
     513             : 
     514           0 : sal_Int32 SwNumberPortion::GetCrsrOfst( const sal_uInt16 ) const
     515             : {
     516           0 :     return 0;
     517             : }
     518             : 
     519        8734 : SwFieldPortion *SwNumberPortion::Clone( const OUString &rExpand ) const
     520             : {
     521             :     SwFont *pNewFnt;
     522        8734 :     if( 0 != ( pNewFnt = pFnt ) )
     523        8664 :         pNewFnt = new SwFont( *pFnt );
     524             : 
     525       17468 :     return new SwNumberPortion( rExpand, pNewFnt, IsLeft(), IsCenter(),
     526       17468 :                                 nMinDist, mbLabelAlignmentPosAndSpaceModeActive );
     527             : }
     528             : 
     529             : /**
     530             :  * We can create multiple NumFields
     531             :  * Tricky, if one enters enough previous-text in the dialog box
     532             :  * to cause the line to overflow
     533             :  * We need to keep the Fly's evasion tactics in mind
     534             :  */
     535       15796 : bool SwNumberPortion::Format( SwTextFormatInfo &rInf )
     536             : {
     537       15796 :     SetHide( false );
     538       15796 :     const bool bFull = SwFieldPortion::Format( rInf );
     539       15796 :     SetLen( 0 );
     540             :     // a numbering portion can be contained in a rotated portion!!!
     541       15796 :     nFixWidth = rInf.IsMulti() ? Height() : Width();
     542       15796 :     rInf.SetNumDone( !rInf.GetRest() );
     543       15796 :     if( rInf.IsNumDone() )
     544             :     {
     545             : //        SetAscent( rInf.GetAscent() );
     546             :         OSL_ENSURE( Height() && nAscent, "NumberPortions without Height | Ascent" );
     547             : 
     548        7132 :         long nDiff( 0 );
     549             : 
     550        7132 :         if ( !mbLabelAlignmentPosAndSpaceModeActive )
     551             :         {
     552        1151 :             if ( !rInf.GetTextFrm()->GetTextNode()->getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) &&
     553             :                  // #i32902#
     554         568 :                  !IsFootnoteNumPortion() )
     555             :             {
     556         436 :                 nDiff = rInf.Left()
     557         872 :                     + rInf.GetTextFrm()->GetTextNode()->
     558         436 :                     GetSwAttrSet().GetLRSpace().GetTextFirstLineOfst()
     559         436 :                     - rInf.First()
     560         436 :                     + rInf.ForcedLeftMargin();
     561             :             }
     562             :             else
     563             :             {
     564         147 :                 nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
     565             :             }
     566             :         }
     567             :         // The text part of the numbering should always at least
     568             :         // start at the left margin
     569        7132 :         if( nDiff < 0 )
     570           3 :             nDiff = 0;
     571        7129 :         else if ( nDiff > rInf.X() )
     572         533 :             nDiff -= rInf.X();
     573             :         else
     574        6596 :             nDiff = 0;
     575             : 
     576        7132 :         if( nDiff < nFixWidth + nMinDist )
     577         155 :             nDiff = nFixWidth + nMinDist;
     578             : 
     579             :         // Numbering evades the Fly, no nDiff in the second round
     580             :         // Tricky special case: FlyFrm is in an Area we're just about to
     581             :         // acquire
     582             :         // The NumberPortion is marked as hidden
     583       14264 :         const bool bFly = rInf.GetFly() ||
     584       21396 :             ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() );
     585        7132 :         if( nDiff > rInf.Width() )
     586             :         {
     587           0 :             nDiff = rInf.Width();
     588           0 :             if ( bFly )
     589           0 :                 SetHide( true );
     590             :         }
     591             : 
     592             :         // A numbering portion can be inside a SwRotatedPortion. Then the
     593             :         // Height has to be changed
     594        7132 :         if ( rInf.IsMulti() )
     595             :         {
     596           0 :             if ( Height() < nDiff )
     597           0 :                 Height( sal_uInt16( nDiff ) );
     598             :         }
     599        7132 :         else if( Width() < nDiff )
     600         493 :             Width( sal_uInt16(nDiff) );
     601             :     }
     602       15796 :     return bFull;
     603             : }
     604             : 
     605             : 
     606             : /**
     607             :  * A FormatEOL indicates that the subsequent text did not fit onto
     608             :  * the line anymore. In order for the Numbering to follow through,
     609             :  * we hide this NumberPortion
     610             :  */
     611          14 : void SwNumberPortion::FormatEOL( SwTextFormatInfo& )
     612             : {
     613             : 
     614             :     // This caused trouble with flys anchored as characters.
     615             :     // If one of these is numbered but does not fit to the line,
     616             :     // it calls this function, causing a loop because both the number
     617             :     // portion and the fly portion go to the next line
     618             : //    SetHide( true );
     619          14 : }
     620             : 
     621             : 
     622             : /**
     623             :  * A hidden NumberPortion is not displayed, unless there are TextPortions in
     624             :  * this line or there's just one line at all
     625             :  */
     626         681 : void SwNumberPortion::Paint( const SwTextPaintInfo &rInf ) const
     627             : {
     628         681 :     if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() )
     629             :     {
     630           0 :         SwLinePortion *pTmp = GetPortion();
     631           0 :         while ( pTmp && !pTmp->InTextGrp() )
     632           0 :             pTmp = pTmp->GetPortion();
     633           0 :         if ( !pTmp )
     634         681 :             return;
     635             :     }
     636             : 
     637             :     // calculate the width of the number portion, including follows
     638         681 :     const sal_uInt16 nOldWidth = Width();
     639         681 :     sal_uInt16 nSumWidth = 0;
     640         681 :     sal_uInt16 nOffset = 0;
     641             : 
     642         681 :     const SwLinePortion* pTmp = this;
     643        1605 :     while ( pTmp && pTmp->InNumberGrp() )
     644             :     {
     645         731 :         nSumWidth = nSumWidth + pTmp->Width();
     646         731 :         if ( static_cast<const SwNumberPortion*>(pTmp)->HasFollow() )
     647         243 :             pTmp = pTmp->GetPortion();
     648             :         else
     649             :         {
     650         488 :             nOffset = pTmp->Width() - static_cast<const SwNumberPortion*>(pTmp)->nFixWidth;
     651         488 :             break;
     652             :         }
     653             :     }
     654             : 
     655             :     // The master portion takes care for painting the background of the
     656             :     // follow field portions
     657         681 :     if ( ! IsFollow() )
     658             :     {
     659         631 :         SwLinePortion *pThis = const_cast<SwLinePortion*>(static_cast<SwLinePortion const *>(this));
     660         631 :         pThis->Width( nSumWidth );
     661         631 :         rInf.DrawViewOpt( *this, POR_NUMBER );
     662         631 :         pThis->Width( nOldWidth );
     663             :     }
     664             : 
     665         681 :     if( !aExpand.isEmpty() )
     666             :     {
     667         681 :         const SwFont *pTmpFnt = rInf.GetFont();
     668        1362 :         bool bPaintSpace = ( UNDERLINE_NONE != pTmpFnt->GetUnderline() ||
     669        1362 :                                  UNDERLINE_NONE != pTmpFnt->GetOverline()  ||
     670        1362 :                                  STRIKEOUT_NONE != pTmpFnt->GetStrikeout() ) &&
     671         681 :                                  !pTmpFnt->IsWordLineMode();
     672         681 :         if( bPaintSpace && pFnt )
     673           0 :             bPaintSpace = ( UNDERLINE_NONE != pFnt->GetUnderline() ||
     674           0 :                             UNDERLINE_NONE != pFnt->GetOverline()  ||
     675           0 :                             STRIKEOUT_NONE != pFnt->GetStrikeout() ) &&
     676           0 :                             !pFnt->IsWordLineMode();
     677             : 
     678         681 :         SwFontSave aSave( rInf, pFnt );
     679             : 
     680         681 :         if( nFixWidth == Width() && ! HasFollow() )
     681          48 :             SwExpandPortion::Paint( rInf );
     682             :         else
     683             :         {
     684             :             // logical const: reset width
     685         633 :             SwLinePortion *pThis = const_cast<SwLinePortion*>(static_cast<SwLinePortion const *>(this));
     686         633 :             bPaintSpace = bPaintSpace && nFixWidth < nOldWidth;
     687         633 :             sal_uInt16 nSpaceOffs = nFixWidth;
     688         633 :             pThis->Width( nFixWidth );
     689             : 
     690        1266 :             if( ( IsLeft() && ! rInf.GetTextFrm()->IsRightToLeft() ) ||
     691           0 :                 ( ! IsLeft() && ! IsCenter() && rInf.GetTextFrm()->IsRightToLeft() ) )
     692         633 :                 SwExpandPortion::Paint( rInf );
     693             :             else
     694             :             {
     695           0 :                 SwTextPaintInfo aInf( rInf );
     696           0 :                 if( nOffset < nMinDist )
     697           0 :                     nOffset = 0;
     698             :                 else
     699             :                 {
     700           0 :                     if( IsCenter() )
     701             :                     {
     702             :                         /* #110778# a / 2 * 2 == a is not a tautology */
     703           0 :                         sal_uInt16 nTmpOffset = nOffset;
     704           0 :                         nOffset /= 2;
     705           0 :                         if( nOffset < nMinDist )
     706           0 :                             nOffset = nTmpOffset - nMinDist;
     707             :                     }
     708             :                     else
     709           0 :                         nOffset = nOffset - nMinDist;
     710             :                 }
     711           0 :                 aInf.X( aInf.X() + nOffset );
     712           0 :                 SwExpandPortion::Paint( aInf );
     713           0 :                 if( bPaintSpace )
     714           0 :                     nSpaceOffs = nSpaceOffs + nOffset;
     715             :             }
     716         633 :             if( bPaintSpace && nOldWidth > nSpaceOffs )
     717             :             {
     718           0 :                 SwTextPaintInfo aInf( rInf );
     719           0 :                 aInf.X( aInf.X() + nSpaceOffs );
     720             : 
     721             :                 // #i53199# Adjust position of underline:
     722           0 :                 if ( rInf.GetUnderFnt() )
     723             :                 {
     724           0 :                     const Point aNewPos( aInf.GetPos().X(), rInf.GetUnderFnt()->GetPos().Y() );
     725           0 :                     rInf.GetUnderFnt()->SetPos( aNewPos );
     726             :                 }
     727             : 
     728           0 :                 pThis->Width( nOldWidth - nSpaceOffs + 12 );
     729             :                 {
     730           0 :                     SwTextSlot aDiffText( &aInf, this, true, false, "  " );
     731           0 :                     aInf.DrawText( *this, aInf.GetLen(), true );
     732           0 :                 }
     733             :             }
     734         633 :             pThis->Width( nOldWidth );
     735         681 :         }
     736             :     }
     737             : }
     738             : 
     739        2443 : SwBulletPortion::SwBulletPortion( const sal_Unicode cBullet,
     740             :                                   const OUString& rBulletFollowedBy,
     741             :                                   SwFont *pFont,
     742             :                                   const bool bLft,
     743             :                                   const bool bCntr,
     744             :                                   const sal_uInt16 nMinDst,
     745             :                                   const bool bLabelAlignmentPosAndSpaceModeActive )
     746        4886 :     : SwNumberPortion( OUString(cBullet) + rBulletFollowedBy,
     747             :                        pFont, bLft, bCntr, nMinDst,
     748        7329 :                        bLabelAlignmentPosAndSpaceModeActive )
     749             : {
     750        2443 :     SetWhichPor( POR_BULLET );
     751        2443 : }
     752             : 
     753             : #define GRFNUM_SECURE 10
     754             : 
     755          70 : SwGrfNumPortion::SwGrfNumPortion(
     756             :         SwFrm*,
     757             :         const OUString& rGraphicFollowedBy,
     758             :         const SvxBrushItem* pGrfBrush,
     759             :         const SwFormatVertOrient* pGrfOrient, const Size& rGrfSize,
     760             :         const bool bLft, const bool bCntr, const sal_uInt16 nMinDst,
     761             :         const bool bLabelAlignmentPosAndSpaceModeActive ) :
     762             :     SwNumberPortion( rGraphicFollowedBy, NULL, bLft, bCntr, nMinDst,
     763             :                      bLabelAlignmentPosAndSpaceModeActive ),
     764          70 :     pBrush( new SvxBrushItem(RES_BACKGROUND) ), nId( 0 )
     765             : {
     766          70 :     SetWhichPor( POR_GRFNUM );
     767          70 :     SetAnimated( false );
     768          70 :     bReplace = false;
     769          70 :     if( pGrfBrush )
     770             :     {
     771          70 :         *pBrush = *pGrfBrush;
     772          70 :         const Graphic* pGraph = pGrfBrush->GetGraphic();
     773          70 :         if( pGraph )
     774          70 :             SetAnimated( pGraph->IsAnimated() );
     775             :         else
     776           0 :             bReplace = true;
     777             :     }
     778          70 :     if( pGrfOrient )
     779             :     {
     780           0 :         nYPos = pGrfOrient->GetPos();
     781           0 :         eOrient = pGrfOrient->GetVertOrient();
     782             :     }
     783             :     else
     784             :     {
     785          70 :         nYPos = 0;
     786          70 :         eOrient = text::VertOrientation::TOP;
     787             :     }
     788          70 :     Width( static_cast<sal_uInt16>(rGrfSize.Width() + 2 * GRFNUM_SECURE) );
     789          70 :     nFixWidth = Width();
     790          70 :     nGrfHeight = rGrfSize.Height() + 2 * GRFNUM_SECURE;
     791          70 :     Height( sal_uInt16(nGrfHeight) );
     792          70 :     bNoPaint = false;
     793          70 : }
     794             : 
     795         210 : SwGrfNumPortion::~SwGrfNumPortion()
     796             : {
     797          70 :     if ( IsAnimated() )
     798             :     {
     799           0 :         Graphic* pGraph = const_cast<Graphic*>(pBrush->GetGraphic());
     800           0 :         if (pGraph)
     801           0 :             pGraph->StopAnimation( 0, nId );
     802             :     }
     803          70 :     delete pBrush;
     804         140 : }
     805             : 
     806           0 : void SwGrfNumPortion::StopAnimation( OutputDevice* pOut )
     807             : {
     808           0 :     if ( IsAnimated() )
     809             :     {
     810           0 :         Graphic* pGraph = const_cast<Graphic*>(pBrush->GetGraphic());
     811           0 :         if (pGraph)
     812           0 :             pGraph->StopAnimation( pOut, nId );
     813             :     }
     814           0 : }
     815             : 
     816          70 : bool SwGrfNumPortion::Format( SwTextFormatInfo &rInf )
     817             : {
     818          70 :     SetHide( false );
     819             : //    Width( nFixWidth );
     820          70 :     sal_uInt16 nFollowedByWidth( 0 );
     821          70 :     if ( mbLabelAlignmentPosAndSpaceModeActive )
     822             :     {
     823          70 :         SwFieldPortion::Format( rInf );
     824          70 :         nFollowedByWidth = Width();
     825          70 :         SetLen( 0 );
     826             :     }
     827          70 :     Width( nFixWidth + nFollowedByWidth );
     828          70 :     const bool bFull = rInf.Width() < rInf.X() + Width();
     829         140 :     const bool bFly = rInf.GetFly() ||
     830         210 :         ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() );
     831          70 :     SetAscent( static_cast<sal_uInt16>(GetRelPos() > 0 ? GetRelPos() : 0) );
     832          70 :     if( GetAscent() > Height() )
     833           0 :         Height( GetAscent() );
     834             : 
     835          70 :     if( bFull )
     836             :     {
     837           0 :         Width( rInf.Width() - (sal_uInt16)rInf.X() );
     838           0 :         if( bFly )
     839             :         {
     840           0 :             SetLen( 0 );
     841           0 :             SetNoPaint( true );
     842           0 :             rInf.SetNumDone( false );
     843           0 :             return true;
     844             :         }
     845             :     }
     846          70 :     rInf.SetNumDone( true );
     847             : //    long nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
     848             :     long nDiff = mbLabelAlignmentPosAndSpaceModeActive
     849             :                  ? 0
     850          70 :                  : rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
     851             :     // The TextPortion should at least always start on the
     852             :     // left margin
     853          70 :     if( nDiff < 0 )
     854           0 :         nDiff = 0;
     855          70 :     else if ( nDiff > rInf.X() )
     856           0 :         nDiff -= rInf.X();
     857          70 :     if( nDiff < nFixWidth + nMinDist )
     858          70 :         nDiff = nFixWidth + nMinDist;
     859             : 
     860             :     // Numbering evades Fly, no nDiff in the second round
     861             :     // Tricky special case: FlyFrm is in the Area we were just
     862             :     // about to get a hold of.
     863             :     // The NumberPortion is marked as hidden
     864          70 :     if( nDiff > rInf.Width() )
     865             :     {
     866           0 :         nDiff = rInf.Width();
     867           0 :         if( bFly )
     868           0 :             SetHide( true );
     869             :     }
     870             : 
     871          70 :     if( Width() < nDiff )
     872           0 :         Width( sal_uInt16(nDiff) );
     873          70 :     return bFull;
     874             : }
     875             : 
     876             : 
     877             : /**
     878             :  * A hidden NumberPortion is not displayed, unless there are TextPortions in
     879             :  * this line or there's only one line at all
     880             :  */
     881           0 : void SwGrfNumPortion::Paint( const SwTextPaintInfo &rInf ) const
     882             : {
     883           0 :     if( DontPaint() )
     884           0 :         return;
     885           0 :     if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() )
     886             :     {
     887           0 :         SwLinePortion *pTmp = GetPortion();
     888           0 :         while ( pTmp && !pTmp->InTextGrp() )
     889           0 :             pTmp = pTmp->GetPortion();
     890           0 :         if ( !pTmp )
     891           0 :             return;
     892             :     }
     893           0 :     Point aPos( rInf.X() + GRFNUM_SECURE, rInf.Y() - GetRelPos() + GRFNUM_SECURE );
     894           0 :     long nTmpWidth = std::max( (long)0, (long)(nFixWidth - 2 * GRFNUM_SECURE) );
     895           0 :     Size aSize( nTmpWidth, GetGrfHeight() - 2 * GRFNUM_SECURE );
     896             : 
     897           0 :     const bool bTmpLeft = mbLabelAlignmentPosAndSpaceModeActive ||
     898           0 :                               ( IsLeft() && ! rInf.GetTextFrm()->IsRightToLeft() ) ||
     899           0 :                               ( ! IsLeft() && ! IsCenter() && rInf.GetTextFrm()->IsRightToLeft() );
     900             : 
     901           0 :     if( nFixWidth < Width() && !bTmpLeft )
     902             :     {
     903           0 :         sal_uInt16 nOffset = Width() - nFixWidth;
     904           0 :         if( nOffset < nMinDist )
     905           0 :             nOffset = 0;
     906             :         else
     907             :         {
     908           0 :             if( IsCenter() )
     909             :             {
     910           0 :                 nOffset /= 2;
     911           0 :                 if( nOffset < nMinDist )
     912           0 :                     nOffset = Width() - nFixWidth - nMinDist;
     913             :             }
     914             :             else
     915           0 :                 nOffset = nOffset - nMinDist;
     916             :         }
     917           0 :         aPos.X() += nOffset;
     918             :     }
     919             : 
     920           0 :     if( bReplace )
     921             :     {
     922           0 :         const long nTmpH = GetPortion() ? GetPortion()->GetAscent() : 120;
     923           0 :         aSize = Size( nTmpH, nTmpH );
     924           0 :         aPos.Y() = rInf.Y() - nTmpH;
     925             :     }
     926           0 :     SwRect aTmp( aPos, aSize );
     927             : 
     928           0 :     bool bDraw = true;
     929             : 
     930           0 :     if ( IsAnimated() )
     931             :     {
     932           0 :         bDraw = !rInf.GetOpt().IsGraphic();
     933           0 :         if( !nId )
     934             :         {
     935           0 :             SetId( sal_IntPtr( rInf.GetTextFrm() ) );
     936           0 :             rInf.GetTextFrm()->SetAnimation();
     937             :         }
     938           0 :         if( aTmp.IsOver( rInf.GetPaintRect() ) && !bDraw )
     939             :         {
     940           0 :             rInf.NoteAnimation();
     941           0 :             const SwViewShell* pViewShell = rInf.GetVsh();
     942             : 
     943             :             // virtual device, not pdf export
     944           0 :             if( OUTDEV_VIRDEV == rInf.GetOut()->GetOutDevType() &&
     945           0 :                 pViewShell && pViewShell->GetWin()  )
     946             :             {
     947           0 :                 Graphic* pGraph = const_cast<Graphic*>(pBrush->GetGraphic());
     948           0 :                 if (pGraph)
     949           0 :                     pGraph->StopAnimation(0,nId);
     950           0 :                 rInf.GetTextFrm()->getRootFrm()->GetCurrShell()->InvalidateWindows( aTmp );
     951             :             }
     952             : 
     953           0 :             else if ( pViewShell &&
     954           0 :                      !pViewShell->GetAccessibilityOptions()->IsStopAnimatedGraphics() &&
     955           0 :                      !pViewShell->IsPreview() &&
     956             :                       // #i9684# Stop animation during printing/pdf export.
     957           0 :                       pViewShell->GetWin() )
     958             :             {
     959           0 :                 Graphic* pGraph = const_cast<Graphic*>(pBrush->GetGraphic());
     960           0 :                 if (pGraph)
     961             :                 {
     962             :                     pGraph->StartAnimation(
     963           0 :                         const_cast<OutputDevice*>(rInf.GetOut()), aPos, aSize, nId );
     964             :                 }
     965             :             }
     966             : 
     967             :             // pdf export, printing, preview, stop animations...
     968             :             else
     969           0 :                 bDraw = true;
     970             :         }
     971           0 :         if( bDraw )
     972             :         {
     973             : 
     974           0 :             Graphic* pGraph = const_cast<Graphic*>(pBrush->GetGraphic());
     975           0 :             if (pGraph)
     976           0 :                 pGraph->StopAnimation( 0, nId );
     977             :         }
     978             :     }
     979             : 
     980           0 :     SwRect aRepaint( rInf.GetPaintRect() );
     981           0 :     const SwTextFrm& rFrm = *rInf.GetTextFrm();
     982           0 :     if( rFrm.IsVertical() )
     983             :     {
     984           0 :         rFrm.SwitchHorizontalToVertical( aTmp );
     985           0 :         rFrm.SwitchHorizontalToVertical( aRepaint );
     986             :     }
     987             : 
     988           0 :     if( rFrm.IsRightToLeft() )
     989             :     {
     990           0 :         rFrm.SwitchLTRtoRTL( aTmp );
     991           0 :         rFrm.SwitchLTRtoRTL( aRepaint );
     992             :     }
     993             : 
     994           0 :     if( bDraw && aTmp.HasArea() )
     995             :     {
     996           0 :         DrawGraphic( pBrush, const_cast<OutputDevice*>(rInf.GetOut()),
     997           0 :             aTmp, aRepaint, bReplace ? GRFNUM_REPLACE : GRFNUM_YES );
     998             :     }
     999             : }
    1000             : 
    1001          70 : void SwGrfNumPortion::SetBase( long nLnAscent, long nLnDescent,
    1002             :                                long nFlyAsc, long nFlyDesc )
    1003             : {
    1004          70 :     if ( GetOrient() != text::VertOrientation::NONE )
    1005             :     {
    1006          70 :         SetRelPos( 0 );
    1007          70 :         if ( GetOrient() == text::VertOrientation::CENTER )
    1008           0 :             SetRelPos( GetGrfHeight() / 2 );
    1009          70 :         else if ( GetOrient() == text::VertOrientation::TOP )
    1010          70 :             SetRelPos( GetGrfHeight() - GRFNUM_SECURE );
    1011           0 :         else if ( GetOrient() == text::VertOrientation::BOTTOM )
    1012             :             ;
    1013           0 :         else if ( GetOrient() == text::VertOrientation::CHAR_CENTER )
    1014           0 :             SetRelPos( ( GetGrfHeight() + nLnAscent - nLnDescent ) / 2 );
    1015           0 :         else if ( GetOrient() == text::VertOrientation::CHAR_TOP )
    1016           0 :             SetRelPos( nLnAscent );
    1017           0 :         else if ( GetOrient() == text::VertOrientation::CHAR_BOTTOM )
    1018           0 :             SetRelPos( GetGrfHeight() - nLnDescent );
    1019             :         else
    1020             :         {
    1021           0 :             if( GetGrfHeight() >= nFlyAsc + nFlyDesc )
    1022             :             {
    1023             :                 // If I'm as large as the line, I do not need to adjust
    1024             :                 // at the line; I'll leave the max. ascent unchanged
    1025           0 :                 SetRelPos( nFlyAsc );
    1026             :             }
    1027           0 :             else if ( GetOrient() == text::VertOrientation::LINE_CENTER )
    1028           0 :                 SetRelPos( ( GetGrfHeight() + nFlyAsc - nFlyDesc ) / 2 );
    1029           0 :             else if ( GetOrient() == text::VertOrientation::LINE_TOP )
    1030           0 :                 SetRelPos( nFlyAsc );
    1031           0 :             else if ( GetOrient() == text::VertOrientation::LINE_BOTTOM )
    1032           0 :                 SetRelPos( GetGrfHeight() - nFlyDesc );
    1033             :         }
    1034             :     }
    1035          70 : }
    1036             : 
    1037           0 : void SwTextFrm::StopAnimation( OutputDevice* pOut )
    1038             : {
    1039             :     OSL_ENSURE( HasAnimation(), "SwTextFrm::StopAnimation: Which Animation?" );
    1040           0 :     if( HasPara() )
    1041             :     {
    1042           0 :         SwLineLayout *pLine = GetPara();
    1043           0 :         while( pLine )
    1044             :         {
    1045           0 :             SwLinePortion *pPor = pLine->GetPortion();
    1046           0 :             while( pPor )
    1047             :             {
    1048           0 :                 if( pPor->IsGrfNumPortion() )
    1049           0 :                     static_cast<SwGrfNumPortion*>(pPor)->StopAnimation( pOut );
    1050             :                 // The NumberPortion is always at the first char,
    1051             :                 // which means we can cancel as soon as we've reached a portion
    1052             :                 // with a length > 0
    1053           0 :                 pPor = pPor->GetLen() ? 0 : pPor->GetPortion();
    1054             :             }
    1055           0 :             pLine = pLine->GetLen() ? 0 : pLine->GetNext();
    1056             :         }
    1057             :     }
    1058           0 : }
    1059             : 
    1060             : /**
    1061             :  * Initializes the script array and clears the width array
    1062             :  */
    1063           0 : SwCombinedPortion::SwCombinedPortion( const OUString &rText )
    1064             :     : SwFieldPortion( rText )
    1065             :     , nUpPos(0)
    1066             :     , nLowPos(0)
    1067           0 :     , nProportion(55)
    1068             : {
    1069           0 :     SetLen(1);
    1070           0 :     SetWhichPor( POR_COMBINED );
    1071           0 :     if( aExpand.getLength() > 6 )
    1072           0 :         aExpand = aExpand.copy( 0, 6 );
    1073             : 
    1074             :     // Initialization of the scripttype array,
    1075             :     // the arrays of width and position are filled by the format function
    1076           0 :     if( g_pBreakIt->GetBreakIter().is() )
    1077             :     {
    1078           0 :         sal_uInt8 nScr = SW_SCRIPTS;
    1079           0 :         for( sal_Int32 i = 0; i < rText.getLength(); ++i )
    1080             :         {
    1081           0 :             switch ( g_pBreakIt->GetBreakIter()->getScriptType( rText, i ) ) {
    1082           0 :                 case i18n::ScriptType::LATIN : nScr = SW_LATIN; break;
    1083           0 :                 case i18n::ScriptType::ASIAN : nScr = SW_CJK; break;
    1084           0 :                 case i18n::ScriptType::COMPLEX : nScr = SW_CTL; break;
    1085             :             }
    1086           0 :             aScrType[i] = nScr;
    1087             :         }
    1088             :     }
    1089             :     else
    1090             :     {
    1091           0 :         for( int i = 0; i < 6; ++i )
    1092           0 :             aScrType[i] = 0;
    1093             :     }
    1094           0 :     memset( &aWidth, 0, sizeof(aWidth) );
    1095           0 : }
    1096             : 
    1097           0 : void SwCombinedPortion::Paint( const SwTextPaintInfo &rInf ) const
    1098             : {
    1099             :     OSL_ENSURE( GetLen() <= 1, "SwFieldPortion::Paint: rest-portion pollution?" );
    1100           0 :     if( Width() )
    1101             :     {
    1102           0 :         rInf.DrawBackBrush( *this );
    1103           0 :         rInf.DrawViewOpt( *this, POR_FLD );
    1104             : 
    1105             :         // do we have to repaint a post it portion?
    1106           0 :         if( rInf.OnWin() && pPortion && !pPortion->Width() )
    1107           0 :             pPortion->PrePaint( rInf, this );
    1108             : 
    1109           0 :         const sal_Int32 nCount = aExpand.getLength();
    1110           0 :         if( !nCount )
    1111           0 :             return;
    1112             :         OSL_ENSURE( nCount < 7, "Too much combined characters" );
    1113             : 
    1114             :         // the first character of the second row
    1115           0 :         const sal_Int32 nTop = ( nCount + 1 ) / 2;
    1116             : 
    1117           0 :         SwFont aTmpFont( *rInf.GetFont() );
    1118           0 :         aTmpFont.SetProportion( nProportion );  // a smaller font
    1119           0 :         SwFontSave aFontSave( rInf, &aTmpFont );
    1120             : 
    1121           0 :         Point aOldPos = rInf.GetPos();
    1122           0 :         Point aOutPos( aOldPos.X(), aOldPos.Y() - nUpPos );// Y of the first row
    1123           0 :         for( sal_Int32 i = 0 ; i < nCount; ++i )
    1124             :         {
    1125           0 :             if( i == nTop ) // change the row
    1126           0 :                 aOutPos.Y() = aOldPos.Y() + nLowPos;    // Y of the second row
    1127           0 :             aOutPos.X() = aOldPos.X() + aPos[i];        // X position
    1128           0 :             const sal_uInt8 nAct = aScrType[i];        // script type
    1129           0 :             aTmpFont.SetActual( nAct );
    1130             : 
    1131             :             // if there're more than 4 characters to display, we choose fonts
    1132             :             // with 2/3 of the original font width.
    1133           0 :             if( aWidth[ nAct ] )
    1134             :             {
    1135           0 :                 Size aTmpSz = aTmpFont.GetSize( nAct );
    1136           0 :                 if( aTmpSz.Width() != aWidth[ nAct ] )
    1137             :                 {
    1138           0 :                     aTmpSz.Width() = aWidth[ nAct ];
    1139           0 :                     aTmpFont.SetSize( aTmpSz, nAct );
    1140             :                 }
    1141             :             }
    1142           0 :             const_cast<SwTextPaintInfo&>(rInf).SetPos( aOutPos );
    1143           0 :             rInf.DrawText( aExpand, *this, i, 1 );
    1144             :         }
    1145             :         // rInf is const, so we have to take back our manipulations
    1146           0 :         const_cast<SwTextPaintInfo&>(rInf).SetPos( aOldPos );
    1147             :     }
    1148             : }
    1149             : 
    1150           0 : bool SwCombinedPortion::Format( SwTextFormatInfo &rInf )
    1151             : {
    1152           0 :     const sal_Int32 nCount = aExpand.getLength();
    1153           0 :     if( !nCount )
    1154             :     {
    1155           0 :         Width( 0 );
    1156           0 :         return false;
    1157             :     }
    1158             : 
    1159             :     OSL_ENSURE( nCount < 7, "Too much combined characters" );
    1160             : 
    1161             :     // If there are leading "weak"-scripttyped characters in this portion,
    1162             :     // they get the actual scripttype.
    1163           0 :     for( sal_Int32 i = 0; i < nCount && SW_SCRIPTS == aScrType[i]; ++i )
    1164           0 :         aScrType[i] = rInf.GetFont()->GetActual();
    1165           0 :     if( nCount > 4 )
    1166             :     {
    1167             :         // more than four? Ok, then we need the 2/3 font width
    1168           0 :         for( sal_Int32 i = 0; i < aExpand.getLength(); ++i )
    1169             :         {
    1170             :             OSL_ENSURE( aScrType[i] < SW_SCRIPTS, "Combined: Script fault" );
    1171           0 :             if( !aWidth[ aScrType[i] ] )
    1172             :             {
    1173           0 :                 rInf.GetOut()->SetFont( rInf.GetFont()->GetFnt( aScrType[i] ) );
    1174           0 :                 aWidth[ aScrType[i] ] =
    1175           0 :                         static_cast<sal_uInt16>(2 * rInf.GetOut()->GetFontMetric().GetSize().Width() / 3);
    1176             :             }
    1177             :         }
    1178             :     }
    1179             : 
    1180           0 :     const sal_Int32 nTop = ( nCount + 1 ) / 2; // the first character of the second line
    1181           0 :     SwViewShell *pSh = rInf.GetTextFrm()->getRootFrm()->GetCurrShell();
    1182           0 :     SwFont aTmpFont( *rInf.GetFont() );
    1183           0 :     SwFontSave aFontSave( rInf, &aTmpFont );
    1184           0 :     nProportion = 55;
    1185             :     // In nMainAscent/Descent we store the ascent and descent
    1186             :     // of the original surrounding font
    1187             :     sal_uInt16 nMaxDescent, nMaxAscent, nMaxWidth;
    1188           0 :     sal_uInt16 nMainDescent = rInf.GetFont()->GetHeight( pSh, *rInf.GetOut() );
    1189           0 :     const sal_uInt16 nMainAscent = rInf.GetFont()->GetAscent( pSh, *rInf.GetOut() );
    1190           0 :     nMainDescent = nMainDescent - nMainAscent;
    1191             :     // we start with a 50% font, but if we notice that the combined portion
    1192             :     // becomes bigger than the surrounding font, we check 45% and maybe 40%.
    1193           0 :     do
    1194             :     {
    1195           0 :         nProportion -= 5;
    1196           0 :         aTmpFont.SetProportion( nProportion );
    1197           0 :         memset( &aPos, 0, sizeof(aPos) );
    1198           0 :         nMaxDescent = 0;
    1199           0 :         nMaxAscent = 0;
    1200           0 :         nMaxWidth = 0;
    1201           0 :         nUpPos = nLowPos = 0;
    1202             : 
    1203             :         // Now we get the width of all characters.
    1204             :         // The ascent and the width of the first line are stored in the
    1205             :         // ascent member of the portion, the descent in nLowPos.
    1206             :         // The ascent, descent and width of the second line are stored in the
    1207             :         // local nMaxAscent, nMaxDescent and nMaxWidth variables.
    1208           0 :         for( sal_Int32 i = 0; i < nCount; ++i )
    1209             :         {
    1210           0 :             sal_uInt8 nScrp = aScrType[i];
    1211           0 :             aTmpFont.SetActual( nScrp );
    1212           0 :             if( aWidth[ nScrp ] )
    1213             :             {
    1214           0 :                 Size aFontSize( aTmpFont.GetSize( nScrp ) );
    1215           0 :                 aFontSize.Width() = aWidth[ nScrp ];
    1216           0 :                 aTmpFont.SetSize( aFontSize, nScrp );
    1217             :             }
    1218             : 
    1219           0 :             SwDrawTextInfo aDrawInf( pSh, *rInf.GetOut(), 0, aExpand, i, 1 );
    1220           0 :             Size aSize = aTmpFont._GetTextSize( aDrawInf );
    1221           0 :             const sal_uInt16 nAsc = aTmpFont.GetAscent( pSh, *rInf.GetOut() );
    1222           0 :             aPos[ i ] = (sal_uInt16)aSize.Width();
    1223           0 :             if( i == nTop ) // enter the second line
    1224             :             {
    1225           0 :                 nLowPos = nMaxDescent;
    1226           0 :                 Height( nMaxDescent + nMaxAscent );
    1227           0 :                 Width( nMaxWidth );
    1228           0 :                 SetAscent( nMaxAscent );
    1229           0 :                 nMaxAscent = 0;
    1230           0 :                 nMaxDescent = 0;
    1231           0 :                 nMaxWidth = 0;
    1232             :             }
    1233           0 :             nMaxWidth = nMaxWidth + aPos[ i ];
    1234           0 :             if( nAsc > nMaxAscent )
    1235           0 :                 nMaxAscent = nAsc;
    1236           0 :             if( aSize.Height() - nAsc > nMaxDescent )
    1237           0 :                 nMaxDescent = static_cast<sal_uInt16>(aSize.Height() - nAsc);
    1238           0 :         }
    1239             :         // for one or two characters we double the width of the portion
    1240           0 :         if( nCount < 3 )
    1241             :         {
    1242           0 :             nMaxWidth *= 2;
    1243           0 :             Width( 2*Width() );
    1244           0 :             if( nCount < 2 )
    1245             :             {
    1246           0 :                 Height( nMaxAscent + nMaxDescent );
    1247           0 :                 nLowPos = nMaxDescent;
    1248             :             }
    1249             :         }
    1250           0 :         Height( Height() + nMaxDescent + nMaxAscent );
    1251           0 :         nUpPos = nMaxAscent;
    1252           0 :         SetAscent( Height() - nMaxDescent - nLowPos );
    1253           0 :     } while( nProportion > 40 && ( GetAscent() > nMainAscent ||
    1254           0 :                                     Height() - GetAscent() > nMainDescent ) );
    1255             :     // if the combined portion is smaller than the surrounding text,
    1256             :     // the portion grows. This looks better, if there's a character background.
    1257           0 :     if( GetAscent() < nMainAscent )
    1258             :     {
    1259           0 :         Height( Height() + nMainAscent - GetAscent() );
    1260           0 :         SetAscent( nMainAscent );
    1261             :     }
    1262           0 :     if( Height() < nMainAscent + nMainDescent )
    1263           0 :         Height( nMainAscent + nMainDescent );
    1264             : 
    1265             :     // We calculate the x positions of the characters in both lines..
    1266           0 :     sal_uInt16 nTopDiff = 0;
    1267           0 :     sal_uInt16 nBotDiff = 0;
    1268           0 :     if( nMaxWidth > Width() )
    1269             :     {
    1270           0 :         nTopDiff = ( nMaxWidth - Width() ) / 2;
    1271           0 :         Width( nMaxWidth );
    1272             :     }
    1273             :     else
    1274           0 :         nBotDiff = ( Width() - nMaxWidth ) / 2;
    1275           0 :     switch( nTop)
    1276             :     {
    1277           0 :         case 3: aPos[1] = aPos[0] + nTopDiff;  // no break
    1278           0 :         case 2: aPos[nTop-1] = Width() - aPos[nTop-1];
    1279             :     }
    1280           0 :     aPos[0] = 0;
    1281           0 :     switch( nCount )
    1282             :     {
    1283           0 :         case 5: aPos[4] = aPos[3] + nBotDiff;   // no break
    1284           0 :         case 3: aPos[nTop] = nBotDiff;          break;
    1285           0 :         case 6: aPos[4] = aPos[3] + nBotDiff;   // no break
    1286           0 :         case 4: aPos[nTop] = 0;                 // no break
    1287           0 :         case 2: aPos[nCount-1] = Width() - aPos[nCount-1];
    1288             :     }
    1289             : 
    1290             :     // Does the combined portion fit the line?
    1291           0 :     const bool bFull = rInf.Width() < rInf.X() + Width();
    1292           0 :     if( bFull )
    1293             :     {
    1294           0 :         if( rInf.GetLineStart() == rInf.GetIdx() && (!rInf.GetLast()->InFieldGrp()
    1295           0 :             || !static_cast<SwFieldPortion*>(rInf.GetLast())->IsFollow() ) )
    1296           0 :             Width( (sal_uInt16)( rInf.Width() - rInf.X() ) );
    1297             :         else
    1298             :         {
    1299           0 :             Truncate();
    1300           0 :             Width( 0 );
    1301           0 :             SetLen( 0 );
    1302           0 :             if( rInf.GetLast() )
    1303           0 :                 rInf.GetLast()->FormatEOL( rInf );
    1304             :         }
    1305             :     }
    1306           0 :     return bFull;
    1307             : }
    1308             : 
    1309           0 : sal_uInt16 SwCombinedPortion::GetViewWidth( const SwTextSizeInfo &rInf ) const
    1310             : {
    1311           0 :     if( !GetLen() ) // for the dummy part at the end of the line, where
    1312           0 :         return 0;   // the combined portion doesn't fit.
    1313           0 :     return SwFieldPortion::GetViewWidth( rInf );
    1314             : }
    1315             : 
    1316           0 : SwFieldPortion *SwFieldFormDropDownPortion::Clone(const OUString &rExpand) const
    1317             : {
    1318           0 :     return new SwFieldFormDropDownPortion(rExpand);
    1319         177 : }
    1320             : 
    1321             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11