1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "hintids.hxx"
27 #include "swselectionlist.hxx"
28 #include <sortedobjs.hxx>
29 #include <editeng/protitem.hxx>
30 #include <editeng/adjitem.hxx>
31 #include <editeng/lspcitem.hxx>
32 #include <editeng/lrspitem.hxx>
34 #include <pagedesc.hxx> // SwPageDesc
35 #include <tgrditem.hxx>
36 #include <IDocumentSettingAccess.hxx>
37 #include <pagefrm.hxx>
41 #include "flyfrms.hxx"
42 #include "porglue.hxx" // SwFlyCnt
43 #include "porfld.hxx" // SwFldPortion::IsFollow()
44 #include "porfly.hxx" // GetFlyCrsrOfst()
45 #include "pordrop.hxx"
46 #include "crstate.hxx" // SwCrsrMoveState
47 #include <pormulti.hxx> // SwMultiPortion
49 #include <numrule.hxx>
51 // Nicht reentrant !!!
52 // wird in GetCharRect gesetzt und im UnitUp/Down ausgewertet.
53 sal_Bool
SwTxtCursor::bRightMargin
= sal_False
;
56 /*************************************************************************
57 * lcl_GetCharRectInsideField
59 * After calculating the position of a character during GetCharRect
60 * this function allows to find the coordinates of a position (defined
61 * in pCMS->pSpecialPos) inside a special portion (e.g., a field)
62 *************************************************************************/
63 static void lcl_GetCharRectInsideField( SwTxtSizeInfo
& rInf
, SwRect
& rOrig
,
64 const SwCrsrMoveState
& rCMS
,
65 const SwLinePortion
& rPor
)
67 OSL_ENSURE( rCMS
.pSpecialPos
, "Information about special pos missing" );
69 if ( rPor
.InFldGrp() && ((SwFldPortion
&)rPor
).GetExp().Len() )
71 const sal_uInt16 nCharOfst
= rCMS
.pSpecialPos
->nCharOfst
;
72 sal_uInt16 nFldIdx
= 0;
73 sal_uInt16 nFldLen
= 0;
75 const XubString
* pString
= 0;
76 const SwLinePortion
* pPor
= &rPor
;
79 if ( pPor
->InFldGrp() )
81 pString
= &((SwFldPortion
*)pPor
)->GetExp();
82 nFldLen
= pString
->Len();
90 if ( ! pPor
->GetPortion() || nFldIdx
+ nFldLen
> nCharOfst
)
93 nFldIdx
= nFldIdx
+ nFldLen
;
94 rOrig
.Pos().X() += pPor
->Width();
95 pPor
= pPor
->GetPortion();
99 OSL_ENSURE( nCharOfst
>= nFldIdx
, "Request of position inside field failed" );
100 sal_uInt16 nLen
= nCharOfst
- nFldIdx
+ 1;
104 // get script for field portion
105 rInf
.GetFont()->SetActual( SwScriptInfo::WhichFont( 0, pString
, 0 ) );
107 xub_StrLen nOldLen
= pPor
->GetLen();
108 ((SwLinePortion
*)pPor
)->SetLen( nLen
- 1 );
109 const SwTwips nX1
= pPor
->GetLen() ?
110 pPor
->GetTxtSize( rInf
).Width() :
114 if ( rCMS
.bRealWidth
)
116 ((SwLinePortion
*)pPor
)->SetLen( nLen
);
117 nX2
= pPor
->GetTxtSize( rInf
).Width();
120 ((SwLinePortion
*)pPor
)->SetLen( nOldLen
);
122 rOrig
.Pos().X() += nX1
;
123 rOrig
.Width( ( nX2
> nX1
) ?
130 // special cases: no common fields, e.g., graphic number portion,
131 // FlyInCntPortions, Notes
132 rOrig
.Width( rCMS
.bRealWidth
&& rPor
.Width() ? rPor
.Width() : 1 );
138 bool AreListLevelIndentsApplicableAndLabelAlignmentActive( const SwTxtNode
& rTxtNode
)
142 if ( rTxtNode
.AreListLevelIndentsApplicable() )
144 const SwNumFmt
& rNumFmt
=
145 rTxtNode
.GetNumRule()->Get( static_cast<sal_uInt16
>(rTxtNode
.GetActualListLevel()) );
146 if ( rNumFmt
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT
)
154 } // end of anonymous namespace
156 /*************************************************************************
157 * SwTxtMargin::CtorInitTxtMargin()
158 *************************************************************************/
159 void SwTxtMargin::CtorInitTxtMargin( SwTxtFrm
*pNewFrm
, SwTxtSizeInfo
*pNewInf
)
161 CtorInitTxtIter( pNewFrm
, pNewInf
);
164 GetInfo().SetFont( GetFnt() );
165 const SwTxtNode
*pNode
= pFrm
->GetTxtNode();
167 const SvxLRSpaceItem
&rSpace
= pFrm
->GetTxtNode()->GetSwAttrSet().GetLRSpace();
170 const bool bListLevelIndentsApplicableAndLabelAlignmentActive(
171 AreListLevelIndentsApplicableAndLabelAlignmentActive( *(pFrm
->GetTxtNode()) ) );
174 // Carefully adjust the text formatting ranges.
176 // This whole area desperately needs some rework. There are
177 // quite a couple of values that need to be considered:
178 // 1. paragraph indent
179 // 2. paragraph first line indent
180 // 3. numbering indent
181 // 4. numbering spacing to text
182 // 5. paragraph border
183 // Note: These values have already been used during calculation
184 // of the printing area of the paragraph.
185 const int nLMWithNum
= pNode
->GetLeftMarginWithNum( sal_True
);
186 if ( pFrm
->IsRightToLeft() )
188 // this calculation is identical this the calculation for L2R layout - see below
189 nLeft
= pFrm
->Frm().Left() +
192 pNode
->GetLeftMarginWithNum( sal_False
) -
195 // rSpace.GetLeft() +
196 // rSpace.GetTxtLeft();
197 ( bListLevelIndentsApplicableAndLabelAlignmentActive
199 : ( rSpace
.GetLeft() - rSpace
.GetTxtLeft() ) );
205 if ( bListLevelIndentsApplicableAndLabelAlignmentActive
||
206 !pNode
->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING
) )
208 // this calculation is identical this the calculation for R2L layout - see above
209 nLeft
= pFrm
->Frm().Left() +
212 pNode
->GetLeftMarginWithNum( sal_False
) -
215 ( bListLevelIndentsApplicableAndLabelAlignmentActive
217 : ( rSpace
.GetLeft() - rSpace
.GetTxtLeft() ) );
221 nLeft
= pFrm
->Frm().Left() +
222 Max( long( rSpace
.GetTxtLeft() + nLMWithNum
),
223 pFrm
->Prt().Left() );
227 nRight
= pFrm
->Frm().Left() + pFrm
->Prt().Left() + pFrm
->Prt().Width();
229 if( nLeft
>= nRight
&&
230 // #i53066# Omit adjustment of nLeft for numbered
231 // paras inside cells inside new documents:
232 ( pNode
->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING
) ||
236 nLeft
= pFrm
->Prt().Left() + pFrm
->Frm().Left();
237 if( nLeft
>= nRight
) // z.B. bei grossen Absatzeinzuegen in schmalen Tabellenspalten
238 nRight
= nLeft
+ 1; // einen goennen wir uns immer
241 if( pFrm
->IsFollow() && pFrm
->GetOfst() )
246 long nFirstLineOfs
= 0;
247 if( !pNode
->GetFirstLineOfsWithNum( nFLOfst
) &&
248 rSpace
.IsAutoFirst() )
250 nFirstLineOfs
= GetFnt()->GetSize( GetFnt()->GetActual() ).Height();
251 const SvxLineSpacingItem
*pSpace
= aLineInf
.GetLineSpacing();
254 switch( pSpace
->GetLineSpaceRule() )
256 case SVX_LINE_SPACE_AUTO
:
258 case SVX_LINE_SPACE_MIN
:
260 if( nFirstLineOfs
< KSHORT( pSpace
->GetLineHeight() ) )
261 nFirstLineOfs
= pSpace
->GetLineHeight();
264 case SVX_LINE_SPACE_FIX
:
265 nFirstLineOfs
= pSpace
->GetLineHeight();
267 default: OSL_FAIL( ": unknown LineSpaceRule" );
269 switch( pSpace
->GetInterLineSpaceRule() )
271 case SVX_INTER_LINE_SPACE_OFF
:
273 case SVX_INTER_LINE_SPACE_PROP
:
275 long nTmp
= pSpace
->GetPropLineSpace();
276 // 50% ist das Minimum, bei 0% schalten wir auf
277 // den Defaultwert 100% um ...
279 nTmp
= nTmp
? 50 : 100;
281 nTmp
*= nFirstLineOfs
;
285 nFirstLineOfs
= (KSHORT
)nTmp
;
288 case SVX_INTER_LINE_SPACE_FIX
:
290 nFirstLineOfs
+= pSpace
->GetInterLineSpace();
293 default: OSL_FAIL( ": unknown InterLineSpaceRule" );
298 nFirstLineOfs
= nFLOfst
;
302 if ( pFrm
->IsRightToLeft() ||
303 bListLevelIndentsApplicableAndLabelAlignmentActive
||
304 !pNode
->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING
) )
306 nFirst
= nLeft
+ nFirstLineOfs
;
310 nFirst
= pFrm
->Frm().Left() +
311 Max( rSpace
.GetTxtLeft() + nLMWithNum
+ nFirstLineOfs
,
312 pFrm
->Prt().Left() );
315 // Note: <SwTxtFrm::GetAdditionalFirstLineOffset()> returns a negative
316 // value for the new list label postion and space mode LABEL_ALIGNMENT
317 // and label alignment CENTER and RIGHT in L2R layout respectively
318 // label alignment LEFT and CENTER in R2L layout
319 nFirst
+= pFrm
->GetAdditionalFirstLineOffset();
321 if( nFirst
>= nRight
)
324 const SvxAdjustItem
& rAdjust
= pFrm
->GetTxtNode()->GetSwAttrSet().GetAdjust();
325 nAdjust
= static_cast<sal_uInt16
>(rAdjust
.GetAdjust());
327 // left is left and right is right
328 if ( pFrm
->IsRightToLeft() )
330 if ( SVX_ADJUST_LEFT
== nAdjust
)
331 nAdjust
= SVX_ADJUST_RIGHT
;
332 else if ( SVX_ADJUST_RIGHT
== nAdjust
)
333 nAdjust
= SVX_ADJUST_LEFT
;
336 bOneBlock
= rAdjust
.GetOneWord() == SVX_ADJUST_BLOCK
;
337 bLastBlock
= rAdjust
.GetLastBlock() == SVX_ADJUST_BLOCK
;
338 bLastCenter
= rAdjust
.GetLastBlock() == SVX_ADJUST_CENTER
;
341 mnTabLeft
= pNode
->GetLeftMarginForTabCalculation();
343 #if OSL_DEBUG_LEVEL > 1
344 static sal_Bool bOne
= sal_False
;
345 static sal_Bool bLast
= sal_False
;
346 static sal_Bool bCenter
= sal_False
;
349 bLastCenter
|= bCenter
;
354 /*************************************************************************
355 * SwTxtMargin::DropInit()
356 *************************************************************************/
357 void SwTxtMargin::DropInit()
359 nDropLeft
= nDropLines
= nDropHeight
= nDropDescent
= 0;
360 const SwParaPortion
*pPara
= GetInfo().GetParaPortion();
363 const SwDropPortion
*pPorDrop
= pPara
->FindDropPortion();
366 nDropLeft
= pPorDrop
->GetDropLeft();
367 nDropLines
= pPorDrop
->GetLines();
368 nDropHeight
= pPorDrop
->GetDropHeight();
369 nDropDescent
= pPorDrop
->GetDropDescent();
374 /*************************************************************************
375 * SwTxtMargin::GetLineStart()
376 *************************************************************************/
378 // Unter Beruecksichtigung des Erstzeileneinzuges und der angebenen Breite.
379 SwTwips
SwTxtMargin::GetLineStart() const
381 SwTwips nRet
= GetLeftMargin();
382 if( GetAdjust() != SVX_ADJUST_LEFT
&&
383 !pCurr
->GetFirstPortion()->IsMarginPortion() )
385 // Wenn die erste Portion ein Margin ist, dann wird das
386 // Adjustment durch die Portions ausgedrueckt.
387 if( GetAdjust() == SVX_ADJUST_RIGHT
)
388 nRet
= Right() - CurrWidth();
389 else if( GetAdjust() == SVX_ADJUST_CENTER
)
390 nRet
+= (GetLineWidth() - CurrWidth()) / 2;
395 /*************************************************************************
396 * SwTxtCursor::CtorInitTxtCursor()
397 *************************************************************************/
398 void SwTxtCursor::CtorInitTxtCursor( SwTxtFrm
*pNewFrm
, SwTxtSizeInfo
*pNewInf
)
400 CtorInitTxtMargin( pNewFrm
, pNewInf
);
401 // 6096: Vorsicht, die Iteratoren sind abgeleitet!
402 // GetInfo().SetOut( GetInfo().GetWin() );
405 /*************************************************************************
406 * SwTxtCursor::GetEndCharRect()
407 *************************************************************************/
409 // 1170: Antikbug: Shift-Ende vergisst das letzte Zeichen ...
411 sal_Bool
SwTxtCursor::GetEndCharRect( SwRect
* pOrig
, const xub_StrLen nOfst
,
412 SwCrsrMoveState
* pCMS
, const long nMax
)
414 // 1170: Mehrdeutigkeit von Dokumentpositionen
415 bRightMargin
= sal_True
;
416 CharCrsrToLine(nOfst
);
418 // Etwas verdreht: nOfst bezeichnet die Position hinter dem letzten
419 // Zeichen der letzten Zeile == Position vor dem ersten Zeichen der
420 // Zeile in der wir gerade stehen:
421 if( nOfst
!= GetStart() || !pCurr
->GetLen() )
423 // 8810: Masterzeile RightMargin, danach LeftMargin
424 const sal_Bool bRet
= GetCharRect( pOrig
, nOfst
, pCMS
, nMax
);
425 bRightMargin
= nOfst
>= GetEnd() && nOfst
< GetInfo().GetTxt().Len();
429 if( !GetPrev() || !GetPrev()->GetLen() || !PrevLine() )
430 return GetCharRect( pOrig
, nOfst
, pCMS
, nMax
);
432 // Adjustierung ggf. nachholen
437 SwLinePortion
*pPor
= pCurr
->GetFirstPortion();
439 KSHORT nTmpHeight
, nTmpAscent
;
440 CalcAscentAndHeight( nTmpAscent
, nTmpHeight
);
441 KSHORT nPorHeight
= nTmpHeight
;
442 KSHORT nPorAscent
= nTmpAscent
;
444 // Die letzte Text/EndPortion der Zeile suchen
447 nX
= nX
+ pPor
->Width();
448 if( pPor
->InTxtGrp() || ( pPor
->GetLen() && !pPor
->IsFlyPortion()
449 && !pPor
->IsHolePortion() ) || pPor
->IsBreakPortion() )
452 nPorHeight
= pPor
->Height();
453 nPorAscent
= pPor
->GetAscent();
455 pPor
= pPor
->GetPortion();
458 const Size
aCharSize( 1, nTmpHeight
);
459 pOrig
->Pos( GetTopLeft() );
460 pOrig
->SSize( aCharSize
);
461 pOrig
->Pos().X() += nLast
;
462 const SwTwips nTmpRight
= Right() - 1;
463 if( pOrig
->Left() > nTmpRight
)
464 pOrig
->Pos().X() = nTmpRight
;
466 if ( pCMS
&& pCMS
->bRealHeight
)
468 if ( nTmpAscent
> nPorAscent
)
469 pCMS
->aRealHeight
.X() = nTmpAscent
- nPorAscent
;
471 pCMS
->aRealHeight
.X() = 0;
472 OSL_ENSURE( nPorHeight
, "GetCharRect: Missing Portion-Height" );
473 pCMS
->aRealHeight
.Y() = nPorHeight
;
479 /*************************************************************************
480 * void SwTxtCursor::_GetCharRect(..)
481 * internal function, called by SwTxtCursor::GetCharRect() to calculate
482 * the relative character position in the current line.
483 * pOrig referes to x and y coordinates, width and height of the cursor
484 * pCMS is used for restricting the cursor, if there are different font
485 * heights in one line ( first value = offset to y of pOrig, second
486 * value = real height of (shortened) cursor
487 *************************************************************************/
489 void SwTxtCursor::_GetCharRect( SwRect
* pOrig
, const xub_StrLen nOfst
,
490 SwCrsrMoveState
* pCMS
)
492 const XubString
&rText
= GetInfo().GetTxt();
493 SwTxtSizeInfo
aInf( GetInfo(), rText
, nStart
);
495 aInf
.GetFont()->SetProportion( GetPropFont() );
496 KSHORT nTmpAscent
, nTmpHeight
; // Zeilenhoehe
497 CalcAscentAndHeight( nTmpAscent
, nTmpHeight
);
498 const Size
aCharSize( 1, nTmpHeight
);
499 const Point aCharPos
;
500 pOrig
->Pos( aCharPos
);
501 pOrig
->SSize( aCharSize
);
503 // If we are looking for a position inside a field which covers
504 // more than one line we may not skip any "empty portions" at the
505 // beginning of a line
506 const sal_Bool bInsideFirstField
= pCMS
&& pCMS
->pSpecialPos
&&
507 ( pCMS
->pSpecialPos
->nLineOfst
||
508 SP_EXTEND_RANGE_BEFORE
==
509 pCMS
->pSpecialPos
->nExtendRange
);
511 sal_Bool bWidth
= pCMS
&& pCMS
->bRealWidth
;
512 if( !pCurr
->GetLen() && !pCurr
->Width() )
514 if ( pCMS
&& pCMS
->bRealHeight
)
516 pCMS
->aRealHeight
.X() = 0;
517 pCMS
->aRealHeight
.Y() = nTmpHeight
;
522 KSHORT nPorHeight
= nTmpHeight
;
523 KSHORT nPorAscent
= nTmpAscent
;
525 SwTwips nTmpFirst
= 0;
526 SwLinePortion
*pPor
= pCurr
->GetFirstPortion();
527 SwBidiPortion
* pLastBidiPor
= 0;
528 SwTwips nLastBidiPorWidth
= 0;
529 std::deque
<sal_uInt16
>* pKanaComp
= pCurr
->GetpKanaComp();
530 MSHORT nSpaceIdx
= 0;
532 long nSpaceAdd
= pCurr
->IsSpaceAdd() ? pCurr
->GetLLSpaceAdd( 0 ) : 0;
534 sal_Bool bNoTxt
= sal_True
;
536 // Zuerst werden alle Portions ohne Len am Zeilenanfang uebersprungen.
537 // Ausnahme bilden die fiesen Spezialportions aus WhichFirstPortion:
538 // Num, ErgoSum, FtnNum, FeldReste
539 // 8477: aber auch die einzige Textportion einer leeren Zeile mit
540 // Right/Center-Adjustment! Also nicht nur pPor->GetExpandPortion() ...
541 while( pPor
&& !pPor
->GetLen() && ! bInsideFirstField
)
544 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
545 nX
+= pPor
->CalcSpacing( nSpaceAdd
, aInf
);
548 // 8670: EndPortions zaehlen hier einmal als TxtPortions.
549 // if( pPor->InTxtGrp() || pPor->IsBreakPortion() )
550 if( pPor
->InTxtGrp() || pPor
->IsBreakPortion() || pPor
->InTabGrp() )
555 if( pPor
->IsMultiPortion() && ((SwMultiPortion
*)pPor
)->HasTabulator() )
557 if ( pCurr
->IsSpaceAdd() )
559 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
560 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
565 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->size() )
568 if( pPor
->InFixMargGrp() )
570 if( pPor
->IsMarginPortion() )
574 // fix margin portion => next SpaceAdd, KanaComp value
575 if ( pCurr
->IsSpaceAdd() )
577 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
578 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
583 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->size() )
587 pPor
= pPor
->GetPortion();
592 // Es sind nur Spezialportions unterwegs.
597 if( !pPor
->IsMarginPortion() && !pPor
->IsPostItsPortion() &&
598 (!pPor
->InFldGrp() || pPor
->GetAscent() ) )
600 nPorHeight
= pPor
->Height();
601 nPorAscent
= pPor
->GetAscent();
603 while( pPor
&& !pPor
->IsBreakPortion() && ( aInf
.GetIdx() < nOfst
||
604 ( bWidth
&& ( pPor
->IsKernPortion() || pPor
->IsMultiPortion() ) ) ) )
606 if( !pPor
->IsMarginPortion() && !pPor
->IsPostItsPortion() &&
607 (!pPor
->InFldGrp() || pPor
->GetAscent() ) )
609 nPorHeight
= pPor
->Height();
610 nPorAscent
= pPor
->GetAscent();
613 // If we are behind the portion, we add the portion width to
614 // nX. Special case: nOfst = aInf.GetIdx() + pPor->GetLen().
615 // For common portions (including BidiPortions) we want to add
616 // the portion width to nX. For MultiPortions, nExtra = 0,
617 // therefore we go to the 'else' branch and start a recursion.
618 const sal_uInt8 nExtra
= pPor
->IsMultiPortion() &&
619 ! ((SwMultiPortion
*)pPor
)->IsBidi() &&
621 if ( aInf
.GetIdx() + pPor
->GetLen() < nOfst
+ nExtra
)
623 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
624 nX
+= pPor
->PrtWidth() +
625 pPor
->CalcSpacing( nSpaceAdd
, aInf
);
628 if( pPor
->InFixMargGrp() && ! pPor
->IsMarginPortion() )
630 // update to current SpaceAdd, KanaComp values
631 if ( pCurr
->IsSpaceAdd() )
633 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
634 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
640 ( nKanaIdx
+ 1 ) < pKanaComp
->size()
644 if ( !pPor
->IsFlyPortion() || ( pPor
->GetPortion() &&
645 !pPor
->GetPortion()->IsMarginPortion() ) )
646 nX
+= pPor
->PrtWidth();
648 if( pPor
->IsMultiPortion() )
650 if ( ((SwMultiPortion
*)pPor
)->HasTabulator() )
652 if ( pCurr
->IsSpaceAdd() )
654 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
655 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
660 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->size() )
664 // if we are right behind a BidiPortion, we have to
665 // hold a pointer to the BidiPortion in order to
666 // find the correct cursor position, depending on the
668 if ( ((SwMultiPortion
*)pPor
)->IsBidi() &&
669 aInf
.GetIdx() + pPor
->GetLen() == nOfst
)
671 pLastBidiPor
= (SwBidiPortion
*)pPor
;
672 nLastBidiPorWidth
= pLastBidiPor
->Width() +
673 pLastBidiPor
->CalcSpacing( nSpaceAdd
, aInf
);;
677 aInf
.SetIdx( aInf
.GetIdx() + pPor
->GetLen() );
678 pPor
= pPor
->GetPortion();
682 if( pPor
->IsMultiPortion() )
684 nTmpAscent
= AdjustBaseLine( *pCurr
, pPor
);
685 GetInfo().SetMulti( sal_True
);
686 pOrig
->Pos().Y() += nTmpAscent
- nPorAscent
;
688 if( pCMS
&& pCMS
->b2Lines
)
690 sal_Bool bRecursion
= sal_True
;
691 if ( ! pCMS
->p2Lines
)
693 pCMS
->p2Lines
= new Sw2LinesPos
;
694 pCMS
->p2Lines
->aLine
= SwRect(aCharPos
, aCharSize
);
695 bRecursion
= sal_False
;
698 if( ((SwMultiPortion
*)pPor
)->HasRotation() )
700 if( ((SwMultiPortion
*)pPor
)->IsRevers() )
701 pCMS
->p2Lines
->nMultiType
= MT_ROT_270
;
703 pCMS
->p2Lines
->nMultiType
= MT_ROT_90
;
705 else if( ((SwMultiPortion
*)pPor
)->IsDouble() )
706 pCMS
->p2Lines
->nMultiType
= MT_TWOLINE
;
707 else if( ((SwMultiPortion
*)pPor
)->IsBidi() )
708 pCMS
->p2Lines
->nMultiType
= MT_BIDI
;
710 pCMS
->p2Lines
->nMultiType
= MT_RUBY
;
712 SwTwips nTmpWidth
= pPor
->Width();
714 nTmpWidth
+= pPor
->CalcSpacing(nSpaceAdd
, aInf
);
716 SwRect
aRect( Point(aCharPos
.X() + nX
, pOrig
->Top() ),
717 Size( nTmpWidth
, pPor
->Height() ) );
720 pCMS
->p2Lines
->aPortion
= aRect
;
722 pCMS
->p2Lines
->aPortion2
= aRect
;
725 // In a multi-portion we use GetCharRect()-function
726 // recursively and must add the x-position
727 // of the multi-portion.
728 xub_StrLen nOldStart
= nStart
;
730 sal_uInt8 nOldProp
= GetPropFont();
731 nStart
= aInf
.GetIdx();
732 SwLineLayout
* pOldCurr
= pCurr
;
733 pCurr
= &((SwMultiPortion
*)pPor
)->GetRoot();
734 if( ((SwMultiPortion
*)pPor
)->IsDouble() )
737 GETGRID( GetTxtFrm()->FindPageFrm() )
738 const sal_Bool bHasGrid
= pGrid
&& GetInfo().SnapToGrid();
739 const sal_uInt16 nRubyHeight
= bHasGrid
?
740 pGrid
->GetRubyHeight() : 0;
742 if( nStart
+ pCurr
->GetLen() <= nOfst
&& GetNext() &&
743 ( ! ((SwMultiPortion
*)pPor
)->IsRuby() ||
744 ((SwMultiPortion
*)pPor
)->OnTop() ) )
747 // in grid mode we may only add the height of the
748 // ruby line if ruby line is on top
750 ((SwMultiPortion
*)pPor
)->IsRuby() &&
751 ((SwMultiPortion
*)pPor
)->OnTop() )
752 nOffset
= nRubyHeight
;
754 nOffset
= GetLineHeight();
756 pOrig
->Pos().Y() += nOffset
;
760 sal_Bool bSpaceChg
= ((SwMultiPortion
*)pPor
)->
761 ChgSpaceAdd( pCurr
, nSpaceAdd
);
762 Point aOldPos
= pOrig
->Pos();
764 // Ok, for ruby portions in grid mode we have to
765 // temporarily set the inner line height to the
766 // outer line height because that value is needed
767 // for the adjustment inside the recursion
768 const sal_uInt16 nOldRubyHeight
= pCurr
->Height();
769 const sal_uInt16 nOldRubyRealHeight
= pCurr
->GetRealHeight();
770 const sal_Bool bChgHeight
=
771 ((SwMultiPortion
*)pPor
)->IsRuby() && bHasGrid
;
775 pCurr
->Height( pOldCurr
->Height() - nRubyHeight
);
776 pCurr
->SetRealHeight( pOldCurr
->GetRealHeight() -
780 SwLayoutModeModifier
aLayoutModeModifier( *GetInfo().GetOut() );
781 if ( ((SwMultiPortion
*)pPor
)->IsBidi() )
783 aLayoutModeModifier
.Modify(
784 ((SwBidiPortion
*)pPor
)->GetLevel() % 2 );
787 _GetCharRect( pOrig
, nOfst
, pCMS
);
791 pCurr
->Height( nOldRubyHeight
);
792 pCurr
->SetRealHeight( nOldRubyRealHeight
);
795 // if we are still in the first row of
796 // our 2 line multiportion, we use the FirstMulti flag
798 if ( ((SwMultiPortion
*)pPor
)->IsDouble() )
800 // the recursion may have damaged our font size
801 SetPropFont( nOldProp
);
804 GetInfo().GetFont()->SetProportion( 100 );
806 if ( pCurr
== &((SwMultiPortion
*)pPor
)->GetRoot() )
808 GetInfo().SetFirstMulti( sal_True
);
810 // we want to treat a double line portion like a
811 // single line portion, if there is no text in
813 if ( !pCurr
->GetNext() ||
814 !pCurr
->GetNext()->GetLen() )
815 GetInfo().SetMulti( sal_False
);
818 // ruby portions are treated like single line portions
819 else if( ((SwMultiPortion
*)pPor
)->IsRuby() ||
820 ((SwMultiPortion
*)pPor
)->IsBidi() )
821 GetInfo().SetMulti( sal_False
);
823 // calculate cursor values
824 if( ((SwMultiPortion
*)pPor
)->HasRotation() )
826 GetInfo().SetMulti( sal_False
);
827 long nTmp
= pOrig
->Width();
828 pOrig
->Width( pOrig
->Height() );
829 pOrig
->Height( nTmp
);
830 nTmp
= pOrig
->Left() - aOldPos
.X();
832 // if we travel into our rotated portion from
833 // a line below, we have to take care, that the
834 // y coord in pOrig is less than line height:
838 pOrig
->Pos().X() = nX
+ aOldPos
.X();
839 if( ((SwMultiPortion
*)pPor
)->IsRevers() )
840 pOrig
->Pos().Y() = aOldPos
.Y() + nTmp
;
842 pOrig
->Pos().Y() = aOldPos
.Y()
843 + pPor
->Height() - nTmp
- pOrig
->Height();
844 if ( pCMS
&& pCMS
->bRealHeight
)
846 pCMS
->aRealHeight
.Y() = -pCMS
->aRealHeight
.Y();
847 // result for rotated multi portion is not
848 // correct for reverse (270 degree) portions
849 if( ((SwMultiPortion
*)pPor
)->IsRevers() )
851 if ( SvxParaVertAlignItem::AUTOMATIC
==
852 GetLineInfo().GetVertAlign() )
853 // if vertical alignment is set to auto,
854 // we switch from base line alignment
855 // to centered alignment
856 pCMS
->aRealHeight
.X() =
858 pCMS
->aRealHeight
.Y() ) / 2;
860 pCMS
->aRealHeight
.X() =
862 pCMS
->aRealHeight
.X() +
863 pCMS
->aRealHeight
.Y() );
869 pOrig
->Pos().Y() += aOldPos
.Y();
870 if ( ((SwMultiPortion
*)pPor
)->IsBidi() )
872 const SwTwips nPorWidth
= pPor
->Width() +
873 pPor
->CalcSpacing( nSpaceAdd
, aInf
);
874 const SwTwips nInsideOfst
= pOrig
->Pos().X();
875 pOrig
->Pos().X() = nX
+ nPorWidth
-
876 nInsideOfst
- pOrig
->Width();
879 pOrig
->Pos().X() += nX
;
881 if( ((SwMultiPortion
*)pPor
)->HasBrackets() )
883 ((SwDoubleLinePortion
*)pPor
)->PreWidth();
887 SwDoubleLinePortion::ResetSpaceAdd( pCurr
);
896 if ( pPor
->PrtWidth() )
898 xub_StrLen nOldLen
= pPor
->GetLen();
899 pPor
->SetLen( nOfst
- aInf
.GetIdx() );
900 aInf
.SetLen( pPor
->GetLen() );
901 if( nX
|| !pPor
->InNumberGrp() )
904 const sal_Bool bOldOnWin
= aInf
.OnWin();
905 aInf
.SetOnWin( sal_False
); // keine BULLETs!
907 aInf
.SetKanaComp( pKanaComp
);
908 aInf
.SetKanaIdx( nKanaIdx
);
909 nX
+= pPor
->GetTxtSize( aInf
).Width();
910 aInf
.SetOnWin( bOldOnWin
);
911 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
912 nX
+= pPor
->CalcSpacing( nSpaceAdd
, aInf
);
915 pPor
->SetLen( pPor
->GetLen() + 1 );
916 aInf
.SetLen( pPor
->GetLen() );
917 aInf
.SetOnWin( sal_False
); // keine BULLETs!
918 nTmp
+= pPor
->GetTxtSize( aInf
).Width();
919 aInf
.SetOnWin( bOldOnWin
);
920 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
921 nTmp
+= pPor
->CalcSpacing(nSpaceAdd
, aInf
);
922 pOrig
->Width( nTmp
- nX
);
925 pPor
->SetLen( nOldLen
);
935 OSL_ENSURE( !pPor
->InNumberGrp() || bInsideFirstField
, "Number surprise" );
936 sal_Bool bEmptyFld
= sal_False
;
937 if( pPor
->InFldGrp() && pPor
->GetLen() )
939 SwFldPortion
*pTmp
= (SwFldPortion
*)pPor
;
940 while( pTmp
->HasFollow() && !pTmp
->GetExp().Len() )
942 KSHORT nAddX
= pTmp
->Width();
943 SwLinePortion
*pNext
= pTmp
->GetPortion();
944 while( pNext
&& !pNext
->InFldGrp() )
946 OSL_ENSURE( !pNext
->GetLen(), "Where's my field follow?" );
947 nAddX
= nAddX
+ pNext
->Width();
948 pNext
= pNext
->GetPortion();
952 pTmp
= (SwFldPortion
*)pNext
;
953 nPorHeight
= pTmp
->Height();
954 nPorAscent
= pTmp
->GetAscent();
956 bEmptyFld
= sal_True
;
959 // 8513: Felder im Blocksatz, ueberspringen
960 while( pPor
&& !pPor
->GetLen() && ! bInsideFirstField
&&
961 ( pPor
->IsFlyPortion() || pPor
->IsKernPortion() ||
962 pPor
->IsBlankPortion() || pPor
->InTabGrp() ||
963 ( !bEmptyFld
&& pPor
->InFldGrp() ) ) )
965 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
966 nX
+= pPor
->PrtWidth() +
967 pPor
->CalcSpacing( nSpaceAdd
, aInf
);
970 if( pPor
->InFixMargGrp() && ! pPor
->IsMarginPortion() )
972 if ( pCurr
->IsSpaceAdd() )
974 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
975 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
980 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->size() )
983 if ( !pPor
->IsFlyPortion() || ( pPor
->GetPortion() &&
984 !pPor
->GetPortion()->IsMarginPortion() ) )
985 nX
+= pPor
->PrtWidth();
987 if( pPor
->IsMultiPortion() &&
988 ((SwMultiPortion
*)pPor
)->HasTabulator() )
990 if ( pCurr
->IsSpaceAdd() )
992 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
993 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
998 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->size() )
1001 if( !pPor
->IsFlyPortion() )
1003 nPorHeight
= pPor
->Height();
1004 nPorAscent
= pPor
->GetAscent();
1006 pPor
= pPor
->GetPortion();
1009 if( aInf
.GetIdx() == nOfst
&& pPor
&& pPor
->InHyphGrp() &&
1010 pPor
->GetPortion() && pPor
->GetPortion()->InFixGrp() )
1012 // Alle Sonderportions muessen uebersprungen werden
1013 // Beispiel: zu-[FLY]sammen, 'u' == 19, 's' == 20; Right()
1014 // Ohne den Ausgleich landen wir vor '-' mit dem
1015 // Ausgleich vor 's'.
1016 while( pPor
&& !pPor
->GetLen() )
1018 nX
+= pPor
->Width();
1019 if( !pPor
->IsMarginPortion() )
1021 nPorHeight
= pPor
->Height();
1022 nPorAscent
= pPor
->GetAscent();
1024 pPor
= pPor
->GetPortion();
1029 if( pCMS
->bFieldInfo
&& pPor
->InFldGrp() && pPor
->Width() )
1030 pOrig
->Width( pPor
->Width() );
1031 if( pPor
->IsDropPortion() )
1033 nPorAscent
= ((SwDropPortion
*)pPor
)->GetDropHeight();
1034 // The drop height is only calculated, if we have more than
1035 // one line. Otherwise it is 0.
1037 nPorAscent
= pPor
->Height();
1038 nPorHeight
= nPorAscent
;
1039 pOrig
->Height( nPorHeight
+
1040 ((SwDropPortion
*)pPor
)->GetDropDescent() );
1041 if( nTmpHeight
< pOrig
->Height() )
1043 nTmpAscent
= nPorAscent
;
1044 nTmpHeight
= sal_uInt16( pOrig
->Height() );
1047 if( bWidth
&& pPor
->PrtWidth() && pPor
->GetLen() &&
1048 aInf
.GetIdx() == nOfst
)
1050 if( !pPor
->IsFlyPortion() && pPor
->Height() &&
1053 nPorHeight
= pPor
->Height();
1054 nPorAscent
= pPor
->GetAscent();
1057 if( 2 > pPor
->GetLen() )
1059 nTmp
= pPor
->Width();
1060 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
1061 nTmp
+= pPor
->CalcSpacing( nSpaceAdd
, aInf
);
1065 const sal_Bool bOldOnWin
= aInf
.OnWin();
1066 xub_StrLen nOldLen
= pPor
->GetLen();
1068 aInf
.SetLen( pPor
->GetLen() );
1070 aInf
.SetOnWin( sal_False
); // keine BULLETs!
1071 aInf
.SetKanaComp( pKanaComp
);
1072 aInf
.SetKanaIdx( nKanaIdx
);
1073 nTmp
= pPor
->GetTxtSize( aInf
).Width();
1074 aInf
.SetOnWin( bOldOnWin
);
1075 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
1076 nTmp
+= pPor
->CalcSpacing( nSpaceAdd
, aInf
);
1077 pPor
->SetLen( nOldLen
);
1079 pOrig
->Width( nTmp
);
1082 // travel inside field portion?
1083 if ( pCMS
->pSpecialPos
)
1085 // apply attributes to font
1087 lcl_GetCharRectInsideField( aInf
, *pOrig
, *pCMS
, *pPor
);
1092 // special case: We are at the beginning of a BidiPortion or
1093 // directly behind a BidiPortion
1097 pPor
->IsMultiPortion() &&
1098 ((SwMultiPortion
*)pPor
)->IsBidi() ) ) )
1100 // we determine if the cursor has to blink before or behind
1104 const sal_uInt8 nPortionLevel
= pLastBidiPor
->GetLevel();
1106 if ( pCMS
->nCursorBidiLevel
>= nPortionLevel
)
1108 // we came from inside the bidi portion, we want to blink
1109 // behind the portion
1110 pOrig
->Pos().X() -= nLastBidiPorWidth
;
1112 // Again, there is a special case: logically behind
1113 // the portion can actually mean that the cursor is inside
1114 // the portion. This can happen is the last portion
1115 // inside the bidi portion is a nested bidi portion
1116 SwLineLayout
& rLineLayout
=
1117 ((SwMultiPortion
*)pLastBidiPor
)->GetRoot();
1119 const SwLinePortion
*pLast
= rLineLayout
.FindLastPortion();
1120 if ( pLast
->IsMultiPortion() )
1122 OSL_ENSURE( ((SwMultiPortion
*)pLast
)->IsBidi(),
1123 "Non-BidiPortion inside BidiPortion" );
1124 pOrig
->Pos().X() += pLast
->Width() +
1125 pLast
->CalcSpacing( nSpaceAdd
, aInf
);
1131 const sal_uInt8 nPortionLevel
= ((SwBidiPortion
*)pPor
)->GetLevel();
1133 if ( pCMS
->nCursorBidiLevel
>= nPortionLevel
)
1135 // we came from inside the bidi portion, we want to blink
1136 // behind the portion
1137 pOrig
->Pos().X() += pPor
->Width() +
1138 pPor
->CalcSpacing( nSpaceAdd
, aInf
);
1143 pOrig
->Pos().X() += nX
;
1145 if ( pCMS
&& pCMS
->bRealHeight
)
1147 nTmpAscent
= AdjustBaseLine( *pCurr
, 0, nPorHeight
, nPorAscent
);
1148 if ( nTmpAscent
> nPorAscent
)
1149 pCMS
->aRealHeight
.X() = nTmpAscent
- nPorAscent
;
1151 pCMS
->aRealHeight
.X() = 0;
1152 OSL_ENSURE( nPorHeight
, "GetCharRect: Missing Portion-Height" );
1153 if ( nTmpHeight
> nPorHeight
)
1154 pCMS
->aRealHeight
.Y() = nPorHeight
;
1156 pCMS
->aRealHeight
.Y() = nTmpHeight
;
1161 /*************************************************************************
1162 * SwTxtCursor::GetCharRect()
1163 *************************************************************************/
1165 sal_Bool
SwTxtCursor::GetCharRect( SwRect
* pOrig
, const xub_StrLen nOfst
,
1166 SwCrsrMoveState
* pCMS
, const long nMax
)
1168 CharCrsrToLine(nOfst
);
1170 // Indicates that a position inside a special portion (field, number portion)
1172 const sal_Bool bSpecialPos
= pCMS
&& pCMS
->pSpecialPos
;
1173 xub_StrLen nFindOfst
= nOfst
;
1177 const sal_uInt8 nExtendRange
= pCMS
->pSpecialPos
->nExtendRange
;
1179 OSL_ENSURE( ! pCMS
->pSpecialPos
->nLineOfst
|| SP_EXTEND_RANGE_BEFORE
!= nExtendRange
,
1180 "LineOffset AND Number Portion?" );
1182 // portions which are behind the string
1183 if ( SP_EXTEND_RANGE_BEHIND
== nExtendRange
)
1186 // skip lines for fields which cover more than one line
1187 for ( sal_uInt16 i
= 0; i
< pCMS
->pSpecialPos
->nLineOfst
; i
++ )
1191 // Adjustierung ggf. nachholen
1194 const Point
aCharPos( GetTopLeft() );
1195 sal_Bool bRet
= sal_True
;
1197 _GetCharRect( pOrig
, nFindOfst
, pCMS
);
1199 const SwTwips nTmpRight
= Right() - 12;
1201 pOrig
->Pos().X() += aCharPos
.X();
1202 pOrig
->Pos().Y() += aCharPos
.Y();
1204 if( pCMS
&& pCMS
->b2Lines
&& pCMS
->p2Lines
)
1206 pCMS
->p2Lines
->aLine
.Pos().X() += aCharPos
.X();
1207 pCMS
->p2Lines
->aLine
.Pos().Y() += aCharPos
.Y();
1208 pCMS
->p2Lines
->aPortion
.Pos().X() += aCharPos
.X();
1209 pCMS
->p2Lines
->aPortion
.Pos().Y() += aCharPos
.Y();
1212 if( pOrig
->Left() > nTmpRight
)
1213 pOrig
->Pos().X() = nTmpRight
;
1217 if( pOrig
->Top() + pOrig
->Height() > nMax
)
1219 if( pOrig
->Top() > nMax
)
1221 pOrig
->Height( nMax
- pOrig
->Top() );
1223 if ( pCMS
&& pCMS
->bRealHeight
&& pCMS
->aRealHeight
.Y() >= 0 )
1225 long nTmp
= pCMS
->aRealHeight
.X() + pOrig
->Top();
1228 pCMS
->aRealHeight
.X() = nMax
- pOrig
->Top();
1229 pCMS
->aRealHeight
.Y() = 0;
1231 else if( nTmp
+ pCMS
->aRealHeight
.Y() > nMax
)
1232 pCMS
->aRealHeight
.Y() = nMax
- nTmp
;
1235 long nOut
= pOrig
->Right() - GetTxtFrm()->Frm().Right();
1238 if( GetTxtFrm()->Frm().Width() < GetTxtFrm()->Prt().Left()
1239 + GetTxtFrm()->Prt().Width() )
1240 nOut
+= GetTxtFrm()->Frm().Width() - GetTxtFrm()->Prt().Left()
1241 - GetTxtFrm()->Prt().Width();
1243 pOrig
->Pos().X() -= nOut
+ 10;
1248 /*************************************************************************
1249 * SwTxtCursor::GetCrsrOfst()
1251 * Return: Offset im String
1252 *************************************************************************/
1253 xub_StrLen
SwTxtCursor::GetCrsrOfst( SwPosition
*pPos
, const Point
&rPoint
,
1254 const MSHORT nChgNode
, SwCrsrMoveState
* pCMS
) const
1256 // Adjustierung ggf. nachholen
1259 const XubString
&rText
= GetInfo().GetTxt();
1260 xub_StrLen nOffset
= 0;
1262 // x ist der horizontale Offset innerhalb der Zeile.
1263 SwTwips x
= rPoint
.X();
1264 const SwTwips nLeftMargin
= GetLineStart();
1265 SwTwips nRightMargin
= GetLineEnd();
1266 if( nRightMargin
== nLeftMargin
)
1269 const sal_Bool bLeftOver
= x
< nLeftMargin
;
1272 const sal_Bool bRightOver
= x
> nRightMargin
;
1276 sal_Bool bRightAllowed
= pCMS
&& ( pCMS
->eState
== MV_NONE
);
1278 // Bis hierher in Dokumentkoordinaten.
1281 KSHORT nX
= KSHORT( x
);
1283 // Wenn es in der Zeile Attributwechsel gibt, den Abschnitt
1284 // suchen, in dem nX liegt.
1285 SwLinePortion
*pPor
= pCurr
->GetFirstPortion();
1286 xub_StrLen nCurrStart
= nStart
;
1287 sal_Bool bHolePortion
= sal_False
;
1288 sal_Bool bLastHyph
= sal_False
;
1290 std::deque
<sal_uInt16
> *pKanaComp
= pCurr
->GetpKanaComp();
1291 xub_StrLen nOldIdx
= GetInfo().GetIdx();
1292 MSHORT nSpaceIdx
= 0;
1293 size_t nKanaIdx
= 0;
1294 long nSpaceAdd
= pCurr
->IsSpaceAdd() ? pCurr
->GetLLSpaceAdd( 0 ) : 0;
1295 short nKanaComp
= pKanaComp
? (*pKanaComp
)[0] : 0;
1297 // nWidth ist die Breite der Zeile, oder die Breite des
1298 // Abschnitts mit dem Fontwechsel, in dem nX liegt.
1300 KSHORT nWidth
= pPor
->Width();
1301 if ( pCurr
->IsSpaceAdd() || pKanaComp
)
1303 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
1305 ((SwTxtSizeInfo
&)GetInfo()).SetIdx( nCurrStart
);
1306 nWidth
= nWidth
+ sal_uInt16( pPor
->CalcSpacing( nSpaceAdd
, GetInfo() ) );
1308 if( ( pPor
->InFixMargGrp() && ! pPor
->IsMarginPortion() ) ||
1309 ( pPor
->IsMultiPortion() && ((SwMultiPortion
*)pPor
)->HasTabulator() )
1312 if ( pCurr
->IsSpaceAdd() )
1314 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
1315 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
1322 if ( nKanaIdx
+ 1 < pKanaComp
->size() )
1323 nKanaComp
= (*pKanaComp
)[++nKanaIdx
];
1331 if ( pPor
->IsPostItsPortion() )
1332 nWidth30
= 30 + pPor
->GetViewWidth( GetInfo() ) / 2;
1334 nWidth30
= ! nWidth
&& pPor
->GetLen() && pPor
->InToxRefOrFldGrp() ?
1338 while( pPor
->GetPortion() && nWidth30
< nX
&& !pPor
->IsBreakPortion() )
1341 nCurrStart
= nCurrStart
+ pPor
->GetLen();
1342 bHolePortion
= pPor
->IsHolePortion();
1343 pPor
= pPor
->GetPortion();
1344 nWidth
= pPor
->Width();
1345 if ( pCurr
->IsSpaceAdd() || pKanaComp
)
1347 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
1349 ((SwTxtSizeInfo
&)GetInfo()).SetIdx( nCurrStart
);
1350 nWidth
= nWidth
+ sal_uInt16( pPor
->CalcSpacing( nSpaceAdd
, GetInfo() ) );
1353 if( ( pPor
->InFixMargGrp() && ! pPor
->IsMarginPortion() ) ||
1354 ( pPor
->IsMultiPortion() && ((SwMultiPortion
*)pPor
)->HasTabulator() )
1357 if ( pCurr
->IsSpaceAdd() )
1359 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
1360 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
1367 if( nKanaIdx
+ 1 < pKanaComp
->size() )
1368 nKanaComp
= (*pKanaComp
)[++nKanaIdx
];
1375 if ( pPor
->IsPostItsPortion() )
1376 nWidth30
= 30 + pPor
->GetViewWidth( GetInfo() ) / 2;
1378 nWidth30
= ! nWidth
&& pPor
->GetLen() && pPor
->InToxRefOrFldGrp() ?
1381 if( !pPor
->IsFlyPortion() && !pPor
->IsMarginPortion() )
1382 bLastHyph
= pPor
->InHyphGrp();
1385 const sal_Bool bLastPortion
= (0 == pPor
->GetPortion());
1389 SwLinePortion
*pNextPor
= pPor
->GetPortion();
1390 while( pNextPor
&& pNextPor
->InFldGrp() && !pNextPor
->Width() )
1392 nCurrStart
= nCurrStart
+ pPor
->GetLen();
1394 if( !pPor
->IsFlyPortion() && !pPor
->IsMarginPortion() )
1395 bLastHyph
= pPor
->InHyphGrp();
1396 pNextPor
= pPor
->GetPortion();
1400 ((SwTxtSizeInfo
&)GetInfo()).SetIdx( nOldIdx
);
1402 xub_StrLen nLength
= pPor
->GetLen();
1404 sal_Bool bFieldInfo
= pCMS
&& pCMS
->bFieldInfo
;
1406 if( bFieldInfo
&& ( nWidth30
< nX
|| bRightOver
|| bLeftOver
||
1407 ( pPor
->InNumberGrp() && !pPor
->IsFtnNumPortion() ) ||
1408 ( pPor
->IsMarginPortion() && nWidth
> nX
+ 30 ) ) )
1409 ((SwCrsrMoveState
*)pCMS
)->bPosCorr
= sal_True
;
1415 if( pCMS
->bInFrontOfLabel
)
1417 if (! (2 * nX
< nWidth
&& pPor
->InNumberGrp() &&
1418 !pPor
->IsFtnNumPortion()))
1419 pCMS
->bInFrontOfLabel
= sal_False
;
1423 // 7684: Wir sind genau auf der HyphPortion angelangt und muessen dafuer
1424 // sorgen, dass wir in dem String landen.
1425 // 7993: Wenn die Laenge 0 ist muessen wir raus...
1430 if( pPor
->IsFlyPortion() && bFieldInfo
)
1431 ((SwCrsrMoveState
*)pCMS
)->bPosCorr
= sal_True
;
1433 if (!bRightOver
&& nX
)
1435 if( pPor
->IsFtnNumPortion())
1436 ((SwCrsrMoveState
*)pCMS
)->bFtnNoInfo
= sal_True
;
1437 else if (pPor
->InNumberGrp() ) // #i23726#
1439 ((SwCrsrMoveState
*)pCMS
)->nInNumPostionOffset
= nX
;
1440 ((SwCrsrMoveState
*)pCMS
)->bInNumPortion
= sal_True
;
1447 // 7849, 7816: auf pPor->GetHyphPortion kann nicht verzichtet werden!
1448 if( bHolePortion
|| ( !bRightAllowed
&& bLastHyph
) ||
1449 ( pPor
->IsMarginPortion() && !pPor
->GetPortion() &&
1450 // 46598: In der letzten Zeile eines zentrierten Absatzes wollen
1451 // wir auch mal hinter dem letzten Zeichen landen.
1452 nCurrStart
< rText
.Len() ) )
1454 else if( pPor
->InFldGrp() && ((SwFldPortion
*)pPor
)->IsFollow()
1461 KSHORT nHeight
= pPor
->Height();
1462 if ( !nHeight
|| nHeight
> nWidth
)
1464 if( nChgNode
&& nWidth
- nHeight
/2 > nX
)
1474 // Sonst kommen wir nicht mehr in zeichengeb. Rahmen hinein...
1475 if( !( nChgNode
&& pPos
&& pPor
->IsFlyCntPortion() ) )
1477 if ( pPor
->InFldGrp() ||
1478 ( pPor
->IsMultiPortion() &&
1479 ((SwMultiPortion
*)pPor
)->IsBidi() ) )
1484 nHeight
= pPor
->Height();
1485 if ( !nHeight
|| nHeight
> nWidth
)
1489 if( nWidth
- nHeight
/2 <= nX
&&
1490 ( ! pPor
->InFldGrp() ||
1491 !((SwFldPortion
*)pPor
)->HasFollow() ) )
1494 else if ( ( !pPor
->IsFlyPortion() || ( pPor
->GetPortion() &&
1495 !pPor
->GetPortion()->IsMarginPortion() &&
1496 !pPor
->GetPortion()->IsHolePortion() ) )
1497 && ( nWidth
/2 < nX
) &&
1499 ( pPor
->GetPortion() &&
1500 pPor
->GetPortion()->IsPostItsPortion() ) )
1501 && ( bRightAllowed
|| !bLastHyph
))
1504 // if we want to get the position inside the field, we should not return
1505 if ( !pCMS
|| !pCMS
->pSpecialPos
)
1511 if ( pPor
->IsPostItsPortion() || pPor
->IsBreakPortion() ||
1512 pPor
->InToxRefGrp() )
1514 if ( pPor
->InFldGrp() )
1516 if( bRightOver
&& !((SwFldPortion
*)pPor
)->HasFollow() )
1523 if( bLastPortion
&& (pCurr
->GetNext() || pFrm
->GetFollow() ) )
1527 ( nWidth
== nX
&& pPor
->IsMultiPortion() && ((SwMultiPortion
*)pPor
)->IsDouble() ) )
1529 if( pPor
->IsMultiPortion() )
1531 // In a multi-portion we use GetCrsrOfst()-function recursively
1532 SwTwips nTmpY
= rPoint
.Y() - pCurr
->GetAscent() + pPor
->GetAscent();
1533 // if we are in the first line of a double line portion, we have
1534 // to add a value to nTmpY for not staying in this line
1535 // we also want to skip the first line, if we are inside ruby
1536 if ( ( ((SwTxtSizeInfo
*)pInf
)->IsMulti() &&
1537 ((SwTxtSizeInfo
*)pInf
)->IsFirstMulti() ) ||
1538 ( ((SwMultiPortion
*)pPor
)->IsRuby() &&
1539 ((SwMultiPortion
*)pPor
)->OnTop() ) )
1540 nTmpY
+= ((SwMultiPortion
*)pPor
)->Height();
1542 // Important for cursor traveling in ruby portions:
1543 // We have to set nTmpY to 0 in order to stay in the first row
1544 // if the phonetic line is the second row
1545 if ( ((SwMultiPortion
*)pPor
)->IsRuby() &&
1546 ! ((SwMultiPortion
*)pPor
)->OnTop() )
1549 SwTxtCursorSave
aSave( (SwTxtCursor
*)this, (SwMultiPortion
*)pPor
,
1550 nTmpY
, nX
, nCurrStart
, nSpaceAdd
);
1552 SwLayoutModeModifier
aLayoutModeModifier( *GetInfo().GetOut() );
1553 if ( ((SwMultiPortion
*)pPor
)->IsBidi() )
1555 const sal_uInt8 nBidiLevel
= ((SwBidiPortion
*)pPor
)->GetLevel();
1556 aLayoutModeModifier
.Modify( nBidiLevel
% 2 );
1559 if( ((SwMultiPortion
*)pPor
)->HasRotation() )
1562 if( !((SwMultiPortion
*)pPor
)->IsRevers() )
1563 nTmpY
= pPor
->Height() - nTmpY
;
1569 if( ((SwMultiPortion
*)pPor
)->HasBrackets() )
1571 sal_uInt16 nPreWidth
= ((SwDoubleLinePortion
*)pPor
)->PreWidth();
1572 if ( nX
> nPreWidth
)
1573 nX
= nX
- nPreWidth
;
1578 return GetCrsrOfst( pPos
, Point( GetLineStart() + nX
, rPoint
.Y() ),
1581 if( pPor
->InTxtGrp() )
1586 ((SwFont
*)GetFnt())->SetProportion( GetPropFont() );
1587 nOldProp
= GetFnt()->GetPropr();
1592 SwTxtSizeInfo
aSizeInf( GetInfo(), rText
, nCurrStart
);
1593 ((SwTxtCursor
*)this)->SeekAndChg( aSizeInf
);
1594 SwTxtSlot
aDiffTxt( &aSizeInf
, ((SwTxtPortion
*)pPor
), false, false );
1595 SwFontSave
aSave( aSizeInf
, pPor
->IsDropPortion() ?
1596 ((SwDropPortion
*)pPor
)->GetFnt() : NULL
);
1598 SwParaPortion
* pPara
= (SwParaPortion
*)GetInfo().GetParaPortion();
1599 OSL_ENSURE( pPara
, "No paragraph!" );
1601 SwDrawTextInfo
aDrawInf( aSizeInf
.GetVsh(),
1603 &pPara
->GetScriptInfo(),
1607 aDrawInf
.SetOfst( nX
);
1611 xub_StrLen nCharCnt
;
1612 // #i41860# Thai justified alignemt needs some
1613 // additional information:
1614 aDrawInf
.SetNumberOfBlanks( pPor
->InTxtGrp() ?
1615 static_cast<const SwTxtPortion
*>(pPor
)->GetSpaceCnt( aSizeInf
, nCharCnt
) :
1619 if ( pPor
->InFldGrp() && pCMS
&& pCMS
->pSpecialPos
)
1620 aDrawInf
.SetLen( STRING_LEN
); // SMARTTAGS
1622 aDrawInf
.SetSpace( nSpaceAdd
);
1623 aDrawInf
.SetFont( aSizeInf
.GetFont() );
1624 aDrawInf
.SetFrm( pFrm
);
1625 aDrawInf
.SetSnapToGrid( aSizeInf
.SnapToGrid() );
1626 aDrawInf
.SetPosMatchesBounds( pCMS
&& pCMS
->bPosMatchesBounds
);
1628 if ( SW_CJK
== aSizeInf
.GetFont()->GetActual() &&
1629 pPara
->GetScriptInfo().CountCompChg() &&
1630 ! pPor
->InFldGrp() )
1631 aDrawInf
.SetKanaComp( nKanaComp
);
1633 nLength
= aSizeInf
.GetFont()->_GetCrsrOfst( aDrawInf
);
1635 // get position inside field portion?
1636 if ( pPor
->InFldGrp() && pCMS
&& pCMS
->pSpecialPos
)
1638 pCMS
->pSpecialPos
->nCharOfst
= nLength
;
1639 nLength
= 0; // SMARTTAGS
1642 // set cursor bidi level
1644 ((SwCrsrMoveState
*)pCMS
)->nCursorBidiLevel
=
1645 aDrawInf
.GetCursorBidiLevel();
1647 if( bFieldInfo
&& nLength
== pPor
->GetLen() &&
1648 ( ! pPor
->GetPortion() ||
1649 ! pPor
->GetPortion()->IsPostItsPortion() ) )
1653 ((SwFont
*)GetFnt())->SetProportion( nOldProp
);
1657 if( nChgNode
&& pPos
&& pPor
->IsFlyCntPortion()
1658 && !( (SwFlyCntPortion
*)pPor
)->IsDraw() )
1660 // JP 24.11.94: liegt die Pos nicht im Fly, dann
1661 // darf nicht mit STRING_LEN returnt werden!
1662 // (BugId: 9692 + Aenderung in feshview)
1663 SwFlyInCntFrm
*pTmp
= ( (SwFlyCntPortion
*)pPor
)->GetFlyFrm();
1664 sal_Bool bChgNode
= 1 < nChgNode
;
1667 SwFrm
* pLower
= pTmp
->GetLower();
1668 if( pLower
&& (pLower
->IsTxtFrm() || pLower
->IsLayoutFrm()) )
1669 bChgNode
= sal_True
;
1671 Point
aTmpPoint( rPoint
);
1673 if ( pFrm
->IsRightToLeft() )
1674 pFrm
->SwitchLTRtoRTL( aTmpPoint
);
1676 if ( pFrm
->IsVertical() )
1677 pFrm
->SwitchHorizontalToVertical( aTmpPoint
);
1679 if( bChgNode
&& pTmp
->Frm().IsInside( aTmpPoint
) &&
1680 !( pTmp
->IsProtected() ) )
1682 nLength
= ((SwFlyCntPortion
*)pPor
)->
1683 GetFlyCrsrOfst( nX
, aTmpPoint
, pPos
, pCMS
);
1684 // Sobald der Frame gewechselt wird, muessen wir aufpassen, dass
1685 // unser Font wieder im OutputDevice steht.
1686 // vgl. Paint und new SwFlyCntPortion !
1687 ((SwTxtSizeInfo
*)pInf
)->SelectFont();
1689 // 6776: Das pIter->GetCrsrOfst returnt
1690 // aus einer Verschachtelung mit STRING_LEN.
1695 nLength
= pPor
->GetCrsrOfst( nX
);
1698 nOffset
= nCurrStart
+ nLength
;
1700 // 7684: Wir sind vor der HyphPortion angelangt und muessen dafuer
1701 // sorgen, dass wir in dem String landen.
1702 // Bei Zeilenenden vor FlyFrms muessen ebenso behandelt werden.
1704 if( nOffset
&& pPor
->GetLen() == nLength
&& pPor
->GetPortion() &&
1705 !pPor
->GetPortion()->GetLen() && pPor
->GetPortion()->InHyphGrp() )
1711 /** Looks for text portions which are inside the given rectangle
1713 For a rectangular text selection every text portions which is inside the given
1714 rectangle has to be put into the SwSelectionList as SwPaM
1715 From these SwPaM the SwCursors will be created.
1718 The container for the overlapped text portions
1721 A rectangle in document coordinates, text inside this rectangle has to be
1724 @return [ true, false ]
1725 true if any overlapping text portion has been found and put into list
1726 false if no portion overlaps, the list has been unchanged
1728 bool SwTxtFrm::FillSelection( SwSelectionList
& rSelList
, const SwRect
& rRect
) const
1731 // PaintArea() instead Frm() for negative indents
1732 SwRect
aTmpFrm( PaintArea() );
1733 if( !rRect
.IsOver( aTmpFrm
) )
1735 if( rSelList
.checkContext( this ) )
1737 SwRect
aRect( aTmpFrm
);
1738 aRect
.Intersection( rRect
);
1739 // rNode without const to create SwPaMs
1740 SwCntntNode
&rNode
= const_cast<SwCntntNode
&>( *GetNode() );
1741 SwNodeIndex
aIdx( rNode
);
1742 SwPosition
aPosL( aIdx
, SwIndex( &rNode
, 0 ) );
1745 SwPaM
*pPam
= new SwPaM( aPosL
, aPosL
);
1746 rSelList
.insertPaM( pPam
);
1748 else if( aRect
.HasArea() )
1750 xub_StrLen nOld
= STRING_LEN
;
1751 SwPosition
aPosR( aPosL
);
1753 SwTxtInfo
aInf( const_cast<SwTxtFrm
*>(this) );
1754 SwTxtIter
aLine( const_cast<SwTxtFrm
*>(this), &aInf
);
1755 // We have to care for top-to-bottom layout, where right becomes top etc.
1757 SwTwips nTop
= (aRect
.*fnRect
->fnGetTop
)();
1758 SwTwips nBottom
= (aRect
.*fnRect
->fnGetBottom
)();
1759 SwTwips nLeft
= (aRect
.*fnRect
->fnGetLeft
)();
1760 SwTwips nRight
= (aRect
.*fnRect
->fnGetRight
)();
1761 SwTwips nY
= aLine
.Y(); // Top position of the first line
1762 SwTwips nLastY
= nY
;
1763 while( nY
< nTop
&& aLine
.Next() ) // line above rectangle
1768 bool bLastLine
= false;
1769 if( nY
< nTop
&& !aLine
.GetNext() )
1772 nY
+= aLine
.GetLineHeight();
1774 do // check the lines for overlapping
1776 if( nLastY
< nTop
) // if the last line was above rectangle
1778 if( nY
> nBottom
) // if the current line leaves the rectangle
1780 if( nY
>= nLastY
) // gotcha: overlapping
1786 aPoint
.X() = nLastY
;
1792 aPoint
.Y() = nLastY
;
1794 // Looking for the position of the left border of the rectangle
1795 // in this text line
1796 SwCrsrMoveState
aState( MV_UPDOWN
);
1797 if( GetCrsrOfst( &aPosL
, aPoint
, &aState
) )
1801 aPoint
.X() = nLastY
;
1802 aPoint
.Y() = nRight
;
1806 aPoint
.X() = nRight
;
1807 aPoint
.Y() = nLastY
;
1809 // If we get a right position and if the left position
1810 // is not the same like the left position of the line before
1811 // which cound happen e.g. for field portions or fly frames
1812 // a SwPaM will be inserted with these positions
1813 if( GetCrsrOfst( &aPosR
, aPoint
, &aState
) &&
1814 nOld
!= aPosL
.nContent
.GetIndex() )
1816 SwPaM
*pPam
= new SwPaM( aPosL
, aPosR
);
1817 rSelList
.insertPaM( pPam
);
1818 nOld
= aPosL
.nContent
.GetIndex();
1827 else if( !bLastLine
)
1831 nY
+= aLine
.GetLineHeight();
1835 }while( nLastY
< nBottom
);
1840 const SwSortedObjs
&rObjs
= *GetDrawObjs();
1841 for ( sal_uInt16 i
= 0; i
< rObjs
.Count(); ++i
)
1843 const SwAnchoredObject
* pAnchoredObj
= rObjs
[i
];
1844 if( !pAnchoredObj
->ISA(SwFlyFrm
) )
1846 const SwFlyFrm
* pFly
= static_cast<const SwFlyFrm
*>(pAnchoredObj
);
1847 if( pFly
->IsFlyInCntFrm() && pFly
->FillSelection( rSelList
, rRect
) )
1854 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */