1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 #include <ascharanchoredobjectposition.hxx>
27 #include <frame.hxx>
28 #include <txtfrm.hxx>
29 #include <flyfrms.hxx>
30 #ifndef _SVX_SVDOBJ_HXX
31 #include <svx/svdobj.hxx>
32 #endif
33 #include <dcontact.hxx>
34 #include <frmfmt.hxx>
35 #include <frmatr.hxx>
36 #include <editeng/lrspitem.hxx>
37 #include <editeng/ulspitem.hxx>
38 #include <fmtornt.hxx>
39
40 #include <com/sun/star/text/HoriOrientation.hpp>
41
42
43 using namespace ::com::sun::star;
44 using namespace objectpositioning;
45
46 /** constructor
47
48 @author OD
49 */
SwAsCharAnchoredObjectPosition(SdrObject & _rDrawObj,const Point & _rProposedAnchorPos,const AsCharFlags _nFlags,const SwTwips _nLineAscent,const SwTwips _nLineDescent,const SwTwips _nLineAscentInclObjs,const SwTwips _nLineDescentInclObjs)50 SwAsCharAnchoredObjectPosition::SwAsCharAnchoredObjectPosition(
51 SdrObject& _rDrawObj,
52 const Point& _rProposedAnchorPos,
53 const AsCharFlags _nFlags,
54 const SwTwips _nLineAscent,
55 const SwTwips _nLineDescent,
56 const SwTwips _nLineAscentInclObjs,
57 const SwTwips _nLineDescentInclObjs )
58 : SwAnchoredObjectPosition( _rDrawObj ),
59 mrProposedAnchorPos( _rProposedAnchorPos ),
60 mnFlags( _nFlags ),
61 mnLineAscent( _nLineAscent ),
62 mnLineDescent( _nLineDescent ),
63 mnLineAscentInclObjs( _nLineAscentInclObjs ),
64 mnLineDescentInclObjs( _nLineDescentInclObjs ),
65 maAnchorPos ( Point() ),
66 mnRelPos ( 0 ),
67 maObjBoundRect ( SwRect() ),
68 mnLineAlignment ( 0 )
69 {}
70
71 /** destructor
72
73 @author OD
74 */
~SwAsCharAnchoredObjectPosition()75 SwAsCharAnchoredObjectPosition::~SwAsCharAnchoredObjectPosition()
76 {}
77
78 /** method to cast <SwAnchoredObjectPosition::GetAnchorFrm()> to needed type
79
80 @author OD
81 */
GetAnchorTxtFrm() const82 const SwTxtFrm& SwAsCharAnchoredObjectPosition::GetAnchorTxtFrm() const
83 {
84 ASSERT( GetAnchorFrm().ISA(SwTxtFrm),
85 "SwAsCharAnchoredObjectPosition::GetAnchorTxtFrm() - wrong anchor frame type" );
86
87 return static_cast<const SwTxtFrm&>(GetAnchorFrm());
88 }
89
90 /** calculate position for object
91
92 OD 30.07.2003 #110978#
93 members <maAnchorPos>, <mnRelPos>, <maObjBoundRect> and
94 <mnLineAlignment> are calculated.
95 calculated position is set at the given object.
96
97 @author OD
98 */
CalcPosition()99 void SwAsCharAnchoredObjectPosition::CalcPosition()
100 {
101 const SwTxtFrm& rAnchorFrm = GetAnchorTxtFrm();
102 // swap anchor frame, if swapped. Note: destructor takes care of the 'undo'
103 SwFrmSwapper aFrmSwapper( &rAnchorFrm, false );
104
105 SWRECTFN( ( &rAnchorFrm ) )
106
107 Point aAnchorPos( mrProposedAnchorPos );
108
109 const SwFrmFmt& rFrmFmt = GetFrmFmt();
110
111 SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() );
112 SwTwips nObjWidth = (aObjBoundRect.*fnRect->fnGetWidth)();
113
114 // determine spacing values considering layout-/text-direction
115 const SvxLRSpaceItem& rLRSpace = rFrmFmt.GetLRSpace();
116 const SvxULSpaceItem& rULSpace = rFrmFmt.GetULSpace();
117 SwTwips nLRSpaceLeft, nLRSpaceRight, nULSpaceUpper, nULSpaceLower;
118 {
119 if ( rAnchorFrm.IsVertical() )
120 {
121 // Seems to be easier to do it all the horizontal way
122 // So, from now on think horizontal.
123 rAnchorFrm.SwitchVerticalToHorizontal( aObjBoundRect );
124 rAnchorFrm.SwitchVerticalToHorizontal( aAnchorPos );
125
126 // convert the spacing values
127 nLRSpaceLeft = rULSpace.GetUpper();
128 nLRSpaceRight = rULSpace.GetLower();
129 nULSpaceUpper = rLRSpace.GetRight();
130 nULSpaceLower = rLRSpace.GetLeft();
131 }
132 else
133 {
134 if ( rAnchorFrm.IsRightToLeft() )
135 {
136 nLRSpaceLeft = rLRSpace.GetRight();
137 nLRSpaceRight = rLRSpace.GetLeft();
138 }
139 else
140 {
141 nLRSpaceLeft = rLRSpace.GetLeft();
142 nLRSpaceRight = rLRSpace.GetRight();
143 }
144
145 nULSpaceUpper = rULSpace.GetUpper();
146 nULSpaceLower = rULSpace.GetLower();
147 }
148 }
149
150 // consider left and upper spacing by adjusting anchor position.
151 // left spacing is only considered, if requested.
152 if( mnFlags & AS_CHAR_ULSPACE )
153 {
154 aAnchorPos.X() += nLRSpaceLeft;
155 }
156 aAnchorPos.Y() += nULSpaceUpper;
157
158 // for drawing objects: consider difference between its bounding rectangle
159 // and its snapping rectangle by adjusting anchor position.
160 // left difference is only considered, if requested.
161 if( !IsObjFly() )
162 {
163 SwRect aSnapRect = GetObject().GetSnapRect();
164 if ( rAnchorFrm.IsVertical() )
165 {
166 rAnchorFrm.SwitchVerticalToHorizontal( aSnapRect );
167 }
168
169 if( mnFlags & AS_CHAR_ULSPACE )
170 {
171 aAnchorPos.X() += aSnapRect.Left() - aObjBoundRect.Left();
172 }
173 aAnchorPos.Y() += aSnapRect.Top() - aObjBoundRect.Top();
174 }
175
176 // enlarge bounding rectangle of object by its spacing.
177 aObjBoundRect.Left( aObjBoundRect.Left() - nLRSpaceLeft );
178 aObjBoundRect.Width( aObjBoundRect.Width() + nLRSpaceRight );
179 aObjBoundRect.Top( aObjBoundRect.Top() - nULSpaceUpper );
180 aObjBoundRect.Height( aObjBoundRect.Height() + nULSpaceLower );
181
182 // calculate relative position to given base line.
183 const SwFmtVertOrient& rVert = rFrmFmt.GetVertOrient();
184 const SwTwips nObjBoundHeight = ( mnFlags & AS_CHAR_ROTATE )
185 ? aObjBoundRect.Width()
186 : aObjBoundRect.Height();
187 const SwTwips nRelPos = _GetRelPosToBase( nObjBoundHeight, rVert );
188
189 // for initial positioning:
190 // adjust the proposed anchor position by difference between
191 // calculated relative position to base line and current maximal line ascent.
192 // Note: In the following line formatting the base line will be adjusted
193 // by the same difference.
194 if( mnFlags & AS_CHAR_INIT && nRelPos < 0 && mnLineAscentInclObjs < -nRelPos )
195 {
196 if( mnFlags & AS_CHAR_ROTATE )
197 aAnchorPos.X() -= mnLineAscentInclObjs + nRelPos;
198 else
199 aAnchorPos.Y() -= mnLineAscentInclObjs + nRelPos;
200 }
201
202 // consider BIDI-multiportion by adjusting proposed anchor position
203 if( mnFlags & AS_CHAR_BIDI )
204 aAnchorPos.X() -= aObjBoundRect.Width();
205
206 // calculate relative position considering rotation and inside rotation
207 // reverse direction.
208 Point aRelPos;
209 {
210 if( mnFlags & AS_CHAR_ROTATE )
211 {
212 if( mnFlags & AS_CHAR_REVERSE )
213 aRelPos.X() = -nRelPos - aObjBoundRect.Width();
214 else
215 {
216 aRelPos.X() = nRelPos;
217 aRelPos.Y() = -aObjBoundRect.Height();
218 }
219 }
220 else
221 aRelPos.Y() = nRelPos;
222 }
223
224 if( !IsObjFly() )
225 {
226 if( !( mnFlags & AS_CHAR_QUICK ) )
227 {
228 // save calculated Y-position value for 'automatic' vertical positioning,
229 // in order to avoid a switch to 'manual' vertical positioning in
230 // <SwDrawContact::_Changed(..)>.
231 const sal_Int16 eVertOrient = rVert.GetVertOrient();
232 if( rVert.GetPos() != nRelPos && eVertOrient != text::VertOrientation::NONE )
233 {
234 SwFmtVertOrient aVert( rVert );
235 aVert.SetPos( nRelPos );
236 const_cast<SwFrmFmt&>(rFrmFmt).LockModify();
237 const_cast<SwFrmFmt&>(rFrmFmt).SetFmtAttr( aVert );
238 const_cast<SwFrmFmt&>(rFrmFmt).UnlockModify();
239 }
240
241 // determine absolute anchor position considering layout directions.
242 // Note: Use copy of <aAnchorPos>, because it's needed for
243 // setting relative position.
244 Point aAbsAnchorPos( aAnchorPos );
245 if ( rAnchorFrm.IsRightToLeft() )
246 {
247 rAnchorFrm.SwitchLTRtoRTL( aAbsAnchorPos );
248 aAbsAnchorPos.X() -= nObjWidth;
249 }
250 if ( rAnchorFrm.IsVertical() )
251 rAnchorFrm.SwitchHorizontalToVertical( aAbsAnchorPos );
252
253 // set proposed anchor position at the drawing object.
254 // OD 2004-04-06 #i26791# - distinction between 'master' drawing
255 // object and 'virtual' drawing object no longer needed.
256 GetObject().SetAnchorPos( aAbsAnchorPos );
257
258 // move drawing object to set its correct relative position.
259 {
260 SwRect aSnapRect = GetObject().GetSnapRect();
261 if ( rAnchorFrm.IsVertical() )
262 rAnchorFrm.SwitchVerticalToHorizontal( aSnapRect );
263
264 Point aDiff;
265 if ( rAnchorFrm.IsRightToLeft() )
266 aDiff = aRelPos + aAbsAnchorPos - aSnapRect.TopLeft();
267 else
268 aDiff = aRelPos + aAnchorPos - aSnapRect.TopLeft();
269
270 if ( rAnchorFrm.IsVertical() )
271 aDiff = Point( -aDiff.Y(), aDiff.X() );
272
273 // OD 2004-04-06 #i26791# - distinction between 'master' drawing
274 // object and 'virtual' drawing object no longer needed.
275 GetObject().Move( Size( aDiff.X(), aDiff.Y() ) );
276 }
277 }
278
279 // switch horizontal, LTR anchor position to absolute values.
280 if ( rAnchorFrm.IsRightToLeft() )
281 {
282 rAnchorFrm.SwitchLTRtoRTL( aAnchorPos );
283 aAnchorPos.X() -= nObjWidth;
284 }
285 if ( rAnchorFrm.IsVertical() )
286 rAnchorFrm.SwitchHorizontalToVertical( aAnchorPos );
287
288 // --> OD 2005-03-09 #i44347# - keep last object rectangle at anchored object
289 ASSERT ( GetAnchoredObj().ISA(SwAnchoredDrawObject),
290 "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong type of anchored object." );
291 SwAnchoredDrawObject& rAnchoredDrawObj =
292 static_cast<SwAnchoredDrawObject&>( GetAnchoredObj() );
293 rAnchoredDrawObj.SetLastObjRect( rAnchoredDrawObj.GetObjRect().SVRect() );
294 // <--
295 }
296 else
297 {
298 // determine absolute anchor position and calculate corresponding
299 // relative position and its relative position attribute.
300 // Note: The relative position contains the spacing values.
301 Point aRelAttr;
302 if ( rAnchorFrm.IsRightToLeft() )
303 {
304 rAnchorFrm.SwitchLTRtoRTL( aAnchorPos );
305 aAnchorPos.X() -= nObjWidth;
306 }
307 if ( rAnchorFrm.IsVertical() )
308 {
309 rAnchorFrm.SwitchHorizontalToVertical( aAnchorPos );
310 aRelAttr = Point( -nRelPos, 0 );
311 aRelPos = Point( -aRelPos.Y(), aRelPos.X() );
312 }
313 else
314 aRelAttr = Point( 0, nRelPos );
315
316 // OD 2004-03-23 #i26791#
317 ASSERT( GetAnchoredObj().ISA(SwFlyInCntFrm),
318 "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong anchored object." );
319 const SwFlyInCntFrm& rFlyInCntFrm =
320 static_cast<const SwFlyInCntFrm&>(GetAnchoredObj());
321 if ( !(mnFlags & AS_CHAR_QUICK) &&
322 ( aAnchorPos != rFlyInCntFrm.GetRefPoint() ||
323 aRelAttr != rFlyInCntFrm.GetCurrRelPos() ) )
324 {
325 // set new anchor position and relative position
326 SwFlyInCntFrm* pFlyInCntFrm = &(const_cast<SwFlyInCntFrm&>(rFlyInCntFrm));
327 pFlyInCntFrm->SetRefPoint( aAnchorPos, aRelAttr, aRelPos );
328 if( nObjWidth != (pFlyInCntFrm->Frm().*fnRect->fnGetWidth)() )
329 {
330 // recalculate object bound rectangle, if object width has changed.
331 aObjBoundRect = GetAnchoredObj().GetObjRect();
332 aObjBoundRect.Left( aObjBoundRect.Left() - rLRSpace.GetLeft() );
333 aObjBoundRect.Width( aObjBoundRect.Width() + rLRSpace.GetRight() );
334 aObjBoundRect.Top( aObjBoundRect.Top() - rULSpace.GetUpper() );
335 aObjBoundRect.Height( aObjBoundRect.Height() + rULSpace.GetLower() );
336 }
337 }
338 ASSERT( (rFlyInCntFrm.Frm().*fnRect->fnGetHeight)(),
339 "SwAnchoredObjectPosition::CalcPosition(..) - fly frame has an invalid height" );
340 }
341
342 // keep calculated values
343 maAnchorPos = aAnchorPos;
344 mnRelPos = nRelPos;
345 maObjBoundRect = aObjBoundRect;
346 }
347
348 /** determine the relative position to base line for object position type AS_CHAR
349
350 OD 29.07.2003 #110978#
351 Note about values set at member <mnLineAlignment> -
352 value gives feedback for the line formatting.
353 0 - no feedback; 1|2|3 - proposed formatting of characters
354 at top|at center|at bottom of line.
355
356 @author OD
357 */
_GetRelPosToBase(const SwTwips _nObjBoundHeight,const SwFmtVertOrient & _rVert)358 SwTwips SwAsCharAnchoredObjectPosition::_GetRelPosToBase(
359 const SwTwips _nObjBoundHeight,
360 const SwFmtVertOrient& _rVert )
361 {
362 SwTwips nRelPosToBase = 0;
363
364 mnLineAlignment = 0;
365
366 const sal_Int16 eVertOrient = _rVert.GetVertOrient();
367
368 if ( eVertOrient == text::VertOrientation::NONE )
369 nRelPosToBase = _rVert.GetPos();
370 else
371 {
372 if ( eVertOrient == text::VertOrientation::CENTER )
373 nRelPosToBase -= _nObjBoundHeight / 2;
374 else if ( eVertOrient == text::VertOrientation::TOP )
375 nRelPosToBase -= _nObjBoundHeight;
376 else if ( eVertOrient == text::VertOrientation::BOTTOM )
377 nRelPosToBase = 0;
378 else if ( eVertOrient == text::VertOrientation::CHAR_CENTER )
379 nRelPosToBase -= ( _nObjBoundHeight + mnLineAscent - mnLineDescent ) / 2;
380 else if ( eVertOrient == text::VertOrientation::CHAR_TOP )
381 nRelPosToBase -= mnLineAscent;
382 else if ( eVertOrient == text::VertOrientation::CHAR_BOTTOM )
383 nRelPosToBase += mnLineDescent - _nObjBoundHeight;
384 else
385 {
386 if( _nObjBoundHeight >= mnLineAscentInclObjs + mnLineDescentInclObjs )
387 {
388 // object is at least as high as the line. Thus, no more is
389 // positioning necessary. Also, the max. ascent isn't changed.
390 nRelPosToBase -= mnLineAscentInclObjs;
391 if ( eVertOrient == text::VertOrientation::LINE_CENTER )
392 mnLineAlignment = 2;
393 else if ( eVertOrient == text::VertOrientation::LINE_TOP )
394 mnLineAlignment = 1;
395 else if ( eVertOrient == text::VertOrientation::LINE_BOTTOM )
396 mnLineAlignment = 3;
397 }
398 else if ( eVertOrient == text::VertOrientation::LINE_CENTER )
399 {
400 nRelPosToBase -= ( _nObjBoundHeight + mnLineAscentInclObjs - mnLineDescentInclObjs ) / 2;
401 mnLineAlignment = 2;
402 }
403 else if ( eVertOrient == text::VertOrientation::LINE_TOP )
404 {
405 nRelPosToBase -= mnLineAscentInclObjs;
406 mnLineAlignment = 1;
407 }
408 else if ( eVertOrient == text::VertOrientation::LINE_BOTTOM )
409 {
410 nRelPosToBase += mnLineDescentInclObjs - _nObjBoundHeight;
411 mnLineAlignment = 3;
412 }
413 }
414 }
415
416 return nRelPosToBase;
417 }
418
419 /** calculated anchored position for object position
420
421 @author OD
422 */
GetAnchorPos() const423 Point SwAsCharAnchoredObjectPosition::GetAnchorPos() const
424 {
425 return maAnchorPos;
426 }
427
428 /** calculated relative position to base line for object position
429
430 @author OD
431 */
GetRelPosY() const432 SwTwips SwAsCharAnchoredObjectPosition::GetRelPosY() const
433 {
434 return mnRelPos;
435 }
436
437 /** determined object rectangle including spacing for object
438
439 @author OD
440 */
GetObjBoundRectInclSpacing() const441 SwRect SwAsCharAnchoredObjectPosition::GetObjBoundRectInclSpacing() const
442 {
443 return maObjBoundRect;
444 }
445
446 /** determined line alignment
447
448 @author OD
449 */
GetLineAlignment() const450 sal_uInt8 SwAsCharAnchoredObjectPosition::GetLineAlignment() const
451 {
452 return mnLineAlignment;
453 }
454
455