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 <fmtornt.hxx>
33 using namespace ::com::sun::star
;
34 using namespace objectpositioning
;
37 SwAsCharAnchoredObjectPosition::SwAsCharAnchoredObjectPosition(
39 const Point
& _rProposedAnchorPos
,
40 const AsCharFlags _nFlags
,
41 const SwTwips _nLineAscent
,
42 const SwTwips _nLineDescent
,
43 const SwTwips _nLineAscentInclObjs
,
44 const SwTwips _nLineDescentInclObjs
)
45 : SwAnchoredObjectPosition( _rDrawObj
),
46 mrProposedAnchorPos( _rProposedAnchorPos
),
48 mnLineAscent( _nLineAscent
),
49 mnLineDescent( _nLineDescent
),
50 mnLineAscentInclObjs( _nLineAscentInclObjs
),
51 mnLineDescentInclObjs( _nLineDescentInclObjs
),
52 maAnchorPos ( Point() ),
54 maObjBoundRect ( SwRect() ),
55 mnLineAlignment ( sw::LineAlign::NONE
)
59 SwAsCharAnchoredObjectPosition::~SwAsCharAnchoredObjectPosition()
62 /** method to cast <SwAnchoredObjectPosition::GetAnchorFrame()> to needed type */
63 const SwTextFrame
& SwAsCharAnchoredObjectPosition::GetAnchorTextFrame() const
65 OSL_ENSURE( dynamic_cast<const SwTextFrame
*>( &GetAnchorFrame() ) != nullptr,
66 "SwAsCharAnchoredObjectPosition::GetAnchorTextFrame() - wrong anchor frame type" );
68 return static_cast<const SwTextFrame
&>(GetAnchorFrame());
71 /** calculate position for object
73 OD 30.07.2003 #110978#
74 members <maAnchorPos>, <mnRelPos>, <maObjBoundRect> and
75 <mnLineAlignment> are calculated.
76 calculated position is set at the given object.
78 void SwAsCharAnchoredObjectPosition::CalcPosition()
80 const SwTextFrame
& rAnchorFrame
= GetAnchorTextFrame();
81 // swap anchor frame, if swapped. Note: destructor takes care of the 'undo'
82 SwFrameSwapper
aFrameSwapper( &rAnchorFrame
, false );
84 SwRectFnSet
aRectFnSet(&rAnchorFrame
);
86 Point
aAnchorPos( mrProposedAnchorPos
);
88 const SwFrameFormat
& rFrameFormat
= GetFrameFormat();
90 SwRect
aObjBoundRect( GetAnchoredObj().GetObjRect() );
91 SwTwips nObjWidth
= aRectFnSet
.GetWidth(aObjBoundRect
);
93 // determine spacing values considering layout-/text-direction
94 const SvxLRSpaceItem
& rLRSpace
= rFrameFormat
.GetLRSpace();
95 const SvxULSpaceItem
& rULSpace
= rFrameFormat
.GetULSpace();
96 SwTwips nLRSpaceLeft
, nLRSpaceRight
, nULSpaceUpper
, nULSpaceLower
;
98 if ( rAnchorFrame
.IsVertical() )
100 // Seems to be easier to do it all the horizontal way
101 // So, from now on think horizontal.
102 rAnchorFrame
.SwitchVerticalToHorizontal( aObjBoundRect
);
103 rAnchorFrame
.SwitchVerticalToHorizontal( aAnchorPos
);
105 // convert the spacing values
106 nLRSpaceLeft
= rULSpace
.GetUpper();
107 nLRSpaceRight
= rULSpace
.GetLower();
108 nULSpaceUpper
= rLRSpace
.GetRight();
109 nULSpaceLower
= rLRSpace
.GetLeft();
113 if ( rAnchorFrame
.IsRightToLeft() )
115 nLRSpaceLeft
= rLRSpace
.GetRight();
116 nLRSpaceRight
= rLRSpace
.GetLeft();
120 nLRSpaceLeft
= rLRSpace
.GetLeft();
121 nLRSpaceRight
= rLRSpace
.GetRight();
124 nULSpaceUpper
= rULSpace
.GetUpper();
125 nULSpaceLower
= rULSpace
.GetLower();
129 // consider left and upper spacing by adjusting anchor position.
130 // left spacing is only considered, if requested.
131 if( mnFlags
& AsCharFlags::UlSpace
)
133 aAnchorPos
.AdjustX(nLRSpaceLeft
);
135 aAnchorPos
.AdjustY(nULSpaceUpper
);
137 // for drawing objects: consider difference between its bounding rectangle
138 // and its snapping rectangle by adjusting anchor position.
139 // left difference is only considered, if requested.
142 SwRect aSnapRect
= GetObject().GetSnapRect();
143 if ( rAnchorFrame
.IsVertical() )
145 rAnchorFrame
.SwitchVerticalToHorizontal( aSnapRect
);
148 if( mnFlags
& AsCharFlags::UlSpace
)
150 aAnchorPos
.AdjustX(aSnapRect
.Left() - aObjBoundRect
.Left() );
152 aAnchorPos
.AdjustY(aSnapRect
.Top() - aObjBoundRect
.Top() );
155 // enlarge bounding rectangle of object by its spacing.
156 aObjBoundRect
.AddLeft( - nLRSpaceLeft
);
157 aObjBoundRect
.AddWidth( nLRSpaceRight
);
158 aObjBoundRect
.AddTop( - nULSpaceUpper
);
159 aObjBoundRect
.AddHeight( nULSpaceLower
);
161 // calculate relative position to given base line.
162 const SwFormatVertOrient
& rVert
= rFrameFormat
.GetVertOrient();
163 const SwTwips nObjBoundHeight
= ( mnFlags
& AsCharFlags::Rotate
)
164 ? aObjBoundRect
.Width()
165 : aObjBoundRect
.Height();
166 const SwTwips nRelPos
= GetRelPosToBase( nObjBoundHeight
, rVert
);
168 // for initial positioning:
169 // adjust the proposed anchor position by difference between
170 // calculated relative position to base line and current maximal line ascent.
171 // Note: In the following line formatting the base line will be adjusted
172 // by the same difference.
173 if( mnFlags
& AsCharFlags::Init
&& nRelPos
< 0 && mnLineAscentInclObjs
< -nRelPos
)
175 if( mnFlags
& AsCharFlags::Rotate
)
176 aAnchorPos
.AdjustX( -(mnLineAscentInclObjs
+ nRelPos
) );
178 aAnchorPos
.AdjustY( -(mnLineAscentInclObjs
+ nRelPos
) );
181 // consider BIDI-multiportion by adjusting proposed anchor position
182 if( mnFlags
& AsCharFlags::Bidi
)
183 aAnchorPos
.AdjustX( -(aObjBoundRect
.Width()) );
185 // calculate relative position considering rotation and inside rotation
186 // reverse direction.
189 if( mnFlags
& AsCharFlags::Rotate
)
191 if( mnFlags
& AsCharFlags::Reverse
)
192 aRelPos
.setX( -nRelPos
- aObjBoundRect
.Width() );
195 aRelPos
.setX( nRelPos
);
196 aRelPos
.setY( -aObjBoundRect
.Height() );
200 aRelPos
.setY( nRelPos
);
205 if( !( mnFlags
& AsCharFlags::Quick
) )
207 // save calculated Y-position value for 'automatic' vertical positioning,
208 // in order to avoid a switch to 'manual' vertical positioning in
209 // <SwDrawContact::Changed_(..)>.
210 const sal_Int16 eVertOrient
= rVert
.GetVertOrient();
211 if( rVert
.GetPos() != nRelPos
&& eVertOrient
!= text::VertOrientation::NONE
)
213 SwFormatVertOrient
aVert( rVert
);
214 aVert
.SetPos( nRelPos
);
215 const_cast<SwFrameFormat
&>(rFrameFormat
).LockModify();
216 const_cast<SwFrameFormat
&>(rFrameFormat
).SetFormatAttr( aVert
);
217 const_cast<SwFrameFormat
&>(rFrameFormat
).UnlockModify();
220 // determine absolute anchor position considering layout directions.
221 // Note: Use copy of <aAnchorPos>, because it's needed for
222 // setting relative position.
223 Point
aAbsAnchorPos( aAnchorPos
);
224 if ( rAnchorFrame
.IsRightToLeft() )
226 rAnchorFrame
.SwitchLTRtoRTL( aAbsAnchorPos
);
227 aAbsAnchorPos
.AdjustX( -nObjWidth
);
229 if ( rAnchorFrame
.IsVertical() )
230 rAnchorFrame
.SwitchHorizontalToVertical( aAbsAnchorPos
);
232 // set proposed anchor position at the drawing object.
233 // OD 2004-04-06 #i26791# - distinction between 'master' drawing
234 // object and 'virtual' drawing object no longer needed.
235 GetObject().SetAnchorPos( aAbsAnchorPos
);
237 // move drawing object to set its correct relative position.
239 SwRect aSnapRect
= GetObject().GetSnapRect();
240 if ( rAnchorFrame
.IsVertical() )
241 rAnchorFrame
.SwitchVerticalToHorizontal( aSnapRect
);
244 if ( rAnchorFrame
.IsRightToLeft() )
245 aDiff
= aRelPos
+ aAbsAnchorPos
- aSnapRect
.TopLeft();
247 aDiff
= aRelPos
+ aAnchorPos
- aSnapRect
.TopLeft();
249 if ( rAnchorFrame
.IsVertical() )
250 aDiff
= Point( -aDiff
.Y(), aDiff
.X() );
252 // OD 2004-04-06 #i26791# - distinction between 'master' drawing
253 // object and 'virtual' drawing object no longer needed.
254 GetObject().Move( Size( aDiff
.X(), aDiff
.Y() ) );
258 // switch horizontal, LTR anchor position to absolute values.
259 if ( rAnchorFrame
.IsRightToLeft() )
261 rAnchorFrame
.SwitchLTRtoRTL( aAnchorPos
);
262 aAnchorPos
.AdjustX( -nObjWidth
);
264 if ( rAnchorFrame
.IsVertical() )
265 rAnchorFrame
.SwitchHorizontalToVertical( aAnchorPos
);
267 // #i44347# - keep last object rectangle at anchored object
268 OSL_ENSURE( dynamic_cast<const SwAnchoredDrawObject
*>( &GetAnchoredObj() ) != nullptr,
269 "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong type of anchored object." );
270 SwAnchoredDrawObject
& rAnchoredDrawObj
=
271 static_cast<SwAnchoredDrawObject
&>( GetAnchoredObj() );
272 rAnchoredDrawObj
.SetLastObjRect( rAnchoredDrawObj
.GetObjRect().SVRect() );
276 // determine absolute anchor position and calculate corresponding
277 // relative position and its relative position attribute.
278 // Note: The relative position contains the spacing values.
280 if ( rAnchorFrame
.IsRightToLeft() )
282 rAnchorFrame
.SwitchLTRtoRTL( aAnchorPos
);
283 aAnchorPos
.AdjustX( -nObjWidth
);
285 if ( rAnchorFrame
.IsVertical() )
287 rAnchorFrame
.SwitchHorizontalToVertical( aAnchorPos
);
288 aRelAttr
= Point( -nRelPos
, 0 );
289 aRelPos
= Point( -aRelPos
.Y(), aRelPos
.X() );
292 aRelAttr
= Point( 0, nRelPos
);
294 // OD 2004-03-23 #i26791#
295 OSL_ENSURE( dynamic_cast<const SwFlyInContentFrame
*>( &GetAnchoredObj()) != nullptr,
296 "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong anchored object." );
297 const SwFlyInContentFrame
& rFlyInContentFrame
=
298 static_cast<const SwFlyInContentFrame
&>(GetAnchoredObj());
299 if ( !(mnFlags
& AsCharFlags::Quick
) &&
300 ( aAnchorPos
!= rFlyInContentFrame
.GetRefPoint() ||
301 aRelAttr
!= rFlyInContentFrame
.GetCurrRelPos() ) )
303 // set new anchor position and relative position
304 SwFlyInContentFrame
* pFlyInContentFrame
= &const_cast<SwFlyInContentFrame
&>(rFlyInContentFrame
);
305 pFlyInContentFrame
->SetRefPoint( aAnchorPos
, aRelAttr
, aRelPos
);
306 if( nObjWidth
!= aRectFnSet
.GetWidth(pFlyInContentFrame
->getFrameArea()) )
308 // recalculate object bound rectangle, if object width has changed.
309 aObjBoundRect
= GetAnchoredObj().GetObjRect();
310 aObjBoundRect
.AddLeft( - rLRSpace
.GetLeft() );
311 aObjBoundRect
.AddWidth( rLRSpace
.GetRight() );
312 aObjBoundRect
.AddTop( - rULSpace
.GetUpper() );
313 aObjBoundRect
.AddHeight( rULSpace
.GetLower() );
316 OSL_ENSURE( aRectFnSet
.GetHeight(rFlyInContentFrame
.getFrameArea()),
317 "SwAnchoredObjectPosition::CalcPosition(..) - fly frame has an invalid height" );
320 // keep calculated values
321 maAnchorPos
= aAnchorPos
;
323 maObjBoundRect
= aObjBoundRect
;
326 /** determine the relative position to base line for object position type AS_CHAR
328 OD 29.07.2003 #110978#
329 Note about values set at member <mnLineAlignment> -
330 value gives feedback for the line formatting.
331 0 - no feedback; 1|2|3 - proposed formatting of characters
332 at top|at center|at bottom of line.
334 SwTwips
SwAsCharAnchoredObjectPosition::GetRelPosToBase(
335 const SwTwips _nObjBoundHeight
,
336 const SwFormatVertOrient
& _rVert
)
338 SwTwips nRelPosToBase
= 0;
340 mnLineAlignment
= sw::LineAlign::NONE
;
342 const sal_Int16 eVertOrient
= _rVert
.GetVertOrient();
344 if ( eVertOrient
== text::VertOrientation::NONE
)
345 nRelPosToBase
= _rVert
.GetPos();
348 if ( eVertOrient
== text::VertOrientation::CENTER
)
349 nRelPosToBase
-= _nObjBoundHeight
/ 2;
350 else if ( eVertOrient
== text::VertOrientation::TOP
)
351 nRelPosToBase
-= _nObjBoundHeight
;
352 else if ( eVertOrient
== text::VertOrientation::BOTTOM
)
354 else if ( eVertOrient
== text::VertOrientation::CHAR_CENTER
)
355 nRelPosToBase
-= ( _nObjBoundHeight
+ mnLineAscent
- mnLineDescent
) / 2;
356 else if ( eVertOrient
== text::VertOrientation::CHAR_TOP
)
357 nRelPosToBase
-= mnLineAscent
;
358 else if ( eVertOrient
== text::VertOrientation::CHAR_BOTTOM
)
359 nRelPosToBase
+= mnLineDescent
- _nObjBoundHeight
;
362 if( _nObjBoundHeight
>= mnLineAscentInclObjs
+ mnLineDescentInclObjs
)
364 // object is at least as high as the line. Thus, no more is
365 // positioning necessary. Also, the max. ascent isn't changed.
366 nRelPosToBase
-= mnLineAscentInclObjs
;
367 if ( eVertOrient
== text::VertOrientation::LINE_CENTER
)
368 mnLineAlignment
= sw::LineAlign::CENTER
;
369 else if ( eVertOrient
== text::VertOrientation::LINE_TOP
)
370 mnLineAlignment
= sw::LineAlign::TOP
;
371 else if ( eVertOrient
== text::VertOrientation::LINE_BOTTOM
)
372 mnLineAlignment
= sw::LineAlign::BOTTOM
;
374 else if ( eVertOrient
== text::VertOrientation::LINE_CENTER
)
376 nRelPosToBase
-= ( _nObjBoundHeight
+ mnLineAscentInclObjs
- mnLineDescentInclObjs
) / 2;
377 mnLineAlignment
= sw::LineAlign::CENTER
;
379 else if ( eVertOrient
== text::VertOrientation::LINE_TOP
)
381 nRelPosToBase
-= mnLineAscentInclObjs
;
382 mnLineAlignment
= sw::LineAlign::TOP
;
384 else if ( eVertOrient
== text::VertOrientation::LINE_BOTTOM
)
386 nRelPosToBase
+= mnLineDescentInclObjs
- _nObjBoundHeight
;
387 mnLineAlignment
= sw::LineAlign::BOTTOM
;
392 return nRelPosToBase
;
395 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */