LCOV - code coverage report
Current view: top level - sw/source/core/text - portxt.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 289 425 68.0 %
Date: 2015-06-13 12:38:46 Functions: 29 33 87.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 <ctype.h>
      21             : 
      22             : #include <com/sun/star/i18n/ScriptType.hpp>
      23             : #include <i18nlangtag/mslangid.hxx>
      24             : #include <hintids.hxx>
      25             : #include <EnhancedPDFExportHelper.hxx>
      26             : #include <SwPortionHandler.hxx>
      27             : #include <porlay.hxx>
      28             : #include <inftxt.hxx>
      29             : #include <guess.hxx>
      30             : #include <porglue.hxx>
      31             : #include <portab.hxx>
      32             : #include <porfld.hxx>
      33             : #include <wrong.hxx>
      34             : #include <viewsh.hxx>
      35             : #include <IDocumentSettingAccess.hxx>
      36             : #include <viewopt.hxx>
      37             : #include <editeng/borderline.hxx>
      38             : 
      39             : #include <IMark.hxx>
      40             : #include <pam.hxx>
      41             : #include <doc.hxx>
      42             : #include <xmloff/odffields.hxx>
      43             : 
      44             : using namespace ::sw::mark;
      45             : using namespace ::com::sun::star;
      46             : using namespace ::com::sun::star::i18n::ScriptType;
      47             : 
      48             : // Returns for how many characters an extra space has to be added
      49             : // (for justified alignment).
      50        5627 : static sal_Int32 lcl_AddSpace( const SwTextSizeInfo &rInf, const OUString* pStr,
      51             :                                const SwLinePortion& rPor )
      52             : {
      53             :     sal_Int32 nPos, nEnd;
      54        5627 :     const SwScriptInfo* pSI = 0;
      55             : 
      56        5627 :     if ( pStr )
      57             :     {
      58             :         // passing a string means we are inside a field
      59           0 :         nPos = 0;
      60           0 :         nEnd = pStr->getLength();
      61             :     }
      62             :     else
      63             :     {
      64        5627 :         nPos = rInf.GetIdx();
      65        5627 :         nEnd = rInf.GetIdx() + rPor.GetLen();
      66        5627 :         pStr = &rInf.GetText();
      67        5627 :         pSI = &const_cast<SwParaPortion*>(rInf.GetParaPortion())->GetScriptInfo();
      68             :     }
      69             : 
      70        5627 :     sal_Int32 nCnt = 0;
      71        5627 :     sal_uInt8 nScript = 0;
      72             : 
      73             :     // If portion consists of Asian characters and language is not
      74             :     // Korean, we add extra space to each character.
      75             :     // first we get the script type
      76        5627 :     if ( pSI )
      77        5627 :         nScript = pSI->ScriptType( nPos );
      78           0 :     else if ( g_pBreakIt->GetBreakIter().is() )
      79           0 :         nScript = (sal_uInt8)g_pBreakIt->GetBreakIter()->getScriptType( *pStr, nPos );
      80             : 
      81             :     // Note: rInf.GetIdx() can differ from nPos,
      82             :     // e.g., when rPor is a field portion. nPos referes to the string passed
      83             :     // to the function, rInf.GetIdx() referes to the original string.
      84             : 
      85             :     // We try to find out which justification mode is required. This is done by
      86             :     // evaluating the script type and the language attribute set for this portion
      87             : 
      88             :     // Asian Justification: Each character get some extra space
      89        5627 :     if ( nEnd > nPos && ASIAN == nScript )
      90             :     {
      91             :         LanguageType aLang =
      92           0 :             rInf.GetTextFrm()->GetTextNode()->GetLang( rInf.GetIdx(), 1, nScript );
      93             : 
      94           0 :         if (!MsLangId::isKorean(aLang))
      95             :         {
      96           0 :             const SwLinePortion* pPor = rPor.GetPortion();
      97           0 :             if ( pPor && ( pPor->IsKernPortion() ||
      98           0 :                            pPor->IsControlCharPortion() ||
      99           0 :                            pPor->IsPostItsPortion() ) )
     100           0 :                 pPor = pPor->GetPortion();
     101             : 
     102           0 :             nCnt += nEnd - nPos;
     103             : 
     104           0 :             if ( !pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() ||
     105           0 :                   pPor->IsBreakPortion() )
     106           0 :                 --nCnt;
     107             : 
     108           0 :             return nCnt;
     109             :         }
     110             :     }
     111             : 
     112             :     // Kashida Justification: Insert Kashidas
     113        5627 :     if ( nEnd > nPos && pSI && COMPLEX == nScript )
     114             :     {
     115           3 :         if ( SwScriptInfo::IsArabicText( *pStr, nPos, nEnd - nPos ) && pSI->CountKashida() )
     116             :         {
     117           0 :             const sal_Int32 nKashRes = pSI->KashidaJustify( 0, 0, nPos, nEnd - nPos );
     118             :             // i60591: need to check result of KashidaJustify
     119             :             // determine if kashida justification is applicable
     120           0 :             if (nKashRes != -1)
     121           0 :                 return nKashRes;
     122             :         }
     123             :     }
     124             : 
     125             :     // Thai Justification: Each character cell gets some extra space
     126        5627 :     if ( nEnd > nPos && COMPLEX == nScript )
     127             :     {
     128             :         LanguageType aLang =
     129           3 :             rInf.GetTextFrm()->GetTextNode()->GetLang( rInf.GetIdx(), 1, nScript );
     130             : 
     131           3 :         if ( LANGUAGE_THAI == aLang )
     132             :         {
     133           0 :             nCnt = SwScriptInfo::ThaiJustify( *pStr, 0, 0, nPos, nEnd - nPos );
     134             : 
     135           0 :             const SwLinePortion* pPor = rPor.GetPortion();
     136           0 :             if ( pPor && ( pPor->IsKernPortion() ||
     137           0 :                            pPor->IsControlCharPortion() ||
     138           0 :                            pPor->IsPostItsPortion() ) )
     139           0 :                 pPor = pPor->GetPortion();
     140             : 
     141           0 :             if ( nCnt && ( ! pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() ) )
     142           0 :                 --nCnt;
     143             : 
     144           0 :             return nCnt;
     145             :         }
     146             :     }
     147             : 
     148             :     // Here starts the good old "Look for blanks and add space to them" part.
     149             :     // Note: We do not want to add space to an isolated latin blank in front
     150             :     // of some complex characters in RTL environment
     151             :     const bool bDoNotAddSpace =
     152        5825 :             LATIN == nScript && ( nEnd == nPos + 1 ) && pSI &&
     153             :             ( i18n::ScriptType::COMPLEX ==
     154         201 :               pSI->ScriptType( nPos + 1 ) ) &&
     155        5627 :             rInf.GetTextFrm() && rInf.GetTextFrm()->IsRightToLeft();
     156             : 
     157        5627 :     if ( bDoNotAddSpace )
     158           0 :         return nCnt;
     159             : 
     160        5627 :     sal_Int32 nTextEnd = std::min(nEnd, pStr->getLength());
     161      358579 :     for ( ; nPos < nTextEnd; ++nPos )
     162             :     {
     163      352952 :         if( CH_BLANK == (*pStr)[ nPos ] )
     164       52416 :             ++nCnt;
     165             :     }
     166             : 
     167             :     // We still have to examine the next character:
     168             :     // If the next character is ASIAN and not KOREAN we have
     169             :     // to add an extra space
     170             :     // nPos referes to the original string, even if a field string has
     171             :     // been passed to this function
     172        5627 :     nPos = rInf.GetIdx() + rPor.GetLen();
     173        5627 :     if ( nPos < rInf.GetText().getLength() )
     174             :     {
     175        5605 :         sal_uInt8 nNextScript = 0;
     176        5605 :         const SwLinePortion* pPor = rPor.GetPortion();
     177        5605 :         if ( pPor && pPor->IsKernPortion() )
     178           0 :             pPor = pPor->GetPortion();
     179             : 
     180        5605 :         if ( ! g_pBreakIt->GetBreakIter().is() || ! pPor || pPor->InFixMargGrp() )
     181         121 :             return nCnt;
     182             : 
     183             :         // next character is inside a field?
     184        5484 :         if ( CH_TXTATR_BREAKWORD == rInf.GetChar( nPos ) && pPor->InExpGrp() )
     185             :         {
     186           0 :             bool bOldOnWin = rInf.OnWin();
     187           0 :             ((SwTextSizeInfo &)rInf).SetOnWin( false );
     188             : 
     189           0 :             OUString aStr;
     190           0 :             pPor->GetExpText( rInf, aStr );
     191           0 :             ((SwTextSizeInfo &)rInf).SetOnWin( bOldOnWin );
     192             : 
     193           0 :             nNextScript = (sal_uInt8)g_pBreakIt->GetBreakIter()->getScriptType( aStr, 0 );
     194             :         }
     195             :         else
     196        5484 :             nNextScript = (sal_uInt8)g_pBreakIt->GetBreakIter()->getScriptType( rInf.GetText(), nPos );
     197             : 
     198        5484 :         if( ASIAN == nNextScript )
     199             :         {
     200             :             LanguageType aLang =
     201           0 :                 rInf.GetTextFrm()->GetTextNode()->GetLang( nPos, 1, nNextScript );
     202             : 
     203           0 :             if (!MsLangId::isKorean(aLang))
     204           0 :                 ++nCnt;
     205             :         }
     206             :     }
     207             : 
     208        5506 :     return nCnt;
     209             : }
     210             : 
     211       13647 : SwTextPortion * SwTextPortion::CopyLinePortion(const SwLinePortion &rPortion)
     212             : {
     213       13647 :     SwTextPortion *const pNew(new SwTextPortion);
     214       13647 :     static_cast<SwLinePortion&>(*pNew) = rPortion;
     215       13647 :     pNew->SetWhichPor( POR_TXT ); // overwrite that!
     216       13647 :     return pNew;
     217             : }
     218             : 
     219        2688 : void SwTextPortion::BreakCut( SwTextFormatInfo &rInf, const SwTextGuess &rGuess )
     220             : {
     221             :     // The word/char is larger than the line
     222             :     // Special case 1: The word is larger than the line
     223             :     // We truncate ...
     224        2688 :     const sal_uInt16 nLineWidth = (sal_uInt16)(rInf.Width() - rInf.X());
     225        2688 :     sal_Int32 nLen = rGuess.CutPos() - rInf.GetIdx();
     226        2688 :     if (nLen > 0)
     227             :     {
     228             :         // special case: guess does not always provide the correct
     229             :         // width, only in common cases.
     230        1970 :         if ( !rGuess.BreakWidth() )
     231             :         {
     232        1626 :             rInf.SetLen( nLen );
     233        1626 :             SetLen( nLen );
     234        1626 :             CalcTextSize( rInf );
     235             : 
     236             :             // changing these values requires also changing them in
     237             :             // guess.cxx
     238        1626 :             sal_uInt16 nItalic = 0;
     239        1626 :             if( ITALIC_NONE != rInf.GetFont()->GetItalic() && !rInf.NotEOL() )
     240             :             {
     241           0 :                 nItalic = Height() / 12;
     242             :             }
     243        1626 :             Width( Width() + nItalic );
     244             :         }
     245             :         else
     246             :         {
     247         344 :             Width( rGuess.BreakWidth() );
     248         344 :             SetLen( nLen );
     249             :         }
     250             :     }
     251             :     // special case: first character does not fit to line
     252         718 :     else if ( rGuess.CutPos() == rInf.GetLineStart() )
     253             :     {
     254         706 :         SetLen( 1 );
     255         706 :         Width( nLineWidth );
     256             :     }
     257             :     else
     258             :     {
     259          12 :         SetLen( 0 );
     260          12 :         Width( 0 );
     261             :     }
     262        2688 : }
     263             : 
     264         127 : void SwTextPortion::BreakUnderflow( SwTextFormatInfo &rInf )
     265             : {
     266         127 :     Truncate();
     267         127 :     Height( 0 );
     268         127 :     Width( 0 );
     269         127 :     SetLen( 0 );
     270         127 :     SetAscent( 0 );
     271         127 :     rInf.SetUnderflow( this );
     272         127 : }
     273             : 
     274           0 : static bool lcl_HasContent( const SwFieldPortion& rField, SwTextFormatInfo &rInf )
     275             : {
     276           0 :     OUString aText;
     277           0 :     return rField.GetExpText( rInf, aText ) && !aText.isEmpty();
     278             : }
     279             : 
     280      102021 : bool SwTextPortion::_Format( SwTextFormatInfo &rInf )
     281             : {
     282             :     // 5744: If only the hypen does not fit anymore, we still need to wrap
     283             :     // the word, or else return true!
     284      102021 :     if( rInf.IsUnderflow() && rInf.GetSoftHyphPos() )
     285             :     {
     286             :         // soft hyphen portion has triggered an underflow event because
     287             :         // of an alternative spelling position
     288           0 :         bool bFull = false;
     289           0 :         const bool bHyph = rInf.ChgHyph( true );
     290           0 :         if( rInf.IsHyphenate() )
     291             :         {
     292           0 :             SwTextGuess aGuess;
     293             :             // check for alternative spelling left from the soft hyphen
     294             :             // this should usually be true but
     295           0 :             aGuess.AlternativeSpelling( rInf, rInf.GetSoftHyphPos() - 1 );
     296           0 :             bFull = CreateHyphen( rInf, aGuess );
     297           0 :             OSL_ENSURE( bFull, "Problem with hyphenation!!!" );
     298             :         }
     299           0 :         rInf.ChgHyph( bHyph );
     300           0 :         rInf.SetSoftHyphPos( 0 );
     301           0 :         return bFull;
     302             :     }
     303             : 
     304      102021 :     SwTextGuess aGuess;
     305      102021 :     const bool bFull = !aGuess.Guess( *this, rInf, Height() );
     306             : 
     307             :     // these are the possible cases:
     308             :     // A Portion fits to current line
     309             :     // B Portion does not fit to current line but a possible line break
     310             :     //   within the portion has been found by the break iterator, 2 subcases
     311             :     //   B1 break is hyphen
     312             :     //   B2 break is word end
     313             :     // C Portion does not fit to current line and no possible line break
     314             :     //   has been found by break iterator, 2 subcases:
     315             :     //   C1 break iterator found a possible line break in portion before us
     316             :     //      ==> this break is used (underflow)
     317             :     //   C2 break iterator does not found a possible line break at all:
     318             :     //      ==> line break
     319             : 
     320             :     // case A: line not yet full
     321      102021 :     if ( !bFull )
     322             :     {
     323       66817 :         Width( aGuess.BreakWidth() );
     324             :         // Vorsicht !
     325       66817 :         if( !InExpGrp() || InFieldGrp() )
     326       66067 :             SetLen( rInf.GetLen() );
     327             : 
     328       66817 :         short nKern = rInf.GetFont()->CheckKerning();
     329       66817 :         if( nKern > 0 && rInf.Width() < rInf.X() + Width() + nKern )
     330             :         {
     331           0 :             nKern = (short)(rInf.Width() - rInf.X() - Width() - 1);
     332           0 :             if( nKern < 0 )
     333           0 :                 nKern = 0;
     334             :         }
     335       66817 :         if( nKern )
     336         297 :             new SwKernPortion( *this, nKern );
     337             :     }
     338             :     // special case: hanging portion
     339       35204 :     else if( bFull && aGuess.GetHangingPortion() )
     340             :     {
     341           0 :         Width( aGuess.BreakWidth() );
     342           0 :         SetLen( aGuess.BreakPos() - rInf.GetIdx() );
     343           0 :         Insert( aGuess.GetHangingPortion() );
     344           0 :         aGuess.GetHangingPortion()->SetAscent( GetAscent() );
     345           0 :         aGuess.ClearHangingPortion();
     346             :     }
     347             :     // breakPos >= index
     348       35204 :     else if ( aGuess.BreakPos() >= rInf.GetIdx() && aGuess.BreakPos() != COMPLETE_STRING )
     349             :     {
     350             :         // case B1
     351      102606 :         if( aGuess.HyphWord().is() && aGuess.BreakPos() > rInf.GetLineStart()
     352      102606 :             && ( aGuess.BreakPos() > rInf.GetIdx() ||
     353           0 :                ( rInf.GetLast() && ! rInf.GetLast()->IsFlyPortion() ) ) )
     354             :         {
     355           0 :             CreateHyphen( rInf, aGuess );
     356           0 :             if ( rInf.GetFly() )
     357           0 :                 rInf.GetRoot()->SetMidHyph( true );
     358             :             else
     359           0 :                 rInf.GetRoot()->SetEndHyph( true );
     360             :         }
     361             :         // case C1
     362             :         // - Footnote portions with fake line start (i.e., not at beginning of line)
     363             :         //   should keep together with the text portion. (Note: no keep together
     364             :         //   with only footnote portions.
     365             :         // - TabPortions not at beginning of line should keep together with the
     366             :         //   text portion, if they are not followed by a blank
     367             :         //   (work around different definition of tab stop character - breaking or
     368             :         //   non breaking character - in compatibility mode)
     369       68404 :         else if ( ( IsFootnotePortion() && rInf.IsFakeLineStart() &&
     370             : 
     371       68413 :                     rInf.IsOtherThanFootnoteInside() ) ||
     372       68404 :                   ( rInf.GetLast() &&
     373       68180 :                     rInf.GetTextFrm()->GetTextNode()->getIDocumentSettingAccess()->get(DocumentSettingId::TAB_COMPAT) &&
     374       34021 :                     rInf.GetLast()->InTabGrp() &&
     375          75 :                     rInf.GetLineStart() + rInf.GetLast()->GetLen() < rInf.GetIdx() &&
     376          41 :                     aGuess.BreakPos() == rInf.GetIdx()  &&
     377          18 :                     CH_BLANK != rInf.GetChar( rInf.GetIdx() ) &&
     378           9 :                     0x3000 != rInf.GetChar( rInf.GetIdx() ) ) )
     379           9 :             BreakUnderflow( rInf );
     380             :         // case B2
     381       99033 :         else if( rInf.GetIdx() > rInf.GetLineStart() ||
     382       32495 :                  aGuess.BreakPos() > rInf.GetIdx() ||
     383             :                  // this is weird: during formatting the follow of a field
     384             :                  // the values rInf.GetIdx and rInf.GetLineStart are replaced
     385             :                  // IsFakeLineStart indicates GetIdx > GetLineStart
     386        3696 :                  rInf.IsFakeLineStart() ||
     387        3692 :                  rInf.GetFly() ||
     388       70230 :                  rInf.IsFirstMulti() ||
     389        3608 :                  ( rInf.GetLast() &&
     390        3608 :                     ( rInf.GetLast()->IsFlyPortion() ||
     391        1804 :                         ( rInf.GetLast()->InFieldGrp() &&
     392           0 :                           ! rInf.GetLast()->InNumberGrp() &&
     393           0 :                           ! rInf.GetLast()->IsErgoSumPortion() &&
     394           0 :                           lcl_HasContent(*static_cast<SwFieldPortion*>(rInf.GetLast()),rInf ) ) ) ) )
     395             :         {
     396       32389 :             if ( rInf.X() + aGuess.BreakWidth() <= rInf.Width() )
     397       32389 :                 Width( aGuess.BreakWidth() );
     398             :             else
     399             :                 // this actually should not happen
     400           0 :                 Width( sal_uInt16(rInf.Width() - rInf.X()) );
     401             : 
     402       32389 :             SetLen( aGuess.BreakPos() - rInf.GetIdx() );
     403             : 
     404             :             OSL_ENSURE( aGuess.BreakStart() >= aGuess.FieldDiff(),
     405             :                     "Trouble with expanded field portions during line break" );
     406       32389 :             const sal_Int32 nRealStart = aGuess.BreakStart() - aGuess.FieldDiff();
     407       32389 :             if( aGuess.BreakPos() < nRealStart && !InExpGrp() )
     408             :             {
     409        3696 :                 SwHolePortion *pNew = new SwHolePortion( *this );
     410        3696 :                 pNew->SetLen( nRealStart - aGuess.BreakPos() );
     411        3696 :                 Insert( pNew );
     412             :             }
     413             :         }
     414             :         else    // case C2, last exit
     415        1804 :             BreakCut( rInf, aGuess );
     416             :     }
     417             :     // breakPos < index or no breakpos at all
     418             :     else
     419             :     {
     420        1002 :         bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx();
     421        2148 :         if( aGuess.BreakPos() != COMPLETE_STRING &&
     422         262 :             aGuess.BreakPos() != rInf.GetLineStart() &&
     423         118 :             ( !bFirstPor || rInf.GetFly() || rInf.GetLast()->IsFlyPortion() ||
     424        1238 :               rInf.IsFirstMulti() ) &&
     425         133 :             ( !rInf.GetLast()->IsBlankPortion() || SwBlankPortion::MayUnderflow( rInf, rInf.GetIdx()-1, true )))
     426             :         {       // case C1 (former BreakUnderflow())
     427         118 :             BreakUnderflow( rInf );
     428             :         }
     429             :         else
     430             :              // case C2, last exit
     431         884 :             BreakCut( rInf, aGuess );
     432             :     }
     433             : 
     434      102021 :     return bFull;
     435             : }
     436             : 
     437      102021 : bool SwTextPortion::Format( SwTextFormatInfo &rInf )
     438             : {
     439      102021 :     if( rInf.X() > rInf.Width() || (!GetLen() && !InExpGrp()) )
     440             :     {
     441           0 :         Height( 0 );
     442           0 :         Width( 0 );
     443           0 :         SetLen( 0 );
     444           0 :         SetAscent( 0 );
     445           0 :         SetPortion( NULL );  // ????
     446           0 :         return true;
     447             :     }
     448             : 
     449             :     OSL_ENSURE( rInf.RealWidth() || (rInf.X() == rInf.Width()),
     450             :         "SwTextPortion::Format: missing real width" );
     451             :     OSL_ENSURE( Height(), "SwTextPortion::Format: missing height" );
     452             : 
     453      102021 :     return _Format( rInf );
     454             : }
     455             : 
     456             : // Format end of line
     457             : // 5083: We can have awkward cases e.g.:
     458             : // "from {Santa}"
     459             : // Santa wraps, "from " turns into "from" and " " in a justified
     460             : // paragraph, in which the glue gets expanded instead of merged
     461             : // with the MarginPortion.
     462             : 
     463             : // rInf.nIdx points to the next word, nIdx-1 is the portion's last char
     464         695 : void SwTextPortion::FormatEOL( SwTextFormatInfo &rInf )
     465             : {
     466        1834 :     if( ( !GetPortion() || ( GetPortion()->IsKernPortion() &&
     467        1208 :         !GetPortion()->GetPortion() ) ) && GetLen() &&
     468         395 :         rInf.GetIdx() < rInf.GetText().getLength() &&
     469         196 :         1 < rInf.GetIdx() && ' ' == rInf.GetChar( rInf.GetIdx() - 1 )
     470         779 :         && !rInf.GetLast()->IsHolePortion() )
     471             :     {
     472             :         // calculate number of blanks
     473          84 :         sal_Int32 nX = rInf.GetIdx() - 1;
     474          84 :         sal_Int32 nHoleLen = 1;
     475         168 :         while( nX && nHoleLen < GetLen() && CH_BLANK == rInf.GetChar( --nX ) )
     476           0 :             nHoleLen++;
     477             : 
     478             :         // First set ourselves and the insert, because there could be
     479             :         // a SwLineLayout
     480             :         sal_uInt16 nBlankSize;
     481          84 :         if( nHoleLen == GetLen() )
     482           1 :             nBlankSize = Width();
     483             :         else
     484          83 :             nBlankSize = nHoleLen * rInf.GetTextSize(OUString(' ')).Width();
     485          84 :         Width( Width() - nBlankSize );
     486          84 :         rInf.X( rInf.X() - nBlankSize );
     487          84 :         SetLen( GetLen() - nHoleLen );
     488          84 :         SwLinePortion *pHole = new SwHolePortion( *this );
     489          84 :         static_cast<SwHolePortion *>( pHole )->SetBlankWidth( nBlankSize );
     490          84 :         static_cast<SwHolePortion *>( pHole )->SetLen( nHoleLen );
     491          84 :         Insert( pHole );
     492             :     }
     493         695 : }
     494             : 
     495           0 : sal_Int32 SwTextPortion::GetCrsrOfst( const sal_uInt16 nOfst ) const
     496             : {
     497             :     OSL_ENSURE( false, "SwTextPortion::GetCrsrOfst: don't use this method!" );
     498           0 :     return SwLinePortion::GetCrsrOfst( nOfst );
     499             : }
     500             : 
     501             : // The GetTextSize() assumes that the own length is correct
     502        3950 : SwPosSize SwTextPortion::GetTextSize( const SwTextSizeInfo &rInf ) const
     503             : {
     504        3950 :     SwPosSize aSize = rInf.GetTextSize();
     505        3950 :     if( !GetJoinBorderWithPrev() )
     506        3950 :         aSize.Width(aSize.Width() + rInf.GetFont()->GetLeftBorderSpace() );
     507        3950 :     if( !GetJoinBorderWithNext() )
     508        3950 :         aSize.Width(aSize.Width() + rInf.GetFont()->GetRightBorderSpace() );
     509             : 
     510        3950 :     aSize.Height(aSize.Height() +
     511        3950 :         rInf.GetFont()->GetTopBorderSpace() +
     512        3950 :         rInf.GetFont()->GetBottomBorderSpace() );
     513             : 
     514        3950 :     return aSize;
     515             : }
     516             : 
     517       19674 : void SwTextPortion::Paint( const SwTextPaintInfo &rInf ) const
     518             : {
     519       19674 :     if (rInf.OnWin() && 1==rInf.GetLen() && CH_TXT_ATR_FIELDEND==rInf.GetText()[rInf.GetIdx()])
     520             :     {
     521             :         assert(false); // this is some debugging only code
     522           0 :         rInf.DrawBackBrush( *this );
     523           0 :         const OUString aText(CH_TXT_ATR_SUBST_FIELDEND);
     524           0 :         rInf.DrawText( aText, *this, 0, aText.getLength(), false );
     525             :     }
     526       19674 :     else if (rInf.OnWin() && 1==rInf.GetLen() && CH_TXT_ATR_FIELDSTART==rInf.GetText()[rInf.GetIdx()])
     527             :     {
     528             :         assert(false); // this is some debugging only code
     529           0 :         rInf.DrawBackBrush( *this );
     530           0 :         const OUString aText(CH_TXT_ATR_SUBST_FIELDSTART);
     531           0 :         rInf.DrawText( aText, *this, 0, aText.getLength(), false );
     532             :     }
     533       19674 :     else if( GetLen() )
     534             :     {
     535       18139 :         rInf.DrawBackBrush( *this );
     536       18139 :         rInf.DrawBorder( *this );
     537             : 
     538             :         // do we have to repaint a post it portion?
     539       18139 :         if( rInf.OnWin() && pPortion && !pPortion->Width() )
     540        1805 :             pPortion->PrePaint( rInf, this );
     541             : 
     542       18139 :         const SwWrongList *pWrongList = rInf.GetpWrongList();
     543       18139 :         const SwWrongList *pGrammarCheckList = rInf.GetGrammarCheckList();
     544       18139 :         const SwWrongList *pSmarttags = rInf.GetSmartTags();
     545             : 
     546       18139 :         const bool bWrong = 0 != pWrongList;
     547       18139 :         const bool bGrammarCheck = 0 != pGrammarCheckList;
     548       18139 :         const bool bSmartTags = 0 != pSmarttags;
     549             : 
     550       18139 :         if ( bWrong || bSmartTags || bGrammarCheck )
     551        6081 :             rInf.DrawMarkedText( *this, rInf.GetLen(), false, bWrong, bSmartTags, bGrammarCheck );
     552             :         else
     553       12058 :             rInf.DrawText( *this, rInf.GetLen(), false );
     554             :     }
     555       19674 : }
     556             : 
     557          16 : bool SwTextPortion::GetExpText( const SwTextSizeInfo &, OUString & ) const
     558             : {
     559          16 :     return false;
     560             : }
     561             : 
     562             : // Responsible for the justified paragraph. They calculate the blank
     563             : // count and the resulting added space.
     564        1563 : sal_Int32 SwTextPortion::GetSpaceCnt( const SwTextSizeInfo &rInf,
     565             :                                       sal_Int32& rCharCnt ) const
     566             : {
     567        1563 :     sal_Int32 nCnt = 0;
     568        1563 :     sal_Int32 nPos = 0;
     569        1563 :     if ( InExpGrp() )
     570             :     {
     571          10 :         if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() )
     572             :         {
     573             :             // OnWin() likes to return a blank instead of an empty string from
     574             :             // time to time. We cannot use that here at all, however.
     575           0 :             bool bOldOnWin = rInf.OnWin();
     576           0 :             ((SwTextSizeInfo &)rInf).SetOnWin( false );
     577             : 
     578           0 :             OUString aStr;
     579           0 :             GetExpText( rInf, aStr );
     580           0 :             ((SwTextSizeInfo &)rInf).SetOnWin( bOldOnWin );
     581             : 
     582           0 :             nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this );
     583           0 :             nPos = aStr.getLength();
     584             :         }
     585             :     }
     586        1553 :     else if( !IsDropPortion() )
     587             :     {
     588        1553 :         nCnt = nCnt + lcl_AddSpace( rInf, 0, *this );
     589        1553 :         nPos = GetLen();
     590             :     }
     591        1563 :     rCharCnt = rCharCnt + nPos;
     592        1563 :     return nCnt;
     593             : }
     594             : 
     595        4089 : long SwTextPortion::CalcSpacing( long nSpaceAdd, const SwTextSizeInfo &rInf ) const
     596             : {
     597        4089 :     sal_Int32 nCnt = 0;
     598             : 
     599        4089 :     if ( InExpGrp() )
     600             :     {
     601          15 :         if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() )
     602             :         {
     603             :             // OnWin() likes to return a blank instead of an empty string from
     604             :             // time to time. We cannot use that here at all, however.
     605           0 :             bool bOldOnWin = rInf.OnWin();
     606           0 :             ((SwTextSizeInfo &)rInf).SetOnWin( false );
     607             : 
     608           0 :             OUString aStr;
     609           0 :             GetExpText( rInf, aStr );
     610           0 :             ((SwTextSizeInfo &)rInf).SetOnWin( bOldOnWin );
     611           0 :             if( nSpaceAdd > 0 )
     612           0 :                 nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this );
     613             :             else
     614             :             {
     615           0 :                 nSpaceAdd = -nSpaceAdd;
     616           0 :                 nCnt = aStr.getLength();
     617           0 :             }
     618             :         }
     619             :     }
     620        4074 :     else if( !IsDropPortion() )
     621             :     {
     622        4074 :         if( nSpaceAdd > 0 )
     623        4074 :             nCnt = nCnt + lcl_AddSpace( rInf, 0, *this );
     624             :         else
     625             :         {
     626           0 :             nSpaceAdd = -nSpaceAdd;
     627           0 :             nCnt = GetLen();
     628           0 :             SwLinePortion* pPor = GetPortion();
     629             : 
     630             :             // we do not want an extra space in front of margin portions
     631           0 :             if ( nCnt )
     632             :             {
     633           0 :                 while ( pPor && !pPor->Width() && ! pPor->IsHolePortion() )
     634           0 :                     pPor = pPor->GetPortion();
     635             : 
     636           0 :                 if ( !pPor || pPor->InFixMargGrp() || pPor->IsHolePortion() )
     637           0 :                     --nCnt;
     638             :             }
     639             :         }
     640             :     }
     641             : 
     642        4089 :     return nCnt * nSpaceAdd / SPACING_PRECISION_FACTOR;
     643             : }
     644             : 
     645         634 : void SwTextPortion::HandlePortion( SwPortionHandler& rPH ) const
     646             : {
     647         634 :     rPH.Text( GetLen(), GetWhichPor(), Height(), Width() );
     648         634 : }
     649             : 
     650          25 : SwTextInputFieldPortion::SwTextInputFieldPortion()
     651             :     : SwTextPortion()
     652             :     , mbContainsInputFieldStart( false )
     653          25 :     , mbContainsInputFieldEnd( false )
     654             : {
     655          25 :     SetWhichPor( POR_INPUTFLD );
     656          25 : }
     657             : 
     658          25 : bool SwTextInputFieldPortion::Format( SwTextFormatInfo &rInf )
     659             : {
     660             :     mbContainsInputFieldStart =
     661          25 :         rInf.GetChar( rInf.GetIdx() ) == CH_TXT_ATR_INPUTFIELDSTART;
     662             :     mbContainsInputFieldEnd =
     663          25 :         rInf.GetChar( rInf.GetIdx() + rInf.GetLen() - 1 ) == CH_TXT_ATR_INPUTFIELDEND;
     664             : 
     665          25 :     bool bRet = false;
     666          50 :     if ( rInf.GetLen() == 1
     667          25 :          && ( mbContainsInputFieldStart || mbContainsInputFieldEnd ) )
     668             :     {
     669           0 :         Width( 0 );
     670             :     }
     671             :     else
     672             :     {
     673          25 :         SwTextSlot aFormatText( &rInf, this, true, true );
     674          25 :         if ( rInf.GetLen() == 0 )
     675             :         {
     676           5 :             Width( 0 );
     677             :         }
     678             :         else
     679             :         {
     680          20 :             const sal_Int32 nFormerLineStart = rInf.GetLineStart();
     681          20 :             if ( !mbContainsInputFieldStart )
     682             :             {
     683           0 :                 rInf.SetLineStart( 0 );
     684             :             }
     685             : 
     686          20 :             bRet = SwTextPortion::Format( rInf );
     687             : 
     688          20 :             if ( mbContainsInputFieldEnd )
     689             :             {
     690             :                 // adjust portion length accordingly, if complete text fits into the portion
     691          20 :                 if ( GetLen() == rInf.GetLen() )
     692             :                 {
     693          20 :                     SetLen( GetLen() + 1 );
     694             :                 }
     695             :             }
     696             : 
     697          20 :             if ( mbContainsInputFieldStart )
     698             :             {
     699             :                 // adjust portion length accordingly
     700          20 :                 SetLen( GetLen() + 1 );
     701             :             }
     702             :             else
     703             :             {
     704           0 :                 rInf.SetLineStart( nFormerLineStart );
     705             :             }
     706          25 :         }
     707             :     }
     708             : 
     709          25 :     return bRet;
     710             : }
     711             : 
     712          25 : void SwTextInputFieldPortion::Paint( const SwTextPaintInfo &rInf ) const
     713             : {
     714          25 :     if ( Width() )
     715             :     {
     716          22 :         rInf.DrawViewOpt( *this, POR_INPUTFLD );
     717             :         SwTextSlot aPaintText( &rInf, this, true, true,
     718          22 :                              ContainsOnlyDummyChars() ? OUString(" ") : OUString() );
     719          22 :         SwTextPortion::Paint( rInf );
     720             :     }
     721          25 : }
     722             : 
     723          45 : bool SwTextInputFieldPortion::GetExpText( const SwTextSizeInfo &rInf, OUString &rText ) const
     724             : {
     725          45 :     sal_Int32 nIdx = rInf.GetIdx();
     726          45 :     sal_Int32 nLen = rInf.GetLen();
     727          45 :     if ( rInf.GetChar( rInf.GetIdx() ) == CH_TXT_ATR_INPUTFIELDSTART )
     728             :     {
     729          45 :         ++nIdx;
     730          45 :         --nLen;
     731             :     }
     732          45 :     if ( rInf.GetChar( rInf.GetIdx() + rInf.GetLen() - 1 ) == CH_TXT_ATR_INPUTFIELDEND )
     733             :     {
     734          45 :         --nLen;
     735             :     }
     736          45 :     rText = rInf.GetText().copy( nIdx, std::min( nLen, rInf.GetText().getLength() - nIdx ) );
     737             : 
     738          45 :     return true;
     739             : }
     740             : 
     741           0 : SwPosSize SwTextInputFieldPortion::GetTextSize( const SwTextSizeInfo &rInf ) const
     742             : {
     743           0 :     SwTextSlot aFormatText( &rInf, this, true, false );
     744           0 :     if ( rInf.GetLen() == 0 )
     745             :     {
     746           0 :         return SwPosSize( 0, 0 );
     747             :     }
     748             : 
     749           0 :     return rInf.GetTextSize();
     750             : }
     751             : 
     752           2 : sal_uInt16 SwTextInputFieldPortion::GetViewWidth( const SwTextSizeInfo &rInf ) const
     753             : {
     754           4 :     if( !Width()
     755           2 :         && ContainsOnlyDummyChars()
     756           2 :         && !rInf.GetOpt().IsPagePreview()
     757           2 :         && !rInf.GetOpt().IsReadonly()
     758           4 :         && SwViewOption::IsFieldShadings() )
     759             :     {
     760           2 :         return rInf.GetTextSize( " " ).Width();
     761             :     }
     762             : 
     763           0 :     return SwTextPortion::GetViewWidth( rInf );
     764             : }
     765             : 
     766          24 : bool SwTextInputFieldPortion::ContainsOnlyDummyChars() const
     767             : {
     768          24 :     return GetLen() <= 2
     769           4 :            && mbContainsInputFieldStart
     770          28 :            && mbContainsInputFieldEnd;
     771             : }
     772             : 
     773        3780 : SwHolePortion::SwHolePortion( const SwTextPortion &rPor )
     774        3780 :     : nBlankWidth( 0 )
     775             : {
     776        3780 :     SetLen( 1 );
     777        3780 :     Height( rPor.Height() );
     778        3780 :     SetAscent( rPor.GetAscent() );
     779        3780 :     SetWhichPor( POR_HOLE );
     780        3780 : }
     781             : 
     782        3827 : SwLinePortion *SwHolePortion::Compress() { return this; }
     783             : 
     784         920 : void SwHolePortion::Paint( const SwTextPaintInfo &rInf ) const
     785             : {
     786         920 :     if( !rInf.GetOut() )
     787         920 :         return;
     788             : 
     789             :     // #i16816# export stuff only needed for tagged pdf support
     790         920 :     if (!SwTaggedPDFHelper::IsExportTaggedPDF( *rInf.GetOut()) )
     791         920 :         return;
     792             : 
     793             :     // #i68503# the hole must have no decoration for a consistent visual appearance
     794           0 :     const SwFont* pOrigFont = rInf.GetFont();
     795           0 :     SwFont* pHoleFont = NULL;
     796           0 :     SwFontSave* pFontSave = NULL;
     797           0 :     if( pOrigFont->GetUnderline() != UNDERLINE_NONE
     798           0 :     ||  pOrigFont->GetOverline() != UNDERLINE_NONE
     799           0 :     ||  pOrigFont->GetStrikeout() != STRIKEOUT_NONE )
     800             :     {
     801           0 :         pHoleFont = new SwFont( *pOrigFont );
     802           0 :         pHoleFont->SetUnderline( UNDERLINE_NONE );
     803           0 :         pHoleFont->SetOverline( UNDERLINE_NONE );
     804           0 :         pHoleFont->SetStrikeout( STRIKEOUT_NONE );
     805           0 :         pFontSave = new SwFontSave( rInf, pHoleFont );
     806             :     }
     807             : 
     808           0 :     const OUString aText( ' ' );
     809           0 :     rInf.DrawText( aText, *this, 0, 1, false );
     810             : 
     811           0 :     delete pFontSave;
     812           0 :     delete pHoleFont;
     813             : }
     814             : 
     815           0 : bool SwHolePortion::Format( SwTextFormatInfo &rInf )
     816             : {
     817           0 :     return rInf.IsFull() || rInf.X() >= rInf.Width();
     818             : }
     819             : 
     820           4 : void SwHolePortion::HandlePortion( SwPortionHandler& rPH ) const
     821             : {
     822           4 :     rPH.Text( GetLen(), GetWhichPor() );
     823           4 : }
     824             : 
     825          16 : void SwFieldMarkPortion::Paint( const SwTextPaintInfo & /*rInf*/) const
     826             : {
     827             :     // These shouldn't be painted!
     828             :     //SwTextPortion::Paint(rInf);
     829          16 : }
     830             : 
     831         222 : bool SwFieldMarkPortion::Format( SwTextFormatInfo & )
     832             : {
     833         222 :     Width(0);
     834         222 :     return false;
     835             : }
     836             : 
     837           2 : void SwFieldFormCheckboxPortion::Paint( const SwTextPaintInfo& rInf ) const
     838             : {
     839           2 :     SwTextNode* pNd = const_cast<SwTextNode*>(rInf.GetTextFrm()->GetTextNode());
     840           2 :     const SwDoc *doc=pNd->GetDoc();
     841           2 :     SwIndex aIndex( pNd, rInf.GetIdx() );
     842           4 :     SwPosition aPosition(*pNd, aIndex);
     843             : 
     844           2 :     IFieldmark* pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition );
     845             : 
     846             :     OSL_ENSURE(pBM && pBM->GetFieldname( ) == ODF_FORMCHECKBOX,
     847             :         "Where is my form field bookmark???");
     848             : 
     849           2 :     if (pBM && pBM->GetFieldname( ) == ODF_FORMCHECKBOX)
     850             :     {
     851           2 :         const ICheckboxFieldmark* pCheckboxFm = dynamic_cast< ICheckboxFieldmark* >(pBM);
     852           2 :         bool bChecked = pCheckboxFm && pCheckboxFm->IsChecked();
     853           2 :         rInf.DrawCheckBox(*this, bChecked);
     854           2 :     }
     855           2 : }
     856             : 
     857           9 : bool SwFieldFormCheckboxPortion::Format( SwTextFormatInfo & rInf )
     858             : {
     859           9 :     SwTextNode *pNd = rInf.GetTextFrm(  )->GetTextNode(  );
     860           9 :     const SwDoc *doc = pNd->GetDoc(  );
     861           9 :     SwIndex aIndex( pNd, rInf.GetIdx(  ) );
     862          18 :     SwPosition aPosition( *pNd, aIndex );
     863           9 :     IFieldmark *pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition );
     864             :     OSL_ENSURE(pBM && pBM->GetFieldname( ) == ODF_FORMCHECKBOX, "Where is my form field bookmark???");
     865           9 :     if (pBM && pBM->GetFieldname( ) == ODF_FORMCHECKBOX)
     866             :     {
     867           9 :         Width( rInf.GetTextHeight(  ) );
     868           9 :         Height( rInf.GetTextHeight(  ) );
     869           9 :         SetAscent( rInf.GetAscent(  ) );
     870             :     }
     871          18 :     return false;
     872         177 : }
     873             : 
     874             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11