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

Generated by: LCOV version 1.11