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

Generated by: LCOV version 1.10