1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: itrcrsr.cxx,v $
10 * $Revision: 1.81.40.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
34 #include "hintids.hxx"
41 #include "swselectionlist.hxx"
42 #include <sortedobjs.hxx>
43 #include <svx/protitem.hxx>
44 #include <svx/adjitem.hxx>
45 #include <svx/lspcitem.hxx>
46 #include <svx/lrspitem.hxx>
48 #include <pagedesc.hxx> // SwPageDesc
49 #include <tgrditem.hxx>
50 #include <IDocumentSettingAccess.hxx>
51 #include <pagefrm.hxx>
56 #include "flyfrms.hxx"
57 #include "porglue.hxx" // SwFlyCnt
58 #include "porfld.hxx" // SwFldPortion::IsFollow()
59 #include "porfly.hxx" // GetFlyCrsrOfst()
60 #include "pordrop.hxx"
61 #include "crstate.hxx" // SwCrsrMoveState
62 #include <pormulti.hxx> // SwMultiPortion
64 // Nicht reentrant !!!
65 // wird in GetCharRect gesetzt und im UnitUp/Down ausgewertet.
66 sal_Bool
SwTxtCursor::bRightMargin
= sal_False
;
69 /*************************************************************************
70 * lcl_GetCharRectInsideField
72 * After calculating the position of a character during GetCharRect
73 * this function allows to find the coordinates of a position (defined
74 * in pCMS->pSpecialPos) inside a special portion (e.g., a field)
75 *************************************************************************/
76 void lcl_GetCharRectInsideField( SwTxtSizeInfo
& rInf
, SwRect
& rOrig
,
77 const SwCrsrMoveState
& rCMS
,
78 const SwLinePortion
& rPor
)
80 ASSERT( rCMS
.pSpecialPos
, "Information about special pos missing" )
82 if ( rPor
.InFldGrp() && ((SwFldPortion
&)rPor
).GetExp().Len() )
84 const USHORT nCharOfst
= rCMS
.pSpecialPos
->nCharOfst
;
88 const XubString
* pString
= 0;
89 const SwLinePortion
* pPor
= &rPor
;
92 if ( pPor
->InFldGrp() )
94 pString
= &((SwFldPortion
*)pPor
)->GetExp();
95 nFldLen
= pString
->Len();
103 if ( ! pPor
->GetPortion() || nFldIdx
+ nFldLen
> nCharOfst
)
106 nFldIdx
= nFldIdx
+ nFldLen
;
107 rOrig
.Pos().X() += pPor
->Width();
108 pPor
= pPor
->GetPortion();
112 ASSERT( nCharOfst
>= nFldIdx
, "Request of position inside field failed" )
113 USHORT nLen
= nCharOfst
- nFldIdx
+ 1;
117 // get script for field portion
118 rInf
.GetFont()->SetActual( SwScriptInfo::WhichFont( 0, pString
, 0 ) );
120 xub_StrLen nOldLen
= pPor
->GetLen();
121 ((SwLinePortion
*)pPor
)->SetLen( nLen
- 1 );
122 const SwTwips nX1
= pPor
->GetLen() ?
123 pPor
->GetTxtSize( rInf
).Width() :
127 if ( rCMS
.bRealWidth
)
129 ((SwLinePortion
*)pPor
)->SetLen( nLen
);
130 nX2
= pPor
->GetTxtSize( rInf
).Width();
133 ((SwLinePortion
*)pPor
)->SetLen( nOldLen
);
135 rOrig
.Pos().X() += nX1
;
136 rOrig
.Width( ( nX2
> nX1
) ?
143 // special cases: no common fields, e.g., graphic number portion,
144 // FlyInCntPortions, Notes
145 rOrig
.Width( rCMS
.bRealWidth
&& rPor
.Width() ? rPor
.Width() : 1 );
149 /*************************************************************************
150 * SwTxtMargin::CtorInitTxtMargin()
151 *************************************************************************/
152 void SwTxtMargin::CtorInitTxtMargin( SwTxtFrm
*pNewFrm
, SwTxtSizeInfo
*pNewInf
)
154 CtorInitTxtIter( pNewFrm
, pNewInf
);
157 GetInfo().SetFont( GetFnt() );
158 const SwTxtNode
*pNode
= pFrm
->GetTxtNode();
160 const SvxLRSpaceItem
&rSpace
= pFrm
->GetTxtNode()->GetSwAttrSet().GetLRSpace();
161 // --> OD 2009-09-02 #i95907#
162 const bool bListLevelIndentsApplicable
= pFrm
->GetTxtNode()->AreListLevelIndentsApplicable();
166 // Carefully adjust the text formatting ranges.
168 // This whole area desperately needs some rework. There are
169 // quite a couple of values that need to be considered:
170 // 1. paragraph indent
171 // 2. paragraph first line indent
172 // 3. numbering indent
173 // 4. numbering spacing to text
174 // 5. paragraph border
175 // Note: These values have already been used during calculation
176 // of the printing area of the paragraph.
177 const int nLMWithNum
= pNode
->GetLeftMarginWithNum( sal_True
);
178 if ( pFrm
->IsRightToLeft() )
180 // --> OD 2008-01-23 #newlistlevelattrs#
181 // this calculation is identical this the calculation for L2R layout - see below
182 nLeft
= pFrm
->Frm().Left() +
185 pNode
->GetLeftMarginWithNum( sal_False
) -
186 // --> OD 2009-09-02 #i95907#
187 // rSpace.GetLeft() +
188 // rSpace.GetTxtLeft();
189 ( bListLevelIndentsApplicable
191 : ( rSpace
.GetLeft() - rSpace
.GetTxtLeft() ) );
196 if ( !pNode
->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING
) )
198 // this calculation is identical this the calculation for R2L layout - see above
199 nLeft
= pFrm
->Frm().Left() +
202 pNode
->GetLeftMarginWithNum( sal_False
) -
203 // --> OD 2009-09-02 #i95907#
204 // rSpace.GetLeft() +
205 // rSpace.GetTxtLeft();
206 ( bListLevelIndentsApplicable
208 : ( rSpace
.GetLeft() - rSpace
.GetTxtLeft() ) );
213 nLeft
= pFrm
->Frm().Left() +
214 Max( long( rSpace
.GetTxtLeft() + nLMWithNum
),
215 pFrm
->Prt().Left() );
219 nRight
= pFrm
->Frm().Left() + pFrm
->Prt().Left() + pFrm
->Prt().Width();
221 if( nLeft
>= nRight
&&
222 // --> FME 2005-08-10 #i53066# Omit adjustment of nLeft for numbered
223 // paras inside cells inside new documents:
224 ( pNode
->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING
) ||
229 nLeft
= pFrm
->Prt().Left() + pFrm
->Frm().Left();
230 if( nLeft
>= nRight
) // z.B. bei grossen Absatzeinzuegen in schmalen Tabellenspalten
231 nRight
= nLeft
+ 1; // einen goennen wir uns immer
234 if( pFrm
->IsFollow() && pFrm
->GetOfst() )
240 if( !pNode
->GetFirstLineOfsWithNum( nFLOfst
) &&
241 rSpace
.IsAutoFirst() )
243 nFirstLineOfs
= GetFnt()->GetSize( GetFnt()->GetActual() ).Height();
244 const SvxLineSpacingItem
*pSpace
= aLineInf
.GetLineSpacing();
247 switch( pSpace
->GetLineSpaceRule() )
249 case SVX_LINE_SPACE_AUTO
:
251 case SVX_LINE_SPACE_MIN
:
253 if( nFirstLineOfs
< KSHORT( pSpace
->GetLineHeight() ) )
254 nFirstLineOfs
= pSpace
->GetLineHeight();
257 case SVX_LINE_SPACE_FIX
:
258 nFirstLineOfs
= pSpace
->GetLineHeight();
260 default: ASSERT( sal_False
, ": unknown LineSpaceRule" );
262 switch( pSpace
->GetInterLineSpaceRule() )
264 case SVX_INTER_LINE_SPACE_OFF
:
266 case SVX_INTER_LINE_SPACE_PROP
:
268 long nTmp
= pSpace
->GetPropLineSpace();
269 // 50% ist das Minimum, bei 0% schalten wir auf
270 // den Defaultwert 100% um ...
272 nTmp
= nTmp
? 50 : 100;
274 nTmp
*= nFirstLineOfs
;
278 nFirstLineOfs
= (KSHORT
)nTmp
;
281 case SVX_INTER_LINE_SPACE_FIX
:
283 nFirstLineOfs
+= pSpace
->GetInterLineSpace();
286 default: ASSERT( sal_False
, ": unknown InterLineSpaceRule" );
291 nFirstLineOfs
= nFLOfst
;
293 if ( pFrm
->IsRightToLeft() ||
294 !pNode
->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING
) )
296 nFirst
= nLeft
+ nFirstLineOfs
;
300 nFirst
= pFrm
->Frm().Left() +
301 Max( rSpace
.GetTxtLeft() + nLMWithNum
+ nFirstLineOfs
,
302 pFrm
->Prt().Left() );
305 // --> OD 2008-01-31 #newlistlevelattrs#
306 // Note: <SwTxtFrm::GetAdditionalFirstLineOffset()> returns a negative
307 // value for the new list label postion and space mode LABEL_ALIGNMENT
308 // and label alignment CENTER and RIGHT in L2R layout respectively
309 // label alignment LEFT and CENTER in R2L layout
310 nFirst
+= pFrm
->GetAdditionalFirstLineOffset();
313 if( nFirst
>= nRight
)
316 const SvxAdjustItem
& rAdjust
= pFrm
->GetTxtNode()->GetSwAttrSet().GetAdjust();
317 nAdjust
= static_cast<USHORT
>(rAdjust
.GetAdjust());
319 // left is left and right is right
320 if ( pFrm
->IsRightToLeft() )
322 if ( SVX_ADJUST_LEFT
== nAdjust
)
323 nAdjust
= SVX_ADJUST_RIGHT
;
324 else if ( SVX_ADJUST_RIGHT
== nAdjust
)
325 nAdjust
= SVX_ADJUST_LEFT
;
328 bOneBlock
= rAdjust
.GetOneWord() == SVX_ADJUST_BLOCK
;
329 bLastBlock
= rAdjust
.GetLastBlock() == SVX_ADJUST_BLOCK
;
330 bLastCenter
= rAdjust
.GetLastBlock() == SVX_ADJUST_CENTER
;
332 // --> OD 2008-07-01 #i91133#
333 mnTabLeft
= pNode
->GetLeftMarginForTabCalculation();
336 #if OSL_DEBUG_LEVEL > 1
337 static sal_Bool bOne
= sal_False
;
338 static sal_Bool bLast
= sal_False
;
339 static sal_Bool bCenter
= sal_False
;
342 bLastCenter
|= bCenter
;
347 /*************************************************************************
348 * SwTxtMargin::DropInit()
349 *************************************************************************/
350 void SwTxtMargin::DropInit()
352 nDropLeft
= nDropLines
= nDropHeight
= nDropDescent
= 0;
353 const SwParaPortion
*pPara
= GetInfo().GetParaPortion();
356 const SwDropPortion
*pPorDrop
= pPara
->FindDropPortion();
359 nDropLeft
= pPorDrop
->GetDropLeft();
360 nDropLines
= pPorDrop
->GetLines();
361 nDropHeight
= pPorDrop
->GetDropHeight();
362 nDropDescent
= pPorDrop
->GetDropDescent();
367 /*************************************************************************
368 * SwTxtMargin::GetLineStart()
369 *************************************************************************/
371 // Unter Beruecksichtigung des Erstzeileneinzuges und der angebenen Breite.
372 SwTwips
SwTxtMargin::GetLineStart() const
374 SwTwips nRet
= GetLeftMargin();
375 if( GetAdjust() != SVX_ADJUST_LEFT
&&
376 !pCurr
->GetFirstPortion()->IsMarginPortion() )
378 // Wenn die erste Portion ein Margin ist, dann wird das
379 // Adjustment durch die Portions ausgedrueckt.
380 if( GetAdjust() == SVX_ADJUST_RIGHT
)
381 nRet
= Right() - CurrWidth();
382 else if( GetAdjust() == SVX_ADJUST_CENTER
)
383 nRet
+= (GetLineWidth() - CurrWidth()) / 2;
388 /*************************************************************************
389 * SwTxtCursor::CtorInitTxtCursor()
390 *************************************************************************/
391 void SwTxtCursor::CtorInitTxtCursor( SwTxtFrm
*pNewFrm
, SwTxtSizeInfo
*pNewInf
)
393 CtorInitTxtMargin( pNewFrm
, pNewInf
);
394 // 6096: Vorsicht, die Iteratoren sind abgeleitet!
395 // GetInfo().SetOut( GetInfo().GetWin() );
398 /*************************************************************************
399 * SwTxtCursor::GetEndCharRect()
400 *************************************************************************/
402 // 1170: Antikbug: Shift-Ende vergisst das letzte Zeichen ...
404 sal_Bool
SwTxtCursor::GetEndCharRect( SwRect
* pOrig
, const xub_StrLen nOfst
,
405 SwCrsrMoveState
* pCMS
, const long nMax
)
407 // 1170: Mehrdeutigkeit von Dokumentpositionen
408 bRightMargin
= sal_True
;
409 CharCrsrToLine(nOfst
);
411 // Etwas verdreht: nOfst bezeichnet die Position hinter dem letzten
412 // Zeichen der letzten Zeile == Position vor dem ersten Zeichen der
413 // Zeile in der wir gerade stehen:
414 if( nOfst
!= GetStart() || !pCurr
->GetLen() )
416 // 8810: Masterzeile RightMargin, danach LeftMargin
417 const sal_Bool bRet
= GetCharRect( pOrig
, nOfst
, pCMS
, nMax
);
418 bRightMargin
= nOfst
>= GetEnd() && nOfst
< GetInfo().GetTxt().Len();
422 if( !GetPrev() || !GetPrev()->GetLen() || !PrevLine() )
423 return GetCharRect( pOrig
, nOfst
, pCMS
, nMax
);
425 // Adjustierung ggf. nachholen
430 SwLinePortion
*pPor
= pCurr
->GetFirstPortion();
432 KSHORT nTmpHeight
, nTmpAscent
;
433 CalcAscentAndHeight( nTmpAscent
, nTmpHeight
);
434 KSHORT nPorHeight
= nTmpHeight
;
435 KSHORT nPorAscent
= nTmpAscent
;
437 // Die letzte Text/EndPortion der Zeile suchen
440 nX
= nX
+ pPor
->Width();
441 if( pPor
->InTxtGrp() || ( pPor
->GetLen() && !pPor
->IsFlyPortion()
442 && !pPor
->IsHolePortion() ) || pPor
->IsBreakPortion() )
445 nPorHeight
= pPor
->Height();
446 nPorAscent
= pPor
->GetAscent();
448 pPor
= pPor
->GetPortion();
451 const Size
aCharSize( 1, nTmpHeight
);
452 pOrig
->Pos( GetTopLeft() );
453 pOrig
->SSize( aCharSize
);
454 pOrig
->Pos().X() += nLast
;
455 const SwTwips nTmpRight
= Right() - 1;
456 if( pOrig
->Left() > nTmpRight
)
457 pOrig
->Pos().X() = nTmpRight
;
459 if ( pCMS
&& pCMS
->bRealHeight
)
461 if ( nTmpAscent
> nPorAscent
)
462 pCMS
->aRealHeight
.X() = nTmpAscent
- nPorAscent
;
464 pCMS
->aRealHeight
.X() = 0;
465 ASSERT( nPorHeight
, "GetCharRect: Missing Portion-Height" );
466 pCMS
->aRealHeight
.Y() = nPorHeight
;
472 /*************************************************************************
473 * void SwTxtCursor::_GetCharRect(..)
474 * internal function, called by SwTxtCursor::GetCharRect() to calculate
475 * the relative character position in the current line.
476 * pOrig referes to x and y coordinates, width and height of the cursor
477 * pCMS is used for restricting the cursor, if there are different font
478 * heights in one line ( first value = offset to y of pOrig, second
479 * value = real height of (shortened) cursor
480 *************************************************************************/
482 void SwTxtCursor::_GetCharRect( SwRect
* pOrig
, const xub_StrLen nOfst
,
483 SwCrsrMoveState
* pCMS
)
485 const XubString
&rText
= GetInfo().GetTxt();
486 SwTxtSizeInfo
aInf( GetInfo(), rText
, nStart
);
488 aInf
.GetFont()->SetProportion( GetPropFont() );
489 KSHORT nTmpAscent
, nTmpHeight
; // Zeilenhoehe
490 CalcAscentAndHeight( nTmpAscent
, nTmpHeight
);
491 const Size
aCharSize( 1, nTmpHeight
);
492 const Point aCharPos
;
493 pOrig
->Pos( aCharPos
);
494 pOrig
->SSize( aCharSize
);
496 // If we are looking for a position inside a field which covers
497 // more than one line we may not skip any "empty portions" at the
498 // beginning of a line
499 const sal_Bool bInsideFirstField
= pCMS
&& pCMS
->pSpecialPos
&&
500 ( pCMS
->pSpecialPos
->nLineOfst
||
501 SP_EXTEND_RANGE_BEFORE
==
502 pCMS
->pSpecialPos
->nExtendRange
);
504 sal_Bool bWidth
= pCMS
&& pCMS
->bRealWidth
;
505 if( !pCurr
->GetLen() && !pCurr
->Width() )
507 if ( pCMS
&& pCMS
->bRealHeight
)
509 pCMS
->aRealHeight
.X() = 0;
510 pCMS
->aRealHeight
.Y() = nTmpHeight
;
515 KSHORT nPorHeight
= nTmpHeight
;
516 KSHORT nPorAscent
= nTmpAscent
;
518 SwTwips nTmpFirst
= 0;
519 SwLinePortion
*pPor
= pCurr
->GetFirstPortion();
520 SwBidiPortion
* pLastBidiPor
= 0;
521 SwTwips nLastBidiPorWidth
= 0;
522 SvUShorts
* pKanaComp
= pCurr
->GetpKanaComp();
523 MSHORT nSpaceIdx
= 0;
525 long nSpaceAdd
= pCurr
->IsSpaceAdd() ? pCurr
->GetLLSpaceAdd( 0 ) : 0;
527 sal_Bool bNoTxt
= sal_True
;
529 // Zuerst werden alle Portions ohne Len am Zeilenanfang uebersprungen.
530 // Ausnahme bilden die fiesen Spezialportions aus WhichFirstPortion:
531 // Num, ErgoSum, FtnNum, FeldReste
532 // 8477: aber auch die einzige Textportion einer leeren Zeile mit
533 // Right/Center-Adjustment! Also nicht nur pPor->GetExpandPortion() ...
534 while( pPor
&& !pPor
->GetLen() && ! bInsideFirstField
)
537 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
538 nX
+= pPor
->CalcSpacing( nSpaceAdd
, aInf
);
541 // 8670: EndPortions zaehlen hier einmal als TxtPortions.
542 // --> OD 2008-01-28 #newlistlevelattrs#
543 // if( pPor->InTxtGrp() || pPor->IsBreakPortion() )
544 if( pPor
->InTxtGrp() || pPor
->IsBreakPortion() || pPor
->InTabGrp() )
550 if( pPor
->IsMultiPortion() && ((SwMultiPortion
*)pPor
)->HasTabulator() )
552 if ( pCurr
->IsSpaceAdd() )
554 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
555 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
560 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->Count() )
563 if( pPor
->InFixMargGrp() )
565 if( pPor
->IsMarginPortion() )
569 // fix margin portion => next SpaceAdd, KanaComp value
570 if ( pCurr
->IsSpaceAdd() )
572 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
573 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
578 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->Count() )
582 pPor
= pPor
->GetPortion();
587 // Es sind nur Spezialportions unterwegs.
592 if( !pPor
->IsMarginPortion() && !pPor
->IsPostItsPortion() &&
593 (!pPor
->InFldGrp() || pPor
->GetAscent() ) )
595 nPorHeight
= pPor
->Height();
596 nPorAscent
= pPor
->GetAscent();
598 while( pPor
&& !pPor
->IsBreakPortion() && ( aInf
.GetIdx() < nOfst
||
599 ( bWidth
&& ( pPor
->IsKernPortion() || pPor
->IsMultiPortion() ) ) ) )
601 if( !pPor
->IsMarginPortion() && !pPor
->IsPostItsPortion() &&
602 (!pPor
->InFldGrp() || pPor
->GetAscent() ) )
604 nPorHeight
= pPor
->Height();
605 nPorAscent
= pPor
->GetAscent();
608 // If we are behind the portion, we add the portion width to
609 // nX. Special case: nOfst = aInf.GetIdx() + pPor->GetLen().
610 // For common portions (including BidiPortions) we want to add
611 // the portion width to nX. For MultiPortions, nExtra = 0,
612 // therefore we go to the 'else' branch and start a recursion.
613 const BYTE nExtra
= pPor
->IsMultiPortion() &&
614 ! ((SwMultiPortion
*)pPor
)->IsBidi() &&
616 if ( aInf
.GetIdx() + pPor
->GetLen() < nOfst
+ nExtra
)
618 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
619 nX
+= pPor
->PrtWidth() +
620 pPor
->CalcSpacing( nSpaceAdd
, aInf
);
623 if( pPor
->InFixMargGrp() && ! pPor
->IsMarginPortion() )
625 // update to current SpaceAdd, KanaComp values
626 if ( pCurr
->IsSpaceAdd() )
628 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
629 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
635 ( nKanaIdx
+ 1 ) < pKanaComp
->Count()
639 if ( !pPor
->IsFlyPortion() || ( pPor
->GetPortion() &&
640 !pPor
->GetPortion()->IsMarginPortion() ) )
641 nX
+= pPor
->PrtWidth();
643 if( pPor
->IsMultiPortion() )
645 if ( ((SwMultiPortion
*)pPor
)->HasTabulator() )
647 if ( pCurr
->IsSpaceAdd() )
649 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
650 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
655 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->Count() )
659 // if we are right behind a BidiPortion, we have to
660 // hold a pointer to the BidiPortion in order to
661 // find the correct cursor position, depending on the
663 if ( ((SwMultiPortion
*)pPor
)->IsBidi() &&
664 aInf
.GetIdx() + pPor
->GetLen() == nOfst
)
666 pLastBidiPor
= (SwBidiPortion
*)pPor
;
667 nLastBidiPorWidth
= pLastBidiPor
->Width() +
668 pLastBidiPor
->CalcSpacing( nSpaceAdd
, aInf
);;
672 aInf
.SetIdx( aInf
.GetIdx() + pPor
->GetLen() );
673 pPor
= pPor
->GetPortion();
677 if( pPor
->IsMultiPortion() )
679 nTmpAscent
= AdjustBaseLine( *pCurr
, pPor
);
680 GetInfo().SetMulti( sal_True
);
681 pOrig
->Pos().Y() += nTmpAscent
- nPorAscent
;
683 if( pCMS
&& pCMS
->b2Lines
)
685 sal_Bool bRecursion
= sal_True
;
686 if ( ! pCMS
->p2Lines
)
688 pCMS
->p2Lines
= new Sw2LinesPos
;
689 pCMS
->p2Lines
->aLine
= SwRect(aCharPos
, aCharSize
);
690 bRecursion
= sal_False
;
693 if( ((SwMultiPortion
*)pPor
)->HasRotation() )
695 if( ((SwMultiPortion
*)pPor
)->IsRevers() )
696 pCMS
->p2Lines
->nMultiType
= MT_ROT_270
;
698 pCMS
->p2Lines
->nMultiType
= MT_ROT_90
;
700 else if( ((SwMultiPortion
*)pPor
)->IsDouble() )
701 pCMS
->p2Lines
->nMultiType
= MT_TWOLINE
;
702 else if( ((SwMultiPortion
*)pPor
)->IsBidi() )
703 pCMS
->p2Lines
->nMultiType
= MT_BIDI
;
705 pCMS
->p2Lines
->nMultiType
= MT_RUBY
;
707 SwTwips nTmpWidth
= pPor
->Width();
709 nTmpWidth
+= pPor
->CalcSpacing(nSpaceAdd
, aInf
);
711 SwRect
aRect( Point(aCharPos
.X() + nX
, pOrig
->Top() ),
712 Size( nTmpWidth
, pPor
->Height() ) );
715 pCMS
->p2Lines
->aPortion
= aRect
;
717 pCMS
->p2Lines
->aPortion2
= aRect
;
720 // In a multi-portion we use GetCharRect()-function
721 // recursively and must add the x-position
722 // of the multi-portion.
723 xub_StrLen nOldStart
= nStart
;
725 BYTE nOldProp
= GetPropFont();
726 nStart
= aInf
.GetIdx();
727 SwLineLayout
* pOldCurr
= pCurr
;
728 pCurr
= &((SwMultiPortion
*)pPor
)->GetRoot();
729 if( ((SwMultiPortion
*)pPor
)->IsDouble() )
732 GETGRID( GetTxtFrm()->FindPageFrm() )
733 const sal_Bool bHasGrid
= pGrid
&& GetInfo().SnapToGrid();
734 const USHORT nRubyHeight
= bHasGrid
?
735 pGrid
->GetRubyHeight() : 0;
737 if( nStart
+ pCurr
->GetLen() <= nOfst
&& GetNext() &&
738 ( ! ((SwMultiPortion
*)pPor
)->IsRuby() ||
739 ((SwMultiPortion
*)pPor
)->OnTop() ) )
742 // in grid mode we may only add the height of the
743 // ruby line if ruby line is on top
745 ((SwMultiPortion
*)pPor
)->IsRuby() &&
746 ((SwMultiPortion
*)pPor
)->OnTop() )
747 nOffset
= nRubyHeight
;
749 nOffset
= GetLineHeight();
751 pOrig
->Pos().Y() += nOffset
;
755 sal_Bool bSpaceChg
= ((SwMultiPortion
*)pPor
)->
756 ChgSpaceAdd( pCurr
, nSpaceAdd
);
757 Point aOldPos
= pOrig
->Pos();
759 // Ok, for ruby portions in grid mode we have to
760 // temporarily set the inner line height to the
761 // outer line height because that value is needed
762 // for the adjustment inside the recursion
763 const USHORT nOldRubyHeight
= pCurr
->Height();
764 const USHORT nOldRubyRealHeight
= pCurr
->GetRealHeight();
765 const sal_Bool bChgHeight
=
766 ((SwMultiPortion
*)pPor
)->IsRuby() && bHasGrid
;
770 pCurr
->Height( pOldCurr
->Height() - nRubyHeight
);
771 pCurr
->SetRealHeight( pOldCurr
->GetRealHeight() -
775 SwLayoutModeModifier
aLayoutModeModifier( *GetInfo().GetOut() );
776 if ( ((SwMultiPortion
*)pPor
)->IsBidi() )
778 aLayoutModeModifier
.Modify(
779 ((SwBidiPortion
*)pPor
)->GetLevel() % 2 );
782 _GetCharRect( pOrig
, nOfst
, pCMS
);
786 pCurr
->Height( nOldRubyHeight
);
787 pCurr
->SetRealHeight( nOldRubyRealHeight
);
790 // if we are still in the first row of
791 // our 2 line multiportion, we use the FirstMulti flag
793 if ( ((SwMultiPortion
*)pPor
)->IsDouble() )
795 // the recursion may have damaged our font size
796 SetPropFont( nOldProp
);
799 GetInfo().GetFont()->SetProportion( 100 );
801 if ( pCurr
== &((SwMultiPortion
*)pPor
)->GetRoot() )
803 GetInfo().SetFirstMulti( sal_True
);
805 // we want to treat a double line portion like a
806 // single line portion, if there is no text in
808 if ( !pCurr
->GetNext() ||
809 !pCurr
->GetNext()->GetLen() )
810 GetInfo().SetMulti( sal_False
);
813 // ruby portions are treated like single line portions
814 else if( ((SwMultiPortion
*)pPor
)->IsRuby() ||
815 ((SwMultiPortion
*)pPor
)->IsBidi() )
816 GetInfo().SetMulti( sal_False
);
818 // calculate cursor values
819 if( ((SwMultiPortion
*)pPor
)->HasRotation() )
821 GetInfo().SetMulti( sal_False
);
822 long nTmp
= pOrig
->Width();
823 pOrig
->Width( pOrig
->Height() );
824 pOrig
->Height( nTmp
);
825 nTmp
= pOrig
->Left() - aOldPos
.X();
827 // if we travel into our rotated portion from
828 // a line below, we have to take care, that the
829 // y coord in pOrig is less than line height:
833 pOrig
->Pos().X() = nX
+ aOldPos
.X();
834 if( ((SwMultiPortion
*)pPor
)->IsRevers() )
835 pOrig
->Pos().Y() = aOldPos
.Y() + nTmp
;
837 pOrig
->Pos().Y() = aOldPos
.Y()
838 + pPor
->Height() - nTmp
- pOrig
->Height();
839 if ( pCMS
&& pCMS
->bRealHeight
)
841 pCMS
->aRealHeight
.Y() = -pCMS
->aRealHeight
.Y();
842 // result for rotated multi portion is not
843 // correct for reverse (270 degree) portions
844 if( ((SwMultiPortion
*)pPor
)->IsRevers() )
846 if ( SvxParaVertAlignItem::AUTOMATIC
==
847 GetLineInfo().GetVertAlign() )
848 // if vertical alignment is set to auto,
849 // we switch from base line alignment
850 // to centered alignment
851 pCMS
->aRealHeight
.X() =
853 pCMS
->aRealHeight
.Y() ) / 2;
855 pCMS
->aRealHeight
.X() =
857 pCMS
->aRealHeight
.X() +
858 pCMS
->aRealHeight
.Y() );
864 pOrig
->Pos().Y() += aOldPos
.Y();
865 if ( ((SwMultiPortion
*)pPor
)->IsBidi() )
867 const SwTwips nPorWidth
= pPor
->Width() +
868 pPor
->CalcSpacing( nSpaceAdd
, aInf
);
869 const SwTwips nInsideOfst
= pOrig
->Pos().X();
870 pOrig
->Pos().X() = nX
+ nPorWidth
-
871 nInsideOfst
- pOrig
->Width();
874 pOrig
->Pos().X() += nX
;
876 if( ((SwMultiPortion
*)pPor
)->HasBrackets() )
878 ((SwDoubleLinePortion
*)pPor
)->PreWidth();
882 SwDoubleLinePortion::ResetSpaceAdd( pCurr
);
891 if ( pPor
->PrtWidth() )
893 xub_StrLen nOldLen
= pPor
->GetLen();
894 pPor
->SetLen( nOfst
- aInf
.GetIdx() );
895 aInf
.SetLen( pPor
->GetLen() );
896 if( nX
|| !pPor
->InNumberGrp() )
899 const sal_Bool bOldOnWin
= aInf
.OnWin();
900 aInf
.SetOnWin( sal_False
); // keine BULLETs!
902 aInf
.SetKanaComp( pKanaComp
);
903 aInf
.SetKanaIdx( nKanaIdx
);
904 nX
+= pPor
->GetTxtSize( aInf
).Width();
905 aInf
.SetOnWin( bOldOnWin
);
906 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
907 nX
+= pPor
->CalcSpacing( nSpaceAdd
, aInf
);
910 pPor
->SetLen( pPor
->GetLen() + 1 );
911 aInf
.SetLen( pPor
->GetLen() );
912 aInf
.SetOnWin( sal_False
); // keine BULLETs!
913 nTmp
+= pPor
->GetTxtSize( aInf
).Width();
914 aInf
.SetOnWin( bOldOnWin
);
915 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
916 nTmp
+= pPor
->CalcSpacing(nSpaceAdd
, aInf
);
917 pOrig
->Width( nTmp
- nX
);
920 pPor
->SetLen( nOldLen
);
930 ASSERT( !pPor
->InNumberGrp() || bInsideFirstField
, "Number surprise" );
931 sal_Bool bEmptyFld
= sal_False
;
932 if( pPor
->InFldGrp() && pPor
->GetLen() )
934 SwFldPortion
*pTmp
= (SwFldPortion
*)pPor
;
935 while( pTmp
->HasFollow() && !pTmp
->GetExp().Len() )
937 KSHORT nAddX
= pTmp
->Width();
938 SwLinePortion
*pNext
= pTmp
->GetPortion();
939 while( pNext
&& !pNext
->InFldGrp() )
941 ASSERT( !pNext
->GetLen(), "Where's my field follow?" );
942 nAddX
= nAddX
+ pNext
->Width();
943 pNext
= pNext
->GetPortion();
947 pTmp
= (SwFldPortion
*)pNext
;
948 nPorHeight
= pTmp
->Height();
949 nPorAscent
= pTmp
->GetAscent();
951 bEmptyFld
= sal_True
;
954 // 8513: Felder im Blocksatz, ueberspringen
955 while( pPor
&& !pPor
->GetLen() && ! bInsideFirstField
&&
956 ( pPor
->IsFlyPortion() || pPor
->IsKernPortion() ||
957 pPor
->IsBlankPortion() || pPor
->InTabGrp() ||
958 ( !bEmptyFld
&& pPor
->InFldGrp() ) ) )
960 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
961 nX
+= pPor
->PrtWidth() +
962 pPor
->CalcSpacing( nSpaceAdd
, aInf
);
965 if( pPor
->InFixMargGrp() && ! pPor
->IsMarginPortion() )
967 if ( pCurr
->IsSpaceAdd() )
969 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
970 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
975 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->Count() )
978 if ( !pPor
->IsFlyPortion() || ( pPor
->GetPortion() &&
979 !pPor
->GetPortion()->IsMarginPortion() ) )
980 nX
+= pPor
->PrtWidth();
982 if( pPor
->IsMultiPortion() &&
983 ((SwMultiPortion
*)pPor
)->HasTabulator() )
985 if ( pCurr
->IsSpaceAdd() )
987 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
988 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
993 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->Count() )
996 if( !pPor
->IsFlyPortion() )
998 nPorHeight
= pPor
->Height();
999 nPorAscent
= pPor
->GetAscent();
1001 pPor
= pPor
->GetPortion();
1004 if( aInf
.GetIdx() == nOfst
&& pPor
&& pPor
->InHyphGrp() &&
1005 pPor
->GetPortion() && pPor
->GetPortion()->InFixGrp() )
1007 // Alle Sonderportions muessen uebersprungen werden
1008 // Beispiel: zu-[FLY]sammen, 'u' == 19, 's' == 20; Right()
1009 // Ohne den Ausgleich landen wir vor '-' mit dem
1010 // Ausgleich vor 's'.
1011 while( pPor
&& !pPor
->GetLen() )
1014 nX
+= pPor
->Width();
1015 if( !pPor
->IsMarginPortion() )
1017 nPorHeight
= pPor
->Height();
1018 nPorAscent
= pPor
->GetAscent();
1020 pPor
= pPor
->GetPortion();
1025 if( pCMS
->bFieldInfo
&& pPor
->InFldGrp() && pPor
->Width() )
1026 pOrig
->Width( pPor
->Width() );
1027 if( pPor
->IsDropPortion() )
1029 nPorAscent
= ((SwDropPortion
*)pPor
)->GetDropHeight();
1030 // The drop height is only calculated, if we have more than
1031 // one line. Otherwise it is 0.
1033 nPorAscent
= pPor
->Height();
1034 nPorHeight
= nPorAscent
;
1035 pOrig
->Height( nPorHeight
+
1036 ((SwDropPortion
*)pPor
)->GetDropDescent() );
1037 if( nTmpHeight
< pOrig
->Height() )
1039 nTmpAscent
= nPorAscent
;
1040 nTmpHeight
= USHORT( pOrig
->Height() );
1043 if( bWidth
&& pPor
->PrtWidth() && pPor
->GetLen() &&
1044 aInf
.GetIdx() == nOfst
)
1046 if( !pPor
->IsFlyPortion() && pPor
->Height() &&
1049 nPorHeight
= pPor
->Height();
1050 nPorAscent
= pPor
->GetAscent();
1053 if( 2 > pPor
->GetLen() )
1055 nTmp
= pPor
->Width();
1056 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
1057 nTmp
+= pPor
->CalcSpacing( nSpaceAdd
, aInf
);
1061 const sal_Bool bOldOnWin
= aInf
.OnWin();
1062 xub_StrLen nOldLen
= pPor
->GetLen();
1064 aInf
.SetLen( pPor
->GetLen() );
1066 aInf
.SetOnWin( sal_False
); // keine BULLETs!
1067 aInf
.SetKanaComp( pKanaComp
);
1068 aInf
.SetKanaIdx( nKanaIdx
);
1069 nTmp
= pPor
->GetTxtSize( aInf
).Width();
1070 aInf
.SetOnWin( bOldOnWin
);
1071 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
1072 nTmp
+= pPor
->CalcSpacing( nSpaceAdd
, aInf
);
1073 pPor
->SetLen( nOldLen
);
1075 pOrig
->Width( nTmp
);
1078 // travel inside field portion?
1079 if ( pCMS
->pSpecialPos
)
1081 // apply attributes to font
1083 lcl_GetCharRectInsideField( aInf
, *pOrig
, *pCMS
, *pPor
);
1088 // special case: We are at the beginning of a BidiPortion or
1089 // directly behind a BidiPortion
1093 pPor
->IsMultiPortion() &&
1094 ((SwMultiPortion
*)pPor
)->IsBidi() ) ) )
1096 // we determine if the cursor has to blink before or behind
1100 const BYTE nPortionLevel
= pLastBidiPor
->GetLevel();
1102 if ( pCMS
->nCursorBidiLevel
>= nPortionLevel
)
1104 // we came from inside the bidi portion, we want to blink
1105 // behind the portion
1106 pOrig
->Pos().X() -= nLastBidiPorWidth
;
1108 // Again, there is a special case: logically behind
1109 // the portion can actually mean that the cursor is inside
1110 // the portion. This can happen is the last portion
1111 // inside the bidi portion is a nested bidi portion
1112 SwLineLayout
& rLineLayout
=
1113 ((SwMultiPortion
*)pLastBidiPor
)->GetRoot();
1115 const SwLinePortion
*pLast
= rLineLayout
.FindLastPortion();
1116 if ( pLast
->IsMultiPortion() )
1118 ASSERT( ((SwMultiPortion
*)pLast
)->IsBidi(),
1119 "Non-BidiPortion inside BidiPortion" )
1120 pOrig
->Pos().X() += pLast
->Width() +
1121 pLast
->CalcSpacing( nSpaceAdd
, aInf
);
1127 const BYTE nPortionLevel
= ((SwBidiPortion
*)pPor
)->GetLevel();
1129 if ( pCMS
->nCursorBidiLevel
>= nPortionLevel
)
1131 // we came from inside the bidi portion, we want to blink
1132 // behind the portion
1133 pOrig
->Pos().X() += pPor
->Width() +
1134 pPor
->CalcSpacing( nSpaceAdd
, aInf
);
1139 pOrig
->Pos().X() += nX
;
1141 if ( pCMS
&& pCMS
->bRealHeight
)
1143 nTmpAscent
= AdjustBaseLine( *pCurr
, 0, nPorHeight
, nPorAscent
);
1144 if ( nTmpAscent
> nPorAscent
)
1145 pCMS
->aRealHeight
.X() = nTmpAscent
- nPorAscent
;
1147 pCMS
->aRealHeight
.X() = 0;
1148 ASSERT( nPorHeight
, "GetCharRect: Missing Portion-Height" );
1149 if ( nTmpHeight
> nPorHeight
)
1150 pCMS
->aRealHeight
.Y() = nPorHeight
;
1152 pCMS
->aRealHeight
.Y() = nTmpHeight
;
1157 /*************************************************************************
1158 * SwTxtCursor::GetCharRect()
1159 *************************************************************************/
1161 sal_Bool
SwTxtCursor::GetCharRect( SwRect
* pOrig
, const xub_StrLen nOfst
,
1162 SwCrsrMoveState
* pCMS
, const long nMax
)
1164 CharCrsrToLine(nOfst
);
1166 // Indicates that a position inside a special portion (field, number portion)
1168 const sal_Bool bSpecialPos
= pCMS
&& pCMS
->pSpecialPos
;
1169 xub_StrLen nFindOfst
= nOfst
;
1173 const BYTE nExtendRange
= pCMS
->pSpecialPos
->nExtendRange
;
1175 ASSERT( ! pCMS
->pSpecialPos
->nLineOfst
|| SP_EXTEND_RANGE_BEFORE
!= nExtendRange
,
1176 "LineOffset AND Number Portion?" )
1178 // portions which are behind the string
1179 if ( SP_EXTEND_RANGE_BEHIND
== nExtendRange
)
1182 // skip lines for fields which cover more than one line
1183 for ( USHORT i
= 0; i
< pCMS
->pSpecialPos
->nLineOfst
; i
++ )
1187 // Adjustierung ggf. nachholen
1190 const Point
aCharPos( GetTopLeft() );
1191 sal_Bool bRet
= sal_True
;
1193 _GetCharRect( pOrig
, nFindOfst
, pCMS
);
1195 const SwTwips nTmpRight
= Right() - 12;
1197 pOrig
->Pos().X() += aCharPos
.X();
1198 pOrig
->Pos().Y() += aCharPos
.Y();
1200 if( pCMS
&& pCMS
->b2Lines
&& pCMS
->p2Lines
)
1202 pCMS
->p2Lines
->aLine
.Pos().X() += aCharPos
.X();
1203 pCMS
->p2Lines
->aLine
.Pos().Y() += aCharPos
.Y();
1204 pCMS
->p2Lines
->aPortion
.Pos().X() += aCharPos
.X();
1205 pCMS
->p2Lines
->aPortion
.Pos().Y() += aCharPos
.Y();
1208 if( pOrig
->Left() > nTmpRight
)
1209 pOrig
->Pos().X() = nTmpRight
;
1213 if( pOrig
->Top() + pOrig
->Height() > nMax
)
1215 if( pOrig
->Top() > nMax
)
1217 pOrig
->Height( nMax
- pOrig
->Top() );
1219 if ( pCMS
&& pCMS
->bRealHeight
&& pCMS
->aRealHeight
.Y() >= 0 )
1221 long nTmp
= pCMS
->aRealHeight
.X() + pOrig
->Top();
1224 pCMS
->aRealHeight
.X() = nMax
- pOrig
->Top();
1225 pCMS
->aRealHeight
.Y() = 0;
1227 else if( nTmp
+ pCMS
->aRealHeight
.Y() > nMax
)
1228 pCMS
->aRealHeight
.Y() = nMax
- nTmp
;
1231 long nOut
= pOrig
->Right() - GetTxtFrm()->Frm().Right();
1234 if( GetTxtFrm()->Frm().Width() < GetTxtFrm()->Prt().Left()
1235 + GetTxtFrm()->Prt().Width() )
1236 nOut
+= GetTxtFrm()->Frm().Width() - GetTxtFrm()->Prt().Left()
1237 - GetTxtFrm()->Prt().Width();
1239 pOrig
->Pos().X() -= nOut
+ 10;
1244 /*************************************************************************
1245 * SwTxtCursor::GetCrsrOfst()
1247 * Return: Offset im String
1248 *************************************************************************/
1249 xub_StrLen
SwTxtCursor::GetCrsrOfst( SwPosition
*pPos
, const Point
&rPoint
,
1250 const MSHORT nChgNode
, SwCrsrMoveState
* pCMS
) const
1252 // Adjustierung ggf. nachholen
1255 const XubString
&rText
= GetInfo().GetTxt();
1256 xub_StrLen nOffset
= 0;
1258 // x ist der horizontale Offset innerhalb der Zeile.
1259 SwTwips x
= rPoint
.X();
1260 CONST SwTwips nLeftMargin
= GetLineStart();
1261 SwTwips nRightMargin
= GetLineEnd();
1262 if( nRightMargin
== nLeftMargin
)
1265 const sal_Bool bLeftOver
= x
< nLeftMargin
;
1268 const sal_Bool bRightOver
= x
> nRightMargin
;
1272 sal_Bool bRightAllowed
= pCMS
&& ( pCMS
->eState
== MV_NONE
);
1274 // Bis hierher in Dokumentkoordinaten.
1277 KSHORT nX
= KSHORT( x
);
1279 // Wenn es in der Zeile Attributwechsel gibt, den Abschnitt
1280 // suchen, in dem nX liegt.
1281 SwLinePortion
*pPor
= pCurr
->GetFirstPortion();
1282 xub_StrLen nCurrStart
= nStart
;
1283 sal_Bool bHolePortion
= sal_False
;
1284 sal_Bool bLastHyph
= sal_False
;
1286 SvUShorts
*pKanaComp
= pCurr
->GetpKanaComp();
1287 xub_StrLen nOldIdx
= GetInfo().GetIdx();
1288 MSHORT nSpaceIdx
= 0;
1289 MSHORT nKanaIdx
= 0;
1290 long nSpaceAdd
= pCurr
->IsSpaceAdd() ? pCurr
->GetLLSpaceAdd( 0 ) : 0;
1291 short nKanaComp
= pKanaComp
? (*pKanaComp
)[0] : 0;
1293 // nWidth ist die Breite der Zeile, oder die Breite des
1294 // Abschnitts mit dem Fontwechsel, in dem nX liegt.
1296 KSHORT nWidth
= pPor
->Width();
1297 if ( pCurr
->IsSpaceAdd() || pKanaComp
)
1299 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
1301 ((SwTxtSizeInfo
&)GetInfo()).SetIdx( nCurrStart
);
1302 nWidth
= nWidth
+ USHORT( pPor
->CalcSpacing( nSpaceAdd
, GetInfo() ) );
1304 if( ( pPor
->InFixMargGrp() && ! pPor
->IsMarginPortion() ) ||
1305 ( pPor
->IsMultiPortion() && ((SwMultiPortion
*)pPor
)->HasTabulator() )
1308 if ( pCurr
->IsSpaceAdd() )
1310 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
1311 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
1318 if ( nKanaIdx
+ 1 < pKanaComp
->Count() )
1319 nKanaComp
= (*pKanaComp
)[++nKanaIdx
];
1327 if ( pPor
->IsPostItsPortion() )
1328 nWidth30
= 30 + pPor
->GetViewWidth( GetInfo() ) / 2;
1330 nWidth30
= ! nWidth
&& pPor
->GetLen() && pPor
->InToxRefOrFldGrp() ?
1334 while( pPor
->GetPortion() && nWidth30
< nX
&& !pPor
->IsBreakPortion() )
1337 nCurrStart
= nCurrStart
+ pPor
->GetLen();
1338 bHolePortion
= pPor
->IsHolePortion();
1339 pPor
= pPor
->GetPortion();
1340 nWidth
= pPor
->Width();
1341 if ( pCurr
->IsSpaceAdd() || pKanaComp
)
1343 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
1345 ((SwTxtSizeInfo
&)GetInfo()).SetIdx( nCurrStart
);
1346 nWidth
= nWidth
+ USHORT( pPor
->CalcSpacing( nSpaceAdd
, GetInfo() ) );
1349 if( ( pPor
->InFixMargGrp() && ! pPor
->IsMarginPortion() ) ||
1350 ( pPor
->IsMultiPortion() && ((SwMultiPortion
*)pPor
)->HasTabulator() )
1353 if ( pCurr
->IsSpaceAdd() )
1355 if ( ++nSpaceIdx
< pCurr
->GetLLSpaceAddCount() )
1356 nSpaceAdd
= pCurr
->GetLLSpaceAdd( nSpaceIdx
);
1363 if( nKanaIdx
+ 1 < pKanaComp
->Count() )
1364 nKanaComp
= (*pKanaComp
)[++nKanaIdx
];
1371 if ( pPor
->IsPostItsPortion() )
1372 nWidth30
= 30 + pPor
->GetViewWidth( GetInfo() ) / 2;
1374 nWidth30
= ! nWidth
&& pPor
->GetLen() && pPor
->InToxRefOrFldGrp() ?
1377 if( !pPor
->IsFlyPortion() && !pPor
->IsMarginPortion() )
1378 bLastHyph
= pPor
->InHyphGrp();
1381 const sal_Bool bLastPortion
= (0 == pPor
->GetPortion());
1385 SwLinePortion
*pNextPor
= pPor
->GetPortion();
1386 while( pNextPor
&& pNextPor
->InFldGrp() && !pNextPor
->Width() )
1388 nCurrStart
= nCurrStart
+ pPor
->GetLen();
1390 if( !pPor
->IsFlyPortion() && !pPor
->IsMarginPortion() )
1391 bLastHyph
= pPor
->InHyphGrp();
1392 pNextPor
= pPor
->GetPortion();
1396 ((SwTxtSizeInfo
&)GetInfo()).SetIdx( nOldIdx
);
1398 xub_StrLen nLength
= pPor
->GetLen();
1400 sal_Bool bFieldInfo
= pCMS
&& pCMS
->bFieldInfo
;
1402 if( bFieldInfo
&& ( nWidth30
< nX
|| bRightOver
|| bLeftOver
||
1403 ( pPor
->InNumberGrp() && !pPor
->IsFtnNumPortion() ) ||
1404 ( pPor
->IsMarginPortion() && nWidth
> nX
+ 30 ) ) )
1405 ((SwCrsrMoveState
*)pCMS
)->bPosCorr
= sal_True
;
1411 if( pCMS
->bInFrontOfLabel
)
1413 if (! (2 * nX
< nWidth
&& pPor
->InNumberGrp() &&
1414 !pPor
->IsFtnNumPortion()))
1415 pCMS
->bInFrontOfLabel
= sal_False
;
1419 // 7684: Wir sind genau auf der HyphPortion angelangt und muessen dafuer
1420 // sorgen, dass wir in dem String landen.
1421 // 7993: Wenn die Laenge 0 ist muessen wir raus...
1426 if( pPor
->IsFlyPortion() && bFieldInfo
)
1427 ((SwCrsrMoveState
*)pCMS
)->bPosCorr
= sal_True
;
1429 if (!bRightOver
&& nX
)
1431 if( pPor
->IsFtnNumPortion())
1432 ((SwCrsrMoveState
*)pCMS
)->bFtnNoInfo
= sal_True
;
1433 else if (pPor
->InNumberGrp() ) // #i23726#
1435 ((SwCrsrMoveState
*)pCMS
)->nInNumPostionOffset
= nX
;
1436 ((SwCrsrMoveState
*)pCMS
)->bInNumPortion
= sal_True
;
1443 // 7849, 7816: auf pPor->GetHyphPortion kann nicht verzichtet werden!
1444 if( bHolePortion
|| ( !bRightAllowed
&& bLastHyph
) ||
1445 ( pPor
->IsMarginPortion() && !pPor
->GetPortion() &&
1446 // 46598: In der letzten Zeile eines zentrierten Absatzes wollen
1447 // wir auch mal hinter dem letzten Zeichen landen.
1448 nCurrStart
< rText
.Len() ) )
1450 else if( pPor
->InFldGrp() && ((SwFldPortion
*)pPor
)->IsFollow()
1457 KSHORT nHeight
= pPor
->Height();
1458 if ( !nHeight
|| nHeight
> nWidth
)
1460 if( nChgNode
&& nWidth
- nHeight
/2 > nX
)
1470 // Sonst kommen wir nicht mehr in zeichengeb. Rahmen hinein...
1471 if( !( nChgNode
&& pPos
&& pPor
->IsFlyCntPortion() ) )
1473 if ( pPor
->InFldGrp() ||
1474 ( pPor
->IsMultiPortion() &&
1475 ((SwMultiPortion
*)pPor
)->IsBidi() ) )
1480 nHeight
= pPor
->Height();
1481 if ( !nHeight
|| nHeight
> nWidth
)
1485 if( nWidth
- nHeight
/2 <= nX
&&
1486 ( ! pPor
->InFldGrp() ||
1487 !((SwFldPortion
*)pPor
)->HasFollow() ) )
1490 else if ( ( !pPor
->IsFlyPortion() || ( pPor
->GetPortion() &&
1491 !pPor
->GetPortion()->IsMarginPortion() &&
1492 !pPor
->GetPortion()->IsHolePortion() ) )
1493 && ( nWidth
/2 < nX
) &&
1495 ( pPor
->GetPortion() &&
1496 pPor
->GetPortion()->IsPostItsPortion() ) )
1497 && ( bRightAllowed
|| !bLastHyph
))
1500 // if we want to get the position inside the field, we should not return
1501 if ( !pCMS
|| !pCMS
->pSpecialPos
)
1507 if ( pPor
->IsPostItsPortion() || pPor
->IsBreakPortion() ||
1508 pPor
->InToxRefGrp() )
1510 if ( pPor
->InFldGrp() )
1512 if( bRightOver
&& !((SwFldPortion
*)pPor
)->HasFollow() )
1519 if( bLastPortion
&& (pCurr
->GetNext() || pFrm
->GetFollow() ) )
1523 ( nWidth
== nX
&& pPor
->IsMultiPortion() && ((SwMultiPortion
*)pPor
)->IsDouble() ) )
1525 if( pPor
->IsMultiPortion() )
1527 // In a multi-portion we use GetCrsrOfst()-function recursively
1528 SwTwips nTmpY
= rPoint
.Y() - pCurr
->GetAscent() + pPor
->GetAscent();
1529 // if we are in the first line of a double line portion, we have
1530 // to add a value to nTmpY for not staying in this line
1531 // we also want to skip the first line, if we are inside ruby
1532 if ( ( ((SwTxtSizeInfo
*)pInf
)->IsMulti() &&
1533 ((SwTxtSizeInfo
*)pInf
)->IsFirstMulti() ) ||
1534 ( ((SwMultiPortion
*)pPor
)->IsRuby() &&
1535 ((SwMultiPortion
*)pPor
)->OnTop() ) )
1536 nTmpY
+= ((SwMultiPortion
*)pPor
)->Height();
1538 // Important for cursor traveling in ruby portions:
1539 // We have to set nTmpY to 0 in order to stay in the first row
1540 // if the phonetic line is the second row
1541 if ( ((SwMultiPortion
*)pPor
)->IsRuby() &&
1542 ! ((SwMultiPortion
*)pPor
)->OnTop() )
1545 SwTxtCursorSave
aSave( (SwTxtCursor
*)this, (SwMultiPortion
*)pPor
,
1546 nTmpY
, nX
, nCurrStart
, nSpaceAdd
);
1548 SwLayoutModeModifier
aLayoutModeModifier( *GetInfo().GetOut() );
1549 if ( ((SwMultiPortion
*)pPor
)->IsBidi() )
1551 const BYTE nBidiLevel
= ((SwBidiPortion
*)pPor
)->GetLevel();
1552 aLayoutModeModifier
.Modify( nBidiLevel
% 2 );
1555 if( ((SwMultiPortion
*)pPor
)->HasRotation() )
1558 if( !((SwMultiPortion
*)pPor
)->IsRevers() )
1559 nTmpY
= pPor
->Height() - nTmpY
;
1565 if( ((SwMultiPortion
*)pPor
)->HasBrackets() )
1567 USHORT nPreWidth
= ((SwDoubleLinePortion
*)pPor
)->PreWidth();
1568 if ( nX
> nPreWidth
)
1569 nX
= nX
- nPreWidth
;
1574 return GetCrsrOfst( pPos
, Point( GetLineStart() + nX
, rPoint
.Y() ),
1577 if( pPor
->InTxtGrp() )
1582 ((SwFont
*)GetFnt())->SetProportion( GetPropFont() );
1583 nOldProp
= GetFnt()->GetPropr();
1588 SwTxtSizeInfo
aSizeInf( GetInfo(), rText
, nCurrStart
);
1589 ((SwTxtCursor
*)this)->SeekAndChg( aSizeInf
);
1590 SwTxtSlot
aDiffTxt( &aSizeInf
, ((SwTxtPortion
*)pPor
), false, false );
1591 SwFontSave
aSave( aSizeInf
, pPor
->IsDropPortion() ?
1592 ((SwDropPortion
*)pPor
)->GetFnt() : NULL
);
1594 SwParaPortion
* pPara
= (SwParaPortion
*)GetInfo().GetParaPortion();
1595 ASSERT( pPara
, "No paragraph!" );
1597 SwDrawTextInfo
aDrawInf( aSizeInf
.GetVsh(),
1599 &pPara
->GetScriptInfo(),
1603 aDrawInf
.SetOfst( nX
);
1607 xub_StrLen nCharCnt
;
1608 // --> FME 2005-04-04 #i41860# Thai justified alignemt needs some
1609 // additional information:
1610 aDrawInf
.SetNumberOfBlanks( pPor
->InTxtGrp() ?
1611 static_cast<const SwTxtPortion
*>(pPor
)->GetSpaceCnt( aSizeInf
, nCharCnt
) :
1616 if ( pPor
->InFldGrp() && pCMS
&& pCMS
->pSpecialPos
)
1617 aDrawInf
.SetLen( STRING_LEN
); // SMARTTAGS
1619 aDrawInf
.SetSpace( nSpaceAdd
);
1620 aDrawInf
.SetFont( aSizeInf
.GetFont() );
1621 aDrawInf
.SetFrm( pFrm
);
1622 aDrawInf
.SetSnapToGrid( aSizeInf
.SnapToGrid() );
1623 aDrawInf
.SetPosMatchesBounds( pCMS
&& pCMS
->bPosMatchesBounds
);
1625 if ( SW_CJK
== aSizeInf
.GetFont()->GetActual() &&
1626 pPara
->GetScriptInfo().CountCompChg() &&
1627 ! pPor
->InFldGrp() )
1628 aDrawInf
.SetKanaComp( nKanaComp
);
1630 nLength
= aSizeInf
.GetFont()->_GetCrsrOfst( aDrawInf
);
1632 // get position inside field portion?
1633 if ( pPor
->InFldGrp() && pCMS
&& pCMS
->pSpecialPos
)
1635 pCMS
->pSpecialPos
->nCharOfst
= nLength
;
1636 nLength
= 0; // SMARTTAGS
1639 // set cursor bidi level
1641 ((SwCrsrMoveState
*)pCMS
)->nCursorBidiLevel
=
1642 aDrawInf
.GetCursorBidiLevel();
1644 if( bFieldInfo
&& nLength
== pPor
->GetLen() &&
1645 ( ! pPor
->GetPortion() ||
1646 ! pPor
->GetPortion()->IsPostItsPortion() ) )
1650 ((SwFont
*)GetFnt())->SetProportion( nOldProp
);
1654 if( nChgNode
&& pPos
&& pPor
->IsFlyCntPortion()
1655 && !( (SwFlyCntPortion
*)pPor
)->IsDraw() )
1657 // JP 24.11.94: liegt die Pos nicht im Fly, dann
1658 // darf nicht mit STRING_LEN returnt werden!
1659 // (BugId: 9692 + Aenderung in feshview)
1660 SwFlyInCntFrm
*pTmp
= ( (SwFlyCntPortion
*)pPor
)->GetFlyFrm();
1661 sal_Bool bChgNode
= 1 < nChgNode
;
1664 SwFrm
* pLower
= pTmp
->GetLower();
1665 if( pLower
&& (pLower
->IsTxtFrm() || pLower
->IsLayoutFrm()) )
1666 bChgNode
= sal_True
;
1668 Point
aTmpPoint( rPoint
);
1670 if ( pFrm
->IsRightToLeft() )
1671 pFrm
->SwitchLTRtoRTL( aTmpPoint
);
1673 if ( pFrm
->IsVertical() )
1674 pFrm
->SwitchHorizontalToVertical( aTmpPoint
);
1676 if( bChgNode
&& pTmp
->Frm().IsInside( aTmpPoint
) &&
1677 !( pTmp
->IsProtected() ) )
1679 nLength
= ((SwFlyCntPortion
*)pPor
)->
1680 GetFlyCrsrOfst( nX
, aTmpPoint
, pPos
, pCMS
);
1681 // Sobald der Frame gewechselt wird, muessen wir aufpassen, dass
1682 // unser Font wieder im OutputDevice steht.
1683 // vgl. Paint und new SwFlyCntPortion !
1684 ((SwTxtSizeInfo
*)pInf
)->SelectFont();
1686 // 6776: Das pIter->GetCrsrOfst returnt
1687 // aus einer Verschachtelung mit STRING_LEN.
1692 nLength
= pPor
->GetCrsrOfst( nX
);
1695 nOffset
= nCurrStart
+ nLength
;
1697 // 7684: Wir sind vor der HyphPortion angelangt und muessen dafuer
1698 // sorgen, dass wir in dem String landen.
1699 // Bei Zeilenenden vor FlyFrms muessen ebenso behandelt werden.
1701 if( nOffset
&& pPor
->GetLen() == nLength
&& pPor
->GetPortion() &&
1702 !pPor
->GetPortion()->GetLen() && pPor
->GetPortion()->InHyphGrp() )
1708 /** Looks for text portions which are inside the given rectangle
1710 For a rectangular text selection every text portions which is inside the given
1711 rectangle has to be put into the SwSelectionList as SwPaM
1712 From these SwPaM the SwCursors will be created.
1715 The container for the overlapped text portions
1718 A rectangle in document coordinates, text inside this rectangle has to be
1721 @return [ true, false ]
1722 true if any overlapping text portion has been found and put into list
1723 false if no portion overlaps, the list has been unchanged
1725 bool SwTxtFrm::FillSelection( SwSelectionList
& rSelList
, const SwRect
& rRect
) const
1728 // PaintArea() instead Frm() for negative indents
1729 SwRect
aTmpFrm( PaintArea() );
1730 if( !rRect
.IsOver( aTmpFrm
) )
1732 if( rSelList
.checkContext( this ) )
1734 SwRect
aRect( aTmpFrm
);
1735 aRect
.Intersection( rRect
);
1736 // rNode without const to create SwPaMs
1737 SwCntntNode
&rNode
= const_cast<SwCntntNode
&>( *GetNode() );
1738 SwNodeIndex
aIdx( rNode
);
1739 SwPosition
aPosL( aIdx
, SwIndex( &rNode
, 0 ) );
1742 SwPaM
*pPam
= new SwPaM( aPosL
, aPosL
);
1743 rSelList
.insertPaM( pPam
);
1745 else if( aRect
.HasArea() )
1747 xub_StrLen nOld
= STRING_LEN
;
1748 SwPosition
aPosR( aPosL
);
1750 SwTxtInfo
aInf( const_cast<SwTxtFrm
*>(this) );
1751 SwTxtIter
aLine( const_cast<SwTxtFrm
*>(this), &aInf
);
1752 // We have to care for top-to-bottom layout, where right becomes top etc.
1754 SwTwips nTop
= (aRect
.*fnRect
->fnGetTop
)();
1755 SwTwips nBottom
= (aRect
.*fnRect
->fnGetBottom
)();
1756 SwTwips nLeft
= (aRect
.*fnRect
->fnGetLeft
)();
1757 SwTwips nRight
= (aRect
.*fnRect
->fnGetRight
)();
1758 SwTwips nY
= aLine
.Y(); // Top position of the first line
1759 SwTwips nLastY
= nY
;
1760 while( nY
< nTop
&& aLine
.Next() ) // line above rectangle
1765 bool bLastLine
= false;
1766 if( nY
< nTop
&& !aLine
.GetNext() )
1769 nY
+= aLine
.GetLineHeight();
1771 do // check the lines for overlapping
1773 if( nLastY
< nTop
) // if the last line was above rectangle
1775 if( nY
> nBottom
) // if the current line leaves the rectangle
1777 if( nY
>= nLastY
) // gotcha: overlapping
1783 aPoint
.X() = nLastY
;
1789 aPoint
.Y() = nLastY
;
1791 // Looking for the position of the left border of the rectangle
1792 // in this text line
1793 SwCrsrMoveState
aState( MV_UPDOWN
);
1794 if( GetCrsrOfst( &aPosL
, aPoint
, &aState
) )
1798 aPoint
.X() = nLastY
;
1799 aPoint
.Y() = nRight
;
1803 aPoint
.X() = nRight
;
1804 aPoint
.Y() = nLastY
;
1806 // If we get a right position and if the left position
1807 // is not the same like the left position of the line before
1808 // which cound happen e.g. for field portions or fly frames
1809 // a SwPaM will be inserted with these positions
1810 if( GetCrsrOfst( &aPosR
, aPoint
, &aState
) &&
1811 nOld
!= aPosL
.nContent
.GetIndex() )
1813 SwPaM
*pPam
= new SwPaM( aPosL
, aPosR
);
1814 rSelList
.insertPaM( pPam
);
1815 nOld
= aPosL
.nContent
.GetIndex();
1824 else if( !bLastLine
)
1828 nY
+= aLine
.GetLineHeight();
1832 }while( nLastY
< nBottom
);
1837 const SwSortedObjs
&rObjs
= *GetDrawObjs();
1838 for ( USHORT i
= 0; i
< rObjs
.Count(); ++i
)
1840 const SwAnchoredObject
* pAnchoredObj
= rObjs
[i
];
1841 if( !pAnchoredObj
->ISA(SwFlyFrm
) )
1843 const SwFlyFrm
* pFly
= static_cast<const SwFlyFrm
*>(pAnchoredObj
);
1844 if( pFly
->IsFlyInCntFrm() && pFly
->FillSelection( rSelList
, rRect
) )