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 */ 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 */ 75 SwAsCharAnchoredObjectPosition::~SwAsCharAnchoredObjectPosition() 76 {} 77 78 /** method to cast <SwAnchoredObjectPosition::GetAnchorFrm()> to needed type 79 80 @author OD 81 */ 82 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 */ 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 */ 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 */ 423 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 */ 432 SwTwips SwAsCharAnchoredObjectPosition::GetRelPosY() const 433 { 434 return mnRelPos; 435 } 436 437 /** determined object rectangle including spacing for object 438 439 @author OD 440 */ 441 SwRect SwAsCharAnchoredObjectPosition::GetObjBoundRectInclSpacing() const 442 { 443 return maObjBoundRect; 444 } 445 446 /** determined line alignment 447 448 @author OD 449 */ 450 sal_uInt8 SwAsCharAnchoredObjectPosition::GetLineAlignment() const 451 { 452 return mnLineAlignment; 453 } 454 455