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