1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <comphelper/flagguard.hxx>
22 #include <tools/line.hxx>
23 #include <editeng/opaqitem.hxx>
24 #include <editeng/protitem.hxx>
25 #include <vcl/settings.hxx>
26 #include <fmtpdsc.hxx>
27 #include <fmtsrnd.hxx>
28 #include <pagedesc.hxx>
29 #include <pagefrm.hxx>
30 #include <rootfrm.hxx>
35 #include <cellfrm.hxx>
37 #include <notxtfrm.hxx>
38 #include <viewopt.hxx>
39 #include <DocumentSettingManager.hxx>
41 #include <dflyobj.hxx>
42 #include <crstate.hxx>
43 #include <dcontact.hxx>
44 #include <sortedobjs.hxx>
45 #include <txatbase.hxx>
49 #include <frmtool.hxx>
53 #include <swselectionlist.hxx>
54 #include <comphelper/lok.hxx>
55 #include <osl/diagnose.h>
58 bool lcl_GetModelPositionForViewPoint_Objects( const SwPageFrame
* pPageFrame
, bool bSearchBackground
,
59 SwPosition
*pPos
, Point
const & rPoint
, SwCursorMoveState
* pCMS
)
62 Point
aPoint( rPoint
);
63 SwOrderIter
aIter( pPageFrame
);
67 const SwVirtFlyDrawObj
* pObj
=
68 static_cast<const SwVirtFlyDrawObj
*>(aIter());
69 const SwAnchoredObject
* pAnchoredObj
= GetUserCall( aIter() )->GetAnchoredObj( aIter() );
70 const SwFormatSurround
& rSurround
= pAnchoredObj
->GetFrameFormat().GetSurround();
71 const SvxOpaqueItem
& rOpaque
= pAnchoredObj
->GetFrameFormat().GetOpaque();
72 bool bInBackground
= ( rSurround
.GetSurround() == css::text::WrapTextMode_THROUGH
) && !rOpaque
.GetValue();
74 bool bBackgroundMatches
= bInBackground
== bSearchBackground
;
76 const SwFlyFrame
* pFly
= pObj
? pObj
->GetFlyFrame() : nullptr;
77 if ( pFly
&& bBackgroundMatches
&&
78 ( ( pCMS
&& pCMS
->m_bSetInReadOnly
) ||
79 !pFly
->IsProtected() ) &&
80 pFly
->GetModelPositionForViewPoint( pPos
, aPoint
, pCMS
) )
86 if ( pCMS
&& pCMS
->m_bStop
)
93 double lcl_getDistance( const SwRect
& rRect
, const Point
& rPoint
)
97 // If the point is inside the rectangle, then distance is 0
98 // Otherwise, compute the distance to the center of the rectangle.
99 if ( !rRect
.Contains( rPoint
) )
101 tools::Line
aLine( rPoint
, rRect
.Center( ) );
102 nDist
= aLine
.GetLength( );
111 //For SwFlyFrame::GetModelPositionForViewPoint
112 class SwCursorOszControl
115 // So the compiler can initialize the class already. No DTOR and member
117 const SwFlyFrame
* m_pEntry
;
118 const SwFlyFrame
* m_pStack1
;
119 const SwFlyFrame
* m_pStack2
;
121 bool ChkOsz( const SwFlyFrame
*pFly
)
124 if (pFly
!= m_pStack1
&& pFly
!= m_pStack2
)
126 m_pStack1
= m_pStack2
;
133 void Entry( const SwFlyFrame
*pFly
)
136 m_pEntry
= m_pStack1
= pFly
;
139 void Exit( const SwFlyFrame
*pFly
)
141 if (pFly
== m_pEntry
)
142 m_pEntry
= m_pStack1
= m_pStack2
= nullptr;
148 static SwCursorOszControl g_OszCtrl
= { nullptr, nullptr, nullptr };
150 /** Searches the ContentFrame owning the PrtArea containing the point. */
151 bool SwLayoutFrame::GetModelPositionForViewPoint( SwPosition
*pPos
, Point
&rPoint
,
152 SwCursorMoveState
* pCMS
, bool ) const
154 vcl::RenderContext
* pRenderContext
= getRootFrame()->GetCurrShell()->GetOut();
156 const SwFrame
*pFrame
= Lower();
157 while ( !bRet
&& pFrame
)
159 pFrame
->Calc(pRenderContext
);
161 // #i43742# New function
162 const bool bContentCheck
= pFrame
->IsTextFrame() && pCMS
&& pCMS
->m_bContentCheck
;
163 const SwRect
aPaintRect( bContentCheck
?
164 pFrame
->UnionFrame() :
165 pFrame
->GetPaintArea() );
167 if ( aPaintRect
.Contains( rPoint
) &&
168 ( bContentCheck
|| pFrame
->GetModelPositionForViewPoint( pPos
, rPoint
, pCMS
) ) )
171 pFrame
= pFrame
->GetNext();
172 if ( pCMS
&& pCMS
->m_bStop
)
178 /** Searches the page containing the searched point. */
180 bool SwPageFrame::GetModelPositionForViewPoint( SwPosition
*pPos
, Point
&rPoint
,
181 SwCursorMoveState
* pCMS
, bool bTestBackground
) const
183 Point
aPoint( rPoint
);
185 // check, if we have to adjust the point
186 if ( !getFrameArea().Contains( aPoint
) )
188 aPoint
.setX( std::max( aPoint
.X(), getFrameArea().Left() ) );
189 aPoint
.setX( std::min( aPoint
.X(), getFrameArea().Right() ) );
190 aPoint
.setY( std::max( aPoint
.Y(), getFrameArea().Top() ) );
191 aPoint
.setY( std::min( aPoint
.Y(), getFrameArea().Bottom() ) );
195 //Could it be a free flying one?
196 //If his content should be protected, we can't set the Cursor in it, thus
197 //all changes should be impossible.
198 if ( GetSortedObjs() )
200 bRet
= lcl_GetModelPositionForViewPoint_Objects( this, false, pPos
, rPoint
, pCMS
);
205 SwPosition
aBackPos( *pPos
);
206 SwPosition
aTextPos( *pPos
);
208 //We fix the StartPoint if no Content below the page 'answers' and then
209 //start all over again one page before the current one.
210 //However we can't use Flys in such a case.
211 if (!SwLayoutFrame::GetModelPositionForViewPoint(&aTextPos
, aPoint
, pCMS
))
213 if ( pCMS
&& (pCMS
->m_bStop
|| pCMS
->m_bExactOnly
) )
215 pCMS
->m_bStop
= true;
219 const SwContentFrame
*pCnt
= GetContentPos( aPoint
, false, false, pCMS
, false );
220 // GetContentPos may have modified pCMS
221 if ( pCMS
&& pCMS
->m_bStop
)
224 bool bTextRet
= false;
226 OSL_ENSURE( pCnt
, "Cursor is gone to a Black hole" );
227 if( pCMS
&& pCMS
->m_pFill
&& pCnt
->IsTextFrame() )
228 bTextRet
= pCnt
->GetModelPositionForViewPoint( &aTextPos
, rPoint
, pCMS
);
230 bTextRet
= pCnt
->GetModelPositionForViewPoint( &aTextPos
, aPoint
, pCMS
);
234 // Set point to pCnt, delete mark
235 // this may happen, if pCnt is hidden
236 if (pCnt
->IsTextFrame())
238 aTextPos
= static_cast<SwTextFrame
const*>(pCnt
)->MapViewToModelPos(TextFrameIndex(0));
242 assert(pCnt
->IsNoTextFrame());
243 aTextPos
.Assign( *static_cast<SwNoTextFrame
const*>(pCnt
)->GetNode() );
248 SwContentNode
* pContentNode
= aTextPos
.GetNode().GetContentNode();
249 bool bConsiderBackground
= true;
250 // If the text position is a clickable field, then that should have priority.
251 if (pContentNode
&& pContentNode
->IsTextNode())
253 SwTextNode
* pTextNd
= pContentNode
->GetTextNode();
254 SwTextAttr
* pTextAttr
= pTextNd
->GetTextAttrForCharAt(aTextPos
.GetContentIndex(), RES_TXTATR_FIELD
);
257 const SwField
* pField
= pTextAttr
->GetFormatField().GetField();
258 if (pField
->IsClickable())
259 bConsiderBackground
= false;
263 bool bBackRet
= false;
264 // Check objects in the background if nothing else matched
265 if ( GetSortedObjs() )
267 bBackRet
= lcl_GetModelPositionForViewPoint_Objects( this, true, &aBackPos
, rPoint
, pCMS
);
270 if (bConsiderBackground
&& bTestBackground
&& bBackRet
)
278 else // bBackRet && !(bConsiderBackground && bTestBackground)
280 /* In order to provide a selection as accurate as possible when we have both
281 * text and background object, then we compute the distance between both
282 * would-be positions and the click point. The shortest distance wins.
284 double nTextDistance
= 0;
285 bool bValidTextDistance
= false;
288 SwContentFrame
* pTextFrame
= pContentNode
->getLayoutFrame( getRootFrame( ) );
290 // try this again but prefer the "previous" position
291 SwCursorMoveState aMoveState
;
292 SwCursorMoveState
*const pState(pCMS
? pCMS
: &aMoveState
);
293 comphelper::FlagRestorationGuard
g(
294 pState
->m_bPosMatchesBounds
, true);
295 SwPosition
prevTextPos(*pPos
);
296 if (SwLayoutFrame::GetModelPositionForViewPoint(&prevTextPos
, aPoint
, pState
))
299 pTextFrame
->GetCharRect(aTextRect
, prevTextPos
);
301 if (prevTextPos
.GetContentIndex() < pContentNode
->Len())
303 // aRextRect is just a line on the left edge of the
304 // previous character; to get a better measure from
305 // lcl_getDistance, extend that to a rectangle over
306 // the entire character.
307 SwPosition
nextTextPos(prevTextPos
);
308 nextTextPos
.AdjustContent(+1);
310 pTextFrame
->GetCharRect(nextTextRect
, nextTextPos
);
311 SwRectFnSet
aRectFnSet(pTextFrame
);
312 if (aRectFnSet
.GetTop(aTextRect
) ==
313 aRectFnSet
.GetTop(nextTextRect
)) // same line?
315 // need to handle mixed RTL/LTR portions somehow
316 if (aRectFnSet
.GetLeft(aTextRect
) <
317 aRectFnSet
.GetLeft(nextTextRect
))
319 aRectFnSet
.SetRight( aTextRect
,
320 aRectFnSet
.GetLeft(nextTextRect
));
324 aRectFnSet
.SetLeft( aTextRect
,
325 aRectFnSet
.GetLeft(nextTextRect
));
330 nTextDistance
= lcl_getDistance(aTextRect
, rPoint
);
331 bValidTextDistance
= true;
335 double nBackDistance
= 0;
336 bool bValidBackDistance
= false;
337 SwContentNode
* pBackNd
= aBackPos
.GetNode( ).GetContentNode( );
338 if ( pBackNd
&& bConsiderBackground
)
340 // FIXME There are still cases were we don't have the proper node here.
341 SwContentFrame
* pBackFrame
= pBackNd
->getLayoutFrame( getRootFrame( ) );
345 pBackFrame
->GetCharRect( rBackRect
, aBackPos
);
347 nBackDistance
= lcl_getDistance( rBackRect
, rPoint
);
348 bValidBackDistance
= true;
352 if ( bValidTextDistance
&& bValidBackDistance
&& basegfx::fTools::more( nTextDistance
, nBackDistance
) )
367 bool SwLayoutFrame::FillSelection( SwSelectionList
& rList
, const SwRect
& rRect
) const
369 if( rRect
.Overlaps(GetPaintArea()) )
371 const SwFrame
* pFrame
= Lower();
374 pFrame
->FillSelection( rList
, rRect
);
375 pFrame
= pFrame
->GetNext();
381 bool SwPageFrame::FillSelection( SwSelectionList
& rList
, const SwRect
& rRect
) const
384 if( rRect
.Overlaps(GetPaintArea()) )
386 bRet
= SwLayoutFrame::FillSelection( rList
, rRect
);
387 if( GetSortedObjs() )
389 const SwSortedObjs
&rObjs
= *GetSortedObjs();
390 for (SwAnchoredObject
* pAnchoredObj
: rObjs
)
392 const SwFlyFrame
* pFly
= pAnchoredObj
->DynCastFlyFrame();
395 if( pFly
->FillSelection( rList
, rRect
) )
403 bool SwRootFrame::FillSelection( SwSelectionList
& aSelList
, const SwRect
& rRect
) const
405 const SwFrame
*pPage
= Lower();
406 const tools::Long nBottom
= rRect
.Bottom();
409 if( pPage
->getFrameArea().Top() < nBottom
)
411 if( pPage
->getFrameArea().Bottom() > rRect
.Top() )
412 pPage
->FillSelection( aSelList
, rRect
);
413 pPage
= pPage
->GetNext();
418 return !aSelList
.isEmpty();
421 /** Primary passes the call to the first page.
423 * @return false, if the passed Point gets changed
425 bool SwRootFrame::GetModelPositionForViewPoint( SwPosition
*pPos
, Point
&rPoint
,
426 SwCursorMoveState
* pCMS
, bool bTestBackground
) const
428 const bool bOldAction
= IsCallbackActionEnabled();
429 const_cast<SwRootFrame
*>(this)->SetCallbackActionEnabled( false );
430 OSL_ENSURE( (Lower() && Lower()->IsPageFrame()), "No PageFrame found." );
431 if( pCMS
&& pCMS
->m_pFill
)
432 pCMS
->m_bFillRet
= false;
433 Point aOldPoint
= rPoint
;
435 // search for page containing rPoint. The borders around the pages are considered
436 const SwPageFrame
* pPage
= GetPageAtPos( rPoint
, nullptr, true );
439 // special handling for <rPoint> beyond root frames area
441 rPoint
.X() > getFrameArea().Right() &&
442 rPoint
.Y() > getFrameArea().Bottom() )
444 pPage
= dynamic_cast<const SwPageFrame
*>(Lower());
445 while ( pPage
&& pPage
->GetNext() )
447 pPage
= dynamic_cast<const SwPageFrame
*>(pPage
->GetNext());
452 pPage
->SwPageFrame::GetModelPositionForViewPoint( pPos
, rPoint
, pCMS
, bTestBackground
);
455 const_cast<SwRootFrame
*>(this)->SetCallbackActionEnabled( bOldAction
);
461 return pCMS
->m_bFillRet
;
463 return aOldPoint
== rPoint
;
467 * If this is about a Content-carrying cell the Cursor will be force inserted into one of the ContentFrames
468 * if there are no other options.
470 * There is no entry for protected cells.
472 bool SwCellFrame::GetModelPositionForViewPoint( SwPosition
*pPos
, Point
&rPoint
,
473 SwCursorMoveState
* pCMS
, bool ) const
475 vcl::RenderContext
* pRenderContext
= getRootFrame()->GetCurrShell()->GetOut();
476 // cell frame does not necessarily have a lower (split table cell)
480 if ( !(pCMS
&& pCMS
->m_bSetInReadOnly
) &&
481 GetFormat()->GetProtect().IsContentProtected() )
484 if ( pCMS
&& pCMS
->m_eState
== CursorMoveState::TableSel
)
486 const SwTabFrame
*pTab
= FindTabFrame();
487 if ( pTab
->IsFollow() && pTab
->IsInHeadline( *this ) )
489 pCMS
->m_bStop
= true;
496 if ( Lower()->IsLayoutFrame() )
497 return SwLayoutFrame::GetModelPositionForViewPoint( pPos
, rPoint
, pCMS
);
500 Calc(pRenderContext
);
503 const SwFrame
*pFrame
= Lower();
504 while ( pFrame
&& !bRet
)
506 pFrame
->Calc(pRenderContext
);
507 if ( pFrame
->getFrameArea().Contains( rPoint
) )
509 bRet
= pFrame
->GetModelPositionForViewPoint( pPos
, rPoint
, pCMS
);
510 if ( pCMS
&& pCMS
->m_bStop
)
513 pFrame
= pFrame
->GetNext();
517 const bool bFill
= pCMS
&& pCMS
->m_pFill
;
518 Point
aPoint( rPoint
);
519 const SwContentFrame
*pCnt
= GetContentPos( rPoint
, true );
520 if( bFill
&& pCnt
->IsTextFrame() )
524 pCnt
->GetModelPositionForViewPoint( pPos
, rPoint
, pCMS
);
533 //Problem: If two Flys have the same size and share the same position then
534 //they end inside each other.
535 //Because we recursively check if a Point doesn't randomly lie inside another
536 //fly which lies completely inside the current Fly we could trigger an endless
537 //loop with the mentioned situation above.
538 //Using the helper class SwCursorOszControl we prevent the recursion. During
539 //a recursion GetModelPositionForViewPoint picks the one which lies on top.
540 bool SwFlyFrame::GetModelPositionForViewPoint( SwPosition
*pPos
, Point
&rPoint
,
541 SwCursorMoveState
* pCMS
, bool ) const
543 vcl::RenderContext
* pRenderContext
= getRootFrame()->GetCurrShell()->GetOut();
544 g_OszCtrl
.Entry( this );
546 //If the Points lies inside the Fly, we try hard to set the Cursor inside it.
547 //However if the Point sits inside a Fly which is completely located inside
548 //the current one, we call GetModelPositionForViewPoint for it.
549 Calc(pRenderContext
);
550 bool bInside
= getFrameArea().Contains( rPoint
) && Lower();
553 //If a Frame contains a graphic, but only text was requested, it basically
554 //won't accept the Cursor.
555 if ( bInside
&& pCMS
&& pCMS
->m_eState
== CursorMoveState::SetOnlyText
&&
556 (!Lower() || Lower()->IsNoTextFrame()) )
559 const SwPageFrame
*pPage
= FindPageFrame();
560 if ( bInside
&& pPage
&& pPage
->GetSortedObjs() )
562 SwOrderIter
aIter( pPage
);
564 while ( aIter() && !bRet
)
566 const SwVirtFlyDrawObj
* pObj
= static_cast<const SwVirtFlyDrawObj
*>(aIter());
567 const SwFlyFrame
* pFly
= pObj
? pObj
->GetFlyFrame() : nullptr;
568 if ( pFly
&& pFly
->getFrameArea().Contains( rPoint
) &&
569 getFrameArea().Contains( pFly
->getFrameArea() ) )
571 if (g_OszCtrl
.ChkOsz(pFly
))
573 bRet
= pFly
->GetModelPositionForViewPoint( pPos
, rPoint
, pCMS
);
576 if ( pCMS
&& pCMS
->m_bStop
)
583 while ( bInside
&& !bRet
)
585 const SwFrame
*pFrame
= Lower();
586 while ( pFrame
&& !bRet
)
588 pFrame
->Calc(pRenderContext
);
589 if ( pFrame
->getFrameArea().Contains( rPoint
) )
591 bRet
= pFrame
->GetModelPositionForViewPoint( pPos
, rPoint
, pCMS
);
592 if ( pCMS
&& pCMS
->m_bStop
)
595 pFrame
= pFrame
->GetNext();
599 const bool bFill
= pCMS
&& pCMS
->m_pFill
;
600 Point
aPoint( rPoint
);
601 const SwContentFrame
*pCnt
= GetContentPos( rPoint
, true, false, pCMS
);
602 if ( pCMS
&& pCMS
->m_bStop
)
604 if( bFill
&& pCnt
->IsTextFrame() )
608 pCnt
->GetModelPositionForViewPoint( pPos
, rPoint
, pCMS
);
612 g_OszCtrl
.Exit( this );
616 /** Layout dependent cursor travelling */
617 bool SwNoTextFrame::LeftMargin(SwPaM
*pPam
) const
619 if( &pPam
->GetPointNode() != GetNode() )
621 pPam
->GetPoint()->AssignStartIndex(*GetNode());
625 bool SwNoTextFrame::RightMargin(SwPaM
*pPam
, bool) const
627 if( &pPam
->GetPointNode() != GetNode() )
629 pPam
->GetPoint()->AssignEndIndex(*GetNode());
633 static const SwContentFrame
*lcl_GetNxtCnt( const SwContentFrame
* pCnt
)
635 return pCnt
->GetNextContentFrame();
638 static const SwContentFrame
*lcl_GetPrvCnt( const SwContentFrame
* pCnt
)
640 return pCnt
->GetPrevContentFrame();
643 typedef const SwContentFrame
*(*GetNxtPrvCnt
)( const SwContentFrame
* );
645 /// Frame in repeated headline?
646 static bool lcl_IsInRepeatedHeadline( const SwFrame
*pFrame
,
647 const SwTabFrame
** ppTFrame
= nullptr )
649 const SwTabFrame
*pTab
= pFrame
->FindTabFrame();
652 return pTab
&& pTab
->IsFollow() && pTab
->IsInHeadline( *pFrame
);
655 /// Skip protected table cells. Optionally also skip repeated headlines.
656 //MA 1998-01-26: Chg also skip other protected areas
657 //FME: Skip follow flow cells
658 static const SwContentFrame
* lcl_MissProtectedFrames( const SwContentFrame
*pCnt
,
659 GetNxtPrvCnt fnNxtPrv
,
662 bool bMissFollowFlowLine
)
664 if ( pCnt
&& pCnt
->IsInTab() )
666 bool bProtect
= true;
667 while ( pCnt
&& bProtect
)
669 const SwLayoutFrame
*pCell
= pCnt
->GetUpper();
670 while ( pCell
&& !pCell
->IsCellFrame() )
671 pCell
= pCell
->GetUpper();
673 ( ( bInReadOnly
|| !pCell
->GetFormat()->GetProtect().IsContentProtected() ) &&
674 ( !bMissHeadline
|| !lcl_IsInRepeatedHeadline( pCell
) ) &&
675 ( !bMissFollowFlowLine
|| !pCell
->IsInFollowFlowRow() ) &&
676 !pCell
->IsCoveredCell() ) )
679 pCnt
= (*fnNxtPrv
)( pCnt
);
682 else if ( !bInReadOnly
)
683 while ( pCnt
&& pCnt
->IsProtected() )
684 pCnt
= (*fnNxtPrv
)( pCnt
);
689 static bool lcl_UpDown( SwPaM
*pPam
, const SwContentFrame
*pStart
,
690 GetNxtPrvCnt fnNxtPrv
, bool bInReadOnly
)
692 OSL_ENSURE( FrameContainsNode(*pStart
, pPam
->GetPointNode().GetIndex()),
693 "lcl_UpDown doesn't work for others." );
695 const SwContentFrame
*pCnt
= nullptr;
697 //We have to cheat a little bit during a table selection: Go to the
698 //beginning of the cell while going up and go to the end of the cell while
700 bool bTableSel
= false;
701 if ( pStart
->IsInTab() &&
702 pPam
->GetPointNode().StartOfSectionNode() !=
703 pPam
->GetMarkNode().StartOfSectionNode() )
706 const SwLayoutFrame
*pCell
= pStart
->GetUpper();
707 while ( !pCell
->IsCellFrame() )
708 pCell
= pCell
->GetUpper();
710 // Check, if cell has a Prev/Follow cell:
711 const bool bFwd
= ( fnNxtPrv
== lcl_GetNxtCnt
);
712 const SwLayoutFrame
* pTmpCell
= bFwd
?
713 static_cast<const SwCellFrame
*>(pCell
)->GetFollowCell() :
714 static_cast<const SwCellFrame
*>(pCell
)->GetPreviousCell();
716 const SwContentFrame
* pTmpStart
= pStart
;
717 while ( pTmpCell
&& nullptr != ( pTmpStart
= pTmpCell
->ContainsContent() ) )
721 static_cast<const SwCellFrame
*>(pCell
)->GetFollowCell() :
722 static_cast<const SwCellFrame
*>(pCell
)->GetPreviousCell();
724 const SwContentFrame
*pNxt
= pCnt
= pTmpStart
;
726 while ( pCell
->IsAnLower( pNxt
) )
729 pNxt
= (*fnNxtPrv
)( pNxt
);
733 pCnt
= (*fnNxtPrv
)( pCnt
? pCnt
: pStart
);
734 pCnt
= ::lcl_MissProtectedFrames( pCnt
, fnNxtPrv
, true, bInReadOnly
, bTableSel
);
736 const SwTabFrame
*pStTab
= pStart
->FindTabFrame();
737 const SwTabFrame
*pTable
= nullptr;
738 const bool bTab
= pStTab
|| (pCnt
&& pCnt
->IsInTab());
741 const SwFrame
* pVertRefFrame
= pStart
;
742 if ( bTableSel
&& pStTab
)
743 pVertRefFrame
= pStTab
;
744 SwRectFnSet
aRectFnSet(pVertRefFrame
);
749 // pStart or pCnt is inside a table. nX will be used for travelling:
750 SwRect
aRect( pStart
->getFrameArea() );
751 pStart
->GetCharRect( aRect
, *pPam
->GetPoint() );
752 Point aCenter
= aRect
.Center();
753 nX
= aRectFnSet
.IsVert() ? aCenter
.Y() : aCenter
.X();
755 pTable
= pCnt
? pCnt
->FindTabFrame() : nullptr;
760 !pStTab
->GetUpper()->IsInTab() &&
761 !pTable
->GetUpper()->IsInTab() )
763 const SwFrame
*pCell
= pStart
->GetUpper();
764 while ( pCell
&& !pCell
->IsCellFrame() )
765 pCell
= pCell
->GetUpper();
766 OSL_ENSURE( pCell
, "could not find the cell" );
767 nX
= aRectFnSet
.XInc(aRectFnSet
.GetLeft(pCell
->getFrameArea()),
768 aRectFnSet
.GetWidth(pCell
->getFrameArea()) / 2);
770 //The flow leads from one table to the next. The X-value needs to be
771 //corrected based on the middle of the starting cell by the amount
772 //of the offset of the tables.
773 if ( pStTab
!= pTable
)
775 nX
+= aRectFnSet
.GetLeft(pTable
->getFrameArea()) -
776 aRectFnSet
.GetLeft(pStTab
->getFrameArea());
780 // Restrict nX to the left and right borders of pTab:
781 // (is this really necessary?)
782 if (pTable
&& !pTable
->GetUpper()->IsInTab())
784 const bool bRTL
= pTable
->IsRightToLeft();
785 const tools::Long nPrtLeft
= bRTL
?
786 aRectFnSet
.GetPrtRight(*pTable
) :
787 aRectFnSet
.GetPrtLeft(*pTable
);
788 if (bRTL
!= (aRectFnSet
.XDiff(nPrtLeft
, nX
) > 0))
792 const tools::Long nPrtRight
= bRTL
?
793 aRectFnSet
.GetPrtLeft(*pTable
) :
794 aRectFnSet
.GetPrtRight(*pTable
);
795 if (bRTL
!= (aRectFnSet
.XDiff(nX
, nPrtRight
) > 0))
803 //If I'm in the DocumentBody, I want to stay there.
804 if ( pStart
->IsInDocBody() )
806 while ( pCnt
&& (!pCnt
->IsInDocBody() ||
807 (pCnt
->IsTextFrame() && static_cast<const SwTextFrame
*>(pCnt
)->IsHiddenNow())))
809 pCnt
= (*fnNxtPrv
)( pCnt
);
810 pCnt
= ::lcl_MissProtectedFrames( pCnt
, fnNxtPrv
, true, bInReadOnly
, bTableSel
);
814 //If I'm in the FootNoteArea, I try to reach the next FootNoteArea in
816 else if ( pStart
->IsInFootnote() )
818 while ( pCnt
&& (!pCnt
->IsInFootnote() ||
819 (pCnt
->IsTextFrame() && static_cast<const SwTextFrame
*>(pCnt
)->IsHiddenNow())))
821 pCnt
= (*fnNxtPrv
)( pCnt
);
822 pCnt
= ::lcl_MissProtectedFrames( pCnt
, fnNxtPrv
, true, bInReadOnly
, bTableSel
);
826 //In Flys we can go ahead blindly as long as we find a Content.
827 else if ( pStart
->IsInFly() )
829 if ( pCnt
&& pCnt
->IsTextFrame() && static_cast<const SwTextFrame
*>(pCnt
)->IsHiddenNow() )
831 pCnt
= (*fnNxtPrv
)( pCnt
);
832 pCnt
= ::lcl_MissProtectedFrames( pCnt
, fnNxtPrv
, true, bInReadOnly
, bTableSel
);
836 //Otherwise I'll just refuse to leave to current area.
839 const SwFrame
*pUp
= pStart
->GetUpper();
840 while (pUp
&& pUp
->GetUpper() && !(pUp
->GetType() & FRM_HEADFOOT
))
841 pUp
= pUp
->GetUpper();
843 const SwFrame
*pCntUp
= pCnt
->GetUpper();
844 while ( pCntUp
&& !bSame
)
849 pCntUp
= pCntUp
->GetUpper();
853 else if (pCnt
->IsTextFrame() && static_cast<const SwTextFrame
*>(pCnt
)->IsHiddenNow()) // i73332
855 pCnt
= (*fnNxtPrv
)( pCnt
);
856 pCnt
= ::lcl_MissProtectedFrames( pCnt
, fnNxtPrv
, true, bInReadOnly
, bTableSel
);
866 const SwTabFrame
*pTab
= pCnt
->FindTabFrame();
871 if ( pTab
!= pTable
)
873 //The flow leads from one table to the next. The X-value
874 //needs to be corrected by the amount of the offset of
877 !pTab
->GetUpper()->IsInTab() &&
878 !pTable
->GetUpper()->IsInTab() )
879 nX
+= pTab
->getFrameArea().Left() - pTable
->getFrameArea().Left();
882 const SwLayoutFrame
*pCell
= pCnt
->GetUpper();
883 while ( pCell
&& !pCell
->IsCellFrame() )
884 pCell
= pCell
->GetUpper();
890 tools::Long nTmpTop
= aRectFnSet
.GetTop(pCell
->getFrameArea());
891 if ( aRectFnSet
.IsVert() )
894 nTmpTop
= aRectFnSet
.XInc(nTmpTop
, -1);
896 aInsideCell
= Point( nTmpTop
, nX
);
899 aInsideCell
= Point( nX
, nTmpTop
);
902 tools::Long nTmpTop
= aRectFnSet
.GetTop(pCnt
->getFrameArea());
903 if ( aRectFnSet
.IsVert() )
906 nTmpTop
= aRectFnSet
.XInc(nTmpTop
, -1);
908 aInsideCnt
= Point( nTmpTop
, nX
);
911 aInsideCnt
= Point( nX
, nTmpTop
);
913 if ( pCell
&& pCell
->getFrameArea().Contains( aInsideCell
) )
916 //Get the right Content out of the cell.
917 if ( !pCnt
->getFrameArea().Contains( aInsideCnt
) )
919 pCnt
= pCell
->ContainsContent();
920 if ( fnNxtPrv
== lcl_GetPrvCnt
)
921 while ( pCell
->IsAnLower(pCnt
->GetNextContentFrame()) )
922 pCnt
= pCnt
->GetNextContentFrame();
925 else if ( pCnt
->getFrameArea().Contains( aInsideCnt
) )
931 pCnt
= (*fnNxtPrv
)( pCnt
);
932 pCnt
= ::lcl_MissProtectedFrames( pCnt
, fnNxtPrv
, true, bInReadOnly
, bTableSel
);
937 (pCnt
&& pCnt
->IsTextFrame() && static_cast<const SwTextFrame
*>(pCnt
)->IsHiddenNow()));
943 if (pCnt
->IsTextFrame())
945 SwTextFrame
const*const pFrame(static_cast<SwTextFrame
const*>(pCnt
));
946 *pPam
->GetPoint() = pFrame
->MapViewToModelPos(TextFrameIndex(
947 fnNxtPrv
== lcl_GetPrvCnt
948 ? pFrame
->GetText().getLength()
952 { // set the Point on the Content-Node
953 assert(pCnt
->IsNoTextFrame());
954 SwContentNode
*const pCNd
= const_cast<SwContentNode
*>(static_cast<SwNoTextFrame
const*>(pCnt
)->GetNode());
955 if ( fnNxtPrv
== lcl_GetPrvCnt
)
956 pPam
->GetPoint()->AssignEndIndex(*pCNd
);
958 pPam
->GetPoint()->AssignStartIndex(*pCNd
);
963 bool SwContentFrame::UnitUp( SwPaM
* pPam
, const SwTwips
, bool bInReadOnly
) const
965 return ::lcl_UpDown( pPam
, this, lcl_GetPrvCnt
, bInReadOnly
);
968 bool SwContentFrame::UnitDown( SwPaM
* pPam
, const SwTwips
, bool bInReadOnly
) const
970 return ::lcl_UpDown( pPam
, this, lcl_GetNxtCnt
, bInReadOnly
);
973 /** Returns the number of the current page.
975 * If the method gets a PaM then the current page is the one in which the PaM sits. Otherwise the
976 * current page is the first one inside the VisibleArea. We only work on available pages!
978 sal_uInt16
SwRootFrame::GetCurrPage( const SwPaM
*pActualCursor
) const
980 OSL_ENSURE( pActualCursor
, "got no page cursor" );
981 SwFrame
const*const pActFrame
= pActualCursor
->GetPoint()->GetNode().
982 GetContentNode()->getLayoutFrame(this,
983 pActualCursor
->GetPoint());
984 return pActFrame
->FindPageFrame()->GetPhyPageNum();
987 /** Returns a PaM which sits at the beginning of the requested page.
989 * Formatting is done as far as necessary.
990 * The PaM sits on the last page, if the page number was chosen too big.
992 * @return Null, if the operation was not possible.
994 sal_uInt16
SwRootFrame::SetCurrPage( SwCursor
* pToSet
, sal_uInt16 nPageNum
)
996 vcl::RenderContext
* pRenderContext
= GetCurrShell() ? GetCurrShell()->GetOut() : nullptr;
997 OSL_ENSURE( Lower() && Lower()->IsPageFrame(), "No page available." );
999 SwPageFrame
*pPage
= static_cast<SwPageFrame
*>(Lower());
1001 while ( !bEnd
&& pPage
->GetPhyPageNum() != nPageNum
)
1002 { if ( pPage
->GetNext() )
1003 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
1005 { //Search the first ContentFrame and format until a new page is started
1006 //or until the ContentFrame are all done.
1007 const SwContentFrame
*pContent
= pPage
->ContainsContent();
1008 while ( pContent
&& pPage
->IsAnLower( pContent
) )
1010 pContent
->Calc(pRenderContext
);
1011 pContent
= pContent
->GetNextContentFrame();
1013 //Either this is a new page or we found the last page.
1014 if ( pPage
->GetNext() )
1015 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
1020 //pPage now points to the 'requested' page. Now we have to create the PaM
1021 //on the beginning of the first ContentFrame in the body-text.
1022 //If this is a footnote-page, the PaM will be set in the first footnote.
1023 const SwContentFrame
*pContent
= pPage
->ContainsContent();
1024 if ( pPage
->IsFootnotePage() )
1025 while ( pContent
&& !pContent
->IsInFootnote() )
1026 pContent
= pContent
->GetNextContentFrame();
1028 while ( pContent
&& !pContent
->IsInDocBody() )
1029 pContent
= pContent
->GetNextContentFrame();
1032 assert(pContent
->IsTextFrame());
1033 SwTextFrame
const*const pFrame(static_cast<const SwTextFrame
*>(pContent
));
1034 *pToSet
->GetPoint() = pFrame
->MapViewToModelPos(pFrame
->GetOffset());
1036 SwShellCursor
* pSCursor
= dynamic_cast<SwShellCursor
*>(pToSet
);
1039 Point
&rPt
= pSCursor
->GetPtPos();
1040 rPt
= pContent
->getFrameArea().Pos();
1041 rPt
+= pContent
->getFramePrintArea().Pos();
1043 return pPage
->GetPhyPageNum();
1048 SwContentFrame
*GetFirstSub( const SwLayoutFrame
*pLayout
)
1050 return const_cast<SwPageFrame
*>(static_cast<const SwPageFrame
*>(pLayout
))->FindFirstBodyContent();
1053 SwContentFrame
*GetLastSub( const SwLayoutFrame
*pLayout
)
1055 return const_cast<SwPageFrame
*>(static_cast<const SwPageFrame
*>(pLayout
))->FindLastBodyContent();
1058 SwLayoutFrame
*GetNextFrame( const SwLayoutFrame
*pFrame
)
1060 SwLayoutFrame
*pNext
=
1061 (pFrame
->GetNext() && pFrame
->GetNext()->IsLayoutFrame()) ?
1062 const_cast<SwLayoutFrame
*>(static_cast<const SwLayoutFrame
*>(pFrame
->GetNext())) : nullptr;
1063 // #i39402# in case of an empty page
1064 if(pNext
&& !pNext
->ContainsContent())
1065 pNext
= (pNext
->GetNext() && pNext
->GetNext()->IsLayoutFrame()) ?
1066 static_cast<SwLayoutFrame
*>(pNext
->GetNext()) : nullptr;
1070 SwLayoutFrame
*GetThisFrame( const SwLayoutFrame
*pFrame
)
1072 return const_cast<SwLayoutFrame
*>(pFrame
);
1075 SwLayoutFrame
*GetPrevFrame( const SwLayoutFrame
*pFrame
)
1077 SwLayoutFrame
*pPrev
=
1078 (pFrame
->GetPrev() && pFrame
->GetPrev()->IsLayoutFrame()) ?
1079 const_cast<SwLayoutFrame
*>(static_cast<const SwLayoutFrame
*>(pFrame
->GetPrev())) : nullptr;
1080 // #i39402# in case of an empty page
1081 if(pPrev
&& !pPrev
->ContainsContent())
1082 pPrev
= (pPrev
->GetPrev() && pPrev
->GetPrev()->IsLayoutFrame()) ?
1083 static_cast<SwLayoutFrame
*>(pPrev
->GetPrev()) : nullptr;
1088 * Returns the first/last Contentframe (controlled using the parameter fnPosPage)
1089 * of the current/previous/next page (controlled using the parameter fnWhichPage).
1091 bool GetFrameInPage( const SwContentFrame
*pCnt
, SwWhichPage fnWhichPage
,
1092 SwPosPage fnPosPage
, SwPaM
*pPam
)
1094 //First find the requested page, at first the current, then the one which
1095 //was requests through fnWichPage.
1096 const SwLayoutFrame
*pLayoutFrame
= pCnt
->FindPageFrame();
1097 if ( !pLayoutFrame
|| (nullptr == (pLayoutFrame
= (*fnWhichPage
)(pLayoutFrame
))) )
1100 //Now the desired ContentFrame below the page
1101 pCnt
= (*fnPosPage
)(pLayoutFrame
);
1102 if( nullptr == pCnt
)
1106 // repeated headlines in tables
1107 if ( pCnt
->IsInTab() && fnPosPage
== GetFirstSub
)
1109 const SwTabFrame
* pTab
= pCnt
->FindTabFrame();
1110 if ( pTab
->IsFollow() )
1112 if ( pTab
->IsInHeadline( *pCnt
) )
1114 SwLayoutFrame
* pRow
= pTab
->GetFirstNonHeadlineRow();
1117 // We are in the first line of a follow table
1118 // with repeated headings.
1119 // To actually make a "real" move we take the first content
1121 pCnt
= pRow
->ContainsContent();
1129 assert(pCnt
->IsTextFrame());
1130 SwTextFrame
const*const pFrame(static_cast<const SwTextFrame
*>(pCnt
));
1131 TextFrameIndex
const nIdx((fnPosPage
== GetFirstSub
)
1132 ? pFrame
->GetOffset()
1133 : (pFrame
->GetFollow())
1134 ? pFrame
->GetFollow()->GetOffset() - TextFrameIndex(1)
1135 : TextFrameIndex(pFrame
->GetText().getLength()));
1136 *pPam
->GetPoint() = pFrame
->MapViewToModelPos(nIdx
);
1141 static sal_uInt64
CalcDiff(const Point
&rPt1
, const Point
&rPt2
)
1143 //Calculate the distance between the two points.
1144 //'delta' X^2 + 'delta'Y^2 = 'distance'^2
1145 sal_uInt64 dX
= std::max( rPt1
.X(), rPt2
.X() ) -
1146 std::min( rPt1
.X(), rPt2
.X() ),
1147 dY
= std::max( rPt1
.Y(), rPt2
.Y() ) -
1148 std::min( rPt1
.Y(), rPt2
.Y() );
1149 return (dX
* dX
) + (dY
* dY
);
1152 /** Check if the point lies inside the page part in which also the ContentFrame lies.
1154 * In this context header, page body, footer and footnote-container count as page part.
1155 * This will suit the purpose that the ContentFrame which lies in the "right" page part will be
1156 * accepted instead of one which doesn't lie there although his distance to the point is shorter.
1158 static const SwLayoutFrame
* lcl_Inside( const SwContentFrame
*pCnt
, Point
const & rPt
)
1160 const SwLayoutFrame
* pUp
= pCnt
->GetUpper();
1163 if( pUp
->IsPageBodyFrame() || pUp
->IsFooterFrame() || pUp
->IsHeaderFrame() )
1165 if( rPt
.Y() >= pUp
->getFrameArea().Top() && rPt
.Y() <= pUp
->getFrameArea().Bottom() )
1169 if( pUp
->IsFootnoteContFrame() )
1170 return pUp
->getFrameArea().Contains( rPt
) ? pUp
: nullptr;
1171 pUp
= pUp
->GetUpper();
1176 /** Search for the nearest Content to pass.
1178 * Considers the previous, the current and the next page.
1179 * If no content is found, the area gets expanded until one is found.
1181 * @return The 'semantically correct' position inside the PrtArea of the found ContentFrame.
1183 const SwContentFrame
*SwLayoutFrame::GetContentPos( Point
& rPoint
,
1184 const bool bDontLeave
,
1185 const bool bBodyOnly
,
1186 SwCursorMoveState
*pCMS
,
1187 const bool bDefaultExpand
) const
1189 //Determine the first ContentFrame.
1190 const SwLayoutFrame
*pStart
= (!bDontLeave
&& bDefaultExpand
&& GetPrev()) ?
1191 static_cast<const SwLayoutFrame
*>(GetPrev()) : this;
1192 const SwContentFrame
*pContent
= pStart
->ContainsContent();
1194 if ( !pContent
&& (GetPrev() && !bDontLeave
) )
1195 pContent
= ContainsContent();
1197 if ( bBodyOnly
&& pContent
&& !pContent
->IsInDocBody() )
1198 while ( pContent
&& !pContent
->IsInDocBody() )
1199 pContent
= pContent
->GetNextContentFrame();
1201 const SwContentFrame
*pActual
= pContent
;
1202 const SwLayoutFrame
*pInside
= nullptr;
1203 sal_uInt16 nMaxPage
= GetPhyPageNum() + (bDefaultExpand
? 1 : 0);
1204 Point aPoint
= rPoint
;
1205 sal_uInt64 nDistance
= SAL_MAX_UINT64
;
1207 while ( true ) //A loop to be sure we always find one.
1210 ((!bDontLeave
|| IsAnLower( pContent
)) &&
1211 (pContent
->GetPhyPageNum() <= nMaxPage
)) )
1213 if ( pContent
->getFrameArea().Width() &&
1214 ( !bBodyOnly
|| pContent
->IsInDocBody() ) )
1216 //If the Content lies in a protected area (cell, Footnote, section),
1217 //we search the next Content which is not protected.
1218 const SwContentFrame
*pComp
= pContent
;
1219 pContent
= ::lcl_MissProtectedFrames( pContent
, lcl_GetNxtCnt
, false,
1220 pCMS
&& pCMS
->m_bSetInReadOnly
, false );
1221 if ( pComp
!= pContent
)
1224 if ( !pContent
->IsTextFrame() || !static_cast<const SwTextFrame
*>(pContent
)->IsHiddenNow() )
1226 SwRect
aContentFrame( pContent
->UnionFrame() );
1227 if ( aContentFrame
.Contains( rPoint
) )
1233 //The distance from rPoint to the nearest Point of pContent
1234 //will now be calculated.
1235 Point
aContentPoint( rPoint
);
1237 //First set the vertical position
1238 if ( aContentFrame
.Top() > aContentPoint
.Y() )
1239 aContentPoint
.setY( aContentFrame
.Top() );
1240 else if ( aContentFrame
.Bottom() < aContentPoint
.Y() )
1241 aContentPoint
.setY( aContentFrame
.Bottom() );
1243 //Now the horizontal position
1244 if ( aContentFrame
.Left() > aContentPoint
.X() )
1245 aContentPoint
.setX( aContentFrame
.Left() );
1246 else if ( aContentFrame
.Right() < aContentPoint
.X() )
1247 aContentPoint
.setX( aContentFrame
.Right() );
1249 // pInside is a page area in which the point lies. As soon
1250 // as pInside != 0 only frames are accepted which are
1252 if( !pInside
|| ( pInside
->IsAnLower( pContent
) &&
1253 ( !pContent
->IsInFootnote() || pInside
->IsFootnoteContFrame() ) ) )
1255 const sal_uInt64 nDiff
= ::CalcDiff(aContentPoint
, rPoint
);
1256 bool bBetter
= nDiff
< nDistance
; // This one is nearer
1259 pInside
= lcl_Inside( pContent
, rPoint
);
1260 if( pInside
) // In the "right" page area
1265 aPoint
= aContentPoint
;
1272 pContent
= pContent
->GetNextContentFrame();
1274 while ( pContent
&& !pContent
->IsInDocBody() )
1275 pContent
= pContent
->GetNextContentFrame();
1278 { //If we not yet found one we have to expand the searched
1279 //area, sometime we will find one!
1280 //MA 1997-01-09: Opt for many empty pages - if we only search inside
1281 //the body, we can expand the searched area sufficiently in one step.
1284 while ( !pContent
&& pStart
->GetPrev() )
1287 if( !pStart
->GetPrev()->IsLayoutFrame() )
1289 pStart
= static_cast<const SwLayoutFrame
*>(pStart
->GetPrev());
1290 if( pStart
->IsInDocBody() )
1291 pContent
= pStart
->ContainsContent();
1294 const SwPageFrame
*pPage
= pStart
->FindPageFrame();
1297 pContent
= pPage
->FindFirstBodyContent();
1300 if ( !pContent
) // Somewhere down the road we have to start with one!
1302 const SwPageFrame
*pPage
= pStart
->FindPageFrame();
1305 pContent
= pPage
->GetUpper()->ContainsContent();
1306 while ( pContent
&& !pContent
->IsInDocBody() )
1307 pContent
= pContent
->GetNextContentFrame();
1309 return nullptr; // There is no document content yet!
1315 if ( pStart
->GetPrev() )
1317 if( !pStart
->GetPrev()->IsLayoutFrame() )
1319 pStart
= static_cast<const SwLayoutFrame
*>(pStart
->GetPrev());
1320 pContent
= pStart
->ContainsContent();
1322 else // Somewhere down the road we have to start with one!
1324 const SwPageFrame
*pPage
= pStart
->FindPageFrame();
1327 pContent
= pPage
->GetUpper()->ContainsContent();
1336 OSL_ENSURE( pActual
, "no Content found." );
1337 OSL_ENSURE( !bBodyOnly
|| pActual
->IsInDocBody(), "Content not in Body." );
1339 //Special case for selecting tables not in repeated TableHeadlines.
1340 if ( pActual
->IsInTab() && pCMS
&& pCMS
->m_eState
== CursorMoveState::TableSel
)
1342 const SwTabFrame
*pTab
= pActual
->FindTabFrame();
1343 if ( pTab
->IsFollow() && pTab
->IsInHeadline( *pActual
) )
1345 pCMS
->m_bStop
= true;
1350 //A small correction at the first/last
1351 Size
aActualSize( pActual
->getFramePrintArea().SSize() );
1352 if ( aActualSize
.Height() > pActual
->GetUpper()->getFramePrintArea().Height() )
1353 aActualSize
.setHeight( pActual
->GetUpper()->getFramePrintArea().Height() );
1355 SwRectFnSet
aRectFnSet(pActual
);
1356 if ( !pActual
->GetPrev() &&
1357 aRectFnSet
.YDiff( aRectFnSet
.GetPrtTop(*pActual
),
1358 aRectFnSet
.IsVert() ? rPoint
.X() : rPoint
.Y() ) > 0 )
1360 aPoint
.setY( pActual
->getFrameArea().Top() + pActual
->getFramePrintArea().Top() );
1361 aPoint
.setX( pActual
->getFrameArea().Left() +
1362 ( pActual
->IsRightToLeft() || aRectFnSet
.IsVert() ?
1363 pActual
->getFramePrintArea().Right() :
1364 pActual
->getFramePrintArea().Left() ) );
1366 else if ( !pActual
->GetNext() &&
1367 aRectFnSet
.YDiff( aRectFnSet
.GetPrtBottom(*pActual
),
1368 aRectFnSet
.IsVert() ? rPoint
.X() : rPoint
.Y() ) < 0 )
1370 aPoint
.setY( pActual
->getFrameArea().Top() + pActual
->getFramePrintArea().Bottom() );
1371 aPoint
.setX( pActual
->getFrameArea().Left() +
1372 ( pActual
->IsRightToLeft() || aRectFnSet
.IsVert() ?
1373 pActual
->getFramePrintArea().Left() :
1374 pActual
->getFramePrintArea().Right() ) );
1377 //Bring the Point into the PrtArea
1378 const SwRect
aRect( pActual
->getFrameArea().Pos() + pActual
->getFramePrintArea().Pos(),
1380 if ( aPoint
.Y() < aRect
.Top() )
1381 aPoint
.setY( aRect
.Top() );
1382 else if ( aPoint
.Y() > aRect
.Bottom() )
1383 aPoint
.setY( aRect
.Bottom() );
1384 if ( aPoint
.X() < aRect
.Left() )
1385 aPoint
.setX( aRect
.Left() );
1386 else if ( aPoint
.X() > aRect
.Right() )
1387 aPoint
.setX( aRect
.Right() );
1392 /** Same as SwLayoutFrame::GetContentPos(). Specialized for fields and border. */
1393 void SwPageFrame::GetContentPosition( const Point
&rPt
, SwPosition
&rPos
) const
1395 //Determine the first ContentFrame.
1396 const SwContentFrame
*pContent
= ContainsContent();
1399 //Look back one more (if possible).
1400 const SwContentFrame
*pTmp
= pContent
->GetPrevContentFrame();
1401 while ( pTmp
&& !pTmp
->IsInDocBody() )
1402 pTmp
= pTmp
->GetPrevContentFrame();
1407 pContent
= GetUpper()->ContainsContent();
1409 const SwContentFrame
*pAct
= pContent
;
1411 sal_uInt64 nDist
= SAL_MAX_UINT64
;
1415 SwRect
aContentFrame( pContent
->UnionFrame() );
1416 if ( aContentFrame
.Contains( rPt
) )
1418 //This is the nearest one.
1423 //Calculate the distance from rPt to the nearest point of pContent.
1424 Point
aPoint( rPt
);
1426 //Calculate the vertical position first
1427 if ( aContentFrame
.Top() > rPt
.Y() )
1428 aPoint
.setY( aContentFrame
.Top() );
1429 else if ( aContentFrame
.Bottom() < rPt
.Y() )
1430 aPoint
.setY( aContentFrame
.Bottom() );
1432 //And now the horizontal position
1433 if ( aContentFrame
.Left() > rPt
.X() )
1434 aPoint
.setX( aContentFrame
.Left() );
1435 else if ( aContentFrame
.Right() < rPt
.X() )
1436 aPoint
.setX( aContentFrame
.Right() );
1438 const sal_uInt64 nDiff
= ::CalcDiff( aPoint
, rPt
);
1439 if ( nDiff
< nDist
)
1445 else if ( aContentFrame
.Top() > getFrameArea().Bottom() )
1446 //In terms of fields, it's not possible to be closer any more!
1449 pContent
= pContent
->GetNextContentFrame();
1450 while ( pContent
&& !pContent
->IsInDocBody() )
1451 pContent
= pContent
->GetNextContentFrame();
1454 //Bring the point into the PrtArea.
1455 const SwRect
aRect( pAct
->getFrameArea().Pos() + pAct
->getFramePrintArea().Pos(), pAct
->getFramePrintArea().SSize() );
1456 if ( aAct
.Y() < aRect
.Top() )
1457 aAct
.setY( aRect
.Top() );
1458 else if ( aAct
.Y() > aRect
.Bottom() )
1459 aAct
.setY( aRect
.Bottom() );
1460 if ( aAct
.X() < aRect
.Left() )
1461 aAct
.setX( aRect
.Left() );
1462 else if ( aAct
.X() > aRect
.Right() )
1463 aAct
.setX( aRect
.Right() );
1465 if (!pAct
->isFrameAreaDefinitionValid() ||
1466 (pAct
->IsTextFrame() && !static_cast<SwTextFrame
const*>(pAct
)->HasPara()))
1468 // ContentFrame not formatted -> always on node-beginning
1469 // tdf#100635 also if the SwTextFrame would require reformatting,
1470 // which is unwanted in case this is called from text formatting code
1471 rPos
= static_cast<SwTextFrame
const*>(pAct
)->MapViewToModelPos(TextFrameIndex(0));
1475 SwCursorMoveState
aTmpState( CursorMoveState::SetOnlyText
);
1476 pAct
->GetModelPositionForViewPoint( &rPos
, aAct
, &aTmpState
);
1480 /** Search the nearest Content to the passed point.
1482 * Only search inside the BodyText.
1483 * @note Only the nearest vertically one will be searched.
1484 * @note JP 11.10.2001: only in tables we try to find the right column - Bug 72294
1486 Point
SwRootFrame::GetNextPrevContentPos( const Point
& rPoint
, bool bNext
) const
1488 vcl::RenderContext
* pRenderContext
= GetCurrShell() ? GetCurrShell()->GetOut() : nullptr;
1489 // #123110# - disable creation of an action by a callback
1490 // event during processing of this method. Needed because formatting is
1491 // triggered by this method.
1492 DisableCallbackAction
aDisableCallbackAction(const_cast<SwRootFrame
&>(*this));
1493 //Search the first ContentFrame and his successor in the body area.
1494 //To be efficient (and not formatting too much) we'll start at the correct
1496 const SwLayoutFrame
*pPage
= static_cast<const SwLayoutFrame
*>(Lower());
1498 while( pPage
->GetNext() && pPage
->getFrameArea().Bottom() < rPoint
.Y() )
1499 pPage
= static_cast<const SwLayoutFrame
*>(pPage
->GetNext());
1501 const SwContentFrame
*pCnt
= pPage
? pPage
->ContainsContent() : ContainsContent();
1502 while ( pCnt
&& !pCnt
->IsInDocBody() )
1503 pCnt
= pCnt
->GetNextContentFrame();
1506 return Point( 0, 0 );
1508 pCnt
->Calc(pRenderContext
);
1511 // As long as the point lies before the first ContentFrame and there are
1512 // still precedent pages I'll go to the next page.
1513 while ( rPoint
.Y() < pCnt
->getFrameArea().Top() && pPage
->GetPrev() )
1515 pPage
= static_cast<const SwLayoutFrame
*>(pPage
->GetPrev());
1516 pCnt
= pPage
->ContainsContent();
1519 pPage
= static_cast<const SwLayoutFrame
*>(pPage
->GetPrev());
1521 pCnt
= pPage
->ContainsContent();
1523 return ContainsContent()->UnionFrame().Pos();
1525 pCnt
->Calc(pRenderContext
);
1529 //Does the point lie above the first ContentFrame?
1530 if ( rPoint
.Y() < pCnt
->getFrameArea().Top() && !lcl_IsInRepeatedHeadline( pCnt
) )
1531 return pCnt
->UnionFrame().Pos();
1536 //Does the point lie in the current ContentFrame?
1537 SwRect
aContentFrame( pCnt
->UnionFrame() );
1538 if ( aContentFrame
.Contains( rPoint
) && !lcl_IsInRepeatedHeadline( pCnt
))
1544 //Is the current one the last ContentFrame?
1545 //If the next ContentFrame lies behind the point, then the current on is the
1547 const SwContentFrame
*pNxt
= pCnt
->GetNextContentFrame();
1548 while ( pNxt
&& !pNxt
->IsInDocBody() )
1549 pNxt
= pNxt
->GetNextContentFrame();
1551 //Does the point lie behind the last ContentFrame?
1554 aRet
= Point( aContentFrame
.Right(), aContentFrame
.Bottom() );
1558 //If the next ContentFrame lies behind the point then it is the one we
1560 const SwTabFrame
* pTFrame
;
1561 pNxt
->Calc(pRenderContext
);
1562 if( pNxt
->getFrameArea().Top() > rPoint
.Y() &&
1563 !lcl_IsInRepeatedHeadline( pCnt
, &pTFrame
) &&
1564 ( !pTFrame
|| pNxt
->getFrameArea().Left() > rPoint
.X() ))
1567 aRet
= pNxt
->getFrameArea().Pos();
1569 aRet
= Point( aContentFrame
.Right(), aContentFrame
.Bottom() );
1578 /** Returns the absolute document position of the desired page.
1580 * Formatting is done only as far as needed and only if bFormat=true.
1581 * Pos is set to the one of the last page, if the page number was chosen too big.
1583 * @return Null, if the operation failed.
1585 Point
SwRootFrame::GetPagePos( sal_uInt16 nPageNum
) const
1587 OSL_ENSURE( Lower() && Lower()->IsPageFrame(), "No page available." );
1589 const SwPageFrame
*pPage
= static_cast<const SwPageFrame
*>(Lower());
1592 if ( pPage
->GetPhyPageNum() >= nPageNum
|| !pPage
->GetNext() )
1594 pPage
= static_cast<const SwPageFrame
*>(pPage
->GetNext());
1596 return pPage
->getFrameArea().Pos();
1599 /** get page frame by physical page number
1601 * @return pointer to the page frame with the given physical page number
1603 SwPageFrame
* SwRootFrame::GetPageByPageNum( sal_uInt16 _nPageNum
) const
1605 const SwPageFrame
* pPageFrame
= static_cast<const SwPageFrame
*>( Lower() );
1606 while ( pPageFrame
&& pPageFrame
->GetPhyPageNum() < _nPageNum
)
1608 pPageFrame
= static_cast<const SwPageFrame
*>( pPageFrame
->GetNext() );
1611 if ( pPageFrame
&& pPageFrame
->GetPhyPageNum() == _nPageNum
)
1613 return const_cast<SwPageFrame
*>( pPageFrame
);
1622 * @return true, when the given physical pagenumber doesn't exist or this page is an empty page.
1624 bool SwRootFrame::IsDummyPage( sal_uInt16 nPageNum
) const
1626 if( !Lower() || !nPageNum
|| nPageNum
> GetPageNum() )
1629 const SwPageFrame
*pPage
= static_cast<const SwPageFrame
*>(Lower());
1630 while( pPage
&& nPageNum
< pPage
->GetPhyPageNum() )
1631 pPage
= static_cast<const SwPageFrame
*>(pPage
->GetNext());
1632 return !pPage
|| pPage
->IsEmptyPage();
1635 /** Is the Frame or rather the Section in which it lies protected?
1637 * Also Fly in Fly in ... and Footnotes
1639 bool SwFrame::IsProtected() const
1643 const SwDoc
*pDoc
= &static_cast<const SwTextFrame
*>(this)->GetDoc();
1644 bool isFormProtected
=pDoc
->GetDocumentSettingManager().get(DocumentSettingId::PROTECT_FORM
);
1645 if (isFormProtected
)
1647 return false; // TODO a hack for now, well deal with it later, I we return true here we have a "double" locking
1650 //The Frame can be protected in borders, cells or sections.
1651 //Also goes up FlyFrames recursive and from footnote to anchor.
1652 const SwFrame
*pFrame
= this;
1655 if (pFrame
->IsTextFrame())
1656 { // sw_redlinehide: redlines can't overlap section nodes, so any node will do
1657 if (static_cast<SwTextFrame
const*>(pFrame
)->GetTextNodeFirst()->IsInProtectSect())
1662 else if ( pFrame
->IsContentFrame() )
1664 assert(pFrame
->IsNoTextFrame());
1665 if (static_cast<const SwNoTextFrame
*>(pFrame
)->GetNode() &&
1666 static_cast<const SwNoTextFrame
*>(pFrame
)->GetNode()->IsInProtectSect())
1673 if ( static_cast<const SwLayoutFrame
*>(pFrame
)->GetFormat() &&
1674 static_cast<const SwLayoutFrame
*>(pFrame
)->GetFormat()->
1675 GetProtect().IsContentProtected() )
1677 if ( pFrame
->IsCoveredCell() )
1680 if ( pFrame
->IsFlyFrame() )
1682 //In a chain the protection of the content can be specified by the
1683 //master of the chain.
1684 if ( static_cast<const SwFlyFrame
*>(pFrame
)->GetPrevLink() )
1686 const SwFlyFrame
*pMaster
= static_cast<const SwFlyFrame
*>(pFrame
);
1688 { pMaster
= pMaster
->GetPrevLink();
1689 } while ( pMaster
->GetPrevLink() );
1690 if ( pMaster
->IsProtected() )
1693 pFrame
= static_cast<const SwFlyFrame
*>(pFrame
)->GetAnchorFrame();
1695 else if ( pFrame
->IsFootnoteFrame() )
1696 pFrame
= static_cast<const SwFootnoteFrame
*>(pFrame
)->GetRef();
1698 pFrame
= pFrame
->GetUpper();
1705 /** @return the physical page number */
1706 sal_uInt16
SwFrame::GetPhyPageNum() const
1708 const SwPageFrame
*pPage
= FindPageFrame();
1709 return pPage
? pPage
->GetPhyPageNum() : 0;
1712 /** Decides if the page want to be a right page or not.
1714 * If the first content of the page has a page descriptor, we take the follow
1715 * of the page descriptor of the last not empty page. If this descriptor allows
1716 * only right(left) pages and the page isn't an empty page then it wants to be
1717 * such right(left) page. If the descriptor allows right and left pages, we
1718 * look for a number offset in the first content. If there is one, odd number
1719 * results right pages (or left pages if document starts with even number),
1720 * even number results left pages (or right pages if document starts with even
1722 * If there is no number offset, we take the physical page number instead,
1723 * but a previous empty page doesn't count.
1725 bool SwFrame::WannaRightPage() const
1727 const SwPageFrame
*pPage
= FindPageFrame();
1728 if ( !pPage
|| !pPage
->GetUpper() )
1731 const SwFrame
*pFlow
= pPage
->FindFirstBodyContent();
1732 const SwPageDesc
*pDesc
= nullptr;
1733 ::std::optional
<sal_uInt16
> oPgNum
;
1736 if ( pFlow
->IsInTab() )
1737 pFlow
= pFlow
->FindTabFrame();
1738 const SwFlowFrame
*pTmp
= SwFlowFrame::CastFlowFrame( pFlow
);
1739 if ( !pTmp
->IsFollow() )
1741 const SwFormatPageDesc
& rPgDesc
= pFlow
->GetPageDescItem();
1742 pDesc
= rPgDesc
.GetPageDesc();
1743 oPgNum
= rPgDesc
.GetNumOffset();
1748 SwPageFrame
*pPrv
= const_cast<SwPageFrame
*>(static_cast<const SwPageFrame
*>(pPage
->GetPrev()));
1749 if( pPrv
&& pPrv
->IsEmptyPage() )
1750 pPrv
= static_cast<SwPageFrame
*>(pPrv
->GetPrev());
1752 pDesc
= pPrv
->GetPageDesc()->GetFollow();
1755 const SwDoc
* pDoc
= pPage
->GetFormat()->GetDoc();
1756 pDesc
= &pDoc
->GetPageDesc( 0 );
1759 OSL_ENSURE( pDesc
, "No pagedescriptor" );
1762 isRightPage
= sw::IsRightPageByNumber(*mpRoot
, *oPgNum
);
1765 isRightPage
= pPage
->OnRightPage();
1766 if( pPage
->GetPrev() && static_cast<const SwPageFrame
*>(pPage
->GetPrev())->IsEmptyPage() )
1767 isRightPage
= !isRightPage
;
1769 if( !pPage
->IsEmptyPage() )
1771 if( !pDesc
->GetRightFormat() )
1772 isRightPage
= false;
1773 else if( !pDesc
->GetLeftFormat() )
1779 bool SwFrame::OnFirstPage() const
1782 const SwPageFrame
*pPage
= FindPageFrame();
1786 const SwPageFrame
* pPrevFrame
= dynamic_cast<const SwPageFrame
*>(pPage
->GetPrev());
1789 // first page of layout may be empty page, but only if it starts with "Left Page" style
1790 const SwPageDesc
* pDesc
= pPage
->GetPageDesc();
1791 bRet
= pPrevFrame
->GetPageDesc() != pDesc
;
1799 void SwFrame::Calc(vcl::RenderContext
* pRenderContext
) const
1801 if ( !isFrameAreaPositionValid() || !isFramePrintAreaValid() || !isFrameAreaSizeValid() )
1803 const_cast<SwFrame
*>(this)->PrepareMake(pRenderContext
);
1807 Point
SwFrame::GetRelPos() const
1809 Point
aRet( getFrameArea().Pos() );
1810 // here we cast since SwLayoutFrame is declared only as forwarded
1811 aRet
-= GetUpper()->getFramePrintArea().Pos();
1812 aRet
-= GetUpper()->getFrameArea().Pos();
1816 /** @return the virtual page number with the offset. */
1817 sal_uInt16
SwFrame::GetVirtPageNum() const
1819 const SwPageFrame
*pPage
= FindPageFrame();
1820 if ( !pPage
|| !pPage
->GetUpper() )
1823 sal_uInt16 nPhyPage
= pPage
->GetPhyPageNum();
1824 if ( !static_cast<const SwRootFrame
*>(pPage
->GetUpper())->IsVirtPageNum() )
1827 //Search the nearest section using the virtual page number.
1828 //Because searching backwards needs a lot of time we search specific using
1829 //the dependencies. From the PageDescs we get the attributes and from the
1830 //attributes we get the sections.
1831 const SwPageFrame
*pVirtPage
= nullptr;
1832 const SwFrame
*pFrame
= nullptr;
1833 const SfxItemPool
&rPool
= pPage
->GetFormat()->GetDoc()->GetAttrPool();
1834 for (const SfxPoolItem
* pItem
: rPool
.GetItemSurrogates(RES_PAGEDESC
))
1836 const SwFormatPageDesc
*pDesc
= dynamic_cast<const SwFormatPageDesc
*>(pItem
);
1840 if ( pDesc
->GetNumOffset() && pDesc
->GetDefinedIn() )
1842 const sw::BroadcastingModify
*pMod
= pDesc
->GetDefinedIn();
1843 SwVirtPageNumInfo
aInfo( pPage
);
1844 pMod
->GetInfo( aInfo
);
1845 if ( aInfo
.GetPage() )
1847 if( !pVirtPage
|| aInfo
.GetPage()->GetPhyPageNum() > pVirtPage
->GetPhyPageNum() )
1849 pVirtPage
= aInfo
.GetPage();
1850 pFrame
= aInfo
.GetFrame();
1857 ::std::optional
<sal_uInt16
> oNumOffset
= pFrame
->GetPageDescItem().GetNumOffset();
1860 return nPhyPage
- pFrame
->GetPhyPageNum() + *oNumOffset
;
1864 return nPhyPage
- pFrame
->GetPhyPageNum();
1870 /** Determines and sets those cells which are enclosed by the selection. */
1871 bool SwRootFrame::MakeTableCursors( SwTableCursor
& rTableCursor
)
1873 //Find Union-Rects and tables (Follows) of the selection.
1874 OSL_ENSURE( rTableCursor
.GetPointContentNode() && rTableCursor
.GetMarkContentNode(),
1875 "Tabselection not on Cnt." );
1879 // For new table models there's no need to ask the layout...
1880 if( rTableCursor
.NewTableSelection() )
1885 SwShellCursor
* pShCursor
= dynamic_cast<SwShellCursor
*>(&rTableCursor
);
1889 aPtPt
= pShCursor
->GetPtPos();
1890 aMkPt
= pShCursor
->GetMkPos();
1894 // #151012# Made code robust here
1895 const SwContentNode
* pTmpStartNode
= rTableCursor
.GetPointContentNode();
1896 const SwContentNode
* pTmpEndNode
= rTableCursor
.GetMarkContentNode();
1898 std::pair
<Point
, bool> tmp(aPtPt
, false);
1899 const SwFrame
*const pTmpStartFrame
= pTmpStartNode
? pTmpStartNode
->getLayoutFrame(this, nullptr, &tmp
) : nullptr;
1901 const SwFrame
*const pTmpEndFrame
= pTmpEndNode
? pTmpEndNode
->getLayoutFrame(this, nullptr, &tmp
) : nullptr;
1903 const SwLayoutFrame
* pStart
= pTmpStartFrame
? pTmpStartFrame
->GetUpper() : nullptr;
1904 const SwLayoutFrame
* pEnd
= pTmpEndFrame
? pTmpEndFrame
->GetUpper() : nullptr;
1906 OSL_ENSURE( pStart
&& pEnd
, "MakeTableCursors: Good to have the code robust here!" );
1908 /* #109590# Only change table boxes if the frames are
1909 valid. Needed because otherwise the table cursor after moving
1910 table cells by dnd resulted in an empty tables cursor. */
1911 if ( pStart
&& pEnd
&& pStart
->isFrameAreaDefinitionValid() && pEnd
->isFrameAreaDefinitionValid())
1913 SwSelUnions aUnions
;
1914 ::MakeSelUnions( aUnions
, pStart
, pEnd
);
1918 const bool bReadOnlyAvailable
= rTableCursor
.IsReadOnlyAvailable();
1920 for (SwSelUnion
& rUnion
: aUnions
)
1922 const SwTabFrame
*pTable
= rUnion
.GetTable();
1924 // Skip any repeated headlines in the follow:
1925 SwLayoutFrame
* pRow
= pTable
->IsFollow() ?
1926 pTable
->GetFirstNonHeadlineRow() :
1927 const_cast<SwLayoutFrame
*>(static_cast<const SwLayoutFrame
*>(pTable
->Lower()));
1931 if ( pRow
->getFrameArea().Overlaps( rUnion
.GetUnion() ) )
1933 const SwLayoutFrame
*pCell
= pRow
->FirstCell();
1935 while ( pCell
&& pRow
->IsAnLower( pCell
) )
1937 OSL_ENSURE( pCell
->IsCellFrame(), "Frame without cell" );
1938 if( IsFrameInTableSel( rUnion
.GetUnion(), pCell
) &&
1939 (bReadOnlyAvailable
||
1940 !pCell
->GetFormat()->GetProtect().IsContentProtected()))
1942 SwTableBox
* pInsBox
= const_cast<SwTableBox
*>(
1943 static_cast<const SwCellFrame
*>(pCell
)->GetTabBox());
1944 aNew
.insert( pInsBox
);
1946 if ( pCell
->GetNext() )
1948 pCell
= static_cast<const SwLayoutFrame
*>(pCell
->GetNext());
1949 if ( pCell
->Lower() && pCell
->Lower()->IsRowFrame() )
1950 pCell
= pCell
->FirstCell();
1954 const SwLayoutFrame
* pLastCell
= pCell
;
1957 pCell
= pCell
->GetNextLayoutLeaf();
1958 } while ( pCell
&& pLastCell
->IsAnLower( pCell
) );
1959 // For sections with columns
1960 if( pCell
&& pCell
->IsInTab() )
1962 while( !pCell
->IsCellFrame() )
1964 pCell
= pCell
->GetUpper();
1965 OSL_ENSURE( pCell
, "Where's my cell?" );
1971 pRow
= static_cast<SwLayoutFrame
*>(pRow
->GetNext());
1975 rTableCursor
.ActualizeSelection( aNew
);
1982 static void Sub( SwRegionRects
& rRegion
, const SwRect
& rRect
)
1984 if( rRect
.Width() > 1 && rRect
.Height() > 1 &&
1985 rRect
.Overlaps( rRegion
.GetOrigin() ))
1989 static void Add( SwRegionRects
& rRegion
, const SwRect
& rRect
)
1991 if( rRect
.Width() > 1 && rRect
.Height() > 1 )
1996 * The following situations can happen:
1997 * 1. Start and end lie in one screen-row and in the same node
1998 * -> one rectangle out of start and end; and we're okay
1999 * 2. Start and end lie in one frame (therefore in the same node!)
2000 * -> expand start to the right, end to the left and if more than two
2001 * screen-rows are involved - calculate the in-between
2002 * 3. Start and end lie in different frames
2003 * -> expand start to the right until frame-end, calculate Rect
2004 * expand end to the left until frame-start, calculate Rect
2005 * and if more than two frames are involved add the PrtArea of all
2006 * frames which lie in between
2008 * Big reorganization because of the FlyFrame - those need to be locked out.
2009 * Exceptions: - The Fly in which the selection took place (if it took place
2011 * - The Flys which are underrun by the text
2012 * - The Flys which are anchored to somewhere inside the selection.
2013 * Functioning: First a SwRegion with a root gets initialized.
2014 * Out of the region the inverted sections are cut out. The
2015 * section gets compressed and finally inverted and thereby the
2016 * inverted rectangles are available.
2017 * In the end the Flys are cut out of the section.
2019 void SwRootFrame::CalcFrameRects(SwShellCursor
&rCursor
)
2021 auto [pStartPos
, pEndPos
] = rCursor
.StartEnd(); // SwPosition*
2023 SwViewShell
*pSh
= GetCurrShell();
2025 bool bIgnoreVisArea
= true;
2027 bIgnoreVisArea
= pSh
->GetViewOptions()->IsPDFExport() || comphelper::LibreOfficeKit::isActive();
2029 // #i12836# enhanced pdf
2030 SwRegionRects
aRegion( !bIgnoreVisArea
?
2033 if( !pStartPos
->GetNode().IsContentNode() ||
2034 !pStartPos
->GetNode().GetContentNode()->getLayoutFrame(this) ||
2035 ( pStartPos
->GetNode() != pEndPos
->GetNode() &&
2036 ( !pEndPos
->GetNode().IsContentNode() ||
2037 !pEndPos
->GetNode().GetContentNode()->getLayoutFrame(this) ) ) )
2042 DisableCallbackAction
a(*this); // the GetCharRect below may format
2044 //First obtain the ContentFrames for the start and the end - those are needed
2046 std::pair
<Point
, bool> tmp(rCursor
.GetSttPos(), true);
2047 SwContentFrame
* pStartFrame
= pStartPos
->GetNode().
2048 GetContentNode()->getLayoutFrame(this, pStartPos
, &tmp
);
2050 tmp
.first
= rCursor
.GetEndPos();
2051 SwContentFrame
* pEndFrame
= pEndPos
->GetNode().
2052 GetContentNode()->getLayoutFrame(this, pEndPos
, &tmp
);
2054 assert(pStartFrame
&& pEndFrame
&& "No ContentFrames found.");
2055 //tdf#119224 start and end are expected to exist for the scope of this function
2056 SwFrameDeleteGuard
aStartFrameGuard(pStartFrame
), aEndFrameGuard(pEndFrame
);
2058 //Do not subtract the FlyFrames in which selected Frames lie.
2059 SwSortedObjs aSortObjs
;
2060 if ( pStartFrame
->IsInFly() )
2062 const SwAnchoredObject
* pObj
= pStartFrame
->FindFlyFrame();
2063 OSL_ENSURE( pObj
, "No Start Object." );
2064 if (pObj
) aSortObjs
.Insert( *const_cast<SwAnchoredObject
*>(pObj
) );
2065 const SwAnchoredObject
* pObj2
= pEndFrame
->FindFlyFrame();
2066 OSL_ENSURE( pObj2
, "SwRootFrame::CalcFrameRects(..) - FlyFrame missing - looks like an invalid selection" );
2067 if ( pObj2
!= nullptr && pObj2
!= pObj
)
2069 aSortObjs
.Insert( *const_cast<SwAnchoredObject
*>(pObj2
) );
2073 // if a selection which is not allowed exists, we correct what is not
2074 // allowed (header/footer/table-headline) for two pages.
2075 do { // middle check loop
2076 const SwLayoutFrame
* pSttLFrame
= pStartFrame
->GetUpper();
2077 const SwFrameType cHdFtTableHd
= SwFrameType::Header
| SwFrameType::Footer
| SwFrameType::Tab
;
2078 while( pSttLFrame
&&
2079 ! (cHdFtTableHd
& pSttLFrame
->GetType() ))
2080 pSttLFrame
= pSttLFrame
->GetUpper();
2083 const SwLayoutFrame
* pEndLFrame
= pEndFrame
->GetUpper();
2084 while( pEndLFrame
&&
2085 ! (cHdFtTableHd
& pEndLFrame
->GetType() ))
2086 pEndLFrame
= pEndLFrame
->GetUpper();
2090 OSL_ENSURE( pEndLFrame
->GetType() == pSttLFrame
->GetType(),
2091 "Selection over different content" );
2092 switch( pSttLFrame
->GetType() )
2094 case SwFrameType::Header
:
2095 case SwFrameType::Footer
:
2096 // On different pages? Then always on the start-page
2097 if( pEndLFrame
->FindPageFrame() != pSttLFrame
->FindPageFrame() )
2099 // Set end- to the start-ContentFrame
2100 if( pStartPos
== rCursor
.GetPoint() )
2101 pEndFrame
= pStartFrame
;
2103 pStartFrame
= pEndFrame
;
2106 case SwFrameType::Tab
:
2107 // On different pages? Then check for table-headline
2109 const SwTabFrame
* pTabFrame
= static_cast<const SwTabFrame
*>(pSttLFrame
);
2110 if( ( pTabFrame
->GetFollow() ||
2111 static_cast<const SwTabFrame
*>(pEndLFrame
)->GetFollow() ) &&
2112 pTabFrame
->GetTable()->GetRowsToRepeat() > 0 &&
2113 pTabFrame
->GetLower() != static_cast<const SwTabFrame
*>(pEndLFrame
)->GetLower() &&
2114 ( lcl_IsInRepeatedHeadline( pStartFrame
) ||
2115 lcl_IsInRepeatedHeadline( pEndFrame
) ) )
2117 // Set end- to the start-ContentFrame
2118 if( pStartPos
== rCursor
.GetPoint() )
2119 pEndFrame
= pStartFrame
;
2121 pStartFrame
= pEndFrame
;
2129 SwCursorMoveState
aTmpState( CursorMoveState::NONE
);
2130 aTmpState
.m_b2Lines
= true;
2131 aTmpState
.m_bNoScroll
= true;
2132 aTmpState
.m_nCursorBidiLevel
= pStartFrame
->IsRightToLeft() ? 1 : 0;
2134 //ContentRects to Start- and EndFrames.
2135 SwRect aStRect
, aEndRect
;
2136 pStartFrame
->GetCharRect( aStRect
, *pStartPos
, &aTmpState
);
2137 std::unique_ptr
<Sw2LinesPos
> pSt2Pos
= std::move(aTmpState
.m_p2Lines
);
2138 aTmpState
.m_nCursorBidiLevel
= pEndFrame
->IsRightToLeft() ? 1 : 0;
2140 pEndFrame
->GetCharRect( aEndRect
, *pEndPos
, &aTmpState
);
2141 std::unique_ptr
<Sw2LinesPos
> pEnd2Pos
= std::move(aTmpState
.m_p2Lines
);
2143 SwRect
aStFrame ( pStartFrame
->UnionFrame( true ) );
2144 aStFrame
.Intersection( pStartFrame
->GetPaintArea() );
2145 SwRect
aEndFrame( pStartFrame
== pEndFrame
? aStFrame
: pEndFrame
->UnionFrame( true ) );
2146 if( pStartFrame
!= pEndFrame
)
2148 aEndFrame
.Intersection( pEndFrame
->GetPaintArea() );
2150 SwRectFnSet
aRectFnSet(pStartFrame
);
2151 const bool bR2L
= pStartFrame
->IsRightToLeft();
2152 const bool bEndR2L
= pEndFrame
->IsRightToLeft();
2153 const bool bB2T
= pStartFrame
->IsVertLRBT();
2155 // If there's no doubleline portion involved or start and end are both
2156 // in the same doubleline portion, all works fine, but otherwise
2157 // we need the following...
2158 if( pSt2Pos
!= pEnd2Pos
&& ( !pSt2Pos
|| !pEnd2Pos
||
2159 pSt2Pos
->aPortion
!= pEnd2Pos
->aPortion
) )
2161 // If we have a start(end) position inside a doubleline portion
2162 // the surrounded part of the doubleline portion is subtracted
2163 // from the region and the aStRect(aEndRect) is set to the
2164 // end(start) of the doubleline portion.
2167 SwRect
aTmp( aStRect
);
2169 // BiDi-Portions are swimming against the current.
2170 const bool bPorR2L
= ( MultiPortionType::BIDI
== pSt2Pos
->nMultiType
) ?
2174 if( MultiPortionType::BIDI
== pSt2Pos
->nMultiType
&&
2175 aRectFnSet
.GetWidth(pSt2Pos
->aPortion2
) )
2177 // nested bidi portion
2178 tools::Long nRightAbs
= aRectFnSet
.GetRight(pSt2Pos
->aPortion
);
2179 nRightAbs
-= aRectFnSet
.GetLeft(pSt2Pos
->aPortion2
);
2180 tools::Long nLeftAbs
= nRightAbs
- aRectFnSet
.GetWidth(pSt2Pos
->aPortion2
);
2182 aRectFnSet
.SetRight( aTmp
, nRightAbs
);
2184 if ( ! pEnd2Pos
|| pEnd2Pos
->aPortion
!= pSt2Pos
->aPortion
)
2186 SwRect
aTmp2( pSt2Pos
->aPortion
);
2187 aRectFnSet
.SetRight( aTmp2
, nLeftAbs
);
2188 aTmp2
.Intersection( aEndFrame
);
2189 Sub( aRegion
, aTmp2
);
2195 aRectFnSet
.SetLeft( aTmp
, aRectFnSet
.GetLeft(pSt2Pos
->aPortion
) );
2197 aRectFnSet
.SetRight( aTmp
, aRectFnSet
.GetRight(pSt2Pos
->aPortion
) );
2200 if( MultiPortionType::ROT_90
== pSt2Pos
->nMultiType
||
2201 aRectFnSet
.GetTop(pSt2Pos
->aPortion
) ==
2202 aRectFnSet
.GetTop(aTmp
) )
2204 aRectFnSet
.SetTop( aTmp
, aRectFnSet
.GetTop(pSt2Pos
->aLine
) );
2207 aTmp
.Intersection( aStFrame
);
2208 Sub( aRegion
, aTmp
);
2210 SwTwips nTmp
= aRectFnSet
.GetBottom(pSt2Pos
->aLine
);
2211 if( MultiPortionType::ROT_90
!= pSt2Pos
->nMultiType
&&
2212 aRectFnSet
.BottomDist( aStRect
, nTmp
) > 0 )
2214 aRectFnSet
.SetTop( aTmp
, aRectFnSet
.GetBottom(aTmp
) );
2215 aRectFnSet
.SetBottom( aTmp
, nTmp
);
2216 if( aRectFnSet
.BottomDist( aStRect
, aRectFnSet
.GetBottom(pSt2Pos
->aPortion
) ) > 0 )
2219 aRectFnSet
.SetRight( aTmp
, aRectFnSet
.GetRight(pSt2Pos
->aPortion
) );
2221 aRectFnSet
.SetLeft( aTmp
, aRectFnSet
.GetLeft(pSt2Pos
->aPortion
) );
2223 aTmp
.Intersection( aStFrame
);
2224 Sub( aRegion
, aTmp
);
2227 aStRect
= pSt2Pos
->aLine
;
2228 aRectFnSet
.SetLeft( aStRect
, bR2L
?
2229 aRectFnSet
.GetLeft(pSt2Pos
->aPortion
) :
2230 aRectFnSet
.GetRight(pSt2Pos
->aPortion
) );
2231 aRectFnSet
.SetWidth( aStRect
, 1 );
2236 SwRectFnSet
fnRectX(pEndFrame
);
2237 SwRect
aTmp( aEndRect
);
2239 // BiDi-Portions are swimming against the current.
2240 const bool bPorR2L
= ( MultiPortionType::BIDI
== pEnd2Pos
->nMultiType
) ?
2244 if( MultiPortionType::BIDI
== pEnd2Pos
->nMultiType
&&
2245 fnRectX
.GetWidth(pEnd2Pos
->aPortion2
) )
2247 // nested bidi portion
2248 tools::Long nRightAbs
= fnRectX
.GetRight(pEnd2Pos
->aPortion
);
2249 nRightAbs
= nRightAbs
- fnRectX
.GetLeft(pEnd2Pos
->aPortion2
);
2250 tools::Long nLeftAbs
= nRightAbs
- fnRectX
.GetWidth(pEnd2Pos
->aPortion2
);
2252 fnRectX
.SetLeft( aTmp
, nLeftAbs
);
2254 if ( ! pSt2Pos
|| pSt2Pos
->aPortion
!= pEnd2Pos
->aPortion
)
2256 SwRect
aTmp2( pEnd2Pos
->aPortion
);
2257 fnRectX
.SetLeft( aTmp2
, nRightAbs
);
2258 aTmp2
.Intersection( aEndFrame
);
2259 Sub( aRegion
, aTmp2
);
2265 fnRectX
.SetRight( aTmp
, fnRectX
.GetRight(pEnd2Pos
->aPortion
) );
2267 fnRectX
.SetLeft( aTmp
, fnRectX
.GetLeft(pEnd2Pos
->aPortion
) );
2270 if( MultiPortionType::ROT_90
== pEnd2Pos
->nMultiType
||
2271 fnRectX
.GetBottom(pEnd2Pos
->aPortion
) ==
2272 fnRectX
.GetBottom(aEndRect
) )
2274 fnRectX
.SetBottom( aTmp
, fnRectX
.GetBottom(pEnd2Pos
->aLine
) );
2277 aTmp
.Intersection( aEndFrame
);
2278 Sub( aRegion
, aTmp
);
2280 // The next statement means neither ruby nor rotate(90):
2281 if( MultiPortionType::RUBY
!= pEnd2Pos
->nMultiType
&& MultiPortionType::ROT_90
!= pEnd2Pos
->nMultiType
)
2283 SwTwips nTmp
= fnRectX
.GetTop(pEnd2Pos
->aLine
);
2284 if( fnRectX
.GetTop(aEndRect
) != nTmp
)
2286 fnRectX
.SetBottom( aTmp
, fnRectX
.GetTop(aTmp
) );
2287 fnRectX
.SetTop( aTmp
, nTmp
);
2288 if( fnRectX
.GetTop(aEndRect
) !=
2289 fnRectX
.GetTop(pEnd2Pos
->aPortion
) )
2292 fnRectX
.SetLeft( aTmp
, fnRectX
.GetLeft(pEnd2Pos
->aPortion
) );
2294 fnRectX
.SetRight( aTmp
, fnRectX
.GetRight(pEnd2Pos
->aPortion
) );
2296 aTmp
.Intersection( aEndFrame
);
2297 Sub( aRegion
, aTmp
);
2301 aEndRect
= pEnd2Pos
->aLine
;
2302 fnRectX
.SetLeft( aEndRect
, bEndR2L
?
2303 fnRectX
.GetRight(pEnd2Pos
->aPortion
) :
2304 fnRectX
.GetLeft(pEnd2Pos
->aPortion
) );
2305 fnRectX
.SetWidth( aEndRect
, 1 );
2308 else if( pSt2Pos
&& pEnd2Pos
&&
2309 MultiPortionType::BIDI
== pSt2Pos
->nMultiType
&&
2310 MultiPortionType::BIDI
== pEnd2Pos
->nMultiType
&&
2311 pSt2Pos
->aPortion
== pEnd2Pos
->aPortion
&&
2312 pSt2Pos
->aPortion2
!= pEnd2Pos
->aPortion2
)
2314 // This is the ugly special case, where the selection starts and
2315 // ends in the same bidi portion but one start or end is inside a
2316 // nested bidi portion.
2318 if ( aRectFnSet
.GetWidth(pSt2Pos
->aPortion2
) )
2320 SwRect
aTmp( aStRect
);
2321 tools::Long nRightAbs
= aRectFnSet
.GetRight(pSt2Pos
->aPortion
);
2322 nRightAbs
-= aRectFnSet
.GetLeft(pSt2Pos
->aPortion2
);
2323 tools::Long nLeftAbs
= nRightAbs
- aRectFnSet
.GetWidth(pSt2Pos
->aPortion2
);
2325 aRectFnSet
.SetRight( aTmp
, nRightAbs
);
2326 aTmp
.Intersection( aStFrame
);
2327 Sub( aRegion
, aTmp
);
2329 aStRect
= pSt2Pos
->aLine
;
2330 aRectFnSet
.SetLeft( aStRect
, bR2L
? nRightAbs
: nLeftAbs
);
2331 aRectFnSet
.SetWidth( aStRect
, 1 );
2334 SwRectFnSet
fnRectX(pEndFrame
);
2335 if ( fnRectX
.GetWidth(pEnd2Pos
->aPortion2
) )
2337 SwRect
aTmp( aEndRect
);
2338 tools::Long nRightAbs
= fnRectX
.GetRight(pEnd2Pos
->aPortion
);
2339 nRightAbs
-= fnRectX
.GetLeft(pEnd2Pos
->aPortion2
);
2340 tools::Long nLeftAbs
= nRightAbs
- fnRectX
.GetWidth(pEnd2Pos
->aPortion2
);
2342 fnRectX
.SetLeft( aTmp
, nLeftAbs
);
2343 aTmp
.Intersection( aEndFrame
);
2344 Sub( aRegion
, aTmp
);
2346 aEndRect
= pEnd2Pos
->aLine
;
2347 fnRectX
.SetLeft( aEndRect
, bEndR2L
? nLeftAbs
: nRightAbs
);
2348 fnRectX
.SetWidth( aEndRect
, 1 );
2352 // The charrect may be outside the paintarea (for cursortravelling)
2353 // but the selection has to be restricted to the paintarea
2354 if( aStRect
.Left() < aStFrame
.Left() )
2355 aStRect
.Left( aStFrame
.Left() );
2356 else if( aStRect
.Left() > aStFrame
.Right() )
2357 aStRect
.Left( aStFrame
.Right() );
2358 SwTwips nTmp
= aStRect
.Right();
2359 if( nTmp
< aStFrame
.Left() )
2360 aStRect
.Right( aStFrame
.Left() );
2361 else if( nTmp
> aStFrame
.Right() )
2362 aStRect
.Right( aStFrame
.Right() );
2363 if( aEndRect
.Left() < aEndFrame
.Left() )
2364 aEndRect
.Left( aEndFrame
.Left() );
2365 else if( aEndRect
.Left() > aEndFrame
.Right() )
2366 aEndRect
.Left( aEndFrame
.Right() );
2367 nTmp
= aEndRect
.Right();
2368 if( nTmp
< aEndFrame
.Left() )
2369 aEndRect
.Right( aEndFrame
.Left() );
2370 else if( nTmp
> aEndFrame
.Right() )
2371 aEndRect
.Right( aEndFrame
.Right() );
2373 if( pStartFrame
== pEndFrame
)
2375 bool bSameRotatedOrBidi
= pSt2Pos
&& pEnd2Pos
&&
2376 ( MultiPortionType::BIDI
== pSt2Pos
->nMultiType
||
2377 MultiPortionType::ROT_270
== pSt2Pos
->nMultiType
||
2378 MultiPortionType::ROT_90
== pSt2Pos
->nMultiType
) &&
2379 pSt2Pos
->aPortion
== pEnd2Pos
->aPortion
;
2380 //case 1: (Same frame and same row)
2381 if( bSameRotatedOrBidi
||
2382 aRectFnSet
.GetTop(aStRect
) == aRectFnSet
.GetTop(aEndRect
) )
2384 Point
aTmpSt( aStRect
.Pos() );
2385 Point
aTmpEnd( aEndRect
.Right(), aEndRect
.Bottom() );
2386 if (bSameRotatedOrBidi
|| bR2L
|| bB2T
)
2388 if( aTmpSt
.Y() > aTmpEnd
.Y() )
2390 tools::Long nTmpY
= aTmpEnd
.Y();
2391 aTmpEnd
.setY( aTmpSt
.Y() );
2392 aTmpSt
.setY( nTmpY
);
2394 if( aTmpSt
.X() > aTmpEnd
.X() )
2396 tools::Long nTmpX
= aTmpEnd
.X();
2397 aTmpEnd
.setX( aTmpSt
.X() );
2398 aTmpSt
.setX( nTmpX
);
2402 SwRect
aTmp( aTmpSt
, aTmpEnd
);
2403 // Bug 34888: If content is selected which doesn't take space
2404 // away (i.e. PostIts, RefMarks, TOXMarks), then at
2405 // least set the width of the Cursor.
2406 if( 1 == aRectFnSet
.GetWidth(aTmp
) &&
2407 pStartPos
->GetContentIndex() !=
2408 pEndPos
->GetContentIndex() )
2410 OutputDevice
* pOut
= pSh
->GetOut();
2411 tools::Long nCursorWidth
= pOut
->GetSettings().GetStyleSettings().
2413 aRectFnSet
.SetWidth( aTmp
, pOut
->PixelToLogic(
2414 Size( nCursorWidth
, 0 ) ).Width() );
2416 aTmp
.Intersection( aStFrame
);
2417 Sub( aRegion
, aTmp
);
2419 //case 2: (Same frame, but not the same line)
2422 SwTwips lLeft
, lRight
;
2423 if( pSt2Pos
&& pEnd2Pos
&& pSt2Pos
->aPortion
== pEnd2Pos
->aPortion
)
2425 lLeft
= aRectFnSet
.GetLeft(pSt2Pos
->aPortion
);
2426 lRight
= aRectFnSet
.GetRight(pSt2Pos
->aPortion
);
2430 lLeft
= aRectFnSet
.GetLeft(pStartFrame
->getFrameArea()) +
2431 aRectFnSet
.GetLeft(pStartFrame
->getFramePrintArea());
2432 lRight
= aRectFnSet
.GetRight(aEndFrame
);
2434 if( lLeft
< aRectFnSet
.GetLeft(aStFrame
) )
2435 lLeft
= aRectFnSet
.GetLeft(aStFrame
);
2436 if( lRight
> aRectFnSet
.GetRight(aStFrame
) )
2437 lRight
= aRectFnSet
.GetRight(aStFrame
);
2438 SwRect
aSubRect( aStRect
);
2441 aRectFnSet
.SetLeft( aSubRect
, lLeft
);
2443 aRectFnSet
.SetRight( aSubRect
, lRight
);
2444 Sub( aRegion
, aSubRect
);
2446 //If there's at least a twips between start- and endline,
2447 //so the whole area between will be added.
2448 SwTwips aTmpBottom
= aRectFnSet
.GetBottom(aStRect
);
2449 SwTwips aTmpTop
= aRectFnSet
.GetTop(aEndRect
);
2450 if( aTmpBottom
!= aTmpTop
)
2452 aRectFnSet
.SetLeft( aSubRect
, lLeft
);
2453 aRectFnSet
.SetRight( aSubRect
, lRight
);
2454 aRectFnSet
.SetTop( aSubRect
, aTmpBottom
);
2455 aRectFnSet
.SetBottom( aSubRect
, aTmpTop
);
2456 Sub( aRegion
, aSubRect
);
2459 aSubRect
= aEndRect
;
2461 aRectFnSet
.SetRight( aSubRect
, lRight
);
2463 aRectFnSet
.SetLeft( aSubRect
, lLeft
);
2464 Sub( aRegion
, aSubRect
);
2467 //case 3: (Different frames, maybe with other frames between)
2470 //The startframe first...
2471 SwRect
aSubRect( aStRect
);
2473 aRectFnSet
.SetLeft( aSubRect
, aRectFnSet
.GetLeft(aStFrame
));
2475 aRectFnSet
.SetRight( aSubRect
, aRectFnSet
.GetRight(aStFrame
));
2476 Sub( aRegion
, aSubRect
);
2477 SwTwips nTmpTwips
= aRectFnSet
.GetBottom(aStRect
);
2478 if( aRectFnSet
.GetBottom(aStFrame
) != nTmpTwips
)
2480 aSubRect
= aStFrame
;
2481 aRectFnSet
.SetTop( aSubRect
, nTmpTwips
);
2482 Sub( aRegion
, aSubRect
);
2485 //Now the frames between, if there are any
2486 bool const bBody
= pStartFrame
->IsInDocBody();
2487 const SwTableBox
* pCellBox
= pStartFrame
->GetUpper()->IsCellFrame() ?
2488 static_cast<const SwCellFrame
*>(pStartFrame
->GetUpper())->GetTabBox() : nullptr;
2489 if (pSh
->IsSelectAll())
2492 const SwContentFrame
*pContent
= pStartFrame
->GetNextContentFrame();
2495 OSL_ENSURE( pContent
,
2496 "<SwRootFrame::CalcFrameRects(..)> - no content frame. This is a serious defect" );
2497 while ( pContent
&& pContent
!= pEndFrame
)
2499 if ( pContent
->IsInFly() )
2501 const SwAnchoredObject
* pObj
= pContent
->FindFlyFrame();
2502 if (!aSortObjs
.Contains(*pObj
))
2503 { // is this even possible, assuming valid cursor pos.?
2504 aSortObjs
.Insert( *const_cast<SwAnchoredObject
*>(pObj
) );
2508 // Consider only frames which have the same IsInDocBody value like pStartFrame
2509 // If pStartFrame is inside a SwCellFrame, consider only frames which are inside the
2510 // same cell frame (or its follow cell)
2511 const SwTableBox
* pTmpCellBox
= pContent
->GetUpper()->IsCellFrame() ?
2512 static_cast<const SwCellFrame
*>(pContent
->GetUpper())->GetTabBox() : nullptr;
2513 if (pSh
->IsSelectAll())
2514 pTmpCellBox
= nullptr;
2515 if ( bBody
== pContent
->IsInDocBody() &&
2516 ( !pCellBox
|| pCellBox
== pTmpCellBox
) )
2518 SwRect
aCRect( pContent
->UnionFrame( true ) );
2519 aCRect
.Intersection( pContent
->GetPaintArea() );
2520 if( aCRect
.Overlaps( aRegion
.GetOrigin() ))
2522 SwRect
aTmp( aPrvRect
);
2523 aTmp
.Union( aCRect
);
2524 if ( (aPrvRect
.Height() * aPrvRect
.Width() +
2525 aCRect
.Height() * aCRect
.Width()) ==
2526 (aTmp
.Height() * aTmp
.Width()) )
2528 aPrvRect
.Union( aCRect
);
2532 if ( aPrvRect
.HasArea() )
2533 Sub( aRegion
, aPrvRect
);
2538 pContent
= pContent
->GetNextContentFrame();
2539 OSL_ENSURE( pContent
,
2540 "<SwRootFrame::CalcFrameRects(..)> - no content frame. This is a serious defect!" );
2542 if ( aPrvRect
.HasArea() )
2543 Sub( aRegion
, aPrvRect
);
2545 //At least the endframe...
2546 aRectFnSet
.Refresh(pEndFrame
);
2547 nTmpTwips
= aRectFnSet
.GetTop(aEndRect
);
2548 if( aRectFnSet
.GetTop(aEndFrame
) != nTmpTwips
)
2550 aSubRect
= aEndFrame
;
2551 aRectFnSet
.SetBottom( aSubRect
, nTmpTwips
);
2552 Sub( aRegion
, aSubRect
);
2554 aSubRect
= aEndRect
;
2556 aRectFnSet
.SetRight(aSubRect
, aRectFnSet
.GetRight(aEndFrame
));
2558 aRectFnSet
.SetLeft( aSubRect
, aRectFnSet
.GetLeft(aEndFrame
) );
2559 Sub( aRegion
, aSubRect
);
2566 // Cut out Flys during loop. We don't cut out Flys when:
2567 // - the Lower is StartFrame/EndFrame (FlyInCnt and all other Flys which again
2569 // - if in the Z-order we have Flys above those in which the StartFrame is
2571 // - if they are anchored to inside the selection and thus part of it
2572 const SwPageFrame
*pPage
= pStartFrame
->FindPageFrame();
2573 const SwPageFrame
*pEndPage
= pEndFrame
->FindPageFrame();
2577 if ( pPage
->GetSortedObjs() )
2579 const SwSortedObjs
&rObjs
= *pPage
->GetSortedObjs();
2580 for (SwAnchoredObject
* pAnchoredObj
: rObjs
)
2582 const SwFlyFrame
* pFly
= pAnchoredObj
->DynCastFlyFrame();
2585 const SwVirtFlyDrawObj
* pObj
= pFly
->GetVirtDrawObj();
2586 const SwFormatSurround
&rSur
= pFly
->GetFormat()->GetSurround();
2587 SwFormatAnchor
const& rAnchor(pAnchoredObj
->GetFrameFormat().GetAnchor());
2588 const SwPosition
* anchoredAt
= rAnchor
.GetContentAnchor();
2589 bool inSelection
= (
2590 anchoredAt
!= nullptr
2591 && ( (rAnchor
.GetAnchorId() == RndStdIds::FLY_AT_CHAR
2592 && IsDestroyFrameAnchoredAtChar(*anchoredAt
, *pStartPos
, *pEndPos
))
2593 || (rAnchor
.GetAnchorId() == RndStdIds::FLY_AT_PARA
2594 && IsSelectFrameAnchoredAtPara(*anchoredAt
, *pStartPos
, *pEndPos
))));
2596 Add( aRegion
, pFly
->getFrameArea() );
2597 else if ( !pFly
->IsAnLower( pStartFrame
) &&
2598 (rSur
.GetSurround() != css::text::WrapTextMode_THROUGH
&&
2599 !rSur
.IsContour()) )
2601 if ( aSortObjs
.Contains( *pAnchoredObj
) )
2605 const sal_uInt32 nPos
= pObj
->GetOrdNum();
2606 for ( size_t k
= 0; bSub
&& k
< aSortObjs
.size(); ++k
)
2608 assert( dynamic_cast< const SwFlyFrame
*>( aSortObjs
[k
] ) &&
2609 "<SwRootFrame::CalcFrameRects(..)> - object in <aSortObjs> of unexpected type" );
2610 const SwFlyFrame
* pTmp
= static_cast<SwFlyFrame
*>(aSortObjs
[k
]);
2613 if ( nPos
< pTmp
->GetVirtDrawObj()->GetOrdNumDirect() )
2619 pTmp
= pTmp
->GetAnchorFrame()->FindFlyFrame();
2621 } while ( bSub
&& pTmp
);
2624 Sub( aRegion
, pFly
->getFrameArea() );
2628 if ( pPage
== pEndPage
)
2631 pPage
= static_cast<const SwPageFrame
*>(pPage
->GetNext());
2634 //Because it looks better, we close the DropCaps.
2636 if ( pStartFrame
->IsTextFrame() )
2638 if ( static_cast<const SwTextFrame
*>(pStartFrame
)->GetDropRect( aDropRect
) )
2639 Sub( aRegion
, aDropRect
);
2641 if ( pEndFrame
!= pStartFrame
&& pEndFrame
->IsTextFrame() )
2643 if ( static_cast<const SwTextFrame
*>(pEndFrame
)->GetDropRect( aDropRect
) )
2644 Sub( aRegion
, aDropRect
);
2647 rCursor
.assign( aRegion
.begin(), aRegion
.end() );
2650 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */