LCOV - code coverage report
Current view: top level - libreoffice/sw/source/core/text - itradj.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 117 398 29.4 %
Date: 2012-12-27 Functions: 6 11 54.5 %
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 <com/sun/star/i18n/ScriptType.hpp>
      21             : #include <vcl/outdev.hxx>
      22             : #include <IDocumentSettingAccess.hxx>
      23             : 
      24             : #include "frame.hxx"       // CalcFlyAdjust()
      25             : #include "paratr.hxx"
      26             : #include "itrtxt.hxx"
      27             : #include "porglue.hxx"
      28             : #include "porlay.hxx"
      29             : #include "porfly.hxx"       // CalcFlyAdjust()
      30             : #include "pordrop.hxx"       // CalcFlyAdjust()
      31             : #include "pormulti.hxx"
      32             : #include <portab.hxx>
      33             : 
      34             : #define MIN_TAB_WIDTH 60
      35             : 
      36             : using namespace ::com::sun::star;
      37             : 
      38             : /*************************************************************************
      39             :  * SwTxtAdjuster::FormatBlock()
      40             :  *************************************************************************/
      41             : 
      42           5 : void SwTxtAdjuster::FormatBlock( )
      43             : {
      44             :     // Block format does not apply to the last line.
      45             :     // And for tabs it doesn't exist out of tradition
      46             :     // If we have Flys we continue.
      47             : 
      48           5 :     const SwLinePortion *pFly = 0;
      49             : 
      50           5 :     sal_Bool bSkip = !IsLastBlock() &&
      51           5 :         nStart + pCurr->GetLen() >= GetInfo().GetTxt().Len();
      52             : 
      53             :     // Multi-line fields are tricky, because we need to check whether there are
      54             :     // any other text portions in the paragraph.
      55           5 :     if( bSkip )
      56             :     {
      57           3 :         const SwLineLayout *pLay = pCurr->GetNext();
      58           6 :         while( pLay && !pLay->GetLen() )
      59             :         {
      60           0 :             const SwLinePortion *pPor = pCurr->GetFirstPortion();
      61           0 :             while( pPor && bSkip )
      62             :             {
      63           0 :                 if( pPor->InTxtGrp() )
      64           0 :                     bSkip = sal_False;
      65           0 :                 pPor = pPor->GetPortion();
      66             :             }
      67           0 :             pLay = bSkip ? pLay->GetNext() : 0;
      68             :         }
      69             :     }
      70             : 
      71           5 :     if( bSkip )
      72             :     {
      73           3 :         if( !GetInfo().GetParaPortion()->HasFly() )
      74             :         {
      75           3 :             if( IsLastCenter() )
      76           0 :                 CalcFlyAdjust( pCurr );
      77           3 :             pCurr->FinishSpaceAdd();
      78           3 :             return;
      79             :         }
      80             :         else
      81             :         {
      82           0 :             const SwLinePortion *pTmpFly = NULL;
      83             : 
      84             :             // End at the last Fly
      85           0 :             const SwLinePortion *pPos = pCurr->GetFirstPortion();
      86           0 :             while( pPos )
      87             :             {
      88             :                 // Look for the last Fly which has text coming after it:
      89           0 :                 if( pPos->IsFlyPortion() )
      90           0 :                     pTmpFly = pPos; // Found a Fly
      91           0 :                 else if ( pTmpFly && pPos->InTxtGrp() )
      92             :                 {
      93           0 :                     pFly = pTmpFly; // A Fly with follow-up text!
      94           0 :                     pTmpFly = NULL;
      95             :                 }
      96           0 :                 pPos = pPos->GetPortion();
      97             :             }
      98             :             // End if we didn't find one
      99           0 :             if( !pFly )
     100             :             {
     101           0 :                 if( IsLastCenter() )
     102           0 :                     CalcFlyAdjust( pCurr );
     103           0 :                 pCurr->FinishSpaceAdd();
     104           0 :                 return;
     105             :             }
     106             :         }
     107             :     }
     108             : 
     109           2 :     const xub_StrLen nOldIdx = GetInfo().GetIdx();
     110           2 :     GetInfo().SetIdx( nStart );
     111           2 :     CalcNewBlock( pCurr, pFly );
     112           2 :     GetInfo().SetIdx( nOldIdx );
     113           2 :     GetInfo().GetParaPortion()->GetRepaint()->SetOfst(0);
     114             : }
     115             : 
     116             : /*************************************************************************
     117             :  * lcl_CheckKashidaPositions()
     118             :  *************************************************************************/
     119           0 : static bool lcl_CheckKashidaPositions( SwScriptInfo& rSI, SwTxtSizeInfo& rInf, SwTxtIter& rItr,
     120             :                                 xub_StrLen& nKashidas, xub_StrLen& nGluePortion )
     121             : {
     122             :     // i60594 validate Kashida justification
     123           0 :     xub_StrLen nIdx = rItr.GetStart();
     124           0 :     xub_StrLen nEnd = rItr.GetEnd();
     125             : 
     126             :     // Note on calling KashidaJustify():
     127             :     // Kashida positions may be marked as invalid. Therefore KashidaJustify may return the clean
     128             :     // total number of kashida positions, or the number of kashida positions after some positions
     129             :     // have been dropped.
     130             :     // Here we want the clean total, which is OK: We have called ClearKashidaInvalid() before.
     131           0 :     nKashidas = rSI.KashidaJustify ( 0, 0, rItr.GetStart(), rItr.GetLength(), 0 );
     132             : 
     133           0 :     if (!nKashidas) // nothing to do
     134           0 :         return true;
     135             : 
     136             :     // kashida positions found in SwScriptInfo are not necessarily valid in every font
     137             :     // if two characters are replaced by a ligature glyph, there will be no place for a kashida
     138           0 :     xub_StrLen* pKashidaPos = new xub_StrLen [ nKashidas ];
     139           0 :     xub_StrLen* pKashidaPosDropped = new xub_StrLen [ nKashidas ];
     140           0 :     rSI.GetKashidaPositions ( nIdx, rItr.GetLength(), pKashidaPos );
     141           0 :     xub_StrLen nKashidaIdx = 0;
     142           0 :     while ( nKashidas && nIdx < nEnd )
     143             :     {
     144           0 :         rItr.SeekAndChgAttrIter( nIdx, rInf.GetOut() );
     145           0 :         xub_StrLen nNext = rItr.GetNextAttr();
     146             : 
     147             :         // is there also a script change before?
     148             :         // if there is, nNext should point to the script change
     149           0 :         xub_StrLen nNextScript = rSI.NextScriptChg( nIdx );
     150           0 :         if( nNextScript < nNext )
     151           0 :             nNext = nNextScript;
     152             : 
     153           0 :         if ( nNext == STRING_LEN || nNext > nEnd )
     154           0 :             nNext = nEnd;
     155           0 :         xub_StrLen nKashidasInAttr = rSI.KashidaJustify ( 0, 0, nIdx, nNext - nIdx );
     156           0 :         if ( nKashidasInAttr )
     157             :         {
     158             :             // Kashida glyph looks suspicious, skip Kashida justification
     159           0 :             if ( rInf.GetOut()->GetMinKashida() <= 0 )
     160           0 :                 return false;
     161             : 
     162           0 :             xub_StrLen nKashidasDropped = 0;
     163           0 :             if ( !SwScriptInfo::IsArabicText( rInf.GetTxt(), nIdx, nNext - nIdx ) )
     164             :             {
     165           0 :                 nKashidasDropped = nKashidasInAttr;
     166           0 :                 nKashidas -= nKashidasDropped;
     167             :             }
     168             :             else
     169             :             {
     170           0 :                 sal_uLong nOldLayout = rInf.GetOut()->GetLayoutMode();
     171           0 :                 rInf.GetOut()->SetLayoutMode ( nOldLayout | TEXT_LAYOUT_BIDI_RTL );
     172           0 :                 nKashidasDropped = rInf.GetOut()->ValidateKashidas ( rInf.GetTxt(), nIdx, nNext - nIdx,
     173             :                                                nKashidasInAttr, pKashidaPos + nKashidaIdx,
     174           0 :                                                pKashidaPosDropped );
     175           0 :                 rInf.GetOut()->SetLayoutMode ( nOldLayout );
     176           0 :                 if ( nKashidasDropped )
     177             :                 {
     178           0 :                     rSI.MarkKashidasInvalid ( nKashidasDropped, pKashidaPosDropped );
     179           0 :                     nKashidas -= nKashidasDropped;
     180           0 :                     nGluePortion -= nKashidasDropped;
     181             :                 }
     182             :             }
     183           0 :             nKashidaIdx += nKashidasInAttr;
     184             :         }
     185           0 :         nIdx = nNext;
     186             :     }
     187           0 :     delete[] pKashidaPos;
     188           0 :     delete[] pKashidaPosDropped;
     189             : 
     190             :     // return false if all kashidas have been eliminated
     191           0 :     return (nKashidas > 0);
     192             : }
     193             : 
     194             : /*************************************************************************
     195             :  * lcl_CheckKashidaWidth()
     196             :  *************************************************************************/
     197           0 : static bool lcl_CheckKashidaWidth ( SwScriptInfo& rSI, SwTxtSizeInfo& rInf, SwTxtIter& rItr, xub_StrLen& nKashidas,
     198             :                              xub_StrLen& nGluePortion, const long nGluePortionWidth, long& nSpaceAdd )
     199             : {
     200             :     // check kashida width
     201             :     // if width is smaller than minimal kashida width allowed by fonts in the current line
     202             :     // drop one kashida after the other until kashida width is OK
     203             :     bool bAddSpaceChanged;
     204           0 :     while ( nKashidas )
     205             :     {
     206           0 :         bAddSpaceChanged = false;
     207           0 :         xub_StrLen nIdx = rItr.GetStart();
     208           0 :         xub_StrLen nEnd = rItr.GetEnd();
     209           0 :         while ( nIdx < nEnd )
     210             :         {
     211           0 :             rItr.SeekAndChgAttrIter( nIdx, rInf.GetOut() );
     212           0 :             xub_StrLen nNext = rItr.GetNextAttr();
     213             : 
     214             :             // is there also a script change before?
     215             :             // if there is, nNext should point to the script change
     216           0 :             xub_StrLen nNextScript = rSI.NextScriptChg( nIdx );
     217           0 :             if( nNextScript < nNext )
     218           0 :                nNext = nNextScript;
     219             : 
     220           0 :             if ( nNext == STRING_LEN || nNext > nEnd )
     221           0 :                 nNext = nEnd;
     222           0 :             xub_StrLen nKashidasInAttr = rSI.KashidaJustify ( 0, 0, nIdx, nNext - nIdx );
     223             : 
     224           0 :             long nFontMinKashida = rInf.GetOut()->GetMinKashida();
     225           0 :             if ( nFontMinKashida && nKashidasInAttr && SwScriptInfo::IsArabicText( rInf.GetTxt(), nIdx, nNext - nIdx ) )
     226             :             {
     227           0 :                 xub_StrLen nKashidasDropped = 0;
     228           0 :                 while ( nKashidas && nGluePortion && nKashidasInAttr &&
     229             :                         nSpaceAdd / SPACING_PRECISION_FACTOR < nFontMinKashida )
     230             :                 {
     231           0 :                     --nGluePortion;
     232           0 :                     --nKashidas;
     233           0 :                     --nKashidasInAttr;
     234           0 :                     ++nKashidasDropped;
     235           0 :                     if( !nKashidas || !nGluePortion ) // nothing left, return false to
     236           0 :                         return false;                 // do regular blank justification
     237             : 
     238           0 :                     nSpaceAdd = nGluePortionWidth / nGluePortion;
     239           0 :                     bAddSpaceChanged = true;
     240             :                }
     241           0 :                if( nKashidasDropped )
     242           0 :                    rSI.MarkKashidasInvalid( nKashidasDropped, nIdx, nNext - nIdx );
     243             :             }
     244           0 :             if ( bAddSpaceChanged )
     245           0 :                 break; // start all over again
     246           0 :             nIdx = nNext;
     247             :         }
     248           0 :         if ( !bAddSpaceChanged )
     249           0 :             break; // everything was OK
     250             :     }
     251           0 :    return true;
     252             : }
     253             : 
     254             : /*************************************************************************
     255             :  * SwTxtAdjuster::CalcNewBlock()
     256             :  *
     257             :  * CalcNewBlock() must only be called _after_ CalcLine()!
     258             :  * We always span between two RandPortions or FixPortions (Tabs and Flys).
     259             :  * We count the Glues and call ExpandBlock.
     260             :  *************************************************************************/
     261             : 
     262           2 : void SwTxtAdjuster::CalcNewBlock( SwLineLayout *pCurrent,
     263             :                                   const SwLinePortion *pStopAt, SwTwips nReal, bool bSkipKashida )
     264             : {
     265             :     OSL_ENSURE( GetInfo().IsMulti() || SVX_ADJUST_BLOCK == GetAdjust(),
     266             :             "CalcNewBlock: Why?" );
     267             :     OSL_ENSURE( pCurrent->Height(), "SwTxtAdjuster::CalcBlockAdjust: missing CalcLine()" );
     268             : 
     269           2 :     pCurrent->InitSpaceAdd();
     270           2 :     xub_StrLen nGluePortion = 0;
     271           2 :     xub_StrLen nCharCnt = 0;
     272           2 :     MSHORT nSpaceIdx = 0;
     273             : 
     274             :     // i60591: hennerdrews
     275           2 :     SwScriptInfo& rSI = GetInfo().GetParaPortion()->GetScriptInfo();
     276           2 :     SwTxtSizeInfo aInf ( GetTxtFrm() );
     277           2 :     SwTxtIter aItr ( GetTxtFrm(), &aInf );
     278             : 
     279           2 :     if ( rSI.CountKashida() )
     280             :     {
     281           0 :         while (aItr.GetCurr() != pCurrent && aItr.GetNext())
     282           0 :            aItr.Next();
     283             : 
     284           0 :         if( bSkipKashida )
     285             :         {
     286           0 :             rSI.SetNoKashidaLine ( aItr.GetStart(), aItr.GetLength());
     287             :         }
     288             :         else
     289             :         {
     290           0 :             rSI.ClearKashidaInvalid ( aItr.GetStart(), aItr.GetLength() );
     291           0 :             rSI.ClearNoKashidaLine( aItr.GetStart(), aItr.GetLength() );
     292             :         }
     293             :     }
     294             : 
     295             :     // Do not forget: CalcRightMargin() sets pCurrent->Width() to the line width!
     296           2 :     if (!bSkipKashida)
     297           2 :         CalcRightMargin( pCurrent, nReal );
     298             : 
     299             :     // #i49277#
     300             :     const sal_Bool bDoNotJustifyLinesWithManualBreak =
     301           2 :                 GetTxtFrm()->GetNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK);
     302             : 
     303           2 :     SwLinePortion *pPos = pCurrent->GetPortion();
     304             : 
     305          10 :     while( pPos )
     306             :     {
     307           6 :         if ( bDoNotJustifyLinesWithManualBreak &&
     308           0 :              pPos->IsBreakPortion() && !IsLastBlock() )
     309             :         {
     310           0 :            pCurrent->FinishSpaceAdd();
     311           0 :            break;
     312             :         }
     313             : 
     314           6 :         if ( pPos->InTxtGrp() )
     315           2 :             nGluePortion = nGluePortion + ((SwTxtPortion*)pPos)->GetSpaceCnt( GetInfo(), nCharCnt );
     316           4 :         else if( pPos->IsMultiPortion() )
     317             :         {
     318           0 :             SwMultiPortion* pMulti = (SwMultiPortion*)pPos;
     319             :             // a multiportion with a tabulator inside breaks the text adjustment
     320             :             // a ruby portion will not be stretched by text adjustment
     321             :             // a double line portion takes additional space for each blank
     322             :             // in the wider line
     323           0 :             if( pMulti->HasTabulator() )
     324             :             {
     325           0 :                 if ( nSpaceIdx == pCurrent->GetLLSpaceAddCount() )
     326           0 :                     pCurrent->SetLLSpaceAdd( 0, nSpaceIdx );
     327             : 
     328           0 :                 nSpaceIdx++;
     329           0 :                 nGluePortion = 0;
     330           0 :                 nCharCnt = 0;
     331             :             }
     332           0 :             else if( pMulti->IsDouble() )
     333           0 :                 nGluePortion = nGluePortion + ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt();
     334           0 :             else if ( pMulti->IsBidi() )
     335           0 :                 nGluePortion = nGluePortion + ((SwBidiPortion*)pMulti)->GetSpaceCnt( GetInfo() );  // i60594
     336             :         }
     337             : 
     338           6 :         if( pPos->InGlueGrp() )
     339             :         {
     340           2 :             if( pPos->InFixMargGrp() )
     341             :             {
     342           2 :                 if ( nSpaceIdx == pCurrent->GetLLSpaceAddCount() )
     343           0 :                     pCurrent->SetLLSpaceAdd( 0, nSpaceIdx );
     344             : 
     345           2 :                 const long nGluePortionWidth = static_cast<SwGluePortion*>(pPos)->GetPrtGlue() *
     346           2 :                                                SPACING_PRECISION_FACTOR;
     347             : 
     348           2 :                 xub_StrLen nKashidas = 0;
     349           2 :                 if( nGluePortion && rSI.CountKashida() && !bSkipKashida )
     350             :                 {
     351             :                     // kashida positions found in SwScriptInfo are not necessarily valid in every font
     352             :                     // if two characters are replaced by a ligature glyph, there will be no place for a kashida
     353           0 :                     if ( !lcl_CheckKashidaPositions ( rSI, aInf, aItr, nKashidas, nGluePortion ))
     354             :                     {
     355             :                         // all kashida positions are invalid
     356             :                         // do regular blank justification
     357           0 :                         pCurrent->FinishSpaceAdd();
     358           0 :                         GetInfo().SetIdx( nStart );
     359           0 :                         CalcNewBlock( pCurrent, pStopAt, nReal, true );
     360             :                         return;
     361             :                     }
     362             :                 }
     363             : 
     364           2 :                 if( nGluePortion )
     365             :                 {
     366           2 :                     long nSpaceAdd = nGluePortionWidth / nGluePortion;
     367             : 
     368             :                     // i60594
     369           2 :                     if( rSI.CountKashida() && !bSkipKashida )
     370             :                     {
     371           0 :                         if( !lcl_CheckKashidaWidth( rSI, aInf, aItr, nKashidas, nGluePortion, nGluePortionWidth, nSpaceAdd ))
     372             :                         {
     373             :                             // no kashidas left
     374             :                             // do regular blank justification
     375           0 :                             pCurrent->FinishSpaceAdd();
     376           0 :                             GetInfo().SetIdx( nStart );
     377           0 :                             CalcNewBlock( pCurrent, pStopAt, nReal, true );
     378             :                             return;
     379             :                         }
     380             :                     }
     381             : 
     382           2 :                     pCurrent->SetLLSpaceAdd( nSpaceAdd , nSpaceIdx );
     383           2 :                     pPos->Width( ( (SwGluePortion*)pPos )->GetFixWidth() );
     384             :                 }
     385           0 :                 else if ( IsOneBlock() && nCharCnt > 1 )
     386             :                 {
     387           0 :                     const long nSpaceAdd = - nGluePortionWidth / ( nCharCnt - 1 );
     388           0 :                     pCurrent->SetLLSpaceAdd( nSpaceAdd, nSpaceIdx );
     389           0 :                     pPos->Width( ( (SwGluePortion*)pPos )->GetFixWidth() );
     390             :                 }
     391             : 
     392           2 :                 nSpaceIdx++;
     393           2 :                 nGluePortion = 0;
     394           2 :                 nCharCnt = 0;
     395             :             }
     396             :             else
     397           0 :                 ++nGluePortion;
     398             :         }
     399           6 :         GetInfo().SetIdx( GetInfo().GetIdx() + pPos->GetLen() );
     400           6 :         if ( pPos == pStopAt )
     401             :         {
     402           0 :             pCurrent->SetLLSpaceAdd( 0, nSpaceIdx );
     403           0 :             break;
     404             :         }
     405           6 :         pPos = pPos->GetPortion();
     406           2 :     }
     407             : }
     408             : 
     409             : /*************************************************************************
     410             :  * SwTxtAdjuster::CalcKanaAdj()
     411             :  *************************************************************************/
     412             : 
     413           0 : SwTwips SwTxtAdjuster::CalcKanaAdj( SwLineLayout* pCurrent )
     414             : {
     415             :     OSL_ENSURE( pCurrent->Height(), "SwTxtAdjuster::CalcBlockAdjust: missing CalcLine()" );
     416             :     OSL_ENSURE( !pCurrent->GetpKanaComp(), "pKanaComp already exists!!" );
     417             : 
     418           0 :     std::deque<sal_uInt16> *pNewKana = new std::deque<sal_uInt16>();
     419           0 :     pCurrent->SetKanaComp( pNewKana );
     420             : 
     421           0 :     const sal_uInt16 nNull = 0;
     422           0 :     MSHORT nKanaIdx = 0;
     423           0 :     long nKanaDiffSum = 0;
     424           0 :     SwTwips nRepaintOfst = 0;
     425           0 :     SwTwips nX = 0;
     426           0 :     sal_Bool bNoCompression = sal_False;
     427             : 
     428             :     // Do not forget: CalcRightMargin() sets pCurrent->Width() to the line width!
     429           0 :     CalcRightMargin( pCurrent, 0 );
     430             : 
     431           0 :     SwLinePortion* pPos = pCurrent->GetPortion();
     432             : 
     433           0 :     while( pPos )
     434             :     {
     435           0 :         if ( pPos->InTxtGrp() )
     436             :         {
     437             :             // get maximum portion width from info structure, calculated
     438             :             // during text formatting
     439           0 :             sal_uInt16 nMaxWidthDiff = GetInfo().GetMaxWidthDiff( (sal_uLong)pPos );
     440             : 
     441             :             // check, if information is stored under other key
     442           0 :             if ( !nMaxWidthDiff && pPos == pCurrent->GetFirstPortion() )
     443           0 :                 nMaxWidthDiff = GetInfo().GetMaxWidthDiff( (sal_uLong)pCurrent );
     444             : 
     445             :             // calculate difference between portion width and max. width
     446           0 :             nKanaDiffSum += nMaxWidthDiff;
     447             : 
     448             :             // we store the beginning of the first compressable portion
     449             :             // for repaint
     450           0 :             if ( nMaxWidthDiff && !nRepaintOfst )
     451           0 :                 nRepaintOfst = nX + GetLeftMargin();
     452             :         }
     453           0 :         else if( pPos->InGlueGrp() && pPos->InFixMargGrp() )
     454             :         {
     455           0 :             if ( nKanaIdx == pCurrent->GetKanaComp().size() )
     456           0 :                 pCurrent->GetKanaComp().push_back( nNull );
     457             : 
     458             :             sal_uInt16 nRest;
     459             : 
     460           0 :             if ( pPos->InTabGrp() )
     461             :             {
     462             :                 nRest = ! bNoCompression &&
     463           0 :                         ( pPos->Width() > MIN_TAB_WIDTH ) ?
     464           0 :                         pPos->Width() - MIN_TAB_WIDTH :
     465           0 :                         0;
     466             : 
     467             :                 // for simplifying the handling of left, right ... tabs,
     468             :                 // we do expand portions, which are lying behind
     469             :                 // those special tabs
     470           0 :                 bNoCompression = !pPos->IsTabLeftPortion();
     471             :             }
     472             :             else
     473             :             {
     474             :                 nRest = ! bNoCompression ?
     475           0 :                         ((SwGluePortion*)pPos)->GetPrtGlue() :
     476           0 :                         0;
     477             : 
     478           0 :                 bNoCompression = sal_False;
     479             :             }
     480             : 
     481           0 :             if( nKanaDiffSum )
     482             :             {
     483           0 :                 sal_uLong nCompress = ( 10000 * nRest ) / nKanaDiffSum;
     484             : 
     485           0 :                 if ( nCompress >= 10000 )
     486             :                     // kanas can be expanded to 100%, and there is still
     487             :                     // some space remaining
     488           0 :                     nCompress = 0;
     489             : 
     490             :                 else
     491           0 :                     nCompress = 10000 - nCompress;
     492             : 
     493           0 :                 ( pCurrent->GetKanaComp() )[ nKanaIdx ] = (sal_uInt16)nCompress;
     494           0 :                 nKanaDiffSum = 0;
     495             :             }
     496             : 
     497           0 :             nKanaIdx++;
     498             :         }
     499             : 
     500           0 :         nX += pPos->Width();
     501           0 :         pPos = pPos->GetPortion();
     502             :     }
     503             : 
     504             :     // set portion width
     505           0 :     nKanaIdx = 0;
     506           0 :     sal_uInt16 nCompress = ( pCurrent->GetKanaComp() )[ nKanaIdx ];
     507           0 :     pPos = pCurrent->GetPortion();
     508           0 :     long nDecompress = 0;
     509           0 :     nKanaDiffSum = 0;
     510             : 
     511           0 :     while( pPos )
     512             :     {
     513           0 :         if ( pPos->InTxtGrp() )
     514             :         {
     515           0 :             const sal_uInt16 nMinWidth = pPos->Width();
     516             : 
     517             :             // get maximum portion width from info structure, calculated
     518             :             // during text formatting
     519           0 :             sal_uInt16 nMaxWidthDiff = GetInfo().GetMaxWidthDiff( (sal_uLong)pPos );
     520             : 
     521             :             // check, if information is stored under other key
     522           0 :             if ( !nMaxWidthDiff && pPos == pCurrent->GetFirstPortion() )
     523           0 :                 nMaxWidthDiff = GetInfo().GetMaxWidthDiff( (sal_uLong)pCurrent );
     524           0 :             nKanaDiffSum += nMaxWidthDiff;
     525             :             pPos->Width( nMinWidth +
     526           0 :                        ( ( 10000 - nCompress ) * nMaxWidthDiff ) / 10000 );
     527           0 :             nDecompress += pPos->Width() - nMinWidth;
     528             :         }
     529           0 :         else if( pPos->InGlueGrp() && pPos->InFixMargGrp() )
     530             :         {
     531           0 :             if( nCompress )
     532             :             {
     533           0 :                 nKanaDiffSum *= nCompress;
     534           0 :                 nKanaDiffSum /= 10000;
     535             :             }
     536             : 
     537           0 :             pPos->Width( static_cast<sal_uInt16>(pPos->Width() - nDecompress) );
     538             : 
     539           0 :             if ( pPos->InTabGrp() )
     540             :                 // set fix width to width
     541           0 :                 ((SwTabPortion*)pPos)->SetFixWidth( pPos->Width() );
     542             : 
     543           0 :             if ( ++nKanaIdx < pCurrent->GetKanaComp().size() )
     544           0 :                 nCompress = ( pCurrent->GetKanaComp() )[ nKanaIdx ];
     545             : 
     546           0 :             nKanaDiffSum = 0;
     547           0 :             nDecompress = 0;
     548             :         }
     549           0 :         pPos = pPos->GetPortion();
     550             :     }
     551             : 
     552           0 :     return nRepaintOfst;
     553             : }
     554             : 
     555             : /*************************************************************************
     556             :  * SwTxtAdjuster::CalcRightMargin()
     557             :  *************************************************************************/
     558             : 
     559          21 : SwMarginPortion *SwTxtAdjuster::CalcRightMargin( SwLineLayout *pCurrent,
     560             :     SwTwips nReal )
     561             : {
     562             :     long nRealWidth;
     563          21 :     const sal_uInt16 nRealHeight = GetLineHeight();
     564          21 :     const sal_uInt16 nLineHeight = pCurrent->Height();
     565             : 
     566          21 :     KSHORT nPrtWidth = pCurrent->PrtWidth();
     567          21 :     SwLinePortion *pLast = pCurrent->FindLastPortion();
     568             : 
     569          21 :     if( GetInfo().IsMulti() )
     570           0 :         nRealWidth = nReal;
     571             :     else
     572             :     {
     573          21 :         nRealWidth = GetLineWidth();
     574             :         // For each FlyFrm extending into the right margin, we create a FlyPortion.
     575          21 :         const long nLeftMar = GetLeftMargin();
     576          21 :         SwRect aCurrRect( nLeftMar + nPrtWidth, Y() + nRealHeight - nLineHeight,
     577          42 :                           nRealWidth - nPrtWidth, nLineHeight );
     578             : 
     579          21 :         SwFlyPortion *pFly = CalcFlyPortion( nRealWidth, aCurrRect );
     580          42 :         while( pFly && long( nPrtWidth )< nRealWidth )
     581             :         {
     582           0 :             pLast->Append( pFly );
     583           0 :             pLast = pFly;
     584           0 :             if( pFly->Fix() > nPrtWidth )
     585           0 :                 pFly->Width( ( pFly->Fix() - nPrtWidth) + pFly->Width() + 1);
     586           0 :             nPrtWidth += pFly->Width() + 1;
     587           0 :             aCurrRect.Left( nLeftMar + nPrtWidth );
     588           0 :             pFly = CalcFlyPortion( nRealWidth, aCurrRect );
     589             :         }
     590          21 :         delete pFly;
     591             :     }
     592             : 
     593          21 :     SwMarginPortion *pRight = new SwMarginPortion( 0 );
     594          21 :     pLast->Append( pRight );
     595             : 
     596          21 :     if( long( nPrtWidth )< nRealWidth )
     597          21 :         pRight->PrtWidth( KSHORT( nRealWidth - nPrtWidth ) );
     598             : 
     599             :     // pCurrent->Width() is set to the real size, because we attach the
     600             :     // MarginPortions.
     601             :     // This trick gives miraculous results:
     602             :     // If pCurrent->Width() == nRealWidth, then the adjustment gets overruled
     603             :     // implicitly. GetLeftMarginAdjust() and IsJustified() think they have a
     604             :     // line filled with chars.
     605             : 
     606          21 :     pCurrent->PrtWidth( KSHORT( nRealWidth ) );
     607          21 :     return pRight;
     608             : }
     609             : 
     610             : /*************************************************************************
     611             :  * SwTxtAdjuster::CalcFlyAdjust()
     612             :  *************************************************************************/
     613             : 
     614          19 : void SwTxtAdjuster::CalcFlyAdjust( SwLineLayout *pCurrent )
     615             : {
     616             :     // 1) We insert a left margin:
     617          19 :     SwMarginPortion *pLeft = pCurrent->CalcLeftMargin();
     618          19 :     SwGluePortion *pGlue = pLeft; // the last GluePortion
     619             : 
     620             : 
     621             :     // 2) We attach a right margin:
     622             :     // CalcRightMargin also calculates a possible overlap with FlyFrms.
     623          19 :     CalcRightMargin( pCurrent );
     624             : 
     625          19 :     SwLinePortion *pPos = pLeft->GetPortion();
     626          19 :     xub_StrLen nLen = 0;
     627             : 
     628             :     // If we only have one line, the text portion is consecutive and we center, then ...
     629          19 :     sal_Bool bComplete = 0 == nStart;
     630          19 :     const sal_Bool bTabCompat = GetTxtFrm()->GetNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT);
     631          19 :     sal_Bool bMultiTab = sal_False;
     632             : 
     633          77 :     while( pPos )
     634             :     {
     635          39 :         if ( pPos->IsMultiPortion() && ((SwMultiPortion*)pPos)->HasTabulator() )
     636           0 :             bMultiTab = sal_True;
     637          58 :         else if( pPos->InFixMargGrp() &&
     638          19 :                ( bTabCompat ? ! pPos->InTabGrp() : ! bMultiTab ) )
     639             :         {
     640             :             // in tab compat mode we do not want to change tab portions
     641             :             // in non tab compat mode we do not want to change margins if we
     642             :             // found a multi portion with tabs
     643          19 :             if( SVX_ADJUST_RIGHT == GetAdjust() )
     644           2 :                 ((SwGluePortion*)pPos)->MoveAllGlue( pGlue );
     645             :             else
     646             :             {
     647             :                 // We set the first text portion to right-aligned and the last one
     648             :                 // to left-aligned.
     649             :                 // The first text portion gets the whole Glue, but only if we have
     650             :                 // more than one line.
     651          17 :                 if( bComplete && GetInfo().GetTxt().Len() == nLen )
     652          17 :                     ((SwGluePortion*)pPos)->MoveHalfGlue( pGlue );
     653             :                 else
     654             :                 {
     655           0 :                     if ( ! bTabCompat )
     656             :                     {
     657           0 :                         if( pLeft == pGlue )
     658             :                         {
     659             :                             // If we only have a left and right margin, the
     660             :                             // margins share the Glue.
     661           0 :                             if( nLen + pPos->GetLen() >= pCurrent->GetLen() )
     662           0 :                                 ((SwGluePortion*)pPos)->MoveHalfGlue( pGlue );
     663             :                             else
     664           0 :                                 ((SwGluePortion*)pPos)->MoveAllGlue( pGlue );
     665             :                         }
     666             :                         else
     667             :                         {
     668             :                          // The last text portion retains its Glue.
     669           0 :                          if( !pPos->IsMarginPortion() )
     670           0 :                               ((SwGluePortion*)pPos)->MoveHalfGlue( pGlue );
     671             :                          }
     672             :                      }
     673             :                      else
     674           0 :                         ((SwGluePortion*)pPos)->MoveHalfGlue( pGlue );
     675             :                 }
     676             :             }
     677             : 
     678          19 :             pGlue = (SwFlyPortion*)pPos;
     679          19 :             bComplete = sal_False;
     680             :         }
     681          39 :         nLen = nLen + pPos->GetLen();
     682          39 :         pPos = pPos->GetPortion();
     683             :      }
     684             : 
     685          19 :      if( ! bTabCompat && ! bMultiTab && SVX_ADJUST_RIGHT == GetAdjust() )
     686             :         // portions are moved to the right if possible
     687           0 :         pLeft->AdjustRight( pCurrent );
     688          19 : }
     689             : 
     690             : /*************************************************************************
     691             :  * SwTxtAdjuster::CalcAdjLine()
     692             :  *************************************************************************/
     693             : 
     694          24 : void SwTxtAdjuster::CalcAdjLine( SwLineLayout *pCurrent )
     695             : {
     696             :     OSL_ENSURE( pCurrent->IsFormatAdj(), "CalcAdjLine: Why?" );
     697             : 
     698          24 :     pCurrent->SetFormatAdj(sal_False);
     699             : 
     700          24 :     SwParaPortion* pPara = GetInfo().GetParaPortion();
     701             : 
     702          24 :     switch( GetAdjust() )
     703             :     {
     704             :         case SVX_ADJUST_RIGHT:
     705             :         case SVX_ADJUST_CENTER:
     706             :         {
     707          19 :             CalcFlyAdjust( pCurrent );
     708          19 :             pPara->GetRepaint()->SetOfst( 0 );
     709          19 :             break;
     710             :         }
     711             :         case SVX_ADJUST_BLOCK:
     712             :         {
     713           5 :             FormatBlock();
     714           5 :             break;
     715             :         }
     716           0 :         default : return;
     717             :     }
     718             : }
     719             : 
     720             : /*************************************************************************
     721             :  * SwTxtAdjuster::CalcFlyPortion()
     722             :  *
     723             :  * This is a quite complicated calculation: nCurrWidth is the width _before_
     724             :  * adding the word, that still fits onto the line! For this reason the FlyPortion's
     725             :  * width is still correct if we get a deadlock-situation of:
     726             :  * bFirstWord && !WORDFITS
     727             :  *************************************************************************/
     728             : 
     729          21 : SwFlyPortion *SwTxtAdjuster::CalcFlyPortion( const long nRealWidth,
     730             :                                              const SwRect &rCurrRect )
     731             : {
     732          21 :     SwTxtFly aTxtFly( GetTxtFrm() );
     733             : 
     734          21 :     const KSHORT nCurrWidth = pCurr->PrtWidth();
     735          21 :     SwFlyPortion *pFlyPortion = 0;
     736             : 
     737          21 :     SwRect aLineVert( rCurrRect );
     738          21 :     if ( GetTxtFrm()->IsRightToLeft() )
     739           0 :         GetTxtFrm()->SwitchLTRtoRTL( aLineVert );
     740          21 :     if ( GetTxtFrm()->IsVertical() )
     741           0 :         GetTxtFrm()->SwitchHorizontalToVertical( aLineVert );
     742             : 
     743             :     // aFlyRect is document-global!
     744          21 :     SwRect aFlyRect( aTxtFly.GetFrm( aLineVert ) );
     745             : 
     746          21 :     if ( GetTxtFrm()->IsRightToLeft() )
     747           0 :         GetTxtFrm()->SwitchRTLtoLTR( aFlyRect );
     748          21 :     if ( GetTxtFrm()->IsVertical() )
     749           0 :         GetTxtFrm()->SwitchVerticalToHorizontal( aFlyRect );
     750             : 
     751             :     // If a Frame overlapps we open a Portion
     752          21 :     if( aFlyRect.HasArea() )
     753             :     {
     754             :         // aLocal is frame-local
     755           0 :         SwRect aLocal( aFlyRect );
     756           0 :         aLocal.Pos( aLocal.Left() - GetLeftMargin(), aLocal.Top() );
     757           0 :         if( nCurrWidth > aLocal.Left() )
     758           0 :             aLocal.Left( nCurrWidth );
     759             : 
     760             :         // If the rect is wider than the line, we adjust it to the right size
     761           0 :         KSHORT nLocalWidth = KSHORT( aLocal.Left() + aLocal.Width() );
     762           0 :         if( nRealWidth < long( nLocalWidth ) )
     763           0 :             aLocal.Width( nRealWidth - aLocal.Left() );
     764           0 :         GetInfo().GetParaPortion()->SetFly( sal_True );
     765           0 :         pFlyPortion = new SwFlyPortion( aLocal );
     766           0 :         pFlyPortion->Height( KSHORT( rCurrRect.Height() ) );
     767             :         // The Width could be smaller than the FixWidth, thus:
     768           0 :         pFlyPortion->AdjFixWidth();
     769             :     }
     770          21 :     return pFlyPortion;
     771             : }
     772             : 
     773             : /*************************************************************************
     774             :  * SwTxtPainter::_CalcDropAdjust()
     775             :  * Drops and Adjustment
     776             :  * CalcDropAdjust is called at the end by Format() if needed
     777             :  *************************************************************************/
     778             : 
     779           0 : void SwTxtAdjuster::CalcDropAdjust()
     780             : {
     781             :     OSL_ENSURE( 1<GetDropLines() && SVX_ADJUST_LEFT!=GetAdjust() && SVX_ADJUST_BLOCK!=GetAdjust(),
     782             :             "CalcDropAdjust: No reason for DropAdjustment." );
     783             : 
     784           0 :     const MSHORT nLineNumber = GetLineNr();
     785             : 
     786             :     // 1) Skip dummies
     787           0 :     Top();
     788             : 
     789           0 :     if( !pCurr->IsDummy() || NextLine() )
     790             :     {
     791             :         // Adjust first
     792           0 :         GetAdjusted();
     793             : 
     794           0 :         SwLinePortion *pPor = pCurr->GetFirstPortion();
     795             : 
     796             :         // 2) Make sure we include the ropPortion
     797             :         // 3) pLeft is the GluePor preceding the DropPor
     798           0 :         if( pPor->InGlueGrp() && pPor->GetPortion()
     799           0 :               && pPor->GetPortion()->IsDropPortion() )
     800             :         {
     801           0 :             const SwLinePortion *pDropPor = (SwDropPortion*) pPor->GetPortion();
     802           0 :             SwGluePortion *pLeft = (SwGluePortion*) pPor;
     803             : 
     804             :             // 4) pRight: Find the GluePor coming after the DropPor
     805           0 :             pPor = pPor->GetPortion();
     806           0 :             while( pPor && !pPor->InFixMargGrp() )
     807           0 :                 pPor = pPor->GetPortion();
     808             : 
     809           0 :             SwGluePortion *pRight = ( pPor && pPor->InGlueGrp() ) ?
     810           0 :                                     (SwGluePortion*) pPor : 0;
     811           0 :             if( pRight && pRight != pLeft )
     812             :             {
     813             :                 // 5) Calculate nMinLeft. Who is the most to left?
     814             :                 const KSHORT nDropLineStart =
     815           0 :                     KSHORT(GetLineStart()) + pLeft->Width() + pDropPor->Width();
     816           0 :                 KSHORT nMinLeft = nDropLineStart;
     817           0 :                 for( MSHORT i = 1; i < GetDropLines(); ++i )
     818             :                 {
     819           0 :                     if( NextLine() )
     820             :                     {
     821             :                         // Adjust first
     822           0 :                         GetAdjusted();
     823             : 
     824           0 :                         pPor = pCurr->GetFirstPortion();
     825           0 :                         const SwMarginPortion *pMar = pPor->IsMarginPortion() ?
     826           0 :                                                       (SwMarginPortion*)pPor : 0;
     827           0 :                         if( !pMar )
     828           0 :                             nMinLeft = 0;
     829             :                         else
     830             :                         {
     831             :                             const KSHORT nLineStart =
     832           0 :                                 KSHORT(GetLineStart()) + pMar->Width();
     833           0 :                             if( nMinLeft > nLineStart )
     834           0 :                                 nMinLeft = nLineStart;
     835             :                         }
     836             :                     }
     837             :                 }
     838             : 
     839             :                 // 6) Distribute the Glue anew between pLeft and pRight
     840           0 :                 if( nMinLeft < nDropLineStart )
     841             :                 {
     842             :                     // The Glue is always passed from pLeft to pRight, so that
     843             :                     // the text moves to the left.
     844           0 :                     const short nGlue = nDropLineStart - nMinLeft;
     845           0 :                     if( !nMinLeft )
     846           0 :                         pLeft->MoveAllGlue( pRight );
     847             :                     else
     848           0 :                         pLeft->MoveGlue( pRight, nGlue );
     849             :                 }
     850             :             }
     851             :         }
     852             :     }
     853             : 
     854           0 :     if( nLineNumber != GetLineNr() )
     855             :     {
     856           0 :         Top();
     857           0 :         while( nLineNumber != GetLineNr() && Next() )
     858             :             ;
     859             :     }
     860           0 : }
     861             : 
     862             : /*************************************************************************
     863             :  * SwTxtAdjuster::CalcDropRepaint()
     864             :  *************************************************************************/
     865             : 
     866           0 : void SwTxtAdjuster::CalcDropRepaint()
     867             : {
     868           0 :     Top();
     869           0 :     SwRepaint &rRepaint = *GetInfo().GetParaPortion()->GetRepaint();
     870           0 :     if( rRepaint.Top() > Y() )
     871           0 :         rRepaint.Top( Y() );
     872           0 :     for( MSHORT i = 1; i < GetDropLines(); ++i )
     873           0 :         NextLine();
     874           0 :     const SwTwips nBottom = Y() + GetLineHeight() - 1;
     875           0 :     if( rRepaint.Bottom() < nBottom )
     876           0 :         rRepaint.Bottom( nBottom );
     877           0 : }
     878             : 
     879             : 
     880             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10