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 27 28 #include <hintids.hxx> 29 30 #include <com/sun/star/i18n/ScriptType.hdl> 31 #include <vcl/graph.hxx> 32 #include <editeng/brshitem.hxx> 33 #include <vcl/metric.hxx> 34 #include <vcl/outdev.hxx> 35 #include <viewopt.hxx> // SwViewOptions 36 #include <txtcfg.hxx> 37 #include <SwPortionHandler.hxx> 38 #include <porlay.hxx> 39 #include <porfld.hxx> 40 #include <inftxt.hxx> 41 #include <blink.hxx> // pBlink 42 #include <frmtool.hxx> // DrawGraphic 43 #include <viewsh.hxx> 44 #include <docsh.hxx> 45 #include <doc.hxx> 46 #include "rootfrm.hxx" 47 #include <breakit.hxx> 48 #include <porrst.hxx> 49 #include <porftn.hxx> // SwFtnPortion 50 #include <accessibilityoptions.hxx> 51 #include <editeng/lrspitem.hxx> 52 53 #include <unicode/ubidi.h> 54 55 using namespace ::com::sun::star; 56 57 /************************************************************************* 58 * class SwFldPortion 59 *************************************************************************/ 60 61 SwLinePortion *SwFldPortion::Compress() 62 { return (GetLen() || aExpand.Len() || SwLinePortion::Compress()) ? this : 0; } 63 64 SwFldPortion *SwFldPortion::Clone( const XubString &rExpand ) const 65 { 66 SwFont *pNewFnt; 67 if( 0 != ( pNewFnt = pFnt ) ) 68 { 69 pNewFnt = new SwFont( *pFnt ); 70 } 71 SwFldPortion* pClone = new SwFldPortion( rExpand, pNewFnt, bPlaceHolder ); 72 pClone->SetNextOffset( nNextOffset ); 73 pClone->m_bNoLength = this->m_bNoLength; 74 return pClone; 75 } 76 77 void SwFldPortion::TakeNextOffset( const SwFldPortion* pFld ) 78 { 79 ASSERT( pFld, "TakeNextOffset: Missing Source" ); 80 nNextOffset = pFld->GetNextOffset(); 81 aExpand.Erase( 0, nNextOffset ); 82 bFollow = sal_True; 83 } 84 85 SwFldPortion::SwFldPortion( const XubString &rExpand, SwFont *pFont, sal_Bool bPlaceHold ) 86 : aExpand(rExpand), pFnt(pFont), nNextOffset(0), nNextScriptChg(STRING_LEN), nViewWidth(0), 87 bFollow( sal_False ), bHasFollow( sal_False ), bPlaceHolder( bPlaceHold ) 88 , m_bNoLength( sal_False ) 89 { 90 SetWhichPor( POR_FLD ); 91 m_nAttrFldType = 0; 92 } 93 94 SwFldPortion::SwFldPortion( const SwFldPortion& rFld ) 95 : SwExpandPortion( rFld ), 96 aExpand( rFld.GetExp() ), 97 nNextOffset( rFld.GetNextOffset() ), 98 nNextScriptChg( rFld.GetNextScriptChg() ), 99 bFollow( rFld.IsFollow() ), 100 bLeft( rFld.IsLeft() ), 101 bHide( rFld.IsHide() ), 102 bCenter( rFld.IsCenter() ), 103 bHasFollow( rFld.HasFollow() ), 104 bPlaceHolder( rFld.bPlaceHolder ) 105 , m_bNoLength( rFld.m_bNoLength ) 106 { 107 if ( rFld.HasFont() ) 108 pFnt = new SwFont( *rFld.GetFont() ); 109 else 110 pFnt = 0; 111 112 SetWhichPor( POR_FLD ); 113 } 114 115 SwFldPortion::~SwFldPortion() 116 { 117 delete pFnt; 118 if( pBlink ) 119 pBlink->Delete( this ); 120 } 121 122 /************************************************************************* 123 * virtual SwFldPortion::GetViewWidth() 124 *************************************************************************/ 125 126 KSHORT SwFldPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const 127 { 128 // Wir stehen zwar im const, aber nViewWidth sollte erst im letzten 129 // Moment errechnet werden: 130 SwFldPortion* pThis = (SwFldPortion*)this; 131 if( !Width() && rInf.OnWin() && !rInf.GetOpt().IsPagePreview() && 132 !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() ) 133 { 134 if( !nViewWidth ) 135 pThis->nViewWidth = rInf.GetTxtSize( ' ' ).Width(); 136 } 137 else 138 pThis->nViewWidth = 0; 139 return nViewWidth; 140 } 141 142 /************************************************************************* 143 * virtual SwFldPortion::Format() 144 *************************************************************************/ 145 146 // 8653: in keinem Fall nur SetLen(0); 147 148 /************************************************************************* 149 * Hilfsklasse SwFldSlot 150 **************************************************************************/ 151 152 class SwFldSlot 153 { 154 const XubString *pOldTxt; 155 XubString aTxt; 156 xub_StrLen nIdx; 157 xub_StrLen nLen; 158 sal_Bool bOn; 159 SwTxtFormatInfo *pInf; 160 public: 161 SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor ); 162 ~SwFldSlot(); 163 }; 164 165 SwFldSlot::SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor ) 166 { 167 bOn = pPor->GetExpTxt( *pNew, aTxt ); 168 169 // Der Text wird ausgetauscht... 170 if( bOn ) 171 { 172 pInf = (SwTxtFormatInfo*)pNew; 173 nIdx = pInf->GetIdx(); 174 nLen = pInf->GetLen(); 175 pOldTxt = &(pInf->GetTxt()); 176 pInf->SetLen( aTxt.Len() ); 177 if( pPor->IsFollow() ) 178 { 179 pInf->SetFakeLineStart( nIdx > pInf->GetLineStart() ); 180 pInf->SetIdx( 0 ); 181 } 182 else 183 { 184 XubString aTmp( aTxt ); 185 aTxt = *pOldTxt; 186 aTxt.Erase( nIdx, 1 ); 187 aTxt.Insert( aTmp, nIdx ); 188 } 189 pInf->SetTxt( aTxt ); 190 } 191 } 192 193 SwFldSlot::~SwFldSlot() 194 { 195 if( bOn ) 196 { 197 pInf->SetTxt( *pOldTxt ); 198 pInf->SetIdx( nIdx ); 199 pInf->SetLen( nLen ); 200 pInf->SetFakeLineStart( sal_False ); 201 } 202 } 203 204 void SwFldPortion::CheckScript( const SwTxtSizeInfo &rInf ) 205 { 206 String aTxt; 207 if( GetExpTxt( rInf, aTxt ) && aTxt.Len() && pBreakIt->GetBreakIter().is() ) 208 { 209 sal_uInt8 nActual = pFnt ? pFnt->GetActual() : rInf.GetFont()->GetActual(); 210 sal_uInt16 nScript; 211 { 212 nScript = pBreakIt->GetBreakIter()->getScriptType( aTxt, 0 ); 213 xub_StrLen nChg = 0; 214 if( i18n::ScriptType::WEAK == nScript ) 215 { 216 nChg =(xub_StrLen)pBreakIt->GetBreakIter()->endOfScript(aTxt,0,nScript); 217 if( nChg < aTxt.Len() ) 218 nScript = pBreakIt->GetBreakIter()->getScriptType( aTxt, nChg ); 219 } 220 221 // 222 // nNextScriptChg will be evaluated during SwFldPortion::Format() 223 // 224 if ( nChg < aTxt.Len() ) 225 nNextScriptChg = (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( aTxt, nChg, nScript ); 226 else 227 nNextScriptChg = aTxt.Len(); 228 229 } 230 sal_uInt8 nTmp; 231 switch ( nScript ) { 232 case i18n::ScriptType::LATIN : nTmp = SW_LATIN; break; 233 case i18n::ScriptType::ASIAN : nTmp = SW_CJK; break; 234 case i18n::ScriptType::COMPLEX : nTmp = SW_CTL; break; 235 default: nTmp = nActual; 236 } 237 238 // #i16354# Change script type for RTL text to CTL. 239 const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo(); 240 // --> OD 2009-01-29 #i98418# 241 // const sal_uInt8 nFldDir = IsNumberPortion() ? 242 const sal_uInt8 nFldDir = ( IsNumberPortion() || IsFtnNumPortion() ) ? 243 rSI.GetDefaultDir() : 244 rSI.DirType( IsFollow() ? rInf.GetIdx() - 1 : rInf.GetIdx() ); 245 // <-- 246 if ( UBIDI_RTL == nFldDir ) 247 { 248 UErrorCode nError = U_ZERO_ERROR; 249 UBiDi* pBidi = ubidi_openSized( aTxt.Len(), 0, &nError ); 250 ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(aTxt.GetBuffer()), aTxt.Len(), nFldDir, NULL, &nError ); 251 int32_t nEnd; 252 UBiDiLevel nCurrDir; 253 ubidi_getLogicalRun( pBidi, 0, &nEnd, &nCurrDir ); 254 ubidi_close( pBidi ); 255 const xub_StrLen nNextDirChg = (xub_StrLen)nEnd; 256 nNextScriptChg = Min( nNextScriptChg, nNextDirChg ); 257 258 // #i89825# change the script type also to CTL 259 // if there is no strong LTR char in the LTR run (numbers) 260 if ( nCurrDir != UBIDI_RTL ) 261 { 262 nCurrDir = UBIDI_RTL; 263 for ( xub_StrLen nCharIdx = 0; nCharIdx < nEnd; ++nCharIdx ) 264 { 265 UCharDirection nCharDir = u_charDirection ( aTxt.GetChar ( nCharIdx )); 266 if ( nCharDir == U_LEFT_TO_RIGHT || 267 nCharDir == U_LEFT_TO_RIGHT_EMBEDDING || 268 nCharDir == U_LEFT_TO_RIGHT_OVERRIDE ) 269 { 270 nCurrDir = UBIDI_LTR; 271 break; 272 } 273 } 274 } 275 276 if ( nCurrDir == UBIDI_RTL ) 277 nTmp = SW_CTL; 278 } 279 280 // --> OD 2009-01-29 #i98418# 281 // keep determined script type for footnote portions as preferred script type. 282 // For footnote portions a font can not be created directly - see footnote 283 // portion format method. 284 // if( !IsFtnPortion() && nTmp != nActual ) 285 if ( IsFtnPortion() ) 286 { 287 dynamic_cast<SwFtnPortion*>(this)->SetPreferredScriptType( nTmp ); 288 } 289 else if ( nTmp != nActual ) 290 { 291 if( !pFnt ) 292 pFnt = new SwFont( *rInf.GetFont() ); 293 pFnt->SetActual( nTmp ); 294 } 295 // <-- 296 } 297 } 298 299 sal_Bool SwFldPortion::Format( SwTxtFormatInfo &rInf ) 300 { 301 // Scope wegen aDiffTxt::DTOR! 302 xub_StrLen nRest; 303 sal_Bool bFull; 304 sal_Bool bEOL = sal_False; 305 long nTxtRest = rInf.GetTxt().Len() - rInf.GetIdx(); 306 { 307 SwFldSlot aDiffTxt( &rInf, this ); 308 SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() ); 309 aLayoutModeModifier.SetAuto(); 310 311 // Field portion has to be split in several parts if 312 // 1. There are script/direction changes inside the field 313 // 2. There are portion breaks (tab, break) inside the field: 314 const xub_StrLen nOldFullLen = rInf.GetLen(); 315 xub_StrLen nFullLen = rInf.ScanPortionEnd( rInf.GetIdx(), rInf.GetIdx() + nOldFullLen ) - rInf.GetIdx(); 316 if ( nNextScriptChg < nFullLen ) 317 { 318 nFullLen = nNextScriptChg; 319 rInf.SetHookChar( 0 ); 320 } 321 rInf.SetLen( nFullLen ); 322 323 if ( STRING_LEN != rInf.GetUnderScorePos() && 324 rInf.GetUnderScorePos() > rInf.GetIdx() ) 325 rInf.SetUnderScorePos( rInf.GetIdx() ); 326 327 if( pFnt ) 328 pFnt->GoMagic( rInf.GetVsh(), pFnt->GetActual() ); 329 330 SwFontSave aSave( rInf, pFnt ); 331 332 // 8674: Laenge muss 0 sein, bei bFull nach Format ist die Laenge 333 // gesetzt und wird in nRest uebertragen. Ansonsten bleibt die 334 // Laenge erhalten und wuerde auch in nRest einfliessen! 335 SetLen(0); 336 const MSHORT nFollow = IsFollow() ? 0 : 1; 337 338 // So komisch es aussieht, die Abfrage auf GetLen() muss wegen der 339 // ExpandPortions _hinter_ aDiffTxt (vgl. SoftHyphs) 340 // sal_False returnen wegen SetFull ... 341 if( !nFullLen ) 342 { 343 // nicht Init(), weil wir Hoehe und Ascent brauchen 344 Width(0); 345 bFull = rInf.Width() <= rInf.GetPos().X(); 346 } 347 else 348 { 349 xub_StrLen nOldLineStart = rInf.GetLineStart(); 350 if( IsFollow() ) 351 rInf.SetLineStart( 0 ); 352 rInf.SetNotEOL( nFullLen == nOldFullLen && nTxtRest > nFollow ); 353 354 // the height depending on the fields font is set, 355 // this is required for SwTxtGuess::Guess 356 Height( rInf.GetTxtHeight() ); 357 // If a kerning portion is inserted after our field portion, 358 // the ascent and height must be known 359 SetAscent( rInf.GetAscent() ); 360 bFull = SwTxtPortion::Format( rInf ); 361 rInf.SetNotEOL( sal_False ); 362 rInf.SetLineStart( nOldLineStart ); 363 } 364 xub_StrLen nTmpLen = GetLen(); 365 bEOL = !nTmpLen && nFollow && bFull; 366 nRest = nOldFullLen - nTmpLen; 367 368 // Das Zeichen wird in der ersten Portion gehalten. 369 // Unbedingt nach Format! 370 SetLen( (m_bNoLength) ? 0 : nFollow ); 371 372 if( nRest ) 373 { 374 // aExpand ist noch nicht gekuerzt worden, der neue Ofst 375 // ergibt sich durch nRest. 376 xub_StrLen nNextOfst = aExpand.Len() - nRest; 377 378 if ( IsQuoVadisPortion() ) 379 nNextOfst = nNextOfst + ((SwQuoVadisPortion*)this)->GetContTxt().Len(); 380 381 XubString aNew( aExpand, nNextOfst, STRING_LEN ); 382 aExpand.Erase( nNextOfst, STRING_LEN ); 383 384 // These characters should not be contained in the follow 385 // field portion. They are handled via the HookChar mechanism. 386 switch( aNew.GetChar( 0 )) 387 { 388 case CH_BREAK : bFull = sal_True; 389 // kein break; 390 case ' ' : 391 case CH_TAB : 392 case CHAR_HARDHYPHEN: // non-breaking hyphen 393 case CHAR_SOFTHYPHEN: 394 case CHAR_HARDBLANK: 395 case CHAR_ZWSP : 396 case CHAR_ZWNBSP : 397 case CH_TXTATR_BREAKWORD: 398 case CH_TXTATR_INWORD: 399 { 400 aNew.Erase( 0, 1 ); 401 ++nNextOfst; 402 break; 403 } 404 default: ; 405 } 406 407 // Even if there is no more text left for a follow field, 408 // we have to build a follow field portion (without font), 409 // otherwise the HookChar mechanism would not work. 410 SwFldPortion *pFld = Clone( aNew ); 411 if( aNew.Len() && !pFld->GetFont() ) 412 { 413 SwFont *pNewFnt = new SwFont( *rInf.GetFont() ); 414 pFld->SetFont( pNewFnt ); 415 } 416 pFld->SetFollow( sal_True ); 417 SetHasFollow( sal_True ); 418 // In nNextOffset steht bei einem neuangelegten Feld zunaechst 419 // der Offset, an dem es selbst im Originalstring beginnt. 420 // Wenn beim Formatieren ein FollowFeld angelegt wird, wird 421 // der Offset dieses FollowFelds in nNextOffset festgehalten. 422 nNextOffset = nNextOffset + nNextOfst; 423 pFld->SetNextOffset( nNextOffset ); 424 rInf.SetRest( pFld ); 425 } 426 } 427 428 if( bEOL && rInf.GetLast() && !rInf.GetUnderFlow() ) 429 rInf.GetLast()->FormatEOL( rInf ); 430 return bFull; 431 } 432 433 /************************************************************************* 434 * virtual SwFldPortion::Paint() 435 *************************************************************************/ 436 437 void SwFldPortion::Paint( const SwTxtPaintInfo &rInf ) const 438 { 439 SwFontSave aSave( rInf, pFnt ); 440 441 ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" ); 442 if( Width() && ( !bPlaceHolder || rInf.GetOpt().IsShowPlaceHolderFields() ) ) 443 { 444 // Dies ist eine freizuegige Auslegung der Hintergrundbelegung ... 445 rInf.DrawViewOpt( *this, POR_FLD ); 446 SwExpandPortion::Paint( rInf ); 447 } 448 } 449 450 /************************************************************************* 451 * virtual SwFldPortion::GetExpTxt() 452 *************************************************************************/ 453 454 sal_Bool SwFldPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const 455 { 456 rTxt = aExpand; 457 if( !rTxt.Len() && rInf.OnWin() && 458 !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() && 459 SwViewOption::IsFieldShadings() && 460 !HasFollow() ) 461 rTxt = ' '; 462 return sal_True; 463 } 464 465 /************************************************************************* 466 * virtual SwFldPortion::HandlePortion() 467 *************************************************************************/ 468 469 void SwFldPortion::HandlePortion( SwPortionHandler& rPH ) const 470 { 471 rPH.Special( GetLen(), aExpand, GetWhichPor() ); 472 if( GetWhichPor() == POR_FLD ) 473 { 474 rPH.SetAttrFieldType(m_nAttrFldType); 475 } 476 } 477 478 /************************************************************************* 479 * virtual SwFldPortion::GetTxtSize() 480 *************************************************************************/ 481 482 SwPosSize SwFldPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const 483 { 484 SwFontSave aSave( rInf, pFnt ); 485 SwPosSize aSize( SwExpandPortion::GetTxtSize( rInf ) ); 486 return aSize; 487 } 488 489 /************************************************************************* 490 * class SwHiddenPortion 491 *************************************************************************/ 492 493 SwFldPortion *SwHiddenPortion::Clone(const XubString &rExpand ) const 494 { 495 SwFont *pNewFnt; 496 if( 0 != ( pNewFnt = pFnt ) ) 497 pNewFnt = new SwFont( *pFnt ); 498 return new SwHiddenPortion( rExpand, pNewFnt ); 499 } 500 501 /************************************************************************* 502 * virtual SwHiddenPortion::Paint() 503 *************************************************************************/ 504 505 void SwHiddenPortion::Paint( const SwTxtPaintInfo &rInf ) const 506 { 507 if( Width() ) 508 { 509 SwFontSave aSave( rInf, pFnt ); 510 rInf.DrawViewOpt( *this, POR_HIDDEN ); 511 SwExpandPortion::Paint( rInf ); 512 } 513 } 514 515 /************************************************************************* 516 * virtual SwHiddenPortion::GetExpTxt() 517 *************************************************************************/ 518 519 sal_Bool SwHiddenPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const 520 { 521 // Nicht auf IsHidden() abfragen ! 522 return SwFldPortion::GetExpTxt( rInf, rTxt ); 523 } 524 525 /************************************************************************* 526 * class SwNumberPortion 527 *************************************************************************/ 528 529 // --> OD 2008-01-23 #newlistlevelattrs# 530 SwNumberPortion::SwNumberPortion( const XubString &rExpand, 531 SwFont *pFont, 532 const sal_Bool bLft, 533 const sal_Bool bCntr, 534 const KSHORT nMinDst, 535 const bool bLabelAlignmentPosAndSpaceModeActive ) 536 : SwFldPortion( rExpand, pFont ), 537 nFixWidth(0), 538 nMinDist( nMinDst ), 539 // --> OD 2008-01-23 #newlistlevelattrs# 540 mbLabelAlignmentPosAndSpaceModeActive( bLabelAlignmentPosAndSpaceModeActive ) 541 // <-- 542 { 543 SetWhichPor( POR_NUMBER ); 544 SetLeft( bLft ); 545 SetHide( sal_False ); 546 SetCenter( bCntr ); 547 } 548 549 xub_StrLen SwNumberPortion::GetCrsrOfst( const MSHORT ) const 550 { 551 return 0; 552 } 553 554 SwFldPortion *SwNumberPortion::Clone( const XubString &rExpand ) const 555 { 556 SwFont *pNewFnt; 557 if( 0 != ( pNewFnt = pFnt ) ) 558 pNewFnt = new SwFont( *pFnt ); 559 // --> OD 2008-01-23 #newlistlevelattrs# 560 return new SwNumberPortion( rExpand, pNewFnt, IsLeft(), IsCenter(), 561 nMinDist, mbLabelAlignmentPosAndSpaceModeActive ); 562 // <-- 563 } 564 565 /************************************************************************* 566 * virtual SwNumberPortion::Format() 567 *************************************************************************/ 568 569 // 5010: Wir sind in der Lage, mehrzeilige NumFelder anzulegen! 570 // 3689: Fies ist, wenn man in der Dialogbox soviel Davor-Text 571 // eingibt, bis die Zeile ueberlaeuft. 572 // Man muss die Fly-Ausweichmanoever beachten! 573 574 sal_Bool SwNumberPortion::Format( SwTxtFormatInfo &rInf ) 575 { 576 SetHide( sal_False ); 577 const sal_Bool bFull = SwFldPortion::Format( rInf ); 578 SetLen( 0 ); 579 // a numbering portion can be contained in a rotated portion!!! 580 nFixWidth = rInf.IsMulti() ? Height() : Width(); 581 rInf.SetNumDone( !rInf.GetRest() ); 582 if( rInf.IsNumDone() ) 583 { 584 // SetAscent( rInf.GetAscent() ); 585 ASSERT( Height() && nAscent, "NumberPortions without Height | Ascent" ); 586 587 long nDiff( 0 ); 588 // --> OD 2008-01-23 #newlistlevelattrs# 589 if ( !mbLabelAlignmentPosAndSpaceModeActive ) 590 { 591 if ( !rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) && 592 // --> FME 2004-08-13 #i32902# 593 !IsFtnNumPortion() ) 594 // <-- 595 { 596 nDiff = rInf.Left() 597 + rInf.GetTxtFrm()->GetTxtNode()-> 598 GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst() 599 - rInf.First() 600 + rInf.ForcedLeftMargin(); 601 } 602 else 603 { 604 nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin(); 605 } 606 } 607 // <-- 608 // Ein Vorschlag von Juergen und Volkmar: 609 // Der Textteil hinter der Numerierung sollte immer 610 // mindestens beim linken Rand beginnen. 611 if( nDiff < 0 ) 612 nDiff = 0; 613 else if ( nDiff > rInf.X() ) 614 nDiff -= rInf.X(); 615 else 616 nDiff = 0; 617 618 if( nDiff < nFixWidth + nMinDist ) 619 nDiff = nFixWidth + nMinDist; 620 // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde 621 // fieser Sonderfall: FlyFrm liegt in dem Bereich, 622 // den wir uns gerade unter den Nagel reissen wollen. 623 // Die NumberPortion wird als verborgen markiert. 624 const sal_Bool bFly = rInf.GetFly() || 625 ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() ); 626 if( nDiff > rInf.Width() ) 627 { 628 nDiff = rInf.Width(); 629 if ( bFly ) 630 SetHide( sal_True ); 631 } 632 633 // A numbering portion can be inside a SwRotatedPortion. Then the 634 // Height has to be changed 635 if ( rInf.IsMulti() ) 636 { 637 if ( Height() < nDiff ) 638 Height( KSHORT( nDiff ) ); 639 } 640 else if( Width() < nDiff ) 641 Width( KSHORT(nDiff) ); 642 } 643 return bFull; 644 } 645 646 void SwNumberPortion::FormatEOL( SwTxtFormatInfo& ) 647 { 648 /* Ein FormatEOL deutet daraufhin, dass der folgende Text 649 * nicht mit auf die Zeile passte. Damit die Numerierung mitwandert, 650 * wird diese NumberPortion verborgen. 651 */ 652 653 // This caused trouble with flys anchored as characters. 654 // If one of these is numbered but does not fit to the line, 655 // it calls this function, causing a loop because both the number 656 // portion and the fly portion go to the next line 657 // SetHide( sal_True ); 658 } 659 660 /************************************************************************* 661 * virtual SwNumberPortion::Paint() 662 *************************************************************************/ 663 664 void SwNumberPortion::Paint( const SwTxtPaintInfo &rInf ) const 665 { 666 /* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt 667 * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile. 668 */ 669 670 if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() ) 671 { 672 SwLinePortion *pTmp = GetPortion(); 673 while ( pTmp && !pTmp->InTxtGrp() ) 674 pTmp = pTmp->GetPortion(); 675 if ( !pTmp ) 676 return; 677 } 678 679 // calculate the width of the number portion, including follows 680 const KSHORT nOldWidth = Width(); 681 sal_uInt16 nSumWidth = 0; 682 sal_uInt16 nOffset = 0; 683 684 const SwLinePortion* pTmp = this; 685 while ( pTmp && pTmp->InNumberGrp() ) 686 { 687 nSumWidth = nSumWidth + pTmp->Width(); 688 if ( ((SwNumberPortion*)pTmp)->HasFollow() ) 689 pTmp = pTmp->GetPortion(); 690 else 691 { 692 nOffset = pTmp->Width() - ((SwNumberPortion*)pTmp)->nFixWidth; 693 break; 694 } 695 } 696 697 // The master portion takes care for painting the background of the 698 // follow field portions 699 if ( ! IsFollow() ) 700 { 701 SwLinePortion *pThis = (SwLinePortion*)this; 702 pThis->Width( nSumWidth ); 703 rInf.DrawViewOpt( *this, POR_NUMBER ); 704 pThis->Width( nOldWidth ); 705 } 706 707 if( aExpand.Len() ) 708 { 709 const SwFont *pTmpFnt = rInf.GetFont(); 710 sal_Bool bPaintSpace = ( UNDERLINE_NONE != pTmpFnt->GetUnderline() || 711 UNDERLINE_NONE != pTmpFnt->GetOverline() || 712 STRIKEOUT_NONE != pTmpFnt->GetStrikeout() ) && 713 !pTmpFnt->IsWordLineMode(); 714 if( bPaintSpace && pFnt ) 715 bPaintSpace = ( UNDERLINE_NONE != pFnt->GetUnderline() || 716 UNDERLINE_NONE != pFnt->GetOverline() || 717 STRIKEOUT_NONE != pFnt->GetStrikeout() ) && 718 !pFnt->IsWordLineMode(); 719 720 SwFontSave aSave( rInf, pFnt ); 721 722 if( nFixWidth == Width() && ! HasFollow() ) 723 SwExpandPortion::Paint( rInf ); 724 else 725 { 726 // logisches const: Width wird wieder zurueckgesetzt 727 SwLinePortion *pThis = (SwLinePortion*)this; 728 bPaintSpace = bPaintSpace && nFixWidth < nOldWidth; 729 KSHORT nSpaceOffs = nFixWidth; 730 pThis->Width( nFixWidth ); 731 732 if( ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) || 733 ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() ) ) 734 SwExpandPortion::Paint( rInf ); 735 else 736 { 737 SwTxtPaintInfo aInf( rInf ); 738 if( nOffset < nMinDist ) 739 nOffset = 0; 740 else 741 { 742 if( IsCenter() ) 743 { 744 /* #110778# a / 2 * 2 == a is not a tautology */ 745 KSHORT nTmpOffset = nOffset; 746 nOffset /= 2; 747 if( nOffset < nMinDist ) 748 nOffset = nTmpOffset - nMinDist; 749 } 750 else 751 nOffset = nOffset - nMinDist; 752 } 753 aInf.X( aInf.X() + nOffset ); 754 SwExpandPortion::Paint( aInf ); 755 if( bPaintSpace ) 756 nSpaceOffs = nSpaceOffs + nOffset; 757 } 758 if( bPaintSpace && nOldWidth > nSpaceOffs ) 759 { 760 SwTxtPaintInfo aInf( rInf ); 761 static sal_Char __READONLY_DATA sDoubleSpace[] = " "; 762 aInf.X( aInf.X() + nSpaceOffs ); 763 764 // --> FME 2005-08-12 #i53199# Adjust position of underline: 765 if ( rInf.GetUnderFnt() ) 766 { 767 const Point aNewPos( aInf.GetPos().X(), rInf.GetUnderFnt()->GetPos().Y() ); 768 rInf.GetUnderFnt()->SetPos( aNewPos ); 769 } 770 // <-- 771 772 pThis->Width( nOldWidth - nSpaceOffs + 12 ); 773 { 774 SwTxtSlot aDiffTxt( &aInf, this, true, false, sDoubleSpace ); 775 aInf.DrawText( *this, aInf.GetLen(), sal_True ); 776 } 777 } 778 pThis->Width( nOldWidth ); 779 } 780 } 781 } 782 783 784 /************************************************************************* 785 * class SwBulletPortion 786 *************************************************************************/ 787 788 // --> OD 2008-01-23 #newlistlevelattrs# 789 SwBulletPortion::SwBulletPortion( const xub_Unicode cBullet, 790 const XubString& rBulletFollowedBy, 791 SwFont *pFont, 792 const sal_Bool bLft, 793 const sal_Bool bCntr, 794 const KSHORT nMinDst, 795 const bool bLabelAlignmentPosAndSpaceModeActive ) 796 : SwNumberPortion( XubString( rBulletFollowedBy ).Insert( cBullet, 0 ) , 797 pFont, bLft, bCntr, nMinDst, 798 bLabelAlignmentPosAndSpaceModeActive ) 799 // <-- 800 { 801 SetWhichPor( POR_BULLET ); 802 } 803 804 /************************************************************************* 805 * class SwGrfNumPortion 806 *************************************************************************/ 807 808 #define GRFNUM_SECURE 10 809 810 // --> OD 2008-01-23 #newlistlevelattrs# 811 SwGrfNumPortion::SwGrfNumPortion( 812 SwFrm*, 813 const XubString& rGraphicFollowedBy, 814 const SvxBrushItem* pGrfBrush, 815 const SwFmtVertOrient* pGrfOrient, const Size& rGrfSize, 816 const sal_Bool bLft, const sal_Bool bCntr, const KSHORT nMinDst, 817 const bool bLabelAlignmentPosAndSpaceModeActive ) : 818 SwNumberPortion( rGraphicFollowedBy, NULL, bLft, bCntr, nMinDst, 819 bLabelAlignmentPosAndSpaceModeActive ), 820 // <-- 821 pBrush( new SvxBrushItem(RES_BACKGROUND) ), nId( 0 ) 822 { 823 SetWhichPor( POR_GRFNUM ); 824 SetAnimated( sal_False ); 825 bReplace = sal_False; 826 if( pGrfBrush ) 827 { 828 *pBrush = *pGrfBrush; 829 const Graphic* pGraph = pGrfBrush->GetGraphic(); 830 if( pGraph ) 831 SetAnimated( pGraph->IsAnimated() ); 832 else 833 bReplace = sal_True; 834 } 835 if( pGrfOrient ) 836 { 837 nYPos = pGrfOrient->GetPos(); 838 eOrient = pGrfOrient->GetVertOrient(); 839 } 840 else 841 { 842 nYPos = 0; 843 eOrient = text::VertOrientation::TOP; 844 } 845 Width( static_cast<sal_uInt16>(rGrfSize.Width() + 2 * GRFNUM_SECURE) ); 846 nFixWidth = Width(); 847 nGrfHeight = rGrfSize.Height() + 2 * GRFNUM_SECURE; 848 Height( KSHORT(nGrfHeight) ); 849 bNoPaint = sal_False; 850 } 851 852 SwGrfNumPortion::~SwGrfNumPortion() 853 { 854 if ( IsAnimated() ) 855 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId ); 856 delete pBrush; 857 } 858 859 void SwGrfNumPortion::StopAnimation( OutputDevice* pOut ) 860 { 861 if ( IsAnimated() ) 862 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( pOut, nId ); 863 } 864 865 sal_Bool SwGrfNumPortion::Format( SwTxtFormatInfo &rInf ) 866 { 867 SetHide( sal_False ); 868 // --> OD 2008-01-29 #newlistlevelattrs# 869 // Width( nFixWidth ); 870 KSHORT nFollowedByWidth( 0 ); 871 if ( mbLabelAlignmentPosAndSpaceModeActive ) 872 { 873 SwFldPortion::Format( rInf ); 874 nFollowedByWidth = Width(); 875 SetLen( 0 ); 876 } 877 Width( nFixWidth + nFollowedByWidth ); 878 // <-- 879 const sal_Bool bFull = rInf.Width() < rInf.X() + Width(); 880 const sal_Bool bFly = rInf.GetFly() || 881 ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() ); 882 SetAscent( static_cast<sal_uInt16>(GetRelPos() > 0 ? GetRelPos() : 0) ); 883 if( GetAscent() > Height() ) 884 Height( GetAscent() ); 885 886 if( bFull ) 887 { 888 Width( rInf.Width() - (KSHORT)rInf.X() ); 889 if( bFly ) 890 { 891 SetLen( 0 ); 892 SetNoPaint( sal_True ); 893 rInf.SetNumDone( sal_False ); 894 return sal_True; 895 } 896 } 897 rInf.SetNumDone( sal_True ); 898 // --> OD 2008-01-23 #newlistlevelattrs# 899 // long nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin(); 900 long nDiff = mbLabelAlignmentPosAndSpaceModeActive 901 ? 0 902 : rInf.Left() - rInf.First() + rInf.ForcedLeftMargin(); 903 // <-- 904 // Ein Vorschlag von Juergen und Volkmar: 905 // Der Textteil hinter der Numerierung sollte immer 906 // mindestens beim linken Rand beginnen. 907 if( nDiff < 0 ) 908 nDiff = 0; 909 else if ( nDiff > rInf.X() ) 910 nDiff -= rInf.X(); 911 if( nDiff < nFixWidth + nMinDist ) 912 nDiff = nFixWidth + nMinDist; 913 // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde 914 // fieser Sonderfall: FlyFrm liegt in dem Bereich, 915 // den wir uns gerade unter den Nagel reissen wollen. 916 // Die NumberPortion wird als verborgen markiert. 917 if( nDiff > rInf.Width() ) 918 { 919 nDiff = rInf.Width(); 920 if( bFly ) 921 SetHide( sal_True ); 922 } 923 924 if( Width() < nDiff ) 925 Width( KSHORT(nDiff) ); 926 return bFull; 927 } 928 929 void SwGrfNumPortion::Paint( const SwTxtPaintInfo &rInf ) const 930 { 931 if( DontPaint() ) 932 return; 933 /* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt 934 * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile. 935 */ 936 if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() ) 937 { 938 SwLinePortion *pTmp = GetPortion(); 939 while ( pTmp && !pTmp->InTxtGrp() ) 940 pTmp = pTmp->GetPortion(); 941 if ( !pTmp ) 942 return; 943 } 944 Point aPos( rInf.X() + GRFNUM_SECURE, rInf.Y() - GetRelPos() + GRFNUM_SECURE ); 945 long nTmpWidth = Max( (long)0, (long)(nFixWidth - 2 * GRFNUM_SECURE) ); 946 Size aSize( nTmpWidth, GetGrfHeight() - 2 * GRFNUM_SECURE ); 947 948 // --> OD 2008-02-05 #newlistlevelattrs# 949 const sal_Bool bTmpLeft = mbLabelAlignmentPosAndSpaceModeActive || 950 ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) || 951 ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() ); 952 // <-- 953 954 if( nFixWidth < Width() && !bTmpLeft ) 955 { 956 KSHORT nOffset = Width() - nFixWidth; 957 if( nOffset < nMinDist ) 958 nOffset = 0; 959 else 960 { 961 if( IsCenter() ) 962 { 963 nOffset /= 2; 964 if( nOffset < nMinDist ) 965 nOffset = Width() - nFixWidth - nMinDist; 966 } 967 else 968 nOffset = nOffset - nMinDist; 969 } 970 aPos.X() += nOffset; 971 } 972 973 if( bReplace ) 974 { 975 KSHORT nTmpH = GetPortion() ? GetPortion()->GetAscent() : 120; 976 aSize = Size( nTmpH, nTmpH ); 977 aPos.Y() = rInf.Y() - nTmpH; 978 } 979 SwRect aTmp( aPos, aSize ); 980 981 sal_Bool bDraw = sal_True; 982 983 if ( IsAnimated() ) 984 { 985 bDraw = !rInf.GetOpt().IsGraphic(); 986 if( !nId ) 987 { 988 SetId( long( rInf.GetTxtFrm() ) ); 989 rInf.GetTxtFrm()->SetAnimation(); 990 } 991 if( aTmp.IsOver( rInf.GetPaintRect() ) && !bDraw ) 992 { 993 rInf.NoteAnimation(); 994 const ViewShell* pViewShell = rInf.GetVsh(); 995 996 // virtual device, not pdf export 997 if( OUTDEV_VIRDEV == rInf.GetOut()->GetOutDevType() && 998 pViewShell && pViewShell->GetWin() ) 999 { 1000 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation(0,nId); 1001 rInf.GetTxtFrm()->getRootFrm()->GetCurrShell()->InvalidateWindows( aTmp ); 1002 } 1003 1004 1005 else if ( pViewShell && 1006 !pViewShell->GetAccessibilityOptions()->IsStopAnimatedGraphics() && 1007 !pViewShell->IsPreView() && 1008 // --> FME 2004-06-21 #i9684# Stop animation during printing/pdf export. 1009 pViewShell->GetWin() ) 1010 // <-- 1011 { 1012 ( (Graphic*) pBrush->GetGraphic() )->StartAnimation( 1013 (OutputDevice*)rInf.GetOut(), aPos, aSize, nId ); 1014 } 1015 1016 // pdf export, printing, preview, stop animations... 1017 else 1018 bDraw = sal_True; 1019 } 1020 if( bDraw ) 1021 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId ); 1022 } 1023 1024 SwRect aRepaint( rInf.GetPaintRect() ); 1025 const SwTxtFrm& rFrm = *rInf.GetTxtFrm(); 1026 if( rFrm.IsVertical() ) 1027 { 1028 rFrm.SwitchHorizontalToVertical( aTmp ); 1029 rFrm.SwitchHorizontalToVertical( aRepaint ); 1030 } 1031 1032 if( rFrm.IsRightToLeft() ) 1033 { 1034 rFrm.SwitchLTRtoRTL( aTmp ); 1035 rFrm.SwitchLTRtoRTL( aRepaint ); 1036 } 1037 1038 if( bDraw && aTmp.HasArea() ) 1039 DrawGraphic( pBrush, (OutputDevice*)rInf.GetOut(), 1040 aTmp, aRepaint, bReplace ? GRFNUM_REPLACE : GRFNUM_YES ); 1041 } 1042 1043 void SwGrfNumPortion::SetBase( long nLnAscent, long nLnDescent, 1044 long nFlyAsc, long nFlyDesc ) 1045 { 1046 if ( GetOrient() != text::VertOrientation::NONE ) 1047 { 1048 SetRelPos( 0 ); 1049 if ( GetOrient() == text::VertOrientation::CENTER ) 1050 SetRelPos( GetGrfHeight() / 2 ); 1051 else if ( GetOrient() == text::VertOrientation::TOP ) 1052 SetRelPos( GetGrfHeight() - GRFNUM_SECURE ); 1053 else if ( GetOrient() == text::VertOrientation::BOTTOM ) 1054 ; 1055 else if ( GetOrient() == text::VertOrientation::CHAR_CENTER ) 1056 SetRelPos( ( GetGrfHeight() + nLnAscent - nLnDescent ) / 2 ); 1057 else if ( GetOrient() == text::VertOrientation::CHAR_TOP ) 1058 SetRelPos( nLnAscent ); 1059 else if ( GetOrient() == text::VertOrientation::CHAR_BOTTOM ) 1060 SetRelPos( GetGrfHeight() - nLnDescent ); 1061 else 1062 { 1063 if( GetGrfHeight() >= nFlyAsc + nFlyDesc ) 1064 { 1065 // wenn ich genauso gross bin wie die Zeile, brauche ich mich 1066 // nicht an der Zeile nicht weiter ausrichten, ich lasse 1067 // dann auch den max. Ascent der Zeile unveraendert 1068 1069 SetRelPos( nFlyAsc ); 1070 } 1071 else if ( GetOrient() == text::VertOrientation::LINE_CENTER ) 1072 SetRelPos( ( GetGrfHeight() + nFlyAsc - nFlyDesc ) / 2 ); 1073 else if ( GetOrient() == text::VertOrientation::LINE_TOP ) 1074 SetRelPos( nFlyAsc ); 1075 else if ( GetOrient() == text::VertOrientation::LINE_BOTTOM ) 1076 SetRelPos( GetGrfHeight() - nFlyDesc ); 1077 } 1078 } 1079 } 1080 1081 void SwTxtFrm::StopAnimation( OutputDevice* pOut ) 1082 { 1083 ASSERT( HasAnimation(), "SwTxtFrm::StopAnimation: Which Animation?" ); 1084 if( HasPara() ) 1085 { 1086 SwLineLayout *pLine = GetPara(); 1087 while( pLine ) 1088 { 1089 SwLinePortion *pPor = pLine->GetPortion(); 1090 while( pPor ) 1091 { 1092 if( pPor->IsGrfNumPortion() ) 1093 ((SwGrfNumPortion*)pPor)->StopAnimation( pOut ); 1094 // Die Numerierungsportion sitzt immer vor dem ersten Zeichen, 1095 // deshalb koennen wir abbrechen, sobald wir eine Portion mit 1096 // einer Laenge > 0 erreicht haben. 1097 pPor = pPor->GetLen() ? 0 : pPor->GetPortion(); 1098 } 1099 pLine = pLine->GetLen() ? 0 : pLine->GetNext(); 1100 } 1101 } 1102 } 1103 1104 /************************************************************************* 1105 * SwCombinedPortion::SwCombinedPortion(..) 1106 * initializes the script array and clears the width array 1107 *************************************************************************/ 1108 1109 SwCombinedPortion::SwCombinedPortion( const XubString &rTxt ) 1110 : SwFldPortion( rTxt ) 1111 { 1112 SetLen(1); 1113 SetWhichPor( POR_COMBINED ); 1114 if( aExpand.Len() > 6 ) 1115 aExpand.Erase( 6 ); 1116 // Initialization of the scripttype array, 1117 // the arrays of width and position are filled by the format function 1118 if( pBreakIt->GetBreakIter().is() ) 1119 { 1120 sal_uInt8 nScr = SW_SCRIPTS; 1121 for( sal_uInt16 i = 0; i < rTxt.Len(); ++i ) 1122 { 1123 sal_uInt16 nScript = pBreakIt->GetBreakIter()->getScriptType( rTxt, i ); 1124 switch ( nScript ) { 1125 case i18n::ScriptType::LATIN : nScr = SW_LATIN; break; 1126 case i18n::ScriptType::ASIAN : nScr = SW_CJK; break; 1127 case i18n::ScriptType::COMPLEX : nScr = SW_CTL; break; 1128 } 1129 aScrType[i] = nScr; 1130 } 1131 } 1132 else 1133 { 1134 for( sal_uInt16 i = 0; i < 6; aScrType[i++] = 0 ) 1135 ; // nothing 1136 } 1137 memset( &aWidth, 0, sizeof(aWidth) ); 1138 } 1139 1140 /************************************************************************* 1141 * SwCombinedPortion::Paint(..) 1142 *************************************************************************/ 1143 1144 void SwCombinedPortion::Paint( const SwTxtPaintInfo &rInf ) const 1145 { 1146 ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" ); 1147 if( Width() ) 1148 { 1149 rInf.DrawBackBrush( *this ); 1150 rInf.DrawViewOpt( *this, POR_FLD ); 1151 1152 // do we have to repaint a post it portion? 1153 if( rInf.OnWin() && pPortion && !pPortion->Width() ) 1154 pPortion->PrePaint( rInf, this ); 1155 1156 sal_uInt16 nCount = aExpand.Len(); 1157 if( !nCount ) 1158 return; 1159 ASSERT( nCount < 7, "Too much combined characters" ); 1160 1161 // the first character of the second row 1162 sal_uInt16 nTop = ( nCount + 1 ) / 2; 1163 1164 SwFont aTmpFont( *rInf.GetFont() ); 1165 aTmpFont.SetProportion( nProportion ); // a smaller font 1166 SwFontSave aFontSave( rInf, &aTmpFont ); 1167 1168 sal_uInt16 i = 0; 1169 Point aOldPos = rInf.GetPos(); 1170 Point aOutPos( aOldPos.X(), aOldPos.Y() - nUpPos );// Y of the first row 1171 while( i < nCount ) 1172 { 1173 if( i == nTop ) // change the row 1174 aOutPos.Y() = aOldPos.Y() + nLowPos; // Y of the second row 1175 aOutPos.X() = aOldPos.X() + aPos[i]; // X position 1176 const sal_uInt8 nAct = aScrType[i]; // script type 1177 aTmpFont.SetActual( nAct ); 1178 // if there're more than 4 characters to display, we choose fonts 1179 // with 2/3 of the original font width. 1180 if( aWidth[ nAct ] ) 1181 { 1182 Size aTmpSz = aTmpFont.GetSize( nAct ); 1183 if( aTmpSz.Width() != aWidth[ nAct ] ) 1184 { 1185 aTmpSz.Width() = aWidth[ nAct ]; 1186 aTmpFont.SetSize( aTmpSz, nAct ); 1187 } 1188 } 1189 ((SwTxtPaintInfo&)rInf).SetPos( aOutPos ); 1190 rInf.DrawText( aExpand, *this, i, 1 ); 1191 ++i; 1192 } 1193 // rInf is const, so we have to take back our manipulations 1194 ((SwTxtPaintInfo&)rInf).SetPos( aOldPos ); 1195 } 1196 } 1197 1198 /************************************************************************* 1199 * SwCombinedPortion::Format(..) 1200 *************************************************************************/ 1201 1202 sal_Bool SwCombinedPortion::Format( SwTxtFormatInfo &rInf ) 1203 { 1204 sal_uInt16 nCount = aExpand.Len(); 1205 if( !nCount ) 1206 { 1207 Width( 0 ); 1208 return sal_False; 1209 } 1210 1211 ASSERT( nCount < 7, "Too much combined characters" ); 1212 // If there are leading "weak"-scripttyped characters in this portion, 1213 // they get the actual scripttype. 1214 sal_uInt16 i = 0; 1215 while( i < nCount && SW_SCRIPTS == aScrType[i] ) 1216 aScrType[i++] = rInf.GetFont()->GetActual(); 1217 if( nCount > 4 ) 1218 { 1219 // more than four? Ok, then we need the 2/3 font width 1220 i = 0; 1221 while( i < aExpand.Len() ) 1222 { 1223 ASSERT( aScrType[i] < SW_SCRIPTS, "Combined: Script fault" ); 1224 if( !aWidth[ aScrType[i] ] ) 1225 { 1226 rInf.GetOut()->SetFont( rInf.GetFont()->GetFnt( aScrType[i] ) ); 1227 aWidth[ aScrType[i] ] = 1228 static_cast<sal_uInt16>(2 * rInf.GetOut()->GetFontMetric().GetSize().Width() / 3); 1229 } 1230 ++i; 1231 } 1232 } 1233 1234 sal_uInt16 nTop = ( nCount + 1 ) / 2; // the first character of the second line 1235 ViewShell *pSh = rInf.GetTxtFrm()->getRootFrm()->GetCurrShell(); 1236 SwFont aTmpFont( *rInf.GetFont() ); 1237 SwFontSave aFontSave( rInf, &aTmpFont ); 1238 nProportion = 55; 1239 // In nMainAscent/Descent we store the ascent and descent 1240 // of the original surrounding font 1241 sal_uInt16 nMaxDescent, nMaxAscent, nMaxWidth; 1242 sal_uInt16 nMainDescent = rInf.GetFont()->GetHeight( pSh, *rInf.GetOut() ); 1243 const sal_uInt16 nMainAscent = rInf.GetFont()->GetAscent( pSh, *rInf.GetOut() ); 1244 nMainDescent = nMainDescent - nMainAscent; 1245 // we start with a 50% font, but if we notice that the combined portion 1246 // becomes bigger than the surrounding font, we check 45% and maybe 40%. 1247 do 1248 { 1249 nProportion -= 5; 1250 aTmpFont.SetProportion( nProportion ); 1251 i = 0; 1252 memset( &aPos, 0, sizeof(aPos) ); 1253 nMaxDescent = 0; 1254 nMaxAscent = 0; 1255 nMaxWidth = 0; 1256 nUpPos = nLowPos = 0; 1257 1258 // Now we get the width of all characters. 1259 // The ascent and the width of the first line are stored in the 1260 // ascent member of the portion, the descent in nLowPos. 1261 // The ascent, descent and width of the second line are stored in the 1262 // local nMaxAscent, nMaxDescent and nMaxWidth variables. 1263 while( i < nCount ) 1264 { 1265 sal_uInt8 nScrp = aScrType[i]; 1266 aTmpFont.SetActual( nScrp ); 1267 if( aWidth[ nScrp ] ) 1268 { 1269 Size aFontSize( aTmpFont.GetSize( nScrp ) ); 1270 aFontSize.Width() = aWidth[ nScrp ]; 1271 aTmpFont.SetSize( aFontSize, nScrp ); 1272 } 1273 1274 SwDrawTextInfo aDrawInf( pSh, *rInf.GetOut(), 0, aExpand, i, 1 ); 1275 Size aSize = aTmpFont._GetTxtSize( aDrawInf ); 1276 sal_uInt16 nAsc = aTmpFont.GetAscent( pSh, *rInf.GetOut() ); 1277 aPos[ i ] = (sal_uInt16)aSize.Width(); 1278 if( i == nTop ) // enter the second line 1279 { 1280 nLowPos = nMaxDescent; 1281 Height( nMaxDescent + nMaxAscent ); 1282 Width( nMaxWidth ); 1283 SetAscent( nMaxAscent ); 1284 nMaxAscent = 0; 1285 nMaxDescent = 0; 1286 nMaxWidth = 0; 1287 } 1288 nMaxWidth = nMaxWidth + aPos[ i++ ]; 1289 if( nAsc > nMaxAscent ) 1290 nMaxAscent = nAsc; 1291 if( aSize.Height() - nAsc > nMaxDescent ) 1292 nMaxDescent = static_cast<sal_uInt16>(aSize.Height() - nAsc); 1293 } 1294 // for one or two characters we double the width of the portion 1295 if( nCount < 3 ) 1296 { 1297 nMaxWidth *= 2; 1298 Width( 2*Width() ); 1299 if( nCount < 2 ) 1300 { 1301 Height( nMaxAscent + nMaxDescent ); 1302 nLowPos = nMaxDescent; 1303 } 1304 } 1305 Height( Height() + nMaxDescent + nMaxAscent ); 1306 nUpPos = nMaxAscent; 1307 SetAscent( Height() - nMaxDescent - nLowPos ); 1308 } while( nProportion > 40 && ( GetAscent() > nMainAscent || 1309 Height() - GetAscent() > nMainDescent ) ); 1310 // if the combined portion is smaller than the surrounding text, 1311 // the portion grows. This looks better, if there's a character background. 1312 if( GetAscent() < nMainAscent ) 1313 { 1314 Height( Height() + nMainAscent - GetAscent() ); 1315 SetAscent( nMainAscent ); 1316 } 1317 if( Height() < nMainAscent + nMainDescent ) 1318 Height( nMainAscent + nMainDescent ); 1319 1320 // We calculate the x positions of the characters in both lines.. 1321 sal_uInt16 nTopDiff = 0; 1322 sal_uInt16 nBotDiff = 0; 1323 if( nMaxWidth > Width() ) 1324 { 1325 nTopDiff = ( nMaxWidth - Width() ) / 2; 1326 Width( nMaxWidth ); 1327 } 1328 else 1329 nBotDiff = ( Width() - nMaxWidth ) / 2; 1330 switch( nTop) 1331 { 1332 case 3: aPos[1] = aPos[0] + nTopDiff; // no break 1333 case 2: aPos[nTop-1] = Width() - aPos[nTop-1]; 1334 } 1335 aPos[0] = 0; 1336 switch( nCount ) 1337 { 1338 case 5: aPos[4] = aPos[3] + nBotDiff; // no break 1339 case 3: aPos[nTop] = nBotDiff; break; 1340 case 6: aPos[4] = aPos[3] + nBotDiff; // no break 1341 case 4: aPos[nTop] = 0; // no break 1342 case 2: aPos[nCount-1] = Width() - aPos[nCount-1]; 1343 } 1344 1345 // Does the combined portion fit the line? 1346 const sal_Bool bFull = rInf.Width() < rInf.X() + Width(); 1347 if( bFull ) 1348 { 1349 if( rInf.GetLineStart() == rInf.GetIdx() && (!rInf.GetLast()->InFldGrp() 1350 || !((SwFldPortion*)rInf.GetLast())->IsFollow() ) ) 1351 Width( (sal_uInt16)( rInf.Width() - rInf.X() ) ); 1352 else 1353 { 1354 Truncate(); 1355 Width( 0 ); 1356 SetLen( 0 ); 1357 if( rInf.GetLast() ) 1358 rInf.GetLast()->FormatEOL( rInf ); 1359 } 1360 } 1361 return bFull; 1362 } 1363 1364 /************************************************************************* 1365 * SwCombinedPortion::GetViewWidth(..) 1366 *************************************************************************/ 1367 1368 KSHORT SwCombinedPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const 1369 { 1370 if( !GetLen() ) // for the dummy part at the end of the line, where 1371 return 0; // the combined portion doesn't fit. 1372 return SwFldPortion::GetViewWidth( rInf ); 1373 } 1374