1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <anchoreddrawobject.hxx>
21 #include <ascharanchoredobjectposition.hxx>
24 #include <flyfrms.hxx>
25 #include <svx/svdobj.hxx>
28 #include <editeng/lrspitem.hxx>
29 #include <editeng/ulspitem.hxx>
30 #include <osl/diagnose.h>
31 #include <fmtornt.hxx>
34 using namespace ::com::sun::star
;
36 namespace objectpositioning
40 SwAsCharAnchoredObjectPosition::SwAsCharAnchoredObjectPosition(
42 const Point
& _rProposedAnchorPos
,
43 const AsCharFlags _nFlags
,
44 const SwTwips _nLineAscent
,
45 const SwTwips _nLineDescent
,
46 const SwTwips _nLineAscentInclObjs
,
47 const SwTwips _nLineDescentInclObjs
)
48 : SwAnchoredObjectPosition( _rDrawObj
),
49 mrProposedAnchorPos( _rProposedAnchorPos
),
51 mnLineAscent( _nLineAscent
),
52 mnLineDescent( _nLineDescent
),
53 mnLineAscentInclObjs( _nLineAscentInclObjs
),
54 mnLineDescentInclObjs( _nLineDescentInclObjs
),
56 mnLineAlignment ( sw::LineAlign::NONE
)
60 SwAsCharAnchoredObjectPosition::~SwAsCharAnchoredObjectPosition()
63 /** method to cast <SwAnchoredObjectPosition::GetAnchorFrame()> to needed type */
64 const SwTextFrame
& SwAsCharAnchoredObjectPosition::GetAnchorTextFrame() const
66 assert( dynamic_cast<const SwTextFrame
*>( &GetAnchorFrame() ) &&
67 "SwAsCharAnchoredObjectPosition::GetAnchorTextFrame() - wrong anchor frame type" );
69 return static_cast<const SwTextFrame
&>(GetAnchorFrame());
72 /** calculate position for object
74 OD 30.07.2003 #110978#
75 members <maAnchorPos>, <mnRelPos>, <maObjBoundRect> and
76 <mnLineAlignment> are calculated.
77 calculated position is set at the given object.
79 void SwAsCharAnchoredObjectPosition::CalcPosition()
81 const SwTextFrame
& rAnchorFrame
= GetAnchorTextFrame();
82 // swap anchor frame, if swapped. Note: destructor takes care of the 'undo'
83 SwFrameSwapper
aFrameSwapper( &rAnchorFrame
, false );
85 SwRectFnSet
aRectFnSet(&rAnchorFrame
);
87 Point
aAnchorPos( mrProposedAnchorPos
);
89 const SwFrameFormat
& rFrameFormat
= GetFrameFormat();
91 SwRect
aObjBoundRect( GetAnchoredObj().GetObjRect() );
92 SwTwips nObjWidth
= aRectFnSet
.GetWidth(aObjBoundRect
);
94 // determine spacing values considering layout-/text-direction
95 const SvxLRSpaceItem
& rLRSpace
= rFrameFormat
.GetLRSpace();
96 const SvxULSpaceItem
& rULSpace
= rFrameFormat
.GetULSpace();
97 SwTwips nLRSpaceLeft
, nLRSpaceRight
, nULSpaceUpper
, nULSpaceLower
;
99 if ( rAnchorFrame
.IsVertical() )
101 // Seems to be easier to do it all the horizontal way
102 // So, from now on think horizontal.
103 rAnchorFrame
.SwitchVerticalToHorizontal( aObjBoundRect
);
104 rAnchorFrame
.SwitchVerticalToHorizontal( aAnchorPos
);
106 // convert the spacing values
107 nLRSpaceLeft
= rULSpace
.GetUpper();
108 nLRSpaceRight
= rULSpace
.GetLower();
109 nULSpaceUpper
= rLRSpace
.GetRight();
110 nULSpaceLower
= rLRSpace
.GetLeft();
114 if ( rAnchorFrame
.IsRightToLeft() )
116 nLRSpaceLeft
= rLRSpace
.GetRight();
117 nLRSpaceRight
= rLRSpace
.GetLeft();
121 nLRSpaceLeft
= rLRSpace
.GetLeft();
122 nLRSpaceRight
= rLRSpace
.GetRight();
125 nULSpaceUpper
= rULSpace
.GetUpper();
126 nULSpaceLower
= rULSpace
.GetLower();
130 // consider left and upper spacing by adjusting anchor position.
131 // left spacing is only considered, if requested.
132 if( mnFlags
& AsCharFlags::UlSpace
)
134 aAnchorPos
.AdjustX(nLRSpaceLeft
);
136 aAnchorPos
.AdjustY(nULSpaceUpper
);
138 // for drawing objects: consider difference between its bounding rectangle
139 // and its snapping rectangle by adjusting anchor position.
140 // left difference is only considered, if requested.
143 SwRect
aSnapRect(GetObject().GetSnapRect());
144 if ( rAnchorFrame
.IsVertical() )
146 rAnchorFrame
.SwitchVerticalToHorizontal( aSnapRect
);
149 if( mnFlags
& AsCharFlags::UlSpace
)
151 aAnchorPos
.AdjustX(aSnapRect
.Left() - aObjBoundRect
.Left() );
153 aAnchorPos
.AdjustY(aSnapRect
.Top() - aObjBoundRect
.Top() );
156 // enlarge bounding rectangle of object by its spacing.
157 aObjBoundRect
.AddLeft( - nLRSpaceLeft
);
158 aObjBoundRect
.AddWidth( nLRSpaceRight
);
159 aObjBoundRect
.AddTop( - nULSpaceUpper
);
160 aObjBoundRect
.AddHeight( nULSpaceLower
);
162 // calculate relative position to given base line.
163 const SwFormatVertOrient
& rVert
= rFrameFormat
.GetVertOrient();
164 const SwTwips nObjBoundHeight
= ( mnFlags
& AsCharFlags::Rotate
)
165 ? aObjBoundRect
.Width()
166 : aObjBoundRect
.Height();
167 const SwTwips nRelPos
= GetRelPosToBase( nObjBoundHeight
, rVert
);
169 // for initial positioning:
170 // adjust the proposed anchor position by difference between
171 // calculated relative position to base line and current maximal line ascent.
172 // Note: In the following line formatting the base line will be adjusted
173 // by the same difference.
174 if( mnFlags
& AsCharFlags::Init
&& nRelPos
< 0 && mnLineAscentInclObjs
< -nRelPos
)
176 if( mnFlags
& AsCharFlags::Rotate
)
177 aAnchorPos
.AdjustX( -(mnLineAscentInclObjs
+ nRelPos
) );
179 aAnchorPos
.AdjustY( -(mnLineAscentInclObjs
+ nRelPos
) );
182 // consider BIDI-multiportion by adjusting proposed anchor position
183 if( mnFlags
& AsCharFlags::Bidi
)
184 aAnchorPos
.AdjustX( -(aObjBoundRect
.Width()) );
186 // calculate relative position considering rotation and inside rotation
187 // reverse direction.
190 if( mnFlags
& AsCharFlags::Rotate
)
192 if( mnFlags
& AsCharFlags::Reverse
)
193 aRelPos
.setX( -nRelPos
- aObjBoundRect
.Width() );
196 aRelPos
.setX( nRelPos
);
197 aRelPos
.setY( -aObjBoundRect
.Height() );
201 aRelPos
.setY( nRelPos
);
206 if( !( mnFlags
& AsCharFlags::Quick
) )
208 // save calculated Y-position value for 'automatic' vertical positioning,
209 // in order to avoid a switch to 'manual' vertical positioning in
210 // <SwDrawContact::Changed_(..)>.
211 const sal_Int16 eVertOrient
= rVert
.GetVertOrient();
212 if( rVert
.GetPos() != nRelPos
&& eVertOrient
!= text::VertOrientation::NONE
)
214 SwFormatVertOrient
aVert( rVert
);
215 aVert
.SetPos( nRelPos
);
216 const_cast<SwFrameFormat
&>(rFrameFormat
).LockModify();
217 const_cast<SwFrameFormat
&>(rFrameFormat
).SetFormatAttr( aVert
);
218 const_cast<SwFrameFormat
&>(rFrameFormat
).UnlockModify();
221 // determine absolute anchor position considering layout directions.
222 // Note: Use copy of <aAnchorPos>, because it's needed for
223 // setting relative position.
224 Point
aAbsAnchorPos( aAnchorPos
);
225 if ( rAnchorFrame
.IsRightToLeft() )
227 rAnchorFrame
.SwitchLTRtoRTL( aAbsAnchorPos
);
228 aAbsAnchorPos
.AdjustX( -nObjWidth
);
230 if ( rAnchorFrame
.IsVertical() )
231 rAnchorFrame
.SwitchHorizontalToVertical( aAbsAnchorPos
);
233 // set proposed anchor position at the drawing object.
234 // OD 2004-04-06 #i26791# - distinction between 'master' drawing
235 // object and 'virtual' drawing object no longer needed.
236 GetObject().SetAnchorPos( aAbsAnchorPos
);
238 // move drawing object to set its correct relative position.
240 SwRect
aSnapRect(GetObject().GetSnapRect());
241 if ( rAnchorFrame
.IsVertical() )
242 rAnchorFrame
.SwitchVerticalToHorizontal( aSnapRect
);
245 if ( rAnchorFrame
.IsRightToLeft() )
246 aDiff
= aRelPos
+ aAbsAnchorPos
- aSnapRect
.TopLeft();
248 aDiff
= aRelPos
+ aAnchorPos
- aSnapRect
.TopLeft();
250 if ( rAnchorFrame
.IsVertical() )
251 aDiff
= Point( -aDiff
.Y(), aDiff
.X() );
253 // OD 2004-04-06 #i26791# - distinction between 'master' drawing
254 // object and 'virtual' drawing object no longer needed.
255 GetObject().Move( Size( aDiff
.X(), aDiff
.Y() ) );
259 // switch horizontal, LTR anchor position to absolute values.
260 if ( rAnchorFrame
.IsRightToLeft() )
262 rAnchorFrame
.SwitchLTRtoRTL( aAnchorPos
);
263 aAnchorPos
.AdjustX( -nObjWidth
);
265 if ( rAnchorFrame
.IsVertical() )
266 rAnchorFrame
.SwitchHorizontalToVertical( aAnchorPos
);
268 // #i44347# - keep last object rectangle at anchored object
269 assert( dynamic_cast<const SwAnchoredDrawObject
*>( &GetAnchoredObj() ) &&
270 "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong type of anchored object." );
271 SwAnchoredDrawObject
& rAnchoredDrawObj
=
272 static_cast<SwAnchoredDrawObject
&>( GetAnchoredObj() );
273 rAnchoredDrawObj
.SetLastObjRect( rAnchoredDrawObj
.GetObjRect().SVRect() );
277 // determine absolute anchor position and calculate corresponding
278 // relative position and its relative position attribute.
279 // Note: The relative position contains the spacing values.
281 if ( rAnchorFrame
.IsRightToLeft() )
283 rAnchorFrame
.SwitchLTRtoRTL( aAnchorPos
);
284 aAnchorPos
.AdjustX( -nObjWidth
);
286 if ( rAnchorFrame
.IsVertical() )
288 rAnchorFrame
.SwitchHorizontalToVertical( aAnchorPos
);
289 aRelAttr
= Point( -nRelPos
, 0 );
290 aRelPos
= Point( -aRelPos
.Y(), aRelPos
.X() );
293 aRelAttr
= Point( 0, nRelPos
);
295 // OD 2004-03-23 #i26791#
296 assert( dynamic_cast<const SwFlyInContentFrame
*>( &GetAnchoredObj()) &&
297 "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong anchored object." );
298 const SwFlyInContentFrame
& rFlyInContentFrame
=
299 static_cast<const SwFlyInContentFrame
&>(GetAnchoredObj());
300 if ( !(mnFlags
& AsCharFlags::Quick
) &&
301 ( aAnchorPos
!= rFlyInContentFrame
.GetRefPoint() ||
302 aRelAttr
!= rFlyInContentFrame
.GetCurrRelPos() ) )
304 // set new anchor position and relative position
305 SwFlyInContentFrame
* pFlyInContentFrame
= &const_cast<SwFlyInContentFrame
&>(rFlyInContentFrame
);
306 pFlyInContentFrame
->SetRefPoint( aAnchorPos
, aRelAttr
, aRelPos
);
307 if( nObjWidth
!= aRectFnSet
.GetWidth(pFlyInContentFrame
->getFrameArea()) )
309 // recalculate object bound rectangle, if object width has changed.
310 aObjBoundRect
= GetAnchoredObj().GetObjRect();
311 aObjBoundRect
.AddLeft( - rLRSpace
.GetLeft() );
312 aObjBoundRect
.AddWidth( rLRSpace
.GetRight() );
313 aObjBoundRect
.AddTop( - rULSpace
.GetUpper() );
314 aObjBoundRect
.AddHeight( rULSpace
.GetLower() );
317 OSL_ENSURE( aRectFnSet
.GetHeight(rFlyInContentFrame
.getFrameArea()),
318 "SwAnchoredObjectPosition::CalcPosition(..) - fly frame has an invalid height" );
321 // keep calculated values
322 maAnchorPos
= aAnchorPos
;
324 maObjBoundRect
= aObjBoundRect
;
327 /** determine the relative position to base line for object position type AS_CHAR
329 OD 29.07.2003 #110978#
330 Note about values set at member <mnLineAlignment> -
331 value gives feedback for the line formatting.
332 0 - no feedback; 1|2|3 - proposed formatting of characters
333 at top|at center|at bottom of line.
335 SwTwips
SwAsCharAnchoredObjectPosition::GetRelPosToBase(
336 const SwTwips _nObjBoundHeight
,
337 const SwFormatVertOrient
& _rVert
)
339 SwTwips nRelPosToBase
= 0;
341 mnLineAlignment
= sw::LineAlign::NONE
;
343 const sal_Int16 eVertOrient
= _rVert
.GetVertOrient();
345 if ( eVertOrient
== text::VertOrientation::NONE
)
346 nRelPosToBase
= _rVert
.GetPos();
349 if ( eVertOrient
== text::VertOrientation::CENTER
)
350 nRelPosToBase
-= _nObjBoundHeight
/ 2;
351 else if ( eVertOrient
== text::VertOrientation::TOP
)
352 nRelPosToBase
-= _nObjBoundHeight
;
353 else if ( eVertOrient
== text::VertOrientation::BOTTOM
)
355 else if ( eVertOrient
== text::VertOrientation::CHAR_CENTER
)
356 nRelPosToBase
-= ( _nObjBoundHeight
+ mnLineAscent
- mnLineDescent
) / 2;
357 else if ( eVertOrient
== text::VertOrientation::CHAR_TOP
)
358 nRelPosToBase
-= mnLineAscent
;
359 else if ( eVertOrient
== text::VertOrientation::CHAR_BOTTOM
)
360 nRelPosToBase
+= mnLineDescent
- _nObjBoundHeight
;
363 if( _nObjBoundHeight
>= mnLineAscentInclObjs
+ mnLineDescentInclObjs
)
365 // object is at least as high as the line. Thus, no more is
366 // positioning necessary. Also, the max. ascent isn't changed.
367 nRelPosToBase
-= mnLineAscentInclObjs
;
368 if ( eVertOrient
== text::VertOrientation::LINE_CENTER
)
369 mnLineAlignment
= sw::LineAlign::CENTER
;
370 else if ( eVertOrient
== text::VertOrientation::LINE_TOP
)
371 mnLineAlignment
= sw::LineAlign::TOP
;
372 else if ( eVertOrient
== text::VertOrientation::LINE_BOTTOM
)
373 mnLineAlignment
= sw::LineAlign::BOTTOM
;
375 else if ( eVertOrient
== text::VertOrientation::LINE_CENTER
)
377 nRelPosToBase
-= ( _nObjBoundHeight
+ mnLineAscentInclObjs
- mnLineDescentInclObjs
) / 2;
378 mnLineAlignment
= sw::LineAlign::CENTER
;
380 else if ( eVertOrient
== text::VertOrientation::LINE_TOP
)
382 nRelPosToBase
-= mnLineAscentInclObjs
;
383 mnLineAlignment
= sw::LineAlign::TOP
;
385 else if ( eVertOrient
== text::VertOrientation::LINE_BOTTOM
)
387 nRelPosToBase
+= mnLineDescentInclObjs
- _nObjBoundHeight
;
388 mnLineAlignment
= sw::LineAlign::BOTTOM
;
393 return nRelPosToBase
;
398 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */