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 .
25 #include <swselectionlist.hxx>
26 #include <sortedobjs.hxx>
27 #include <editeng/adjustitem.hxx>
28 #include <editeng/lspcitem.hxx>
29 #include <editeng/lrspitem.hxx>
31 #include <tgrditem.hxx>
32 #include <IDocumentSettingAccess.hxx>
33 #include <pagefrm.hxx>
37 #include <flyfrms.hxx>
40 #include "pordrop.hxx"
41 #include <crstate.hxx>
42 #include "pormulti.hxx"
43 #include <numrule.hxx>
44 #include <com/sun/star/i18n/ScriptType.hpp>
47 // is set in GetCharRect and is interpreted in UnitUp/Down.
48 bool SwTextCursor::s_bRightMargin
= false;
50 // After calculating the position of a character during GetCharRect
51 // this function allows to find the coordinates of a position (defined
52 // in pCMS->pSpecialPos) inside a special portion (e.g., a field)
53 static void lcl_GetCharRectInsideField( SwTextSizeInfo
& rInf
, SwRect
& rOrig
,
54 const SwCursorMoveState
& rCMS
,
55 const SwLinePortion
& rPor
)
57 OSL_ENSURE( rCMS
.m_pSpecialPos
, "Information about special pos missing" );
59 if ( rPor
.InFieldGrp() && !static_cast<const SwFieldPortion
&>(rPor
).GetExp().isEmpty() )
61 const sal_Int32 nCharOfst
= rCMS
.m_pSpecialPos
->nCharOfst
;
62 sal_Int32 nFieldIdx
= 0;
63 sal_Int32 nFieldLen
= 0;
66 const OUString
* pString
= nullptr;
67 const SwLinePortion
* pPor
= &rPor
;
70 if ( pPor
->InFieldGrp() )
72 sString
= static_cast<const SwFieldPortion
*>(pPor
)->GetExp();
74 nFieldLen
= pString
->getLength();
82 if ( ! pPor
->GetNextPortion() || nFieldIdx
+ nFieldLen
> nCharOfst
)
85 nFieldIdx
= nFieldIdx
+ nFieldLen
;
86 rOrig
.Pos().AdjustX(pPor
->Width() );
87 pPor
= pPor
->GetNextPortion();
91 OSL_ENSURE( nCharOfst
>= nFieldIdx
, "Request of position inside field failed" );
92 sal_Int32 nLen
= nCharOfst
- nFieldIdx
+ 1;
96 // get script for field portion
97 rInf
.GetFont()->SetActual( SwScriptInfo::WhichFont(0, *pString
) );
99 TextFrameIndex
const nOldLen
= pPor
->GetLen();
100 const_cast<SwLinePortion
*>(pPor
)->SetLen(TextFrameIndex(nLen
- 1));
101 const SwTwips nX1
= pPor
->GetLen() ?
102 pPor
->GetTextSize( rInf
).Width() :
106 if ( rCMS
.m_bRealWidth
)
108 const_cast<SwLinePortion
*>(pPor
)->SetLen(TextFrameIndex(nLen
));
109 nX2
= pPor
->GetTextSize( rInf
).Width();
112 const_cast<SwLinePortion
*>(pPor
)->SetLen( nOldLen
);
114 rOrig
.Pos().AdjustX(nX1
);
115 rOrig
.Width( ( nX2
> nX1
) ?
122 // special cases: no common fields, e.g., graphic number portion,
123 // FlyInCntPortions, Notes
124 rOrig
.Width( rCMS
.m_bRealWidth
&& rPor
.Width() ? rPor
.Width() : 1 );
130 bool IsLabelAlignmentActive( const SwTextNode
& rTextNode
)
134 if ( rTextNode
.GetNumRule() )
136 int nListLevel
= rTextNode
.GetActualListLevel();
141 if (nListLevel
>= MAXLEVEL
)
142 nListLevel
= MAXLEVEL
- 1;
144 const SwNumFormat
& rNumFormat
=
145 rTextNode
.GetNumRule()->Get( o3tl::narrowing
<sal_uInt16
>(nListLevel
) );
146 if ( rNumFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT
)
154 } // end of anonymous namespace
156 void SwTextMargin::CtorInitTextMargin( SwTextFrame
*pNewFrame
, SwTextSizeInfo
*pNewInf
)
158 CtorInitTextIter( pNewFrame
, pNewInf
);
161 GetInfo().SetFont( GetFnt() );
162 const SwTextNode
*const pNode
= m_pFrame
->GetTextNodeForParaProps();
164 SvxFirstLineIndentItem
const& rFirstLine(pNode
->GetSwAttrSet().GetFirstLineIndent());
165 SvxTextLeftMarginItem
const& rTextLeftMargin(pNode
->GetSwAttrSet().GetTextLeftMargin());
168 const SwTextNode
*pTextNode
= m_pFrame
->GetTextNodeForParaProps();
169 const bool bLabelAlignmentActive
= IsLabelAlignmentActive( *pTextNode
);
170 const bool bListLevelIndentsApplicable
= pTextNode
->AreListLevelIndentsApplicable() != ::sw::ListLevelIndents::No
;
171 const bool bListLevelIndentsApplicableAndLabelAlignmentActive
= bListLevelIndentsApplicable
&& bLabelAlignmentActive
;
173 // Carefully adjust the text formatting ranges.
175 // This whole area desperately needs some rework. There are
176 // quite a couple of values that need to be considered:
177 // 1. paragraph indent
178 // 2. paragraph first line indent
179 // 3. numbering indent
180 // 4. numbering spacing to text
181 // 5. paragraph border
182 // Note: These values have already been used during calculation
183 // of the printing area of the paragraph.
184 const int nLMWithNum
= pNode
->GetLeftMarginWithNum( true );
185 if ( m_pFrame
->IsRightToLeft() )
187 // this calculation is identical this the calculation for L2R layout - see below
188 mnLeft
= m_pFrame
->getFrameArea().Left() +
189 m_pFrame
->getFramePrintArea().Left() +
191 pNode
->GetLeftMarginWithNum() -
194 // rSpace.GetLeft() + rSpace.GetTextLeft();
195 (rTextLeftMargin
.GetLeft(rFirstLine
) - rTextLeftMargin
.GetTextLeft());
201 if ( bListLevelIndentsApplicableAndLabelAlignmentActive
||
202 !pNode
->getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING
) )
204 // this calculation is identical this the calculation for R2L layout - see above
205 mnLeft
= m_pFrame
->getFrameArea().Left() +
206 m_pFrame
->getFramePrintArea().Left() +
208 pNode
->GetLeftMarginWithNum() -
211 (rTextLeftMargin
.GetLeft(rFirstLine
) - rTextLeftMargin
.GetTextLeft());
215 mnLeft
= m_pFrame
->getFrameArea().Left() +
216 std::max(tools::Long(rTextLeftMargin
.GetTextLeft() + nLMWithNum
),
217 m_pFrame
->getFramePrintArea().Left() );
221 mnRight
= m_pFrame
->getFrameArea().Left() + m_pFrame
->getFramePrintArea().Left() + m_pFrame
->getFramePrintArea().Width();
223 if( mnLeft
>= mnRight
&&
224 // #i53066# Omit adjustment of nLeft for numbered
225 // paras inside cells inside new documents:
226 ( pNode
->getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING
) ||
227 !m_pFrame
->IsInTab() ||
228 (bListLevelIndentsApplicable
&& nLMWithNum
== rTextLeftMargin
.GetTextLeft())
229 || (!bLabelAlignmentActive
&& nLMWithNum
== 0)))
231 mnLeft
= m_pFrame
->getFramePrintArea().Left() + m_pFrame
->getFrameArea().Left();
232 if( mnLeft
>= mnRight
) // e.g. with large paragraph indentations in slim table columns
233 mnRight
= mnLeft
+ 1; // einen goennen wir uns immer
236 if( m_pFrame
->IsFollow() && m_pFrame
->GetOffset() )
241 tools::Long nFirstLineOfs
= 0;
242 if( !pNode
->GetFirstLineOfsWithNum( nFLOfst
) &&
243 rFirstLine
.IsAutoFirst())
245 nFirstLineOfs
= GetFnt()->GetSize( GetFnt()->GetActual() ).Height();
246 LanguageType
const aLang
= m_pFrame
->GetLangOfChar(
247 TextFrameIndex(0), css::i18n::ScriptType::ASIAN
);
248 if (aLang
!= LANGUAGE_KOREAN
&& aLang
!= LANGUAGE_JAPANESE
)
251 // tdf#129448: Auto first-line indent should not be effected by line space.
252 // Below is for compatibility with old documents.
253 if (!pNode
->getIDocumentSettingAccess()->get(DocumentSettingId::AUTO_FIRST_LINE_INDENT_DISREGARD_LINE_SPACE
))
255 const SvxLineSpacingItem
*pSpace
= m_aLineInf
.GetLineSpacing();
258 switch( pSpace
->GetLineSpaceRule() )
260 case SvxLineSpaceRule::Auto
:
262 case SvxLineSpaceRule::Min
:
264 if( nFirstLineOfs
< pSpace
->GetLineHeight() )
265 nFirstLineOfs
= pSpace
->GetLineHeight();
268 case SvxLineSpaceRule::Fix
:
269 nFirstLineOfs
= pSpace
->GetLineHeight();
271 default: OSL_FAIL( ": unknown LineSpaceRule" );
273 switch( pSpace
->GetInterLineSpaceRule() )
275 case SvxInterLineSpaceRule::Off
:
277 case SvxInterLineSpaceRule::Prop
:
279 tools::Long nTmp
= pSpace
->GetPropLineSpace();
280 // 50% is the minimum, at 0% we switch to
281 // the default value 100%...
283 nTmp
= nTmp
? 50 : 100;
285 nTmp
*= nFirstLineOfs
;
289 nFirstLineOfs
= nTmp
;
292 case SvxInterLineSpaceRule::Fix
:
294 nFirstLineOfs
+= pSpace
->GetInterLineSpace();
297 default: OSL_FAIL( ": unknown InterLineSpaceRule" );
303 nFirstLineOfs
= nFLOfst
;
307 if ( m_pFrame
->IsRightToLeft() ||
308 bListLevelIndentsApplicableAndLabelAlignmentActive
||
309 !pNode
->getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING
) )
311 if ( nFirstLineOfs
< 0 && m_pFrame
->IsInTab() &&
312 mnLeft
== m_pFrame
->getFramePrintArea().Left() + m_pFrame
->getFrameArea().Left() &&
313 !m_pFrame
->IsRightToLeft() &&
314 !bListLevelIndentsApplicableAndLabelAlignmentActive
)
316 // tdf#130218 always show hanging indent in narrow table cells
317 // to avoid hiding the text content of the first line
318 mnLeft
-= nFirstLineOfs
;
321 mnFirst
= mnLeft
+ nFirstLineOfs
;
325 mnFirst
= m_pFrame
->getFrameArea().Left() +
326 std::max(rTextLeftMargin
.GetTextLeft() + nLMWithNum
+ nFirstLineOfs
,
327 m_pFrame
->getFramePrintArea().Left() );
330 // Note: <SwTextFrame::GetAdditionalFirstLineOffset()> returns a negative
331 // value for the new list label position and space mode LABEL_ALIGNMENT
332 // and label alignment CENTER and RIGHT in L2R layout respectively
333 // label alignment LEFT and CENTER in R2L layout
334 mnFirst
+= m_pFrame
->GetAdditionalFirstLineOffset();
336 if( mnFirst
>= mnRight
)
337 mnFirst
= mnRight
- 1;
339 const SvxAdjustItem
& rAdjust
= m_pFrame
->GetTextNodeForParaProps()->GetSwAttrSet().GetAdjust();
340 mnAdjust
= rAdjust
.GetAdjust();
342 // left is left and right is right
343 if ( m_pFrame
->IsRightToLeft() )
345 if ( SvxAdjust::Left
== mnAdjust
)
346 mnAdjust
= SvxAdjust::Right
;
347 else if ( SvxAdjust::Right
== mnAdjust
)
348 mnAdjust
= SvxAdjust::Left
;
351 m_bOneBlock
= rAdjust
.GetOneWord() == SvxAdjust::Block
;
352 m_bLastBlock
= rAdjust
.GetLastBlock() == SvxAdjust::Block
;
353 m_bLastCenter
= rAdjust
.GetLastBlock() == SvxAdjust::Center
;
356 mnTabLeft
= pNode
->GetLeftMarginForTabCalculation();
361 void SwTextMargin::DropInit()
363 mnDropLeft
= mnDropLines
= mnDropHeight
= mnDropDescent
= 0;
364 const SwParaPortion
*pPara
= GetInfo().GetParaPortion();
367 const SwDropPortion
*pPorDrop
= pPara
->FindDropPortion();
370 mnDropLeft
= pPorDrop
->GetDropLeft();
371 mnDropLines
= pPorDrop
->GetLines();
372 mnDropHeight
= pPorDrop
->GetDropHeight();
373 mnDropDescent
= pPorDrop
->GetDropDescent();
378 // The function is interpreting / observing / evaluating / keeping / respecting the first line indention and the specified width.
379 SwTwips
SwTextMargin::GetLineStart() const
381 SwTwips nRet
= GetLeftMargin();
382 if( GetAdjust() != SvxAdjust::Left
&&
383 !m_pCurr
->GetFirstPortion()->IsMarginPortion() )
385 // If the first portion is a Margin, then the
386 // adjustment is expressed by the portions.
387 if( GetAdjust() == SvxAdjust::Right
)
388 nRet
= Right() - CurrWidth();
389 else if( GetAdjust() == SvxAdjust::Center
)
390 nRet
+= (GetLineWidth() - CurrWidth()) / 2;
395 void SwTextCursor::CtorInitTextCursor( SwTextFrame
*pNewFrame
, SwTextSizeInfo
*pNewInf
)
397 CtorInitTextMargin( pNewFrame
, pNewInf
);
398 // 6096: Attention, the iterators are derived!
399 // GetInfo().SetOut( GetInfo().GetWin() );
402 // tdf#120715 tdf#43100: Make width for some HolePortions, so cursor will be able to move into it.
403 // It should not change the layout, so this should be called after the layout is calculated.
404 void SwTextCursor::AddExtraBlankWidth()
406 SwLinePortion
* pPos
= m_pCurr
->GetNextPortion();
407 SwLinePortion
* pNextPos
;
410 pNextPos
= pPos
->GetNextPortion();
411 // Do it only if it is the last portion that able to handle the cursor,
412 // else the next portion would miscalculate the cursor position
413 if (pPos
->ExtraBlankWidth() && (!pNextPos
|| pNextPos
->IsMarginPortion()))
415 pPos
->Width(pPos
->Width() + pPos
->ExtraBlankWidth());
416 pPos
->ExtraBlankWidth(0);
422 // 1170: Ancient bug: Shift-End forgets the last character ...
423 void SwTextCursor::GetEndCharRect(SwRect
* pOrig
, const TextFrameIndex nOfst
,
424 SwCursorMoveState
* pCMS
, const tools::Long nMax
)
426 // 1170: Ambiguity of document positions
427 s_bRightMargin
= true;
428 CharCursorToLine(nOfst
);
430 // Somehow twisted: nOfst names the position behind the last
431 // character of the last line == This is the position in front of the first character
432 // of the line, in which we are situated:
433 if( nOfst
!= GetStart() || !m_pCurr
->GetLen() )
435 // 8810: Master line RightMargin, after that LeftMargin
436 GetCharRect( pOrig
, nOfst
, pCMS
, nMax
);
437 s_bRightMargin
= nOfst
>= GetEnd() && nOfst
< TextFrameIndex(GetInfo().GetText().getLength());
441 if( !GetPrev() || !GetPrev()->GetLen() || !PrevLine() )
443 GetCharRect( pOrig
, nOfst
, pCMS
, nMax
);
447 // If necessary, as catch up, do the adjustment
451 tools::Long nLast
= 0;
452 SwLinePortion
*pPor
= m_pCurr
->GetFirstPortion();
454 SwTwips nTmpHeight
, nTmpAscent
;
455 CalcAscentAndHeight( nTmpAscent
, nTmpHeight
);
456 sal_uInt16 nPorHeight
= nTmpHeight
;
457 sal_uInt16 nPorAscent
= nTmpAscent
;
459 // Search for the last Text/EndPortion of the line
462 nX
= nX
+ pPor
->Width();
463 if( pPor
->InTextGrp() || ( pPor
->GetLen() && !pPor
->IsFlyPortion()
464 && !pPor
->IsHolePortion() ) || pPor
->IsBreakPortion() )
467 nPorHeight
= pPor
->Height();
468 nPorAscent
= pPor
->GetAscent();
470 pPor
= pPor
->GetNextPortion();
473 const Size
aCharSize( 1, nTmpHeight
);
474 pOrig
->Pos( GetTopLeft() );
475 pOrig
->SSize( aCharSize
);
476 pOrig
->Pos().AdjustX(nLast
);
477 const SwTwips nTmpRight
= Right() - 1;
478 if( pOrig
->Left() > nTmpRight
)
479 pOrig
->Pos().setX( nTmpRight
);
481 if ( pCMS
&& pCMS
->m_bRealHeight
)
483 if ( nTmpAscent
> nPorAscent
)
484 pCMS
->m_aRealHeight
.setX( nTmpAscent
- nPorAscent
);
486 pCMS
->m_aRealHeight
.setX( 0 );
487 OSL_ENSURE( nPorHeight
, "GetCharRect: Missing Portion-Height" );
488 pCMS
->m_aRealHeight
.setY( nPorHeight
);
492 // internal function, called by SwTextCursor::GetCharRect() to calculate
493 // the relative character position in the current line.
494 // pOrig refers to x and y coordinates, width and height of the cursor
495 // pCMS is used for restricting the cursor, if there are different font
496 // heights in one line ( first value = offset to y of pOrig, second
497 // value = real height of (shortened) cursor
498 void SwTextCursor::GetCharRect_( SwRect
* pOrig
, TextFrameIndex
const nOfst
,
499 SwCursorMoveState
* pCMS
)
501 const OUString aText
= GetInfo().GetText();
502 SwTextSizeInfo
aInf( GetInfo(), &aText
, m_nStart
);
504 aInf
.GetFont()->SetProportion( GetPropFont() );
505 SwTwips nTmpAscent
, nTmpHeight
; // Line height
506 CalcAscentAndHeight( nTmpAscent
, nTmpHeight
);
507 const Size
aCharSize( 1, nTmpHeight
);
508 const Point aCharPos
;
509 pOrig
->Pos( aCharPos
);
510 pOrig
->SSize( aCharSize
);
512 // If we are looking for a position inside a field which covers
513 // more than one line we may not skip any "empty portions" at the
514 // beginning of a line
515 const bool bInsideFirstField
= pCMS
&& pCMS
->m_pSpecialPos
&&
516 ( pCMS
->m_pSpecialPos
->nLineOfst
||
517 SwSPExtendRange::BEFORE
==
518 pCMS
->m_pSpecialPos
->nExtendRange
);
520 bool bWidth
= pCMS
&& pCMS
->m_bRealWidth
;
521 if( !m_pCurr
->GetLen() && !m_pCurr
->Width() )
523 if ( pCMS
&& pCMS
->m_bRealHeight
)
525 pCMS
->m_aRealHeight
.setX( 0 );
526 pCMS
->m_aRealHeight
.setY( nTmpHeight
);
531 SwTwips nPorHeight
= nTmpHeight
;
532 SwTwips nPorAscent
= nTmpAscent
;
534 SwTwips nTmpFirst
= 0;
535 SwLinePortion
*pPor
= m_pCurr
->GetFirstPortion();
536 SwBidiPortion
* pLastBidiPor
= nullptr;
537 TextFrameIndex
nLastBidiIdx(-1);
538 SwTwips nLastBidiPorWidth
= 0;
539 std::deque
<sal_uInt16
>* pKanaComp
= m_pCurr
->GetpKanaComp();
540 sal_uInt16 nSpaceIdx
= 0;
542 tools::Long nSpaceAdd
= m_pCurr
->IsSpaceAdd() ? m_pCurr
->GetLLSpaceAdd( 0 ) : 0;
546 // First all portions without Len at beginning of line are skipped.
547 // Exceptions are the mean special portions from WhichFirstPortion:
548 // Num, ErgoSum, FootnoteNum, FieldRests
549 // 8477: but also the only Textportion of an empty line with
550 // Right/Center-Adjustment! So not just pPor->GetExpandPortion() ...
551 while( pPor
&& !pPor
->GetLen() && ! bInsideFirstField
)
554 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
555 nX
+= pPor
->CalcSpacing( nSpaceAdd
, aInf
);
558 // 8670: EndPortions count once as TextPortions.
559 // if( pPor->InTextGrp() || pPor->IsBreakPortion() )
560 if( pPor
->InTextGrp() || pPor
->IsBreakPortion() || pPor
->InTabGrp() )
565 if( pPor
->IsMultiPortion() && static_cast<SwMultiPortion
*>(pPor
)->HasTabulator() )
567 if ( m_pCurr
->IsSpaceAdd() )
569 if ( ++nSpaceIdx
< m_pCurr
->GetLLSpaceAddCount() )
570 nSpaceAdd
= m_pCurr
->GetLLSpaceAdd( nSpaceIdx
);
575 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->size() )
578 if( pPor
->InFixMargGrp() )
580 if( pPor
->IsMarginPortion() )
584 // fix margin portion => next SpaceAdd, KanaComp value
585 if ( m_pCurr
->IsSpaceAdd() )
587 if ( ++nSpaceIdx
< m_pCurr
->GetLLSpaceAddCount() )
588 nSpaceAdd
= m_pCurr
->GetLLSpaceAdd( nSpaceIdx
);
593 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->size() )
597 pPor
= pPor
->GetNextPortion();
602 // There's just Spezialportions.
607 if( !pPor
->IsMarginPortion() && !pPor
->IsPostItsPortion() &&
608 (!pPor
->InFieldGrp() || pPor
->GetAscent() ) )
610 nPorHeight
= pPor
->Height();
611 nPorAscent
= pPor
->GetAscent();
613 while( pPor
&& !pPor
->IsBreakPortion() && ( aInf
.GetIdx() < nOfst
||
614 ( bWidth
&& ( pPor
->IsKernPortion() || pPor
->IsMultiPortion() ) ) ) )
616 if( !pPor
->IsMarginPortion() && !pPor
->IsPostItsPortion() &&
617 (!pPor
->InFieldGrp() || pPor
->GetAscent() ) )
619 nPorHeight
= pPor
->Height();
620 nPorAscent
= pPor
->GetAscent();
623 // If we are behind the portion, we add the portion width to
624 // nX. Special case: nOfst = aInf.GetIdx() + pPor->GetLen().
625 // For common portions (including BidiPortions) we want to add
626 // the portion width to nX. For MultiPortions, nExtra = 0,
627 // therefore we go to the 'else' branch and start a recursion.
628 const TextFrameIndex
nExtra( (pPor
->IsMultiPortion()
629 && !static_cast<SwMultiPortion
*>(pPor
)->IsBidi()
632 if ( aInf
.GetIdx() + pPor
->GetLen() < nOfst
+ nExtra
)
634 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
635 nX
+= pPor
->PrtWidth() +
636 pPor
->CalcSpacing( nSpaceAdd
, aInf
);
639 if( pPor
->InFixMargGrp() && ! pPor
->IsMarginPortion() )
641 // update to current SpaceAdd, KanaComp values
642 if ( m_pCurr
->IsSpaceAdd() )
644 if ( ++nSpaceIdx
< m_pCurr
->GetLLSpaceAddCount() )
645 nSpaceAdd
= m_pCurr
->GetLLSpaceAdd( nSpaceIdx
);
651 ( nKanaIdx
+ 1 ) < pKanaComp
->size()
655 if ( !pPor
->IsFlyPortion() || ( pPor
->GetNextPortion() &&
656 !pPor
->GetNextPortion()->IsMarginPortion() ) )
657 nX
+= pPor
->PrtWidth();
659 if( pPor
->IsMultiPortion() )
661 if ( static_cast<SwMultiPortion
*>(pPor
)->HasTabulator() )
663 if ( m_pCurr
->IsSpaceAdd() )
665 if ( ++nSpaceIdx
< m_pCurr
->GetLLSpaceAddCount() )
666 nSpaceAdd
= m_pCurr
->GetLLSpaceAdd( nSpaceIdx
);
671 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->size() )
675 // if we are right behind a BidiPortion, we have to
676 // hold a pointer to the BidiPortion in order to
677 // find the correct cursor position, depending on the
679 if ( static_cast<SwMultiPortion
*>(pPor
)->IsBidi() &&
680 aInf
.GetIdx() + pPor
->GetLen() == nOfst
)
682 pLastBidiPor
= static_cast<SwBidiPortion
*>(pPor
);
683 nLastBidiIdx
= aInf
.GetIdx();
684 nLastBidiPorWidth
= pLastBidiPor
->Width() +
685 pLastBidiPor
->CalcSpacing( nSpaceAdd
, aInf
);
689 aInf
.SetIdx( aInf
.GetIdx() + pPor
->GetLen() );
690 pPor
= pPor
->GetNextPortion();
694 if( pPor
->IsMultiPortion() )
696 nTmpAscent
= AdjustBaseLine( *m_pCurr
, pPor
);
697 GetInfo().SetMulti( true );
698 pOrig
->Pos().AdjustY(nTmpAscent
- nPorAscent
);
700 if( pCMS
&& pCMS
->m_b2Lines
)
702 const bool bRecursion (pCMS
->m_p2Lines
);
705 pCMS
->m_p2Lines
.reset(new Sw2LinesPos
);
706 pCMS
->m_p2Lines
->aLine
= SwRect(aCharPos
, aCharSize
);
709 if( static_cast<SwMultiPortion
*>(pPor
)->HasRotation() )
711 if( static_cast<SwMultiPortion
*>(pPor
)->IsRevers() )
712 pCMS
->m_p2Lines
->nMultiType
= MultiPortionType::ROT_270
;
714 pCMS
->m_p2Lines
->nMultiType
= MultiPortionType::ROT_90
;
716 else if( static_cast<SwMultiPortion
*>(pPor
)->IsDouble() )
717 pCMS
->m_p2Lines
->nMultiType
= MultiPortionType::TWOLINE
;
718 else if( static_cast<SwMultiPortion
*>(pPor
)->IsBidi() )
719 pCMS
->m_p2Lines
->nMultiType
= MultiPortionType::BIDI
;
721 pCMS
->m_p2Lines
->nMultiType
= MultiPortionType::RUBY
;
723 SwTwips nTmpWidth
= pPor
->Width();
725 nTmpWidth
+= pPor
->CalcSpacing(nSpaceAdd
, aInf
);
727 SwRect
aRect( Point(aCharPos
.X() + nX
, pOrig
->Top() ),
728 Size( nTmpWidth
, pPor
->Height() ) );
731 pCMS
->m_p2Lines
->aPortion
= aRect
;
733 pCMS
->m_p2Lines
->aPortion2
= aRect
;
736 // In a multi-portion we use GetCharRect()-function
737 // recursively and must add the x-position
738 // of the multi-portion.
739 TextFrameIndex
const nOldStart
= m_nStart
;
740 SwTwips nOldY
= m_nY
;
741 sal_uInt8 nOldProp
= GetPropFont();
742 m_nStart
= aInf
.GetIdx();
743 SwLineLayout
* pOldCurr
= m_pCurr
;
744 m_pCurr
= &static_cast<SwMultiPortion
*>(pPor
)->GetRoot();
745 if( static_cast<SwMultiPortion
*>(pPor
)->IsDouble() )
748 SwTextGridItem
const*const pGrid(
749 GetGridItem(GetTextFrame()->FindPageFrame()));
750 const bool bHasGrid
= pGrid
&& GetInfo().SnapToGrid();
751 const sal_uInt16 nRubyHeight
= bHasGrid
?
752 pGrid
->GetRubyHeight() : 0;
754 if( m_nStart
+ m_pCurr
->GetLen() <= nOfst
&& GetNext() &&
755 ( ! static_cast<SwMultiPortion
*>(pPor
)->IsRuby() ||
756 static_cast<SwMultiPortion
*>(pPor
)->OnTop() ) )
759 // in grid mode we may only add the height of the
760 // ruby line if ruby line is on top
762 static_cast<SwMultiPortion
*>(pPor
)->IsRuby() &&
763 static_cast<SwMultiPortion
*>(pPor
)->OnTop() )
764 nOffset
= nRubyHeight
;
766 nOffset
= GetLineHeight();
768 pOrig
->Pos().AdjustY(nOffset
);
772 const bool bSpaceChg
= static_cast<SwMultiPortion
*>(pPor
)->
773 ChgSpaceAdd( m_pCurr
, nSpaceAdd
);
774 Point aOldPos
= pOrig
->Pos();
776 // Ok, for ruby portions in grid mode we have to
777 // temporarily set the inner line height to the
778 // outer line height because that value is needed
779 // for the adjustment inside the recursion
780 const sal_uInt16 nOldRubyHeight
= m_pCurr
->Height();
781 const sal_uInt16 nOldRubyRealHeight
= m_pCurr
->GetRealHeight();
782 const bool bChgHeight
=
783 static_cast<SwMultiPortion
*>(pPor
)->IsRuby() && bHasGrid
;
787 m_pCurr
->Height( pOldCurr
->Height() - nRubyHeight
);
788 m_pCurr
->SetRealHeight( pOldCurr
->GetRealHeight() -
792 SwLayoutModeModifier
aLayoutModeModifier( *GetInfo().GetOut() );
793 if ( static_cast<SwMultiPortion
*>(pPor
)->IsBidi() )
795 aLayoutModeModifier
.Modify(
796 static_cast<SwBidiPortion
*>(pPor
)->GetLevel() % 2 );
799 GetCharRect_( pOrig
, nOfst
, pCMS
);
803 m_pCurr
->Height( nOldRubyHeight
);
804 m_pCurr
->SetRealHeight( nOldRubyRealHeight
);
807 // if we are still in the first row of
808 // our 2 line multiportion, we use the FirstMulti flag
810 if ( static_cast<SwMultiPortion
*>(pPor
)->IsDouble() )
812 // the recursion may have damaged our font size
813 SetPropFont( nOldProp
);
814 GetInfo().GetFont()->SetProportion( 100 );
816 if ( m_pCurr
== &static_cast<SwMultiPortion
*>(pPor
)->GetRoot() )
818 GetInfo().SetFirstMulti( true );
820 // we want to treat a double line portion like a
821 // single line portion, if there is no text in
823 if ( !m_pCurr
->GetNext() ||
824 !m_pCurr
->GetNext()->GetLen() )
825 GetInfo().SetMulti( false );
828 // ruby portions are treated like single line portions
829 else if( static_cast<SwMultiPortion
*>(pPor
)->IsRuby() ||
830 static_cast<SwMultiPortion
*>(pPor
)->IsBidi() )
831 GetInfo().SetMulti( false );
833 // calculate cursor values
834 if( static_cast<SwMultiPortion
*>(pPor
)->HasRotation() )
836 GetInfo().SetMulti( false );
837 tools::Long nTmp
= pOrig
->Width();
838 pOrig
->Width( pOrig
->Height() );
839 pOrig
->Height( nTmp
);
840 nTmp
= pOrig
->Left() - aOldPos
.X();
842 // if we travel into our rotated portion from
843 // a line below, we have to take care, that the
844 // y coord in pOrig is less than line height:
848 pOrig
->Pos().setX( nX
+ aOldPos
.X() );
849 if( static_cast<SwMultiPortion
*>(pPor
)->IsRevers() )
850 pOrig
->Pos().setY( aOldPos
.Y() + nTmp
);
852 pOrig
->Pos().setY( aOldPos
.Y()
853 + pPor
->Height() - nTmp
- pOrig
->Height() );
854 if ( pCMS
&& pCMS
->m_bRealHeight
)
856 pCMS
->m_aRealHeight
.setY( -pCMS
->m_aRealHeight
.Y() );
857 // result for rotated multi portion is not
858 // correct for reverse (270 degree) portions
859 if( static_cast<SwMultiPortion
*>(pPor
)->IsRevers() )
861 if ( SvxParaVertAlignItem::Align::Automatic
==
862 GetLineInfo().GetVertAlign() )
863 // if vertical alignment is set to auto,
864 // we switch from base line alignment
865 // to centered alignment
866 pCMS
->m_aRealHeight
.setX(
868 pCMS
->m_aRealHeight
.Y() ) / 2 );
870 pCMS
->m_aRealHeight
.setX(
872 pCMS
->m_aRealHeight
.X() +
873 pCMS
->m_aRealHeight
.Y() );
879 pOrig
->Pos().AdjustY(aOldPos
.Y() );
880 if ( static_cast<SwMultiPortion
*>(pPor
)->IsBidi() )
882 const SwTwips nPorWidth
= pPor
->Width() +
883 pPor
->CalcSpacing( nSpaceAdd
, aInf
);
884 const SwTwips nInsideOfst
= pOrig
->Pos().X();
885 pOrig
->Pos().setX( nX
+ nPorWidth
-
886 nInsideOfst
- pOrig
->Width() );
889 pOrig
->Pos().AdjustX(nX
);
891 if( static_cast<SwMultiPortion
*>(pPor
)->HasBrackets() )
892 pOrig
->Pos().AdjustX(
893 static_cast<SwDoubleLinePortion
*>(pPor
)->PreWidth() );
897 SwDoubleLinePortion::ResetSpaceAdd( m_pCurr
);
900 m_nStart
= nOldStart
;
906 if ( pPor
->PrtWidth() )
908 // tdf#30731: To get the correct nOfst width, we need
909 // to send the whole portion string to GetTextSize()
910 // and ask it to return the width of nOfst by calling
911 // SetMeasureLen(). Cutting the string at nOfst can
912 // give the wrong width if nOfst is in e.g. the middle
913 // of a ligature. See SwFntObj::DrawText().
914 TextFrameIndex
const nOldLen
= pPor
->GetLen();
915 aInf
.SetLen( pPor
->GetLen() );
916 pPor
->SetLen( nOfst
- aInf
.GetIdx() );
917 aInf
.SetMeasureLen(pPor
->GetLen());
918 if (aInf
.GetLen() < aInf
.GetMeasureLen())
920 pPor
->SetLen(aInf
.GetMeasureLen());
921 aInf
.SetLen(pPor
->GetLen());
923 if( nX
|| !pPor
->InNumberGrp() )
926 const bool bOldOnWin
= aInf
.OnWin();
927 aInf
.SetOnWin( false ); // no BULLETs!
929 aInf
.SetKanaComp( pKanaComp
);
930 aInf
.SetKanaIdx( nKanaIdx
);
931 nX
+= pPor
->GetTextSize( aInf
).Width();
932 aInf
.SetOnWin( bOldOnWin
);
933 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
934 nX
+= pPor
->CalcSpacing( nSpaceAdd
, aInf
);
937 pPor
->SetLen(pPor
->GetLen() + TextFrameIndex(1));
938 aInf
.SetMeasureLen(pPor
->GetLen());
939 if (aInf
.GetLen() < aInf
.GetMeasureLen())
941 pPor
->SetLen(aInf
.GetMeasureLen());
942 aInf
.SetLen(pPor
->GetLen());
944 aInf
.SetOnWin( false ); // no BULLETs!
945 nTmp
+= pPor
->GetTextSize( aInf
).Width();
946 aInf
.SetOnWin( bOldOnWin
);
947 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
948 nTmp
+= pPor
->CalcSpacing(nSpaceAdd
, aInf
);
949 pOrig
->Width( nTmp
- nX
);
952 pPor
->SetLen( nOldLen
);
954 // Shift the cursor with the right border width
955 // Note: nX remains positive because GetTextSize() also include the width of the right border
956 if( aInf
.GetIdx() < nOfst
&& nOfst
< aInf
.GetIdx() + pPor
->GetLen() )
958 // Find the current drop portion part and use its right border
959 if( pPor
->IsDropPortion() && static_cast<SwDropPortion
*>(pPor
)->GetLines() > 1 )
961 SwDropPortion
* pDrop
= static_cast<SwDropPortion
*>(pPor
);
962 const SwDropPortionPart
* pCurrPart
= pDrop
->GetPart();
963 TextFrameIndex
nSumLength(0);
964 while( pCurrPart
&& (nSumLength
+= pCurrPart
->GetLen()) < nOfst
- aInf
.GetIdx() )
966 pCurrPart
= pCurrPart
->GetFollow();
968 if( pCurrPart
&& nSumLength
!= nOfst
- aInf
.GetIdx() &&
969 pCurrPart
->GetFont().GetRightBorder() && !pCurrPart
->GetJoinBorderWithNext() )
971 nX
-= pCurrPart
->GetFont().GetRightBorderSpace();
974 else if( GetInfo().GetFont()->GetRightBorder() && !pPor
->GetJoinBorderWithNext())
976 nX
-= GetInfo().GetFont()->GetRightBorderSpace();
988 OSL_ENSURE( !pPor
->InNumberGrp() || bInsideFirstField
, "Number surprise" );
989 bool bEmptyField
= false;
990 if( pPor
->InFieldGrp() && pPor
->GetLen() )
992 SwFieldPortion
*pTmp
= static_cast<SwFieldPortion
*>(pPor
);
993 while( pTmp
->HasFollow() && pTmp
->GetExp().isEmpty() )
995 sal_uInt16 nAddX
= pTmp
->Width();
996 SwLinePortion
*pNext
= pTmp
->GetNextPortion();
997 while( pNext
&& !pNext
->InFieldGrp() )
999 OSL_ENSURE( !pNext
->GetLen(), "Where's my field follow?" );
1000 nAddX
= nAddX
+ pNext
->Width();
1001 pNext
= pNext
->GetNextPortion();
1005 pTmp
= static_cast<SwFieldPortion
*>(pNext
);
1006 nPorHeight
= pTmp
->Height();
1007 nPorAscent
= pTmp
->GetAscent();
1012 // 8513: Fields in justified text, skipped
1013 while( pPor
&& !pPor
->GetLen() && ! bInsideFirstField
&&
1014 ( pPor
->IsFlyPortion() || pPor
->IsKernPortion() ||
1015 pPor
->IsBlankPortion() || pPor
->InTabGrp() ||
1016 ( !bEmptyField
&& pPor
->InFieldGrp() ) ) )
1018 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
1019 nX
+= pPor
->PrtWidth() +
1020 pPor
->CalcSpacing( nSpaceAdd
, aInf
);
1023 if( pPor
->InFixMargGrp() && ! pPor
->IsMarginPortion() )
1025 if ( m_pCurr
->IsSpaceAdd() )
1027 if ( ++nSpaceIdx
< m_pCurr
->GetLLSpaceAddCount() )
1028 nSpaceAdd
= m_pCurr
->GetLLSpaceAdd( nSpaceIdx
);
1033 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->size() )
1036 if ( !pPor
->IsFlyPortion() || ( pPor
->GetNextPortion() &&
1037 !pPor
->GetNextPortion()->IsMarginPortion() ) )
1038 nX
+= pPor
->PrtWidth();
1040 if( pPor
->IsMultiPortion() &&
1041 static_cast<SwMultiPortion
*>(pPor
)->HasTabulator() )
1043 if ( m_pCurr
->IsSpaceAdd() )
1045 if ( ++nSpaceIdx
< m_pCurr
->GetLLSpaceAddCount() )
1046 nSpaceAdd
= m_pCurr
->GetLLSpaceAdd( nSpaceIdx
);
1051 if( pKanaComp
&& ( nKanaIdx
+ 1 ) < pKanaComp
->size() )
1054 if( !pPor
->IsFlyPortion() )
1056 nPorHeight
= pPor
->Height();
1057 nPorAscent
= pPor
->GetAscent();
1059 pPor
= pPor
->GetNextPortion();
1062 if( aInf
.GetIdx() == nOfst
&& pPor
&& pPor
->InHyphGrp() &&
1063 pPor
->GetNextPortion() && pPor
->GetNextPortion()->InFixGrp() )
1065 // All special portions have to be skipped
1066 // Taking the German word "zusammen" as example: zu-[FLY]sammen, 'u' == 19, 's' == 20; Right()
1067 // Without the adjustment we end up in front of '-', with the
1068 // adjustment in front of the 's'.
1069 while( pPor
&& !pPor
->GetLen() )
1071 nX
+= pPor
->Width();
1072 if( !pPor
->IsMarginPortion() )
1074 nPorHeight
= pPor
->Height();
1075 nPorAscent
= pPor
->GetAscent();
1077 pPor
= pPor
->GetNextPortion();
1082 if( pCMS
->m_bFieldInfo
&& pPor
->InFieldGrp() && pPor
->Width() )
1083 pOrig
->Width( pPor
->Width() );
1084 if( pPor
->IsDropPortion() )
1086 nPorAscent
= static_cast<SwDropPortion
*>(pPor
)->GetDropHeight();
1087 // The drop height is only calculated, if we have more than
1088 // one line. Otherwise it is 0.
1090 nPorAscent
= pPor
->Height();
1091 nPorHeight
= nPorAscent
;
1092 pOrig
->Height( nPorHeight
+
1093 static_cast<SwDropPortion
*>(pPor
)->GetDropDescent() );
1094 if( nTmpHeight
< pOrig
->Height() )
1096 nTmpAscent
= nPorAscent
;
1097 nTmpHeight
= sal_uInt16( pOrig
->Height() );
1100 if( bWidth
&& pPor
->PrtWidth() && pPor
->GetLen() &&
1101 aInf
.GetIdx() == nOfst
)
1103 if( !pPor
->IsFlyPortion() && pPor
->Height() &&
1106 nPorHeight
= pPor
->Height();
1107 nPorAscent
= pPor
->GetAscent();
1110 if (TextFrameIndex(2) > pPor
->GetLen())
1112 nTmp
= pPor
->Width();
1113 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
1114 nTmp
+= pPor
->CalcSpacing( nSpaceAdd
, aInf
);
1118 const bool bOldOnWin
= aInf
.OnWin();
1119 TextFrameIndex
const nOldLen
= pPor
->GetLen();
1120 aInf
.SetLen( pPor
->GetLen() );
1121 pPor
->SetLen( TextFrameIndex(1) );
1122 aInf
.SetMeasureLen(pPor
->GetLen());
1123 if (aInf
.GetLen() < aInf
.GetMeasureLen())
1125 pPor
->SetLen(aInf
.GetMeasureLen());
1126 aInf
.SetLen(pPor
->GetLen());
1129 aInf
.SetOnWin( false ); // no BULLETs!
1130 aInf
.SetKanaComp( pKanaComp
);
1131 aInf
.SetKanaIdx( nKanaIdx
);
1132 nTmp
= pPor
->GetTextSize( aInf
).Width();
1133 aInf
.SetOnWin( bOldOnWin
);
1134 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
1135 nTmp
+= pPor
->CalcSpacing( nSpaceAdd
, aInf
);
1136 pPor
->SetLen( nOldLen
);
1138 pOrig
->Width( nTmp
);
1141 // travel inside field portion?
1142 if ( pCMS
->m_pSpecialPos
)
1144 // apply attributes to font
1146 lcl_GetCharRectInsideField( aInf
, *pOrig
, *pCMS
, *pPor
);
1151 // special case: We are at the beginning of a BidiPortion or
1152 // directly behind a BidiPortion
1156 pPor
->IsMultiPortion() &&
1157 static_cast<SwMultiPortion
*>(pPor
)->IsBidi() ) ) )
1159 // we determine if the cursor has to blink before or behind
1163 const sal_uInt8 nPortionLevel
= pLastBidiPor
->GetLevel();
1165 if ( pCMS
->m_nCursorBidiLevel
>= nPortionLevel
)
1167 // we came from inside the bidi portion, we want to blink
1168 // behind the portion
1169 pOrig
->Pos().AdjustX( -nLastBidiPorWidth
);
1171 // Again, there is a special case: logically behind
1172 // the portion can actually mean that the cursor is inside
1173 // the portion. This can happen is the last portion
1174 // inside the bidi portion is a nested bidi portion
1175 SwLineLayout
& rLineLayout
=
1176 static_cast<SwMultiPortion
*>(pLastBidiPor
)->GetRoot();
1178 const SwLinePortion
*pLast
= rLineLayout
.FindLastPortion();
1179 if ( pLast
->IsMultiPortion() )
1181 OSL_ENSURE( static_cast<const SwMultiPortion
*>(pLast
)->IsBidi(),
1182 "Non-BidiPortion inside BidiPortion" );
1183 TextFrameIndex
const nIdx
= aInf
.GetIdx();
1184 // correct the index before using CalcSpacing.
1185 aInf
.SetIdx(nLastBidiIdx
);
1186 pOrig
->Pos().AdjustX(pLast
->Width() +
1187 pLast
->CalcSpacing( nSpaceAdd
, aInf
) );
1194 const sal_uInt8 nPortionLevel
= static_cast<SwBidiPortion
*>(pPor
)->GetLevel();
1196 if ( pCMS
->m_nCursorBidiLevel
>= nPortionLevel
)
1198 // we came from inside the bidi portion, we want to blink
1199 // behind the portion
1200 pOrig
->Pos().AdjustX(pPor
->Width() +
1201 pPor
->CalcSpacing( nSpaceAdd
, aInf
) );
1206 pOrig
->Pos().AdjustX(nX
);
1208 if ( pCMS
&& pCMS
->m_bRealHeight
)
1210 nTmpAscent
= AdjustBaseLine( *m_pCurr
, nullptr, nPorHeight
, nPorAscent
);
1211 if ( nTmpAscent
> nPorAscent
)
1212 pCMS
->m_aRealHeight
.setX( nTmpAscent
- nPorAscent
);
1214 pCMS
->m_aRealHeight
.setX( 0 );
1215 OSL_ENSURE( nPorHeight
, "GetCharRect: Missing Portion-Height" );
1216 if ( nTmpHeight
> nPorHeight
)
1217 pCMS
->m_aRealHeight
.setY( nPorHeight
);
1219 pCMS
->m_aRealHeight
.setY( nTmpHeight
);
1224 void SwTextCursor::GetCharRect( SwRect
* pOrig
, TextFrameIndex
const nOfst
,
1225 SwCursorMoveState
* pCMS
, const tools::Long nMax
)
1227 CharCursorToLine(nOfst
);
1229 // Indicates that a position inside a special portion (field, number portion)
1231 const bool bSpecialPos
= pCMS
&& pCMS
->m_pSpecialPos
;
1232 TextFrameIndex nFindOfst
= nOfst
;
1236 const SwSPExtendRange nExtendRange
= pCMS
->m_pSpecialPos
->nExtendRange
;
1238 OSL_ENSURE( ! pCMS
->m_pSpecialPos
->nLineOfst
|| SwSPExtendRange::BEFORE
!= nExtendRange
,
1239 "LineOffset AND Number Portion?" );
1241 // portions which are behind the string
1242 if ( SwSPExtendRange::BEHIND
== nExtendRange
)
1245 // skip lines for fields which cover more than one line
1246 for ( sal_Int32 i
= 0; i
< pCMS
->m_pSpecialPos
->nLineOfst
; i
++ )
1250 // If necessary, as catch up, do the adjustment
1253 const Point
aCharPos( GetTopLeft() );
1255 GetCharRect_( pOrig
, nFindOfst
, pCMS
);
1257 pOrig
->Pos().AdjustX(aCharPos
.X() );
1258 pOrig
->Pos().AdjustY(aCharPos
.Y() );
1260 if( pCMS
&& pCMS
->m_b2Lines
&& pCMS
->m_p2Lines
)
1262 pCMS
->m_p2Lines
->aLine
.Pos().AdjustX(aCharPos
.X() );
1263 pCMS
->m_p2Lines
->aLine
.Pos().AdjustY(aCharPos
.Y() );
1264 pCMS
->m_p2Lines
->aPortion
.Pos().AdjustX(aCharPos
.X() );
1265 pCMS
->m_p2Lines
->aPortion
.Pos().AdjustY(aCharPos
.Y() );
1270 if( pOrig
->Top() + pOrig
->Height() > nMax
)
1272 if( pOrig
->Top() > nMax
)
1274 pOrig
->Height( nMax
- pOrig
->Top() );
1276 if ( pCMS
&& pCMS
->m_bRealHeight
&& pCMS
->m_aRealHeight
.Y() >= 0 )
1278 tools::Long nTmp
= pCMS
->m_aRealHeight
.X() + pOrig
->Top();
1281 pCMS
->m_aRealHeight
.setX( nMax
- pOrig
->Top() );
1282 pCMS
->m_aRealHeight
.setY( 0 );
1284 else if( nTmp
+ pCMS
->m_aRealHeight
.Y() > nMax
)
1285 pCMS
->m_aRealHeight
.setY( nMax
- nTmp
);
1291 * Determines if SwTextCursor::GetModelPositionForViewPoint() should consider the next portion when calculating the
1292 * doc model position from a Point.
1294 static bool ConsiderNextPortionForCursorOffset(const SwLinePortion
* pPor
, SwTwips nWidth30
, sal_uInt16 nX
)
1296 if (!pPor
->GetNextPortion() || pPor
->IsBreakPortion())
1301 // tdf#138592: consider all following zero-width text portions of current text portion,
1302 // like combining characters.
1303 if (nWidth30
== nX
&& pPor
->IsTextPortion() && pPor
->GetNextPortion()->IsTextPortion()
1304 && pPor
->GetNextPortion()->Width() == 0)
1307 // If we're past the target position, stop the iteration in general.
1308 // Exception: don't stop the iteration between as-char fly portions and their comments.
1309 if (nWidth30
>= nX
&& (!pPor
->IsFlyCntPortion() || !pPor
->GetNextPortion()->IsPostItsPortion()))
1311 // Normally returns false.
1313 // Another exception: If the cursor is at the very end of the portion, and the next portion is a comment,
1314 // then place the cursor after the zero-width comment. This is primarily to benefit the very end of a line.
1315 return nWidth30
== nX
&& pPor
->GetNextPortion()->IsPostItsPortion();
1321 // Return: Offset in String
1322 TextFrameIndex
SwTextCursor::GetModelPositionForViewPoint( SwPosition
*pPos
, const Point
&rPoint
,
1323 bool bChgNode
, SwCursorMoveState
* pCMS
) const
1325 // If necessary, as catch up, do the adjustment
1328 const OUString
&rText
= GetInfo().GetText();
1329 TextFrameIndex
nOffset(0);
1331 // x is the horizontal offset within the line.
1332 SwTwips x
= rPoint
.X();
1333 const SwTwips nLeftMargin
= GetLineStart();
1334 SwTwips nRightMargin
= GetLineEnd() +
1335 ( GetCurr()->IsHanging() ? GetCurr()->GetHangingMargin() : 0 );
1336 if( nRightMargin
== nLeftMargin
)
1339 const bool bLeftOver
= x
< nLeftMargin
;
1342 const bool bRightOver
= x
> nRightMargin
;
1343 const bool bRightAllowed
= pCMS
&& ( pCMS
->m_eState
== CursorMoveState::NONE
);
1345 // Until here everything in document coordinates.
1350 // If there are attribute changes in the line, search for the paragraph,
1351 // in which nX is situated.
1352 SwLinePortion
*pPor
= m_pCurr
->GetFirstPortion();
1353 TextFrameIndex nCurrStart
= m_nStart
;
1354 bool bHolePortion
= false;
1355 bool bLastHyph
= false;
1357 std::deque
<sal_uInt16
> *pKanaComp
= m_pCurr
->GetpKanaComp();
1358 TextFrameIndex
const nOldIdx
= GetInfo().GetIdx();
1359 sal_uInt16 nSpaceIdx
= 0;
1360 size_t nKanaIdx
= 0;
1361 tools::Long nSpaceAdd
= m_pCurr
->IsSpaceAdd() ? m_pCurr
->GetLLSpaceAdd( 0 ) : 0;
1362 short nKanaComp
= pKanaComp
? (*pKanaComp
)[0] : 0;
1364 // nWidth is the width of the line, or the width of
1365 // the paragraph with the font change, in which nX is situated.
1367 SwTwips nWidth
= pPor
->Width();
1368 if ( m_pCurr
->IsSpaceAdd() || pKanaComp
)
1370 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
1372 const_cast<SwTextSizeInfo
&>(GetInfo()).SetIdx( nCurrStart
);
1373 nWidth
= nWidth
+ sal_uInt16( pPor
->CalcSpacing( nSpaceAdd
, GetInfo() ) );
1375 if( ( pPor
->InFixMargGrp() && ! pPor
->IsMarginPortion() ) ||
1376 ( pPor
->IsMultiPortion() && static_cast<SwMultiPortion
*>(pPor
)->HasTabulator() )
1379 if ( m_pCurr
->IsSpaceAdd() )
1381 if ( ++nSpaceIdx
< m_pCurr
->GetLLSpaceAddCount() )
1382 nSpaceAdd
= m_pCurr
->GetLLSpaceAdd( nSpaceIdx
);
1389 if ( nKanaIdx
+ 1 < pKanaComp
->size() )
1390 nKanaComp
= (*pKanaComp
)[++nKanaIdx
];
1398 if ( pPor
->IsPostItsPortion() )
1401 nWidth30
= ! nWidth
&& pPor
->GetLen() && pPor
->InToxRefOrFieldGrp() ?
1405 while (ConsiderNextPortionForCursorOffset(pPor
, nWidth30
, nX
))
1408 nCurrStart
= nCurrStart
+ pPor
->GetLen();
1409 bHolePortion
= pPor
->IsHolePortion();
1410 pPor
= pPor
->GetNextPortion();
1411 nWidth
= pPor
->Width();
1412 if ( m_pCurr
->IsSpaceAdd() || pKanaComp
)
1414 if ( pPor
->InSpaceGrp() && nSpaceAdd
)
1416 const_cast<SwTextSizeInfo
&>(GetInfo()).SetIdx( nCurrStart
);
1417 nWidth
= nWidth
+ sal_uInt16( pPor
->CalcSpacing( nSpaceAdd
, GetInfo() ) );
1420 if( ( pPor
->InFixMargGrp() && ! pPor
->IsMarginPortion() ) ||
1421 ( pPor
->IsMultiPortion() && static_cast<SwMultiPortion
*>(pPor
)->HasTabulator() )
1424 if ( m_pCurr
->IsSpaceAdd() )
1426 if ( ++nSpaceIdx
< m_pCurr
->GetLLSpaceAddCount() )
1427 nSpaceAdd
= m_pCurr
->GetLLSpaceAdd( nSpaceIdx
);
1434 if( nKanaIdx
+ 1 < pKanaComp
->size() )
1435 nKanaComp
= (*pKanaComp
)[++nKanaIdx
];
1442 if ( pPor
->IsPostItsPortion() )
1445 nWidth30
= ! nWidth
&& pPor
->GetLen() && pPor
->InToxRefOrFieldGrp() ?
1448 if( !pPor
->IsFlyPortion() && !pPor
->IsMarginPortion() )
1449 bLastHyph
= pPor
->InHyphGrp();
1452 const bool bLastPortion
= (nullptr == pPor
->GetNextPortion());
1456 SwLinePortion
*pNextPor
= pPor
->GetNextPortion();
1457 while( pNextPor
&& pNextPor
->InFieldGrp() && !pNextPor
->Width() )
1459 nCurrStart
= nCurrStart
+ pPor
->GetLen();
1461 if( !pPor
->IsFlyPortion() && !pPor
->IsMarginPortion() )
1462 bLastHyph
= pPor
->InHyphGrp();
1463 pNextPor
= pPor
->GetNextPortion();
1467 const_cast<SwTextSizeInfo
&>(GetInfo()).SetIdx( nOldIdx
);
1469 TextFrameIndex nLength
= pPor
->GetLen();
1471 const bool bFieldInfo
= pCMS
&& pCMS
->m_bFieldInfo
;
1473 if( bFieldInfo
&& ( nWidth30
< nX
|| bRightOver
|| bLeftOver
||
1474 ( pPor
->InNumberGrp() && !pPor
->IsFootnoteNumPortion() ) ||
1475 ( pPor
->IsMarginPortion() && nWidth
> nX
+ 30 ) ) )
1476 pCMS
->m_bPosCorr
= true;
1479 if (pCMS
&& pCMS
->m_bInFrontOfLabel
)
1481 if (2 * nX
>= nWidth
|| !pPor
->InNumberGrp() || pPor
->IsFootnoteNumPortion())
1482 pCMS
->m_bInFrontOfLabel
= false;
1485 // 7684: We are exactly ended up at their HyphPortion. It is our task to
1486 // provide, that we end up in the String.
1487 // 7993: If length = 0, then we must exit...
1492 if( pPor
->IsFlyPortion() && bFieldInfo
)
1493 pCMS
->m_bPosCorr
= true;
1495 if (!bRightOver
&& nX
)
1497 if( pPor
->IsFootnoteNumPortion())
1498 pCMS
->m_bFootnoteNoInfo
= true;
1499 else if (pPor
->InNumberGrp() ) // #i23726#
1501 pCMS
->m_nInNumPortionOffset
= nX
;
1502 pCMS
->m_bInNumPortion
= true;
1507 return TextFrameIndex(0);
1509 // 7849, 7816: pPor->GetHyphPortion is mandatory!
1510 if( bHolePortion
|| ( !bRightAllowed
&& bLastHyph
) ||
1511 ( pPor
->IsMarginPortion() && !pPor
->GetNextPortion() &&
1512 // 46598: Consider the situation: We might end up behind the last character,
1513 // in the last line of a centered paragraph
1514 nCurrStart
< TextFrameIndex(rText
.getLength())))
1516 else if( pPor
->InFieldGrp() && static_cast<SwFieldPortion
*>(pPor
)->IsFollow()
1523 sal_uInt16 nHeight
= pPor
->Height();
1524 if ( !nHeight
|| nHeight
> nWidth
)
1526 if( bChgNode
&& nWidth
- nHeight
/2 > nX
)
1532 if (TextFrameIndex(1) == nLength
|| pPor
->InFieldGrp())
1536 // no quick return for as-character frames, we want to peek inside
1537 if (!(bChgNode
&& pPos
&& pPor
->IsFlyCntPortion())
1538 // if we want to get the position inside the field, we should not return
1539 && (!pCMS
|| !pCMS
->m_pSpecialPos
))
1541 if ( pPor
->InFieldGrp() ||
1542 ( pPor
->IsMultiPortion() &&
1543 static_cast<SwMultiPortion
*>(pPor
)->IsBidi() ) )
1545 sal_uInt16 nHeight
= 0;
1548 nHeight
= pPor
->Height();
1549 if ( !nHeight
|| nHeight
> nWidth
)
1553 if( nWidth
- nHeight
/2 <= nX
&&
1554 ( ! pPor
->InFieldGrp() ||
1555 !static_cast<SwFieldPortion
*>(pPor
)->HasFollow() ) )
1557 if (pPor
->InFieldGrp())
1559 nCurrStart
+= static_cast<SwFieldPortion
*>(pPor
)->GetFieldLen();
1567 else if ( ( !pPor
->IsFlyPortion() || ( pPor
->GetNextPortion() &&
1568 !pPor
->GetNextPortion()->IsMarginPortion() &&
1569 !pPor
->GetNextPortion()->IsHolePortion() ) )
1570 && ( nWidth
/2 < nX
) &&
1572 ( pPor
->GetNextPortion() &&
1573 pPor
->GetNextPortion()->IsPostItsPortion() ) )
1574 && ( bRightAllowed
|| !bLastHyph
))
1582 if ( pPor
->IsPostItsPortion() || pPor
->IsBreakPortion() ||
1583 pPor
->InToxRefGrp() )
1585 SwPostItsPortion
* pPostItsPortion
= pPor
->IsPostItsPortion() ? dynamic_cast<SwPostItsPortion
*>(pPor
) : nullptr;
1586 if (pPostItsPortion
)
1588 if (!pPostItsPortion
->IsScript()) // tdf#141079
1590 // Offset would be nCurrStart + nLength below, do the same for post-it portions.
1591 nCurrStart
+= pPor
->GetLen();
1596 if ( pPor
->InFieldGrp() )
1598 if( bRightOver
&& !static_cast<SwFieldPortion
*>(pPor
)->HasFollow() )
1600 nCurrStart
+= static_cast<SwFieldPortion
*>(pPor
)->GetFieldLen();
1607 // Skip space at the end of the line
1608 if( bLastPortion
&& (m_pCurr
->GetNext() || m_pFrame
->GetFollow() )
1609 && rText
[sal_Int32(nCurrStart
+ nLength
) - 1] == ' ' )
1613 ( nWidth
== nX
&& pPor
->IsMultiPortion() && static_cast<SwMultiPortion
*>(pPor
)->IsDouble() ) )
1615 if( pPor
->IsMultiPortion() )
1617 // In a multi-portion we use GetModelPositionForViewPoint()-function recursively
1618 SwTwips nTmpY
= rPoint
.Y() - m_pCurr
->GetAscent() + pPor
->GetAscent();
1619 // if we are in the first line of a double line portion, we have
1620 // to add a value to nTmpY for not staying in this line
1621 // we also want to skip the first line, if we are inside ruby
1622 if ( ( static_cast<SwTextSizeInfo
*>(m_pInf
)->IsMulti() &&
1623 static_cast<SwTextSizeInfo
*>(m_pInf
)->IsFirstMulti() ) ||
1624 ( static_cast<SwMultiPortion
*>(pPor
)->IsRuby() &&
1625 static_cast<SwMultiPortion
*>(pPor
)->OnTop() ) )
1626 nTmpY
+= static_cast<SwMultiPortion
*>(pPor
)->Height();
1628 // Important for cursor traveling in ruby portions:
1629 // We have to set nTmpY to 0 in order to stay in the first row
1630 // if the phonetic line is the second row
1631 if ( static_cast<SwMultiPortion
*>(pPor
)->IsRuby() &&
1632 ! static_cast<SwMultiPortion
*>(pPor
)->OnTop() )
1635 SwTextCursorSave
aSave( const_cast<SwTextCursor
*>(this), static_cast<SwMultiPortion
*>(pPor
),
1636 nTmpY
, nX
, nCurrStart
, nSpaceAdd
);
1638 SwLayoutModeModifier
aLayoutModeModifier( *GetInfo().GetOut() );
1639 if ( static_cast<SwMultiPortion
*>(pPor
)->IsBidi() )
1641 const sal_uInt8 nBidiLevel
= static_cast<SwBidiPortion
*>(pPor
)->GetLevel();
1642 aLayoutModeModifier
.Modify( nBidiLevel
% 2 );
1645 if( static_cast<SwMultiPortion
*>(pPor
)->HasRotation() )
1648 if( !static_cast<SwMultiPortion
*>(pPor
)->IsRevers() )
1649 nTmpY
= pPor
->Height() - nTmpY
;
1652 nX
= o3tl::narrowing
<sal_uInt16
>(nTmpY
);
1655 if( static_cast<SwMultiPortion
*>(pPor
)->HasBrackets() )
1657 const sal_uInt16 nPreWidth
= static_cast<SwDoubleLinePortion
*>(pPor
)->PreWidth();
1658 if ( nX
> nPreWidth
)
1659 nX
= nX
- nPreWidth
;
1664 return GetModelPositionForViewPoint( pPos
, Point( GetLineStart() + nX
, rPoint
.Y() ),
1667 if( pPor
->InTextGrp() || pPor
->IsHolePortion() )
1672 const_cast<SwFont
*>(GetFnt())->SetProportion( GetPropFont() );
1673 nOldProp
= GetFnt()->GetPropr();
1678 SwTextSizeInfo
aSizeInf( GetInfo(), &rText
, nCurrStart
);
1679 const_cast<SwTextCursor
*>(this)->SeekAndChg( aSizeInf
);
1680 SwTextSlot
aDiffText( &aSizeInf
, pPor
, false, false );
1681 SwFontSave
aSave( aSizeInf
, pPor
->IsDropPortion() ?
1682 static_cast<SwDropPortion
*>(pPor
)->GetFnt() : nullptr );
1684 SwParaPortion
* pPara
= const_cast<SwParaPortion
*>(GetInfo().GetParaPortion());
1685 OSL_ENSURE( pPara
, "No paragraph!" );
1687 // protect against bugs elsewhere
1688 SAL_WARN_IF( aSizeInf
.GetIdx().get() + pPor
->GetLen().get() > aSizeInf
.GetText().getLength(), "sw", "portion and text are out of sync" );
1689 TextFrameIndex
nSafeLen( std::min(pPor
->GetLen().get(), aSizeInf
.GetText().getLength() - aSizeInf
.GetIdx().get()) );
1691 SwDrawTextInfo
aDrawInf( aSizeInf
.GetVsh(),
1693 &pPara
->GetScriptInfo(),
1698 // Drop portion works like a multi portion, just its parts are not portions
1699 if( pPor
->IsDropPortion() && static_cast<SwDropPortion
*>(pPor
)->GetLines() > 1 )
1701 SwDropPortion
* pDrop
= static_cast<SwDropPortion
*>(pPor
);
1702 const SwDropPortionPart
* pCurrPart
= pDrop
->GetPart();
1703 sal_uInt16 nSumWidth
= 0;
1704 sal_uInt16 nSumBorderWidth
= 0;
1705 // Shift offset with the right and left border of previous parts and left border of actual one
1706 while (pCurrPart
&& nSumWidth
<= nX
- sal_Int32(nCurrStart
))
1708 nSumWidth
+= pCurrPart
->GetWidth();
1709 if( pCurrPart
->GetFont().GetLeftBorder() && !pCurrPart
->GetJoinBorderWithPrev() )
1711 nSumBorderWidth
+= pCurrPart
->GetFont().GetLeftBorderSpace();
1713 if (nSumWidth
<= nX
- sal_Int32(nCurrStart
) && pCurrPart
->GetFont().GetRightBorder() &&
1714 !pCurrPart
->GetJoinBorderWithNext() )
1716 nSumBorderWidth
+= pCurrPart
->GetFont().GetRightBorderSpace();
1718 pCurrPart
= pCurrPart
->GetFollow();
1720 nX
= std::max(static_cast<SwTwips
>(0), nX
- nSumBorderWidth
);
1722 // Shift the offset with the left border width
1723 else if( GetInfo().GetFont()->GetLeftBorder() && !pPor
->GetJoinBorderWithPrev() )
1725 nX
= std::max(static_cast<SwTwips
>(0), nX
- GetInfo().GetFont()->GetLeftBorderSpace());
1728 aDrawInf
.SetOffset( nX
);
1732 TextFrameIndex
nCharCnt(0);
1733 // #i41860# Thai justified alignment needs some
1734 // additional information:
1735 aDrawInf
.SetNumberOfBlanks( pPor
->InTextGrp() ?
1736 static_cast<const SwTextPortion
*>(pPor
)->GetSpaceCnt( aSizeInf
, nCharCnt
) :
1737 TextFrameIndex(0) );
1740 if ( pPor
->InFieldGrp() && pCMS
&& pCMS
->m_pSpecialPos
)
1741 aDrawInf
.SetLen( TextFrameIndex(COMPLETE_STRING
) );
1743 aDrawInf
.SetSpace( nSpaceAdd
);
1744 aDrawInf
.SetFont( aSizeInf
.GetFont() );
1745 aDrawInf
.SetFrame( m_pFrame
);
1746 aDrawInf
.SetSnapToGrid( aSizeInf
.SnapToGrid() );
1747 aDrawInf
.SetPosMatchesBounds( pCMS
&& pCMS
->m_bPosMatchesBounds
);
1749 if ( SwFontScript::CJK
== aSizeInf
.GetFont()->GetActual() &&
1750 pPara
->GetScriptInfo().CountCompChg() &&
1751 ! pPor
->InFieldGrp() )
1752 aDrawInf
.SetKanaComp( nKanaComp
);
1754 nLength
= aSizeInf
.GetFont()->GetModelPositionForViewPoint_( aDrawInf
);
1756 // get position inside field portion?
1757 if ( pPor
->InFieldGrp() && pCMS
&& pCMS
->m_pSpecialPos
)
1759 pCMS
->m_pSpecialPos
->nCharOfst
= sal_Int32(nLength
);
1760 nLength
= TextFrameIndex(0);
1763 // set cursor bidi level
1765 pCMS
->m_nCursorBidiLevel
=
1766 aDrawInf
.GetCursorBidiLevel();
1768 if( bFieldInfo
&& nLength
== pPor
->GetLen() &&
1769 ( ! pPor
->GetNextPortion() ||
1770 ! pPor
->GetNextPortion()->IsPostItsPortion() ) )
1774 const_cast<SwFont
*>(GetFnt())->SetProportion( nOldProp
);
1778 sw::FlyContentPortion
* pFlyPor(nullptr);
1779 if(bChgNode
&& pPos
&& (pFlyPor
= dynamic_cast<sw::FlyContentPortion
*>(pPor
)))
1781 // JP 24.11.94: if the Position is not in Fly, then
1782 // we many not return with COMPLETE_STRING as value!
1783 // (BugId: 9692 + Change in feshview)
1784 SwFlyInContentFrame
*pTmp
= pFlyPor
->GetFlyFrame();
1785 SwFrame
* pLower
= pTmp
->GetLower();
1786 // Allow non-text-frames to get SwGrfNode for as-char anchored images into pPos
1787 // instead of the closest SwTextNode, to be consistent with at-char behavior.
1788 bool bChgNodeInner
= pLower
1789 && (pLower
->IsTextFrame() || pLower
->IsLayoutFrame() || pLower
->IsNoTextFrame());
1790 Point
aTmpPoint( rPoint
);
1792 if ( m_pFrame
->IsRightToLeft() )
1793 m_pFrame
->SwitchLTRtoRTL( aTmpPoint
);
1795 if ( m_pFrame
->IsVertical() )
1796 m_pFrame
->SwitchHorizontalToVertical( aTmpPoint
);
1798 if( bChgNodeInner
&& pTmp
->getFrameArea().Contains( aTmpPoint
) &&
1799 !( pTmp
->IsProtected() ) )
1801 pFlyPor
->GetFlyCursorOfst(aTmpPoint
, *pPos
, pCMS
);
1802 // After a change of the frame, our font must be still
1803 // available for/in the OutputDevice.
1804 // For comparison: Paint and new SwFlyCntPortion !
1805 static_cast<SwTextSizeInfo
*>(m_pInf
)->SelectFont();
1807 // 6776: The pIter->GetModelPositionForViewPoint is returning here
1808 // from a nesting with COMPLETE_STRING.
1809 return TextFrameIndex(COMPLETE_STRING
);
1813 nLength
= pPor
->GetModelPositionForViewPoint( nX
);
1816 nOffset
= nCurrStart
+ nLength
;
1818 // 7684: We end up in front of the HyphPortion. We must assure
1819 // that we end up in the string.
1820 // If we are at end of line in front of FlyFrames, we must proceed the same way.
1821 if( nOffset
&& pPor
->GetLen() == nLength
&& pPor
->GetNextPortion() &&
1822 !pPor
->GetNextPortion()->GetLen() && pPor
->GetNextPortion()->InHyphGrp() )
1828 /** Looks for text portions which are inside the given rectangle
1830 For a rectangular text selection every text portions which is inside the given
1831 rectangle has to be put into the SwSelectionList as SwPaM
1832 From these SwPaM the SwCursors will be created.
1835 The container for the overlapped text portions
1838 A rectangle in document coordinates, text inside this rectangle has to be
1841 @return [ true, false ]
1842 true if any overlapping text portion has been found and put into list
1843 false if no portion overlaps, the list has been unchanged
1845 bool SwTextFrame::FillSelection( SwSelectionList
& rSelList
, const SwRect
& rRect
) const
1848 // GetPaintArea() instead getFrameArea() for negative indents
1849 SwRect
aTmpFrame( GetPaintArea() );
1850 if( !rRect
.Overlaps( aTmpFrame
) )
1852 if( rSelList
.checkContext( this ) )
1854 SwRect
aRect( aTmpFrame
);
1855 aRect
.Intersection( rRect
);
1856 SwPosition
aPosL( MapViewToModelPos(TextFrameIndex(0)) );
1859 SwPaM
*pPam
= new SwPaM( aPosL
, aPosL
);
1860 rSelList
.insertPaM( pPam
);
1862 else if( aRect
.HasArea() )
1864 SwPosition
aOld(aPosL
.GetNodes().GetEndOfContent());
1865 SwPosition
aPosR( aPosL
);
1867 SwTextInfo
aInf( const_cast<SwTextFrame
*>(this) );
1868 SwTextIter
aLine( const_cast<SwTextFrame
*>(this), &aInf
);
1869 // We have to care for top-to-bottom layout, where right becomes top etc.
1870 SwRectFnSet
aRectFnSet(this);
1871 SwTwips nTop
= aRectFnSet
.GetTop(aRect
);
1872 SwTwips nBottom
= aRectFnSet
.GetBottom(aRect
);
1873 SwTwips nLeft
= aRectFnSet
.GetLeft(aRect
);
1874 SwTwips nRight
= aRectFnSet
.GetRight(aRect
);
1875 SwTwips nY
= aLine
.Y(); // Top position of the first line
1876 SwTwips nLastY
= nY
;
1877 while( nY
< nTop
&& aLine
.Next() ) // line above rectangle
1882 bool bLastLine
= false;
1883 if( nY
< nTop
&& !aLine
.GetNext() )
1886 nY
+= aLine
.GetLineHeight();
1888 do // check the lines for overlapping
1890 if( nLastY
< nTop
) // if the last line was above rectangle
1892 if( nY
> nBottom
) // if the current line leaves the rectangle
1894 if( nY
>= nLastY
) // gotcha: overlapping
1898 if( aRectFnSet
.IsVert() )
1900 aPoint
.setX( nLastY
);
1901 aPoint
.setY( nLeft
);
1905 aPoint
.setX( nLeft
);
1906 aPoint
.setY( nLastY
);
1908 // Looking for the position of the left border of the rectangle
1909 // in this text line
1910 SwCursorMoveState
aState( CursorMoveState::UpDown
);
1911 if( GetModelPositionForViewPoint( &aPosL
, aPoint
, &aState
) )
1913 if( aRectFnSet
.IsVert() )
1915 aPoint
.setX( nLastY
);
1916 aPoint
.setY( nRight
);
1920 aPoint
.setX( nRight
);
1921 aPoint
.setY( nLastY
);
1923 // If we get a right position and if the left position
1924 // is not the same like the left position of the line before
1925 // which could happen e.g. for field portions or fly frames
1926 // a SwPaM will be inserted with these positions
1927 if( GetModelPositionForViewPoint( &aPosR
, aPoint
, &aState
) &&
1930 SwPaM
*pPam
= new SwPaM( aPosL
, aPosR
);
1931 rSelList
.insertPaM( pPam
);
1941 else if( !bLastLine
)
1945 nY
+= aLine
.GetLineHeight();
1949 }while( nLastY
< nBottom
);
1954 const SwSortedObjs
&rObjs
= *GetDrawObjs();
1955 for (SwAnchoredObject
* pAnchoredObj
: rObjs
)
1957 const SwFlyFrame
* pFly
= pAnchoredObj
->DynCastFlyFrame();
1960 if( pFly
->IsFlyInContentFrame() && pFly
->FillSelection( rSelList
, rRect
) )
1967 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */