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 #include "hintids.hxx" 32 #include "errhdl.hxx" 33 #include "ndtxt.hxx" 34 #include "frmfmt.hxx" 35 #include "paratr.hxx" 36 #include "flyfrm.hxx" 37 #include "pam.hxx" 38 #include "swselectionlist.hxx" 39 #include <sortedobjs.hxx> 40 #include <editeng/protitem.hxx> 41 #include <editeng/adjitem.hxx> 42 #include <editeng/lspcitem.hxx> 43 #include <editeng/lrspitem.hxx> 44 #include <frmatr.hxx> 45 #include <pagedesc.hxx> // SwPageDesc 46 #include <tgrditem.hxx> 47 #include <IDocumentSettingAccess.hxx> 48 #include <pagefrm.hxx> 49 50 #include "txtcfg.hxx" 51 #include "itrtxt.hxx" 52 #include "txtfrm.hxx" 53 #include "flyfrms.hxx" 54 #include "porglue.hxx" // SwFlyCnt 55 #include "porfld.hxx" // SwFldPortion::IsFollow() 56 #include "porfly.hxx" // GetFlyCrsrOfst() 57 #include "pordrop.hxx" 58 #include "crstate.hxx" // SwCrsrMoveState 59 #include <pormulti.hxx> // SwMultiPortion 60 // --> OD 2010-05-05 #i111284# 61 #include <numrule.hxx> 62 // <-- 63 64 // Nicht reentrant !!! 65 // wird in GetCharRect gesetzt und im UnitUp/Down ausgewertet. 66 sal_Bool SwTxtCursor::bRightMargin = sal_False; 67 68 69 /************************************************************************* 70 * lcl_GetCharRectInsideField 71 * 72 * After calculating the position of a character during GetCharRect 73 * this function allows to find the coordinates of a position (defined 74 * in pCMS->pSpecialPos) inside a special portion (e.g., a field) 75 *************************************************************************/ 76 void lcl_GetCharRectInsideField( SwTxtSizeInfo& rInf, SwRect& rOrig, 77 const SwCrsrMoveState& rCMS, 78 const SwLinePortion& rPor ) 79 { 80 ASSERT( rCMS.pSpecialPos, "Information about special pos missing" ) 81 82 if ( rPor.InFldGrp() && ((SwFldPortion&)rPor).GetExp().Len() ) 83 { 84 const sal_uInt16 nCharOfst = rCMS.pSpecialPos->nCharOfst; 85 sal_uInt16 nFldIdx = 0; 86 sal_uInt16 nFldLen = 0; 87 88 const XubString* pString = 0; 89 const SwLinePortion* pPor = &rPor; 90 do 91 { 92 if ( pPor->InFldGrp() ) 93 { 94 pString = &((SwFldPortion*)pPor)->GetExp(); 95 nFldLen = pString->Len(); 96 } 97 else 98 { 99 pString = 0; 100 nFldLen = 0; 101 } 102 103 if ( ! pPor->GetPortion() || nFldIdx + nFldLen > nCharOfst ) 104 break; 105 106 nFldIdx = nFldIdx + nFldLen; 107 rOrig.Pos().X() += pPor->Width(); 108 pPor = pPor->GetPortion(); 109 110 } while ( sal_True ); 111 112 ASSERT( nCharOfst >= nFldIdx, "Request of position inside field failed" ) 113 sal_uInt16 nLen = nCharOfst - nFldIdx + 1; 114 115 if ( pString ) 116 { 117 // get script for field portion 118 rInf.GetFont()->SetActual( SwScriptInfo::WhichFont( 0, pString, 0 ) ); 119 120 xub_StrLen nOldLen = pPor->GetLen(); 121 ((SwLinePortion*)pPor)->SetLen( nLen - 1 ); 122 const SwTwips nX1 = pPor->GetLen() ? 123 pPor->GetTxtSize( rInf ).Width() : 124 0; 125 126 SwTwips nX2 = 0; 127 if ( rCMS.bRealWidth ) 128 { 129 ((SwLinePortion*)pPor)->SetLen( nLen ); 130 nX2 = pPor->GetTxtSize( rInf ).Width(); 131 } 132 133 ((SwLinePortion*)pPor)->SetLen( nOldLen ); 134 135 rOrig.Pos().X() += nX1; 136 rOrig.Width( ( nX2 > nX1 ) ? 137 ( nX2 - nX1 ) : 138 1 ); 139 } 140 } 141 else 142 { 143 // special cases: no common fields, e.g., graphic number portion, 144 // FlyInCntPortions, Notes 145 rOrig.Width( rCMS.bRealWidth && rPor.Width() ? rPor.Width() : 1 ); 146 } 147 } 148 149 // --> OD 2010-05-05 #i111284# 150 namespace { 151 bool AreListLevelIndentsApplicableAndLabelAlignmentActive( const SwTxtNode& rTxtNode ) 152 { 153 bool bRet( false ); 154 155 if ( rTxtNode.AreListLevelIndentsApplicable() ) 156 { 157 const SwNumFmt& rNumFmt = 158 rTxtNode.GetNumRule()->Get( static_cast<sal_uInt16>(rTxtNode.GetActualListLevel()) ); 159 if ( rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) 160 { 161 bRet = true; 162 } 163 } 164 165 return bRet; 166 } 167 } // end of anonymous namespace 168 // <-- 169 170 /************************************************************************* 171 * SwTxtMargin::CtorInitTxtMargin() 172 *************************************************************************/ 173 void SwTxtMargin::CtorInitTxtMargin( SwTxtFrm *pNewFrm, SwTxtSizeInfo *pNewInf ) 174 { 175 CtorInitTxtIter( pNewFrm, pNewInf ); 176 177 pInf = pNewInf; 178 GetInfo().SetFont( GetFnt() ); 179 const SwTxtNode *pNode = pFrm->GetTxtNode(); 180 181 const SvxLRSpaceItem &rSpace = pFrm->GetTxtNode()->GetSwAttrSet().GetLRSpace(); 182 // --> OD 2009-09-08 #i95907#, #b6879723# 183 // --> OD 2010-05-05 #i111284# 184 const bool bListLevelIndentsApplicableAndLabelAlignmentActive( 185 AreListLevelIndentsApplicableAndLabelAlignmentActive( *(pFrm->GetTxtNode()) ) ); 186 // <-- 187 188 // 189 // Carefully adjust the text formatting ranges. 190 // 191 // This whole area desperately needs some rework. There are 192 // quite a couple of values that need to be considered: 193 // 1. paragraph indent 194 // 2. paragraph first line indent 195 // 3. numbering indent 196 // 4. numbering spacing to text 197 // 5. paragraph border 198 // Note: These values have already been used during calculation 199 // of the printing area of the paragraph. 200 const int nLMWithNum = pNode->GetLeftMarginWithNum( sal_True ); 201 if ( pFrm->IsRightToLeft() ) 202 { 203 // --> OD 2008-01-23 #newlistlevelattrs# 204 // this calculation is identical this the calculation for L2R layout - see below 205 nLeft = pFrm->Frm().Left() + 206 pFrm->Prt().Left() + 207 nLMWithNum - 208 pNode->GetLeftMarginWithNum( sal_False ) - 209 // --> OD 2009-09-08 #i95907#, #b6879723# 210 // --> OD 2010-05-05 #i111284# 211 // rSpace.GetLeft() + 212 // rSpace.GetTxtLeft(); 213 ( bListLevelIndentsApplicableAndLabelAlignmentActive 214 ? 0 215 : ( rSpace.GetLeft() - rSpace.GetTxtLeft() ) ); 216 // <-- 217 } 218 else 219 { 220 // --> OD 2009-09-08 #i95907#, #b6879723# 221 // --> OD 2010-05-05 #i111284# 222 // if ( !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) ) 223 if ( bListLevelIndentsApplicableAndLabelAlignmentActive || 224 !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) ) 225 // <-- 226 { 227 // this calculation is identical this the calculation for R2L layout - see above 228 nLeft = pFrm->Frm().Left() + 229 pFrm->Prt().Left() + 230 nLMWithNum - 231 pNode->GetLeftMarginWithNum( sal_False ) - 232 // --> OD 2009-09-08 #i95907#, #b6879723# 233 // --> OD 2010-05-05 #i111284# 234 // rSpace.GetLeft() + 235 // rSpace.GetTxtLeft(); 236 ( bListLevelIndentsApplicableAndLabelAlignmentActive 237 ? 0 238 : ( rSpace.GetLeft() - rSpace.GetTxtLeft() ) ); 239 // <-- 240 } 241 else 242 { 243 nLeft = pFrm->Frm().Left() + 244 Max( long( rSpace.GetTxtLeft() + nLMWithNum ), 245 pFrm->Prt().Left() ); 246 } 247 } 248 249 nRight = pFrm->Frm().Left() + pFrm->Prt().Left() + pFrm->Prt().Width(); 250 251 if( nLeft >= nRight && 252 // --> FME 2005-08-10 #i53066# Omit adjustment of nLeft for numbered 253 // paras inside cells inside new documents: 254 ( pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) || 255 !pFrm->IsInTab() || 256 !nLMWithNum ) ) 257 // <-- 258 { 259 nLeft = pFrm->Prt().Left() + pFrm->Frm().Left(); 260 if( nLeft >= nRight ) // z.B. bei grossen Absatzeinzuegen in schmalen Tabellenspalten 261 nRight = nLeft + 1; // einen goennen wir uns immer 262 } 263 264 if( pFrm->IsFollow() && pFrm->GetOfst() ) 265 nFirst = nLeft; 266 else 267 { 268 short nFLOfst = 0; 269 long nFirstLineOfs = 0; 270 if( !pNode->GetFirstLineOfsWithNum( nFLOfst ) && 271 rSpace.IsAutoFirst() ) 272 { 273 nFirstLineOfs = GetFnt()->GetSize( GetFnt()->GetActual() ).Height(); 274 const SvxLineSpacingItem *pSpace = aLineInf.GetLineSpacing(); 275 if( pSpace ) 276 { 277 switch( pSpace->GetLineSpaceRule() ) 278 { 279 case SVX_LINE_SPACE_AUTO: 280 break; 281 case SVX_LINE_SPACE_MIN: 282 { 283 if( nFirstLineOfs < KSHORT( pSpace->GetLineHeight() ) ) 284 nFirstLineOfs = pSpace->GetLineHeight(); 285 break; 286 } 287 case SVX_LINE_SPACE_FIX: 288 nFirstLineOfs = pSpace->GetLineHeight(); 289 break; 290 default: ASSERT( sal_False, ": unknown LineSpaceRule" ); 291 } 292 switch( pSpace->GetInterLineSpaceRule() ) 293 { 294 case SVX_INTER_LINE_SPACE_OFF: 295 break; 296 case SVX_INTER_LINE_SPACE_PROP: 297 { 298 long nTmp = pSpace->GetPropLineSpace(); 299 // 50% ist das Minimum, bei 0% schalten wir auf 300 // den Defaultwert 100% um ... 301 if( nTmp < 50 ) 302 nTmp = nTmp ? 50 : 100; 303 304 nTmp *= nFirstLineOfs; 305 nTmp /= 100; 306 if( !nTmp ) 307 ++nTmp; 308 nFirstLineOfs = (KSHORT)nTmp; 309 break; 310 } 311 case SVX_INTER_LINE_SPACE_FIX: 312 { 313 nFirstLineOfs += pSpace->GetInterLineSpace(); 314 break; 315 } 316 default: ASSERT( sal_False, ": unknown InterLineSpaceRule" ); 317 } 318 } 319 } 320 else 321 nFirstLineOfs = nFLOfst; 322 323 // --> OD 2009-09-08 #i95907#, #b6879723# 324 // --> OD 2010-05-05 #i111284# 325 // if ( pFrm->IsRightToLeft() || 326 // !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) ) 327 if ( pFrm->IsRightToLeft() || 328 bListLevelIndentsApplicableAndLabelAlignmentActive || 329 !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) ) 330 // <-- 331 { 332 nFirst = nLeft + nFirstLineOfs; 333 } 334 else 335 { 336 nFirst = pFrm->Frm().Left() + 337 Max( rSpace.GetTxtLeft() + nLMWithNum+ nFirstLineOfs, 338 pFrm->Prt().Left() ); 339 } 340 341 // --> OD 2008-01-31 #newlistlevelattrs# 342 // Note: <SwTxtFrm::GetAdditionalFirstLineOffset()> returns a negative 343 // value for the new list label postion and space mode LABEL_ALIGNMENT 344 // and label alignment CENTER and RIGHT in L2R layout respectively 345 // label alignment LEFT and CENTER in R2L layout 346 nFirst += pFrm->GetAdditionalFirstLineOffset(); 347 // <-- 348 349 if( nFirst >= nRight ) 350 nFirst = nRight - 1; 351 } 352 const SvxAdjustItem& rAdjust = pFrm->GetTxtNode()->GetSwAttrSet().GetAdjust(); 353 nAdjust = static_cast<sal_uInt16>(rAdjust.GetAdjust()); 354 355 // left is left and right is right 356 if ( pFrm->IsRightToLeft() ) 357 { 358 if ( SVX_ADJUST_LEFT == nAdjust ) 359 nAdjust = SVX_ADJUST_RIGHT; 360 else if ( SVX_ADJUST_RIGHT == nAdjust ) 361 nAdjust = SVX_ADJUST_LEFT; 362 } 363 364 bOneBlock = rAdjust.GetOneWord() == SVX_ADJUST_BLOCK; 365 bLastBlock = rAdjust.GetLastBlock() == SVX_ADJUST_BLOCK; 366 bLastCenter = rAdjust.GetLastBlock() == SVX_ADJUST_CENTER; 367 368 // --> OD 2008-07-01 #i91133# 369 mnTabLeft = pNode->GetLeftMarginForTabCalculation(); 370 // <-- 371 372 #if OSL_DEBUG_LEVEL > 1 373 static sal_Bool bOne = sal_False; 374 static sal_Bool bLast = sal_False; 375 static sal_Bool bCenter = sal_False; 376 bOneBlock |= bOne; 377 bLastBlock |= bLast; 378 bLastCenter |= bCenter; 379 #endif 380 DropInit(); 381 } 382 383 /************************************************************************* 384 * SwTxtMargin::DropInit() 385 *************************************************************************/ 386 void SwTxtMargin::DropInit() 387 { 388 nDropLeft = nDropLines = nDropHeight = nDropDescent = 0; 389 const SwParaPortion *pPara = GetInfo().GetParaPortion(); 390 if( pPara ) 391 { 392 const SwDropPortion *pPorDrop = pPara->FindDropPortion(); 393 if ( pPorDrop ) 394 { 395 nDropLeft = pPorDrop->GetDropLeft(); 396 nDropLines = pPorDrop->GetLines(); 397 nDropHeight = pPorDrop->GetDropHeight(); 398 nDropDescent = pPorDrop->GetDropDescent(); 399 } 400 } 401 } 402 403 /************************************************************************* 404 * SwTxtMargin::GetLineStart() 405 *************************************************************************/ 406 407 // Unter Beruecksichtigung des Erstzeileneinzuges und der angebenen Breite. 408 SwTwips SwTxtMargin::GetLineStart() const 409 { 410 SwTwips nRet = GetLeftMargin(); 411 if( GetAdjust() != SVX_ADJUST_LEFT && 412 !pCurr->GetFirstPortion()->IsMarginPortion() ) 413 { 414 // Wenn die erste Portion ein Margin ist, dann wird das 415 // Adjustment durch die Portions ausgedrueckt. 416 if( GetAdjust() == SVX_ADJUST_RIGHT ) 417 nRet = Right() - CurrWidth(); 418 else if( GetAdjust() == SVX_ADJUST_CENTER ) 419 nRet += (GetLineWidth() - CurrWidth()) / 2; 420 } 421 return nRet; 422 } 423 424 /************************************************************************* 425 * SwTxtCursor::CtorInitTxtCursor() 426 *************************************************************************/ 427 void SwTxtCursor::CtorInitTxtCursor( SwTxtFrm *pNewFrm, SwTxtSizeInfo *pNewInf ) 428 { 429 CtorInitTxtMargin( pNewFrm, pNewInf ); 430 // 6096: Vorsicht, die Iteratoren sind abgeleitet! 431 // GetInfo().SetOut( GetInfo().GetWin() ); 432 } 433 434 /************************************************************************* 435 * SwTxtCursor::GetEndCharRect() 436 *************************************************************************/ 437 438 // 1170: Antikbug: Shift-Ende vergisst das letzte Zeichen ... 439 440 sal_Bool SwTxtCursor::GetEndCharRect( SwRect* pOrig, const xub_StrLen nOfst, 441 SwCrsrMoveState* pCMS, const long nMax ) 442 { 443 // 1170: Mehrdeutigkeit von Dokumentpositionen 444 bRightMargin = sal_True; 445 CharCrsrToLine(nOfst); 446 447 // Etwas verdreht: nOfst bezeichnet die Position hinter dem letzten 448 // Zeichen der letzten Zeile == Position vor dem ersten Zeichen der 449 // Zeile in der wir gerade stehen: 450 if( nOfst != GetStart() || !pCurr->GetLen() ) 451 { 452 // 8810: Masterzeile RightMargin, danach LeftMargin 453 const sal_Bool bRet = GetCharRect( pOrig, nOfst, pCMS, nMax ); 454 bRightMargin = nOfst >= GetEnd() && nOfst < GetInfo().GetTxt().Len(); 455 return bRet; 456 } 457 458 if( !GetPrev() || !GetPrev()->GetLen() || !PrevLine() ) 459 return GetCharRect( pOrig, nOfst, pCMS, nMax ); 460 461 // Adjustierung ggf. nachholen 462 GetAdjusted(); 463 464 KSHORT nX = 0; 465 KSHORT nLast = 0; 466 SwLinePortion *pPor = pCurr->GetFirstPortion(); 467 468 KSHORT nTmpHeight, nTmpAscent; 469 CalcAscentAndHeight( nTmpAscent, nTmpHeight ); 470 KSHORT nPorHeight = nTmpHeight; 471 KSHORT nPorAscent = nTmpAscent; 472 473 // Die letzte Text/EndPortion der Zeile suchen 474 while( pPor ) 475 { 476 nX = nX + pPor->Width(); 477 if( pPor->InTxtGrp() || ( pPor->GetLen() && !pPor->IsFlyPortion() 478 && !pPor->IsHolePortion() ) || pPor->IsBreakPortion() ) 479 { 480 nLast = nX; 481 nPorHeight = pPor->Height(); 482 nPorAscent = pPor->GetAscent(); 483 } 484 pPor = pPor->GetPortion(); 485 } 486 487 const Size aCharSize( 1, nTmpHeight ); 488 pOrig->Pos( GetTopLeft() ); 489 pOrig->SSize( aCharSize ); 490 pOrig->Pos().X() += nLast; 491 const SwTwips nTmpRight = Right() - 1; 492 if( pOrig->Left() > nTmpRight ) 493 pOrig->Pos().X() = nTmpRight; 494 495 if ( pCMS && pCMS->bRealHeight ) 496 { 497 if ( nTmpAscent > nPorAscent ) 498 pCMS->aRealHeight.X() = nTmpAscent - nPorAscent; 499 else 500 pCMS->aRealHeight.X() = 0; 501 ASSERT( nPorHeight, "GetCharRect: Missing Portion-Height" ); 502 pCMS->aRealHeight.Y() = nPorHeight; 503 } 504 505 return sal_True; 506 } 507 508 /************************************************************************* 509 * void SwTxtCursor::_GetCharRect(..) 510 * internal function, called by SwTxtCursor::GetCharRect() to calculate 511 * the relative character position in the current line. 512 * pOrig referes to x and y coordinates, width and height of the cursor 513 * pCMS is used for restricting the cursor, if there are different font 514 * heights in one line ( first value = offset to y of pOrig, second 515 * value = real height of (shortened) cursor 516 *************************************************************************/ 517 518 void SwTxtCursor::_GetCharRect( SwRect* pOrig, const xub_StrLen nOfst, 519 SwCrsrMoveState* pCMS ) 520 { 521 const XubString &rText = GetInfo().GetTxt(); 522 SwTxtSizeInfo aInf( GetInfo(), rText, nStart ); 523 if( GetPropFont() ) 524 aInf.GetFont()->SetProportion( GetPropFont() ); 525 KSHORT nTmpAscent, nTmpHeight; // Zeilenhoehe 526 CalcAscentAndHeight( nTmpAscent, nTmpHeight ); 527 const Size aCharSize( 1, nTmpHeight ); 528 const Point aCharPos; 529 pOrig->Pos( aCharPos ); 530 pOrig->SSize( aCharSize ); 531 532 // If we are looking for a position inside a field which covers 533 // more than one line we may not skip any "empty portions" at the 534 // beginning of a line 535 const sal_Bool bInsideFirstField = pCMS && pCMS->pSpecialPos && 536 ( pCMS->pSpecialPos->nLineOfst || 537 SP_EXTEND_RANGE_BEFORE == 538 pCMS->pSpecialPos->nExtendRange ); 539 540 sal_Bool bWidth = pCMS && pCMS->bRealWidth; 541 if( !pCurr->GetLen() && !pCurr->Width() ) 542 { 543 if ( pCMS && pCMS->bRealHeight ) 544 { 545 pCMS->aRealHeight.X() = 0; 546 pCMS->aRealHeight.Y() = nTmpHeight; 547 } 548 } 549 else 550 { 551 KSHORT nPorHeight = nTmpHeight; 552 KSHORT nPorAscent = nTmpAscent; 553 SwTwips nX = 0; 554 SwTwips nTmpFirst = 0; 555 SwLinePortion *pPor = pCurr->GetFirstPortion(); 556 SwBidiPortion* pLastBidiPor = 0; 557 SwTwips nLastBidiPorWidth = 0; 558 SvUShorts* pKanaComp = pCurr->GetpKanaComp(); 559 MSHORT nSpaceIdx = 0; 560 MSHORT nKanaIdx = 0; 561 long nSpaceAdd = pCurr->IsSpaceAdd() ? pCurr->GetLLSpaceAdd( 0 ) : 0; 562 563 sal_Bool bNoTxt = sal_True; 564 565 // Zuerst werden alle Portions ohne Len am Zeilenanfang uebersprungen. 566 // Ausnahme bilden die fiesen Spezialportions aus WhichFirstPortion: 567 // Num, ErgoSum, FtnNum, FeldReste 568 // 8477: aber auch die einzige Textportion einer leeren Zeile mit 569 // Right/Center-Adjustment! Also nicht nur pPor->GetExpandPortion() ... 570 while( pPor && !pPor->GetLen() && ! bInsideFirstField ) 571 { 572 nX += pPor->Width(); 573 if ( pPor->InSpaceGrp() && nSpaceAdd ) 574 nX += pPor->CalcSpacing( nSpaceAdd, aInf ); 575 if( bNoTxt ) 576 nTmpFirst = nX; 577 // 8670: EndPortions zaehlen hier einmal als TxtPortions. 578 // --> OD 2008-01-28 #newlistlevelattrs# 579 // if( pPor->InTxtGrp() || pPor->IsBreakPortion() ) 580 if( pPor->InTxtGrp() || pPor->IsBreakPortion() || pPor->InTabGrp() ) 581 // <-- 582 { 583 bNoTxt = sal_False; 584 nTmpFirst = nX; 585 } 586 if( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->HasTabulator() ) 587 { 588 if ( pCurr->IsSpaceAdd() ) 589 { 590 if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() ) 591 nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx ); 592 else 593 nSpaceAdd = 0; 594 } 595 596 if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() ) 597 ++nKanaIdx; 598 } 599 if( pPor->InFixMargGrp() ) 600 { 601 if( pPor->IsMarginPortion() ) 602 bNoTxt = sal_False; 603 else 604 { 605 // fix margin portion => next SpaceAdd, KanaComp value 606 if ( pCurr->IsSpaceAdd() ) 607 { 608 if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() ) 609 nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx ); 610 else 611 nSpaceAdd = 0; 612 } 613 614 if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() ) 615 ++nKanaIdx; 616 } 617 } 618 pPor = pPor->GetPortion(); 619 } 620 621 if( !pPor ) 622 { 623 // Es sind nur Spezialportions unterwegs. 624 nX = nTmpFirst; 625 } 626 else 627 { 628 if( !pPor->IsMarginPortion() && !pPor->IsPostItsPortion() && 629 (!pPor->InFldGrp() || pPor->GetAscent() ) ) 630 { 631 nPorHeight = pPor->Height(); 632 nPorAscent = pPor->GetAscent(); 633 } 634 while( pPor && !pPor->IsBreakPortion() && ( aInf.GetIdx() < nOfst || 635 ( bWidth && ( pPor->IsKernPortion() || pPor->IsMultiPortion() ) ) ) ) 636 { 637 if( !pPor->IsMarginPortion() && !pPor->IsPostItsPortion() && 638 (!pPor->InFldGrp() || pPor->GetAscent() ) ) 639 { 640 nPorHeight = pPor->Height(); 641 nPorAscent = pPor->GetAscent(); 642 } 643 644 // If we are behind the portion, we add the portion width to 645 // nX. Special case: nOfst = aInf.GetIdx() + pPor->GetLen(). 646 // For common portions (including BidiPortions) we want to add 647 // the portion width to nX. For MultiPortions, nExtra = 0, 648 // therefore we go to the 'else' branch and start a recursion. 649 const sal_uInt8 nExtra = pPor->IsMultiPortion() && 650 ! ((SwMultiPortion*)pPor)->IsBidi() && 651 ! bWidth ? 0 : 1; 652 if ( aInf.GetIdx() + pPor->GetLen() < nOfst + nExtra ) 653 { 654 if ( pPor->InSpaceGrp() && nSpaceAdd ) 655 nX += pPor->PrtWidth() + 656 pPor->CalcSpacing( nSpaceAdd, aInf ); 657 else 658 { 659 if( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() ) 660 { 661 // update to current SpaceAdd, KanaComp values 662 if ( pCurr->IsSpaceAdd() ) 663 { 664 if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() ) 665 nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx ); 666 else 667 nSpaceAdd = 0; 668 } 669 670 if ( pKanaComp && 671 ( nKanaIdx + 1 ) < pKanaComp->Count() 672 ) 673 ++nKanaIdx; 674 } 675 if ( !pPor->IsFlyPortion() || ( pPor->GetPortion() && 676 !pPor->GetPortion()->IsMarginPortion() ) ) 677 nX += pPor->PrtWidth(); 678 } 679 if( pPor->IsMultiPortion() ) 680 { 681 if ( ((SwMultiPortion*)pPor)->HasTabulator() ) 682 { 683 if ( pCurr->IsSpaceAdd() ) 684 { 685 if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() ) 686 nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx ); 687 else 688 nSpaceAdd = 0; 689 } 690 691 if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() ) 692 ++nKanaIdx; 693 } 694 695 // if we are right behind a BidiPortion, we have to 696 // hold a pointer to the BidiPortion in order to 697 // find the correct cursor position, depending on the 698 // cursor level 699 if ( ((SwMultiPortion*)pPor)->IsBidi() && 700 aInf.GetIdx() + pPor->GetLen() == nOfst ) 701 { 702 pLastBidiPor = (SwBidiPortion*)pPor; 703 nLastBidiPorWidth = pLastBidiPor->Width() + 704 pLastBidiPor->CalcSpacing( nSpaceAdd, aInf );; 705 } 706 } 707 708 aInf.SetIdx( aInf.GetIdx() + pPor->GetLen() ); 709 pPor = pPor->GetPortion(); 710 } 711 else 712 { 713 if( pPor->IsMultiPortion() ) 714 { 715 nTmpAscent = AdjustBaseLine( *pCurr, pPor ); 716 GetInfo().SetMulti( sal_True ); 717 pOrig->Pos().Y() += nTmpAscent - nPorAscent; 718 719 if( pCMS && pCMS->b2Lines ) 720 { 721 sal_Bool bRecursion = sal_True; 722 if ( ! pCMS->p2Lines ) 723 { 724 pCMS->p2Lines = new Sw2LinesPos; 725 pCMS->p2Lines->aLine = SwRect(aCharPos, aCharSize); 726 bRecursion = sal_False; 727 } 728 729 if( ((SwMultiPortion*)pPor)->HasRotation() ) 730 { 731 if( ((SwMultiPortion*)pPor)->IsRevers() ) 732 pCMS->p2Lines->nMultiType = MT_ROT_270; 733 else 734 pCMS->p2Lines->nMultiType = MT_ROT_90; 735 } 736 else if( ((SwMultiPortion*)pPor)->IsDouble() ) 737 pCMS->p2Lines->nMultiType = MT_TWOLINE; 738 else if( ((SwMultiPortion*)pPor)->IsBidi() ) 739 pCMS->p2Lines->nMultiType = MT_BIDI; 740 else 741 pCMS->p2Lines->nMultiType = MT_RUBY; 742 743 SwTwips nTmpWidth = pPor->Width(); 744 if( nSpaceAdd ) 745 nTmpWidth += pPor->CalcSpacing(nSpaceAdd, aInf); 746 747 SwRect aRect( Point(aCharPos.X() + nX, pOrig->Top() ), 748 Size( nTmpWidth, pPor->Height() ) ); 749 750 if ( ! bRecursion ) 751 pCMS->p2Lines->aPortion = aRect; 752 else 753 pCMS->p2Lines->aPortion2 = aRect; 754 } 755 756 // In a multi-portion we use GetCharRect()-function 757 // recursively and must add the x-position 758 // of the multi-portion. 759 xub_StrLen nOldStart = nStart; 760 SwTwips nOldY = nY; 761 sal_uInt8 nOldProp = GetPropFont(); 762 nStart = aInf.GetIdx(); 763 SwLineLayout* pOldCurr = pCurr; 764 pCurr = &((SwMultiPortion*)pPor)->GetRoot(); 765 if( ((SwMultiPortion*)pPor)->IsDouble() ) 766 SetPropFont( 50 ); 767 768 GETGRID( GetTxtFrm()->FindPageFrm() ) 769 const sal_Bool bHasGrid = pGrid && GetInfo().SnapToGrid(); 770 const sal_uInt16 nRubyHeight = bHasGrid ? 771 pGrid->GetRubyHeight() : 0; 772 773 if( nStart + pCurr->GetLen() <= nOfst && GetNext() && 774 ( ! ((SwMultiPortion*)pPor)->IsRuby() || 775 ((SwMultiPortion*)pPor)->OnTop() ) ) 776 { 777 sal_uInt16 nOffset; 778 // in grid mode we may only add the height of the 779 // ruby line if ruby line is on top 780 if ( bHasGrid && 781 ((SwMultiPortion*)pPor)->IsRuby() && 782 ((SwMultiPortion*)pPor)->OnTop() ) 783 nOffset = nRubyHeight; 784 else 785 nOffset = GetLineHeight(); 786 787 pOrig->Pos().Y() += nOffset; 788 Next(); 789 } 790 791 sal_Bool bSpaceChg = ((SwMultiPortion*)pPor)-> 792 ChgSpaceAdd( pCurr, nSpaceAdd ); 793 Point aOldPos = pOrig->Pos(); 794 795 // Ok, for ruby portions in grid mode we have to 796 // temporarily set the inner line height to the 797 // outer line height because that value is needed 798 // for the adjustment inside the recursion 799 const sal_uInt16 nOldRubyHeight = pCurr->Height(); 800 const sal_uInt16 nOldRubyRealHeight = pCurr->GetRealHeight(); 801 const sal_Bool bChgHeight = 802 ((SwMultiPortion*)pPor)->IsRuby() && bHasGrid; 803 804 if ( bChgHeight ) 805 { 806 pCurr->Height( pOldCurr->Height() - nRubyHeight ); 807 pCurr->SetRealHeight( pOldCurr->GetRealHeight() - 808 nRubyHeight ); 809 } 810 811 SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() ); 812 if ( ((SwMultiPortion*)pPor)->IsBidi() ) 813 { 814 aLayoutModeModifier.Modify( 815 ((SwBidiPortion*)pPor)->GetLevel() % 2 ); 816 } 817 818 _GetCharRect( pOrig, nOfst, pCMS ); 819 820 if ( bChgHeight ) 821 { 822 pCurr->Height( nOldRubyHeight ); 823 pCurr->SetRealHeight( nOldRubyRealHeight ); 824 } 825 826 // if we are still in the first row of 827 // our 2 line multiportion, we use the FirstMulti flag 828 // to indicate this 829 if ( ((SwMultiPortion*)pPor)->IsDouble() ) 830 { 831 // the recursion may have damaged our font size 832 SetPropFont( nOldProp ); 833 if ( !nOldProp ) 834 nOldProp = 100; 835 GetInfo().GetFont()->SetProportion( 100 ); 836 837 if ( pCurr == &((SwMultiPortion*)pPor)->GetRoot() ) 838 { 839 GetInfo().SetFirstMulti( sal_True ); 840 841 // we want to treat a double line portion like a 842 // single line portion, if there is no text in 843 // the second line 844 if ( !pCurr->GetNext() || 845 !pCurr->GetNext()->GetLen() ) 846 GetInfo().SetMulti( sal_False ); 847 } 848 } 849 // ruby portions are treated like single line portions 850 else if( ((SwMultiPortion*)pPor)->IsRuby() || 851 ((SwMultiPortion*)pPor)->IsBidi() ) 852 GetInfo().SetMulti( sal_False ); 853 854 // calculate cursor values 855 if( ((SwMultiPortion*)pPor)->HasRotation() ) 856 { 857 GetInfo().SetMulti( sal_False ); 858 long nTmp = pOrig->Width(); 859 pOrig->Width( pOrig->Height() ); 860 pOrig->Height( nTmp ); 861 nTmp = pOrig->Left() - aOldPos.X(); 862 863 // if we travel into our rotated portion from 864 // a line below, we have to take care, that the 865 // y coord in pOrig is less than line height: 866 if ( nTmp ) 867 nTmp--; 868 869 pOrig->Pos().X() = nX + aOldPos.X(); 870 if( ((SwMultiPortion*)pPor)->IsRevers() ) 871 pOrig->Pos().Y() = aOldPos.Y() + nTmp; 872 else 873 pOrig->Pos().Y() = aOldPos.Y() 874 + pPor->Height() - nTmp - pOrig->Height(); 875 if ( pCMS && pCMS->bRealHeight ) 876 { 877 pCMS->aRealHeight.Y() = -pCMS->aRealHeight.Y(); 878 // result for rotated multi portion is not 879 // correct for reverse (270 degree) portions 880 if( ((SwMultiPortion*)pPor)->IsRevers() ) 881 { 882 if ( SvxParaVertAlignItem::AUTOMATIC == 883 GetLineInfo().GetVertAlign() ) 884 // if vertical alignment is set to auto, 885 // we switch from base line alignment 886 // to centered alignment 887 pCMS->aRealHeight.X() = 888 ( pOrig->Width() + 889 pCMS->aRealHeight.Y() ) / 2; 890 else 891 pCMS->aRealHeight.X() = 892 ( pOrig->Width() - 893 pCMS->aRealHeight.X() + 894 pCMS->aRealHeight.Y() ); 895 } 896 } 897 } 898 else 899 { 900 pOrig->Pos().Y() += aOldPos.Y(); 901 if ( ((SwMultiPortion*)pPor)->IsBidi() ) 902 { 903 const SwTwips nPorWidth = pPor->Width() + 904 pPor->CalcSpacing( nSpaceAdd, aInf ); 905 const SwTwips nInsideOfst = pOrig->Pos().X(); 906 pOrig->Pos().X() = nX + nPorWidth - 907 nInsideOfst - pOrig->Width(); 908 } 909 else 910 pOrig->Pos().X() += nX; 911 912 if( ((SwMultiPortion*)pPor)->HasBrackets() ) 913 pOrig->Pos().X() += 914 ((SwDoubleLinePortion*)pPor)->PreWidth(); 915 } 916 917 if( bSpaceChg ) 918 SwDoubleLinePortion::ResetSpaceAdd( pCurr ); 919 920 pCurr = pOldCurr; 921 nStart = nOldStart; 922 nY = nOldY; 923 bPrev = sal_False; 924 925 return; 926 } 927 if ( pPor->PrtWidth() ) 928 { 929 xub_StrLen nOldLen = pPor->GetLen(); 930 pPor->SetLen( nOfst - aInf.GetIdx() ); 931 aInf.SetLen( pPor->GetLen() ); 932 if( nX || !pPor->InNumberGrp() ) 933 { 934 SeekAndChg( aInf ); 935 const sal_Bool bOldOnWin = aInf.OnWin(); 936 aInf.SetOnWin( sal_False ); // keine BULLETs! 937 SwTwips nTmp = nX; 938 aInf.SetKanaComp( pKanaComp ); 939 aInf.SetKanaIdx( nKanaIdx ); 940 nX += pPor->GetTxtSize( aInf ).Width(); 941 aInf.SetOnWin( bOldOnWin ); 942 if ( pPor->InSpaceGrp() && nSpaceAdd ) 943 nX += pPor->CalcSpacing( nSpaceAdd, aInf ); 944 if( bWidth ) 945 { 946 pPor->SetLen( pPor->GetLen() + 1 ); 947 aInf.SetLen( pPor->GetLen() ); 948 aInf.SetOnWin( sal_False ); // keine BULLETs! 949 nTmp += pPor->GetTxtSize( aInf ).Width(); 950 aInf.SetOnWin( bOldOnWin ); 951 if ( pPor->InSpaceGrp() && nSpaceAdd ) 952 nTmp += pPor->CalcSpacing(nSpaceAdd, aInf); 953 pOrig->Width( nTmp - nX ); 954 } 955 } 956 pPor->SetLen( nOldLen ); 957 } 958 bWidth = sal_False; 959 break; 960 } 961 } 962 } 963 964 if( pPor ) 965 { 966 ASSERT( !pPor->InNumberGrp() || bInsideFirstField, "Number surprise" ); 967 sal_Bool bEmptyFld = sal_False; 968 if( pPor->InFldGrp() && pPor->GetLen() ) 969 { 970 SwFldPortion *pTmp = (SwFldPortion*)pPor; 971 while( pTmp->HasFollow() && !pTmp->GetExp().Len() ) 972 { 973 KSHORT nAddX = pTmp->Width(); 974 SwLinePortion *pNext = pTmp->GetPortion(); 975 while( pNext && !pNext->InFldGrp() ) 976 { 977 ASSERT( !pNext->GetLen(), "Where's my field follow?" ); 978 nAddX = nAddX + pNext->Width(); 979 pNext = pNext->GetPortion(); 980 } 981 if( !pNext ) 982 break; 983 pTmp = (SwFldPortion*)pNext; 984 nPorHeight = pTmp->Height(); 985 nPorAscent = pTmp->GetAscent(); 986 nX += nAddX; 987 bEmptyFld = sal_True; 988 } 989 } 990 // 8513: Felder im Blocksatz, ueberspringen 991 while( pPor && !pPor->GetLen() && ! bInsideFirstField && 992 ( pPor->IsFlyPortion() || pPor->IsKernPortion() || 993 pPor->IsBlankPortion() || pPor->InTabGrp() || 994 ( !bEmptyFld && pPor->InFldGrp() ) ) ) 995 { 996 if ( pPor->InSpaceGrp() && nSpaceAdd ) 997 nX += pPor->PrtWidth() + 998 pPor->CalcSpacing( nSpaceAdd, aInf ); 999 else 1000 { 1001 if( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() ) 1002 { 1003 if ( pCurr->IsSpaceAdd() ) 1004 { 1005 if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() ) 1006 nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx ); 1007 else 1008 nSpaceAdd = 0; 1009 } 1010 1011 if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() ) 1012 ++nKanaIdx; 1013 } 1014 if ( !pPor->IsFlyPortion() || ( pPor->GetPortion() && 1015 !pPor->GetPortion()->IsMarginPortion() ) ) 1016 nX += pPor->PrtWidth(); 1017 } 1018 if( pPor->IsMultiPortion() && 1019 ((SwMultiPortion*)pPor)->HasTabulator() ) 1020 { 1021 if ( pCurr->IsSpaceAdd() ) 1022 { 1023 if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() ) 1024 nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx ); 1025 else 1026 nSpaceAdd = 0; 1027 } 1028 1029 if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() ) 1030 ++nKanaIdx; 1031 } 1032 if( !pPor->IsFlyPortion() ) 1033 { 1034 nPorHeight = pPor->Height(); 1035 nPorAscent = pPor->GetAscent(); 1036 } 1037 pPor = pPor->GetPortion(); 1038 } 1039 1040 if( aInf.GetIdx() == nOfst && pPor && pPor->InHyphGrp() && 1041 pPor->GetPortion() && pPor->GetPortion()->InFixGrp() ) 1042 { 1043 // Alle Sonderportions muessen uebersprungen werden 1044 // Beispiel: zu-[FLY]sammen, 'u' == 19, 's' == 20; Right() 1045 // Ohne den Ausgleich landen wir vor '-' mit dem 1046 // Ausgleich vor 's'. 1047 while( pPor && !pPor->GetLen() ) 1048 { 1049 DBG_LOOP; 1050 nX += pPor->Width(); 1051 if( !pPor->IsMarginPortion() ) 1052 { 1053 nPorHeight = pPor->Height(); 1054 nPorAscent = pPor->GetAscent(); 1055 } 1056 pPor = pPor->GetPortion(); 1057 } 1058 } 1059 if( pPor && pCMS ) 1060 { 1061 if( pCMS->bFieldInfo && pPor->InFldGrp() && pPor->Width() ) 1062 pOrig->Width( pPor->Width() ); 1063 if( pPor->IsDropPortion() ) 1064 { 1065 nPorAscent = ((SwDropPortion*)pPor)->GetDropHeight(); 1066 // The drop height is only calculated, if we have more than 1067 // one line. Otherwise it is 0. 1068 if ( ! nPorAscent) 1069 nPorAscent = pPor->Height(); 1070 nPorHeight = nPorAscent; 1071 pOrig->Height( nPorHeight + 1072 ((SwDropPortion*)pPor)->GetDropDescent() ); 1073 if( nTmpHeight < pOrig->Height() ) 1074 { 1075 nTmpAscent = nPorAscent; 1076 nTmpHeight = sal_uInt16( pOrig->Height() ); 1077 } 1078 } 1079 if( bWidth && pPor->PrtWidth() && pPor->GetLen() && 1080 aInf.GetIdx() == nOfst ) 1081 { 1082 if( !pPor->IsFlyPortion() && pPor->Height() && 1083 pPor->GetAscent() ) 1084 { 1085 nPorHeight = pPor->Height(); 1086 nPorAscent = pPor->GetAscent(); 1087 } 1088 SwTwips nTmp; 1089 if( 2 > pPor->GetLen() ) 1090 { 1091 nTmp = pPor->Width(); 1092 if ( pPor->InSpaceGrp() && nSpaceAdd ) 1093 nTmp += pPor->CalcSpacing( nSpaceAdd, aInf ); 1094 } 1095 else 1096 { 1097 const sal_Bool bOldOnWin = aInf.OnWin(); 1098 xub_StrLen nOldLen = pPor->GetLen(); 1099 pPor->SetLen( 1 ); 1100 aInf.SetLen( pPor->GetLen() ); 1101 SeekAndChg( aInf ); 1102 aInf.SetOnWin( sal_False ); // keine BULLETs! 1103 aInf.SetKanaComp( pKanaComp ); 1104 aInf.SetKanaIdx( nKanaIdx ); 1105 nTmp = pPor->GetTxtSize( aInf ).Width(); 1106 aInf.SetOnWin( bOldOnWin ); 1107 if ( pPor->InSpaceGrp() && nSpaceAdd ) 1108 nTmp += pPor->CalcSpacing( nSpaceAdd, aInf ); 1109 pPor->SetLen( nOldLen ); 1110 } 1111 pOrig->Width( nTmp ); 1112 } 1113 1114 // travel inside field portion? 1115 if ( pCMS->pSpecialPos ) 1116 { 1117 // apply attributes to font 1118 Seek( nOfst ); 1119 lcl_GetCharRectInsideField( aInf, *pOrig, *pCMS, *pPor ); 1120 } 1121 } 1122 } 1123 1124 // special case: We are at the beginning of a BidiPortion or 1125 // directly behind a BidiPortion 1126 if ( pCMS && 1127 ( pLastBidiPor || 1128 ( pPor && 1129 pPor->IsMultiPortion() && 1130 ((SwMultiPortion*)pPor)->IsBidi() ) ) ) 1131 { 1132 // we determine if the cursor has to blink before or behind 1133 // the bidi portion 1134 if ( pLastBidiPor ) 1135 { 1136 const sal_uInt8 nPortionLevel = pLastBidiPor->GetLevel(); 1137 1138 if ( pCMS->nCursorBidiLevel >= nPortionLevel ) 1139 { 1140 // we came from inside the bidi portion, we want to blink 1141 // behind the portion 1142 pOrig->Pos().X() -= nLastBidiPorWidth; 1143 1144 // Again, there is a special case: logically behind 1145 // the portion can actually mean that the cursor is inside 1146 // the portion. This can happen is the last portion 1147 // inside the bidi portion is a nested bidi portion 1148 SwLineLayout& rLineLayout = 1149 ((SwMultiPortion*)pLastBidiPor)->GetRoot(); 1150 1151 const SwLinePortion *pLast = rLineLayout.FindLastPortion(); 1152 if ( pLast->IsMultiPortion() ) 1153 { 1154 ASSERT( ((SwMultiPortion*)pLast)->IsBidi(), 1155 "Non-BidiPortion inside BidiPortion" ) 1156 pOrig->Pos().X() += pLast->Width() + 1157 pLast->CalcSpacing( nSpaceAdd, aInf ); 1158 } 1159 } 1160 } 1161 else 1162 { 1163 const sal_uInt8 nPortionLevel = ((SwBidiPortion*)pPor)->GetLevel(); 1164 1165 if ( pCMS->nCursorBidiLevel >= nPortionLevel ) 1166 { 1167 // we came from inside the bidi portion, we want to blink 1168 // behind the portion 1169 pOrig->Pos().X() += pPor->Width() + 1170 pPor->CalcSpacing( nSpaceAdd, aInf ); 1171 } 1172 } 1173 } 1174 1175 pOrig->Pos().X() += nX; 1176 1177 if ( pCMS && pCMS->bRealHeight ) 1178 { 1179 nTmpAscent = AdjustBaseLine( *pCurr, 0, nPorHeight, nPorAscent ); 1180 if ( nTmpAscent > nPorAscent ) 1181 pCMS->aRealHeight.X() = nTmpAscent - nPorAscent; 1182 else 1183 pCMS->aRealHeight.X() = 0; 1184 ASSERT( nPorHeight, "GetCharRect: Missing Portion-Height" ); 1185 if ( nTmpHeight > nPorHeight ) 1186 pCMS->aRealHeight.Y() = nPorHeight; 1187 else 1188 pCMS->aRealHeight.Y() = nTmpHeight; 1189 } 1190 } 1191 } 1192 1193 /************************************************************************* 1194 * SwTxtCursor::GetCharRect() 1195 *************************************************************************/ 1196 1197 sal_Bool SwTxtCursor::GetCharRect( SwRect* pOrig, const xub_StrLen nOfst, 1198 SwCrsrMoveState* pCMS, const long nMax ) 1199 { 1200 CharCrsrToLine(nOfst); 1201 1202 // Indicates that a position inside a special portion (field, number portion) 1203 // is requested. 1204 const sal_Bool bSpecialPos = pCMS && pCMS->pSpecialPos; 1205 xub_StrLen nFindOfst = nOfst; 1206 1207 if ( bSpecialPos ) 1208 { 1209 const sal_uInt8 nExtendRange = pCMS->pSpecialPos->nExtendRange; 1210 1211 ASSERT( ! pCMS->pSpecialPos->nLineOfst || SP_EXTEND_RANGE_BEFORE != nExtendRange, 1212 "LineOffset AND Number Portion?" ) 1213 1214 // portions which are behind the string 1215 if ( SP_EXTEND_RANGE_BEHIND == nExtendRange ) 1216 ++nFindOfst; 1217 1218 // skip lines for fields which cover more than one line 1219 for ( sal_uInt16 i = 0; i < pCMS->pSpecialPos->nLineOfst; i++ ) 1220 Next(); 1221 } 1222 1223 // Adjustierung ggf. nachholen 1224 GetAdjusted(); 1225 1226 const Point aCharPos( GetTopLeft() ); 1227 sal_Bool bRet = sal_True; 1228 1229 _GetCharRect( pOrig, nFindOfst, pCMS ); 1230 1231 const SwTwips nTmpRight = Right() - 12; 1232 1233 pOrig->Pos().X() += aCharPos.X(); 1234 pOrig->Pos().Y() += aCharPos.Y(); 1235 1236 if( pCMS && pCMS->b2Lines && pCMS->p2Lines ) 1237 { 1238 pCMS->p2Lines->aLine.Pos().X() += aCharPos.X(); 1239 pCMS->p2Lines->aLine.Pos().Y() += aCharPos.Y(); 1240 pCMS->p2Lines->aPortion.Pos().X() += aCharPos.X(); 1241 pCMS->p2Lines->aPortion.Pos().Y() += aCharPos.Y(); 1242 } 1243 1244 if( pOrig->Left() > nTmpRight ) 1245 pOrig->Pos().X() = nTmpRight; 1246 1247 if( nMax ) 1248 { 1249 if( pOrig->Top() + pOrig->Height() > nMax ) 1250 { 1251 if( pOrig->Top() > nMax ) 1252 pOrig->Top( nMax ); 1253 pOrig->Height( nMax - pOrig->Top() ); 1254 } 1255 if ( pCMS && pCMS->bRealHeight && pCMS->aRealHeight.Y() >= 0 ) 1256 { 1257 long nTmp = pCMS->aRealHeight.X() + pOrig->Top(); 1258 if( nTmp >= nMax ) 1259 { 1260 pCMS->aRealHeight.X() = nMax - pOrig->Top(); 1261 pCMS->aRealHeight.Y() = 0; 1262 } 1263 else if( nTmp + pCMS->aRealHeight.Y() > nMax ) 1264 pCMS->aRealHeight.Y() = nMax - nTmp; 1265 } 1266 } 1267 long nOut = pOrig->Right() - GetTxtFrm()->Frm().Right(); 1268 if( nOut > 0 ) 1269 { 1270 if( GetTxtFrm()->Frm().Width() < GetTxtFrm()->Prt().Left() 1271 + GetTxtFrm()->Prt().Width() ) 1272 nOut += GetTxtFrm()->Frm().Width() - GetTxtFrm()->Prt().Left() 1273 - GetTxtFrm()->Prt().Width(); 1274 if( nOut > 0 ) 1275 pOrig->Pos().X() -= nOut + 10; 1276 } 1277 return bRet; 1278 } 1279 1280 /************************************************************************* 1281 * SwTxtCursor::GetCrsrOfst() 1282 * 1283 * Return: Offset im String 1284 *************************************************************************/ 1285 xub_StrLen SwTxtCursor::GetCrsrOfst( SwPosition *pPos, const Point &rPoint, 1286 const MSHORT nChgNode, SwCrsrMoveState* pCMS ) const 1287 { 1288 // Adjustierung ggf. nachholen 1289 GetAdjusted(); 1290 1291 const XubString &rText = GetInfo().GetTxt(); 1292 xub_StrLen nOffset = 0; 1293 1294 // x ist der horizontale Offset innerhalb der Zeile. 1295 SwTwips x = rPoint.X(); 1296 CONST SwTwips nLeftMargin = GetLineStart(); 1297 SwTwips nRightMargin = GetLineEnd(); 1298 if( nRightMargin == nLeftMargin ) 1299 nRightMargin += 30; 1300 1301 const sal_Bool bLeftOver = x < nLeftMargin; 1302 if( bLeftOver ) 1303 x = nLeftMargin; 1304 const sal_Bool bRightOver = x > nRightMargin; 1305 if( bRightOver ) 1306 x = nRightMargin; 1307 1308 sal_Bool bRightAllowed = pCMS && ( pCMS->eState == MV_NONE ); 1309 1310 // Bis hierher in Dokumentkoordinaten. 1311 x -= nLeftMargin; 1312 1313 KSHORT nX = KSHORT( x ); 1314 1315 // Wenn es in der Zeile Attributwechsel gibt, den Abschnitt 1316 // suchen, in dem nX liegt. 1317 SwLinePortion *pPor = pCurr->GetFirstPortion(); 1318 xub_StrLen nCurrStart = nStart; 1319 sal_Bool bHolePortion = sal_False; 1320 sal_Bool bLastHyph = sal_False; 1321 1322 SvUShorts *pKanaComp = pCurr->GetpKanaComp(); 1323 xub_StrLen nOldIdx = GetInfo().GetIdx(); 1324 MSHORT nSpaceIdx = 0; 1325 MSHORT nKanaIdx = 0; 1326 long nSpaceAdd = pCurr->IsSpaceAdd() ? pCurr->GetLLSpaceAdd( 0 ) : 0; 1327 short nKanaComp = pKanaComp ? (*pKanaComp)[0] : 0; 1328 1329 // nWidth ist die Breite der Zeile, oder die Breite des 1330 // Abschnitts mit dem Fontwechsel, in dem nX liegt. 1331 1332 KSHORT nWidth = pPor->Width(); 1333 if ( pCurr->IsSpaceAdd() || pKanaComp ) 1334 { 1335 if ( pPor->InSpaceGrp() && nSpaceAdd ) 1336 { 1337 ((SwTxtSizeInfo&)GetInfo()).SetIdx( nCurrStart ); 1338 nWidth = nWidth + sal_uInt16( pPor->CalcSpacing( nSpaceAdd, GetInfo() ) ); 1339 } 1340 if( ( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() ) || 1341 ( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->HasTabulator() ) 1342 ) 1343 { 1344 if ( pCurr->IsSpaceAdd() ) 1345 { 1346 if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() ) 1347 nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx ); 1348 else 1349 nSpaceAdd = 0; 1350 } 1351 1352 if( pKanaComp ) 1353 { 1354 if ( nKanaIdx + 1 < pKanaComp->Count() ) 1355 nKanaComp = (*pKanaComp)[++nKanaIdx]; 1356 else 1357 nKanaComp = 0; 1358 } 1359 } 1360 } 1361 1362 KSHORT nWidth30; 1363 if ( pPor->IsPostItsPortion() ) 1364 nWidth30 = 30 + pPor->GetViewWidth( GetInfo() ) / 2; 1365 else 1366 nWidth30 = ! nWidth && pPor->GetLen() && pPor->InToxRefOrFldGrp() ? 1367 30 : 1368 nWidth; 1369 1370 while( pPor->GetPortion() && nWidth30 < nX && !pPor->IsBreakPortion() ) 1371 { 1372 nX = nX - nWidth; 1373 nCurrStart = nCurrStart + pPor->GetLen(); 1374 bHolePortion = pPor->IsHolePortion(); 1375 pPor = pPor->GetPortion(); 1376 nWidth = pPor->Width(); 1377 if ( pCurr->IsSpaceAdd() || pKanaComp ) 1378 { 1379 if ( pPor->InSpaceGrp() && nSpaceAdd ) 1380 { 1381 ((SwTxtSizeInfo&)GetInfo()).SetIdx( nCurrStart ); 1382 nWidth = nWidth + sal_uInt16( pPor->CalcSpacing( nSpaceAdd, GetInfo() ) ); 1383 } 1384 1385 if( ( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() ) || 1386 ( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->HasTabulator() ) 1387 ) 1388 { 1389 if ( pCurr->IsSpaceAdd() ) 1390 { 1391 if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() ) 1392 nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx ); 1393 else 1394 nSpaceAdd = 0; 1395 } 1396 1397 if ( pKanaComp ) 1398 { 1399 if( nKanaIdx + 1 < pKanaComp->Count() ) 1400 nKanaComp = (*pKanaComp)[++nKanaIdx]; 1401 else 1402 nKanaComp = 0; 1403 } 1404 } 1405 } 1406 1407 if ( pPor->IsPostItsPortion() ) 1408 nWidth30 = 30 + pPor->GetViewWidth( GetInfo() ) / 2; 1409 else 1410 nWidth30 = ! nWidth && pPor->GetLen() && pPor->InToxRefOrFldGrp() ? 1411 30 : 1412 nWidth; 1413 if( !pPor->IsFlyPortion() && !pPor->IsMarginPortion() ) 1414 bLastHyph = pPor->InHyphGrp(); 1415 } 1416 1417 const sal_Bool bLastPortion = (0 == pPor->GetPortion()); 1418 1419 if( nX==nWidth ) 1420 { 1421 SwLinePortion *pNextPor = pPor->GetPortion(); 1422 while( pNextPor && pNextPor->InFldGrp() && !pNextPor->Width() ) 1423 { 1424 nCurrStart = nCurrStart + pPor->GetLen(); 1425 pPor = pNextPor; 1426 if( !pPor->IsFlyPortion() && !pPor->IsMarginPortion() ) 1427 bLastHyph = pPor->InHyphGrp(); 1428 pNextPor = pPor->GetPortion(); 1429 } 1430 } 1431 1432 ((SwTxtSizeInfo&)GetInfo()).SetIdx( nOldIdx ); 1433 1434 xub_StrLen nLength = pPor->GetLen(); 1435 1436 sal_Bool bFieldInfo = pCMS && pCMS->bFieldInfo; 1437 1438 if( bFieldInfo && ( nWidth30 < nX || bRightOver || bLeftOver || 1439 ( pPor->InNumberGrp() && !pPor->IsFtnNumPortion() ) || 1440 ( pPor->IsMarginPortion() && nWidth > nX + 30 ) ) ) 1441 ((SwCrsrMoveState*)pCMS)->bPosCorr = sal_True; 1442 1443 1444 // #i27615# 1445 if (pCMS) 1446 { 1447 if( pCMS->bInFrontOfLabel) 1448 { 1449 if (! (2 * nX < nWidth && pPor->InNumberGrp() && 1450 !pPor->IsFtnNumPortion())) 1451 pCMS->bInFrontOfLabel = sal_False; 1452 } 1453 } 1454 1455 // 7684: Wir sind genau auf der HyphPortion angelangt und muessen dafuer 1456 // sorgen, dass wir in dem String landen. 1457 // 7993: Wenn die Laenge 0 ist muessen wir raus... 1458 if( !nLength ) 1459 { 1460 if( pCMS ) 1461 { 1462 if( pPor->IsFlyPortion() && bFieldInfo ) 1463 ((SwCrsrMoveState*)pCMS)->bPosCorr = sal_True; 1464 1465 if (!bRightOver && nX) 1466 { 1467 if( pPor->IsFtnNumPortion()) 1468 ((SwCrsrMoveState*)pCMS)->bFtnNoInfo = sal_True; 1469 else if (pPor->InNumberGrp() ) // #i23726# 1470 { 1471 ((SwCrsrMoveState*)pCMS)->nInNumPostionOffset = nX; 1472 ((SwCrsrMoveState*)pCMS)->bInNumPortion = sal_True; 1473 } 1474 } 1475 } 1476 if( !nCurrStart ) 1477 return 0; 1478 1479 // 7849, 7816: auf pPor->GetHyphPortion kann nicht verzichtet werden! 1480 if( bHolePortion || ( !bRightAllowed && bLastHyph ) || 1481 ( pPor->IsMarginPortion() && !pPor->GetPortion() && 1482 // 46598: In der letzten Zeile eines zentrierten Absatzes wollen 1483 // wir auch mal hinter dem letzten Zeichen landen. 1484 nCurrStart < rText.Len() ) ) 1485 --nCurrStart; 1486 else if( pPor->InFldGrp() && ((SwFldPortion*)pPor)->IsFollow() 1487 && nWidth > nX ) 1488 { 1489 if( bFieldInfo ) 1490 --nCurrStart; 1491 else 1492 { 1493 KSHORT nHeight = pPor->Height(); 1494 if ( !nHeight || nHeight > nWidth ) 1495 nHeight = nWidth; 1496 if( nChgNode && nWidth - nHeight/2 > nX ) 1497 --nCurrStart; 1498 } 1499 } 1500 return nCurrStart; 1501 } 1502 if ( 1 == nLength ) 1503 { 1504 if ( nWidth ) 1505 { 1506 // Sonst kommen wir nicht mehr in zeichengeb. Rahmen hinein... 1507 if( !( nChgNode && pPos && pPor->IsFlyCntPortion() ) ) 1508 { 1509 if ( pPor->InFldGrp() || 1510 ( pPor->IsMultiPortion() && 1511 ((SwMultiPortion*)pPor)->IsBidi() ) ) 1512 { 1513 KSHORT nHeight = 0; 1514 if( !bFieldInfo ) 1515 { 1516 nHeight = pPor->Height(); 1517 if ( !nHeight || nHeight > nWidth ) 1518 nHeight = nWidth; 1519 } 1520 1521 if( nWidth - nHeight/2 <= nX && 1522 ( ! pPor->InFldGrp() || 1523 !((SwFldPortion*)pPor)->HasFollow() ) ) 1524 ++nCurrStart; 1525 } 1526 else if ( ( !pPor->IsFlyPortion() || ( pPor->GetPortion() && 1527 !pPor->GetPortion()->IsMarginPortion() && 1528 !pPor->GetPortion()->IsHolePortion() ) ) 1529 && ( nWidth/2 < nX ) && 1530 ( !bFieldInfo || 1531 ( pPor->GetPortion() && 1532 pPor->GetPortion()->IsPostItsPortion() ) ) 1533 && ( bRightAllowed || !bLastHyph )) 1534 ++nCurrStart; 1535 1536 // if we want to get the position inside the field, we should not return 1537 if ( !pCMS || !pCMS->pSpecialPos ) 1538 return nCurrStart; 1539 } 1540 } 1541 else 1542 { 1543 if ( pPor->IsPostItsPortion() || pPor->IsBreakPortion() || 1544 pPor->InToxRefGrp() ) 1545 return nCurrStart; 1546 if ( pPor->InFldGrp() ) 1547 { 1548 if( bRightOver && !((SwFldPortion*)pPor)->HasFollow() ) 1549 ++nCurrStart; 1550 return nCurrStart; 1551 } 1552 } 1553 } 1554 1555 if( bLastPortion && (pCurr->GetNext() || pFrm->GetFollow() ) ) 1556 --nLength; 1557 1558 if( nWidth > nX || 1559 ( nWidth == nX && pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsDouble() ) ) 1560 { 1561 if( pPor->IsMultiPortion() ) 1562 { 1563 // In a multi-portion we use GetCrsrOfst()-function recursively 1564 SwTwips nTmpY = rPoint.Y() - pCurr->GetAscent() + pPor->GetAscent(); 1565 // if we are in the first line of a double line portion, we have 1566 // to add a value to nTmpY for not staying in this line 1567 // we also want to skip the first line, if we are inside ruby 1568 if ( ( ((SwTxtSizeInfo*)pInf)->IsMulti() && 1569 ((SwTxtSizeInfo*)pInf)->IsFirstMulti() ) || 1570 ( ((SwMultiPortion*)pPor)->IsRuby() && 1571 ((SwMultiPortion*)pPor)->OnTop() ) ) 1572 nTmpY += ((SwMultiPortion*)pPor)->Height(); 1573 1574 // Important for cursor traveling in ruby portions: 1575 // We have to set nTmpY to 0 in order to stay in the first row 1576 // if the phonetic line is the second row 1577 if ( ((SwMultiPortion*)pPor)->IsRuby() && 1578 ! ((SwMultiPortion*)pPor)->OnTop() ) 1579 nTmpY = 0; 1580 1581 SwTxtCursorSave aSave( (SwTxtCursor*)this, (SwMultiPortion*)pPor, 1582 nTmpY, nX, nCurrStart, nSpaceAdd ); 1583 1584 SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() ); 1585 if ( ((SwMultiPortion*)pPor)->IsBidi() ) 1586 { 1587 const sal_uInt8 nBidiLevel = ((SwBidiPortion*)pPor)->GetLevel(); 1588 aLayoutModeModifier.Modify( nBidiLevel % 2 ); 1589 } 1590 1591 if( ((SwMultiPortion*)pPor)->HasRotation() ) 1592 { 1593 nTmpY -= nY; 1594 if( !((SwMultiPortion*)pPor)->IsRevers() ) 1595 nTmpY = pPor->Height() - nTmpY; 1596 if( nTmpY < 0 ) 1597 nTmpY = 0; 1598 nX = (KSHORT)nTmpY; 1599 } 1600 1601 if( ((SwMultiPortion*)pPor)->HasBrackets() ) 1602 { 1603 sal_uInt16 nPreWidth = ((SwDoubleLinePortion*)pPor)->PreWidth(); 1604 if ( nX > nPreWidth ) 1605 nX = nX - nPreWidth; 1606 else 1607 nX = 0; 1608 } 1609 1610 return GetCrsrOfst( pPos, Point( GetLineStart() + nX, rPoint.Y() ), 1611 nChgNode, pCMS ); 1612 } 1613 if( pPor->InTxtGrp() ) 1614 { 1615 sal_uInt8 nOldProp; 1616 if( GetPropFont() ) 1617 { 1618 ((SwFont*)GetFnt())->SetProportion( GetPropFont() ); 1619 nOldProp = GetFnt()->GetPropr(); 1620 } 1621 else 1622 nOldProp = 0; 1623 { 1624 SwTxtSizeInfo aSizeInf( GetInfo(), rText, nCurrStart ); 1625 ((SwTxtCursor*)this)->SeekAndChg( aSizeInf ); 1626 SwTxtSlot aDiffTxt( &aSizeInf, ((SwTxtPortion*)pPor), false, false ); 1627 SwFontSave aSave( aSizeInf, pPor->IsDropPortion() ? 1628 ((SwDropPortion*)pPor)->GetFnt() : NULL ); 1629 1630 SwParaPortion* pPara = (SwParaPortion*)GetInfo().GetParaPortion(); 1631 ASSERT( pPara, "No paragraph!" ); 1632 1633 SwDrawTextInfo aDrawInf( aSizeInf.GetVsh(), 1634 *aSizeInf.GetOut(), 1635 &pPara->GetScriptInfo(), 1636 aSizeInf.GetTxt(), 1637 aSizeInf.GetIdx(), 1638 pPor->GetLen() ); 1639 aDrawInf.SetOfst( nX ); 1640 1641 if ( nSpaceAdd ) 1642 { 1643 xub_StrLen nCharCnt; 1644 // --> FME 2005-04-04 #i41860# Thai justified alignemt needs some 1645 // additional information: 1646 aDrawInf.SetNumberOfBlanks( pPor->InTxtGrp() ? 1647 static_cast<const SwTxtPortion*>(pPor)->GetSpaceCnt( aSizeInf, nCharCnt ) : 1648 0 ); 1649 // <-- 1650 } 1651 1652 if ( pPor->InFldGrp() && pCMS && pCMS->pSpecialPos ) 1653 aDrawInf.SetLen( STRING_LEN ); // SMARTTAGS 1654 1655 aDrawInf.SetSpace( nSpaceAdd ); 1656 aDrawInf.SetFont( aSizeInf.GetFont() ); 1657 aDrawInf.SetFrm( pFrm ); 1658 aDrawInf.SetSnapToGrid( aSizeInf.SnapToGrid() ); 1659 aDrawInf.SetPosMatchesBounds( pCMS && pCMS->bPosMatchesBounds ); 1660 1661 if ( SW_CJK == aSizeInf.GetFont()->GetActual() && 1662 pPara->GetScriptInfo().CountCompChg() && 1663 ! pPor->InFldGrp() ) 1664 aDrawInf.SetKanaComp( nKanaComp ); 1665 1666 nLength = aSizeInf.GetFont()->_GetCrsrOfst( aDrawInf ); 1667 1668 // get position inside field portion? 1669 if ( pPor->InFldGrp() && pCMS && pCMS->pSpecialPos ) 1670 { 1671 pCMS->pSpecialPos->nCharOfst = nLength; 1672 nLength = 0; // SMARTTAGS 1673 } 1674 1675 // set cursor bidi level 1676 if ( pCMS ) 1677 ((SwCrsrMoveState*)pCMS)->nCursorBidiLevel = 1678 aDrawInf.GetCursorBidiLevel(); 1679 1680 if( bFieldInfo && nLength == pPor->GetLen() && 1681 ( ! pPor->GetPortion() || 1682 ! pPor->GetPortion()->IsPostItsPortion() ) ) 1683 --nLength; 1684 } 1685 if( nOldProp ) 1686 ((SwFont*)GetFnt())->SetProportion( nOldProp ); 1687 } 1688 else 1689 { 1690 if( nChgNode && pPos && pPor->IsFlyCntPortion() 1691 && !( (SwFlyCntPortion*)pPor )->IsDraw() ) 1692 { 1693 // JP 24.11.94: liegt die Pos nicht im Fly, dann 1694 // darf nicht mit STRING_LEN returnt werden! 1695 // (BugId: 9692 + Aenderung in feshview) 1696 SwFlyInCntFrm *pTmp = ( (SwFlyCntPortion*)pPor )->GetFlyFrm(); 1697 sal_Bool bChgNode = 1 < nChgNode; 1698 if( !bChgNode ) 1699 { 1700 SwFrm* pLower = pTmp->GetLower(); 1701 if( pLower && (pLower->IsTxtFrm() || pLower->IsLayoutFrm()) ) 1702 bChgNode = sal_True; 1703 } 1704 Point aTmpPoint( rPoint ); 1705 1706 if ( pFrm->IsRightToLeft() ) 1707 pFrm->SwitchLTRtoRTL( aTmpPoint ); 1708 1709 if ( pFrm->IsVertical() ) 1710 pFrm->SwitchHorizontalToVertical( aTmpPoint ); 1711 1712 if( bChgNode && pTmp->Frm().IsInside( aTmpPoint ) && 1713 !( pTmp->IsProtected() ) ) 1714 { 1715 nLength = ((SwFlyCntPortion*)pPor)-> 1716 GetFlyCrsrOfst( nX, aTmpPoint, pPos, pCMS ); 1717 // Sobald der Frame gewechselt wird, muessen wir aufpassen, dass 1718 // unser Font wieder im OutputDevice steht. 1719 // vgl. Paint und new SwFlyCntPortion ! 1720 ((SwTxtSizeInfo*)pInf)->SelectFont(); 1721 1722 // 6776: Das pIter->GetCrsrOfst returnt 1723 // aus einer Verschachtelung mit STRING_LEN. 1724 return STRING_LEN; 1725 } 1726 } 1727 else 1728 nLength = pPor->GetCrsrOfst( nX ); 1729 } 1730 } 1731 nOffset = nCurrStart + nLength; 1732 1733 // 7684: Wir sind vor der HyphPortion angelangt und muessen dafuer 1734 // sorgen, dass wir in dem String landen. 1735 // Bei Zeilenenden vor FlyFrms muessen ebenso behandelt werden. 1736 1737 if( nOffset && pPor->GetLen() == nLength && pPor->GetPortion() && 1738 !pPor->GetPortion()->GetLen() && pPor->GetPortion()->InHyphGrp() ) 1739 --nOffset; 1740 1741 return nOffset; 1742 } 1743 1744 /** Looks for text portions which are inside the given rectangle 1745 1746 For a rectangular text selection every text portions which is inside the given 1747 rectangle has to be put into the SwSelectionList as SwPaM 1748 From these SwPaM the SwCursors will be created. 1749 1750 @param rSelList 1751 The container for the overlapped text portions 1752 1753 @param rRect 1754 A rectangle in document coordinates, text inside this rectangle has to be 1755 selected. 1756 1757 @return [ true, false ] 1758 true if any overlapping text portion has been found and put into list 1759 false if no portion overlaps, the list has been unchanged 1760 */ 1761 bool SwTxtFrm::FillSelection( SwSelectionList& rSelList, const SwRect& rRect ) const 1762 { 1763 bool bRet = false; 1764 // PaintArea() instead Frm() for negative indents 1765 SwRect aTmpFrm( PaintArea() ); 1766 if( !rRect.IsOver( aTmpFrm ) ) 1767 return false; 1768 if( rSelList.checkContext( this ) ) 1769 { 1770 SwRect aRect( aTmpFrm ); 1771 aRect.Intersection( rRect ); 1772 // rNode without const to create SwPaMs 1773 SwCntntNode &rNode = const_cast<SwCntntNode&>( *GetNode() ); 1774 SwNodeIndex aIdx( rNode ); 1775 SwPosition aPosL( aIdx, SwIndex( &rNode, 0 ) ); 1776 if( IsEmpty() ) 1777 { 1778 SwPaM *pPam = new SwPaM( aPosL, aPosL ); 1779 rSelList.insertPaM( pPam ); 1780 } 1781 else if( aRect.HasArea() ) 1782 { 1783 xub_StrLen nOld = STRING_LEN; 1784 SwPosition aPosR( aPosL ); 1785 Point aPoint; 1786 SwTxtInfo aInf( const_cast<SwTxtFrm*>(this) ); 1787 SwTxtIter aLine( const_cast<SwTxtFrm*>(this), &aInf ); 1788 // We have to care for top-to-bottom layout, where right becomes top etc. 1789 SWRECTFN( this ) 1790 SwTwips nTop = (aRect.*fnRect->fnGetTop)(); 1791 SwTwips nBottom = (aRect.*fnRect->fnGetBottom)(); 1792 SwTwips nLeft = (aRect.*fnRect->fnGetLeft)(); 1793 SwTwips nRight = (aRect.*fnRect->fnGetRight)(); 1794 SwTwips nY = aLine.Y(); // Top position of the first line 1795 SwTwips nLastY = nY; 1796 while( nY < nTop && aLine.Next() ) // line above rectangle 1797 { 1798 nLastY = nY; 1799 nY = aLine.Y(); 1800 } 1801 bool bLastLine = false; 1802 if( nY < nTop && !aLine.GetNext() ) 1803 { 1804 bLastLine = true; 1805 nY += aLine.GetLineHeight(); 1806 } 1807 do // check the lines for overlapping 1808 { 1809 if( nLastY < nTop ) // if the last line was above rectangle 1810 nLastY = nTop; 1811 if( nY > nBottom ) // if the current line leaves the rectangle 1812 nY = nBottom; 1813 if( nY >= nLastY ) // gotcha: overlapping 1814 { 1815 nLastY += nY; 1816 nLastY /= 2; 1817 if( bVert ) 1818 { 1819 aPoint.X() = nLastY; 1820 aPoint.Y() = nLeft; 1821 } 1822 else 1823 { 1824 aPoint.X() = nLeft; 1825 aPoint.Y() = nLastY; 1826 } 1827 // Looking for the position of the left border of the rectangle 1828 // in this text line 1829 SwCrsrMoveState aState( MV_UPDOWN ); 1830 if( GetCrsrOfst( &aPosL, aPoint, &aState ) ) 1831 { 1832 if( bVert ) 1833 { 1834 aPoint.X() = nLastY; 1835 aPoint.Y() = nRight; 1836 } 1837 else 1838 { 1839 aPoint.X() = nRight; 1840 aPoint.Y() = nLastY; 1841 } 1842 // If we get a right position and if the left position 1843 // is not the same like the left position of the line before 1844 // which cound happen e.g. for field portions or fly frames 1845 // a SwPaM will be inserted with these positions 1846 if( GetCrsrOfst( &aPosR, aPoint, &aState ) && 1847 nOld != aPosL.nContent.GetIndex() ) 1848 { 1849 SwPaM *pPam = new SwPaM( aPosL, aPosR ); 1850 rSelList.insertPaM( pPam ); 1851 nOld = aPosL.nContent.GetIndex(); 1852 } 1853 } 1854 } 1855 if( aLine.Next() ) 1856 { 1857 nLastY = nY; 1858 nY = aLine.Y(); 1859 } 1860 else if( !bLastLine ) 1861 { 1862 bLastLine = true; 1863 nLastY = nY; 1864 nY += aLine.GetLineHeight(); 1865 } 1866 else 1867 break; 1868 }while( nLastY < nBottom ); 1869 } 1870 } 1871 if( GetDrawObjs() ) 1872 { 1873 const SwSortedObjs &rObjs = *GetDrawObjs(); 1874 for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) 1875 { 1876 const SwAnchoredObject* pAnchoredObj = rObjs[i]; 1877 if( !pAnchoredObj->ISA(SwFlyFrm) ) 1878 continue; 1879 const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pAnchoredObj); 1880 if( pFly->IsFlyInCntFrm() && pFly->FillSelection( rSelList, rRect ) ) 1881 bRet = true; 1882 } 1883 } 1884 return bRet; 1885 } 1886 1887