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

Generated by: LCOV version 1.10