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