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