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