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