android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / objectpositioning / anchoredobjectposition.cxx
blobe530e36df36569aba2de04b5eeee6ad7ece00412
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 <fmtfollowtextflow.hxx>
34 #include <editeng/lrspitem.hxx>
35 #include <editeng/ulspitem.hxx>
36 #include <ndtxt.hxx>
37 #include <IDocumentSettingAccess.hxx>
38 #include <textboxhelper.hxx>
39 #include <fmtsrnd.hxx>
40 #include <osl/diagnose.h>
42 using namespace ::com::sun::star;
44 namespace objectpositioning
47 SwAnchoredObjectPosition::SwAnchoredObjectPosition( SdrObject& _rDrawObj )
48 : mrDrawObj( _rDrawObj ),
49 mpAnchoredObj( nullptr ),
50 mpAnchorFrame( nullptr ),
51 mpContact( nullptr ),
52 mbIsObjFly( false ),
53 // #i62875#
54 mbFollowTextFlow( false ),
55 mbDoNotCaptureAnchoredObj( false )
57 #if OSL_DEBUG_LEVEL > 0
58 // assert, if object isn't of expected type
59 const bool bObjOfExceptedType =
60 dynamic_cast<const SwVirtFlyDrawObj*>( &mrDrawObj) != nullptr || // object representing fly frame
61 dynamic_cast<const SwDrawVirtObj*>( &mrDrawObj) != nullptr || // 'virtual' drawing object
62 ( dynamic_cast<const SdrVirtObj*>( &mrDrawObj) == nullptr && // 'master' drawing object
63 dynamic_cast<const SwFlyDrawObj*>( &mrDrawObj) == nullptr ); // - indirectly checked
64 OSL_ENSURE( bObjOfExceptedType,
65 "SwAnchoredObjectPosition(..) - object of unexpected type!" );
66 #endif
68 GetInfoAboutObj();
71 /** determine information about object
73 members <mbIsObjFly>, <mpFrameOfObj>, <mpAnchorFrame>, <mpContact>,
74 <mbFollowTextFlow> and <mbDoNotCaptureAnchoredObj> are set
76 void SwAnchoredObjectPosition::GetInfoAboutObj()
78 // determine, if object represents a fly frame
80 mbIsObjFly = dynamic_cast<const SwVirtFlyDrawObj*>( &mrDrawObj) != nullptr;
83 // determine contact object
85 mpContact = GetUserCall( &mrDrawObj );
86 assert(mpContact &&
87 "SwAnchoredObjectPosition::GetInfoAboutObj() - missing SwContact-object.");
90 // determine anchored object, the object belongs to
92 // #i26791#
93 mpAnchoredObj = mpContact->GetAnchoredObj( &mrDrawObj );
94 assert(mpAnchoredObj &&
95 "SwAnchoredObjectPosition::GetInfoAboutObj() - missing anchored object.");
98 // determine frame, the object is anchored at
100 // #i26791#
101 mpAnchorFrame = mpAnchoredObj->AnchorFrame();
102 OSL_ENSURE( mpAnchorFrame,
103 "SwAnchoredObjectPosition::GetInfoAboutObj() - missing anchor frame." );
106 // determine format the object belongs to
108 // #i28701#
109 mpFrameFormat = &mpAnchoredObj->GetFrameFormat();
110 assert(mpFrameFormat &&
111 "<SwAnchoredObjectPosition::GetInfoAboutObj() - missing frame format.");
114 // #i62875# - determine attribute value of <Follow-Text-Flow>
116 mbFollowTextFlow = mpFrameFormat->GetFollowTextFlow().GetValue();
119 // determine, if anchored object has not to be captured on the page.
120 // the following conditions must be hold to *not* capture it:
121 // - corresponding document compatibility flag is set
122 // - it's a drawing object or it's a non-textbox wrap-though fly frame
123 // - it doesn't follow the text flow
125 bool bTextBox = SwTextBoxHelper::isTextBox(mpFrameFormat, RES_FLYFRMFMT);
126 bool bWrapThrough = mpFrameFormat->GetSurround().GetSurround() == css::text::WrapTextMode_THROUGH;
127 mbDoNotCaptureAnchoredObj = (!mbIsObjFly || (!bTextBox && bWrapThrough)) && !mbFollowTextFlow &&
128 mpFrameFormat->getIDocumentSettingAccess().get(DocumentSettingId::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE);
132 SwAnchoredObjectPosition::~SwAnchoredObjectPosition()
135 bool SwAnchoredObjectPosition::IsAnchoredToChar() const
137 return false;
140 const SwFrame* SwAnchoredObjectPosition::ToCharOrientFrame() const
142 return nullptr;
145 const SwRect* SwAnchoredObjectPosition::ToCharRect() const
147 return nullptr;
150 // #i22341#
151 SwTwips SwAnchoredObjectPosition::ToCharTopOfLine() const
153 return 0;
156 /** helper method to determine top of a frame for the vertical
157 object positioning
159 #i11860#
161 SwTwips SwAnchoredObjectPosition::GetTopForObjPos( const SwFrame& _rFrame,
162 const SwRectFn& _fnRect,
163 const bool _bVert ) const
165 SwTwips nTopOfFrameForObjPos = (_rFrame.getFrameArea().*_fnRect->fnGetTop)();
167 if ( _rFrame.IsTextFrame() )
169 const SwTextFrame& rTextFrame = static_cast<const SwTextFrame&>(_rFrame);
170 if ( _bVert )
172 nTopOfFrameForObjPos -=
173 rTextFrame.GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
175 else
177 nTopOfFrameForObjPos +=
178 rTextFrame.GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
180 const SwFormatSurround& rSurround = mpFrameFormat->GetSurround();
181 bool bWrapThrough = rSurround.GetSurround() == css::text::WrapTextMode_THROUGH;
182 // If the frame format is a TextBox of a draw shape, then use the
183 // surround of the original shape.
184 SwTextBoxHelper::getShapeWrapThrough(mpFrameFormat, bWrapThrough);
186 // Get the offset between the top of the text frame and the top of
187 // the first line inside the frame that has more than just fly
188 // portions.
189 nTopOfFrameForObjPos += rTextFrame.GetBaseVertOffsetForFly(!bWrapThrough);
193 return nTopOfFrameForObjPos;
196 void SwAnchoredObjectPosition::GetVertAlignmentValues(
197 const SwFrame& _rVertOrientFrame,
198 const SwFrame& _rPageAlignLayFrame,
199 const sal_Int16 _eRelOrient,
200 SwTwips& _orAlignAreaHeight,
201 SwTwips& _orAlignAreaOffset ) const
203 SwTwips nHeight = 0;
204 SwTwips nOffset = 0;
205 SwRectFnSet aRectFnSet(&_rVertOrientFrame);
206 // #i11860# - top of <_rVertOrientFrame> for object positioning
207 const SwTwips nVertOrientTop = GetTopForObjPos( _rVertOrientFrame, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
208 // #i11860# - upper space amount of <_rVertOrientFrame> considered
209 // for previous frame
210 const SwTwips nVertOrientUpperSpaceForPrevFrameAndPageGrid =
211 _rVertOrientFrame.IsTextFrame()
212 ? static_cast<const SwTextFrame&>(_rVertOrientFrame).
213 GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid()
214 : 0;
215 switch ( _eRelOrient )
217 case text::RelOrientation::FRAME:
219 // #i11860# - consider upper space of previous frame
220 nHeight = aRectFnSet.GetHeight(_rVertOrientFrame.getFrameArea()) -
221 nVertOrientUpperSpaceForPrevFrameAndPageGrid;
222 nOffset = 0;
224 break;
225 case text::RelOrientation::PRINT_AREA:
227 nHeight = aRectFnSet.GetHeight(_rVertOrientFrame.getFramePrintArea());
228 // #i11860# - consider upper space of previous frame
229 nOffset = aRectFnSet.GetTopMargin(_rVertOrientFrame) -
230 nVertOrientUpperSpaceForPrevFrameAndPageGrid;
231 // if aligned to page in horizontal layout, consider header and
232 // footer frame height appropriately.
233 if( _rVertOrientFrame.IsPageFrame() && !aRectFnSet.IsVert() )
235 const SwFrame* pPrtFrame =
236 static_cast<const SwPageFrame&>(_rVertOrientFrame).Lower();
237 while( pPrtFrame )
239 if( pPrtFrame->IsHeaderFrame() )
241 nHeight -= pPrtFrame->getFrameArea().Height();
242 nOffset += pPrtFrame->getFrameArea().Height();
244 else if( pPrtFrame->IsFooterFrame() )
246 nHeight -= pPrtFrame->getFrameArea().Height();
248 pPrtFrame = pPrtFrame->GetNext();
252 break;
253 case text::RelOrientation::PAGE_FRAME:
254 case text::RelOrientation::PAGE_PRINT_AREA_TOP:
256 nHeight = aRectFnSet.GetHeight(_rPageAlignLayFrame.getFrameArea());
257 nOffset = aRectFnSet.YDiff(
258 aRectFnSet.GetTop(_rPageAlignLayFrame.getFrameArea()),
259 nVertOrientTop );
261 break;
262 case text::RelOrientation::PAGE_PRINT_AREA:
264 nHeight = aRectFnSet.GetHeight(_rPageAlignLayFrame.getFramePrintArea());
265 nOffset = aRectFnSet.GetTopMargin(_rPageAlignLayFrame) +
266 aRectFnSet.YDiff(
267 aRectFnSet.GetTop(_rPageAlignLayFrame.getFrameArea()),
268 nVertOrientTop );
269 // if aligned to page in horizontal layout, consider header and
270 // footer frame height appropriately.
271 if( _rPageAlignLayFrame.IsPageFrame() && !aRectFnSet.IsVert() )
273 const SwFrame* pPrtFrame =
274 static_cast<const SwPageFrame&>(_rPageAlignLayFrame).Lower();
275 while( pPrtFrame )
277 if( pPrtFrame->IsHeaderFrame() )
279 nHeight -= pPrtFrame->getFrameArea().Height();
280 nOffset += pPrtFrame->getFrameArea().Height();
282 else if( pPrtFrame->IsFooterFrame() )
284 nHeight -= pPrtFrame->getFrameArea().Height();
286 pPrtFrame = pPrtFrame->GetNext();
290 break;
291 case text::RelOrientation::PAGE_PRINT_AREA_BOTTOM:
293 nHeight = aRectFnSet.GetBottomMargin(_rPageAlignLayFrame);
294 nOffset = aRectFnSet.YDiff(
295 aRectFnSet.GetPrtBottom(_rPageAlignLayFrame),
296 nVertOrientTop);
298 if (_rPageAlignLayFrame.IsPageFrame() && !aRectFnSet.IsVert())
300 const SwFrame* pPrtFrame =
301 static_cast<const SwPageFrame&>(_rPageAlignLayFrame).Lower();
303 while (pPrtFrame)
305 if (pPrtFrame->IsFooterFrame())
307 nHeight += pPrtFrame->getFrameArea().Height();
308 nOffset -= pPrtFrame->getFrameArea().Height();
310 pPrtFrame = pPrtFrame->GetNext();
315 break;
316 // #i22341# - vertical alignment at top of line
317 case text::RelOrientation::TEXT_LINE:
319 if ( IsAnchoredToChar() )
321 nHeight = 0;
322 nOffset = aRectFnSet.YDiff( ToCharTopOfLine(), nVertOrientTop );
324 else
326 OSL_FAIL( "<SwAnchoredObjectPosition::GetVertAlignmentValues(..)> - invalid relative alignment" );
329 break;
330 case text::RelOrientation::CHAR:
332 if ( IsAnchoredToChar() )
334 nHeight = aRectFnSet.GetHeight(*ToCharRect());
335 nOffset = aRectFnSet.YDiff( aRectFnSet.GetTop(*ToCharRect()),
336 nVertOrientTop );
338 else
340 OSL_FAIL( "<SwAnchoredObjectPosition::GetVertAlignmentValues(..)> - invalid relative alignment" );
343 break;
344 // no break here, because text::RelOrientation::CHAR is invalid, if !mbAnchorToChar
345 default:
347 OSL_FAIL( "<SwAnchoredObjectPosition::GetVertAlignmentValues(..)> - invalid relative alignment" );
351 _orAlignAreaHeight = nHeight;
352 _orAlignAreaOffset = nOffset;
355 // #i26791# - add output parameter <_roVertOffsetToFrameAnchorPos>
356 SwTwips SwAnchoredObjectPosition::GetVertRelPos(
357 const SwFrame& _rVertOrientFrame,
358 const SwFrame& _rPageAlignLayFrame,
359 const sal_Int16 _eVertOrient,
360 const sal_Int16 _eRelOrient,
361 const SwTwips _nVertPos,
362 const SvxLRSpaceItem& _rLRSpacing,
363 const SvxULSpaceItem& _rULSpacing,
364 SwTwips& _roVertOffsetToFrameAnchorPos ) const
366 SwTwips nRelPosY = 0;
367 SwRectFnSet aRectFnSet(&_rVertOrientFrame);
369 SwTwips nAlignAreaHeight;
370 SwTwips nAlignAreaOffset;
371 GetVertAlignmentValues( _rVertOrientFrame, _rPageAlignLayFrame,
372 _eRelOrient, nAlignAreaHeight, nAlignAreaOffset );
374 nRelPosY = nAlignAreaOffset;
375 const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() );
376 const SwTwips nObjHeight = aRectFnSet.GetHeight(aObjBoundRect);
378 switch ( _eVertOrient )
380 case text::VertOrientation::NONE:
382 // 'manual' vertical position
383 nRelPosY += _nVertPos;
385 break;
386 case text::VertOrientation::TOP:
388 nRelPosY += aRectFnSet.IsVert()
389 ? ( aRectFnSet.IsVertL2R()
390 ? _rLRSpacing.GetLeft()
391 : _rLRSpacing.GetRight() )
392 : _rULSpacing.GetUpper();
394 break;
395 case text::VertOrientation::CENTER:
397 nRelPosY += (nAlignAreaHeight / 2) - (nObjHeight / 2);
399 break;
400 case text::VertOrientation::BOTTOM:
402 nRelPosY += nAlignAreaHeight -
403 ( nObjHeight + ( aRectFnSet.IsVert()
404 ? ( aRectFnSet.IsVertL2R()
405 ? _rLRSpacing.GetRight()
406 : _rLRSpacing.GetLeft() )
407 : _rULSpacing.GetLower() ) );
409 break;
410 default:
412 OSL_FAIL( "<SwAnchoredObjectPosition::GetVertRelPos(..) - invalid vertical positioning" );
416 // #i26791#
417 _roVertOffsetToFrameAnchorPos = nAlignAreaOffset;
419 return nRelPosY;
422 /** adjust calculated vertical in order to keep object inside
423 'page' alignment layout frame.
425 #i28701# - parameter <_nTopOfAnch> and <_bVert> added
426 #i31805# - add parameter <_bCheckBottom>
427 #i26945# - add parameter <_bFollowTextFlow>
428 #i62875# - method now private and renamed.
429 OD 2009-09-01 #mongolianlayout# - add parameter <bVertL2R>
431 SwTwips SwAnchoredObjectPosition::ImplAdjustVertRelPos( const SwTwips nTopOfAnch,
432 const bool bVert,
433 const bool bVertL2R,
434 const SwFrame& rPageAlignLayFrame,
435 const SwTwips nProposedRelPosY,
436 const bool bFollowTextFlow,
437 const bool bCheckBottom ) const
439 SwTwips nAdjustedRelPosY = nProposedRelPosY;
440 // TODO: Replace the following condition with the correction
441 // of the implementation of option FollowTextFlow.
442 if ( SwAnchoredObject::IsDraggingOffPageAllowed(FindFrameFormat(&mrDrawObj)) &&
443 !(GetAnchorFrame().IsInTab() && DoesObjFollowsTextFlow()) )
445 return nAdjustedRelPosY;
448 const Size aObjSize(GetAnchoredObj().GetObjRect().SSize());
449 // determine the area of 'page' alignment frame, to which the vertical
450 // position is restricted.
451 // #i28701# - Extend restricted area for the vertical
452 // position to area of the page frame, if wrapping style influence is
453 // considered on object positioning. Needed to avoid layout loops in the
454 // object positioning algorithm considering the wrapping style influence
455 // caused by objects, which follow the text flow and thus are restricted
456 // to its environment (e.g. page header/footer).
457 SwRect aPgAlignArea;
459 // #i26945# - no extension of restricted area, if
460 // object's attribute follow text flow is set and its inside a table
461 if ( GetFrameFormat().getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) &&
462 ( !bFollowTextFlow ||
463 !GetAnchoredObj().GetAnchorFrame()->IsInTab() ) )
465 aPgAlignArea = rPageAlignLayFrame.FindPageFrame()->getFrameArea();
467 else
469 aPgAlignArea = rPageAlignLayFrame.getFrameArea();
473 if ( bVert )
475 // #i31805# - consider value of <_bCheckBottom>
476 if ( !bVertL2R )
478 if ( bCheckBottom &&
479 nTopOfAnch - nAdjustedRelPosY - aObjSize.Width() <
480 aPgAlignArea.Left() )
482 nAdjustedRelPosY = aPgAlignArea.Left() +
483 nTopOfAnch -
484 aObjSize.Width();
486 // #i32964# - correction
487 if ( nTopOfAnch - nAdjustedRelPosY > aPgAlignArea.Right() )
489 nAdjustedRelPosY = nTopOfAnch - aPgAlignArea.Right();
492 else
494 // tdf#112443 if position is completely off-page
495 // return the proposed position and do not adjust it...
496 // tdf#120839 .. unless anchored to char (anchor can jump on other page)
497 const bool bDisablePositioning = mpFrameFormat->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
498 if ( bDisablePositioning && !IsAnchoredToChar() && nTopOfAnch + nAdjustedRelPosY > aPgAlignArea.Right() )
500 return nProposedRelPosY;
503 if ( bCheckBottom &&
504 nTopOfAnch + nAdjustedRelPosY + aObjSize.Width() >
505 aPgAlignArea.Right() )
507 nAdjustedRelPosY = aPgAlignArea.Right() -
508 nTopOfAnch -
509 aObjSize.Width();
511 if ( nTopOfAnch + nAdjustedRelPosY < aPgAlignArea.Left() )
513 nAdjustedRelPosY = aPgAlignArea.Left() - nTopOfAnch;
517 else
519 // tdf#112443 if position is completely off-page
520 // return the proposed position and do not adjust it...
521 const bool bDisablePositioning = mpFrameFormat->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
523 // tdf#123002 disable the positioning in header and footer only
524 // we should limit this since anchors of body frames may appear on other pages
525 const bool bIsFooterOrHeader = GetAnchorFrame().GetUpper()
526 && (GetAnchorFrame().GetUpper()->IsFooterFrame() || GetAnchorFrame().GetUpper()->IsHeaderFrame() );
528 if ( bDisablePositioning && bIsFooterOrHeader && nTopOfAnch + nAdjustedRelPosY > aPgAlignArea.Bottom() )
530 return nProposedRelPosY;
533 // #i31805# - consider value of <bCheckBottom>
534 if ( bCheckBottom &&
535 nTopOfAnch + nAdjustedRelPosY + aObjSize.Height() >
536 aPgAlignArea.Top() + aPgAlignArea.Height() )
538 nAdjustedRelPosY = aPgAlignArea.Top() + aPgAlignArea.Height() -
539 nTopOfAnch -
540 aObjSize.Height();
542 if ( nTopOfAnch + nAdjustedRelPosY < aPgAlignArea.Top() )
544 nAdjustedRelPosY = aPgAlignArea.Top() - nTopOfAnch;
547 return nAdjustedRelPosY;
550 /** adjust calculated horizontal in order to keep object inside
551 'page' alignment layout frame.
553 #i62875# - method now private and renamed.
555 SwTwips SwAnchoredObjectPosition::ImplAdjustHoriRelPos(
556 const SwFrame& _rPageAlignLayFrame,
557 const SwTwips _nProposedRelPosX ) const
559 SwTwips nAdjustedRelPosX = _nProposedRelPosX;
561 if (SwAnchoredObject::IsDraggingOffPageAllowed(FindFrameFormat(&mrDrawObj)))
562 return nAdjustedRelPosX;
564 const SwFrame& rAnchorFrame = GetAnchorFrame();
565 const bool bVert = rAnchorFrame.IsVertical();
567 const Size aObjSize( GetAnchoredObj().GetObjRect().SSize() );
569 if( bVert )
571 if ( rAnchorFrame.getFrameArea().Top() + nAdjustedRelPosX + aObjSize.Height() >
572 _rPageAlignLayFrame.getFrameArea().Bottom() )
574 nAdjustedRelPosX = _rPageAlignLayFrame.getFrameArea().Bottom() -
575 rAnchorFrame.getFrameArea().Top() -
576 aObjSize.Height();
578 if ( rAnchorFrame.getFrameArea().Top() + nAdjustedRelPosX <
579 _rPageAlignLayFrame.getFrameArea().Top() )
581 nAdjustedRelPosX = _rPageAlignLayFrame.getFrameArea().Top() -
582 rAnchorFrame.getFrameArea().Top();
585 else
587 if ( rAnchorFrame.getFrameArea().Left() + nAdjustedRelPosX + aObjSize.Width() >
588 _rPageAlignLayFrame.getFrameArea().Right() )
590 nAdjustedRelPosX = _rPageAlignLayFrame.getFrameArea().Right() -
591 rAnchorFrame.getFrameArea().Left() -
592 aObjSize.Width();
594 if ( rAnchorFrame.getFrameArea().Left() + nAdjustedRelPosX <
595 _rPageAlignLayFrame.getFrameArea().Left() )
597 nAdjustedRelPosX = _rPageAlignLayFrame.getFrameArea().Left() -
598 rAnchorFrame.getFrameArea().Left();
602 return nAdjustedRelPosX;
605 /** determine alignment value for horizontal position of object */
606 void SwAnchoredObjectPosition::GetHoriAlignmentValues( const SwFrame& _rHoriOrientFrame,
607 const SwFrame& _rPageAlignLayFrame,
608 const sal_Int16 _eRelOrient,
609 const bool _bObjWrapThrough,
610 SwTwips& _orAlignAreaWidth,
611 SwTwips& _orAlignAreaOffset,
612 bool& _obAlignedRelToPage ) const
614 SwTwips nWidth = 0;
615 SwTwips nOffset = 0;
616 SwRectFnSet aRectFnSet(&_rHoriOrientFrame);
617 switch ( _eRelOrient )
619 case text::RelOrientation::PRINT_AREA:
621 nWidth = aRectFnSet.GetWidth(_rHoriOrientFrame.getFramePrintArea());
622 nOffset = aRectFnSet.GetLeftMargin(_rHoriOrientFrame);
623 if ( _rHoriOrientFrame.IsTextFrame() )
625 // consider movement of text frame left
626 nOffset += static_cast<const SwTextFrame&>(_rHoriOrientFrame).GetBaseOffsetForFly( !_bObjWrapThrough );
628 else if ( _rHoriOrientFrame.IsPageFrame() && aRectFnSet.IsVert() )
630 // for to-page anchored objects, consider header/footer frame
631 // in vertical layout
632 const SwFrame* pPrtFrame =
633 static_cast<const SwPageFrame&>(_rHoriOrientFrame).Lower();
634 while( pPrtFrame )
636 if( pPrtFrame->IsHeaderFrame() )
638 nWidth -= pPrtFrame->getFrameArea().Height();
639 nOffset += pPrtFrame->getFrameArea().Height();
641 else if( pPrtFrame->IsFooterFrame() )
643 nWidth -= pPrtFrame->getFrameArea().Height();
645 pPrtFrame = pPrtFrame->GetNext();
648 break;
650 case text::RelOrientation::PAGE_LEFT:
652 // align at left border of page frame/fly frame/cell frame
653 nWidth = aRectFnSet.GetLeftMargin(_rPageAlignLayFrame);
654 nOffset = aRectFnSet.XDiff(
655 aRectFnSet.GetLeft(_rPageAlignLayFrame.getFrameArea()),
656 aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea()) );
657 _obAlignedRelToPage = true;
659 break;
660 case text::RelOrientation::PAGE_RIGHT:
662 // align at right border of page frame/fly frame/cell frame
663 nWidth = aRectFnSet.GetRightMargin(_rPageAlignLayFrame);
664 nOffset = aRectFnSet.XDiff(
665 aRectFnSet.GetPrtRight(_rPageAlignLayFrame),
666 aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea()) );
667 _obAlignedRelToPage = true;
669 break;
670 case text::RelOrientation::FRAME_LEFT:
672 // align at left border of anchor frame
673 nWidth = aRectFnSet.GetLeftMargin(_rHoriOrientFrame);
674 nOffset = 0;
676 break;
677 case text::RelOrientation::FRAME_RIGHT:
679 // align at right border of anchor frame
680 // Unify and simplify
681 nWidth = aRectFnSet.GetRightMargin(_rHoriOrientFrame);
682 nOffset = aRectFnSet.GetRight(_rHoriOrientFrame.getFramePrintArea());
684 break;
685 case text::RelOrientation::CHAR:
687 // alignment relative to character - assure, that corresponding
688 // character rectangle is set.
689 if ( IsAnchoredToChar() )
691 nWidth = 0;
692 nOffset = aRectFnSet.XDiff(
693 aRectFnSet.GetLeft(*ToCharRect()),
694 aRectFnSet.GetLeft(ToCharOrientFrame()->getFrameArea()) );
695 break;
697 [[fallthrough]];
699 case text::RelOrientation::PAGE_PRINT_AREA:
701 nWidth = aRectFnSet.GetWidth(_rPageAlignLayFrame.getFramePrintArea());
702 nOffset = aRectFnSet.XDiff(
703 aRectFnSet.GetPrtLeft(_rPageAlignLayFrame),
704 aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea()) );
705 if ( _rHoriOrientFrame.IsPageFrame() && aRectFnSet.IsVert() )
707 // for to-page anchored objects, consider header/footer frame
708 // in vertical layout
709 const SwFrame* pPrtFrame =
710 static_cast<const SwPageFrame&>(_rHoriOrientFrame).Lower();
711 while( pPrtFrame )
713 if( pPrtFrame->IsHeaderFrame() )
715 nWidth -= pPrtFrame->getFrameArea().Height();
716 nOffset += pPrtFrame->getFrameArea().Height();
718 else if( pPrtFrame->IsFooterFrame() )
720 nWidth -= pPrtFrame->getFrameArea().Height();
722 pPrtFrame = pPrtFrame->GetNext();
725 _obAlignedRelToPage = true;
726 break;
728 case text::RelOrientation::PAGE_FRAME:
730 nWidth = aRectFnSet.GetWidth(_rPageAlignLayFrame.getFrameArea());
731 nOffset = aRectFnSet.XDiff(
732 aRectFnSet.GetLeft(_rPageAlignLayFrame.getFrameArea()),
733 aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea()) );
734 _obAlignedRelToPage = true;
735 break;
737 default:
739 nWidth = aRectFnSet.GetWidth(_rHoriOrientFrame.getFrameArea());
741 bool bWrapThrough = _bObjWrapThrough;
742 // If the frame format is a TextBox of a draw shape, then use the
743 // surround of the original shape.
744 SwTextBoxHelper::getShapeWrapThrough(mpFrameFormat, bWrapThrough);
746 bool bIgnoreFlysAnchoredAtFrame = !bWrapThrough;
747 nOffset = _rHoriOrientFrame.IsTextFrame() ?
748 static_cast<const SwTextFrame&>(_rHoriOrientFrame).GetBaseOffsetForFly( bIgnoreFlysAnchoredAtFrame ) :
750 break;
754 _orAlignAreaWidth = nWidth;
755 _orAlignAreaOffset = nOffset;
758 /** toggle given horizontal orientation and relative alignment */
759 void SwAnchoredObjectPosition::ToggleHoriOrientAndAlign(
760 const bool _bToggleLeftRight,
761 sal_Int16& _ioeHoriOrient,
762 sal_Int16& _iopeRelOrient
765 if( !_bToggleLeftRight )
766 return;
768 // toggle orientation
769 switch ( _ioeHoriOrient )
771 case text::HoriOrientation::RIGHT :
773 _ioeHoriOrient = text::HoriOrientation::LEFT;
775 break;
776 case text::HoriOrientation::LEFT :
778 _ioeHoriOrient = text::HoriOrientation::RIGHT;
780 break;
781 default:
782 break;
785 // toggle relative alignment
786 switch ( _iopeRelOrient )
788 case text::RelOrientation::PAGE_RIGHT :
790 _iopeRelOrient = text::RelOrientation::PAGE_LEFT;
792 break;
793 case text::RelOrientation::PAGE_LEFT :
795 _iopeRelOrient = text::RelOrientation::PAGE_RIGHT;
797 break;
798 case text::RelOrientation::FRAME_RIGHT :
800 _iopeRelOrient = text::RelOrientation::FRAME_LEFT;
802 break;
803 case text::RelOrientation::FRAME_LEFT :
805 _iopeRelOrient = text::RelOrientation::FRAME_RIGHT;
807 break;
808 default:
809 break;
813 /** calculate relative horizontal position */
814 SwTwips SwAnchoredObjectPosition::CalcRelPosX(
815 const SwFrame& _rHoriOrientFrame,
816 const SwEnvironmentOfAnchoredObject& _rEnvOfObj,
817 const SwFormatHoriOrient& _rHoriOrient,
818 const SvxLRSpaceItem& _rLRSpacing,
819 const SvxULSpaceItem& _rULSpacing,
820 const bool _bObjWrapThrough,
821 const SwTwips _nRelPosY,
822 SwTwips& _roHoriOffsetToFrameAnchorPos
823 ) const
825 // determine 'page' alignment layout frame
826 const SwFrame& rPageAlignLayFrame =
827 _rEnvOfObj.GetHoriEnvironmentLayoutFrame( _rHoriOrientFrame );
829 const bool bEvenPage = !rPageAlignLayFrame.OnRightPage();
830 const bool bToggle = _rHoriOrient.IsPosToggle() && bEvenPage;
832 // determine orientation and relative alignment
833 sal_Int16 eHoriOrient = _rHoriOrient.GetHoriOrient();
834 sal_Int16 eRelOrient = _rHoriOrient.GetRelationOrient();
835 // toggle orientation and relative alignment
836 ToggleHoriOrientAndAlign( bToggle, eHoriOrient, eRelOrient );
838 // determine alignment parameter
839 // <nWidth>: 'width' of alignment area
840 // <nOffset>: offset of alignment area, relative to 'left' of anchor frame
841 SwTwips nWidth = 0;
842 SwTwips nOffset = 0;
843 bool bAlignedRelToPage = false;
844 GetHoriAlignmentValues( _rHoriOrientFrame, rPageAlignLayFrame,
845 eRelOrient, _bObjWrapThrough,
846 nWidth, nOffset, bAlignedRelToPage );
848 const SwFrame& rAnchorFrame = GetAnchorFrame();
849 SwRectFnSet aRectFnSet(&_rHoriOrientFrame);
850 SwTwips nObjWidth = aRectFnSet.GetWidth(GetAnchoredObj().GetObjRect());
851 SwTwips nRelPosX = nOffset;
852 if ( _rHoriOrient.GetHoriOrient() == text::HoriOrientation::NONE )
854 // 'manual' horizontal position
855 const bool bR2L = rAnchorFrame.IsRightToLeft();
856 if( IsAnchoredToChar() && text::RelOrientation::CHAR == eRelOrient )
858 if( bR2L )
859 nRelPosX -= _rHoriOrient.GetPos();
860 else
861 nRelPosX += _rHoriOrient.GetPos();
863 else if ( bToggle || ( !_rHoriOrient.IsPosToggle() && bR2L ) )
865 // Correction: consider <nOffset> also for
866 // toggling from left to right.
867 nRelPosX += nWidth - nObjWidth - _rHoriOrient.GetPos();
869 else
871 nRelPosX += _rHoriOrient.GetPos();
874 else if ( text::HoriOrientation::CENTER == eHoriOrient )
875 nRelPosX += (nWidth / 2) - (nObjWidth / 2);
876 else if ( text::HoriOrientation::RIGHT == eHoriOrient )
877 nRelPosX += nWidth -
878 ( nObjWidth +
879 ( aRectFnSet.IsVert() ? _rULSpacing.GetLower() : _rLRSpacing.GetRight() ) );
880 else
881 nRelPosX += aRectFnSet.IsVert() ? _rULSpacing.GetUpper() : _rLRSpacing.GetLeft();
883 // adjust relative position by distance between anchor frame and
884 // the frame, the object is oriented at.
885 if ( &rAnchorFrame != &_rHoriOrientFrame )
887 SwTwips nLeftOrient = aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea());
888 SwTwips nLeftAnchor = aRectFnSet.GetLeft(rAnchorFrame.getFrameArea());
889 nRelPosX += aRectFnSet.XDiff( nLeftOrient, nLeftAnchor );
892 // adjust calculated relative horizontal position, in order to
893 // keep object inside 'page' alignment layout frame
894 const SwFrame& rEnvironmentLayFrame =
895 _rEnvOfObj.GetHoriEnvironmentLayoutFrame( _rHoriOrientFrame );
896 bool bFollowTextFlow = GetFrameFormat().GetFollowTextFlow().GetValue();
897 bool bWrapThrough = GetFrameFormat().GetSurround().GetSurround() != text::WrapTextMode_THROUGH;
898 // Don't try to keep wrap-though objects inside the cell, even if they are following text flow.
899 if (!rEnvironmentLayFrame.IsInTab() || !bFollowTextFlow || bWrapThrough)
901 nRelPosX = AdjustHoriRelPos( rEnvironmentLayFrame, nRelPosX );
904 // if object is a Writer fly frame and it's anchored to a content and
905 // it is horizontal positioned left or right, but not relative to character,
906 // it has to be drawn aside another object, which have the same horizontal
907 // position and lay below it.
908 if ( GetAnchoredObj().DynCastFlyFrame() &&
909 ( mpContact->ObjAnchoredAtPara() || mpContact->ObjAnchoredAtChar() ) &&
910 ( eHoriOrient == text::HoriOrientation::LEFT || eHoriOrient == text::HoriOrientation::RIGHT ) &&
911 eRelOrient != text::RelOrientation::CHAR )
913 nRelPosX = AdjustHoriRelPosForDrawAside( _rHoriOrientFrame,
914 nRelPosX, _nRelPosY,
915 eHoriOrient, eRelOrient,
916 _rLRSpacing, _rULSpacing,
917 bEvenPage );
920 // #i26791#
921 _roHoriOffsetToFrameAnchorPos = nOffset;
923 return nRelPosX;
926 // method incl. helper methods for adjusting proposed horizontal position,
927 // if object has to draw aside another object.
928 /** adjust calculated horizontal position in order to draw object
929 aside other objects with same positioning
931 SwTwips SwAnchoredObjectPosition::AdjustHoriRelPosForDrawAside(
932 const SwFrame& _rHoriOrientFrame,
933 const SwTwips _nProposedRelPosX,
934 const SwTwips _nRelPosY,
935 const sal_Int16 _eHoriOrient,
936 const sal_Int16 _eRelOrient,
937 const SvxLRSpaceItem& _rLRSpacing,
938 const SvxULSpaceItem& _rULSpacing,
939 const bool _bEvenPage
940 ) const
942 // #i26791#
943 if ( GetAnchorFrame().DynCastTextFrame() == nullptr ||
944 dynamic_cast<const SwFlyAtContentFrame*>( &GetAnchoredObj() ) == nullptr )
946 OSL_FAIL( "<SwAnchoredObjectPosition::AdjustHoriRelPosForDrawAside(..) - usage for wrong anchor type" );
947 return _nProposedRelPosX;
950 const SwTextFrame& rAnchorTextFrame = static_cast<const SwTextFrame&>(GetAnchorFrame());
951 // #i26791#
952 const SwFlyAtContentFrame& rFlyAtContentFrame =
953 static_cast<const SwFlyAtContentFrame&>(GetAnchoredObj());
954 const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() );
955 SwRectFnSet aRectFnSet(&_rHoriOrientFrame);
957 SwTwips nAdjustedRelPosX = _nProposedRelPosX;
959 // determine proposed object bound rectangle
960 Point aTmpPos = aRectFnSet.GetPos(rAnchorTextFrame.getFrameArea());
961 if( aRectFnSet.IsVert() )
963 aTmpPos.AdjustX( -(_nRelPosY + aObjBoundRect.Width()) );
964 aTmpPos.AdjustY(nAdjustedRelPosX );
966 else
968 aTmpPos.AdjustX(nAdjustedRelPosX );
969 aTmpPos.AdjustY(_nRelPosY );
971 SwRect aTmpObjRect( aTmpPos, aObjBoundRect.SSize() );
973 const sal_uInt32 nObjOrdNum = GetObject().GetOrdNum();
974 const SwPageFrame* pObjPage = rFlyAtContentFrame.FindPageFrame();
975 const SwFrame* pObjContext = ::FindContext( &rAnchorTextFrame, SwFrameType::Column );
976 SwNodeOffset nObjIndex = rAnchorTextFrame.GetTextNodeFirst()->GetIndex();
977 SwOrderIter aIter( pObjPage );
978 const SwFlyFrame* pFly = static_cast<const SwVirtFlyDrawObj*>(aIter.Bottom())->GetFlyFrame();
979 while ( pFly && nObjOrdNum > pFly->GetVirtDrawObj()->GetOrdNumDirect() )
981 if ( DrawAsideFly( pFly, aTmpObjRect, pObjContext, nObjIndex,
982 _bEvenPage, _eHoriOrient, _eRelOrient ) )
984 if( aRectFnSet.IsVert() )
986 const SvxULSpaceItem& rOtherUL = pFly->GetFormat()->GetULSpace();
987 const SwTwips nOtherTop = pFly->getFrameArea().Top() - rOtherUL.GetUpper();
988 const SwTwips nOtherBot = pFly->getFrameArea().Bottom() + rOtherUL.GetLower();
989 if ( nOtherTop <= aTmpObjRect.Bottom() + _rULSpacing.GetLower() &&
990 nOtherBot >= aTmpObjRect.Top() - _rULSpacing.GetUpper() )
992 if ( _eHoriOrient == text::HoriOrientation::LEFT )
994 SwTwips nTmp = nOtherBot + 1 + _rULSpacing.GetUpper() -
995 rAnchorTextFrame.getFrameArea().Top();
996 if ( nTmp > nAdjustedRelPosX &&
997 rAnchorTextFrame.getFrameArea().Top() + nTmp +
998 aObjBoundRect.Height() + _rULSpacing.GetLower()
999 <= pObjPage->getFrameArea().Height() + pObjPage->getFrameArea().Top() )
1001 nAdjustedRelPosX = nTmp;
1004 else if ( _eHoriOrient == text::HoriOrientation::RIGHT )
1006 SwTwips nTmp = nOtherTop - 1 - _rULSpacing.GetLower() -
1007 aObjBoundRect.Height() -
1008 rAnchorTextFrame.getFrameArea().Top();
1009 if ( nTmp < nAdjustedRelPosX &&
1010 rAnchorTextFrame.getFrameArea().Top() + nTmp - _rULSpacing.GetUpper()
1011 >= pObjPage->getFrameArea().Top() )
1013 nAdjustedRelPosX = nTmp;
1016 aTmpObjRect.Pos().setY( rAnchorTextFrame.getFrameArea().Top() +
1017 nAdjustedRelPosX );
1020 else
1022 const SvxLRSpaceItem& rOtherLR = pFly->GetFormat()->GetLRSpace();
1023 const SwTwips nOtherLeft = pFly->getFrameArea().Left() - rOtherLR.GetLeft();
1024 const SwTwips nOtherRight = pFly->getFrameArea().Right() + rOtherLR.GetRight();
1025 if( nOtherLeft <= aTmpObjRect.Right() + _rLRSpacing.GetRight() &&
1026 nOtherRight >= aTmpObjRect.Left() - _rLRSpacing.GetLeft() )
1028 if ( _eHoriOrient == text::HoriOrientation::LEFT )
1030 SwTwips nTmp = nOtherRight + 1 + _rLRSpacing.GetLeft() -
1031 rAnchorTextFrame.getFrameArea().Left();
1032 if ( nTmp > nAdjustedRelPosX &&
1033 rAnchorTextFrame.getFrameArea().Left() + nTmp +
1034 aObjBoundRect.Width() + _rLRSpacing.GetRight()
1035 <= pObjPage->getFrameArea().Width() + pObjPage->getFrameArea().Left() )
1037 nAdjustedRelPosX = nTmp;
1040 else if ( _eHoriOrient == text::HoriOrientation::RIGHT )
1042 SwTwips nTmp = nOtherLeft - 1 - _rLRSpacing.GetRight() -
1043 aObjBoundRect.Width() -
1044 rAnchorTextFrame.getFrameArea().Left();
1045 if ( nTmp < nAdjustedRelPosX &&
1046 rAnchorTextFrame.getFrameArea().Left() + nTmp - _rLRSpacing.GetLeft()
1047 >= pObjPage->getFrameArea().Left() )
1049 nAdjustedRelPosX = nTmp;
1052 aTmpObjRect.Pos().setX( rAnchorTextFrame.getFrameArea().Left() +
1053 nAdjustedRelPosX );
1055 } // end of <if (bVert)>
1056 } // end of <if DrawAsideFly(..)>
1058 pFly = static_cast<const SwVirtFlyDrawObj*>(aIter.Next())->GetFlyFrame();
1059 } // end of <loop on fly frames
1061 return nAdjustedRelPosX;
1064 /** determine, if object has to draw aside given fly frame
1066 method used by <AdjustHoriRelPosForDrawAside(..)>
1068 bool SwAnchoredObjectPosition::DrawAsideFly( const SwFlyFrame* _pFly,
1069 const SwRect& _rObjRect,
1070 const SwFrame* _pObjContext,
1071 const SwNodeOffset _nObjIndex,
1072 const bool _bEvenPage,
1073 const sal_Int16 _eHoriOrient,
1074 const sal_Int16 _eRelOrient
1075 ) const
1077 bool bRetVal = false;
1079 SwRectFnSet aRectFnSet(&GetAnchorFrame());
1081 if ( _pFly->IsFlyAtContentFrame() &&
1082 aRectFnSet.BottomDist( _pFly->getFrameArea(), aRectFnSet.GetTop(_rObjRect) ) < 0 &&
1083 aRectFnSet.BottomDist( _rObjRect, aRectFnSet.GetTop(_pFly->getFrameArea()) ) < 0 &&
1084 ::FindContext( _pFly->GetAnchorFrame(), SwFrameType::Column ) == _pObjContext )
1086 SwNodeOffset nOtherIndex =
1087 static_cast<const SwTextFrame*>(_pFly->GetAnchorFrame())->GetTextNodeFirst()->GetIndex();
1088 if (sw::FrameContainsNode(static_cast<SwTextFrame const&>(*_pFly->GetAnchorFrame()), _nObjIndex)
1089 || nOtherIndex < _nObjIndex)
1091 const SwFormatHoriOrient& rHori = _pFly->GetFormat()->GetHoriOrient();
1092 sal_Int16 eOtherRelOrient = rHori.GetRelationOrient();
1093 if( text::RelOrientation::CHAR != eOtherRelOrient )
1095 sal_Int16 eOtherHoriOrient = rHori.GetHoriOrient();
1096 ToggleHoriOrientAndAlign( _bEvenPage && rHori.IsPosToggle(),
1097 eOtherHoriOrient,
1098 eOtherRelOrient );
1099 if ( eOtherHoriOrient == _eHoriOrient &&
1100 Minor_( _eRelOrient, eOtherRelOrient, text::HoriOrientation::LEFT == _eHoriOrient ) )
1102 bRetVal = true;
1108 return bRetVal;
1111 /** determine, if object has to draw aside another object
1113 the different alignments of the objects determines, if one has
1114 to draw aside another one. Thus, the given alignment are checked
1115 against each other, which one has to be drawn aside the other one.
1116 depending on parameter _bLeft check is done for left or right
1117 positioning.
1118 method used by <DrawAsideFly(..)>
1120 bool SwAnchoredObjectPosition::Minor_( sal_Int16 _eRelOrient1,
1121 sal_Int16 _eRelOrient2,
1122 bool _bLeft )
1124 bool bRetVal;
1126 // draw aside order for left horizontal position
1127 //! one array entry for each value in text::RelOrientation
1128 static sal_uInt16 const aLeft[ 10 ] =
1129 { 5, 6, 0, 1, 8, 4, 7, 2, 3, 9 };
1130 // draw aside order for right horizontal position
1131 //! one array entry for each value in text::RelOrientation
1132 static sal_uInt16 const aRight[ 10 ] =
1133 { 5, 6, 0, 8, 1, 7, 4, 2, 3, 9 };
1135 // decide depending on given order, which frame has to draw aside another frame
1136 if( _bLeft )
1137 bRetVal = aLeft[ _eRelOrient1 ] >= aLeft[ _eRelOrient2 ];
1138 else
1139 bRetVal = aRight[ _eRelOrient1 ] >= aRight[ _eRelOrient2 ];
1141 return bRetVal;
1146 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */