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