1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sw.hxx" 26 27 28 29 #include "swrect.hxx" 30 #include "paratr.hxx" // pTabStop, ADJ* 31 #include "viewopt.hxx" // SwViewOptions 32 #include "errhdl.hxx" // ASSERT 33 #include <SwPortionHandler.hxx> 34 35 #include "txtcfg.hxx" 36 #include "porglue.hxx" 37 #include "inftxt.hxx" 38 #include "porlay.hxx" // SwParaPortion, SetFull 39 #include "porfly.hxx" // SwParaPortion, SetFull 40 41 /************************************************************************* 42 * class SwGluePortion 43 *************************************************************************/ 44 45 SwGluePortion::SwGluePortion( const KSHORT nInitFixWidth ) 46 : nFixWidth( nInitFixWidth ) 47 { 48 PrtWidth( nFixWidth ); 49 SetWhichPor( POR_GLUE ); 50 } 51 52 /************************************************************************* 53 * virtual SwGluePortion::GetCrsrOfst() 54 *************************************************************************/ 55 56 xub_StrLen SwGluePortion::GetCrsrOfst( const KSHORT nOfst ) const 57 { 58 if( !GetLen() || nOfst > GetLen() || !Width() ) 59 return SwLinePortion::GetCrsrOfst( nOfst ); 60 else 61 return nOfst / (Width() / GetLen()); 62 } 63 64 /************************************************************************* 65 * virtual SwGluePortion::GetTxtSize() 66 *************************************************************************/ 67 68 SwPosSize SwGluePortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const 69 { 70 if( 1 >= GetLen() || rInf.GetLen() > GetLen() || !Width() || !GetLen() ) 71 return SwPosSize(*this); 72 else 73 return SwPosSize( (Width() / GetLen()) * rInf.GetLen(), Height() ); 74 } 75 76 /************************************************************************* 77 * virtual SwGluePortion::GetExpTxt() 78 *************************************************************************/ 79 80 sal_Bool SwGluePortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const 81 { 82 if( GetLen() && rInf.OnWin() && 83 rInf.GetOpt().IsBlank() && rInf.IsNoSymbol() ) 84 { 85 rTxt.Fill( GetLen(), CH_BULLET ); 86 return sal_True; 87 } 88 return sal_False; 89 } 90 91 /************************************************************************* 92 * virtual SwGluePortion::Paint() 93 *************************************************************************/ 94 95 void SwGluePortion::Paint( const SwTxtPaintInfo &rInf ) const 96 { 97 if( !GetLen() ) 98 return; 99 100 if( rInf.GetFont()->IsPaintBlank() ) 101 { 102 XubString aTxt; 103 aTxt.Fill( GetFixWidth() / GetLen(), ' ' ); 104 SwTxtPaintInfo aInf( rInf, aTxt ); 105 aInf.DrawText( *this, aTxt.Len(), sal_True ); 106 } 107 108 if( rInf.OnWin() && rInf.GetOpt().IsBlank() && rInf.IsNoSymbol() ) 109 { 110 #ifdef DBG_UTIL 111 const xub_Unicode cChar = rInf.GetChar( rInf.GetIdx() ); 112 ASSERT( CH_BLANK == cChar || CH_BULLET == cChar, 113 "SwGluePortion::Paint: blank expected" ); 114 #endif 115 if( 1 == GetLen() ) 116 { 117 String aBullet( CH_BULLET ); 118 SwPosSize aBulletSize( rInf.GetTxtSize( aBullet ) ); 119 Point aPos( rInf.GetPos() ); 120 aPos.X() += (Width()/2) - (aBulletSize.Width()/2); 121 SwTxtPaintInfo aInf( rInf, aBullet ); 122 aInf.SetPos( aPos ); 123 SwTxtPortion aBulletPor; 124 aBulletPor.Width( aBulletSize.Width() ); 125 aBulletPor.Height( aBulletSize.Height() ); 126 aBulletPor.SetAscent( GetAscent() ); 127 aInf.DrawText( aBulletPor, aBullet.Len(), sal_True ); 128 } 129 else 130 { 131 SwTxtSlot aSlot( &rInf, this, true, false ); 132 rInf.DrawText( *this, rInf.GetLen(), sal_True ); 133 } 134 } 135 } 136 137 /************************************************************************* 138 * SwGluePortion::MoveGlue() 139 *************************************************************************/ 140 141 void SwGluePortion::MoveGlue( SwGluePortion *pTarget, const short nPrtGlue ) 142 { 143 short nPrt = Min( nPrtGlue, GetPrtGlue() ); 144 if( 0 < nPrt ) 145 { 146 pTarget->AddPrtWidth( nPrt ); 147 SubPrtWidth( nPrt ); 148 } 149 } 150 151 /************************************************************************* 152 * void SwGluePortion::Join() 153 *************************************************************************/ 154 155 void SwGluePortion::Join( SwGluePortion *pVictim ) 156 { 157 // Die GluePortion wird ausgesogen und weggespuelt ... 158 AddPrtWidth( pVictim->PrtWidth() ); 159 SetLen( pVictim->GetLen() + GetLen() ); 160 if( Height() < pVictim->Height() ) 161 Height( pVictim->Height() ); 162 163 AdjFixWidth(); 164 Cut( pVictim ); 165 delete pVictim; 166 } 167 168 /************************************************************************* 169 * class SwFixPortion 170 *************************************************************************/ 171 172 // Wir erwarten ein framelokales SwRect ! 173 SwFixPortion::SwFixPortion( const SwRect &rRect ) 174 :SwGluePortion( KSHORT(rRect.Width()) ), nFix( KSHORT(rRect.Left()) ) 175 { 176 Height( KSHORT(rRect.Height()) ); 177 SetWhichPor( POR_FIX ); 178 } 179 180 SwFixPortion::SwFixPortion(const KSHORT nFixedWidth, const KSHORT nFixedPos) 181 : SwGluePortion(nFixedWidth), nFix(nFixedPos) 182 { 183 SetWhichPor( POR_FIX ); 184 } 185 186 /************************************************************************* 187 * class SwMarginPortion 188 *************************************************************************/ 189 190 SwMarginPortion::SwMarginPortion( const KSHORT nFixedWidth ) 191 :SwGluePortion( nFixedWidth ) 192 { 193 SetWhichPor( POR_MARGIN ); 194 } 195 196 /************************************************************************* 197 * SwMarginPortion::AdjustRight() 198 * 199 * In der umschliessenden Schleife werden alle Portions durchsucht, 200 * dabei werden erst die am Ende liegenden GluePortions verarbeitet. 201 * Das Ende wird nach jeder Schleife nach vorne verlegt, bis keine 202 * GluePortions mehr vorhanden sind. 203 * Es werden immer GluePortion-Paare betrachtet (pLeft und pRight), 204 * wobei Textportions zwischen pLeft und pRight hinter pRight verschoben 205 * werden, wenn pRight genuegend Glue besitzt. Bei jeder Verschiebung 206 * wandert ein Teil des Glues von pRight nach pLeft. 207 * Im naechsten Schleifendurchlauf ist pLeft das pRight und das Spiel 208 * beginnt von vorne. 209 *************************************************************************/ 210 211 void SwMarginPortion::AdjustRight( const SwLineLayout *pCurr ) 212 { 213 SwGluePortion *pRight = 0; 214 sal_Bool bNoMove = 0 != pCurr->GetpKanaComp(); 215 while( pRight != this ) 216 { 217 218 // 1) Wir suchen den linken Glue 219 SwLinePortion *pPos = (SwLinePortion*)this; 220 SwGluePortion *pLeft = 0; 221 while( pPos ) 222 { 223 DBG_LOOP; 224 if( pPos->InFixMargGrp() ) 225 pLeft = (SwGluePortion*)pPos; 226 pPos = pPos->GetPortion(); 227 if( pPos == pRight) 228 pPos = 0; 229 } 230 231 // Zwei nebeneinander liegende FlyPortions verschmelzen 232 if( pRight && pLeft->GetPortion() == pRight ) 233 { 234 pRight->MoveAllGlue( pLeft ); 235 pRight = 0; 236 } 237 KSHORT nRightGlue = pRight && 0 < pRight->GetPrtGlue() 238 ? KSHORT(pRight->GetPrtGlue()) : 0; 239 // 2) linken und rechten Glue ausgleichen 240 // Bei Tabs haengen wir nix um ... 241 if( pLeft && nRightGlue && !pRight->InTabGrp() ) 242 { 243 // pPrev ist die Portion, die unmittelbar vor pRight liegt. 244 SwLinePortion *pPrev = pRight->FindPrevPortion( pLeft ); 245 246 if ( pRight->IsFlyPortion() && pRight->GetLen() ) 247 { 248 SwFlyPortion *pFly = (SwFlyPortion *)pRight; 249 if ( pFly->GetBlankWidth() < nRightGlue ) 250 { 251 // Hier entsteht eine neue TxtPortion, die dass zuvor 252 // vom Fly verschluckte Blank reaktiviert. 253 nRightGlue = nRightGlue - pFly->GetBlankWidth(); 254 pFly->SubPrtWidth( pFly->GetBlankWidth() ); 255 pFly->SetLen( 0 ); 256 SwTxtPortion *pNewPor = new SwTxtPortion; 257 pNewPor->SetLen( 1 ); 258 pNewPor->Height( pFly->Height() ); 259 pNewPor->Width( pFly->GetBlankWidth() ); 260 pFly->Insert( pNewPor ); 261 } 262 else 263 pPrev = pLeft; 264 } 265 while( pPrev != pLeft ) 266 { 267 DBG_LOOP; 268 269 if( bNoMove || pPrev->PrtWidth() >= nRightGlue || 270 pPrev->InHyphGrp() || pPrev->IsKernPortion() ) 271 { 272 // Die Portion, die vor pRight liegt kann nicht 273 // verschoben werden, weil kein Glue mehr vorhanden ist. 274 // Wir fuehren die Abbruchbedingung herbei: 275 pPrev = pLeft; 276 } 277 else 278 { 279 nRightGlue = nRightGlue - pPrev->PrtWidth(); 280 // pPrev wird hinter pRight verschoben. 281 // Dazu wird der Gluewert zwischen pRight und pLeft 282 // ausgeglichen. 283 pRight->MoveGlue( pLeft, short( pPrev->PrtWidth() ) ); 284 // Jetzt wird die Verkettung gerichtet. 285 SwLinePortion *pPrevPrev = pPrev->FindPrevPortion( pLeft ); 286 pPrevPrev->SetPortion( pRight ); 287 pPrev->SetPortion( pRight->GetPortion() ); 288 pRight->SetPortion( pPrev ); 289 if ( pPrev->GetPortion() && pPrev->InTxtGrp() 290 && pPrev->GetPortion()->IsHolePortion() ) 291 { 292 SwHolePortion *pHolePor = 293 (SwHolePortion*)pPrev->GetPortion(); 294 if ( !pHolePor->GetPortion() || 295 !pHolePor->GetPortion()->InFixMargGrp() ) 296 { 297 pPrev->AddPrtWidth( pHolePor->GetBlankWidth() ); 298 pPrev->SetLen( pPrev->GetLen() + 1 ); 299 pPrev->SetPortion( pHolePor->GetPortion() ); 300 delete pHolePor; 301 } 302 } 303 pPrev = pPrevPrev; 304 } 305 } 306 } 307 // Wenn es keinen linken Glue mehr gibt, wird die Abbruchbedingung 308 // herbeigefuehrt. 309 pRight = pLeft ? pLeft : (SwGluePortion*)this; 310 } 311 } 312 313 314 315