nss: upgrade to release 3.73
[LibreOffice.git] / sw / source / core / objectpositioning / anchoredobjectposition.cxx
bloba5180ac0653605d560bb18ac6413e5303505271c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <anchoredobjectposition.hxx>
21 #include <environmentofanchoredobject.hxx>
22 #include <flyfrm.hxx>
23 #include <flyfrms.hxx>
24 #include <txtfrm.hxx>
25 #include <pagefrm.hxx>
26 #include <frmatr.hxx>
27 #include <frmtool.hxx>
28 #include <svx/svdobj.hxx>
29 #include <dflyobj.hxx>
30 #include <dcontact.hxx>
31 #include <frmfmt.hxx>
32 #include <fmtornt.hxx>
33 #include <fmtfsize.hxx>
34 #include <fmtfollowtextflow.hxx>
35 #include <editeng/lrspitem.hxx>
36 #include <editeng/ulspitem.hxx>
37 #include <ndtxt.hxx>
38 #include <IDocumentSettingAccess.hxx>
39 #include <textboxhelper.hxx>
40 #include <fmtsrnd.hxx>
41 #include <svx/sdtagitm.hxx>
43 using namespace ::com::sun::star;
44 using namespace objectpositioning;
46 SwAnchoredObjectPosition::SwAnchoredObjectPosition( SdrObject& _rDrawObj )
47 : mrDrawObj( _rDrawObj ),
48 mpAnchoredObj( nullptr ),
49 mpAnchorFrame( nullptr ),
50 mpContact( nullptr ),
51 mbIsObjFly( false ),
52 // #i62875#
53 mbFollowTextFlow( false ),
54 mbDoNotCaptureAnchoredObj( false )
56 #if OSL_DEBUG_LEVEL > 0
57 // assert, if object isn't of expected type
58 const bool bObjOfExceptedType =
59 dynamic_cast<const SwVirtFlyDrawObj*>( &mrDrawObj) != nullptr || // object representing fly frame
60 dynamic_cast<const SwDrawVirtObj*>( &mrDrawObj) != nullptr || // 'virtual' drawing object
61 ( dynamic_cast<const SdrVirtObj*>( &mrDrawObj) == nullptr && // 'master' drawing object
62 dynamic_cast<const SwFlyDrawObj*>( &mrDrawObj) == nullptr ); // - indirectly checked
63 OSL_ENSURE( bObjOfExceptedType,
64 "SwAnchoredObjectPosition(..) - object of unexpected type!" );
65 #endif
67 GetInfoAboutObj();
70 /** determine information about object
72 members <mbIsObjFly>, <mpFrameOfObj>, <mpAnchorFrame>, <mpContact>,
73 <mbFollowTextFlow> and <mbDoNotCaptureAnchoredObj> are set
75 void SwAnchoredObjectPosition::GetInfoAboutObj()
77 // determine, if object represents a fly frame
79 mbIsObjFly = dynamic_cast<const SwVirtFlyDrawObj*>( &mrDrawObj) != nullptr;
82 // determine contact object
84 mpContact = GetUserCall( &mrDrawObj );
85 assert(mpContact &&
86 "SwAnchoredObjectPosition::GetInfoAboutObj() - missing SwContact-object.");
89 // determine anchored object, the object belongs to
91 // #i26791#
92 mpAnchoredObj = mpContact->GetAnchoredObj( &mrDrawObj );
93 assert(mpAnchoredObj &&
94 "SwAnchoredObjectPosition::GetInfoAboutObj() - missing anchored object.");
97 // determine frame, the object is anchored at
99 // #i26791#
100 mpAnchorFrame = mpAnchoredObj->AnchorFrame();
101 OSL_ENSURE( mpAnchorFrame,
102 "SwAnchoredObjectPosition::GetInfoAboutObj() - missing anchor frame." );
105 // determine format the object belongs to
107 // #i28701#
108 mpFrameFormat = &mpAnchoredObj->GetFrameFormat();
109 assert(mpFrameFormat &&
110 "<SwAnchoredObjectPosition::GetInfoAboutObj() - missing frame format.");
113 // #i62875# - determine attribute value of <Follow-Text-Flow>
115 mbFollowTextFlow = mpFrameFormat->GetFollowTextFlow().GetValue();
118 // determine, if anchored object has not to be captured on the page.
119 // the following conditions must be hold to *not* capture it:
120 // - corresponding document compatibility flag is set
121 // - it's a drawing object or it's a non-textbox wrap-though fly frame
122 // - it doesn't follow the text flow
124 bool bTextBox = SwTextBoxHelper::isTextBox(mpFrameFormat, RES_FLYFRMFMT);
125 bool bWrapThrough = mpFrameFormat->GetSurround().GetSurround() == css::text::WrapTextMode_THROUGH;
126 mbDoNotCaptureAnchoredObj = (!mbIsObjFly || (!bTextBox && bWrapThrough)) && !mbFollowTextFlow &&
127 mpFrameFormat->getIDocumentSettingAccess().get(DocumentSettingId::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE);
131 SwAnchoredObjectPosition::~SwAnchoredObjectPosition()
134 bool SwAnchoredObjectPosition::IsAnchoredToChar() const
136 return false;
139 const SwFrame* SwAnchoredObjectPosition::ToCharOrientFrame() const
141 return nullptr;
144 const SwRect* SwAnchoredObjectPosition::ToCharRect() const
146 return nullptr;
149 // #i22341#
150 SwTwips SwAnchoredObjectPosition::ToCharTopOfLine() const
152 return 0;
155 /** helper method to determine top of a frame for the vertical
156 object positioning
158 #i11860#
160 SwTwips SwAnchoredObjectPosition::GetTopForObjPos( const SwFrame& _rFrame,
161 const SwRectFn& _fnRect,
162 const bool _bVert ) const
164 SwTwips nTopOfFrameForObjPos = (_rFrame.getFrameArea().*_fnRect->fnGetTop)();
166 if ( _rFrame.IsTextFrame() )
168 const SwTextFrame& rTextFrame = static_cast<const SwTextFrame&>(_rFrame);
169 if ( _bVert )
171 nTopOfFrameForObjPos -=
172 rTextFrame.GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
174 else
176 nTopOfFrameForObjPos +=
177 rTextFrame.GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
179 const SwFormatSurround& rSurround = mpFrameFormat->GetSurround();
180 bool bWrapThrough = rSurround.GetSurround() == css::text::WrapTextMode_THROUGH;
181 // If the frame format is a TextBox of a draw shape, then use the
182 // surround of the original shape.
183 SwTextBoxHelper::getShapeWrapThrough(mpFrameFormat, bWrapThrough);
185 // Get the offset between the top of the text frame and the top of
186 // the first line inside the frame that has more than just fly
187 // portions.
188 nTopOfFrameForObjPos += rTextFrame.GetBaseVertOffsetForFly(!bWrapThrough);
192 return nTopOfFrameForObjPos;
195 void SwAnchoredObjectPosition::GetVertAlignmentValues(
196 const SwFrame& _rVertOrientFrame,
197 const SwFrame& _rPageAlignLayFrame,
198 const sal_Int16 _eRelOrient,
199 SwTwips& _orAlignAreaHeight,
200 SwTwips& _orAlignAreaOffset ) const
202 SwTwips nHeight = 0;
203 SwTwips nOffset = 0;
204 SwRectFnSet aRectFnSet(&_rVertOrientFrame);
205 // #i11860# - top of <_rVertOrientFrame> for object positioning
206 const SwTwips nVertOrientTop = GetTopForObjPos( _rVertOrientFrame, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
207 // #i11860# - upper space amount of <_rVertOrientFrame> considered
208 // for previous frame
209 const SwTwips nVertOrientUpperSpaceForPrevFrameAndPageGrid =
210 _rVertOrientFrame.IsTextFrame()
211 ? static_cast<const SwTextFrame&>(_rVertOrientFrame).
212 GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid()
213 : 0;
214 switch ( _eRelOrient )
216 case text::RelOrientation::FRAME:
218 // #i11860# - consider upper space of previous frame
219 nHeight = aRectFnSet.GetHeight(_rVertOrientFrame.getFrameArea()) -
220 nVertOrientUpperSpaceForPrevFrameAndPageGrid;
221 nOffset = 0;
223 break;
224 case text::RelOrientation::PRINT_AREA:
226 nHeight = aRectFnSet.GetHeight(_rVertOrientFrame.getFramePrintArea());
227 // #i11860# - consider upper space of previous frame
228 nOffset = aRectFnSet.GetTopMargin(_rVertOrientFrame) -
229 nVertOrientUpperSpaceForPrevFrameAndPageGrid;
230 // if aligned to page in horizontal layout, consider header and
231 // footer frame height appropriately.
232 if( _rVertOrientFrame.IsPageFrame() && !aRectFnSet.IsVert() )
234 const SwFrame* pPrtFrame =
235 static_cast<const SwPageFrame&>(_rVertOrientFrame).Lower();
236 while( pPrtFrame )
238 if( pPrtFrame->IsHeaderFrame() )
240 nHeight -= pPrtFrame->getFrameArea().Height();
241 nOffset += pPrtFrame->getFrameArea().Height();
243 else if( pPrtFrame->IsFooterFrame() )
245 nHeight -= pPrtFrame->getFrameArea().Height();
247 pPrtFrame = pPrtFrame->GetNext();
251 break;
252 case text::RelOrientation::PAGE_FRAME:
253 case text::RelOrientation::PAGE_PRINT_AREA_TOP:
255 nHeight = aRectFnSet.GetHeight(_rPageAlignLayFrame.getFrameArea());
256 nOffset = aRectFnSet.YDiff(
257 aRectFnSet.GetTop(_rPageAlignLayFrame.getFrameArea()),
258 nVertOrientTop );
260 break;
261 case text::RelOrientation::PAGE_PRINT_AREA:
263 nHeight = aRectFnSet.GetHeight(_rPageAlignLayFrame.getFramePrintArea());
264 nOffset = aRectFnSet.GetTopMargin(_rPageAlignLayFrame) +
265 aRectFnSet.YDiff(
266 aRectFnSet.GetTop(_rPageAlignLayFrame.getFrameArea()),
267 nVertOrientTop );
268 // if aligned to page in horizontal layout, consider header and
269 // footer frame height appropriately.
270 if( _rPageAlignLayFrame.IsPageFrame() && !aRectFnSet.IsVert() )
272 const SwFrame* pPrtFrame =
273 static_cast<const SwPageFrame&>(_rPageAlignLayFrame).Lower();
274 while( pPrtFrame )
276 if( pPrtFrame->IsHeaderFrame() )
278 nHeight -= pPrtFrame->getFrameArea().Height();
279 nOffset += pPrtFrame->getFrameArea().Height();
281 else if( pPrtFrame->IsFooterFrame() )
283 nHeight -= pPrtFrame->getFrameArea().Height();
285 pPrtFrame = pPrtFrame->GetNext();
289 break;
290 case text::RelOrientation::PAGE_PRINT_AREA_BOTTOM:
292 nHeight = aRectFnSet.GetBottomMargin(_rPageAlignLayFrame);
293 nOffset = aRectFnSet.YDiff(
294 aRectFnSet.GetPrtBottom(_rPageAlignLayFrame),
295 nVertOrientTop);
297 if (_rPageAlignLayFrame.IsPageFrame() && !aRectFnSet.IsVert())
299 const SwFrame* pPrtFrame =
300 static_cast<const SwPageFrame&>(_rPageAlignLayFrame).Lower();
302 while (pPrtFrame)
304 if (pPrtFrame->IsFooterFrame())
306 nHeight += pPrtFrame->getFrameArea().Height();
307 nOffset -= pPrtFrame->getFrameArea().Height();
309 pPrtFrame = pPrtFrame->GetNext();
314 break;
315 // #i22341# - vertical alignment at top of line
316 case text::RelOrientation::TEXT_LINE:
318 if ( IsAnchoredToChar() )
320 nHeight = 0;
321 nOffset = aRectFnSet.YDiff( ToCharTopOfLine(), nVertOrientTop );
323 else
325 OSL_FAIL( "<SwAnchoredObjectPosition::GetVertAlignmentValues(..)> - invalid relative alignment" );
328 break;
329 case text::RelOrientation::CHAR:
331 if ( IsAnchoredToChar() )
333 nHeight = aRectFnSet.GetHeight(*ToCharRect());
334 nOffset = aRectFnSet.YDiff( aRectFnSet.GetTop(*ToCharRect()),
335 nVertOrientTop );
337 else
339 OSL_FAIL( "<SwAnchoredObjectPosition::GetVertAlignmentValues(..)> - invalid relative alignment" );
342 break;
343 // no break here, because text::RelOrientation::CHAR is invalid, if !mbAnchorToChar
344 default:
346 OSL_FAIL( "<SwAnchoredObjectPosition::GetVertAlignmentValues(..)> - invalid relative alignment" );
350 _orAlignAreaHeight = nHeight;
351 _orAlignAreaOffset = nOffset;
354 // #i26791# - add output parameter <_roVertOffsetToFrameAnchorPos>
355 SwTwips SwAnchoredObjectPosition::GetVertRelPos(
356 const SwFrame& _rVertOrientFrame,
357 const SwFrame& _rPageAlignLayFrame,
358 const sal_Int16 _eVertOrient,
359 const sal_Int16 _eRelOrient,
360 const SwTwips _nVertPos,
361 const SvxLRSpaceItem& _rLRSpacing,
362 const SvxULSpaceItem& _rULSpacing,
363 SwTwips& _roVertOffsetToFrameAnchorPos ) const
365 SwTwips nRelPosY = 0;
366 SwRectFnSet aRectFnSet(&_rVertOrientFrame);
368 SwTwips nAlignAreaHeight;
369 SwTwips nAlignAreaOffset;
370 GetVertAlignmentValues( _rVertOrientFrame, _rPageAlignLayFrame,
371 _eRelOrient, nAlignAreaHeight, nAlignAreaOffset );
373 nRelPosY = nAlignAreaOffset;
374 const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() );
375 const SwTwips nObjHeight = aRectFnSet.GetHeight(aObjBoundRect);
377 switch ( _eVertOrient )
379 case text::VertOrientation::NONE:
381 // 'manual' vertical position
382 nRelPosY += _nVertPos;
384 break;
385 case text::VertOrientation::TOP:
387 nRelPosY += aRectFnSet.IsVert()
388 ? ( aRectFnSet.IsVertL2R()
389 ? _rLRSpacing.GetLeft()
390 : _rLRSpacing.GetRight() )
391 : _rULSpacing.GetUpper();
393 break;
394 case text::VertOrientation::CENTER:
396 nRelPosY += (nAlignAreaHeight / 2) - (nObjHeight / 2);
398 break;
399 case text::VertOrientation::BOTTOM:
401 nRelPosY += nAlignAreaHeight -
402 ( nObjHeight + ( aRectFnSet.IsVert()
403 ? ( aRectFnSet.IsVertL2R()
404 ? _rLRSpacing.GetRight()
405 : _rLRSpacing.GetLeft() )
406 : _rULSpacing.GetLower() ) );
408 break;
409 default:
411 OSL_FAIL( "<SwAnchoredObjectPosition::GetVertRelPos(..) - invalid vertical positioning" );
415 // #i26791#
416 _roVertOffsetToFrameAnchorPos = nAlignAreaOffset;
418 return nRelPosY;
421 /** adjust calculated vertical in order to keep object inside
422 'page' alignment layout frame.
424 #i28701# - parameter <_nTopOfAnch> and <_bVert> added
425 #i31805# - add parameter <_bCheckBottom>
426 #i26945# - add parameter <_bFollowTextFlow>
427 #i62875# - method now private and renamed.
428 OD 2009-09-01 #mongolianlayout# - add parameter <bVertL2R>
430 SwTwips SwAnchoredObjectPosition::ImplAdjustVertRelPos( const SwTwips nTopOfAnch,
431 const bool bVert,
432 const bool bVertL2R,
433 const SwFrame& rPageAlignLayFrame,
434 const SwTwips nProposedRelPosY,
435 const bool bFollowTextFlow,
436 const bool bCheckBottom ) const
438 SwTwips nAdjustedRelPosY = nProposedRelPosY;
439 // TODO: Replace the following condition with the correction
440 // of the implementation of option FollowTextFlow.
441 if ( SwAnchoredObject::IsDraggingOffPageAllowed(FindFrameFormat(&mrDrawObj)) &&
442 !(GetAnchorFrame().IsInTab() && DoesObjFollowsTextFlow()) )
444 return nAdjustedRelPosY;
447 const Size aObjSize(GetAnchoredObj().GetObjRect().SSize());
448 // determine the area of 'page' alignment frame, to which the vertical
449 // position is restricted.
450 // #i28701# - Extend restricted area for the vertical
451 // position to area of the page frame, if wrapping style influence is
452 // considered on object positioning. Needed to avoid layout loops in the
453 // object positioning algorithm considering the wrapping style influence
454 // caused by objects, which follow the text flow and thus are restricted
455 // to its environment (e.g. page header/footer).
456 SwRect aPgAlignArea;
458 // #i26945# - no extension of restricted area, if
459 // object's attribute follow text flow is set and its inside a table
460 if ( GetFrameFormat().getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) &&
461 ( !bFollowTextFlow ||
462 !GetAnchoredObj().GetAnchorFrame()->IsInTab() ) )
464 aPgAlignArea = rPageAlignLayFrame.FindPageFrame()->getFrameArea();
466 else
468 aPgAlignArea = rPageAlignLayFrame.getFrameArea();
472 if ( bVert )
474 // #i31805# - consider value of <_bCheckBottom>
475 if ( !bVertL2R )
477 if ( bCheckBottom &&
478 nTopOfAnch - nAdjustedRelPosY - aObjSize.Width() <
479 aPgAlignArea.Left() )
481 nAdjustedRelPosY = aPgAlignArea.Left() +
482 nTopOfAnch -
483 aObjSize.Width();
485 // #i32964# - correction
486 if ( nTopOfAnch - nAdjustedRelPosY > aPgAlignArea.Right() )
488 nAdjustedRelPosY = nTopOfAnch - aPgAlignArea.Right();
491 else
493 // tdf#112443 if position is completely off-page
494 // return the proposed position and do not adjust it...
495 // tdf#120839 .. unless anchored to char (anchor can jump on other page)
496 const bool bDisablePositioning = mpFrameFormat->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
497 if ( bDisablePositioning && !IsAnchoredToChar() && nTopOfAnch + nAdjustedRelPosY > aPgAlignArea.Right() )
499 return nProposedRelPosY;
502 if ( bCheckBottom &&
503 nTopOfAnch + nAdjustedRelPosY + aObjSize.Width() >
504 aPgAlignArea.Right() )
506 nAdjustedRelPosY = aPgAlignArea.Right() -
507 nTopOfAnch -
508 aObjSize.Width();
510 if ( nTopOfAnch + nAdjustedRelPosY < aPgAlignArea.Left() )
512 nAdjustedRelPosY = aPgAlignArea.Left() - nTopOfAnch;
516 else
518 // tdf#112443 if position is completely off-page
519 // return the proposed position and do not adjust it...
520 const bool bDisablePositioning = mpFrameFormat->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
522 // tdf#123002 disable the positioning in header and footer only
523 // we should limit this since anchors of body frames may appear on other pages
524 const bool bIsFooterOrHeader = GetAnchorFrame().GetUpper()
525 && (GetAnchorFrame().GetUpper()->IsFooterFrame() || GetAnchorFrame().GetUpper()->IsHeaderFrame() );
527 if ( bDisablePositioning && bIsFooterOrHeader && nTopOfAnch + nAdjustedRelPosY > aPgAlignArea.Bottom() )
529 return nProposedRelPosY;
532 // #i31805# - consider value of <bCheckBottom>
533 if ( bCheckBottom &&
534 nTopOfAnch + nAdjustedRelPosY + aObjSize.Height() >
535 aPgAlignArea.Top() + aPgAlignArea.Height() )
537 nAdjustedRelPosY = aPgAlignArea.Top() + aPgAlignArea.Height() -
538 nTopOfAnch -
539 aObjSize.Height();
541 if ( nTopOfAnch + nAdjustedRelPosY < aPgAlignArea.Top() )
543 nAdjustedRelPosY = aPgAlignArea.Top() - nTopOfAnch;
546 return nAdjustedRelPosY;
549 /** adjust calculated horizontal in order to keep object inside
550 'page' alignment layout frame.
552 #i62875# - method now private and renamed.
554 SwTwips SwAnchoredObjectPosition::ImplAdjustHoriRelPos(
555 const SwFrame& _rPageAlignLayFrame,
556 const SwTwips _nProposedRelPosX ) const
558 SwTwips nAdjustedRelPosX = _nProposedRelPosX;
560 if (SwAnchoredObject::IsDraggingOffPageAllowed(FindFrameFormat(&mrDrawObj)))
561 return nAdjustedRelPosX;
563 const SwFrame& rAnchorFrame = GetAnchorFrame();
564 const bool bVert = rAnchorFrame.IsVertical();
566 const Size aObjSize( GetAnchoredObj().GetObjRect().SSize() );
568 if( bVert )
570 if ( rAnchorFrame.getFrameArea().Top() + nAdjustedRelPosX + aObjSize.Height() >
571 _rPageAlignLayFrame.getFrameArea().Bottom() )
573 nAdjustedRelPosX = _rPageAlignLayFrame.getFrameArea().Bottom() -
574 rAnchorFrame.getFrameArea().Top() -
575 aObjSize.Height();
577 if ( rAnchorFrame.getFrameArea().Top() + nAdjustedRelPosX <
578 _rPageAlignLayFrame.getFrameArea().Top() )
580 nAdjustedRelPosX = _rPageAlignLayFrame.getFrameArea().Top() -
581 rAnchorFrame.getFrameArea().Top();
584 else
586 if ( rAnchorFrame.getFrameArea().Left() + nAdjustedRelPosX + aObjSize.Width() >
587 _rPageAlignLayFrame.getFrameArea().Right() )
589 nAdjustedRelPosX = _rPageAlignLayFrame.getFrameArea().Right() -
590 rAnchorFrame.getFrameArea().Left() -
591 aObjSize.Width();
593 if ( rAnchorFrame.getFrameArea().Left() + nAdjustedRelPosX <
594 _rPageAlignLayFrame.getFrameArea().Left() )
596 nAdjustedRelPosX = _rPageAlignLayFrame.getFrameArea().Left() -
597 rAnchorFrame.getFrameArea().Left();
601 return nAdjustedRelPosX;
604 /** determine alignment value for horizontal position of object */
605 void SwAnchoredObjectPosition::GetHoriAlignmentValues( const SwFrame& _rHoriOrientFrame,
606 const SwFrame& _rPageAlignLayFrame,
607 const sal_Int16 _eRelOrient,
608 const bool _bObjWrapThrough,
609 SwTwips& _orAlignAreaWidth,
610 SwTwips& _orAlignAreaOffset,
611 bool& _obAlignedRelToPage ) const
613 SwTwips nWidth = 0;
614 SwTwips nOffset = 0;
615 SwRectFnSet aRectFnSet(&_rHoriOrientFrame);
616 switch ( _eRelOrient )
618 case text::RelOrientation::PRINT_AREA:
620 nWidth = aRectFnSet.GetWidth(_rHoriOrientFrame.getFramePrintArea());
621 nOffset = aRectFnSet.GetLeftMargin(_rHoriOrientFrame);
622 if ( _rHoriOrientFrame.IsTextFrame() )
624 // consider movement of text frame left
625 nOffset += static_cast<const SwTextFrame&>(_rHoriOrientFrame).GetBaseOffsetForFly( !_bObjWrapThrough );
627 else if ( _rHoriOrientFrame.IsPageFrame() && aRectFnSet.IsVert() )
629 // for to-page anchored objects, consider header/footer frame
630 // in vertical layout
631 const SwFrame* pPrtFrame =
632 static_cast<const SwPageFrame&>(_rHoriOrientFrame).Lower();
633 while( pPrtFrame )
635 if( pPrtFrame->IsHeaderFrame() )
637 nWidth -= pPrtFrame->getFrameArea().Height();
638 nOffset += pPrtFrame->getFrameArea().Height();
640 else if( pPrtFrame->IsFooterFrame() )
642 nWidth -= pPrtFrame->getFrameArea().Height();
644 pPrtFrame = pPrtFrame->GetNext();
647 break;
649 case text::RelOrientation::PAGE_LEFT:
651 // align at left border of page frame/fly frame/cell frame
652 nWidth = aRectFnSet.GetLeftMargin(_rPageAlignLayFrame);
653 nOffset = aRectFnSet.XDiff(
654 aRectFnSet.GetLeft(_rPageAlignLayFrame.getFrameArea()),
655 aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea()) );
656 _obAlignedRelToPage = true;
658 break;
659 case text::RelOrientation::PAGE_RIGHT:
661 // align at right border of page frame/fly frame/cell frame
662 nWidth = aRectFnSet.GetRightMargin(_rPageAlignLayFrame);
663 nOffset = aRectFnSet.XDiff(
664 aRectFnSet.GetPrtRight(_rPageAlignLayFrame),
665 aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea()) );
666 _obAlignedRelToPage = true;
668 break;
669 case text::RelOrientation::FRAME_LEFT:
671 // align at left border of anchor frame
672 nWidth = aRectFnSet.GetLeftMargin(_rHoriOrientFrame);
673 nOffset = 0;
675 break;
676 case text::RelOrientation::FRAME_RIGHT:
678 // align at right border of anchor frame
679 // Unify and simplify
680 nWidth = aRectFnSet.GetRightMargin(_rHoriOrientFrame);
681 nOffset = aRectFnSet.GetRight(_rHoriOrientFrame.getFramePrintArea());
683 break;
684 case text::RelOrientation::CHAR:
686 // alignment relative to character - assure, that corresponding
687 // character rectangle is set.
688 if ( IsAnchoredToChar() )
690 nWidth = 0;
691 nOffset = aRectFnSet.XDiff(
692 aRectFnSet.GetLeft(*ToCharRect()),
693 aRectFnSet.GetLeft(ToCharOrientFrame()->getFrameArea()) );
694 break;
696 [[fallthrough]];
698 case text::RelOrientation::PAGE_PRINT_AREA:
700 nWidth = aRectFnSet.GetWidth(_rPageAlignLayFrame.getFramePrintArea());
701 nOffset = aRectFnSet.XDiff(
702 aRectFnSet.GetPrtLeft(_rPageAlignLayFrame),
703 aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea()) );
704 if ( _rHoriOrientFrame.IsPageFrame() && aRectFnSet.IsVert() )
706 // for to-page anchored objects, consider header/footer frame
707 // in vertical layout
708 const SwFrame* pPrtFrame =
709 static_cast<const SwPageFrame&>(_rHoriOrientFrame).Lower();
710 while( pPrtFrame )
712 if( pPrtFrame->IsHeaderFrame() )
714 nWidth -= pPrtFrame->getFrameArea().Height();
715 nOffset += pPrtFrame->getFrameArea().Height();
717 else if( pPrtFrame->IsFooterFrame() )
719 nWidth -= pPrtFrame->getFrameArea().Height();
721 pPrtFrame = pPrtFrame->GetNext();
724 _obAlignedRelToPage = true;
725 break;
727 case text::RelOrientation::PAGE_FRAME:
729 nWidth = aRectFnSet.GetWidth(_rPageAlignLayFrame.getFrameArea());
730 nOffset = aRectFnSet.XDiff(
731 aRectFnSet.GetLeft(_rPageAlignLayFrame.getFrameArea()),
732 aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea()) );
733 _obAlignedRelToPage = true;
734 break;
736 default:
738 nWidth = aRectFnSet.GetWidth(_rHoriOrientFrame.getFrameArea());
740 bool bWrapThrough = _bObjWrapThrough;
741 // If the frame format is a TextBox of a draw shape, then use the
742 // surround of the original shape.
743 SwTextBoxHelper::getShapeWrapThrough(mpFrameFormat, bWrapThrough);
745 bool bIgnoreFlysAnchoredAtFrame = !bWrapThrough;
746 nOffset = _rHoriOrientFrame.IsTextFrame() ?
747 static_cast<const SwTextFrame&>(_rHoriOrientFrame).GetBaseOffsetForFly( bIgnoreFlysAnchoredAtFrame ) :
749 break;
753 _orAlignAreaWidth = nWidth;
754 _orAlignAreaOffset = nOffset;
757 /** toggle given horizontal orientation and relative alignment */
758 void SwAnchoredObjectPosition::ToggleHoriOrientAndAlign(
759 const bool _bToggleLeftRight,
760 sal_Int16& _ioeHoriOrient,
761 sal_Int16& _iopeRelOrient
764 if( !_bToggleLeftRight )
765 return;
767 // toggle orientation
768 switch ( _ioeHoriOrient )
770 case text::HoriOrientation::RIGHT :
772 _ioeHoriOrient = text::HoriOrientation::LEFT;
774 break;
775 case text::HoriOrientation::LEFT :
777 _ioeHoriOrient = text::HoriOrientation::RIGHT;
779 break;
780 default:
781 break;
784 // toggle relative alignment
785 switch ( _iopeRelOrient )
787 case text::RelOrientation::PAGE_RIGHT :
789 _iopeRelOrient = text::RelOrientation::PAGE_LEFT;
791 break;
792 case text::RelOrientation::PAGE_LEFT :
794 _iopeRelOrient = text::RelOrientation::PAGE_RIGHT;
796 break;
797 case text::RelOrientation::FRAME_RIGHT :
799 _iopeRelOrient = text::RelOrientation::FRAME_LEFT;
801 break;
802 case text::RelOrientation::FRAME_LEFT :
804 _iopeRelOrient = text::RelOrientation::FRAME_RIGHT;
806 break;
807 default:
808 break;
812 /** calculate relative horizontal position */
813 SwTwips SwAnchoredObjectPosition::CalcRelPosX(
814 const SwFrame& _rHoriOrientFrame,
815 const SwEnvironmentOfAnchoredObject& _rEnvOfObj,
816 const SwFormatHoriOrient& _rHoriOrient,
817 const SvxLRSpaceItem& _rLRSpacing,
818 const SvxULSpaceItem& _rULSpacing,
819 const bool _bObjWrapThrough,
820 const SwTwips _nRelPosY,
821 SwTwips& _roHoriOffsetToFrameAnchorPos
822 ) const
824 // determine 'page' alignment layout frame
825 const SwFrame& rPageAlignLayFrame =
826 _rEnvOfObj.GetHoriEnvironmentLayoutFrame( _rHoriOrientFrame );
828 const bool bEvenPage = !rPageAlignLayFrame.OnRightPage();
829 const bool bToggle = _rHoriOrient.IsPosToggle() && bEvenPage;
831 // determine orientation and relative alignment
832 sal_Int16 eHoriOrient = _rHoriOrient.GetHoriOrient();
833 sal_Int16 eRelOrient = _rHoriOrient.GetRelationOrient();
834 // toggle orientation and relative alignment
835 ToggleHoriOrientAndAlign( bToggle, eHoriOrient, eRelOrient );
837 // determine alignment parameter
838 // <nWidth>: 'width' of alignment area
839 // <nOffset>: offset of alignment area, relative to 'left' of anchor frame
840 SwTwips nWidth = 0;
841 SwTwips nOffset = 0;
842 bool bAlignedRelToPage = false;
843 GetHoriAlignmentValues( _rHoriOrientFrame, rPageAlignLayFrame,
844 eRelOrient, _bObjWrapThrough,
845 nWidth, nOffset, bAlignedRelToPage );
847 const SwFrame& rAnchorFrame = GetAnchorFrame();
848 SwRectFnSet aRectFnSet(&_rHoriOrientFrame);
849 SwTwips nObjWidth = aRectFnSet.GetWidth(GetAnchoredObj().GetObjRect());
850 SwTwips nRelPosX = nOffset;
851 if ( _rHoriOrient.GetHoriOrient() == text::HoriOrientation::NONE )
853 // 'manual' horizontal position
854 const bool bR2L = rAnchorFrame.IsRightToLeft();
855 if( IsAnchoredToChar() && text::RelOrientation::CHAR == eRelOrient )
857 if( bR2L )
858 nRelPosX -= _rHoriOrient.GetPos();
859 else
860 nRelPosX += _rHoriOrient.GetPos();
862 else if ( bToggle || ( !_rHoriOrient.IsPosToggle() && bR2L ) )
864 // Correction: consider <nOffset> also for
865 // toggling from left to right.
866 nRelPosX += nWidth - nObjWidth - _rHoriOrient.GetPos();
868 else
870 nRelPosX += _rHoriOrient.GetPos();
873 else if ( text::HoriOrientation::CENTER == eHoriOrient )
874 nRelPosX += (nWidth / 2) - (nObjWidth / 2);
875 else if ( text::HoriOrientation::RIGHT == eHoriOrient )
876 nRelPosX += nWidth -
877 ( nObjWidth +
878 ( aRectFnSet.IsVert() ? _rULSpacing.GetLower() : _rLRSpacing.GetRight() ) );
879 else
880 nRelPosX += aRectFnSet.IsVert() ? _rULSpacing.GetUpper() : _rLRSpacing.GetLeft();
882 // adjust relative position by distance between anchor frame and
883 // the frame, the object is oriented at.
884 if ( &rAnchorFrame != &_rHoriOrientFrame )
886 SwTwips nLeftOrient = aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea());
887 SwTwips nLeftAnchor = aRectFnSet.GetLeft(rAnchorFrame.getFrameArea());
888 nRelPosX += aRectFnSet.XDiff( nLeftOrient, nLeftAnchor );
891 // adjust calculated relative horizontal position, in order to
892 // keep object inside 'page' alignment layout frame
893 const SwFrame& rEnvironmentLayFrame =
894 _rEnvOfObj.GetHoriEnvironmentLayoutFrame( _rHoriOrientFrame );
895 bool bFollowTextFlow = GetFrameFormat().GetFollowTextFlow().GetValue();
896 bool bWrapThrough = GetFrameFormat().GetSurround().GetSurround() != text::WrapTextMode_THROUGH;
897 // Don't try to keep wrap-though objects inside the cell, even if they are following text flow.
898 if (!rEnvironmentLayFrame.IsInTab() || !bFollowTextFlow || bWrapThrough)
900 nRelPosX = AdjustHoriRelPos( rEnvironmentLayFrame, nRelPosX );
903 // if object is a Writer fly frame and it's anchored to a content and
904 // it is horizontal positioned left or right, but not relative to character,
905 // it has to be drawn aside another object, which have the same horizontal
906 // position and lay below it.
907 if ( dynamic_cast<const SwFlyFrame*>( &GetAnchoredObj() ) != nullptr &&
908 ( mpContact->ObjAnchoredAtPara() || mpContact->ObjAnchoredAtChar() ) &&
909 ( eHoriOrient == text::HoriOrientation::LEFT || eHoriOrient == text::HoriOrientation::RIGHT ) &&
910 eRelOrient != text::RelOrientation::CHAR )
912 nRelPosX = AdjustHoriRelPosForDrawAside( _rHoriOrientFrame,
913 nRelPosX, _nRelPosY,
914 eHoriOrient, eRelOrient,
915 _rLRSpacing, _rULSpacing,
916 bEvenPage );
919 // #i26791#
920 _roHoriOffsetToFrameAnchorPos = nOffset;
922 return nRelPosX;
925 // method incl. helper methods for adjusting proposed horizontal position,
926 // if object has to draw aside another object.
927 /** adjust calculated horizontal position in order to draw object
928 aside other objects with same positioning
930 SwTwips SwAnchoredObjectPosition::AdjustHoriRelPosForDrawAside(
931 const SwFrame& _rHoriOrientFrame,
932 const SwTwips _nProposedRelPosX,
933 const SwTwips _nRelPosY,
934 const sal_Int16 _eHoriOrient,
935 const sal_Int16 _eRelOrient,
936 const SvxLRSpaceItem& _rLRSpacing,
937 const SvxULSpaceItem& _rULSpacing,
938 const bool _bEvenPage
939 ) const
941 // #i26791#
942 if ( dynamic_cast<const SwTextFrame*>( &GetAnchorFrame() ) == nullptr ||
943 dynamic_cast<const SwFlyAtContentFrame*>( &GetAnchoredObj() ) == nullptr )
945 OSL_FAIL( "<SwAnchoredObjectPosition::AdjustHoriRelPosForDrawAside(..) - usage for wrong anchor type" );
946 return _nProposedRelPosX;
949 const SwTextFrame& rAnchorTextFrame = static_cast<const SwTextFrame&>(GetAnchorFrame());
950 // #i26791#
951 const SwFlyAtContentFrame& rFlyAtContentFrame =
952 static_cast<const SwFlyAtContentFrame&>(GetAnchoredObj());
953 const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() );
954 SwRectFnSet aRectFnSet(&_rHoriOrientFrame);
956 SwTwips nAdjustedRelPosX = _nProposedRelPosX;
958 // determine proposed object bound rectangle
959 Point aTmpPos = aRectFnSet.GetPos(rAnchorTextFrame.getFrameArea());
960 if( aRectFnSet.IsVert() )
962 aTmpPos.AdjustX( -(_nRelPosY + aObjBoundRect.Width()) );
963 aTmpPos.AdjustY(nAdjustedRelPosX );
965 else
967 aTmpPos.AdjustX(nAdjustedRelPosX );
968 aTmpPos.AdjustY(_nRelPosY );
970 SwRect aTmpObjRect( aTmpPos, aObjBoundRect.SSize() );
972 const sal_uInt32 nObjOrdNum = GetObject().GetOrdNum();
973 const SwPageFrame* pObjPage = rFlyAtContentFrame.FindPageFrame();
974 const SwFrame* pObjContext = ::FindContext( &rAnchorTextFrame, SwFrameType::Column );
975 sal_uLong nObjIndex = rAnchorTextFrame.GetTextNodeFirst()->GetIndex();
976 SwOrderIter aIter( pObjPage );
977 const SwFlyFrame* pFly = static_cast<const SwVirtFlyDrawObj*>(aIter.Bottom())->GetFlyFrame();
978 while ( pFly && nObjOrdNum > pFly->GetVirtDrawObj()->GetOrdNumDirect() )
980 if ( DrawAsideFly( pFly, aTmpObjRect, pObjContext, nObjIndex,
981 _bEvenPage, _eHoriOrient, _eRelOrient ) )
983 if( aRectFnSet.IsVert() )
985 const SvxULSpaceItem& rOtherUL = pFly->GetFormat()->GetULSpace();
986 const SwTwips nOtherTop = pFly->getFrameArea().Top() - rOtherUL.GetUpper();
987 const SwTwips nOtherBot = pFly->getFrameArea().Bottom() + rOtherUL.GetLower();
988 if ( nOtherTop <= aTmpObjRect.Bottom() + _rULSpacing.GetLower() &&
989 nOtherBot >= aTmpObjRect.Top() - _rULSpacing.GetUpper() )
991 if ( _eHoriOrient == text::HoriOrientation::LEFT )
993 SwTwips nTmp = nOtherBot + 1 + _rULSpacing.GetUpper() -
994 rAnchorTextFrame.getFrameArea().Top();
995 if ( nTmp > nAdjustedRelPosX &&
996 rAnchorTextFrame.getFrameArea().Top() + nTmp +
997 aObjBoundRect.Height() + _rULSpacing.GetLower()
998 <= pObjPage->getFrameArea().Height() + pObjPage->getFrameArea().Top() )
1000 nAdjustedRelPosX = nTmp;
1003 else if ( _eHoriOrient == text::HoriOrientation::RIGHT )
1005 SwTwips nTmp = nOtherTop - 1 - _rULSpacing.GetLower() -
1006 aObjBoundRect.Height() -
1007 rAnchorTextFrame.getFrameArea().Top();
1008 if ( nTmp < nAdjustedRelPosX &&
1009 rAnchorTextFrame.getFrameArea().Top() + nTmp - _rULSpacing.GetUpper()
1010 >= pObjPage->getFrameArea().Top() )
1012 nAdjustedRelPosX = nTmp;
1015 aTmpObjRect.Pos().setY( rAnchorTextFrame.getFrameArea().Top() +
1016 nAdjustedRelPosX );
1019 else
1021 const SvxLRSpaceItem& rOtherLR = pFly->GetFormat()->GetLRSpace();
1022 const SwTwips nOtherLeft = pFly->getFrameArea().Left() - rOtherLR.GetLeft();
1023 const SwTwips nOtherRight = pFly->getFrameArea().Right() + rOtherLR.GetRight();
1024 if( nOtherLeft <= aTmpObjRect.Right() + _rLRSpacing.GetRight() &&
1025 nOtherRight >= aTmpObjRect.Left() - _rLRSpacing.GetLeft() )
1027 if ( _eHoriOrient == text::HoriOrientation::LEFT )
1029 SwTwips nTmp = nOtherRight + 1 + _rLRSpacing.GetLeft() -
1030 rAnchorTextFrame.getFrameArea().Left();
1031 if ( nTmp > nAdjustedRelPosX &&
1032 rAnchorTextFrame.getFrameArea().Left() + nTmp +
1033 aObjBoundRect.Width() + _rLRSpacing.GetRight()
1034 <= pObjPage->getFrameArea().Width() + pObjPage->getFrameArea().Left() )
1036 nAdjustedRelPosX = nTmp;
1039 else if ( _eHoriOrient == text::HoriOrientation::RIGHT )
1041 SwTwips nTmp = nOtherLeft - 1 - _rLRSpacing.GetRight() -
1042 aObjBoundRect.Width() -
1043 rAnchorTextFrame.getFrameArea().Left();
1044 if ( nTmp < nAdjustedRelPosX &&
1045 rAnchorTextFrame.getFrameArea().Left() + nTmp - _rLRSpacing.GetLeft()
1046 >= pObjPage->getFrameArea().Left() )
1048 nAdjustedRelPosX = nTmp;
1051 aTmpObjRect.Pos().setX( rAnchorTextFrame.getFrameArea().Left() +
1052 nAdjustedRelPosX );
1054 } // end of <if (bVert)>
1055 } // end of <if DrawAsideFly(..)>
1057 pFly = static_cast<const SwVirtFlyDrawObj*>(aIter.Next())->GetFlyFrame();
1058 } // end of <loop on fly frames
1060 return nAdjustedRelPosX;
1063 /** determine, if object has to draw aside given fly frame
1065 method used by <AdjustHoriRelPosForDrawAside(..)>
1067 bool SwAnchoredObjectPosition::DrawAsideFly( const SwFlyFrame* _pFly,
1068 const SwRect& _rObjRect,
1069 const SwFrame* _pObjContext,
1070 const sal_uLong _nObjIndex,
1071 const bool _bEvenPage,
1072 const sal_Int16 _eHoriOrient,
1073 const sal_Int16 _eRelOrient
1074 ) const
1076 bool bRetVal = false;
1078 SwRectFnSet aRectFnSet(&GetAnchorFrame());
1080 if ( _pFly->IsFlyAtContentFrame() &&
1081 aRectFnSet.BottomDist( _pFly->getFrameArea(), aRectFnSet.GetTop(_rObjRect) ) < 0 &&
1082 aRectFnSet.BottomDist( _rObjRect, aRectFnSet.GetTop(_pFly->getFrameArea()) ) < 0 &&
1083 ::FindContext( _pFly->GetAnchorFrame(), SwFrameType::Column ) == _pObjContext )
1085 sal_uLong nOtherIndex =
1086 static_cast<const SwTextFrame*>(_pFly->GetAnchorFrame())->GetTextNodeFirst()->GetIndex();
1087 if (sw::FrameContainsNode(static_cast<SwTextFrame const&>(*_pFly->GetAnchorFrame()), _nObjIndex)
1088 || nOtherIndex < _nObjIndex)
1090 const SwFormatHoriOrient& rHori = _pFly->GetFormat()->GetHoriOrient();
1091 sal_Int16 eOtherRelOrient = rHori.GetRelationOrient();
1092 if( text::RelOrientation::CHAR != eOtherRelOrient )
1094 sal_Int16 eOtherHoriOrient = rHori.GetHoriOrient();
1095 ToggleHoriOrientAndAlign( _bEvenPage && rHori.IsPosToggle(),
1096 eOtherHoriOrient,
1097 eOtherRelOrient );
1098 if ( eOtherHoriOrient == _eHoriOrient &&
1099 Minor_( _eRelOrient, eOtherRelOrient, text::HoriOrientation::LEFT == _eHoriOrient ) )
1101 bRetVal = true;
1107 return bRetVal;
1110 /** determine, if object has to draw aside another object
1112 the different alignments of the objects determines, if one has
1113 to draw aside another one. Thus, the given alignment are checked
1114 against each other, which one has to be drawn aside the other one.
1115 depending on parameter _bLeft check is done for left or right
1116 positioning.
1117 method used by <DrawAsideFly(..)>
1119 bool SwAnchoredObjectPosition::Minor_( sal_Int16 _eRelOrient1,
1120 sal_Int16 _eRelOrient2,
1121 bool _bLeft )
1123 bool bRetVal;
1125 // draw aside order for left horizontal position
1126 //! one array entry for each value in text::RelOrientation
1127 static sal_uInt16 const aLeft[ 10 ] =
1128 { 5, 6, 0, 1, 8, 4, 7, 2, 3, 9 };
1129 // draw aside order for right horizontal position
1130 //! one array entry for each value in text::RelOrientation
1131 static sal_uInt16 const aRight[ 10 ] =
1132 { 5, 6, 0, 8, 1, 7, 4, 2, 3, 9 };
1134 // decide depending on given order, which frame has to draw aside another frame
1135 if( _bLeft )
1136 bRetVal = aLeft[ _eRelOrient1 ] >= aLeft[ _eRelOrient2 ];
1137 else
1138 bRetVal = aRight[ _eRelOrient1 ] >= aRight[ _eRelOrient2 ];
1140 return bRetVal;
1143 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */