Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx
Warning:line 1501, column 60
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name trvlfrm.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <hints.hxx>
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>
31#include <ftnfrm.hxx>
32#include <flyfrm.hxx>
33#include <tabfrm.hxx>
34#include <rowfrm.hxx>
35#include <cellfrm.hxx>
36#include <txtfrm.hxx>
37#include <notxtfrm.hxx>
38#include <viewopt.hxx>
39#include <DocumentSettingManager.hxx>
40#include <viscrs.hxx>
41#include <dflyobj.hxx>
42#include <crstate.hxx>
43#include <dcontact.hxx>
44#include <sortedobjs.hxx>
45#include <txatbase.hxx>
46#include <fmtfld.hxx>
47#include <fldbas.hxx>
48#include <frmatr.hxx>
49#include <frmtool.hxx>
50#include <ndtxt.hxx>
51#include <undobj.hxx>
52
53#include <swselectionlist.hxx>
54#include <comphelper/lok.hxx>
55
56namespace {
57 bool lcl_GetModelPositionForViewPoint_Objects( const SwPageFrame* pPageFrame, bool bSearchBackground,
58 SwPosition *pPos, Point const & rPoint, SwCursorMoveState* pCMS )
59 {
60 bool bRet = false;
61 Point aPoint( rPoint );
62 SwOrderIter aIter( pPageFrame );
63 aIter.Top();
64 while ( aIter() )
65 {
66 const SwVirtFlyDrawObj* pObj =
67 static_cast<const SwVirtFlyDrawObj*>(aIter());
68 const SwAnchoredObject* pAnchoredObj = GetUserCall( aIter() )->GetAnchoredObj( aIter() );
69 const SwFormatSurround& rSurround = pAnchoredObj->GetFrameFormat().GetSurround();
70 const SvxOpaqueItem& rOpaque = pAnchoredObj->GetFrameFormat().GetOpaque();
71 bool bInBackground = ( rSurround.GetSurround() == css::text::WrapTextMode_THROUGH ) && !rOpaque.GetValue();
72
73 bool bBackgroundMatches = bInBackground == bSearchBackground;
74
75 const SwFlyFrame* pFly = pObj ? pObj->GetFlyFrame() : nullptr;
76 if ( pFly && bBackgroundMatches &&
77 ( ( pCMS && pCMS->m_bSetInReadOnly ) ||
78 !pFly->IsProtected() ) &&
79 pFly->GetModelPositionForViewPoint( pPos, aPoint, pCMS ) )
80 {
81 bRet = true;
82 break;
83 }
84
85 if ( pCMS && pCMS->m_bStop )
86 return false;
87 aIter.Prev();
88 }
89 return bRet;
90 }
91
92 double lcl_getDistance( const SwRect& rRect, const Point& rPoint )
93 {
94 double nDist = 0.0;
95
96 // If the point is inside the rectangle, then distance is 0
97 // Otherwise, compute the distance to the center of the rectangle.
98 if ( !rRect.IsInside( rPoint ) )
99 {
100 tools::Line aLine( rPoint, rRect.Center( ) );
101 nDist = aLine.GetLength( );
102 }
103
104 return nDist;
105 }
106}
107
108namespace {
109
110//For SwFlyFrame::GetModelPositionForViewPoint
111class SwCursorOszControl
112{
113public:
114 // So the compiler can initialize the class already. No DTOR and member
115 // as public members
116 const SwFlyFrame *pEntry;
117 const SwFlyFrame *pStack1;
118 const SwFlyFrame *pStack2;
119
120 bool ChkOsz( const SwFlyFrame *pFly )
121 {
122 bool bRet = true;
123 if ( pFly != pStack1 && pFly != pStack2 )
124 {
125 pStack1 = pStack2;
126 pStack2 = pFly;
127 bRet = false;
128 }
129 return bRet;
130 }
131
132 void Entry( const SwFlyFrame *pFly )
133 {
134 if ( !pEntry )
135 pEntry = pStack1 = pFly;
136 }
137
138 void Exit( const SwFlyFrame *pFly )
139 {
140 if ( pFly == pEntry )
141 pEntry = pStack1 = pStack2 = nullptr;
142 }
143};
144
145}
146
147static SwCursorOszControl g_OszCtrl = { nullptr, nullptr, nullptr };
148
149/** Searches the ContentFrame owning the PrtArea containing the point. */
150bool SwLayoutFrame::GetModelPositionForViewPoint( SwPosition *pPos, Point &rPoint,
151 SwCursorMoveState* pCMS, bool ) const
152{
153 vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut();
154 bool bRet = false;
155 const SwFrame *pFrame = Lower();
156 while ( !bRet && pFrame )
157 {
158 pFrame->Calc(pRenderContext);
159
160 // #i43742# New function
161 const bool bContentCheck = pFrame->IsTextFrame() && pCMS && pCMS->m_bContentCheck;
162 const SwRect aPaintRect( bContentCheck ?
163 pFrame->UnionFrame() :
164 pFrame->GetPaintArea() );
165
166 if ( aPaintRect.IsInside( rPoint ) &&
167 ( bContentCheck || pFrame->GetModelPositionForViewPoint( pPos, rPoint, pCMS ) ) )
168 bRet = true;
169 else
170 pFrame = pFrame->GetNext();
171 if ( pCMS && pCMS->m_bStop )
172 return false;
173 }
174 return bRet;
175}
176
177/** Searches the page containing the searched point. */
178
179bool SwPageFrame::GetModelPositionForViewPoint( SwPosition *pPos, Point &rPoint,
180 SwCursorMoveState* pCMS, bool bTestBackground ) const
181{
182 Point aPoint( rPoint );
183
184 // check, if we have to adjust the point
185 if ( !getFrameArea().IsInside( aPoint ) )
186 {
187 aPoint.setX( std::max( aPoint.X(), getFrameArea().Left() ) );
188 aPoint.setX( std::min( aPoint.X(), getFrameArea().Right() ) );
189 aPoint.setY( std::max( aPoint.Y(), getFrameArea().Top() ) );
190 aPoint.setY( std::min( aPoint.Y(), getFrameArea().Bottom() ) );
191 }
192
193 bool bRet = false;
194 //Could it be a free flying one?
195 //If his content should be protected, we can't set the Cursor in it, thus
196 //all changes should be impossible.
197 if ( GetSortedObjs() )
198 {
199 bRet = lcl_GetModelPositionForViewPoint_Objects( this, false, pPos, rPoint, pCMS );
200 }
201
202 if ( !bRet )
203 {
204 SwPosition aBackPos( *pPos );
205 SwPosition aTextPos( *pPos );
206
207 //We fix the StartPoint if no Content below the page 'answers' and then
208 //start all over again one page before the current one.
209 //However we can't use Flys in such a case.
210 if (!SwLayoutFrame::GetModelPositionForViewPoint(&aTextPos, aPoint, pCMS))
211 {
212 if ( pCMS && (pCMS->m_bStop || pCMS->m_bExactOnly) )
213 {
214 pCMS->m_bStop = true;
215 return false;
216 }
217
218 const SwContentFrame *pCnt = GetContentPos( aPoint, false, false, pCMS, false );
219 // GetContentPos may have modified pCMS
220 if ( pCMS && pCMS->m_bStop )
221 return false;
222
223 bool bTextRet = false;
224
225 OSL_ENSURE( pCnt, "Cursor is gone to a Black hole" )do { if (true && (!(pCnt))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "225" ": "), "%s", "Cursor is gone to a Black hole"); } }
while (false)
;
226 if( pCMS && pCMS->m_pFill && pCnt->IsTextFrame() )
227 bTextRet = pCnt->GetModelPositionForViewPoint( &aTextPos, rPoint, pCMS );
228 else
229 bTextRet = pCnt->GetModelPositionForViewPoint( &aTextPos, aPoint, pCMS );
230
231 if ( !bTextRet )
232 {
233 // Set point to pCnt, delete mark
234 // this may happen, if pCnt is hidden
235 if (pCnt->IsTextFrame())
236 {
237 aTextPos = static_cast<SwTextFrame const*>(pCnt)->MapViewToModelPos(TextFrameIndex(0));
238 }
239 else
240 {
241 assert(pCnt->IsNoTextFrame())(static_cast <bool> (pCnt->IsNoTextFrame()) ? void (
0) : __assert_fail ("pCnt->IsNoTextFrame()", "/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
, 241, __extension__ __PRETTY_FUNCTION__))
;
242 aTextPos = SwPosition( *static_cast<SwNoTextFrame const*>(pCnt)->GetNode() );
243 }
244 }
245 }
246
247 SwContentNode* pContentNode = aTextPos.nNode.GetNode().GetContentNode();
248 bool bConsiderBackground = true;
249 // If the text position is a clickable field, then that should have priority.
250 if (pContentNode && pContentNode->IsTextNode())
251 {
252 SwTextNode* pTextNd = pContentNode->GetTextNode();
253 SwTextAttr* pTextAttr = pTextNd->GetTextAttrForCharAt(aTextPos.nContent.GetIndex(), RES_TXTATR_FIELD);
254 if (pTextAttr)
255 {
256 const SwField* pField = pTextAttr->GetFormatField().GetField();
257 if (pField->IsClickable())
258 bConsiderBackground = false;
259 }
260 }
261
262 bool bBackRet = false;
263 // Check objects in the background if nothing else matched
264 if ( GetSortedObjs() )
265 {
266 bBackRet = lcl_GetModelPositionForViewPoint_Objects( this, true, &aBackPos, rPoint, pCMS );
267 }
268
269 if (bConsiderBackground && bTestBackground && bBackRet)
270 {
271 (*pPos) = aBackPos;
272 }
273 else if (!bBackRet)
274 {
275 (*pPos) = aTextPos;
276 }
277 else // bBackRet && !(bConsiderBackground && bTestBackground)
278 {
279 /* In order to provide a selection as accurate as possible when we have both
280 * text and background object, then we compute the distance between both
281 * would-be positions and the click point. The shortest distance wins.
282 */
283 double nTextDistance = 0;
284 bool bValidTextDistance = false;
285 if (pContentNode)
286 {
287 SwContentFrame* pTextFrame = pContentNode->getLayoutFrame( getRootFrame( ) );
288
289 // try this again but prefer the "previous" position
290 SwCursorMoveState aMoveState;
291 SwCursorMoveState *const pState(pCMS ? pCMS : &aMoveState);
292 comphelper::FlagRestorationGuard g(
293 pState->m_bPosMatchesBounds, true);
294 SwPosition prevTextPos(*pPos);
295 if (SwLayoutFrame::GetModelPositionForViewPoint(&prevTextPos, aPoint, pState))
296 {
297 SwRect aTextRect;
298 pTextFrame->GetCharRect(aTextRect, prevTextPos);
299
300 if (prevTextPos.nContent < pContentNode->Len())
301 {
302 // aRextRect is just a line on the left edge of the
303 // previous character; to get a better measure from
304 // lcl_getDistance, extend that to a rectangle over
305 // the entire character.
306 SwPosition const nextTextPos(prevTextPos.nNode,
307 SwIndex(prevTextPos.nContent, +1));
308 SwRect nextTextRect;
309 pTextFrame->GetCharRect(nextTextRect, nextTextPos);
310 SwRectFnSet aRectFnSet(pTextFrame);
311 if (aRectFnSet.GetTop(aTextRect) ==
312 aRectFnSet.GetTop(nextTextRect)) // same line?
313 {
314 // need to handle mixed RTL/LTR portions somehow
315 if (aRectFnSet.GetLeft(aTextRect) <
316 aRectFnSet.GetLeft(nextTextRect))
317 {
318 aRectFnSet.SetRight( aTextRect,
319 aRectFnSet.GetLeft(nextTextRect));
320 }
321 else // RTL
322 {
323 aRectFnSet.SetLeft( aTextRect,
324 aRectFnSet.GetLeft(nextTextRect));
325 }
326 }
327 }
328
329 nTextDistance = lcl_getDistance(aTextRect, rPoint);
330 bValidTextDistance = true;
331 }
332 }
333
334 double nBackDistance = 0;
335 bool bValidBackDistance = false;
336 SwContentNode* pBackNd = aBackPos.nNode.GetNode( ).GetContentNode( );
337 if ( pBackNd && bConsiderBackground)
338 {
339 // FIXME There are still cases were we don't have the proper node here.
340 SwContentFrame* pBackFrame = pBackNd->getLayoutFrame( getRootFrame( ) );
341 if (pBackFrame)
342 {
343 SwRect rBackRect;
344 pBackFrame->GetCharRect( rBackRect, aBackPos );
345
346 nBackDistance = lcl_getDistance( rBackRect, rPoint );
347 bValidBackDistance = true;
348 }
349 }
350
351 if ( bValidTextDistance && bValidBackDistance && basegfx::fTools::more( nTextDistance, nBackDistance ) )
352 {
353 (*pPos) = aBackPos;
354 }
355 else
356 {
357 (*pPos) = aTextPos;
358 }
359 }
360 }
361
362 rPoint = aPoint;
363 return true;
364}
365
366bool SwLayoutFrame::FillSelection( SwSelectionList& rList, const SwRect& rRect ) const
367{
368 if( rRect.IsOver(GetPaintArea()) )
369 {
370 const SwFrame* pFrame = Lower();
371 while( pFrame )
372 {
373 pFrame->FillSelection( rList, rRect );
374 pFrame = pFrame->GetNext();
375 }
376 }
377 return false;
378}
379
380bool SwPageFrame::FillSelection( SwSelectionList& rList, const SwRect& rRect ) const
381{
382 bool bRet = false;
383 if( rRect.IsOver(GetPaintArea()) )
384 {
385 bRet = SwLayoutFrame::FillSelection( rList, rRect );
386 if( GetSortedObjs() )
387 {
388 const SwSortedObjs &rObjs = *GetSortedObjs();
389 for (SwAnchoredObject* pAnchoredObj : rObjs)
390 {
391 if( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) == nullptr )
392 continue;
393 const SwFlyFrame* pFly = static_cast<const SwFlyFrame*>(pAnchoredObj);
394 if( pFly->FillSelection( rList, rRect ) )
395 bRet = true;
396 }
397 }
398 }
399 return bRet;
400}
401
402bool SwRootFrame::FillSelection( SwSelectionList& aSelList, const SwRect& rRect) const
403{
404 const SwFrame *pPage = Lower();
405 const long nBottom = rRect.Bottom();
406 while( pPage )
407 {
408 if( pPage->getFrameArea().Top() < nBottom )
409 {
410 if( pPage->getFrameArea().Bottom() > rRect.Top() )
411 pPage->FillSelection( aSelList, rRect );
412 pPage = pPage->GetNext();
413 }
414 else
415 pPage = nullptr;
416 }
417 return !aSelList.isEmpty();
418}
419
420/** Primary passes the call to the first page.
421 *
422 * @return false, if the passed Point gets changed
423 */
424bool SwRootFrame::GetModelPositionForViewPoint( SwPosition *pPos, Point &rPoint,
425 SwCursorMoveState* pCMS, bool bTestBackground ) const
426{
427 const bool bOldAction = IsCallbackActionEnabled();
428 const_cast<SwRootFrame*>(this)->SetCallbackActionEnabled( false );
429 OSL_ENSURE( (Lower() && Lower()->IsPageFrame()), "No PageFrame found." )do { if (true && (!((Lower() && Lower()->IsPageFrame
())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "429" ": "), "%s", "No PageFrame found."); } } while (false
)
;
430 if( pCMS && pCMS->m_pFill )
431 pCMS->m_bFillRet = false;
432 Point aOldPoint = rPoint;
433
434 // search for page containing rPoint. The borders around the pages are considered
435 const SwPageFrame* pPage = GetPageAtPos( rPoint, nullptr, true );
436
437 // #i95626#
438 // special handling for <rPoint> beyond root frames area
439 if ( !pPage &&
440 rPoint.X() > getFrameArea().Right() &&
441 rPoint.Y() > getFrameArea().Bottom() )
442 {
443 pPage = dynamic_cast<const SwPageFrame*>(Lower());
444 while ( pPage && pPage->GetNext() )
445 {
446 pPage = dynamic_cast<const SwPageFrame*>(pPage->GetNext());
447 }
448 }
449 if ( pPage )
450 {
451 pPage->SwPageFrame::GetModelPositionForViewPoint( pPos, rPoint, pCMS, bTestBackground );
452 }
453
454 const_cast<SwRootFrame*>(this)->SetCallbackActionEnabled( bOldAction );
455 if( pCMS )
456 {
457 if( pCMS->m_bStop )
458 return false;
459 if( pCMS->m_pFill )
460 return pCMS->m_bFillRet;
461 }
462 return aOldPoint == rPoint;
463}
464
465/**
466 * If this is about a Content-carrying cell the Cursor will be force inserted into one of the ContentFrames
467 * if there are no other options.
468 *
469 * There is no entry for protected cells.
470 */
471bool SwCellFrame::GetModelPositionForViewPoint( SwPosition *pPos, Point &rPoint,
472 SwCursorMoveState* pCMS, bool ) const
473{
474 vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut();
475 // cell frame does not necessarily have a lower (split table cell)
476 if ( !Lower() )
477 return false;
478
479 if ( !(pCMS && pCMS->m_bSetInReadOnly) &&
480 GetFormat()->GetProtect().IsContentProtected() )
481 return false;
482
483 if ( pCMS && pCMS->m_eState == CursorMoveState::TableSel )
484 {
485 const SwTabFrame *pTab = FindTabFrame();
486 if ( pTab->IsFollow() && pTab->IsInHeadline( *this ) )
487 {
488 pCMS->m_bStop = true;
489 return false;
490 }
491 }
492
493 if ( Lower() )
494 {
495 if ( Lower()->IsLayoutFrame() )
496 return SwLayoutFrame::GetModelPositionForViewPoint( pPos, rPoint, pCMS );
497 else
498 {
499 Calc(pRenderContext);
500 bool bRet = false;
501
502 const SwFrame *pFrame = Lower();
503 while ( pFrame && !bRet )
504 {
505 pFrame->Calc(pRenderContext);
506 if ( pFrame->getFrameArea().IsInside( rPoint ) )
507 {
508 bRet = pFrame->GetModelPositionForViewPoint( pPos, rPoint, pCMS );
509 if ( pCMS && pCMS->m_bStop )
510 return false;
511 }
512 pFrame = pFrame->GetNext();
513 }
514 if ( !bRet )
515 {
516 const bool bFill = pCMS && pCMS->m_pFill;
517 Point aPoint( rPoint );
518 const SwContentFrame *pCnt = GetContentPos( rPoint, true );
519 if( bFill && pCnt->IsTextFrame() )
520 {
521 rPoint = aPoint;
522 }
523 pCnt->GetModelPositionForViewPoint( pPos, rPoint, pCMS );
524 }
525 return true;
526 }
527 }
528
529 return false;
530}
531
532//Problem: If two Flys have the same size and share the same position then
533//they end inside each other.
534//Because we recursively check if a Point doesn't randomly lie inside another
535//fly which lies completely inside the current Fly we could trigger an endless
536//loop with the mentioned situation above.
537//Using the helper class SwCursorOszControl we prevent the recursion. During
538//a recursion GetModelPositionForViewPoint picks the one which lies on top.
539bool SwFlyFrame::GetModelPositionForViewPoint( SwPosition *pPos, Point &rPoint,
540 SwCursorMoveState* pCMS, bool ) const
541{
542 vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut();
543 g_OszCtrl.Entry( this );
544
545 //If the Points lies inside the Fly, we try hard to set the Cursor inside it.
546 //However if the Point sits inside a Fly which is completely located inside
547 //the current one, we call GetModelPositionForViewPoint for it.
548 Calc(pRenderContext);
549 bool bInside = getFrameArea().IsInside( rPoint ) && Lower();
550 bool bRet = false;
551
552 //If a Frame contains a graphic, but only text was requested, it basically
553 //won't accept the Cursor.
554 if ( bInside && pCMS && pCMS->m_eState == CursorMoveState::SetOnlyText &&
555 (!Lower() || Lower()->IsNoTextFrame()) )
556 bInside = false;
557
558 const SwPageFrame *pPage = FindPageFrame();
559 if ( bInside && pPage && pPage->GetSortedObjs() )
560 {
561 SwOrderIter aIter( pPage );
562 aIter.Top();
563 while ( aIter() && !bRet )
564 {
565 const SwVirtFlyDrawObj* pObj = static_cast<const SwVirtFlyDrawObj*>(aIter());
566 const SwFlyFrame* pFly = pObj ? pObj->GetFlyFrame() : nullptr;
567 if ( pFly && pFly->getFrameArea().IsInside( rPoint ) &&
568 getFrameArea().IsInside( pFly->getFrameArea() ) )
569 {
570 if (g_OszCtrl.ChkOsz(pFly))
571 break;
572 bRet = pFly->GetModelPositionForViewPoint( pPos, rPoint, pCMS );
573 if ( bRet )
574 break;
575 if ( pCMS && pCMS->m_bStop )
576 return false;
577 }
578 aIter.Next();
579 }
580 }
581
582 while ( bInside && !bRet )
583 {
584 const SwFrame *pFrame = Lower();
585 while ( pFrame && !bRet )
586 {
587 pFrame->Calc(pRenderContext);
588 if ( pFrame->getFrameArea().IsInside( rPoint ) )
589 {
590 bRet = pFrame->GetModelPositionForViewPoint( pPos, rPoint, pCMS );
591 if ( pCMS && pCMS->m_bStop )
592 return false;
593 }
594 pFrame = pFrame->GetNext();
595 }
596 if ( !bRet )
597 {
598 const bool bFill = pCMS && pCMS->m_pFill;
599 Point aPoint( rPoint );
600 const SwContentFrame *pCnt = GetContentPos( rPoint, true, false, pCMS );
601 if ( pCMS && pCMS->m_bStop )
602 return false;
603 if( bFill && pCnt->IsTextFrame() )
604 {
605 rPoint = aPoint;
606 }
607 pCnt->GetModelPositionForViewPoint( pPos, rPoint, pCMS );
608 bRet = true;
609 }
610 }
611 g_OszCtrl.Exit( this );
612 return bRet;
613}
614
615/** Layout dependent cursor travelling */
616bool SwNoTextFrame::LeftMargin(SwPaM *pPam) const
617{
618 if( &pPam->GetNode() != GetNode() )
619 return false;
620 const_cast<SwContentNode*>(GetNode())->
621 MakeStartIndex(&pPam->GetPoint()->nContent);
622 return true;
623}
624
625bool SwNoTextFrame::RightMargin(SwPaM *pPam, bool) const
626{
627 if( &pPam->GetNode() != GetNode() )
628 return false;
629 const_cast<SwContentNode*>(GetNode())->
630 MakeEndIndex(&pPam->GetPoint()->nContent);
631 return true;
632}
633
634static const SwContentFrame *lcl_GetNxtCnt( const SwContentFrame* pCnt )
635{
636 return pCnt->GetNextContentFrame();
637}
638
639static const SwContentFrame *lcl_GetPrvCnt( const SwContentFrame* pCnt )
640{
641 return pCnt->GetPrevContentFrame();
642}
643
644typedef const SwContentFrame *(*GetNxtPrvCnt)( const SwContentFrame* );
645
646/// Frame in repeated headline?
647static bool lcl_IsInRepeatedHeadline( const SwFrame *pFrame,
648 const SwTabFrame** ppTFrame = nullptr )
649{
650 const SwTabFrame *pTab = pFrame->FindTabFrame();
651 if( ppTFrame )
652 *ppTFrame = pTab;
653 return pTab && pTab->IsFollow() && pTab->IsInHeadline( *pFrame );
654}
655
656/// Skip protected table cells. Optionally also skip repeated headlines.
657//MA 1998-01-26: Chg also skip other protected areas
658//FME: Skip follow flow cells
659static const SwContentFrame * lcl_MissProtectedFrames( const SwContentFrame *pCnt,
660 GetNxtPrvCnt fnNxtPrv,
661 bool bMissHeadline,
662 bool bInReadOnly,
663 bool bMissFollowFlowLine )
664{
665 if ( pCnt && pCnt->IsInTab() )
666 {
667 bool bProtect = true;
668 while ( pCnt && bProtect )
669 {
670 const SwLayoutFrame *pCell = pCnt->GetUpper();
671 while ( pCell && !pCell->IsCellFrame() )
672 pCell = pCell->GetUpper();
673 if ( !pCell ||
674 ( ( bInReadOnly || !pCell->GetFormat()->GetProtect().IsContentProtected() ) &&
675 ( !bMissHeadline || !lcl_IsInRepeatedHeadline( pCell ) ) &&
676 ( !bMissFollowFlowLine || !pCell->IsInFollowFlowRow() ) &&
677 !pCell->IsCoveredCell() ) )
678 bProtect = false;
679 else
680 pCnt = (*fnNxtPrv)( pCnt );
681 }
682 }
683 else if ( !bInReadOnly )
684 while ( pCnt && pCnt->IsProtected() )
685 pCnt = (*fnNxtPrv)( pCnt );
686
687 return pCnt;
688}
689
690static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart,
691 GetNxtPrvCnt fnNxtPrv, bool bInReadOnly )
692{
693 OSL_ENSURE( FrameContainsNode(*pStart, pPam->GetNode().GetIndex()),do { if (true && (!(FrameContainsNode(*pStart, pPam->
GetNode().GetIndex())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "694" ": "), "%s", "lcl_UpDown doesn't work for others."
); } } while (false)
694 "lcl_UpDown doesn't work for others." )do { if (true && (!(FrameContainsNode(*pStart, pPam->
GetNode().GetIndex())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "694" ": "), "%s", "lcl_UpDown doesn't work for others."
); } } while (false)
;
695
696 const SwContentFrame *pCnt = nullptr;
697
698 //We have to cheat a little bit during a table selection: Go to the
699 //beginning of the cell while going up and go to the end of the cell while
700 //going down.
701 bool bTableSel = false;
702 if ( pStart->IsInTab() &&
703 pPam->GetNode().StartOfSectionNode() !=
704 pPam->GetNode( false ).StartOfSectionNode() )
705 {
706 bTableSel = true;
707 const SwLayoutFrame *pCell = pStart->GetUpper();
708 while ( !pCell->IsCellFrame() )
709 pCell = pCell->GetUpper();
710
711 // Check, if cell has a Prev/Follow cell:
712 const bool bFwd = ( fnNxtPrv == lcl_GetNxtCnt );
713 const SwLayoutFrame* pTmpCell = bFwd ?
714 static_cast<const SwCellFrame*>(pCell)->GetFollowCell() :
715 static_cast<const SwCellFrame*>(pCell)->GetPreviousCell();
716
717 const SwContentFrame* pTmpStart = pStart;
718 while ( pTmpCell && nullptr != ( pTmpStart = pTmpCell->ContainsContent() ) )
719 {
720 pCell = pTmpCell;
721 pTmpCell = bFwd ?
722 static_cast<const SwCellFrame*>(pCell)->GetFollowCell() :
723 static_cast<const SwCellFrame*>(pCell)->GetPreviousCell();
724 }
725 const SwContentFrame *pNxt = pCnt = pTmpStart;
726
727 while ( pCell->IsAnLower( pNxt ) )
728 {
729 pCnt = pNxt;
730 pNxt = (*fnNxtPrv)( pNxt );
731 }
732 }
733
734 pCnt = (*fnNxtPrv)( pCnt ? pCnt : pStart );
735 pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel );
736
737 const SwTabFrame *pStTab = pStart->FindTabFrame();
738 const SwTabFrame *pTable = nullptr;
739 const bool bTab = pStTab || (pCnt && pCnt->IsInTab());
740 bool bEnd = !bTab;
741
742 const SwFrame* pVertRefFrame = pStart;
743 if ( bTableSel && pStTab )
744 pVertRefFrame = pStTab;
745 SwRectFnSet aRectFnSet(pVertRefFrame);
746
747 SwTwips nX = 0;
748 if ( bTab )
749 {
750 // pStart or pCnt is inside a table. nX will be used for travelling:
751 SwRect aRect( pStart->getFrameArea() );
752 pStart->GetCharRect( aRect, *pPam->GetPoint() );
753 Point aCenter = aRect.Center();
754 nX = aRectFnSet.IsVert() ? aCenter.Y() : aCenter.X();
755
756 pTable = pCnt ? pCnt->FindTabFrame() : nullptr;
757 if ( !pTable )
758 pTable = pStTab;
759
760 if ( pStTab &&
761 !pStTab->GetUpper()->IsInTab() &&
762 !pTable->GetUpper()->IsInTab() )
763 {
764 const SwFrame *pCell = pStart->GetUpper();
765 while ( pCell && !pCell->IsCellFrame() )
766 pCell = pCell->GetUpper();
767 OSL_ENSURE( pCell, "could not find the cell" )do { if (true && (!(pCell))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "767" ": "), "%s", "could not find the cell"); } } while
(false)
;
768 nX = aRectFnSet.XInc(aRectFnSet.GetLeft(pCell->getFrameArea()),
769 aRectFnSet.GetWidth(pCell->getFrameArea()) / 2);
770
771 //The flow leads from one table to the next. The X-value needs to be
772 //corrected based on the middle of the starting cell by the amount
773 //of the offset of the tables.
774 if ( pStTab != pTable )
775 {
776 nX += aRectFnSet.GetLeft(pTable->getFrameArea()) -
777 aRectFnSet.GetLeft(pStTab->getFrameArea());
778 }
779 }
780
781 // Restrict nX to the left and right borders of pTab:
782 // (is this really necessary?)
783 if (pTable && !pTable->GetUpper()->IsInTab())
784 {
785 const bool bRTL = pTable->IsRightToLeft();
786 const long nPrtLeft = bRTL ?
787 aRectFnSet.GetPrtRight(*pTable) :
788 aRectFnSet.GetPrtLeft(*pTable);
789 if (bRTL != (aRectFnSet.XDiff(nPrtLeft, nX) > 0))
790 nX = nPrtLeft;
791 else
792 {
793 const long nPrtRight = bRTL ?
794 aRectFnSet.GetPrtLeft(*pTable) :
795 aRectFnSet.GetPrtRight(*pTable);
796 if (bRTL != (aRectFnSet.XDiff(nX, nPrtRight) > 0))
797 nX = nPrtRight;
798 }
799 }
800 }
801
802 do
803 {
804 //If I'm in the DocumentBody, I want to stay there.
805 if ( pStart->IsInDocBody() )
806 {
807 while ( pCnt && (!pCnt->IsInDocBody() ||
808 (pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow())))
809 {
810 pCnt = (*fnNxtPrv)( pCnt );
811 pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel );
812 }
813 }
814
815 //If I'm in the FootNoteArea, I try to reach the next FootNoteArea in
816 //case of necessity.
817 else if ( pStart->IsInFootnote() )
818 {
819 while ( pCnt && (!pCnt->IsInFootnote() ||
820 (pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow())))
821 {
822 pCnt = (*fnNxtPrv)( pCnt );
823 pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel );
824 }
825 }
826
827 //In Flys we can go ahead blindly as long as we find a Content.
828 else if ( pStart->IsInFly() )
829 {
830 if ( pCnt && pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow() )
831 {
832 pCnt = (*fnNxtPrv)( pCnt );
833 pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel );
834 }
835 }
836
837 //Otherwise I'll just refuse to leave to current area.
838 else if ( pCnt )
839 {
840 const SwFrame *pUp = pStart->GetUpper();
841 while (pUp && pUp->GetUpper() && !(pUp->GetType() & FRM_HEADFOOT(SwFrameType::Header | SwFrameType::Footer)))
842 pUp = pUp->GetUpper();
843 bool bSame = false;
844 const SwFrame *pCntUp = pCnt->GetUpper();
845 while ( pCntUp && !bSame )
846 {
847 if ( pUp == pCntUp )
848 bSame = true;
849 else
850 pCntUp = pCntUp->GetUpper();
851 }
852 if ( !bSame )
853 pCnt = nullptr;
854 else if (pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow()) // i73332
855 {
856 pCnt = (*fnNxtPrv)( pCnt );
857 pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel );
858 }
859 }
860
861 if ( bTab )
862 {
863 if ( !pCnt )
864 bEnd = true;
865 else
866 {
867 const SwTabFrame *pTab = pCnt->FindTabFrame();
868 if( !pTab )
869 bEnd = true;
870 else
871 {
872 if ( pTab != pTable )
873 {
874 //The flow leads from one table to the next. The X-value
875 //needs to be corrected by the amount of the offset of
876 //the tables
877 if ( pTable &&
878 !pTab->GetUpper()->IsInTab() &&
879 !pTable->GetUpper()->IsInTab() )
880 nX += pTab->getFrameArea().Left() - pTable->getFrameArea().Left();
881 pTable = pTab;
882 }
883 const SwLayoutFrame *pCell = pCnt->GetUpper();
884 while ( pCell && !pCell->IsCellFrame() )
885 pCell = pCell->GetUpper();
886
887 Point aInsideCell;
888 Point aInsideCnt;
889 if ( pCell )
890 {
891 long nTmpTop = aRectFnSet.GetTop(pCell->getFrameArea());
892 if ( aRectFnSet.IsVert() )
893 {
894 if ( nTmpTop )
895 nTmpTop = aRectFnSet.XInc(nTmpTop, -1);
896
897 aInsideCell = Point( nTmpTop, nX );
898 }
899 else
900 aInsideCell = Point( nX, nTmpTop );
901 }
902
903 long nTmpTop = aRectFnSet.GetTop(pCnt->getFrameArea());
904 if ( aRectFnSet.IsVert() )
905 {
906 if ( nTmpTop )
907 nTmpTop = aRectFnSet.XInc(nTmpTop, -1);
908
909 aInsideCnt = Point( nTmpTop, nX );
910 }
911 else
912 aInsideCnt = Point( nX, nTmpTop );
913
914 if ( pCell && pCell->getFrameArea().IsInside( aInsideCell ) )
915 {
916 bEnd = true;
917 //Get the right Content out of the cell.
918 if ( !pCnt->getFrameArea().IsInside( aInsideCnt ) )
919 {
920 pCnt = pCell->ContainsContent();
921 if ( fnNxtPrv == lcl_GetPrvCnt )
922 while ( pCell->IsAnLower(pCnt->GetNextContentFrame()) )
923 pCnt = pCnt->GetNextContentFrame();
924 }
925 }
926 else if ( pCnt->getFrameArea().IsInside( aInsideCnt ) )
927 bEnd = true;
928 }
929 }
930 if ( !bEnd )
931 {
932 pCnt = (*fnNxtPrv)( pCnt );
933 pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel );
934 }
935 }
936
937 } while ( !bEnd ||
938 (pCnt && pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow()));
939
940 if (pCnt == nullptr)
941 {
942 return false;
943 }
944 if (pCnt->IsTextFrame())
945 {
946 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(pCnt));
947 *pPam->GetPoint() = pFrame->MapViewToModelPos(TextFrameIndex(
948 fnNxtPrv == lcl_GetPrvCnt
949 ? pFrame->GetText().getLength()
950 : 0));
951 }
952 else
953 { // set the Point on the Content-Node
954 assert(pCnt->IsNoTextFrame())(static_cast <bool> (pCnt->IsNoTextFrame()) ? void (
0) : __assert_fail ("pCnt->IsNoTextFrame()", "/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
, 954, __extension__ __PRETTY_FUNCTION__))
;
955 SwContentNode *const pCNd = const_cast<SwContentNode*>(static_cast<SwNoTextFrame const*>(pCnt)->GetNode());
956 pPam->GetPoint()->nNode = *pCNd;
957 if ( fnNxtPrv == lcl_GetPrvCnt )
958 pCNd->MakeEndIndex( &pPam->GetPoint()->nContent );
959 else
960 pCNd->MakeStartIndex( &pPam->GetPoint()->nContent );
961 }
962 return true;
963}
964
965bool SwContentFrame::UnitUp( SwPaM* pPam, const SwTwips, bool bInReadOnly ) const
966{
967 return ::lcl_UpDown( pPam, this, lcl_GetPrvCnt, bInReadOnly );
968}
969
970bool SwContentFrame::UnitDown( SwPaM* pPam, const SwTwips, bool bInReadOnly ) const
971{
972 return ::lcl_UpDown( pPam, this, lcl_GetNxtCnt, bInReadOnly );
973}
974
975/** Returns the number of the current page.
976 *
977 * If the method gets a PaM then the current page is the one in which the PaM sits. Otherwise the
978 * current page is the first one inside the VisibleArea. We only work on available pages!
979 */
980sal_uInt16 SwRootFrame::GetCurrPage( const SwPaM *pActualCursor ) const
981{
982 OSL_ENSURE( pActualCursor, "got no page cursor" )do { if (true && (!(pActualCursor))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "982" ": "), "%s", "got no page cursor"); } } while (false
)
;
983 SwFrame const*const pActFrame = pActualCursor->GetPoint()->nNode.GetNode().
984 GetContentNode()->getLayoutFrame(this,
985 pActualCursor->GetPoint());
986 return pActFrame->FindPageFrame()->GetPhyPageNum();
987}
988
989/** Returns a PaM which sits at the beginning of the requested page.
990 *
991 * Formatting is done as far as necessary.
992 * The PaM sits on the last page, if the page number was chosen too big.
993 *
994 * @return Null, if the operation was not possible.
995 */
996sal_uInt16 SwRootFrame::SetCurrPage( SwCursor* pToSet, sal_uInt16 nPageNum )
997{
998 vcl::RenderContext* pRenderContext = GetCurrShell() ? GetCurrShell()->GetOut() : nullptr;
999 OSL_ENSURE( Lower() && Lower()->IsPageFrame(), "No page available." )do { if (true && (!(Lower() && Lower()->IsPageFrame
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "999" ": "), "%s", "No page available."); } } while (false
)
;
1000
1001 SwPageFrame *pPage = static_cast<SwPageFrame*>(Lower());
1002 bool bEnd =false;
1003 while ( !bEnd && pPage->GetPhyPageNum() != nPageNum )
1004 { if ( pPage->GetNext() )
1005 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1006 else
1007 { //Search the first ContentFrame and format until a new page is started
1008 //or until the ContentFrame are all done.
1009 const SwContentFrame *pContent = pPage->ContainsContent();
1010 while ( pContent && pPage->IsAnLower( pContent ) )
1011 {
1012 pContent->Calc(pRenderContext);
1013 pContent = pContent->GetNextContentFrame();
1014 }
1015 //Either this is a new page or we found the last page.
1016 if ( pPage->GetNext() )
1017 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1018 else
1019 bEnd = true;
1020 }
1021 }
1022 //pPage now points to the 'requested' page. Now we have to create the PaM
1023 //on the beginning of the first ContentFrame in the body-text.
1024 //If this is a footnote-page, the PaM will be set in the first footnote.
1025 const SwContentFrame *pContent = pPage->ContainsContent();
1026 if ( pPage->IsFootnotePage() )
1027 while ( pContent && !pContent->IsInFootnote() )
1028 pContent = pContent->GetNextContentFrame();
1029 else
1030 while ( pContent && !pContent->IsInDocBody() )
1031 pContent = pContent->GetNextContentFrame();
1032 if ( pContent )
1033 {
1034 assert(pContent->IsTextFrame())(static_cast <bool> (pContent->IsTextFrame()) ? void
(0) : __assert_fail ("pContent->IsTextFrame()", "/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
, 1034, __extension__ __PRETTY_FUNCTION__))
;
1035 SwTextFrame const*const pFrame(static_cast<const SwTextFrame*>(pContent));
1036 *pToSet->GetPoint() = pFrame->MapViewToModelPos(pFrame->GetOffset());
1037
1038 SwShellCursor* pSCursor = dynamic_cast<SwShellCursor*>(pToSet);
1039 if( pSCursor )
1040 {
1041 Point &rPt = pSCursor->GetPtPos();
1042 rPt = pContent->getFrameArea().Pos();
1043 rPt += pContent->getFramePrintArea().Pos();
1044 }
1045 return pPage->GetPhyPageNum();
1046 }
1047 return 0;
1048}
1049
1050SwContentFrame *GetFirstSub( const SwLayoutFrame *pLayout )
1051{
1052 return const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(pLayout))->FindFirstBodyContent();
1053}
1054
1055SwContentFrame *GetLastSub( const SwLayoutFrame *pLayout )
1056{
1057 return const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(pLayout))->FindLastBodyContent();
1058}
1059
1060SwLayoutFrame *GetNextFrame( const SwLayoutFrame *pFrame )
1061{
1062 SwLayoutFrame *pNext =
1063 (pFrame->GetNext() && pFrame->GetNext()->IsLayoutFrame()) ?
1064 const_cast<SwLayoutFrame*>(static_cast<const SwLayoutFrame*>(pFrame->GetNext())) : nullptr;
1065 // #i39402# in case of an empty page
1066 if(pNext && !pNext->ContainsContent())
1067 pNext = (pNext->GetNext() && pNext->GetNext()->IsLayoutFrame()) ?
1068 static_cast<SwLayoutFrame*>(pNext->GetNext()) : nullptr;
1069 return pNext;
1070}
1071
1072SwLayoutFrame *GetThisFrame( const SwLayoutFrame *pFrame )
1073{
1074 return const_cast<SwLayoutFrame*>(pFrame);
1075}
1076
1077SwLayoutFrame *GetPrevFrame( const SwLayoutFrame *pFrame )
1078{
1079 SwLayoutFrame *pPrev =
1080 (pFrame->GetPrev() && pFrame->GetPrev()->IsLayoutFrame()) ?
1081 const_cast<SwLayoutFrame*>(static_cast<const SwLayoutFrame*>(pFrame->GetPrev())) : nullptr;
1082 // #i39402# in case of an empty page
1083 if(pPrev && !pPrev->ContainsContent())
1084 pPrev = (pPrev->GetPrev() && pPrev->GetPrev()->IsLayoutFrame()) ?
1085 static_cast<SwLayoutFrame*>(pPrev->GetPrev()) : nullptr;
1086 return pPrev;
1087}
1088
1089/**
1090 * Returns the first/last Contentframe (controlled using the parameter fnPosPage)
1091 * of the current/previous/next page (controlled using the parameter fnWhichPage).
1092 */
1093bool GetFrameInPage( const SwContentFrame *pCnt, SwWhichPage fnWhichPage,
1094 SwPosPage fnPosPage, SwPaM *pPam )
1095{
1096 //First find the requested page, at first the current, then the one which
1097 //was requests through fnWichPage.
1098 const SwLayoutFrame *pLayoutFrame = pCnt->FindPageFrame();
1099 if ( !pLayoutFrame || (nullptr == (pLayoutFrame = (*fnWhichPage)(pLayoutFrame))) )
1100 return false;
1101
1102 //Now the desired ContentFrame below the page
1103 pCnt = (*fnPosPage)(pLayoutFrame);
1104 if( nullptr == pCnt )
1105 return false;
1106 else
1107 {
1108 // repeated headlines in tables
1109 if ( pCnt->IsInTab() && fnPosPage == GetFirstSub )
1110 {
1111 const SwTabFrame* pTab = pCnt->FindTabFrame();
1112 if ( pTab->IsFollow() )
1113 {
1114 if ( pTab->IsInHeadline( *pCnt ) )
1115 {
1116 SwLayoutFrame* pRow = pTab->GetFirstNonHeadlineRow();
1117 if ( pRow )
1118 {
1119 // We are in the first line of a follow table
1120 // with repeated headings.
1121 // To actually make a "real" move we take the first content
1122 // of the next row
1123 pCnt = pRow->ContainsContent();
1124 if ( ! pCnt )
1125 return false;
1126 }
1127 }
1128 }
1129 }
1130
1131 assert(pCnt->IsTextFrame())(static_cast <bool> (pCnt->IsTextFrame()) ? void (0)
: __assert_fail ("pCnt->IsTextFrame()", "/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
, 1131, __extension__ __PRETTY_FUNCTION__))
;
1132 SwTextFrame const*const pFrame(static_cast<const SwTextFrame*>(pCnt));
1133 TextFrameIndex const nIdx((fnPosPage == GetFirstSub)
1134 ? pFrame->GetOffset()
1135 : (pFrame->GetFollow())
1136 ? pFrame->GetFollow()->GetOffset() - TextFrameIndex(1)
1137 : TextFrameIndex(pFrame->GetText().getLength()));
1138 *pPam->GetPoint() = pFrame->MapViewToModelPos(nIdx);
1139 return true;
1140 }
1141}
1142
1143static sal_uInt64 CalcDiff(const Point &rPt1, const Point &rPt2)
1144{
1145 //Calculate the distance between the two points.
1146 //'delta' X^2 + 'delta'Y^2 = 'distance'^2
1147 sal_uInt64 dX = std::max( rPt1.X(), rPt2.X() ) -
1148 std::min( rPt1.X(), rPt2.X() ),
1149 dY = std::max( rPt1.Y(), rPt2.Y() ) -
1150 std::min( rPt1.Y(), rPt2.Y() );
1151 return (dX * dX) + (dY * dY);
1152}
1153
1154/** Check if the point lies inside the page part in which also the ContentFrame lies.
1155 *
1156 * In this context header, page body, footer and footnote-container count as page part.
1157 * This will suit the purpose that the ContentFrame which lies in the "right" page part will be
1158 * accepted instead of one which doesn't lie there although his distance to the point is shorter.
1159 */
1160static const SwLayoutFrame* lcl_Inside( const SwContentFrame *pCnt, Point const & rPt )
1161{
1162 const SwLayoutFrame* pUp = pCnt->GetUpper();
1163 while( pUp )
1164 {
1165 if( pUp->IsPageBodyFrame() || pUp->IsFooterFrame() || pUp->IsHeaderFrame() )
1166 {
1167 if( rPt.Y() >= pUp->getFrameArea().Top() && rPt.Y() <= pUp->getFrameArea().Bottom() )
1168 return pUp;
1169 return nullptr;
1170 }
1171 if( pUp->IsFootnoteContFrame() )
1172 return pUp->getFrameArea().IsInside( rPt ) ? pUp : nullptr;
1173 pUp = pUp->GetUpper();
1174 }
1175 return nullptr;
1176}
1177
1178/** Search for the nearest Content to pass.
1179 *
1180 * Considers the previous, the current and the next page.
1181 * If no content is found, the area gets expanded until one is found.
1182 *
1183 * @return The 'semantically correct' position inside the PrtArea of the found ContentFrame.
1184 */
1185const SwContentFrame *SwLayoutFrame::GetContentPos( Point& rPoint,
1186 const bool bDontLeave,
1187 const bool bBodyOnly,
1188 SwCursorMoveState *pCMS,
1189 const bool bDefaultExpand ) const
1190{
1191 //Determine the first ContentFrame.
1192 const SwLayoutFrame *pStart = (!bDontLeave && bDefaultExpand && GetPrev()) ?
1193 static_cast<const SwLayoutFrame*>(GetPrev()) : this;
1194 const SwContentFrame *pContent = pStart->ContainsContent();
1195
1196 if ( !pContent && (GetPrev() && !bDontLeave) )
1197 pContent = ContainsContent();
1198
1199 if ( bBodyOnly && pContent && !pContent->IsInDocBody() )
1200 while ( pContent && !pContent->IsInDocBody() )
1201 pContent = pContent->GetNextContentFrame();
1202
1203 const SwContentFrame *pActual= pContent;
1204 const SwLayoutFrame *pInside = nullptr;
1205 sal_uInt16 nMaxPage = GetPhyPageNum() + (bDefaultExpand ? 1 : 0);
1206 Point aPoint = rPoint;
1207 sal_uInt64 nDistance = SAL_MAX_UINT64((sal_uInt64) 0xFFFFFFFFFFFFFFFFul);
1208
1209 while ( true ) //A loop to be sure we always find one.
1210 {
1211 while ( pContent &&
1212 ((!bDontLeave || IsAnLower( pContent )) &&
1213 (pContent->GetPhyPageNum() <= nMaxPage)) )
1214 {
1215 if ( pContent->getFrameArea().Width() &&
1216 ( !bBodyOnly || pContent->IsInDocBody() ) )
1217 {
1218 //If the Content lies in a protected area (cell, Footnote, section),
1219 //we search the next Content which is not protected.
1220 const SwContentFrame *pComp = pContent;
1221 pContent = ::lcl_MissProtectedFrames( pContent, lcl_GetNxtCnt, false,
1222 pCMS && pCMS->m_bSetInReadOnly, false );
1223 if ( pComp != pContent )
1224 continue;
1225
1226 if ( !pContent->IsTextFrame() || !static_cast<const SwTextFrame*>(pContent)->IsHiddenNow() )
1227 {
1228 SwRect aContentFrame( pContent->UnionFrame() );
1229 if ( aContentFrame.IsInside( rPoint ) )
1230 {
1231 pActual = pContent;
1232 aPoint = rPoint;
1233 break;
1234 }
1235 //The distance from rPoint to the nearest Point of pContent
1236 //will now be calculated.
1237 Point aContentPoint( rPoint );
1238
1239 //First set the vertical position
1240 if ( aContentFrame.Top() > aContentPoint.Y() )
1241 aContentPoint.setY( aContentFrame.Top() );
1242 else if ( aContentFrame.Bottom() < aContentPoint.Y() )
1243 aContentPoint.setY( aContentFrame.Bottom() );
1244
1245 //Now the horizontal position
1246 if ( aContentFrame.Left() > aContentPoint.X() )
1247 aContentPoint.setX( aContentFrame.Left() );
1248 else if ( aContentFrame.Right() < aContentPoint.X() )
1249 aContentPoint.setX( aContentFrame.Right() );
1250
1251 // pInside is a page area in which the point lies. As soon
1252 // as pInside != 0 only frames are accepted which are
1253 // placed inside.
1254 if( !pInside || ( pInside->IsAnLower( pContent ) &&
1255 ( !pContent->IsInFootnote() || pInside->IsFootnoteContFrame() ) ) )
1256 {
1257 const sal_uInt64 nDiff = ::CalcDiff(aContentPoint, rPoint);
1258 bool bBetter = nDiff < nDistance; // This one is nearer
1259 if( !pInside )
1260 {
1261 pInside = lcl_Inside( pContent, rPoint );
1262 if( pInside ) // In the "right" page area
1263 bBetter = true;
1264 }
1265 if( bBetter )
1266 {
1267 aPoint = aContentPoint;
1268 nDistance = nDiff;
1269 pActual = pContent;
1270 }
1271 }
1272 }
1273 }
1274 pContent = pContent->GetNextContentFrame();
1275 if ( bBodyOnly )
1276 while ( pContent && !pContent->IsInDocBody() )
1277 pContent = pContent->GetNextContentFrame();
1278 }
1279 if ( !pActual )
1280 { //If we not yet found one we have to expand the searched
1281 //area, sometime we will find one!
1282 //MA 1997-01-09: Opt for many empty pages - if we only search inside
1283 //the body, we can expand the searched area sufficiently in one step.
1284 if ( bBodyOnly )
1285 {
1286 while ( !pContent && pStart->GetPrev() )
1287 {
1288 ++nMaxPage;
1289 if( !pStart->GetPrev()->IsLayoutFrame() )
1290 return nullptr;
1291 pStart = static_cast<const SwLayoutFrame*>(pStart->GetPrev());
1292 pContent = pStart->IsInDocBody()
1293 ? pStart->ContainsContent()
1294 : pStart->FindPageFrame()->FindFirstBodyContent();
1295 }
1296 if ( !pContent ) // Somewhere down the road we have to start with one!
1297 {
1298 pContent = pStart->FindPageFrame()->GetUpper()->ContainsContent();
1299 while ( pContent && !pContent->IsInDocBody() )
1300 pContent = pContent->GetNextContentFrame();
1301 if ( !pContent )
1302 return nullptr; // There is no document content yet!
1303 }
1304 }
1305 else
1306 {
1307 ++nMaxPage;
1308 if ( pStart->GetPrev() )
1309 {
1310 if( !pStart->GetPrev()->IsLayoutFrame() )
1311 return nullptr;
1312 pStart = static_cast<const SwLayoutFrame*>(pStart->GetPrev());
1313 pContent = pStart->ContainsContent();
1314 }
1315 else // Somewhere down the road we have to start with one!
1316 pContent = pStart->FindPageFrame()->GetUpper()->ContainsContent();
1317 }
1318 pActual = pContent;
1319 }
1320 else
1321 break;
1322 }
1323
1324 OSL_ENSURE( pActual, "no Content found." )do { if (true && (!(pActual))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "1324" ": "), "%s", "no Content found."); } } while (false
)
;
1325 OSL_ENSURE( !bBodyOnly || pActual->IsInDocBody(), "Content not in Body." )do { if (true && (!(!bBodyOnly || pActual->IsInDocBody
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "1325" ": "), "%s", "Content not in Body."); } } while (
false)
;
1326
1327 //Special case for selecting tables not in repeated TableHeadlines.
1328 if ( pActual->IsInTab() && pCMS && pCMS->m_eState == CursorMoveState::TableSel )
1329 {
1330 const SwTabFrame *pTab = pActual->FindTabFrame();
1331 if ( pTab->IsFollow() && pTab->IsInHeadline( *pActual ) )
1332 {
1333 pCMS->m_bStop = true;
1334 return nullptr;
1335 }
1336 }
1337
1338 //A small correction at the first/last
1339 Size aActualSize( pActual->getFramePrintArea().SSize() );
1340 if ( aActualSize.Height() > pActual->GetUpper()->getFramePrintArea().Height() )
1341 aActualSize.setHeight( pActual->GetUpper()->getFramePrintArea().Height() );
1342
1343 SwRectFnSet aRectFnSet(pActual);
1344 if ( !pActual->GetPrev() &&
1345 aRectFnSet.YDiff( aRectFnSet.GetPrtTop(*pActual),
1346 aRectFnSet.IsVert() ? rPoint.X() : rPoint.Y() ) > 0 )
1347 {
1348 aPoint.setY( pActual->getFrameArea().Top() + pActual->getFramePrintArea().Top() );
1349 aPoint.setX( pActual->getFrameArea().Left() +
1350 ( pActual->IsRightToLeft() || aRectFnSet.IsVert() ?
1351 pActual->getFramePrintArea().Right() :
1352 pActual->getFramePrintArea().Left() ) );
1353 }
1354 else if ( !pActual->GetNext() &&
1355 aRectFnSet.YDiff( aRectFnSet.GetPrtBottom(*pActual),
1356 aRectFnSet.IsVert() ? rPoint.X() : rPoint.Y() ) < 0 )
1357 {
1358 aPoint.setY( pActual->getFrameArea().Top() + pActual->getFramePrintArea().Bottom() );
1359 aPoint.setX( pActual->getFrameArea().Left() +
1360 ( pActual->IsRightToLeft() || aRectFnSet.IsVert() ?
1361 pActual->getFramePrintArea().Left() :
1362 pActual->getFramePrintArea().Right() ) );
1363 }
1364
1365 //Bring the Point into the PrtArea
1366 const SwRect aRect( pActual->getFrameArea().Pos() + pActual->getFramePrintArea().Pos(),
1367 aActualSize );
1368 if ( aPoint.Y() < aRect.Top() )
1369 aPoint.setY( aRect.Top() );
1370 else if ( aPoint.Y() > aRect.Bottom() )
1371 aPoint.setY( aRect.Bottom() );
1372 if ( aPoint.X() < aRect.Left() )
1373 aPoint.setX( aRect.Left() );
1374 else if ( aPoint.X() > aRect.Right() )
1375 aPoint.setX( aRect.Right() );
1376 rPoint = aPoint;
1377 return pActual;
1378}
1379
1380/** Same as SwLayoutFrame::GetContentPos(). Specialized for fields and border. */
1381void SwPageFrame::GetContentPosition( const Point &rPt, SwPosition &rPos ) const
1382{
1383 //Determine the first ContentFrame.
1384 const SwContentFrame *pContent = ContainsContent();
1385 if ( pContent )
1386 {
1387 //Look back one more (if possible).
1388 const SwContentFrame *pTmp = pContent->GetPrevContentFrame();
1389 while ( pTmp && !pTmp->IsInDocBody() )
1390 pTmp = pTmp->GetPrevContentFrame();
1391 if ( pTmp )
1392 pContent = pTmp;
1393 }
1394 else
1395 pContent = GetUpper()->ContainsContent();
1396
1397 const SwContentFrame *pAct = pContent;
1398 Point aAct = rPt;
1399 sal_uInt64 nDist = SAL_MAX_UINT64((sal_uInt64) 0xFFFFFFFFFFFFFFFFul);
1400
1401 while ( pContent )
1402 {
1403 SwRect aContentFrame( pContent->UnionFrame() );
1404 if ( aContentFrame.IsInside( rPt ) )
1405 {
1406 //This is the nearest one.
1407 pAct = pContent;
1408 break;
1409 }
1410
1411 //Calculate the distance from rPt to the nearest point of pContent.
1412 Point aPoint( rPt );
1413
1414 //Calculate the vertical position first
1415 if ( aContentFrame.Top() > rPt.Y() )
1416 aPoint.setY( aContentFrame.Top() );
1417 else if ( aContentFrame.Bottom() < rPt.Y() )
1418 aPoint.setY( aContentFrame.Bottom() );
1419
1420 //And now the horizontal position
1421 if ( aContentFrame.Left() > rPt.X() )
1422 aPoint.setX( aContentFrame.Left() );
1423 else if ( aContentFrame.Right() < rPt.X() )
1424 aPoint.setX( aContentFrame.Right() );
1425
1426 const sal_uInt64 nDiff = ::CalcDiff( aPoint, rPt );
1427 if ( nDiff < nDist )
1428 {
1429 aAct = aPoint;
1430 nDist = nDiff;
1431 pAct = pContent;
1432 }
1433 else if ( aContentFrame.Top() > getFrameArea().Bottom() )
1434 //In terms of fields, it's not possible to be closer any more!
1435 break;
1436
1437 pContent = pContent->GetNextContentFrame();
1438 while ( pContent && !pContent->IsInDocBody() )
1439 pContent = pContent->GetNextContentFrame();
1440 }
1441
1442 //Bring the point into the PrtArea.
1443 const SwRect aRect( pAct->getFrameArea().Pos() + pAct->getFramePrintArea().Pos(), pAct->getFramePrintArea().SSize() );
1444 if ( aAct.Y() < aRect.Top() )
1445 aAct.setY( aRect.Top() );
1446 else if ( aAct.Y() > aRect.Bottom() )
1447 aAct.setY( aRect.Bottom() );
1448 if ( aAct.X() < aRect.Left() )
1449 aAct.setX( aRect.Left() );
1450 else if ( aAct.X() > aRect.Right() )
1451 aAct.setX( aRect.Right() );
1452
1453 if (!pAct->isFrameAreaDefinitionValid() ||
1454 (pAct->IsTextFrame() && !static_cast<SwTextFrame const*>(pAct)->HasPara()))
1455 {
1456 // ContentFrame not formatted -> always on node-beginning
1457 // tdf#100635 also if the SwTextFrame would require reformatting,
1458 // which is unwanted in case this is called from text formatting code
1459 rPos = static_cast<SwTextFrame const*>(pAct)->MapViewToModelPos(TextFrameIndex(0));
1460 }
1461 else
1462 {
1463 SwCursorMoveState aTmpState( CursorMoveState::SetOnlyText );
1464 pAct->GetModelPositionForViewPoint( &rPos, aAct, &aTmpState );
1465 }
1466}
1467
1468/** Search the nearest Content to the passed point.
1469 *
1470 * Only search inside the BodyText.
1471 * @note Only the nearest vertically one will be searched.
1472 * @note JP 11.10.2001: only in tables we try to find the right column - Bug 72294
1473 */
1474Point SwRootFrame::GetNextPrevContentPos( const Point& rPoint, bool bNext ) const
1475{
1476 vcl::RenderContext* pRenderContext = GetCurrShell() ? GetCurrShell()->GetOut() : nullptr;
1
Assuming the condition is false
2
'?' condition is false
1477 // #123110# - disable creation of an action by a callback
1478 // event during processing of this method. Needed because formatting is
1479 // triggered by this method.
1480 DisableCallbackAction aDisableCallbackAction(const_cast<SwRootFrame&>(*this));
1481 //Search the first ContentFrame and his successor in the body area.
1482 //To be efficient (and not formatting too much) we'll start at the correct
1483 //page.
1484 const SwLayoutFrame *pPage = static_cast<const SwLayoutFrame*>(Lower());
3
'pPage' initialized here
1485 if( pPage )
4
Assuming 'pPage' is null
5
Taking false branch
1486 while( pPage->GetNext() && pPage->getFrameArea().Bottom() < rPoint.Y() )
1487 pPage = static_cast<const SwLayoutFrame*>(pPage->GetNext());
1488
1489 const SwContentFrame *pCnt = pPage
5.1
'pPage' is null
? pPage->ContainsContent() : ContainsContent();
6
'?' condition is false
1490 while ( pCnt && !pCnt->IsInDocBody() )
7
Assuming 'pCnt' is non-null
8
Assuming the condition is false
9
Loop condition is false. Execution continues on line 1493
1491 pCnt = pCnt->GetNextContentFrame();
1492
1493 if ( !pCnt
9.1
'pCnt' is non-null
)
10
Taking false branch
1494 return Point( 0, 0 );
1495
1496 pCnt->Calc(pRenderContext);
1497 if( !bNext )
11
Assuming 'bNext' is false
12
Taking true branch
1498 {
1499 // As long as the point lies before the first ContentFrame and there are
1500 // still precedent pages I'll go to the next page.
1501 while ( rPoint.Y() < pCnt->getFrameArea().Top() && pPage->GetPrev() )
13
Assuming the condition is true
14
Called C++ object pointer is null
1502 {
1503 pPage = static_cast<const SwLayoutFrame*>(pPage->GetPrev());
1504 pCnt = pPage->ContainsContent();
1505 while ( !pCnt )
1506 {
1507 pPage = static_cast<const SwLayoutFrame*>(pPage->GetPrev());
1508 if ( pPage )
1509 pCnt = pPage->ContainsContent();
1510 else
1511 return ContainsContent()->UnionFrame().Pos();
1512 }
1513 pCnt->Calc(pRenderContext);
1514 }
1515 }
1516
1517 //Does the point lie above the first ContentFrame?
1518 if ( rPoint.Y() < pCnt->getFrameArea().Top() && !lcl_IsInRepeatedHeadline( pCnt ) )
1519 return pCnt->UnionFrame().Pos();
1520
1521 Point aRet(0, 0);
1522 do
1523 {
1524 //Does the point lie in the current ContentFrame?
1525 SwRect aContentFrame( pCnt->UnionFrame() );
1526 if ( aContentFrame.IsInside( rPoint ) && !lcl_IsInRepeatedHeadline( pCnt ))
1527 {
1528 aRet = rPoint;
1529 break;
1530 }
1531
1532 //Is the current one the last ContentFrame?
1533 //If the next ContentFrame lies behind the point, then the current on is the
1534 //one we searched.
1535 const SwContentFrame *pNxt = pCnt->GetNextContentFrame();
1536 while ( pNxt && !pNxt->IsInDocBody() )
1537 pNxt = pNxt->GetNextContentFrame();
1538
1539 //Does the point lie behind the last ContentFrame?
1540 if ( !pNxt )
1541 {
1542 aRet = Point( aContentFrame.Right(), aContentFrame.Bottom() );
1543 break;
1544 }
1545
1546 //If the next ContentFrame lies behind the point then it is the one we
1547 //searched.
1548 const SwTabFrame* pTFrame;
1549 pNxt->Calc(pRenderContext);
1550 if( pNxt->getFrameArea().Top() > rPoint.Y() &&
1551 !lcl_IsInRepeatedHeadline( pCnt, &pTFrame ) &&
1552 ( !pTFrame || pNxt->getFrameArea().Left() > rPoint.X() ))
1553 {
1554 if (bNext)
1555 aRet = pNxt->getFrameArea().Pos();
1556 else
1557 aRet = Point( aContentFrame.Right(), aContentFrame.Bottom() );
1558 break;
1559 }
1560 pCnt = pNxt;
1561 }
1562 while (pCnt);
1563 return aRet;
1564}
1565
1566/** Returns the absolute document position of the desired page.
1567 *
1568 * Formatting is done only as far as needed and only if bFormat=true.
1569 * Pos is set to the one of the last page, if the page number was chosen too big.
1570 *
1571 * @return Null, if the operation failed.
1572 */
1573Point SwRootFrame::GetPagePos( sal_uInt16 nPageNum ) const
1574{
1575 OSL_ENSURE( Lower() && Lower()->IsPageFrame(), "No page available." )do { if (true && (!(Lower() && Lower()->IsPageFrame
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "1575" ": "), "%s", "No page available."); } } while (false
)
;
1576
1577 const SwPageFrame *pPage = static_cast<const SwPageFrame*>(Lower());
1578 while ( true )
1579 {
1580 if ( pPage->GetPhyPageNum() >= nPageNum || !pPage->GetNext() )
1581 break;
1582 pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
1583 }
1584 return pPage->getFrameArea().Pos();
1585}
1586
1587/** get page frame by physical page number
1588 *
1589 * @return pointer to the page frame with the given physical page number
1590 */
1591SwPageFrame* SwRootFrame::GetPageByPageNum( sal_uInt16 _nPageNum ) const
1592{
1593 const SwPageFrame* pPageFrame = static_cast<const SwPageFrame*>( Lower() );
1594 while ( pPageFrame && pPageFrame->GetPhyPageNum() < _nPageNum )
1595 {
1596 pPageFrame = static_cast<const SwPageFrame*>( pPageFrame->GetNext() );
1597 }
1598
1599 if ( pPageFrame && pPageFrame->GetPhyPageNum() == _nPageNum )
1600 {
1601 return const_cast<SwPageFrame*>( pPageFrame );
1602 }
1603 else
1604 {
1605 return nullptr;
1606 }
1607}
1608
1609/**
1610 * @return true, when the given physical pagenumber doesn't exist or this page is an empty page.
1611 */
1612bool SwRootFrame::IsDummyPage( sal_uInt16 nPageNum ) const
1613{
1614 if( !Lower() || !nPageNum || nPageNum > GetPageNum() )
1615 return true;
1616
1617 const SwPageFrame *pPage = static_cast<const SwPageFrame*>(Lower());
1618 while( pPage && nPageNum < pPage->GetPhyPageNum() )
1619 pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
1620 return !pPage || pPage->IsEmptyPage();
1621}
1622
1623/** Is the Frame or rather the Section in which it lies protected?
1624 *
1625 * Also Fly in Fly in ... and Footnotes
1626 */
1627bool SwFrame::IsProtected() const
1628{
1629 if (IsTextFrame())
1630 {
1631 const SwDoc *pDoc = &static_cast<const SwTextFrame*>(this)->GetDoc();
1632 bool isFormProtected=pDoc->GetDocumentSettingManager().get(DocumentSettingId::PROTECT_FORM );
1633 if (isFormProtected)
1634 {
1635 return false; // TODO a hack for now, well deal with it later, I we return true here we have a "double" locking
1636 }
1637 }
1638 //The Frame can be protected in borders, cells or sections.
1639 //Also goes up FlyFrames recursive and from footnote to anchor.
1640 const SwFrame *pFrame = this;
1641 do
1642 {
1643 if (pFrame->IsTextFrame())
1644 { // sw_redlinehide: redlines can't overlap section nodes, so any node will do
1645 if (static_cast<SwTextFrame const*>(pFrame)->GetTextNodeFirst()->IsInProtectSect())
1646 {
1647 return true;
1648 }
1649 }
1650 else if ( pFrame->IsContentFrame() )
1651 {
1652 assert(pFrame->IsNoTextFrame())(static_cast <bool> (pFrame->IsNoTextFrame()) ? void
(0) : __assert_fail ("pFrame->IsNoTextFrame()", "/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
, 1652, __extension__ __PRETTY_FUNCTION__))
;
1653 if (static_cast<const SwNoTextFrame*>(pFrame)->GetNode() &&
1654 static_cast<const SwNoTextFrame*>(pFrame)->GetNode()->IsInProtectSect())
1655 {
1656 return true;
1657 }
1658 }
1659 else
1660 {
1661 if ( static_cast<const SwLayoutFrame*>(pFrame)->GetFormat() &&
1662 static_cast<const SwLayoutFrame*>(pFrame)->GetFormat()->
1663 GetProtect().IsContentProtected() )
1664 return true;
1665 if ( pFrame->IsCoveredCell() )
1666 return true;
1667 }
1668 if ( pFrame->IsFlyFrame() )
1669 {
1670 //In a chain the protection of the content can be specified by the
1671 //master of the chain.
1672 if ( static_cast<const SwFlyFrame*>(pFrame)->GetPrevLink() )
1673 {
1674 const SwFlyFrame *pMaster = static_cast<const SwFlyFrame*>(pFrame);
1675 do
1676 { pMaster = pMaster->GetPrevLink();
1677 } while ( pMaster->GetPrevLink() );
1678 if ( pMaster->IsProtected() )
1679 return true;
1680 }
1681 pFrame = static_cast<const SwFlyFrame*>(pFrame)->GetAnchorFrame();
1682 }
1683 else if ( pFrame->IsFootnoteFrame() )
1684 pFrame = static_cast<const SwFootnoteFrame*>(pFrame)->GetRef();
1685 else
1686 pFrame = pFrame->GetUpper();
1687
1688 } while ( pFrame );
1689
1690 return false;
1691}
1692
1693/** @return the physical page number */
1694sal_uInt16 SwFrame::GetPhyPageNum() const
1695{
1696 const SwPageFrame *pPage = FindPageFrame();
1697 return pPage ? pPage->GetPhyPageNum() : 0;
1698}
1699
1700/** Decides if the page want to be a right page or not.
1701 *
1702 * If the first content of the page has a page descriptor, we take the follow
1703 * of the page descriptor of the last not empty page. If this descriptor allows
1704 * only right(left) pages and the page isn't an empty page then it wants to be
1705 * such right(left) page. If the descriptor allows right and left pages, we
1706 * look for a number offset in the first content. If there is one, odd number
1707 * results right pages (or left pages if document starts with even number),
1708 * even number results left pages (or right pages if document starts with even
1709 * number).
1710 * If there is no number offset, we take the physical page number instead,
1711 * but a previous empty page doesn't count.
1712 */
1713bool SwFrame::WannaRightPage() const
1714{
1715 const SwPageFrame *pPage = FindPageFrame();
1716 if ( !pPage || !pPage->GetUpper() )
1717 return true;
1718
1719 const SwFrame *pFlow = pPage->FindFirstBodyContent();
1720 const SwPageDesc *pDesc = nullptr;
1721 ::std::optional<sal_uInt16> oPgNum;
1722 if ( pFlow )
1723 {
1724 if ( pFlow->IsInTab() )
1725 pFlow = pFlow->FindTabFrame();
1726 const SwFlowFrame *pTmp = SwFlowFrame::CastFlowFrame( pFlow );
1727 if ( !pTmp->IsFollow() )
1728 {
1729 const SwFormatPageDesc& rPgDesc = pFlow->GetPageDescItem();
1730 pDesc = rPgDesc.GetPageDesc();
1731 oPgNum = rPgDesc.GetNumOffset();
1732 }
1733 }
1734 if ( !pDesc )
1735 {
1736 SwPageFrame *pPrv = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(pPage->GetPrev()));
1737 if( pPrv && pPrv->IsEmptyPage() )
1738 pPrv = static_cast<SwPageFrame*>(pPrv->GetPrev());
1739 if( pPrv )
1740 pDesc = pPrv->GetPageDesc()->GetFollow();
1741 else
1742 {
1743 const SwDoc* pDoc = pPage->GetFormat()->GetDoc();
1744 pDesc = &pDoc->GetPageDesc( 0 );
1745 }
1746 }
1747 OSL_ENSURE( pDesc, "No pagedescriptor" )do { if (true && (!(pDesc))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "1747" ": "), "%s", "No pagedescriptor"); } } while (false
)
;
1748 bool isRightPage;
1749 if( oPgNum )
1750 isRightPage = sw::IsRightPageByNumber(*mpRoot, *oPgNum);
1751 else
1752 {
1753 isRightPage = pPage->OnRightPage();
1754 if( pPage->GetPrev() && static_cast<const SwPageFrame*>(pPage->GetPrev())->IsEmptyPage() )
1755 isRightPage = !isRightPage;
1756 }
1757 if( !pPage->IsEmptyPage() )
1758 {
1759 if( !pDesc->GetRightFormat() )
1760 isRightPage = false;
1761 else if( !pDesc->GetLeftFormat() )
1762 isRightPage = true;
1763 }
1764 return isRightPage;
1765}
1766
1767bool SwFrame::OnFirstPage() const
1768{
1769 bool bRet = false;
1770 const SwPageFrame *pPage = FindPageFrame();
1771
1772 if (pPage)
1773 {
1774 const SwPageFrame* pPrevFrame = dynamic_cast<const SwPageFrame*>(pPage->GetPrev());
1775 if (pPrevFrame)
1776 {
1777 // first page of layout may be empty page, but only if it starts with "Left Page" style
1778 const SwPageDesc* pDesc = pPage->GetPageDesc();
1779 bRet = pPrevFrame->GetPageDesc() != pDesc;
1780 }
1781 else
1782 bRet = true;
1783 }
1784 return bRet;
1785}
1786
1787void SwFrame::Calc(vcl::RenderContext* pRenderContext) const
1788{
1789 if ( !isFrameAreaPositionValid() || !isFramePrintAreaValid() || !isFrameAreaSizeValid() )
1790 {
1791 const_cast<SwFrame*>(this)->PrepareMake(pRenderContext);
1792 }
1793}
1794
1795Point SwFrame::GetRelPos() const
1796{
1797 Point aRet( getFrameArea().Pos() );
1798 // here we cast since SwLayoutFrame is declared only as forwarded
1799 aRet -= GetUpper()->getFramePrintArea().Pos();
1800 aRet -= GetUpper()->getFrameArea().Pos();
1801 return aRet;
1802}
1803
1804/** @return the virtual page number with the offset. */
1805sal_uInt16 SwFrame::GetVirtPageNum() const
1806{
1807 const SwPageFrame *pPage = FindPageFrame();
1808 if ( !pPage || !pPage->GetUpper() )
1809 return 0;
1810
1811 sal_uInt16 nPhyPage = pPage->GetPhyPageNum();
1812 if ( !static_cast<const SwRootFrame*>(pPage->GetUpper())->IsVirtPageNum() )
1813 return nPhyPage;
1814
1815 //Search the nearest section using the virtual page number.
1816 //Because searching backwards needs a lot of time we search specific using
1817 //the dependencies. From the PageDescs we get the attributes and from the
1818 //attributes we get the sections.
1819 const SwPageFrame *pVirtPage = nullptr;
1820 const SwFrame *pFrame = nullptr;
1821 const SfxItemPool &rPool = pPage->GetFormat()->GetDoc()->GetAttrPool();
1822 for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(RES_PAGEDESC))
1823 {
1824 const SwFormatPageDesc *pDesc = dynamic_cast<const SwFormatPageDesc*>(pItem);
1825 if ( !pDesc )
1826 continue;
1827
1828 if ( pDesc->GetNumOffset() && pDesc->GetDefinedIn() )
1829 {
1830 const SwModify *pMod = pDesc->GetDefinedIn();
1831 SwVirtPageNumInfo aInfo( pPage );
1832 pMod->GetInfo( aInfo );
1833 if ( aInfo.GetPage() )
1834 {
1835 if( !pVirtPage || aInfo.GetPage()->GetPhyPageNum() > pVirtPage->GetPhyPageNum() )
1836 {
1837 pVirtPage = aInfo.GetPage();
1838 pFrame = aInfo.GetFrame();
1839 }
1840 }
1841 }
1842 }
1843 if ( pFrame )
1844 {
1845 ::std::optional<sal_uInt16> oNumOffset = pFrame->GetPageDescItem().GetNumOffset();
1846 if (oNumOffset)
1847 {
1848 return nPhyPage - pFrame->GetPhyPageNum() + *oNumOffset;
1849 }
1850 else
1851 {
1852 return nPhyPage - pFrame->GetPhyPageNum();
1853 }
1854 }
1855 return nPhyPage;
1856}
1857
1858/** Determines and sets those cells which are enclosed by the selection. */
1859bool SwRootFrame::MakeTableCursors( SwTableCursor& rTableCursor )
1860{
1861 //Find Union-Rects and tables (Follows) of the selection.
1862 OSL_ENSURE( rTableCursor.GetContentNode() && rTableCursor.GetContentNode( false ),do { if (true && (!(rTableCursor.GetContentNode() &&
rTableCursor.GetContentNode( false )))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "1863" ": "), "%s", "Tabselection not on Cnt."); } } while
(false)
1863 "Tabselection not on Cnt." )do { if (true && (!(rTableCursor.GetContentNode() &&
rTableCursor.GetContentNode( false )))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "1863" ": "), "%s", "Tabselection not on Cnt."); } } while
(false)
;
1864
1865 bool bRet = false;
1866
1867 // For new table models there's no need to ask the layout...
1868 if( rTableCursor.NewTableSelection() )
1869 return true;
1870
1871 Point aPtPt, aMkPt;
1872 {
1873 SwShellCursor* pShCursor = dynamic_cast<SwShellCursor*>(&rTableCursor);
1874
1875 if( pShCursor )
1876 {
1877 aPtPt = pShCursor->GetPtPos();
1878 aMkPt = pShCursor->GetMkPos();
1879 }
1880 }
1881
1882 // #151012# Made code robust here
1883 const SwContentNode* pTmpStartNode = rTableCursor.GetContentNode();
1884 const SwContentNode* pTmpEndNode = rTableCursor.GetContentNode(false);
1885
1886 std::pair<Point, bool> tmp(aPtPt, false);
1887 const SwFrame *const pTmpStartFrame = pTmpStartNode ? pTmpStartNode->getLayoutFrame(this, nullptr, &tmp) : nullptr;
1888 tmp.first = aMkPt;
1889 const SwFrame *const pTmpEndFrame = pTmpEndNode ? pTmpEndNode->getLayoutFrame(this, nullptr, &tmp) : nullptr;
1890
1891 const SwLayoutFrame* pStart = pTmpStartFrame ? pTmpStartFrame->GetUpper() : nullptr;
1892 const SwLayoutFrame* pEnd = pTmpEndFrame ? pTmpEndFrame->GetUpper() : nullptr;
1893
1894 OSL_ENSURE( pStart && pEnd, "MakeTableCursors: Good to have the code robust here!" )do { if (true && (!(pStart && pEnd))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "1894" ": "), "%s", "MakeTableCursors: Good to have the code robust here!"
); } } while (false)
;
1895
1896 /* #109590# Only change table boxes if the frames are
1897 valid. Needed because otherwise the table cursor after moving
1898 table cells by dnd resulted in an empty tables cursor. */
1899 if ( pStart && pEnd && pStart->isFrameAreaDefinitionValid() && pEnd->isFrameAreaDefinitionValid())
1900 {
1901 SwSelUnions aUnions;
1902 ::MakeSelUnions( aUnions, pStart, pEnd );
1903
1904 SwSelBoxes aNew;
1905
1906 const bool bReadOnlyAvailable = rTableCursor.IsReadOnlyAvailable();
1907
1908 for (SwSelUnion & rUnion : aUnions)
1909 {
1910 const SwTabFrame *pTable = rUnion.GetTable();
1911
1912 // Skip any repeated headlines in the follow:
1913 SwLayoutFrame* pRow = pTable->IsFollow() ?
1914 pTable->GetFirstNonHeadlineRow() :
1915 const_cast<SwLayoutFrame*>(static_cast<const SwLayoutFrame*>(pTable->Lower()));
1916
1917 while ( pRow )
1918 {
1919 if ( pRow->getFrameArea().IsOver( rUnion.GetUnion() ) )
1920 {
1921 const SwLayoutFrame *pCell = pRow->FirstCell();
1922
1923 while ( pCell && pRow->IsAnLower( pCell ) )
1924 {
1925 OSL_ENSURE( pCell->IsCellFrame(), "Frame without cell" )do { if (true && (!(pCell->IsCellFrame()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "1925" ": "), "%s", "Frame without cell"); } } while (false
)
;
1926 if( IsFrameInTableSel( rUnion.GetUnion(), pCell ) &&
1927 (bReadOnlyAvailable ||
1928 !pCell->GetFormat()->GetProtect().IsContentProtected()))
1929 {
1930 SwTableBox* pInsBox = const_cast<SwTableBox*>(
1931 static_cast<const SwCellFrame*>(pCell)->GetTabBox());
1932 aNew.insert( pInsBox );
1933 }
1934 if ( pCell->GetNext() )
1935 {
1936 pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext());
1937 if ( pCell->Lower() && pCell->Lower()->IsRowFrame() )
1938 pCell = pCell->FirstCell();
1939 }
1940 else
1941 {
1942 const SwLayoutFrame* pLastCell = pCell;
1943 do
1944 {
1945 pCell = pCell->GetNextLayoutLeaf();
1946 } while ( pCell && pLastCell->IsAnLower( pCell ) );
1947 // For sections with columns
1948 if( pCell && pCell->IsInTab() )
1949 {
1950 while( !pCell->IsCellFrame() )
1951 {
1952 pCell = pCell->GetUpper();
1953 OSL_ENSURE( pCell, "Where's my cell?" )do { if (true && (!(pCell))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "1953" ": "), "%s", "Where's my cell?"); } } while (false
)
;
1954 }
1955 }
1956 }
1957 }
1958 }
1959 pRow = static_cast<SwLayoutFrame*>(pRow->GetNext());
1960 }
1961 }
1962
1963 rTableCursor.ActualizeSelection( aNew );
1964 bRet = true;
1965 }
1966
1967 return bRet;
1968}
1969
1970static void Sub( SwRegionRects& rRegion, const SwRect& rRect )
1971{
1972 if( rRect.Width() > 1 && rRect.Height() > 1 &&
1973 rRect.IsOver( rRegion.GetOrigin() ))
1974 rRegion -= rRect;
1975}
1976
1977static void Add( SwRegionRects& rRegion, const SwRect& rRect )
1978{
1979 if( rRect.Width() > 1 && rRect.Height() > 1 )
1980 rRegion += rRect;
1981}
1982
1983/*
1984 * The following situations can happen:
1985 * 1. Start and end lie in one screen-row and in the same node
1986 * -> one rectangle out of start and end; and we're okay
1987 * 2. Start and end lie in one frame (therefore in the same node!)
1988 * -> expand start to the right, end to the left and if more than two
1989 * screen-rows are involved - calculate the in-between
1990 * 3. Start and end lie in different frames
1991 * -> expand start to the right until frame-end, calculate Rect
1992 * expand end to the left until frame-start, calculate Rect
1993 * and if more than two frames are involved add the PrtArea of all
1994 * frames which lie in between
1995 *
1996 * Big reorganization because of the FlyFrame - those need to be locked out.
1997 * Exceptions: - The Fly in which the selection took place (if it took place
1998 * in a Fly)
1999 * - The Flys which are underrun by the text
2000 * - The Flys which are anchored to somewhere inside the selection.
2001 * Functioning: First a SwRegion with a root gets initialized.
2002 * Out of the region the inverted sections are cut out. The
2003 * section gets compressed and finally inverted and thereby the
2004 * inverted rectangles are available.
2005 * In the end the Flys are cut out of the section.
2006 */
2007void SwRootFrame::CalcFrameRects(SwShellCursor &rCursor)
2008{
2009 SwPosition *pStartPos = rCursor.Start(),
2010 *pEndPos = rCursor.GetPoint() == pStartPos ? rCursor.GetMark() : rCursor.GetPoint();
2011
2012 SwViewShell *pSh = GetCurrShell();
2013
2014 bool bIgnoreVisArea = true;
2015 if (pSh)
2016 bIgnoreVisArea = pSh->GetViewOptions()->IsPDFExport() || comphelper::LibreOfficeKit::isActive();
2017
2018 // #i12836# enhanced pdf
2019 SwRegionRects aRegion( !bIgnoreVisArea ?
2020 pSh->VisArea() :
2021 getFrameArea() );
2022 if( !pStartPos->nNode.GetNode().IsContentNode() ||
2023 !pStartPos->nNode.GetNode().GetContentNode()->getLayoutFrame(this) ||
2024 ( pStartPos->nNode != pEndPos->nNode &&
2025 ( !pEndPos->nNode.GetNode().IsContentNode() ||
2026 !pEndPos->nNode.GetNode().GetContentNode()->getLayoutFrame(this) ) ) )
2027 {
2028 return;
2029 }
2030
2031 DisableCallbackAction a(*this); // the GetCharRect below may format
2032
2033 //First obtain the ContentFrames for the start and the end - those are needed
2034 //anyway.
2035 std::pair<Point, bool> tmp(rCursor.GetSttPos(), true);
2036 SwContentFrame* pStartFrame = pStartPos->nNode.GetNode().
2037 GetContentNode()->getLayoutFrame(this, pStartPos, &tmp);
2038
2039 tmp.first = rCursor.GetEndPos();
2040 SwContentFrame* pEndFrame = pEndPos->nNode.GetNode().
2041 GetContentNode()->getLayoutFrame(this, pEndPos, &tmp);
2042
2043 assert(pStartFrame && pEndFrame && "No ContentFrames found.")(static_cast <bool> (pStartFrame && pEndFrame &&
"No ContentFrames found.") ? void (0) : __assert_fail ("pStartFrame && pEndFrame && \"No ContentFrames found.\""
, "/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
, 2043, __extension__ __PRETTY_FUNCTION__))
;
2044 //tdf#119224 start and end are expected to exist for the scope of this function
2045 SwFrameDeleteGuard aStartFrameGuard(pStartFrame), aEndFrameGuard(pEndFrame);
2046
2047 //Do not subtract the FlyFrames in which selected Frames lie.
2048 SwSortedObjs aSortObjs;
2049 if ( pStartFrame->IsInFly() )
2050 {
2051 const SwAnchoredObject* pObj = pStartFrame->FindFlyFrame();
2052 OSL_ENSURE( pObj, "No Start Object." )do { if (true && (!(pObj))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "2052" ": "), "%s", "No Start Object."); } } while (false
)
;
2053 if (pObj) aSortObjs.Insert( *const_cast<SwAnchoredObject*>(pObj) );
2054 const SwAnchoredObject* pObj2 = pEndFrame->FindFlyFrame();
2055 OSL_ENSURE( pObj2, "SwRootFrame::CalcFrameRects(..) - FlyFrame missing - looks like an invalid selection" )do { if (true && (!(pObj2))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "2055" ": "), "%s", "SwRootFrame::CalcFrameRects(..) - FlyFrame missing - looks like an invalid selection"
); } } while (false)
;
2056 if ( pObj2 != nullptr && pObj2 != pObj )
2057 {
2058 aSortObjs.Insert( *const_cast<SwAnchoredObject*>(pObj2) );
2059 }
2060 }
2061
2062 // if a selection which is not allowed exists, we correct what is not
2063 // allowed (header/footer/table-headline) for two pages.
2064 do { // middle check loop
2065 const SwLayoutFrame* pSttLFrame = pStartFrame->GetUpper();
2066 const SwFrameType cHdFtTableHd = SwFrameType::Header | SwFrameType::Footer | SwFrameType::Tab;
2067 while( pSttLFrame &&
2068 ! (cHdFtTableHd & pSttLFrame->GetType() ))
2069 pSttLFrame = pSttLFrame->GetUpper();
2070 if( !pSttLFrame )
2071 break;
2072 const SwLayoutFrame* pEndLFrame = pEndFrame->GetUpper();
2073 while( pEndLFrame &&
2074 ! (cHdFtTableHd & pEndLFrame->GetType() ))
2075 pEndLFrame = pEndLFrame->GetUpper();
2076 if( !pEndLFrame )
2077 break;
2078
2079 OSL_ENSURE( pEndLFrame->GetType() == pSttLFrame->GetType(),do { if (true && (!(pEndLFrame->GetType() == pSttLFrame
->GetType()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "2080" ": "), "%s", "Selection over different content");
} } while (false)
2080 "Selection over different content" )do { if (true && (!(pEndLFrame->GetType() == pSttLFrame
->GetType()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "2080" ": "), "%s", "Selection over different content");
} } while (false)
;
2081 switch( pSttLFrame->GetType() )
2082 {
2083 case SwFrameType::Header:
2084 case SwFrameType::Footer:
2085 // On different pages? Then always on the start-page
2086 if( pEndLFrame->FindPageFrame() != pSttLFrame->FindPageFrame() )
2087 {
2088 // Set end- to the start-ContentFrame
2089 if( pStartPos == rCursor.GetPoint() )
2090 pEndFrame = pStartFrame;
2091 else
2092 pStartFrame = pEndFrame;
2093 }
2094 break;
2095 case SwFrameType::Tab:
2096 // On different pages? Then check for table-headline
2097 {
2098 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>(pSttLFrame);
2099 if( ( pTabFrame->GetFollow() ||
2100 static_cast<const SwTabFrame*>(pEndLFrame)->GetFollow() ) &&
2101 pTabFrame->GetTable()->GetRowsToRepeat() > 0 &&
2102 pTabFrame->GetLower() != static_cast<const SwTabFrame*>(pEndLFrame)->GetLower() &&
2103 ( lcl_IsInRepeatedHeadline( pStartFrame ) ||
2104 lcl_IsInRepeatedHeadline( pEndFrame ) ) )
2105 {
2106 // Set end- to the start-ContentFrame
2107 if( pStartPos == rCursor.GetPoint() )
2108 pEndFrame = pStartFrame;
2109 else
2110 pStartFrame = pEndFrame;
2111 }
2112 }
2113 break;
2114 default: break;
2115 }
2116 } while( false );
2117
2118 SwCursorMoveState aTmpState( CursorMoveState::NONE );
2119 aTmpState.m_b2Lines = true;
2120 aTmpState.m_bNoScroll = true;
2121 aTmpState.m_nCursorBidiLevel = pStartFrame->IsRightToLeft() ? 1 : 0;
2122
2123 //ContentRects to Start- and EndFrames.
2124 SwRect aStRect, aEndRect;
2125 pStartFrame->GetCharRect( aStRect, *pStartPos, &aTmpState );
2126 std::unique_ptr<Sw2LinesPos> pSt2Pos = std::move(aTmpState.m_p2Lines);
2127 aTmpState.m_nCursorBidiLevel = pEndFrame->IsRightToLeft() ? 1 : 0;
2128
2129 pEndFrame->GetCharRect( aEndRect, *pEndPos, &aTmpState );
2130 std::unique_ptr<Sw2LinesPos> pEnd2Pos = std::move(aTmpState.m_p2Lines);
2131
2132 SwRect aStFrame ( pStartFrame->UnionFrame( true ) );
2133 aStFrame.Intersection( pStartFrame->GetPaintArea() );
2134 SwRect aEndFrame( pStartFrame == pEndFrame ? aStFrame : pEndFrame->UnionFrame( true ) );
2135 if( pStartFrame != pEndFrame )
2136 {
2137 aEndFrame.Intersection( pEndFrame->GetPaintArea() );
2138 }
2139 SwRectFnSet aRectFnSet(pStartFrame);
2140 const bool bR2L = pStartFrame->IsRightToLeft();
2141 const bool bEndR2L = pEndFrame->IsRightToLeft();
2142 const bool bB2T = pStartFrame->IsVertLRBT();
2143
2144 // If there's no doubleline portion involved or start and end are both
2145 // in the same doubleline portion, all works fine, but otherwise
2146 // we need the following...
2147 if( pSt2Pos != pEnd2Pos && ( !pSt2Pos || !pEnd2Pos ||
2148 pSt2Pos->aPortion != pEnd2Pos->aPortion ) )
2149 {
2150 // If we have a start(end) position inside a doubleline portion
2151 // the surrounded part of the doubleline portion is subtracted
2152 // from the region and the aStRect(aEndRect) is set to the
2153 // end(start) of the doubleline portion.
2154 if( pSt2Pos )
2155 {
2156 SwRect aTmp( aStRect );
2157
2158 // BiDi-Portions are swimming against the current.
2159 const bool bPorR2L = ( MultiPortionType::BIDI == pSt2Pos->nMultiType ) ?
2160 ! bR2L :
2161 bR2L;
2162
2163 if( MultiPortionType::BIDI == pSt2Pos->nMultiType &&
2164 aRectFnSet.GetWidth(pSt2Pos->aPortion2) )
2165 {
2166 // nested bidi portion
2167 long nRightAbs = aRectFnSet.GetRight(pSt2Pos->aPortion);
2168 nRightAbs -= aRectFnSet.GetLeft(pSt2Pos->aPortion2);
2169 long nLeftAbs = nRightAbs - aRectFnSet.GetWidth(pSt2Pos->aPortion2);
2170
2171 aRectFnSet.SetRight( aTmp, nRightAbs );
2172
2173 if ( ! pEnd2Pos || pEnd2Pos->aPortion != pSt2Pos->aPortion )
2174 {
2175 SwRect aTmp2( pSt2Pos->aPortion );
2176 aRectFnSet.SetRight( aTmp2, nLeftAbs );
2177 aTmp2.Intersection( aEndFrame );
2178 Sub( aRegion, aTmp2 );
2179 }
2180 }
2181 else
2182 {
2183 if( bPorR2L )
2184 aRectFnSet.SetLeft( aTmp, aRectFnSet.GetLeft(pSt2Pos->aPortion) );
2185 else
2186 aRectFnSet.SetRight( aTmp, aRectFnSet.GetRight(pSt2Pos->aPortion) );
2187 }
2188
2189 if( MultiPortionType::ROT_90 == pSt2Pos->nMultiType ||
2190 aRectFnSet.GetTop(pSt2Pos->aPortion) ==
2191 aRectFnSet.GetTop(aTmp) )
2192 {
2193 aRectFnSet.SetTop( aTmp, aRectFnSet.GetTop(pSt2Pos->aLine) );
2194 }
2195
2196 aTmp.Intersection( aStFrame );
2197 Sub( aRegion, aTmp );
2198
2199 SwTwips nTmp = aRectFnSet.GetBottom(pSt2Pos->aLine);
2200 if( MultiPortionType::ROT_90 != pSt2Pos->nMultiType &&
2201 aRectFnSet.BottomDist( aStRect, nTmp ) > 0 )
2202 {
2203 aRectFnSet.SetTop( aTmp, aRectFnSet.GetBottom(aTmp) );
2204 aRectFnSet.SetBottom( aTmp, nTmp );
2205 if( aRectFnSet.BottomDist( aStRect, aRectFnSet.GetBottom(pSt2Pos->aPortion) ) > 0 )
2206 {
2207 if( bPorR2L )
2208 aRectFnSet.SetRight( aTmp, aRectFnSet.GetRight(pSt2Pos->aPortion) );
2209 else
2210 aRectFnSet.SetLeft( aTmp, aRectFnSet.GetLeft(pSt2Pos->aPortion) );
2211 }
2212 aTmp.Intersection( aStFrame );
2213 Sub( aRegion, aTmp );
2214 }
2215
2216 aStRect = pSt2Pos->aLine;
2217 aRectFnSet.SetLeft( aStRect, bR2L ?
2218 aRectFnSet.GetLeft(pSt2Pos->aPortion) :
2219 aRectFnSet.GetRight(pSt2Pos->aPortion) );
2220 aRectFnSet.SetWidth( aStRect, 1 );
2221 }
2222
2223 if( pEnd2Pos )
2224 {
2225 SwRectFnSet fnRectX(pEndFrame);
2226 SwRect aTmp( aEndRect );
2227
2228 // BiDi-Portions are swimming against the current.
2229 const bool bPorR2L = ( MultiPortionType::BIDI == pEnd2Pos->nMultiType ) ?
2230 ! bEndR2L :
2231 bEndR2L;
2232
2233 if( MultiPortionType::BIDI == pEnd2Pos->nMultiType &&
2234 fnRectX.GetWidth(pEnd2Pos->aPortion2) )
2235 {
2236 // nested bidi portion
2237 long nRightAbs = fnRectX.GetRight(pEnd2Pos->aPortion);
2238 nRightAbs = nRightAbs - fnRectX.GetLeft(pEnd2Pos->aPortion2);
2239 long nLeftAbs = nRightAbs - fnRectX.GetWidth(pEnd2Pos->aPortion2);
2240
2241 fnRectX.SetLeft( aTmp, nLeftAbs );
2242
2243 if ( ! pSt2Pos || pSt2Pos->aPortion != pEnd2Pos->aPortion )
2244 {
2245 SwRect aTmp2( pEnd2Pos->aPortion );
2246 fnRectX.SetLeft( aTmp2, nRightAbs );
2247 aTmp2.Intersection( aEndFrame );
2248 Sub( aRegion, aTmp2 );
2249 }
2250 }
2251 else
2252 {
2253 if ( bPorR2L )
2254 fnRectX.SetRight( aTmp, fnRectX.GetRight(pEnd2Pos->aPortion) );
2255 else
2256 fnRectX.SetLeft( aTmp, fnRectX.GetLeft(pEnd2Pos->aPortion) );
2257 }
2258
2259 if( MultiPortionType::ROT_90 == pEnd2Pos->nMultiType ||
2260 fnRectX.GetBottom(pEnd2Pos->aPortion) ==
2261 fnRectX.GetBottom(aEndRect) )
2262 {
2263 fnRectX.SetBottom( aTmp, fnRectX.GetBottom(pEnd2Pos->aLine) );
2264 }
2265
2266 aTmp.Intersection( aEndFrame );
2267 Sub( aRegion, aTmp );
2268
2269 // The next statement means neither ruby nor rotate(90):
2270 if( MultiPortionType::RUBY != pEnd2Pos->nMultiType && MultiPortionType::ROT_90 != pEnd2Pos->nMultiType )
2271 {
2272 SwTwips nTmp = fnRectX.GetTop(pEnd2Pos->aLine);
2273 if( fnRectX.GetTop(aEndRect) != nTmp )
2274 {
2275 fnRectX.SetBottom( aTmp, fnRectX.GetTop(aTmp) );
2276 fnRectX.SetTop( aTmp, nTmp );
2277 if( fnRectX.GetTop(aEndRect) !=
2278 fnRectX.GetTop(pEnd2Pos->aPortion) )
2279 {
2280 if( bPorR2L )
2281 fnRectX.SetLeft( aTmp, fnRectX.GetLeft(pEnd2Pos->aPortion) );
2282 else
2283 fnRectX.SetRight( aTmp, fnRectX.GetRight(pEnd2Pos->aPortion) );
2284 }
2285 aTmp.Intersection( aEndFrame );
2286 Sub( aRegion, aTmp );
2287 }
2288 }
2289
2290 aEndRect = pEnd2Pos->aLine;
2291 fnRectX.SetLeft( aEndRect, bEndR2L ?
2292 fnRectX.GetRight(pEnd2Pos->aPortion) :
2293 fnRectX.GetLeft(pEnd2Pos->aPortion) );
2294 fnRectX.SetWidth( aEndRect, 1 );
2295 }
2296 }
2297 else if( pSt2Pos && pEnd2Pos &&
2298 MultiPortionType::BIDI == pSt2Pos->nMultiType &&
2299 MultiPortionType::BIDI == pEnd2Pos->nMultiType &&
2300 pSt2Pos->aPortion == pEnd2Pos->aPortion &&
2301 pSt2Pos->aPortion2 != pEnd2Pos->aPortion2 )
2302 {
2303 // This is the ugly special case, where the selection starts and
2304 // ends in the same bidi portion but one start or end is inside a
2305 // nested bidi portion.
2306
2307 if ( aRectFnSet.GetWidth(pSt2Pos->aPortion2) )
2308 {
2309 SwRect aTmp( aStRect );
2310 long nRightAbs = aRectFnSet.GetRight(pSt2Pos->aPortion);
2311 nRightAbs -= aRectFnSet.GetLeft(pSt2Pos->aPortion2);
2312 long nLeftAbs = nRightAbs - aRectFnSet.GetWidth(pSt2Pos->aPortion2);
2313
2314 aRectFnSet.SetRight( aTmp, nRightAbs );
2315 aTmp.Intersection( aStFrame );
2316 Sub( aRegion, aTmp );
2317
2318 aStRect = pSt2Pos->aLine;
2319 aRectFnSet.SetLeft( aStRect, bR2L ? nRightAbs : nLeftAbs );
2320 aRectFnSet.SetWidth( aStRect, 1 );
2321 }
2322
2323 SwRectFnSet fnRectX(pEndFrame);
2324 if ( fnRectX.GetWidth(pEnd2Pos->aPortion2) )
2325 {
2326 SwRect aTmp( aEndRect );
2327 long nRightAbs = fnRectX.GetRight(pEnd2Pos->aPortion);
2328 nRightAbs -= fnRectX.GetLeft(pEnd2Pos->aPortion2);
2329 long nLeftAbs = nRightAbs - fnRectX.GetWidth(pEnd2Pos->aPortion2);
2330
2331 fnRectX.SetLeft( aTmp, nLeftAbs );
2332 aTmp.Intersection( aEndFrame );
2333 Sub( aRegion, aTmp );
2334
2335 aEndRect = pEnd2Pos->aLine;
2336 fnRectX.SetLeft( aEndRect, bEndR2L ? nLeftAbs : nRightAbs );
2337 fnRectX.SetWidth( aEndRect, 1 );
2338 }
2339 }
2340
2341 // The charrect may be outside the paintarea (for cursortravelling)
2342 // but the selection has to be restricted to the paintarea
2343 if( aStRect.Left() < aStFrame.Left() )
2344 aStRect.Left( aStFrame.Left() );
2345 else if( aStRect.Left() > aStFrame.Right() )
2346 aStRect.Left( aStFrame.Right() );
2347 SwTwips nTmp = aStRect.Right();
2348 if( nTmp < aStFrame.Left() )
2349 aStRect.Right( aStFrame.Left() );
2350 else if( nTmp > aStFrame.Right() )
2351 aStRect.Right( aStFrame.Right() );
2352 if( aEndRect.Left() < aEndFrame.Left() )
2353 aEndRect.Left( aEndFrame.Left() );
2354 else if( aEndRect.Left() > aEndFrame.Right() )
2355 aEndRect.Left( aEndFrame.Right() );
2356 nTmp = aEndRect.Right();
2357 if( nTmp < aEndFrame.Left() )
2358 aEndRect.Right( aEndFrame.Left() );
2359 else if( nTmp > aEndFrame.Right() )
2360 aEndRect.Right( aEndFrame.Right() );
2361
2362 if( pStartFrame == pEndFrame )
2363 {
2364 bool bSameRotatedOrBidi = pSt2Pos && pEnd2Pos &&
2365 ( MultiPortionType::BIDI == pSt2Pos->nMultiType ||
2366 MultiPortionType::ROT_270 == pSt2Pos->nMultiType ||
2367 MultiPortionType::ROT_90 == pSt2Pos->nMultiType ) &&
2368 pSt2Pos->aPortion == pEnd2Pos->aPortion;
2369 //case 1: (Same frame and same row)
2370 if( bSameRotatedOrBidi ||
2371 aRectFnSet.GetTop(aStRect) == aRectFnSet.GetTop(aEndRect) )
2372 {
2373 Point aTmpSt( aStRect.Pos() );
2374 Point aTmpEnd( aEndRect.Right(), aEndRect.Bottom() );
2375 if (bSameRotatedOrBidi || bR2L || bB2T)
2376 {
2377 if( aTmpSt.Y() > aTmpEnd.Y() )
2378 {
2379 long nTmpY = aTmpEnd.Y();
2380 aTmpEnd.setY( aTmpSt.Y() );
2381 aTmpSt.setY( nTmpY );
2382 }
2383 if( aTmpSt.X() > aTmpEnd.X() )
2384 {
2385 long nTmpX = aTmpEnd.X();
2386 aTmpEnd.setX( aTmpSt.X() );
2387 aTmpSt.setX( nTmpX );
2388 }
2389 }
2390
2391 SwRect aTmp( aTmpSt, aTmpEnd );
2392 // Bug 34888: If content is selected which doesn't take space
2393 // away (i.e. PostIts, RefMarks, TOXMarks), then at
2394 // least set the width of the Cursor.
2395 if( 1 == aRectFnSet.GetWidth(aTmp) &&
2396 pStartPos->nContent.GetIndex() !=
2397 pEndPos->nContent.GetIndex() )
2398 {
2399 OutputDevice* pOut = pSh->GetOut();
2400 long nCursorWidth = pOut->GetSettings().GetStyleSettings().
2401 GetCursorSize();
2402 aRectFnSet.SetWidth( aTmp, pOut->PixelToLogic(
2403 Size( nCursorWidth, 0 ) ).Width() );
2404 }
2405 aTmp.Intersection( aStFrame );
2406 Sub( aRegion, aTmp );
2407 }
2408 //case 2: (Same frame, but not the same line)
2409 else
2410 {
2411 SwTwips lLeft, lRight;
2412 if( pSt2Pos && pEnd2Pos && pSt2Pos->aPortion == pEnd2Pos->aPortion )
2413 {
2414 lLeft = aRectFnSet.GetLeft(pSt2Pos->aPortion);
2415 lRight = aRectFnSet.GetRight(pSt2Pos->aPortion);
2416 }
2417 else
2418 {
2419 lLeft = aRectFnSet.GetLeft(pStartFrame->getFrameArea()) +
2420 aRectFnSet.GetLeft(pStartFrame->getFramePrintArea());
2421 lRight = aRectFnSet.GetRight(aEndFrame);
2422 }
2423 if( lLeft < aRectFnSet.GetLeft(aStFrame) )
2424 lLeft = aRectFnSet.GetLeft(aStFrame);
2425 if( lRight > aRectFnSet.GetRight(aStFrame) )
2426 lRight = aRectFnSet.GetRight(aStFrame);
2427 SwRect aSubRect( aStRect );
2428 //First line
2429 if( bR2L )
2430 aRectFnSet.SetLeft( aSubRect, lLeft );
2431 else
2432 aRectFnSet.SetRight( aSubRect, lRight );
2433 Sub( aRegion, aSubRect );
2434
2435 //If there's at least a twips between start- and endline,
2436 //so the whole area between will be added.
2437 SwTwips aTmpBottom = aRectFnSet.GetBottom(aStRect);
2438 SwTwips aTmpTop = aRectFnSet.GetTop(aEndRect);
2439 if( aTmpBottom != aTmpTop )
2440 {
2441 aRectFnSet.SetLeft( aSubRect, lLeft );
2442 aRectFnSet.SetRight( aSubRect, lRight );
2443 aRectFnSet.SetTop( aSubRect, aTmpBottom );
2444 aRectFnSet.SetBottom( aSubRect, aTmpTop );
2445 Sub( aRegion, aSubRect );
2446 }
2447 //and the last line
2448 aSubRect = aEndRect;
2449 if( bR2L )
2450 aRectFnSet.SetRight( aSubRect, lRight );
2451 else
2452 aRectFnSet.SetLeft( aSubRect, lLeft );
2453 Sub( aRegion, aSubRect );
2454 }
2455 }
2456 //case 3: (Different frames, maybe with other frames between)
2457 else
2458 {
2459 //The startframe first...
2460 SwRect aSubRect( aStRect );
2461 if( bR2L )
2462 aRectFnSet.SetLeft( aSubRect, aRectFnSet.GetLeft(aStFrame));
2463 else
2464 aRectFnSet.SetRight( aSubRect, aRectFnSet.GetRight(aStFrame));
2465 Sub( aRegion, aSubRect );
2466 SwTwips nTmpTwips = aRectFnSet.GetBottom(aStRect);
2467 if( aRectFnSet.GetBottom(aStFrame) != nTmpTwips )
2468 {
2469 aSubRect = aStFrame;
2470 aRectFnSet.SetTop( aSubRect, nTmpTwips );
2471 Sub( aRegion, aSubRect );
2472 }
2473
2474 //Now the frames between, if there are any
2475 bool const bBody = pStartFrame->IsInDocBody();
2476 const SwTableBox* pCellBox = pStartFrame->GetUpper()->IsCellFrame() ?
2477 static_cast<const SwCellFrame*>(pStartFrame->GetUpper())->GetTabBox() : nullptr;
2478 if (pSh->IsSelectAll())
2479 pCellBox = nullptr;
2480
2481 const SwContentFrame *pContent = pStartFrame->GetNextContentFrame();
2482 SwRect aPrvRect;
2483
2484 OSL_ENSURE( pContent,do { if (true && (!(pContent))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "2485" ": "), "%s", "<SwRootFrame::CalcFrameRects(..)> - no content frame. This is a serious defect"
); } } while (false)
2485 "<SwRootFrame::CalcFrameRects(..)> - no content frame. This is a serious defect" )do { if (true && (!(pContent))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "2485" ": "), "%s", "<SwRootFrame::CalcFrameRects(..)> - no content frame. This is a serious defect"
); } } while (false)
;
2486 while ( pContent && pContent != pEndFrame )
2487 {
2488 if ( pContent->IsInFly() )
2489 {
2490 const SwAnchoredObject* pObj = pContent->FindFlyFrame();
2491 if (!aSortObjs.Contains(*pObj))
2492 { // is this even possible, assuming valid cursor pos.?
2493 aSortObjs.Insert( *const_cast<SwAnchoredObject*>(pObj) );
2494 }
2495 }
2496
2497 // Consider only frames which have the same IsInDocBody value like pStartFrame
2498 // If pStartFrame is inside a SwCellFrame, consider only frames which are inside the
2499 // same cell frame (or its follow cell)
2500 const SwTableBox* pTmpCellBox = pContent->GetUpper()->IsCellFrame() ?
2501 static_cast<const SwCellFrame*>(pContent->GetUpper())->GetTabBox() : nullptr;
2502 if (pSh->IsSelectAll())
2503 pTmpCellBox = nullptr;
2504 if ( bBody == pContent->IsInDocBody() &&
2505 ( !pCellBox || pCellBox == pTmpCellBox ) )
2506 {
2507 SwRect aCRect( pContent->UnionFrame( true ) );
2508 aCRect.Intersection( pContent->GetPaintArea() );
2509 if( aCRect.IsOver( aRegion.GetOrigin() ))
2510 {
2511 SwRect aTmp( aPrvRect );
2512 aTmp.Union( aCRect );
2513 if ( (aPrvRect.Height() * aPrvRect.Width() +
2514 aCRect.Height() * aCRect.Width()) ==
2515 (aTmp.Height() * aTmp.Width()) )
2516 {
2517 aPrvRect.Union( aCRect );
2518 }
2519 else
2520 {
2521 if ( aPrvRect.HasArea() )
2522 Sub( aRegion, aPrvRect );
2523 aPrvRect = aCRect;
2524 }
2525 }
2526 }
2527 pContent = pContent->GetNextContentFrame();
2528 OSL_ENSURE( pContent,do { if (true && (!(pContent))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "2529" ": "), "%s", "<SwRootFrame::CalcFrameRects(..)> - no content frame. This is a serious defect!"
); } } while (false)
2529 "<SwRootFrame::CalcFrameRects(..)> - no content frame. This is a serious defect!" )do { if (true && (!(pContent))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "2529" ": "), "%s", "<SwRootFrame::CalcFrameRects(..)> - no content frame. This is a serious defect!"
); } } while (false)
;
2530 }
2531 if ( aPrvRect.HasArea() )
2532 Sub( aRegion, aPrvRect );
2533
2534 //At least the endframe...
2535 aRectFnSet.Refresh(pEndFrame);
2536 nTmpTwips = aRectFnSet.GetTop(aEndRect);
2537 if( aRectFnSet.GetTop(aEndFrame) != nTmpTwips )
2538 {
2539 aSubRect = aEndFrame;
2540 aRectFnSet.SetBottom( aSubRect, nTmpTwips );
2541 Sub( aRegion, aSubRect );
2542 }
2543 aSubRect = aEndRect;
2544 if( bEndR2L )
2545 aRectFnSet.SetRight(aSubRect, aRectFnSet.GetRight(aEndFrame));
2546 else
2547 aRectFnSet.SetLeft( aSubRect, aRectFnSet.GetLeft(aEndFrame) );
2548 Sub( aRegion, aSubRect );
2549 }
2550
2551 aRegion.Invert();
2552 pSt2Pos.reset();
2553 pEnd2Pos.reset();
2554
2555 // Cut out Flys during loop. We don't cut out Flys when:
2556 // - the Lower is StartFrame/EndFrame (FlyInCnt and all other Flys which again
2557 // sit in it)
2558 // - if in the Z-order we have Flys above those in which the StartFrame is
2559 // placed
2560 // - if they are anchored to inside the selection and thus part of it
2561 const SwPageFrame *pPage = pStartFrame->FindPageFrame();
2562 const SwPageFrame *pEndPage = pEndFrame->FindPageFrame();
2563
2564 while ( pPage )
2565 {
2566 if ( pPage->GetSortedObjs() )
2567 {
2568 const SwSortedObjs &rObjs = *pPage->GetSortedObjs();
2569 for (SwAnchoredObject* pAnchoredObj : rObjs)
2570 {
2571 if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) == nullptr )
2572 continue;
2573 const SwFlyFrame* pFly = static_cast<const SwFlyFrame*>(pAnchoredObj);
2574 const SwVirtFlyDrawObj* pObj = pFly->GetVirtDrawObj();
2575 const SwFormatSurround &rSur = pFly->GetFormat()->GetSurround();
2576 SwFormatAnchor const& rAnchor(pAnchoredObj->GetFrameFormat().GetAnchor());
2577 const SwPosition* anchoredAt = rAnchor.GetContentAnchor();
2578 bool inSelection = (
2579 anchoredAt != nullptr
2580 && ( (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR
2581 && IsDestroyFrameAnchoredAtChar(*anchoredAt, *pStartPos, *pEndPos))
2582 || (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA
2583 && IsSelectFrameAnchoredAtPara(*anchoredAt, *pStartPos, *pEndPos))));
2584 if( inSelection )
2585 Add( aRegion, pFly->getFrameArea() );
2586 else if ( !pFly->IsAnLower( pStartFrame ) &&
2587 (rSur.GetSurround() != css::text::WrapTextMode_THROUGH &&
2588 !rSur.IsContour()) )
2589 {
2590 if ( aSortObjs.Contains( *pAnchoredObj ) )
2591 continue;
2592
2593 bool bSub = true;
2594 const sal_uInt32 nPos = pObj->GetOrdNum();
2595 for ( size_t k = 0; bSub && k < aSortObjs.size(); ++k )
2596 {
2597 OSL_ENSURE( dynamic_cast< const SwFlyFrame *>( aSortObjs[k] ) != nullptr,do { if (true && (!(dynamic_cast< const SwFlyFrame
*>( aSortObjs[k] ) != nullptr))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "2598" ": "), "%s", "<SwRootFrame::CalcFrameRects(..)> - object in <aSortObjs> of unexpected type"
); } } while (false)
2598 "<SwRootFrame::CalcFrameRects(..)> - object in <aSortObjs> of unexpected type" )do { if (true && (!(dynamic_cast< const SwFlyFrame
*>( aSortObjs[k] ) != nullptr))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/trvlfrm.cxx"
":" "2598" ": "), "%s", "<SwRootFrame::CalcFrameRects(..)> - object in <aSortObjs> of unexpected type"
); } } while (false)
;
2599 const SwFlyFrame* pTmp = static_cast<SwFlyFrame*>(aSortObjs[k]);
2600 do
2601 {
2602 if ( nPos < pTmp->GetVirtDrawObj()->GetOrdNumDirect() )
2603 {
2604 bSub = false;
2605 }
2606 else
2607 {
2608 pTmp = pTmp->GetAnchorFrame()->FindFlyFrame();
2609 }
2610 } while ( bSub && pTmp );
2611 }
2612 if ( bSub )
2613 Sub( aRegion, pFly->getFrameArea() );
2614 }
2615 }
2616 }
2617 if ( pPage == pEndPage )
2618 break;
2619 else
2620 pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
2621 }
2622
2623 //Because it looks better, we close the DropCaps.
2624 SwRect aDropRect;
2625 if ( pStartFrame->IsTextFrame() )
2626 {
2627 if ( static_cast<const SwTextFrame*>(pStartFrame)->GetDropRect( aDropRect ) )
2628 Sub( aRegion, aDropRect );
2629 }
2630 if ( pEndFrame != pStartFrame && pEndFrame->IsTextFrame() )
2631 {
2632 if ( static_cast<const SwTextFrame*>(pEndFrame)->GetDropRect( aDropRect ) )
2633 Sub( aRegion, aDropRect );
2634 }
2635
2636 rCursor.assign( aRegion.begin(), aRegion.end() );
2637}
2638
2639/* vim:set shiftwidth=4 softtabstop=4 expandtab: */