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