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 *************************************************************************/
lcl_GetCharRectInsideField(SwTxtSizeInfo & rInf,SwRect & rOrig,const SwCrsrMoveState & rCMS,const SwLinePortion & rPor)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 {
AreListLevelIndentsApplicableAndLabelAlignmentActive(const SwTxtNode & rTxtNode)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 *************************************************************************/
CtorInitTxtMargin(SwTxtFrm * pNewFrm,SwTxtSizeInfo * pNewInf)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 *************************************************************************/
DropInit()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.
GetLineStart() const404 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 *************************************************************************/
CtorInitTxtCursor(SwTxtFrm * pNewFrm,SwTxtSizeInfo * pNewInf)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
GetEndCharRect(SwRect * pOrig,const xub_StrLen nOfst,SwCrsrMoveState * pCMS,const long nMax)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
_GetCharRect(SwRect * pOrig,const xub_StrLen nOfst,SwCrsrMoveState * pCMS)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
GetCharRect(SwRect * pOrig,const xub_StrLen nOfst,SwCrsrMoveState * pCMS,const long nMax)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 *************************************************************************/
GetCrsrOfst(SwPosition * pPos,const Point & rPoint,const MSHORT nChgNode,SwCrsrMoveState * pCMS) const1281 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 */
FillSelection(SwSelectionList & rSelList,const SwRect & rRect) const1757 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