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 #include "ndtxt.hxx" 29 #include "flyfrm.hxx" 30 #include "paratr.hxx" 31 #include "errhdl.hxx" 32 #include <vcl/outdev.hxx> 33 #include <editeng/paravertalignitem.hxx> 34 35 #include "pormulti.hxx" 36 #include <pagefrm.hxx> 37 #include <pagedesc.hxx> // SwPageDesc 38 #include <tgrditem.hxx> 39 #include <porfld.hxx> 40 41 #include "txtcfg.hxx" 42 #include "itrtxt.hxx" 43 #include "txtfrm.hxx" 44 #include "porfly.hxx" 45 46 #if OSL_DEBUG_LEVEL > 1 47 # include "txtfrm.hxx" // GetFrmID, 48 #endif 49 50 /************************************************************************* 51 * SwTxtIter::CtorInitTxtIter() 52 *************************************************************************/ 53 54 void SwTxtIter::CtorInitTxtIter( SwTxtFrm *pNewFrm, SwTxtInfo *pNewInf ) 55 { 56 #ifdef DBGTXT 57 // nStopAt laesst sich vom CV bearbeiten. 58 static MSHORT nStopAt = 0; 59 if( nStopAt == pNewFrm->GetFrmId() ) 60 { 61 int i = pNewFrm->GetFrmId(); 62 } 63 #endif 64 65 SwTxtNode *pNode = pNewFrm->GetTxtNode(); 66 67 ASSERT( pNewFrm->GetPara(), "No paragraph" ); 68 69 CtorInitAttrIter( *pNode, pNewFrm->GetPara()->GetScriptInfo(), pNewFrm ); 70 71 pFrm = pNewFrm; 72 pInf = pNewInf; 73 // --> OD 2008-01-17 #newlistlevelattrs# 74 aLineInf.CtorInitLineInfo( pNode->GetSwAttrSet(), *pNode ); 75 // <-- 76 nFrameStart = pFrm->Frm().Pos().Y() + pFrm->Prt().Pos().Y(); 77 SwTxtIter::Init(); 78 if( pNode->GetSwAttrSet().GetRegister().GetValue() ) 79 bRegisterOn = pFrm->FillRegister( nRegStart, nRegDiff ); 80 else 81 bRegisterOn = sal_False; 82 } 83 84 /************************************************************************* 85 * SwTxtIter::Init() 86 *************************************************************************/ 87 88 void SwTxtIter::Init() 89 { 90 pCurr = pInf->GetParaPortion(); 91 nStart = pInf->GetTxtStart(); 92 nY = nFrameStart; 93 bPrev = sal_True; 94 pPrev = 0; 95 nLineNr = 1; 96 } 97 98 /************************************************************************* 99 * SwTxtIter::_GetHeightAndAscent() 100 *************************************************************************/ 101 102 void SwTxtIter::CalcAscentAndHeight( KSHORT &rAscent, KSHORT &rHeight ) const 103 { 104 rHeight = GetLineHeight(); 105 rAscent = pCurr->GetAscent() + rHeight - pCurr->Height(); 106 } 107 108 /************************************************************************* 109 * SwTxtIter::_GetPrev() 110 *************************************************************************/ 111 112 SwLineLayout *SwTxtIter::_GetPrev() 113 { 114 pPrev = 0; 115 bPrev = sal_True; 116 SwLineLayout *pLay = pInf->GetParaPortion(); 117 if( pCurr == pLay ) 118 return 0; 119 while( pLay->GetNext() != pCurr ) 120 pLay = pLay->GetNext(); 121 return pPrev = pLay; 122 } 123 124 /************************************************************************* 125 * SwTxtIter::GetPrev() 126 *************************************************************************/ 127 128 const SwLineLayout *SwTxtIter::GetPrev() 129 { 130 if(! bPrev) 131 _GetPrev(); 132 return pPrev; 133 } 134 135 /************************************************************************* 136 * SwTxtIter::Prev() 137 *************************************************************************/ 138 139 const SwLineLayout *SwTxtIter::Prev() 140 { 141 if( !bPrev ) 142 _GetPrev(); 143 if( pPrev ) 144 { 145 bPrev = sal_False; 146 pCurr = pPrev; 147 nStart = nStart - pCurr->GetLen(); 148 nY = nY - GetLineHeight(); 149 if( !pCurr->IsDummy() && !(--nLineNr) ) 150 ++nLineNr; 151 return pCurr; 152 } 153 else 154 return 0; 155 } 156 157 /************************************************************************* 158 * SwTxtIter::Next() 159 *************************************************************************/ 160 161 const SwLineLayout *SwTxtIter::Next() 162 { 163 if(pCurr->GetNext()) 164 { 165 pPrev = pCurr; 166 bPrev = sal_True; 167 nStart = nStart + pCurr->GetLen(); 168 nY += GetLineHeight(); 169 if( pCurr->GetLen() || ( nLineNr>1 && !pCurr->IsDummy() ) ) 170 ++nLineNr; 171 return pCurr = pCurr->GetNext(); 172 } 173 else 174 return 0; 175 } 176 177 /************************************************************************* 178 * SwTxtIter::NextLine() 179 *************************************************************************/ 180 181 const SwLineLayout *SwTxtIter::NextLine() 182 { 183 const SwLineLayout *pNext = Next(); 184 while( pNext && pNext->IsDummy() && pNext->GetNext() ) 185 { 186 DBG_LOOP; 187 pNext = Next(); 188 } 189 return pNext; 190 } 191 192 /************************************************************************* 193 * SwTxtIter::GetNextLine() 194 *************************************************************************/ 195 196 const SwLineLayout *SwTxtIter::GetNextLine() const 197 { 198 const SwLineLayout *pNext = pCurr->GetNext(); 199 while( pNext && pNext->IsDummy() && pNext->GetNext() ) 200 { 201 DBG_LOOP; 202 pNext = pNext->GetNext(); 203 } 204 return (SwLineLayout*)pNext; 205 } 206 207 /************************************************************************* 208 * SwTxtIter::GetPrevLine() 209 *************************************************************************/ 210 211 const SwLineLayout *SwTxtIter::GetPrevLine() 212 { 213 const SwLineLayout *pRoot = pInf->GetParaPortion(); 214 if( pRoot == pCurr ) 215 return 0; 216 const SwLineLayout *pLay = pRoot; 217 218 while( pLay->GetNext() != pCurr ) 219 pLay = pLay->GetNext(); 220 221 if( pLay->IsDummy() ) 222 { 223 const SwLineLayout *pTmp = pRoot; 224 pLay = pRoot->IsDummy() ? 0 : pRoot; 225 while( pTmp->GetNext() != pCurr ) 226 { 227 if( !pTmp->IsDummy() ) 228 pLay = pTmp; 229 pTmp = pTmp->GetNext(); 230 } 231 } 232 233 // Wenn sich nichts getan hat, dann gibt es nur noch Dummys 234 return (SwLineLayout*)pLay; 235 } 236 237 /************************************************************************* 238 * SwTxtIter::PrevLine() 239 *************************************************************************/ 240 241 const SwLineLayout *SwTxtIter::PrevLine() 242 { 243 const SwLineLayout *pMyPrev = Prev(); 244 if( !pMyPrev ) 245 return 0; 246 247 const SwLineLayout *pLast = pMyPrev; 248 while( pMyPrev && pMyPrev->IsDummy() ) 249 { 250 DBG_LOOP; 251 pLast = pMyPrev; 252 pMyPrev = Prev(); 253 } 254 return (SwLineLayout*)(pMyPrev ? pMyPrev : pLast); 255 } 256 257 /************************************************************************* 258 * SwTxtIter::Bottom() 259 *************************************************************************/ 260 261 void SwTxtIter::Bottom() 262 { 263 while( Next() ) 264 { 265 DBG_LOOP; 266 } 267 } 268 269 /************************************************************************* 270 * SwTxtIter::CharToLine() 271 *************************************************************************/ 272 273 void SwTxtIter::CharToLine(const xub_StrLen nChar) 274 { 275 while( nStart + pCurr->GetLen() <= nChar && Next() ) 276 ; 277 while( nStart > nChar && Prev() ) 278 ; 279 } 280 281 /************************************************************************* 282 * SwTxtIter::CharCrsrToLine() 283 *************************************************************************/ 284 285 // 1170: beruecksichtigt Mehrdeutigkeiten: 286 const SwLineLayout *SwTxtCursor::CharCrsrToLine( const xub_StrLen nPosition ) 287 { 288 CharToLine( nPosition ); 289 if( nPosition != nStart ) 290 bRightMargin = sal_False; 291 sal_Bool bPrevious = bRightMargin && pCurr->GetLen() && GetPrev() && 292 GetPrev()->GetLen(); 293 if( bPrevious && nPosition && CH_BREAK == GetInfo().GetChar( nPosition-1 ) ) 294 bPrevious = sal_False; 295 return bPrevious ? PrevLine() : pCurr; 296 } 297 298 /************************************************************************* 299 * SwTxtCrsr::AdjustBaseLine() 300 *************************************************************************/ 301 302 sal_uInt16 SwTxtCursor::AdjustBaseLine( const SwLineLayout& rLine, 303 const SwLinePortion* pPor, 304 sal_uInt16 nPorHeight, sal_uInt16 nPorAscent, 305 const sal_Bool bAutoToCentered ) const 306 { 307 if ( pPor ) 308 { 309 nPorHeight = pPor->Height(); 310 nPorAscent = pPor->GetAscent(); 311 } 312 313 sal_uInt16 nOfst = rLine.GetRealHeight() - rLine.Height(); 314 315 GETGRID( pFrm->FindPageFrm() ) 316 const sal_Bool bHasGrid = pGrid && GetInfo().SnapToGrid(); 317 318 if ( bHasGrid ) 319 { 320 const sal_uInt16 nRubyHeight = pGrid->GetRubyHeight(); 321 const sal_Bool bRubyTop = ! pGrid->GetRubyTextBelow(); 322 323 if ( GetInfo().IsMulti() ) 324 // we are inside the GetCharRect recursion for multi portions 325 // we center the portion in its surrounding line 326 nOfst = ( pCurr->Height() - nPorHeight ) / 2 + nPorAscent; 327 else 328 { 329 // We have to take care for ruby portions. 330 // The ruby portion is NOT centered 331 nOfst = nOfst + nPorAscent; 332 333 if ( ! pPor || ! pPor->IsMultiPortion() || 334 ! ((SwMultiPortion*)pPor)->IsRuby() ) 335 { 336 // Portions which are bigger than on grid distance are 337 // centered inside the whole line. 338 339 //for text refactor 340 const sal_uInt16 nLineNetto = rLine.Height() - nRubyHeight; 341 //const sal_uInt16 nLineNetto = ( nPorHeight > nGridWidth ) ? 342 // rLine.Height() - nRubyHeight : 343 // nGridWidth; 344 nOfst += ( nLineNetto - nPorHeight ) / 2; 345 if ( bRubyTop ) 346 nOfst = nOfst + nRubyHeight; 347 } 348 } 349 } 350 else 351 { 352 switch ( GetLineInfo().GetVertAlign() ) { 353 case SvxParaVertAlignItem::TOP : 354 nOfst = nOfst + nPorAscent; 355 break; 356 case SvxParaVertAlignItem::CENTER : 357 ASSERT( rLine.Height() >= nPorHeight, "Portion height > Line height"); 358 nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent; 359 break; 360 case SvxParaVertAlignItem::BOTTOM : 361 nOfst += rLine.Height() - nPorHeight + nPorAscent; 362 break; 363 case SvxParaVertAlignItem::AUTOMATIC : 364 if ( bAutoToCentered || GetInfo().GetTxtFrm()->IsVertical() ) 365 { 366 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin 367 if( GetInfo().GetTxtFrm()->IsVertLR() ) 368 nOfst += rLine.Height() - ( rLine.Height() - nPorHeight ) / 2 - nPorAscent; 369 else 370 nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent; 371 break; 372 } 373 case SvxParaVertAlignItem::BASELINE : 374 // base line 375 nOfst = nOfst + rLine.GetAscent(); 376 break; 377 } 378 } 379 380 return nOfst; 381 } 382 383 /************************************************************************* 384 * SwTxtIter::TwipsToLine() 385 *************************************************************************/ 386 387 const SwLineLayout *SwTxtIter::TwipsToLine( const SwTwips y) 388 { 389 while( nY + GetLineHeight() <= y && Next() ) 390 ; 391 while( nY > y && Prev() ) 392 ; 393 return pCurr; 394 } 395 396 // 397 // Local helper function to check, if pCurr needs a field rest portion: 398 // 399 sal_Bool lcl_NeedsFieldRest( const SwLineLayout* pCurr ) 400 { 401 const SwLinePortion *pPor = pCurr->GetPortion(); 402 sal_Bool bRet = sal_False; 403 while( pPor && !bRet ) 404 { 405 bRet = pPor->InFldGrp() && ((SwFldPortion*)pPor)->HasFollow(); 406 if( !pPor->GetPortion() || !pPor->GetPortion()->InFldGrp() ) 407 break; 408 pPor = pPor->GetPortion(); 409 } 410 return bRet; 411 } 412 413 /************************************************************************* 414 * SwTxtIter::TruncLines() 415 *************************************************************************/ 416 417 void SwTxtIter::TruncLines( sal_Bool bNoteFollow ) 418 { 419 SwLineLayout *pDel = pCurr->GetNext(); 420 const xub_StrLen nEnd = nStart + pCurr->GetLen(); 421 422 if( pDel ) 423 { 424 pCurr->SetNext( 0 ); 425 if( GetHints() && bNoteFollow ) 426 { 427 GetInfo().GetParaPortion()->SetFollowField( pDel->IsRest() || 428 lcl_NeedsFieldRest( pCurr ) ); 429 430 // bug 88534: wrong positioning of flys 431 SwTxtFrm* pFollow = GetTxtFrm()->GetFollow(); 432 if ( pFollow && ! pFollow->IsLocked() && 433 nEnd == pFollow->GetOfst() ) 434 { 435 xub_StrLen nRangeEnd = nEnd; 436 SwLineLayout* pLine = pDel; 437 438 // determine range to be searched for flys anchored as characters 439 while ( pLine ) 440 { 441 nRangeEnd = nRangeEnd + pLine->GetLen(); 442 pLine = pLine->GetNext(); 443 } 444 445 SwpHints* pTmpHints = GetTxtFrm()->GetTxtNode()->GetpSwpHints(); 446 447 // examine hints in range nEnd - (nEnd + nRangeChar) 448 for( sal_uInt16 i = 0; i < pTmpHints->Count(); i++ ) 449 { 450 const SwTxtAttr* pHt = pTmpHints->GetTextHint( i ); 451 if( RES_TXTATR_FLYCNT == pHt->Which() ) 452 { 453 // check, if hint is in our range 454 const sal_uInt16 nTmpPos = *pHt->GetStart(); 455 if ( nEnd <= nTmpPos && nTmpPos < nRangeEnd ) 456 pFollow->_InvalidateRange( 457 SwCharRange( nTmpPos, nTmpPos ), 0 ); 458 } 459 } 460 } 461 } 462 delete pDel; 463 } 464 if( pCurr->IsDummy() && 465 !pCurr->GetLen() && 466 nStart < GetTxtFrm()->GetTxt().Len() ) 467 pCurr->SetRealHeight( 1 ); 468 if( GetHints() ) 469 pFrm->RemoveFtn( nEnd ); 470 } 471 472 /************************************************************************* 473 * SwTxtIter::CntHyphens() 474 *************************************************************************/ 475 476 void SwTxtIter::CntHyphens( sal_uInt8 &nEndCnt, sal_uInt8 &nMidCnt) const 477 { 478 nEndCnt = 0; 479 nMidCnt = 0; 480 if ( bPrev && pPrev && !pPrev->IsEndHyph() && !pPrev->IsMidHyph() ) 481 return; 482 SwLineLayout *pLay = pInf->GetParaPortion(); 483 if( pCurr == pLay ) 484 return; 485 while( pLay != pCurr ) 486 { 487 DBG_LOOP; 488 if ( pLay->IsEndHyph() ) 489 nEndCnt++; 490 else 491 nEndCnt = 0; 492 if ( pLay->IsMidHyph() ) 493 nMidCnt++; 494 else 495 nMidCnt = 0; 496 pLay = pLay->GetNext(); 497 } 498 } 499 500 /************************************************************************* 501 * SwHookOut 502 * 503 * Change current output device to formatting device, this has to be done before 504 * formatting. 505 *************************************************************************/ 506 507 SwHookOut::SwHookOut( SwTxtSizeInfo& rInfo ) : 508 pInf( &rInfo ), 509 pOut( rInfo.GetOut() ), 510 bOnWin( rInfo.OnWin() ) 511 { 512 ASSERT( rInfo.GetRefDev(), "No reference device for text formatting" ) 513 514 // set new values 515 rInfo.SetOut( rInfo.GetRefDev() ); 516 rInfo.SetOnWin( sal_False ); 517 } 518 519 SwHookOut::~SwHookOut() 520 { 521 pInf->SetOut( pOut ); 522 pInf->SetOnWin( bOnWin ); 523 } 524