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 31 32 #ifndef _OUTDEV_HXX //autogen 33 #include <vcl/outdev.hxx> 34 #endif 35 #ifndef _PRINT_HXX //autogen 36 #include <vcl/print.hxx> 37 #endif 38 #include <vcl/lineinfo.hxx> 39 #ifndef _METRIC_HXX //autogen 40 #include <vcl/metric.hxx> 41 #endif 42 #include <vcl/window.hxx> 43 #include <vcl/svapp.hxx> 44 #ifndef _COM_SUN_STAR_I18N_CHARACTERITERATORMODE_HDL_ 45 #include <com/sun/star/i18n/CharacterIteratorMode.hdl> 46 #endif 47 #ifndef _COM_SUN_STAR_I18N_WORDTYPE_HDL 48 #include <com/sun/star/i18n/WordType.hdl> 49 #endif 50 #include <breakit.hxx> 51 #include <viewsh.hxx> // Bildschirmabgleich 52 #include <viewopt.hxx> // Bildschirmabgleich abschalten, ViewOption 53 #include <fntcache.hxx> 54 #include <IDocumentSettingAccess.hxx> 55 #include <swfont.hxx> // CH_BLANK + CH_BULLET 56 #include <wrong.hxx> 57 #include "dbg_lay.hxx" 58 #include <txtfrm.hxx> // SwTxtFrm 59 #include <pagefrm.hxx> 60 #include <pagedesc.hxx> // SwPageDesc 61 #include <tgrditem.hxx> 62 #include <scriptinfo.hxx> 63 #include <editeng/brshitem.hxx> 64 #include <tools/shl.hxx> 65 #include <swmodule.hxx> 66 #include <accessibilityoptions.hxx> 67 #include <svtools/accessibilityoptions.hxx> 68 #include <doc.hxx> 69 #include <editeng/fhgtitem.hxx> 70 #include <docsh.hxx> 71 #ifndef _POOLFMT_HRC 72 #include <poolfmt.hrc> 73 #endif 74 75 using namespace ::com::sun::star; 76 77 // globale Variablen, werden in FntCache.Hxx bekanntgegeben 78 // Der FontCache wird in TxtInit.Cxx _TXTINIT erzeugt und in _TXTEXIT geloescht 79 SwFntCache *pFntCache = NULL; 80 // Letzter Font, der durch ChgFntCache eingestellt wurde. 81 SwFntObj *pLastFont = NULL; 82 // Die "MagicNumber", die den Fonts zur Identifizierung verpasst wird 83 sal_uInt8* pMagicNo = NULL; 84 85 Color *pWaveCol = 0; 86 87 long SwFntObj::nPixWidth; 88 MapMode* SwFntObj::pPixMap = NULL; 89 OutputDevice* SwFntObj::pPixOut = NULL; 90 91 extern sal_uInt16 UnMapDirection( sal_uInt16 nDir, const sal_Bool bVertFormat ); 92 sal_uInt16 GetDefaultFontHeight( SwDrawTextInfo &rInf ) 93 { 94 SwDocShell* pDocShell = rInf.GetShell()->GetDoc()->GetDocShell(); 95 SfxStyleSheetBasePool* pBasePool = pDocShell->GetStyleSheetPool(); 96 97 String aString(SW_RES(STR_POOLCOLL_STANDARD)); 98 99 SfxStyleSheetBase* pStyle = pBasePool->Find( aString, (SfxStyleFamily)SFX_STYLE_FAMILY_PARA ); 100 SfxItemSet& aTmpSet = pStyle->GetItemSet(); 101 SvxFontHeightItem &aDefaultFontItem = (SvxFontHeightItem&)aTmpSet.Get(RES_CHRATR_CJK_FONTSIZE); 102 return (sal_uInt16)aDefaultFontItem.GetHeight(); 103 } 104 105 106 107 /************************************************************************* 108 |* 109 |* SwFntCache::Flush() 110 |* 111 |* Ersterstellung AMA 16. Dez. 94 112 |* Letzte Aenderung AMA 16. Dez. 94 113 |* 114 |*************************************************************************/ 115 116 void SwFntCache::Flush( ) 117 { 118 if ( pLastFont ) 119 { 120 pLastFont->Unlock(); 121 pLastFont = NULL; 122 } 123 SwCache::Flush( ); 124 } 125 126 /************************************************************************* 127 |* 128 |* SwFntObj::SwFntObj(), ~SwFntObj() 129 |* 130 |* Ersterstellung AMA 7. Nov. 94 131 |* Letzte Aenderung AMA 7. Nov. 94 132 |* 133 |*************************************************************************/ 134 135 SwFntObj::SwFntObj( const SwSubFont &rFont, const void *pOwn, ViewShell *pSh ) : 136 SwCacheObj( (void*)pOwn ), 137 aFont( rFont ), 138 pScrFont( NULL ), 139 pPrtFont( &aFont ), 140 pPrinter( NULL ), 141 nPropWidth( rFont.GetPropWidth() ) 142 { 143 nZoom = pSh ? pSh->GetViewOptions()->GetZoom() : USHRT_MAX; 144 nGuessedLeading = USHRT_MAX; 145 nExtLeading = USHRT_MAX; 146 nPrtAscent = USHRT_MAX; 147 nPrtHeight = USHRT_MAX; 148 bPaintBlank = ( UNDERLINE_NONE != aFont.GetUnderline() 149 || UNDERLINE_NONE != aFont.GetOverline() 150 || STRIKEOUT_NONE != aFont.GetStrikeout() ) 151 && !aFont.IsWordLineMode(); 152 aFont.SetLanguage(rFont.GetLanguage()); 153 } 154 155 SwFntObj::~SwFntObj() 156 { 157 if ( pScrFont != pPrtFont ) 158 delete pScrFont; 159 if ( pPrtFont != &aFont ) 160 delete pPrtFont; 161 } 162 163 void SwFntObj::CreatePrtFont( const OutputDevice& rPrt ) 164 { 165 if ( nPropWidth != 100 && pPrinter != &rPrt ) 166 { 167 if( pScrFont != pPrtFont ) 168 delete pScrFont; 169 if( pPrtFont != &aFont ) 170 delete pPrtFont; 171 172 const Font aOldFnt( rPrt.GetFont() ); 173 ((OutputDevice&)rPrt).SetFont( aFont ); 174 const FontMetric aWinMet( rPrt.GetFontMetric() ); 175 ((OutputDevice&)rPrt).SetFont( aOldFnt ); 176 long nWidth = ( aWinMet.GetSize().Width() * nPropWidth ) / 100; 177 178 if( !nWidth ) 179 ++nWidth; 180 pPrtFont = new Font( aFont ); 181 pPrtFont->SetSize( Size( nWidth, aFont.GetSize().Height() ) ); 182 pScrFont = NULL; 183 } 184 } 185 186 /************************************************************************* 187 * 188 * bool lcl_IsFontAdjustNecessary( rOutDev, rRefDev ) 189 * 190 * returns whether we have to adjust the output font to resemble 191 * the formatting font 192 * 193 * _Not_ necessary if 194 * 195 * 1. RefDef == OutDev (text formatting, online layout...) 196 * 2. PDF export from online layout 197 * 3. Prospect/PagePreview pringing 198 * 199 *************************************************************************/ 200 201 bool lcl_IsFontAdjustNecessary( const OutputDevice& rOutDev, 202 const OutputDevice& rRefDev ) 203 { 204 return &rRefDev != &rOutDev && 205 OUTDEV_WINDOW != rRefDev.GetOutDevType() && 206 ( OUTDEV_PRINTER != rRefDev.GetOutDevType() || 207 OUTDEV_PRINTER != rOutDev.GetOutDevType() ); 208 } 209 210 struct CalcLinePosData 211 { 212 SwDrawTextInfo& rInf; 213 Font& rFont; 214 xub_StrLen nCnt; 215 const sal_Bool bSwitchH2V; 216 const sal_Bool bSwitchL2R; 217 long nHalfSpace; 218 sal_Int32* pKernArray; 219 const sal_Bool bBidiPor; 220 221 CalcLinePosData( SwDrawTextInfo& _rInf, Font& _rFont, 222 xub_StrLen _nCnt, const sal_Bool _bSwitchH2V, const sal_Bool _bSwitchL2R, 223 long _nHalfSpace, sal_Int32* _pKernArray, const sal_Bool _bBidiPor) : 224 rInf( _rInf ), 225 rFont( _rFont ), 226 nCnt( _nCnt ), 227 bSwitchH2V( _bSwitchH2V ), 228 bSwitchL2R( _bSwitchL2R ), 229 nHalfSpace( _nHalfSpace ), 230 pKernArray( _pKernArray ), 231 bBidiPor( _bBidiPor ) 232 { 233 } 234 }; 235 236 /** Function: lcl_calcLinePos 237 238 Computes the start and end position of an underline. This function is called 239 from the DrawText-method (for underlining misspelled words or smarttag terms). 240 */ 241 242 void lcl_calcLinePos( const CalcLinePosData &rData, 243 Point &rStart, Point &rEnd, xub_StrLen nStart, xub_StrLen nWrLen ) 244 { 245 long nBlank = 0; 246 const xub_StrLen nEnd = nStart + nWrLen; 247 const long nTmpSpaceAdd = rData.rInf.GetSpace() / SPACING_PRECISION_FACTOR; 248 249 if ( nEnd < rData.nCnt 250 && CH_BLANK == rData.rInf.GetText().GetChar( rData.rInf.GetIdx() + nEnd ) ) 251 { 252 if( nEnd + 1 == rData.nCnt ) 253 nBlank -= nTmpSpaceAdd; 254 else 255 nBlank -= rData.nHalfSpace; 256 } 257 258 // determine start, end and length of wave line 259 sal_Int32 nKernStart = nStart ? rData.pKernArray[ sal_uInt16( nStart - 1 ) ] : 0; 260 sal_Int32 nKernEnd = rData.pKernArray[ sal_uInt16( nEnd - 1 ) ]; 261 262 sal_uInt16 nDir = rData.bBidiPor ? 1800 : 263 UnMapDirection( rData.rFont.GetOrientation(), rData.bSwitchH2V ); 264 265 switch ( nDir ) 266 { 267 case 0 : 268 rStart.X() += nKernStart; 269 rEnd.X() = nBlank + rData.rInf.GetPos().X() + nKernEnd; 270 rEnd.Y() = rData.rInf.GetPos().Y(); 271 break; 272 case 900 : 273 rStart.Y() -= nKernStart; 274 rEnd.X() = rData.rInf.GetPos().X(); 275 rEnd.Y() = nBlank + rData.rInf.GetPos().Y() - nKernEnd; 276 break; 277 case 1800 : 278 rStart.X() -= nKernStart; 279 rEnd.X() = rData.rInf.GetPos().X() - nKernEnd - nBlank; 280 rEnd.Y() = rData.rInf.GetPos().Y(); 281 break; 282 case 2700 : 283 rStart.Y() += nKernStart; 284 rEnd.X() = rData.rInf.GetPos().X(); 285 rEnd.Y() = nBlank + rData.rInf.GetPos().Y() + nKernEnd; 286 break; 287 } 288 289 if ( rData.bSwitchL2R ) 290 { 291 rData.rInf.GetFrm()->SwitchLTRtoRTL( rStart ); 292 rData.rInf.GetFrm()->SwitchLTRtoRTL( rEnd ); 293 } 294 295 if ( rData.bSwitchH2V ) 296 { 297 rData.rInf.GetFrm()->SwitchHorizontalToVertical( rStart ); 298 rData.rInf.GetFrm()->SwitchHorizontalToVertical( rEnd ); 299 } 300 } 301 302 /************************************************************************* 303 * 304 * sal_uInt16 SwFntObj::GetFontAscent( const OutputDevice& rOut ) 305 * 306 * Ersterstellung AMA 7. Nov. 94 307 * Letzte Aenderung AMA 7. Nov. 94 308 * 309 * Beschreibung: liefern den Ascent des Fonts auf dem 310 * gewuenschten Outputdevice zurueck, ggf. muss der Bildschirmfont erst 311 * erzeugt werden. 312 *************************************************************************/ 313 314 sal_uInt16 SwFntObj::GetFontAscent( const ViewShell *pSh, const OutputDevice& rOut ) 315 { 316 sal_uInt16 nRet = 0; 317 const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut; 318 319 if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) ) 320 { 321 CreateScrFont( *pSh, rOut ); 322 ASSERT( USHRT_MAX != nScrAscent, "nScrAscent is going berzerk" ) 323 nRet = nScrAscent; 324 } 325 else 326 { 327 if ( nPrtAscent == USHRT_MAX ) // DruckerAscent noch nicht bekannt? 328 { 329 CreatePrtFont( rOut ); 330 const Font aOldFnt( rRefDev.GetFont() ); 331 ((OutputDevice&)rRefDev).SetFont( *pPrtFont ); 332 const FontMetric aOutMet( rRefDev.GetFontMetric() ); 333 nPrtAscent = (sal_uInt16) aOutMet.GetAscent(); 334 ( (OutputDevice&)rRefDev).SetFont( aOldFnt ); 335 } 336 337 nRet = nPrtAscent; 338 } 339 340 #if !defined(MACOSX) // #i89844# extleading is below the line for Mac 341 // TODO: move extleading below the line for all platforms too 342 nRet += GetFontLeading( pSh, rRefDev ); 343 #endif 344 345 ASSERT( USHRT_MAX != nRet, "GetFontAscent returned USHRT_MAX" ) 346 return nRet; 347 } 348 349 /************************************************************************* 350 * 351 * sal_uInt16 SwFntObj::GetFontHeight( const OutputDevice* pOut ) 352 * 353 * Ersterstellung AMA 7. Nov. 94 354 * Letzte Aenderung AMA 7. Nov. 94 355 * 356 * Beschreibung: liefern die H?he des Fonts auf dem 357 * gewuenschten Outputdevice zurueck, ggf. muss der Bildschirmfont erst 358 * erzeugt werden. 359 *************************************************************************/ 360 361 sal_uInt16 SwFntObj::GetFontHeight( const ViewShell* pSh, const OutputDevice& rOut ) 362 { 363 sal_uInt16 nRet = 0; 364 const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut; 365 366 if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) ) 367 { 368 CreateScrFont( *pSh, rOut ); 369 ASSERT( USHRT_MAX != nScrHeight, "nScrHeight is going berzerk" ) 370 nRet = nScrHeight + GetFontLeading( pSh, rRefDev ); 371 } 372 else 373 { 374 if ( nPrtHeight == USHRT_MAX ) // PrinterHeight noch nicht bekannt? 375 { 376 CreatePrtFont( rOut ); 377 const Font aOldFnt( rRefDev.GetFont() ); 378 ((OutputDevice&)rRefDev).SetFont( *pPrtFont ); 379 nPrtHeight = static_cast<sal_uInt16>(rRefDev.GetTextHeight()); 380 381 #if OSL_DEBUG_LEVEL > 1 382 // Check if vcl did not change the meading of GetTextHeight 383 const FontMetric aOutMet( rRefDev.GetFontMetric() ); 384 long nTmpPrtHeight = (sal_uInt16)aOutMet.GetAscent() + aOutMet.GetDescent(); 385 (void) nTmpPrtHeight; 386 // #i106098#: do not compare with == here due to rounding error 387 ASSERT( abs(nTmpPrtHeight - nPrtHeight) < 3, 388 "GetTextHeight != Ascent + Descent" ); 389 #endif 390 391 ((OutputDevice&)rRefDev).SetFont( aOldFnt ); 392 } 393 394 nRet = nPrtHeight + GetFontLeading( pSh, rRefDev ); 395 } 396 397 ASSERT( USHRT_MAX != nRet, "GetFontHeight returned USHRT_MAX" ) 398 return nRet; 399 } 400 401 sal_uInt16 SwFntObj::GetFontLeading( const ViewShell *pSh, const OutputDevice& rOut ) 402 { 403 sal_uInt16 nRet = 0; 404 405 if ( pSh ) 406 { 407 if ( USHRT_MAX == nGuessedLeading || USHRT_MAX == nExtLeading ) 408 { 409 const Font aOldFnt( rOut.GetFont() ); 410 ((OutputDevice&)rOut).SetFont( *pPrtFont ); 411 const FontMetric aMet( rOut.GetFontMetric() ); 412 ((OutputDevice&)rOut).SetFont( aOldFnt ); 413 bSymbol = RTL_TEXTENCODING_SYMBOL == aMet.GetCharSet(); 414 GuessLeading( *pSh, aMet ); 415 nExtLeading = static_cast<sal_uInt16>(aMet.GetExtLeading()); 416 } 417 418 const IDocumentSettingAccess& rIDSA = *pSh->getIDocumentSettingAccess(); 419 const bool bBrowse = ( pSh->GetWin() && 420 pSh->GetViewOptions()->getBrowseMode() && 421 !pSh->GetViewOptions()->IsPrtFormat() ); 422 423 if ( !bBrowse && rIDSA.get(IDocumentSettingAccess::ADD_EXT_LEADING) ) 424 nRet = nExtLeading; 425 else 426 nRet = nGuessedLeading; 427 } 428 429 ASSERT( USHRT_MAX != nRet, "GetFontLeading returned USHRT_MAX" ) 430 return nRet; 431 } 432 433 434 /************************************************************************* 435 * 436 * SwFntObj::CreateScrFont( const ViewShell& rSh, const OutputDevice& rOut ) 437 * 438 * Ersterstellung AMA 7. Nov. 94 439 * Letzte Aenderung AMA 7. Nov. 94 440 * 441 * pOut is the output device, not the reference device 442 * 443 *************************************************************************/ 444 445 void SwFntObj::CreateScrFont( const ViewShell& rSh, const OutputDevice& rOut ) 446 { 447 if ( pScrFont ) 448 return; 449 450 // any changes to the output device are reset at the end of the function 451 OutputDevice* pOut = (OutputDevice*)&rOut; 452 453 // Save old font 454 Font aOldOutFont( pOut->GetFont() ); 455 456 nScrHeight = USHRT_MAX; 457 458 // Condition for output font / refdev font adjustment 459 OutputDevice* pPrt = &rSh.GetRefDev(); 460 461 if( !rSh.GetWin() || 462 !rSh.GetViewOptions()->getBrowseMode() || 463 rSh.GetViewOptions()->IsPrtFormat() ) 464 { 465 // After CreatePrtFont pPrtFont is the font which is actually used 466 // by the reference device 467 CreatePrtFont( *pPrt ); 468 pPrinter = pPrt; 469 470 // save old reference device font 471 Font aOldPrtFnt( pPrt->GetFont() ); 472 473 // set the font used at the reference device at the reference device 474 // and the output device 475 pPrt->SetFont( *pPrtFont ); 476 pOut->SetFont( *pPrtFont ); 477 478 // This should be the default for pScrFont. 479 pScrFont = pPrtFont; 480 481 FontMetric aMet = pPrt->GetFontMetric( ); 482 //Don't loose "faked" properties of the logical font that don't truly 483 //exist in the physical font metrics which vcl which fake up for us 484 aMet.SetWeight(pScrFont->GetWeight()); 485 aMet.SetItalic(pScrFont->GetItalic()); 486 487 bSymbol = RTL_TEXTENCODING_SYMBOL == aMet.GetCharSet(); 488 489 if ( USHRT_MAX == nGuessedLeading ) 490 GuessLeading( rSh, aMet ); 491 492 if ( USHRT_MAX == nExtLeading ) 493 nExtLeading = static_cast<sal_uInt16>(aMet.GetExtLeading()); 494 495 // reset the original reference device font 496 pPrt->SetFont( aOldPrtFnt ); 497 } 498 else 499 { 500 bSymbol = RTL_TEXTENCODING_SYMBOL == aFont.GetCharSet(); 501 if ( nGuessedLeading == USHRT_MAX ) 502 nGuessedLeading = 0; 503 504 // no external leading in browse mode 505 if ( nExtLeading == USHRT_MAX ) 506 nExtLeading = 0; 507 508 pScrFont = pPrtFont; 509 } 510 511 // Zoomfaktor ueberpruefen, z.B. wg. PrtOle2 beim Speichern 512 { 513 // Sollte der Zoomfaktor des OutputDevices nicht mit dem der View- 514 // Options uebereinstimmen, so darf dieser Font nicht gecacht 515 // werden, deshalb wird der Zoomfaktor auf einen "ungueltigen" Wert 516 // gesetzt. 517 long nTmp; 518 if( pOut->GetMapMode().GetScaleX().IsValid() && 519 pOut->GetMapMode().GetScaleY().IsValid() && 520 pOut->GetMapMode().GetScaleX() == pOut->GetMapMode().GetScaleY() ) 521 { 522 nTmp = ( 100 * pOut->GetMapMode().GetScaleX().GetNumerator() ) / 523 pOut->GetMapMode().GetScaleX().GetDenominator(); 524 } 525 else 526 nTmp = 0; 527 if( nTmp != nZoom ) 528 nZoom = USHRT_MAX - 1; 529 } 530 531 nScrAscent = (sal_uInt16)pOut->GetFontMetric().GetAscent(); 532 if ( USHRT_MAX == nScrHeight ) 533 nScrHeight = (sal_uInt16)pOut->GetTextHeight(); 534 535 // reset original output device font 536 pOut->SetFont( aOldOutFont ); 537 } 538 539 540 void SwFntObj::GuessLeading( const ViewShell& 541 #if defined(WNT) || defined(PM2) 542 rSh 543 #endif 544 , const FontMetric& rMet ) 545 { 546 // If leading >= 5, this seems to be enough leading. 547 // Nothing has to be done. 548 if ( rMet.GetIntLeading() >= 5 ) 549 { 550 nGuessedLeading = 0; 551 return; 552 } 553 554 #if defined(WNT) || defined(PM2) 555 OutputDevice *pWin = rSh.GetWin() ? 556 rSh.GetWin() : 557 GetpApp()->GetDefaultDevice(); 558 if ( pWin ) 559 { 560 MapMode aTmpMap( MAP_TWIP ); 561 MapMode aOldMap = pWin->GetMapMode( ); 562 pWin->SetMapMode( aTmpMap ); 563 const Font aOldFnt( pWin->GetFont() ); 564 pWin->SetFont( *pPrtFont ); 565 const FontMetric aWinMet( pWin->GetFontMetric() ); 566 const sal_uInt16 nWinHeight = sal_uInt16( aWinMet.GetSize().Height() ); 567 if( pPrtFont->GetName().Search( aWinMet.GetName() ) < USHRT_MAX ) 568 { 569 // Wenn das Leading auf dem Window auch 0 ist, dann 570 // muss es auch so bleiben (vgl. StarMath!). 571 long nTmpLeading = (long)aWinMet.GetIntLeading(); 572 // einen Versuch haben wir noch wg. 31003: 573 if( nTmpLeading <= 0 ) 574 { 575 pWin->SetFont( rMet ); 576 nTmpLeading = (long)pWin->GetFontMetric().GetIntLeading(); 577 if( nTmpLeading < 0 ) 578 nGuessedLeading = 0; 579 else 580 nGuessedLeading = sal_uInt16(nTmpLeading); 581 } 582 else 583 { 584 nGuessedLeading = sal_uInt16(nTmpLeading); 585 // Manta-Hack #50153#: 586 // Wer beim Leading luegt, luegt moeglicherweise auch beim 587 // Ascent/Descent, deshalb wird hier ggf. der Font ein wenig 588 // tiefergelegt, ohne dabei seine Hoehe zu aendern. 589 long nDiff = Min( rMet.GetDescent() - aWinMet.GetDescent(), 590 aWinMet.GetAscent() - rMet.GetAscent() - nTmpLeading ); 591 if( nDiff > 0 ) 592 { 593 ASSERT( nPrtAscent < USHRT_MAX, "GuessLeading: PrtAscent-Fault" ); 594 if ( nPrtAscent < USHRT_MAX ) 595 nPrtAscent = nPrtAscent + (sal_uInt16)(( 2 * nDiff ) / 5); 596 } 597 } 598 } 599 else 600 { 601 // Wenn alle Stricke reissen, nehmen wir 15% der 602 // Hoehe, ein von CL empirisch ermittelter Wert. 603 nGuessedLeading = (nWinHeight * 15) / 100; 604 } 605 pWin->SetFont( aOldFnt ); 606 pWin->SetMapMode( aOldMap ); 607 } 608 else 609 #endif 610 nGuessedLeading = 0; 611 } 612 613 /************************************************************************* 614 * 615 * void SwFntObj::SetDeviceFont( const OutputDevice *pOut ), 616 * 617 * Ersterstellung AMA 7. Nov. 94 618 * Letzte Aenderung AMA 7. Nov. 94 619 * 620 * Beschreibung: stellt den Font am gewuenschten OutputDevice ein, 621 * am Bildschirm muss eventuell erst den Abgleich durchgefuehrt werden. 622 * 623 *************************************************************************/ 624 625 void SwFntObj::SetDevFont( const ViewShell *pSh, OutputDevice& rOut ) 626 { 627 const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut; 628 629 if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) ) 630 { 631 CreateScrFont( *pSh, rOut ); 632 if( !GetScrFont()->IsSameInstance( rOut.GetFont() ) ) 633 rOut.SetFont( *pScrFont ); 634 if( pPrinter && ( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) ) ) 635 pPrinter->SetFont( *pPrtFont ); 636 } 637 else 638 { 639 CreatePrtFont( rOut ); 640 if( !pPrtFont->IsSameInstance( rOut.GetFont() ) ) 641 rOut.SetFont( *pPrtFont ); 642 } 643 644 // Here, we actually do not need the leading values, but by calling 645 // GetFontLeading() we assure that the values are calculated for later use. 646 GetFontLeading( pSh, rRefDev ); 647 } 648 649 #define WRONG_SHOW_MIN 5 650 #define WRONG_SHOW_SMALL 11 651 #define WRONG_SHOW_MEDIUM 15 652 653 /************************************************************************* 654 * 655 * void SwFntObj::DrawText( ... ) 656 * 657 * Ersterstellung AMA 16. Dez. 94 658 * Letzte Aenderung AMA 16. Dez. 94 659 * 660 * Beschreibung: Textausgabe 661 * auf dem Bildschirm => DrawTextArray 662 * auf dem Drucker, !Kerning => DrawText 663 * auf dem Drucker + Kerning => DrawStretchText 664 * 665 *************************************************************************/ 666 667 sal_uInt8 lcl_WhichPunctuation( xub_Unicode cChar ) 668 { 669 if ( ( cChar < 0x3001 || cChar > 0x3002 ) && 670 ( cChar < 0x3008 || cChar > 0x3011 ) && 671 ( cChar < 0x3014 || cChar > 0x301F ) && 672 0xFF62 != cChar && 0xFF63 != cChar ) 673 // no punctuation 674 return SwScriptInfo::NONE; 675 else if ( 0x3001 == cChar || 0x3002 == cChar || 676 0x3009 == cChar || 0x300B == cChar || 677 0x300D == cChar || 0x300F == cChar || 678 0x3011 == cChar || 0x3015 == cChar || 679 0x3017 == cChar || 0x3019 == cChar || 680 0x301B == cChar || 0x301E == cChar || 681 0x301F == cChar || 0xFF63 == cChar ) 682 // right punctuation 683 return SwScriptInfo::SPECIAL_RIGHT; 684 685 return SwScriptInfo::SPECIAL_LEFT; 686 } 687 688 static sal_Bool lcl_IsMonoSpaceFont( const OutputDevice& rOut ) 689 { 690 const String aStr1( xub_Unicode( 0x3008 ) ); 691 const String aStr2( xub_Unicode( 0x307C ) ); 692 const long nWidth1 = rOut.GetTextWidth( aStr1 ); 693 const long nWidth2 = rOut.GetTextWidth( aStr2 ); 694 return nWidth1 == nWidth2; 695 } 696 697 // ER 09.07.95 20:34 698 // mit -Ox Optimierung stuerzt's unter win95 ab 699 // JP 12.07.95: unter WNT auch (i386); Alpha ?? 700 // global optimization off 701 #ifdef _MSC_VER 702 #pragma optimize("g",off) 703 #endif 704 705 /* This helper structure (SwForbidden) contains the already marked parts of the string 706 to avoid double lines (e.g grammar + spell check error) */ 707 708 typedef std::vector< std::pair< xub_StrLen, xub_StrLen > > SwForbidden; 709 710 static void lcl_DrawLineForWrongListData( 711 SwForbidden &rForbidden, 712 const SwDrawTextInfo &rInf, 713 const SwWrongList *pWList, 714 const CalcLinePosData &rCalcLinePosData, 715 const Size &rPrtFontSize ) 716 { 717 if (!pWList) 718 return; 719 720 xub_StrLen nStart = rInf.GetIdx(); 721 xub_StrLen nWrLen = rInf.GetLen(); 722 723 // check if respective data is available in the current text range 724 if (pWList->Check( nStart, nWrLen )) 725 { 726 // get line color to use... 727 Color aLineColor; 728 if (pWList == rInf.GetWrong()) // ... for spell checking 729 aLineColor = SwViewOption::GetSpellColor(); 730 else if (pWList == rInf.GetGrammarCheck()) // ... for grammar checking 731 // currently there is no specific color for grammar check errors available in the configuration 732 aLineColor = Color( COL_LIGHTBLUE ); 733 else if (pWList == rInf.GetSmartTags()) // ... for smart tags 734 aLineColor = SwViewOption::GetSmarttagColor(); 735 736 long nHght = rInf.GetOut().LogicToPixel( rPrtFontSize ).Height(); 737 738 // Draw wavy lines for spell and grammar errors only if font is large enough. 739 // Lines for smart tags will always be drawn. 740 if (pWList == rInf.GetSmartTags() || WRONG_SHOW_MIN < nHght) 741 { 742 SwForbidden::iterator pIter = rForbidden.begin(); 743 if (rInf.GetOut().GetConnectMetaFile()) 744 rInf.GetOut().Push(); 745 746 const Color aCol( rInf.GetOut().GetLineColor() ); 747 const sal_Bool bColSave = aCol != aLineColor; 748 if (bColSave) 749 rInf.GetOut().SetLineColor( aLineColor ); 750 751 // iterate over all ranges stored in the respective SwWrongList 752 do 753 { 754 nStart = nStart - rInf.GetIdx(); 755 756 const xub_StrLen nEnd = nStart + nWrLen; 757 xub_StrLen nNext = nStart; 758 while( nNext < nEnd ) 759 { 760 while( pIter != rForbidden.end() && pIter->second <= nNext ) 761 ++pIter; 762 xub_StrLen nNextStart = nNext; 763 xub_StrLen nNextEnd = nEnd; 764 if( pIter == rForbidden.end() || nNextEnd <= pIter->first ) 765 { 766 // No overlapping mark up found 767 std::pair< xub_StrLen, xub_StrLen > aNew; 768 aNew.first = nNextStart; 769 aNew.second = nNextEnd; 770 rForbidden.insert( pIter, aNew ); 771 pIter = rForbidden.begin(); 772 nNext = nEnd; 773 } 774 else 775 { 776 nNext = pIter->second; 777 if( nNextStart < pIter->first ) 778 { 779 nNextEnd = pIter->first; 780 pIter->first = nNextStart; 781 } 782 else 783 continue; 784 } 785 // determine line pos 786 Point aStart( rInf.GetPos() ); 787 Point aEnd; 788 lcl_calcLinePos( rCalcLinePosData, aStart, aEnd, nNextStart, nNextEnd - nNextStart ); 789 790 // draw line for smart tags? 791 if (pWList == rInf.GetSmartTags()) 792 { 793 aStart.Y() +=30; 794 aEnd.Y() +=30; 795 796 LineInfo aLineInfo( LINE_DASH ); 797 aLineInfo.SetDistance( 40 ); 798 aLineInfo.SetDashLen( 1 ); 799 aLineInfo.SetDashCount(1); 800 801 rInf.GetOut().DrawLine( aStart, aEnd, aLineInfo ); 802 } 803 else // draw wavy lines for spell or grammar errors 804 { 805 // get wavy line type to use 806 sal_uInt16 nWave = 807 WRONG_SHOW_MEDIUM < nHght ? WAVE_NORMAL : 808 ( WRONG_SHOW_SMALL < nHght ? WAVE_SMALL : WAVE_FLAT ); 809 810 rInf.GetOut().DrawWaveLine( aStart, aEnd, nWave ); 811 } 812 } 813 814 nStart = nEnd + rInf.GetIdx(); 815 nWrLen = rInf.GetIdx() + rInf.GetLen() - nStart; 816 } 817 while (nWrLen && pWList->Check( nStart, nWrLen )); 818 819 if (bColSave) 820 rInf.GetOut().SetLineColor( aCol ); 821 822 if (rInf.GetOut().GetConnectMetaFile()) 823 rInf.GetOut().Pop(); 824 } 825 } 826 } 827 828 829 void SwFntObj::DrawText( SwDrawTextInfo &rInf ) 830 { 831 ASSERT( rInf.GetShell(), "SwFntObj::DrawText without shell" ) 832 833 OutputDevice& rRefDev = rInf.GetShell()->GetRefDev(); 834 OutputDevice* pWin = rInf.GetShell()->GetWin(); 835 836 // true if pOut is the printer and the printer has been used for formatting 837 const sal_Bool bPrt = OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() && 838 OUTDEV_PRINTER == rRefDev.GetOutDevType(); 839 const sal_Bool bBrowse = ( pWin && 840 rInf.GetShell()->GetViewOptions()->getBrowseMode() && 841 !rInf.GetShell()->GetViewOptions()->IsPrtFormat() && 842 !rInf.GetBullet() && 843 ( rInf.GetSpace() || !rInf.GetKern() ) && 844 !rInf.GetWrong() && 845 !rInf.GetGrammarCheck() && 846 !rInf.GetSmartTags() && 847 !rInf.GetGreyWave() ); 848 849 // bDirectPrint indicates that we can enter the branch which calls 850 // the DrawText functions instead of calling the DrawTextArray functions 851 const sal_Bool bDirectPrint = bPrt || bBrowse; 852 853 // Condition for output font / refdev font adjustment 854 const sal_Bool bUseScrFont = 855 lcl_IsFontAdjustNecessary( rInf.GetOut(), rRefDev ); 856 857 Font* pTmpFont = bUseScrFont ? pScrFont : pPrtFont; 858 859 // 860 // bDirectPrint and bUseScrFont should have these values: 861 // 862 // Outdev / RefDef | Printer | VirtPrinter | Window 863 // ---------------------------------------------------- 864 // Printer | 1 - 0 | 0 - 1 | - 865 // ---------------------------------------------------- 866 // VirtPrinter/PDF | 0 - 1 | 0 - 1 | - 867 // ---------------------------------------------------- 868 // Window/VirtWindow| 0 - 1 | 0 - 1 | 1 - 0 869 // 870 // Exception: During painting of a Writer OLE object, we do not have 871 // a window. Therefore bUseSrcFont is always 0 in this case. 872 // 873 874 #ifdef DBG_UTIL 875 876 const sal_Bool bNoAdjust = bPrt || 877 ( pWin && 878 rInf.GetShell()->GetViewOptions()->getBrowseMode() && 879 !rInf.GetShell()->GetViewOptions()->IsPrtFormat() ); 880 881 if ( OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() ) 882 { 883 // Printer output 884 if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() ) 885 { 886 ASSERT( bNoAdjust == 1 && bUseScrFont == 0, "Outdev Check failed" ) 887 } 888 else if ( OUTDEV_VIRDEV == rRefDev.GetOutDevType() ) 889 { 890 ASSERT( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" ) 891 } 892 else 893 { 894 ASSERT( sal_False, "Outdev Check failed" ) 895 } 896 } 897 else if ( OUTDEV_VIRDEV == rInf.GetOut().GetOutDevType() && ! pWin ) 898 { 899 // PDF export 900 if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() ) 901 { 902 ASSERT( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" ) 903 } 904 else if ( OUTDEV_VIRDEV == rRefDev.GetOutDevType() ) 905 { 906 ASSERT( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" ) 907 } 908 else 909 { 910 ASSERT( sal_False, "Outdev Check failed" ) 911 } 912 } 913 else if ( OUTDEV_WINDOW == rInf.GetOut().GetOutDevType() || 914 ( OUTDEV_VIRDEV == rInf.GetOut().GetOutDevType() && pWin ) ) 915 { 916 // Window or virtual window 917 if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() ) 918 { 919 ASSERT( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" ) 920 } 921 else if ( OUTDEV_VIRDEV == rRefDev.GetOutDevType() ) 922 { 923 ASSERT( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" ) 924 } 925 else if ( OUTDEV_WINDOW == rRefDev.GetOutDevType() ) 926 { 927 ASSERT( bNoAdjust == 1 && bUseScrFont == 0, "Outdev Check failed" ) 928 } 929 else 930 { 931 ASSERT( sal_False, "Outdev Check failed" ) 932 } 933 } 934 else 935 { 936 ASSERT( sal_False, "Outdev Check failed" ) 937 } 938 939 #endif 940 941 // robust: better use the printer font instead of using no font at all 942 ASSERT( pTmpFont, "No screen or printer font?" ); 943 if ( ! pTmpFont ) 944 pTmpFont = pPrtFont; 945 946 // HACK: UNDERLINE_WAVE darf nicht mehr missbraucht werden, daher 947 // wird die graue Wellenlinie des ExtendedAttributSets zunaechst 948 // in der Fontfarbe erscheinen. 949 950 const sal_Bool bSwitchH2V = rInf.GetFrm() && rInf.GetFrm()->IsVertical(); 951 const sal_Bool bSwitchL2R = rInf.GetFrm() && rInf.GetFrm()->IsRightToLeft() && 952 ! rInf.IsIgnoreFrmRTL(); 953 const sal_uLong nMode = rInf.GetOut().GetLayoutMode(); 954 const sal_Bool bBidiPor = ( bSwitchL2R != 955 ( 0 != ( TEXT_LAYOUT_BIDI_RTL & nMode ) ) ); 956 957 // be sure to have the correct layout mode at the printer 958 if ( pPrinter ) 959 { 960 pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() ); 961 pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() ); 962 } 963 964 Point aPos( rInf.GetPos() ); 965 if( !bPrt ) 966 { 967 if( rInf.GetpOut() != pPixOut || rInf.GetOut().GetMapMode() != *pPixMap ) 968 { 969 *pPixMap = rInf.GetOut().GetMapMode(); 970 pPixOut = rInf.GetpOut(); 971 Size aTmp( 1, 1 ); 972 nPixWidth = rInf.GetOut().PixelToLogic( aTmp ).Width(); 973 } 974 975 aPos.X() += rInf.GetFrm()->IsRightToLeft() ? 0 : nPixWidth; 976 } 977 978 Color aOldColor( pTmpFont->GetColor() ); 979 sal_Bool bChgColor = rInf.ApplyAutoColor( pTmpFont ); 980 if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) ) 981 rInf.GetOut().SetFont( *pTmpFont ); 982 if ( bChgColor ) 983 pTmpFont->SetColor( aOldColor ); 984 985 if ( STRING_LEN == rInf.GetLen() ) 986 rInf.SetLen( rInf.GetText().Len() ); 987 988 989 // 990 // ASIAN LINE AND CHARACTER GRID MODE START: snap to characters 991 // 992 993 if ( rInf.GetFrm() && rInf.SnapToGrid() && rInf.GetFont() && 994 SW_CJK == rInf.GetFont()->GetActual() ) 995 { 996 GETGRID( rInf.GetFrm()->FindPageFrm() ) 997 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars()) 998 { 999 //for textgrid refactor 1000 //const sal_uInt16 nGridWidth = pGrid->GetBaseHeight(); 1001 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 1002 const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc); 1003 sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()]; 1004 1005 if ( pPrinter ) 1006 pPrinter->GetTextArray( rInf.GetText(), pKernArray, 1007 rInf.GetIdx(), rInf.GetLen() ); 1008 else 1009 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 1010 rInf.GetIdx(), rInf.GetLen() ); 1011 1012 long nWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen(); 1013 1014 const sal_uLong i = nWidthPerChar ? 1015 ( nWidthPerChar - 1 ) / nGridWidth + 1: 1016 1; 1017 1018 nWidthPerChar = i * nGridWidth; 1019 1020 // position of first character, we take the printer position 1021 long nCharWidth = pKernArray[ 0 ]; 1022 sal_uLong nHalfWidth = nWidthPerChar / 2; 1023 1024 long nNextFix; 1025 1026 // punctuation characters are not centered 1027 xub_Unicode cChar = rInf.GetText().GetChar( rInf.GetIdx() ); 1028 sal_uInt8 nType = lcl_WhichPunctuation( cChar ); 1029 switch ( nType ) 1030 { 1031 case SwScriptInfo::NONE : 1032 aPos.X() += ( nWidthPerChar - nCharWidth ) / 2; 1033 nNextFix = nCharWidth / 2; 1034 break; 1035 case SwScriptInfo::SPECIAL_RIGHT : 1036 nNextFix = nHalfWidth; 1037 break; 1038 default: 1039 aPos.X() += nWidthPerChar - nCharWidth; 1040 nNextFix = nCharWidth - nHalfWidth; 1041 } 1042 1043 // calculate offsets 1044 for ( xub_StrLen j = 1; j < rInf.GetLen(); ++j ) 1045 { 1046 long nScr = pKernArray[ j ] - pKernArray[ j - 1 ]; 1047 nNextFix += nWidthPerChar; 1048 1049 // punctuation characters are not centered 1050 cChar = rInf.GetText().GetChar( rInf.GetIdx() + j ); 1051 nType = lcl_WhichPunctuation( cChar ); 1052 switch ( nType ) 1053 { 1054 case SwScriptInfo::NONE : 1055 pKernArray[ j - 1 ] = nNextFix - ( nScr / 2 ); 1056 break; 1057 case SwScriptInfo::SPECIAL_RIGHT : 1058 pKernArray[ j - 1 ] = nNextFix - nHalfWidth; 1059 break; 1060 default: 1061 pKernArray[ j - 1 ] = nNextFix + nHalfWidth - nScr; 1062 } 1063 } 1064 1065 // the layout engine requires the total width of the output 1066 pKernArray[ rInf.GetLen() - 1 ] = rInf.GetWidth() - 1067 aPos.X() + rInf.GetPos().X() ; 1068 1069 if ( bSwitchH2V ) 1070 rInf.GetFrm()->SwitchHorizontalToVertical( aPos ); 1071 1072 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1073 pKernArray, rInf.GetIdx(), rInf.GetLen() ); 1074 1075 delete[] pKernArray; 1076 return; 1077 } 1078 } 1079 1080 // For text grid refactor 1081 // ASIAN LINE AND CHARACTER GRID MODE START: not snap to characters 1082 // 1083 if ( rInf.GetFrm() && rInf.SnapToGrid() && rInf.GetFont() && 1084 SW_CJK == rInf.GetFont()->GetActual() ) 1085 { 1086 GETGRID( rInf.GetFrm()->FindPageFrm() ) 1087 1088 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() ) 1089 { 1090 const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf ); 1091 1092 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 1093 long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc); 1094 if( SW_LATIN == rInf.GetFont()->GetActual() ) 1095 nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2; 1096 else 1097 nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight; 1098 1099 sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()]; 1100 1101 if ( pPrinter ) 1102 pPrinter->GetTextArray( rInf.GetText(), pKernArray, 1103 rInf.GetIdx(), rInf.GetLen() ); 1104 else 1105 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 1106 rInf.GetIdx(), rInf.GetLen() ); 1107 if ( bSwitchH2V ) 1108 rInf.GetFrm()->SwitchHorizontalToVertical( aPos ); 1109 if ( rInf.GetSpace() || rInf.GetKanaComp()) 1110 { 1111 long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR; 1112 sal_Bool bSpecialJust = sal_False; 1113 if ( rInf.GetFont() && rInf.GetLen() ) 1114 { 1115 const SwScriptInfo* pSI = rInf.GetScriptInfo(); 1116 const sal_uInt8 nActual = rInf.GetFont()->GetActual(); 1117 ///Kana Compression 1118 if( SW_CJK == nActual && rInf.GetKanaComp() && 1119 pSI && pSI->CountCompChg() && 1120 lcl_IsMonoSpaceFont( *(rInf.GetpOut()) ) ) 1121 { 1122 pSI->Compress( pKernArray,rInf.GetIdx(), rInf.GetLen(), 1123 rInf.GetKanaComp(), (sal_uInt16)aFont.GetSize().Height(),&aPos ); 1124 bSpecialJust = sal_True; 1125 } 1126 ///Asian Justification 1127 if ( ( SW_CJK == nActual || SW_LATIN == nActual ) && nSpaceAdd ) 1128 { 1129 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK ); 1130 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang) 1131 { 1132 long nSpaceSum = nSpaceAdd; 1133 for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI ) 1134 { 1135 pKernArray[ nI ] += nSpaceSum; 1136 nSpaceSum += nSpaceAdd; 1137 } 1138 bSpecialJust = sal_True; 1139 nSpaceAdd = 0; 1140 } 1141 } 1142 long nGridAddSum = nGridWidthAdd; 1143 for(xub_StrLen i = 0; i < rInf.GetLen(); i++,nGridAddSum += nGridWidthAdd ) 1144 { 1145 pKernArray[i] += nGridAddSum; 1146 } 1147 long nKernSum = rInf.GetKern(); 1148 if ( bSpecialJust || rInf.GetKern() ) 1149 { 1150 for( xub_StrLen i = 0; i < rInf.GetLen(); i++, nKernSum += rInf.GetKern() ) 1151 { 1152 if ( CH_BLANK == rInf.GetText().GetChar(rInf.GetIdx()+i) ) 1153 nKernSum += nSpaceAdd; 1154 pKernArray[i] += nKernSum; 1155 } 1156 ///With through/uderstr. Grouped style requires a blank at the end 1157 ///of a text edition special measures: 1158 if( bPaintBlank && rInf.GetLen() && (CH_BLANK == 1159 rInf.GetText().GetChar( rInf.GetIdx() + rInf.GetLen() - 1) ) ) 1160 { 1161 ///If it concerns a singular, underlined space acts, 1162 ///we must spend two: 1163 if( 1 == rInf.GetLen() ) 1164 { 1165 pKernArray[0] = rInf.GetWidth() + nSpaceAdd; 1166 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1167 pKernArray, rInf.GetIdx(), 1 ); 1168 } 1169 else 1170 { 1171 pKernArray[ rInf.GetLen() - 2] += nSpaceAdd; 1172 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1173 pKernArray, rInf.GetIdx(), rInf.GetLen() ); 1174 } 1175 } 1176 else 1177 { 1178 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1179 pKernArray, rInf.GetIdx(), rInf.GetLen() ); 1180 } 1181 } 1182 else 1183 { 1184 Point aTmpPos( aPos ); 1185 xub_StrLen i; 1186 xub_StrLen j = 0; 1187 long nSpaceSum = 0; 1188 for( i = 0; i < rInf.GetLen(); i++ ) 1189 { 1190 if( CH_BLANK == rInf.GetText().GetChar( rInf.GetIdx() + i) ) 1191 { 1192 nSpaceSum += nSpaceAdd; 1193 if( j < i) 1194 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(), 1195 rInf.GetIdx() + j, i - j ); 1196 j = i + 1; 1197 pKernArray[i] = pKernArray[i] + nSpaceSum; 1198 aTmpPos.X() = aPos.X() + pKernArray[ i ] + nKernSum; 1199 } 1200 } 1201 if( j < i ) 1202 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(), 1203 rInf.GetIdx() +j , i - j ); 1204 } 1205 } 1206 } 1207 else 1208 { 1209 //long nKernAdd = rInf.GetKern(); 1210 long nKernAdd = 0; 1211 long nGridAddSum = nGridWidthAdd + nKernAdd; 1212 for(xub_StrLen i = 0; i < rInf.GetLen(); i++,nGridAddSum += nGridWidthAdd + nKernAdd ) 1213 { 1214 pKernArray[i] += nGridAddSum; 1215 } 1216 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1217 pKernArray, rInf.GetIdx(), rInf.GetLen() ); 1218 } 1219 delete[] pKernArray; 1220 return; 1221 } 1222 } 1223 1224 // 1225 // DIRECT PAINTING WITHOUT SCREEN ADJUSTMENT 1226 // 1227 1228 if ( bDirectPrint ) 1229 { 1230 const Fraction aTmp( 1, 1 ); 1231 sal_Bool bStretch = rInf.GetWidth() && ( rInf.GetLen() > 1 ) && bPrt 1232 && ( aTmp != rInf.GetOut().GetMapMode().GetScaleX() ); 1233 1234 if ( bSwitchL2R ) 1235 rInf.GetFrm()->SwitchLTRtoRTL( aPos ); 1236 1237 if ( bSwitchH2V ) 1238 rInf.GetFrm()->SwitchHorizontalToVertical( aPos ); 1239 1240 // In the good old days we used to have a simple DrawText if the 1241 // output device is the printer. Now we need a DrawTextArray if 1242 // 1. KanaCompression is enabled 1243 // 2. Justified alignment 1244 // Simple kerning is handled by DrawStretchText 1245 if( rInf.GetSpace() || rInf.GetKanaComp() ) 1246 { 1247 sal_Int32 *pKernArray = new sal_Int32[ rInf.GetLen() ]; 1248 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 1249 rInf.GetIdx(), rInf.GetLen() ); 1250 1251 if( bStretch ) 1252 { 1253 xub_StrLen nZwi = rInf.GetLen() - 1; 1254 long nDiff = rInf.GetWidth() - pKernArray[ nZwi ] 1255 - rInf.GetLen() * rInf.GetKern(); 1256 long nRest = nDiff % nZwi; 1257 long nAdd; 1258 if( nRest < 0 ) 1259 { 1260 nAdd = -1; 1261 nRest += nZwi; 1262 } 1263 else 1264 { 1265 nAdd = +1; 1266 nRest = nZwi - nRest; 1267 } 1268 nDiff /= nZwi; 1269 long nSum = nDiff; 1270 for( xub_StrLen i = 0; i < nZwi; ) 1271 { 1272 pKernArray[ i ] += nSum; 1273 if( ++i == nRest ) 1274 nDiff += nAdd; 1275 nSum += nDiff; 1276 } 1277 } 1278 1279 // 1280 // Modify Array for special justifications 1281 // 1282 long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR; 1283 sal_Bool bSpecialJust = sal_False; 1284 1285 if ( rInf.GetFont() && rInf.GetLen() ) 1286 { 1287 const SwScriptInfo* pSI = rInf.GetScriptInfo(); 1288 const sal_uInt8 nActual = rInf.GetFont()->GetActual(); 1289 1290 // Kana Compression 1291 if ( SW_CJK == nActual && rInf.GetKanaComp() && 1292 pSI && pSI->CountCompChg() && 1293 lcl_IsMonoSpaceFont( rInf.GetOut() ) ) 1294 { 1295 pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(), 1296 rInf.GetKanaComp(), 1297 (sal_uInt16)aFont.GetSize().Height(), &aPos ); 1298 bSpecialJust = sal_True; 1299 } 1300 1301 // Asian Justification 1302 if ( SW_CJK == nActual && nSpaceAdd ) 1303 { 1304 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK ); 1305 1306 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang ) 1307 { 1308 long nSpaceSum = nSpaceAdd; 1309 for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI ) 1310 { 1311 pKernArray[ nI ] += nSpaceSum; 1312 nSpaceSum += nSpaceAdd; 1313 } 1314 1315 bSpecialJust = sal_True; 1316 nSpaceAdd = 0; 1317 } 1318 } 1319 1320 // Kashida Justification 1321 if ( SW_CTL == nActual && nSpaceAdd ) 1322 { 1323 if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) 1324 { 1325 if ( pSI && pSI->CountKashida() && 1326 pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), 1327 rInf.GetLen(), nSpaceAdd ) != STRING_LEN ) 1328 { 1329 bSpecialJust = sal_True; 1330 nSpaceAdd = 0; 1331 } 1332 } 1333 } 1334 1335 // Thai Justification 1336 if ( SW_CTL == nActual && nSpaceAdd ) 1337 { 1338 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL ); 1339 1340 if ( LANGUAGE_THAI == aLang ) 1341 { 1342 // Use rInf.GetSpace() because it has more precision than 1343 // nSpaceAdd: 1344 SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray, 0, 1345 rInf.GetIdx(), rInf.GetLen(), 1346 rInf.GetNumberOfBlanks(), 1347 rInf.GetSpace() ); 1348 1349 // adding space to blanks is already done 1350 bSpecialJust = sal_True; 1351 nSpaceAdd = 0; 1352 } 1353 } 1354 } 1355 1356 long nKernSum = rInf.GetKern(); 1357 1358 if ( bStretch || bPaintBlank || rInf.GetKern() || bSpecialJust ) 1359 { 1360 for( xub_StrLen i = 0; i < rInf.GetLen(); i++, 1361 nKernSum += rInf.GetKern() ) 1362 { 1363 if ( CH_BLANK == rInf.GetText().GetChar(rInf.GetIdx()+i) ) 1364 nKernSum += nSpaceAdd; 1365 pKernArray[i] += nKernSum; 1366 } 1367 1368 // Bei durch/unterstr. Blocksatz erfordert ein Blank am Ende 1369 // einer Textausgabe besondere Massnahmen: 1370 if( bPaintBlank && rInf.GetLen() && ( CH_BLANK == 1371 rInf.GetText().GetChar( rInf.GetIdx()+rInf.GetLen()-1 ) ) ) 1372 { 1373 // Wenn es sich um ein singulaeres, unterstrichenes Space 1374 // handelt, muessen wir zwei ausgeben: 1375 if( 1 == rInf.GetLen() ) 1376 { 1377 pKernArray[0] = rInf.GetWidth() + nSpaceAdd; 1378 1379 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1380 pKernArray, rInf.GetIdx(), 1 ); 1381 } 1382 else 1383 { 1384 pKernArray[ rInf.GetLen() - 2 ] += nSpaceAdd; 1385 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1386 pKernArray, rInf.GetIdx(), rInf.GetLen() ); 1387 } 1388 } 1389 else 1390 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1391 pKernArray, rInf.GetIdx(), rInf.GetLen() ); 1392 } 1393 else 1394 { 1395 Point aTmpPos( aPos ); 1396 xub_StrLen j = 0; 1397 xub_StrLen i; 1398 for( i = 0; i < rInf.GetLen(); i++ ) 1399 { 1400 if( CH_BLANK == rInf.GetText().GetChar( rInf.GetIdx()+i ) ) 1401 { 1402 nKernSum += nSpaceAdd; 1403 if( j < i ) 1404 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(), 1405 rInf.GetIdx() + j, i - j ); 1406 j = i + 1; 1407 SwTwips nAdd = pKernArray[ i ] + nKernSum; 1408 if ( ( TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL ) == nMode ) 1409 nAdd *= -1; 1410 aTmpPos.X() = aPos.X() + nAdd; 1411 } 1412 } 1413 if( j < i ) 1414 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(), 1415 rInf.GetIdx() + j, i - j ); 1416 } 1417 delete[] pKernArray; 1418 } 1419 else if( bStretch ) 1420 { 1421 long nTmpWidth = rInf.GetWidth(); 1422 if( rInf.GetKern() && rInf.GetLen() && nTmpWidth > rInf.GetKern() ) 1423 nTmpWidth -= rInf.GetKern(); 1424 rInf.GetOut().DrawStretchText( aPos, nTmpWidth, 1425 rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ); 1426 } 1427 else if( rInf.GetKern() ) 1428 { 1429 const long nTmpWidth = GetTextSize( rInf ).Width(); 1430 1431 const Color aSaveColor( pTmpFont->GetColor() ); 1432 const sal_Bool bColorChanged = rInf.ApplyAutoColor( pTmpFont ); 1433 1434 if( bColorChanged ) 1435 { 1436 if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) ) 1437 rInf.GetOut().SetFont( *pTmpFont ); 1438 pTmpFont->SetColor( aSaveColor ); 1439 } 1440 1441 rInf.GetOut().DrawStretchText( aPos, (sal_uInt16)nTmpWidth, 1442 rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ); 1443 } 1444 else 1445 rInf.GetOut().DrawText( aPos, rInf.GetText(), 1446 rInf.GetIdx(), rInf.GetLen() ); 1447 } 1448 1449 // 1450 // PAINTING WITH FORMATTING DEVICE/SCREEN ADJUSTMENT 1451 // 1452 1453 else 1454 { 1455 const String* pStr = &rInf.GetText(); 1456 String aStr( aEmptyStr ); 1457 sal_Bool bBullet = rInf.GetBullet(); 1458 if( bSymbol ) 1459 bBullet = sal_False; 1460 sal_Int32 *pKernArray = new sal_Int32[ rInf.GetLen() ]; 1461 CreateScrFont( *rInf.GetShell(), rInf.GetOut() ); 1462 long nScrPos; 1463 1464 // get screen array 1465 sal_Int32* pScrArray = new sal_Int32[ rInf.GetLen() ]; 1466 rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray, 1467 rInf.GetIdx(), rInf.GetLen() ); 1468 1469 // OLE: no printer available 1470 // ASSERT( pPrinter, "DrawText needs pPrinter" ) 1471 if ( pPrinter ) 1472 { 1473 // pTmpFont has already been set as current font for rInf.GetOut() 1474 if ( pPrinter != rInf.GetpOut() || pTmpFont != pPrtFont ) 1475 { 1476 if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) ) 1477 pPrinter->SetFont( *pPrtFont ); 1478 } 1479 pPrinter->GetTextArray( rInf.GetText(), pKernArray, rInf.GetIdx(), 1480 rInf.GetLen() ); 1481 } 1482 else 1483 { 1484 // sal_Bool bRestore = sal_False; 1485 // MapMode aOld( rInf.GetOut().GetMapMode() ); 1486 // if( rInf.GetZoom().GetNumerator() && 1487 // rInf.GetZoom() != aOld.GetScaleX() ) 1488 // { 1489 // MapMode aNew( aOld ); 1490 // aNew.SetScaleX( rInf.GetZoom() ); 1491 // aNew.SetScaleY( rInf.GetZoom() ); 1492 // rInf.GetOut().SetMapMode( aNew ); 1493 // bRestore = sal_True; 1494 // } 1495 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 1496 rInf.GetIdx(), rInf.GetLen() ); 1497 // if( bRestore ) 1498 // rInf.GetOut().SetMapMode( aOld ); 1499 } 1500 1501 // 1502 // Modify Printer and ScreenArrays for special justifications 1503 // 1504 long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR; 1505 bool bNoHalfSpace = false; 1506 1507 if ( rInf.GetFont() && rInf.GetLen() ) 1508 { 1509 const sal_uInt8 nActual = rInf.GetFont()->GetActual(); 1510 const SwScriptInfo* pSI = rInf.GetScriptInfo(); 1511 1512 // Kana Compression 1513 if ( SW_CJK == nActual && rInf.GetKanaComp() && 1514 pSI && pSI->CountCompChg() && 1515 lcl_IsMonoSpaceFont( rInf.GetOut() ) ) 1516 { 1517 Point aTmpPos( aPos ); 1518 pSI->Compress( pScrArray, rInf.GetIdx(), rInf.GetLen(), 1519 rInf.GetKanaComp(), 1520 (sal_uInt16)aFont.GetSize().Height(), &aTmpPos ); 1521 pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(), 1522 rInf.GetKanaComp(), 1523 (sal_uInt16)aFont.GetSize().Height(), &aPos ); 1524 } 1525 1526 // Asian Justification 1527 if ( SW_CJK == nActual && nSpaceAdd ) 1528 { 1529 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK ); 1530 1531 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang ) 1532 { 1533 long nSpaceSum = nSpaceAdd; 1534 for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI ) 1535 { 1536 pKernArray[ nI ] += nSpaceSum; 1537 pScrArray[ nI ] += nSpaceSum; 1538 nSpaceSum += nSpaceAdd; 1539 } 1540 1541 nSpaceAdd = 0; 1542 } 1543 } 1544 1545 // Kashida Justification 1546 if ( SW_CTL == nActual && nSpaceAdd ) 1547 { 1548 if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) 1549 { 1550 if ( pSI && pSI->CountKashida() && 1551 pSI->KashidaJustify( pKernArray, pScrArray, rInf.GetIdx(), 1552 rInf.GetLen(), nSpaceAdd ) != STRING_LEN ) 1553 nSpaceAdd = 0; 1554 else 1555 bNoHalfSpace = true; 1556 } 1557 } 1558 1559 // Thai Justification 1560 if ( SW_CTL == nActual && nSpaceAdd ) 1561 { 1562 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL ); 1563 1564 if ( LANGUAGE_THAI == aLang ) 1565 { 1566 SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray, 1567 pScrArray, rInf.GetIdx(), 1568 rInf.GetLen(), 1569 rInf.GetNumberOfBlanks(), 1570 rInf.GetSpace() ); 1571 1572 // adding space to blanks is already done 1573 nSpaceAdd = 0; 1574 } 1575 } 1576 } 1577 1578 nScrPos = pScrArray[ 0 ]; 1579 1580 if( bBullet ) 1581 { 1582 // !!! HACK !!! 1583 // The Arabic layout engine requires some context of the string 1584 // which should be painted. 1585 xub_StrLen nCopyStart = rInf.GetIdx(); 1586 if ( nCopyStart ) 1587 --nCopyStart; 1588 1589 xub_StrLen nCopyLen = rInf.GetLen(); 1590 if ( nCopyStart + nCopyLen < rInf.GetText().Len() ) 1591 ++nCopyLen; 1592 1593 aStr = rInf.GetText().Copy( nCopyStart, nCopyLen ); 1594 pStr = &aStr; 1595 1596 for( xub_StrLen i = 0; i < aStr.Len(); ++i ) 1597 if( CH_BLANK == aStr.GetChar( i ) ) 1598 aStr.SetChar( i, CH_BULLET ); 1599 } 1600 1601 xub_StrLen nCnt = rInf.GetText().Len(); 1602 if ( nCnt < rInf.GetIdx() ) 1603 nCnt = 0; 1604 else 1605 nCnt = nCnt - rInf.GetIdx(); 1606 nCnt = Min( nCnt, rInf.GetLen() ); 1607 long nKernSum = rInf.GetKern(); 1608 xub_Unicode cChPrev = rInf.GetText().GetChar( rInf.GetIdx() ); 1609 1610 // Wenn es sich um ein singulaeres, unterstrichenes Space 1611 // im Blocksatz handelt, muessen wir zwei ausgeben: 1612 if ( ( nCnt == 1 ) && rInf.GetSpace() && ( cChPrev == CH_BLANK ) ) 1613 { 1614 pKernArray[0] = rInf.GetWidth() + 1615 rInf.GetKern() + 1616 ( rInf.GetSpace() / SPACING_PRECISION_FACTOR ); 1617 1618 if ( bSwitchL2R ) 1619 rInf.GetFrm()->SwitchLTRtoRTL( aPos ); 1620 1621 if ( bSwitchH2V ) 1622 rInf.GetFrm()->SwitchHorizontalToVertical( aPos ); 1623 1624 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1625 pKernArray, rInf.GetIdx(), 1 ); 1626 if( bBullet ) 1627 rInf.GetOut().DrawTextArray( aPos, *pStr, pKernArray, 1628 rInf.GetIdx() ? 1 : 0, 1 ); 1629 } 1630 else 1631 { 1632 xub_Unicode nCh; 1633 1634 // Bei Pairkerning waechst der Printereinfluss auf die Positionierung 1635 sal_uInt16 nMul = 3; 1636 1637 if ( pPrtFont->GetKerning() ) 1638 nMul = 1; 1639 1640 const sal_uInt16 nDiv = nMul+1; 1641 1642 // In nSpaceSum wird der durch Blocksatz auf die Spaces verteilte 1643 // Zwischenraum aufsummiert. 1644 // Die Spaces selbst werden im Normalfall in der Mitte des 1645 // Zwischenraums positioniert, deshalb die nSpace/2-Mimik. 1646 // Bei wortweiser Unterstreichung muessen sie am Anfang des 1647 // Zwischenraums stehen, damit dieser nicht unterstrichen wird. 1648 // Ein Space am Anfang oder am Ende des Textes muss allerdings 1649 // vor bzw. hinter den kompletten Zwischenraum gesetzt werden, 1650 // sonst wuerde das Durch-/Unterstreichen Luecken aufweisen. 1651 long nSpaceSum = 0; 1652 // in word line mode and for Arabic, we disable the half space trick: 1653 const long nHalfSpace = pPrtFont->IsWordLineMode() || bNoHalfSpace ? 0 : nSpaceAdd / 2; 1654 const long nOtherHalf = nSpaceAdd - nHalfSpace; 1655 if ( nSpaceAdd && ( cChPrev == CH_BLANK ) ) 1656 nSpaceSum = nHalfSpace; 1657 for ( xub_StrLen i=1; i<nCnt; ++i,nKernSum += rInf.GetKern() ) 1658 { 1659 nCh = rInf.GetText().GetChar( rInf.GetIdx() + i ); 1660 1661 ASSERT( pScrArray, "Where is the screen array?" ) 1662 long nScr; 1663 nScr = pScrArray[ i ] - pScrArray[ i - 1 ]; 1664 1665 // Wenn vor uns ein (Ex-)SPACE ist, positionieren wir uns optimal, 1666 // d.h. unseren rechten Rand auf die 100% Druckerposition, 1667 // sind wir sogar selbst ein Ex-SPACE, so positionieren wir uns 1668 // linksbuendig zur Druckerposition. 1669 if ( nCh == CH_BLANK ) 1670 { 1671 #ifdef FONT_TEST_DEBUG 1672 lcl_Pos( 3, nScrPos, nScr, pKernArray[i-1], pKernArray[i] ); 1673 #else 1674 nScrPos = pKernArray[i-1] + nScr; 1675 #endif 1676 if ( cChPrev == CH_BLANK ) 1677 nSpaceSum += nOtherHalf; 1678 if ( i + 1 == nCnt ) 1679 nSpaceSum += nSpaceAdd; 1680 else 1681 nSpaceSum += nHalfSpace; 1682 } 1683 else 1684 { 1685 if ( cChPrev == CH_BLANK ) 1686 { 1687 #ifdef FONT_TEST_DEBUG 1688 lcl_Pos( 6, nScrPos, nScr, pKernArray[i-1], pKernArray[i] ); 1689 #else 1690 nScrPos = pKernArray[i-1] + nScr; 1691 #endif 1692 // kein Pixel geht verloren: 1693 nSpaceSum += nOtherHalf; 1694 } 1695 else if ( cChPrev == '-' ) 1696 #ifdef FONT_TEST_DEBUG 1697 lcl_Pos( 6, nScrPos, nScr, pKernArray[i-1], pKernArray[i] ); 1698 #else 1699 nScrPos = pKernArray[i-1] + nScr; 1700 #endif 1701 else 1702 { 1703 #ifdef FONT_TEST_DEBUG 1704 lcl_Pos( 0, nScrPos, nScr, pKernArray[i-1], pKernArray[i] ); 1705 #else 1706 nScrPos += nScr; 1707 nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv; 1708 #endif 1709 } 1710 } 1711 cChPrev = nCh; 1712 pKernArray[i-1] = nScrPos - nScr + nKernSum + nSpaceSum; 1713 // In word line mode and for Arabic, we disabled the half space trick. If a portion 1714 // ends with a blank, the full nSpaceAdd value has been added to the character in 1715 // front of the blank. This leads to painting artifacts, therefore we remove the 1716 // nSpaceAdd value again: 1717 if ( (bNoHalfSpace || pPrtFont->IsWordLineMode()) && i+1 == nCnt && nCh == CH_BLANK ) 1718 pKernArray[i-1] = pKernArray[i-1] - nSpaceAdd; 1719 } 1720 1721 // the layout engine requires the total width of the output 1722 pKernArray[ rInf.GetLen() - 1 ] += nKernSum + nSpaceSum; 1723 1724 if( rInf.GetGreyWave() ) 1725 { 1726 if( rInf.GetLen() ) 1727 { 1728 long nHght = rInf.GetOut().LogicToPixel( 1729 pPrtFont->GetSize() ).Height(); 1730 if( WRONG_SHOW_MIN < nHght ) 1731 { 1732 if ( rInf.GetOut().GetConnectMetaFile() ) 1733 rInf.GetOut().Push(); 1734 1735 sal_uInt16 nWave = 1736 WRONG_SHOW_MEDIUM < nHght ? WAVE_NORMAL : 1737 ( WRONG_SHOW_SMALL < nHght ? WAVE_SMALL : 1738 WAVE_FLAT ); 1739 Color aCol( rInf.GetOut().GetLineColor() ); 1740 sal_Bool bColSave = aCol != *pWaveCol; 1741 if ( bColSave ) 1742 rInf.GetOut().SetLineColor( *pWaveCol ); 1743 1744 Point aEnd; 1745 long nKernVal = pKernArray[ sal_uInt16( rInf.GetLen() - 1 ) ]; 1746 1747 sal_uInt16 nDir = bBidiPor ? 1748 1800 : 1749 UnMapDirection( 1750 GetFont()->GetOrientation(), 1751 bSwitchH2V ); 1752 1753 switch ( nDir ) 1754 { 1755 case 0 : 1756 aEnd.X() = rInf.GetPos().X() + nKernVal; 1757 aEnd.Y() = rInf.GetPos().Y(); 1758 break; 1759 case 900 : 1760 aEnd.X() = rInf.GetPos().X(); 1761 aEnd.Y() = rInf.GetPos().Y() - nKernVal; 1762 break; 1763 case 1800 : 1764 aEnd.X() = rInf.GetPos().X() - nKernVal; 1765 aEnd.Y() = rInf.GetPos().Y(); 1766 break; 1767 case 2700 : 1768 aEnd.X() = rInf.GetPos().X(); 1769 aEnd.Y() = rInf.GetPos().Y() + nKernVal; 1770 break; 1771 } 1772 1773 Point aCurrPos( rInf.GetPos() ); 1774 1775 if ( bSwitchL2R ) 1776 { 1777 rInf.GetFrm()->SwitchLTRtoRTL( aCurrPos ); 1778 rInf.GetFrm()->SwitchLTRtoRTL( aEnd ); 1779 } 1780 1781 if ( bSwitchH2V ) 1782 { 1783 rInf.GetFrm()->SwitchHorizontalToVertical( aCurrPos ); 1784 rInf.GetFrm()->SwitchHorizontalToVertical( aEnd ); 1785 } 1786 rInf.GetOut().DrawWaveLine( aCurrPos, aEnd, nWave ); 1787 1788 if ( bColSave ) 1789 rInf.GetOut().SetLineColor( aCol ); 1790 1791 if ( rInf.GetOut().GetConnectMetaFile() ) 1792 rInf.GetOut().Pop(); 1793 } 1794 } 1795 } 1796 else if( !bSymbol && rInf.GetLen() ) 1797 { 1798 // anything to do? 1799 if (rInf.GetWrong() || rInf.GetGrammarCheck() || rInf.GetSmartTags()) 1800 { 1801 CalcLinePosData aCalcLinePosData(rInf, *GetFont(), 1802 nCnt, bSwitchH2V, bSwitchL2R, 1803 nHalfSpace, pKernArray, bBidiPor); 1804 1805 SwForbidden aForbidden; 1806 // draw line for smart tag data 1807 lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetSmartTags(), aCalcLinePosData, Size() ); 1808 // draw wave line for spell check errors 1809 // draw them BEFORE the grammar check lines to 'override' the latter in case of conflict. 1810 // reason: some grammar errors can only be found if spelling errors are fixed, 1811 // therefore we don't want the user to miss a spelling error. 1812 lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetWrong(), aCalcLinePosData, pPrtFont->GetSize() ); 1813 // draw wave line for grammar check errors 1814 lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetGrammarCheck(), aCalcLinePosData, pPrtFont->GetSize() ); 1815 } 1816 } 1817 1818 xub_StrLen nOffs = 0; 1819 xub_StrLen nLen = rInf.GetLen(); 1820 #ifdef COMING_SOON 1821 if( aPos.X() < rInf.GetLeft() ) 1822 { 1823 while( nOffs < nLen && 1824 aPos.X() + pKernArray[ nOffs ] < rInf.GetLeft() ) 1825 ++nOffs; 1826 if( nOffs < nLen ) 1827 { 1828 --nLen; 1829 while( nLen > nOffs && 1830 aPos.X() + pKernArray[ nLen ] > rInf.GetRight() ) 1831 --nLen; 1832 ++nLen; 1833 if( nOffs ) 1834 --nOffs; 1835 } 1836 if( nOffs ) 1837 { 1838 long nDiff = pKernArray[ nOffs - 1 ]; 1839 aPos.X() += nDiff; 1840 for( xub_StrLen nX = nOffs; nX < nLen; ++nX ) 1841 pKernArray[ nX ] -= nDiff; 1842 } 1843 } 1844 #endif 1845 if( nOffs < nLen ) 1846 { 1847 // If we paint bullets instead of spaces, we use a copy of 1848 // the paragraph string. For the layout engine, the copy 1849 // of the string has to be an environment of the range which 1850 // is painted 1851 xub_StrLen nTmpIdx = bBullet ? 1852 ( rInf.GetIdx() ? 1 : 0 ) : 1853 rInf.GetIdx(); 1854 1855 if ( bSwitchL2R ) 1856 rInf.GetFrm()->SwitchLTRtoRTL( aPos ); 1857 1858 if ( bSwitchH2V ) 1859 rInf.GetFrm()->SwitchHorizontalToVertical( aPos ); 1860 1861 rInf.GetOut().DrawTextArray( aPos, *pStr, pKernArray + nOffs, 1862 nTmpIdx + nOffs , nLen - nOffs ); 1863 } 1864 } 1865 delete[] pScrArray; 1866 delete[] pKernArray; 1867 } 1868 } 1869 1870 1871 // Optimierung war fuer DrawText() ausgeschaltet 1872 #ifdef _MSC_VER 1873 #pragma optimize("",on) 1874 #endif 1875 1876 1877 /************************************************************************* 1878 * 1879 * Size SwFntObj::GetTextSize( const OutputDevice *pOut, const String &rTxt, 1880 * const sal_uInt16 nIdx, const sal_uInt16 nLen, const short nKern = 0 ); 1881 * 1882 * Ersterstellung AMA 16. Dez. 94 1883 * Letzte Aenderung AMA 16. Dez. 94 1884 * 1885 * Beschreibung: ermittelt die TextSize (des Druckers) 1886 * 1887 *************************************************************************/ 1888 1889 Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf ) 1890 { 1891 Size aTxtSize; 1892 const xub_StrLen nLn = ( STRING_LEN != rInf.GetLen() ) ? rInf.GetLen() : 1893 rInf.GetText().Len(); 1894 1895 // be sure to have the correct layout mode at the printer 1896 if ( pPrinter ) 1897 { 1898 pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() ); 1899 pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() ); 1900 } 1901 1902 if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() && 1903 SW_CJK == rInf.GetFont()->GetActual() ) 1904 { 1905 GETGRID( rInf.GetFrm()->FindPageFrm() ) 1906 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() ) 1907 { 1908 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 1909 const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc); 1910 1911 OutputDevice* pOutDev; 1912 1913 if ( pPrinter ) 1914 { 1915 if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) ) 1916 pPrinter->SetFont(*pPrtFont); 1917 pOutDev = pPrinter; 1918 } 1919 else 1920 pOutDev = rInf.GetpOut(); 1921 1922 aTxtSize.Width() = 1923 pOutDev->GetTextWidth( rInf.GetText(), rInf.GetIdx(), nLn ); 1924 1925 ASSERT( !rInf.GetShell() || 1926 ( USHRT_MAX != GetGuessedLeading() && USHRT_MAX != GetExtLeading() ), 1927 "Leading values should be already calculated" ) 1928 aTxtSize.Height() = pOutDev->GetTextHeight() + 1929 GetFontLeading( rInf.GetShell(), rInf.GetOut() ); 1930 1931 long nWidthPerChar = aTxtSize.Width() / nLn; 1932 1933 const sal_uLong i = nWidthPerChar ? 1934 ( nWidthPerChar - 1 ) / nGridWidth + 1: 1935 1; 1936 1937 aTxtSize.Width() = i * nGridWidth * nLn; 1938 rInf.SetKanaDiff( 0 ); 1939 return aTxtSize; 1940 } 1941 } 1942 1943 //for textgrid refactor 1944 if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() && 1945 SW_CJK == rInf.GetFont()->GetActual() ) 1946 { 1947 GETGRID( rInf.GetFrm()->FindPageFrm() ) 1948 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() ) 1949 { 1950 const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf ); 1951 1952 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 1953 long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc); 1954 if( SW_LATIN == rInf.GetFont()->GetActual() ) 1955 nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2; 1956 else 1957 nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight; 1958 OutputDevice* pOutDev; 1959 if ( pPrinter ) 1960 { 1961 if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) ) 1962 pPrinter->SetFont(*pPrtFont); 1963 pOutDev = pPrinter; 1964 } 1965 else 1966 pOutDev = rInf.GetpOut(); 1967 aTxtSize.Width() = pOutDev->GetTextWidth( rInf.GetText(), rInf.GetIdx(), nLn ); 1968 aTxtSize.Height() = pOutDev->GetTextHeight() + 1969 GetFontLeading( rInf.GetShell(), rInf.GetOut() ); 1970 aTxtSize.Width() += (nLn) * long( nGridWidthAdd ); 1971 //if ( rInf.GetKern() && nLn ) 1972 // aTxtSize.Width() += ( nLn ) * long( rInf.GetKern() ); 1973 1974 rInf.SetKanaDiff( 0 ); 1975 return aTxtSize; 1976 } 1977 } 1978 1979 const sal_Bool bCompress = rInf.GetKanaComp() && nLn && 1980 rInf.GetFont() && 1981 SW_CJK == rInf.GetFont()->GetActual() && 1982 rInf.GetScriptInfo() && 1983 rInf.GetScriptInfo()->CountCompChg() && 1984 lcl_IsMonoSpaceFont( rInf.GetOut() ); 1985 1986 ASSERT( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()-> 1987 CountCompChg()), "Compression without info" ); 1988 1989 // This is the part used e.g., for cursor travelling 1990 // See condition for DrawText or DrawTextArray (bDirectPrint) 1991 if ( pPrinter && pPrinter != rInf.GetpOut() ) 1992 { 1993 if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) ) 1994 pPrinter->SetFont(*pPrtFont); 1995 aTxtSize.Width() = pPrinter->GetTextWidth( rInf.GetText(), 1996 rInf.GetIdx(), nLn ); 1997 aTxtSize.Height() = pPrinter->GetTextHeight(); 1998 sal_Int32 *pKernArray = new sal_Int32[nLn]; 1999 CreateScrFont( *rInf.GetShell(), rInf.GetOut() ); 2000 if( !GetScrFont()->IsSameInstance( rInf.GetOut().GetFont() ) ) 2001 rInf.GetOut().SetFont( *pScrFont ); 2002 long nScrPos; 2003 2004 pPrinter->GetTextArray( rInf.GetText(), pKernArray, rInf.GetIdx(),nLn ); 2005 if( bCompress ) 2006 rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray, 2007 rInf.GetIdx(), nLn, rInf.GetKanaComp(), 2008 (sal_uInt16)aFont.GetSize().Height() ) ); 2009 else 2010 rInf.SetKanaDiff( 0 ); 2011 2012 if ( rInf.GetKanaDiff() ) 2013 nScrPos = pKernArray[ nLn - 1 ]; 2014 else 2015 { 2016 sal_Int32* pScrArray = new sal_Int32[ rInf.GetLen() ]; 2017 rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray, 2018 rInf.GetIdx(), rInf.GetLen() ); 2019 nScrPos = pScrArray[ 0 ]; 2020 xub_StrLen nCnt = rInf.GetText().Len(); 2021 if ( nCnt < rInf.GetIdx() ) 2022 nCnt=0; 2023 else 2024 nCnt = nCnt - rInf.GetIdx(); 2025 nCnt = Min (nCnt, nLn); 2026 xub_Unicode nChPrev = rInf.GetText().GetChar( rInf.GetIdx() ); 2027 2028 xub_Unicode nCh; 2029 2030 // Bei Pairkerning waechst der Printereinfluss auf die Positionierung 2031 sal_uInt16 nMul = 3; 2032 if ( pPrtFont->GetKerning() ) 2033 nMul = 1; 2034 const sal_uInt16 nDiv = nMul+1; 2035 for( xub_StrLen i=1; i<nCnt; i++ ) 2036 { 2037 nCh = rInf.GetText().GetChar( rInf.GetIdx() + i ); 2038 long nScr; 2039 nScr = pScrArray[ i ] - pScrArray[ i - 1 ]; 2040 if ( nCh == CH_BLANK ) 2041 nScrPos = pKernArray[i-1]+nScr; 2042 else 2043 { 2044 if ( nChPrev == CH_BLANK || nChPrev == '-' ) 2045 nScrPos = pKernArray[i-1]+nScr; 2046 else 2047 { 2048 nScrPos += nScr; 2049 nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv; 2050 } 2051 } 2052 nChPrev = nCh; 2053 pKernArray[i-1] = nScrPos - nScr; 2054 } 2055 delete[] pScrArray; 2056 } 2057 2058 delete[] pKernArray; 2059 aTxtSize.Width() = nScrPos; 2060 } 2061 else 2062 { 2063 if( !pPrtFont->IsSameInstance( rInf.GetOut().GetFont() ) ) 2064 rInf.GetOut().SetFont( *pPrtFont ); 2065 if( bCompress ) 2066 { 2067 sal_Int32 *pKernArray = new sal_Int32[nLn]; 2068 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 2069 rInf.GetIdx(), nLn ); 2070 rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray, 2071 rInf.GetIdx(), nLn, rInf.GetKanaComp(), 2072 (sal_uInt16) aFont.GetSize().Height() ) ); 2073 aTxtSize.Width() = pKernArray[ nLn - 1 ]; 2074 delete[] pKernArray; 2075 } 2076 else 2077 { 2078 aTxtSize.Width() = rInf.GetOut().GetTextWidth( rInf.GetText(), 2079 rInf.GetIdx(), nLn ); 2080 rInf.SetKanaDiff( 0 ); 2081 } 2082 2083 aTxtSize.Height() = rInf.GetOut().GetTextHeight(); 2084 } 2085 2086 if ( rInf.GetKern() && nLn ) 2087 aTxtSize.Width() += ( nLn - 1 ) * long( rInf.GetKern() ); 2088 2089 ASSERT( !rInf.GetShell() || 2090 ( USHRT_MAX != GetGuessedLeading() && USHRT_MAX != GetExtLeading() ), 2091 "Leading values should be already calculated" ) 2092 aTxtSize.Height() += GetFontLeading( rInf.GetShell(), rInf.GetOut() ); 2093 return aTxtSize; 2094 } 2095 2096 2097 xub_StrLen SwFntObj::GetCrsrOfst( SwDrawTextInfo &rInf ) 2098 { 2099 long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR; 2100 const long nSperren = -rInf.GetSperren() / SPACING_PRECISION_FACTOR; 2101 long nKern = rInf.GetKern(); 2102 2103 if( 0 != nSperren ) 2104 nKern -= nSperren; 2105 2106 sal_Int32 *pKernArray = new sal_Int32[ rInf.GetLen() ]; 2107 2108 // be sure to have the correct layout mode at the printer 2109 if ( pPrinter ) 2110 { 2111 pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() ); 2112 pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() ); 2113 pPrinter->GetTextArray( rInf.GetText(), pKernArray, 2114 rInf.GetIdx(), rInf.GetLen() ); 2115 } 2116 else 2117 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 2118 rInf.GetIdx(), rInf.GetLen() ); 2119 2120 const SwScriptInfo* pSI = rInf.GetScriptInfo(); 2121 if ( rInf.GetFont() && rInf.GetLen() ) 2122 { 2123 const sal_uInt8 nActual = rInf.GetFont()->GetActual(); 2124 2125 // Kana Compression 2126 if ( SW_CJK == nActual && rInf.GetKanaComp() && 2127 pSI && pSI->CountCompChg() && 2128 lcl_IsMonoSpaceFont( rInf.GetOut() ) ) 2129 { 2130 pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(), 2131 rInf.GetKanaComp(), 2132 (sal_uInt16) aFont.GetSize().Height() ); 2133 } 2134 2135 // Asian Justification 2136 if ( SW_CJK == rInf.GetFont()->GetActual() ) 2137 { 2138 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK ); 2139 2140 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang ) 2141 { 2142 long nSpaceSum = nSpaceAdd; 2143 for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI ) 2144 { 2145 pKernArray[ nI ] += nSpaceSum; 2146 nSpaceSum += nSpaceAdd; 2147 } 2148 2149 nSpaceAdd = 0; 2150 } 2151 2152 } 2153 2154 // Kashida Justification 2155 if ( SW_CTL == nActual && rInf.GetSpace() ) 2156 { 2157 if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) 2158 { 2159 if ( pSI && pSI->CountKashida() && 2160 pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), rInf.GetLen(), 2161 nSpaceAdd ) != STRING_LEN ) 2162 nSpaceAdd = 0; 2163 } 2164 } 2165 2166 // Thai Justification 2167 if ( SW_CTL == nActual && nSpaceAdd ) 2168 { 2169 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL ); 2170 2171 if ( LANGUAGE_THAI == aLang ) 2172 { 2173 SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray, 0, 2174 rInf.GetIdx(), rInf.GetLen(), 2175 rInf.GetNumberOfBlanks(), 2176 rInf.GetSpace() ); 2177 2178 // adding space to blanks is already done 2179 nSpaceAdd = 0; 2180 } 2181 } 2182 } 2183 2184 long nLeft = 0; 2185 long nRight = 0; 2186 xub_StrLen nCnt = 0; 2187 long nSpaceSum = 0; 2188 long nKernSum = 0; 2189 2190 if ( rInf.GetFrm() && rInf.GetLen() && rInf.SnapToGrid() && 2191 rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() ) 2192 { 2193 GETGRID( rInf.GetFrm()->FindPageFrm() ) 2194 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() ) 2195 { 2196 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 2197 const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc); 2198 2199 long nWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen(); 2200 2201 sal_uLong i = nWidthPerChar ? 2202 ( nWidthPerChar - 1 ) / nGridWidth + 1: 2203 1; 2204 2205 nWidthPerChar = i * nGridWidth; 2206 2207 nCnt = (sal_uInt16)(rInf.GetOfst() / nWidthPerChar); 2208 if ( 2 * ( rInf.GetOfst() - nCnt * nWidthPerChar ) > nWidthPerChar ) 2209 ++nCnt; 2210 2211 delete[] pKernArray; 2212 return nCnt; 2213 } 2214 } 2215 2216 //for textgrid refactor 2217 if ( rInf.GetFrm() && rInf.GetLen() && rInf.SnapToGrid() && 2218 rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() ) 2219 { 2220 GETGRID( rInf.GetFrm()->FindPageFrm() ) 2221 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() ) 2222 { 2223 2224 const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf ); 2225 2226 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 2227 long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc); 2228 if( SW_LATIN == rInf.GetFont()->GetActual() ) 2229 nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2; 2230 else 2231 nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight; 2232 2233 for(xub_StrLen j = 0; j < rInf.GetLen(); j++) 2234 { 2235 long nScr = pKernArray[ j ] + ( nSpaceAdd + nGridWidthAdd ) * ( j + 1 ); 2236 if( nScr >= rInf.GetOfst()) 2237 { 2238 nCnt = j; 2239 break; 2240 } 2241 } 2242 delete[] pKernArray; 2243 return nCnt; 2244 } 2245 } 2246 2247 sal_uInt16 nItrMode = i18n::CharacterIteratorMode::SKIPCELL; 2248 sal_Int32 nDone = 0; 2249 LanguageType aLang = LANGUAGE_NONE; 2250 bool bSkipCharacterCells = false; 2251 xub_StrLen nIdx = rInf.GetIdx(); 2252 xub_StrLen nLastIdx = nIdx; 2253 const xub_StrLen nEnd = rInf.GetIdx() + rInf.GetLen(); 2254 2255 // --> OD 2009-12-29 #i105901# 2256 // skip character cells for all script types 2257 if ( pBreakIt->GetBreakIter().is() ) 2258 // <-- 2259 { 2260 aLang = rInf.GetFont()->GetLanguage(); 2261 bSkipCharacterCells = true; 2262 } 2263 2264 while ( ( nRight < long( rInf.GetOfst() ) ) && ( nIdx < nEnd ) ) 2265 { 2266 if ( nSpaceAdd && CH_BLANK == rInf.GetText().GetChar( nIdx ) ) 2267 nSpaceSum += nSpaceAdd; 2268 2269 // go to next character (cell). 2270 nLastIdx = nIdx; 2271 2272 if ( bSkipCharacterCells ) 2273 { 2274 nIdx = (xub_StrLen)pBreakIt->GetBreakIter()->nextCharacters( rInf.GetText(), 2275 nIdx, pBreakIt->GetLocale( aLang ), nItrMode, 1, nDone ); 2276 if ( nIdx <= nLastIdx ) 2277 break; 2278 } 2279 else 2280 ++nIdx; 2281 2282 nLeft = nRight; 2283 nRight = pKernArray[ nIdx - rInf.GetIdx() - 1 ] + nKernSum + nSpaceSum; 2284 2285 nKernSum += nKern; 2286 } 2287 2288 // step back if position is before the middle of the character 2289 // or if we do not want to go to the next character 2290 if ( nIdx > rInf.GetIdx() && 2291 ( rInf.IsPosMatchesBounds() || 2292 ( ( nRight > long( rInf.GetOfst() ) ) && 2293 ( nRight - rInf.GetOfst() > rInf.GetOfst() - nLeft ) ) ) ) 2294 nCnt = nLastIdx - rInf.GetIdx(); // first half 2295 else 2296 nCnt = nIdx - rInf.GetIdx(); // second half 2297 2298 if ( pSI ) 2299 rInf.SetCursorBidiLevel( pSI->DirType( nLastIdx ) ); 2300 2301 delete[] pKernArray; 2302 return nCnt; 2303 } 2304 2305 2306 /************************************************************************* 2307 |* 2308 |* SwFntAccess::SwFntAccess() 2309 |* 2310 |* Ersterstellung AMA 9. Nov. 94 2311 |* Letzte Aenderung AMA 9. Nov. 94 2312 |* 2313 |*************************************************************************/ 2314 2315 SwFntAccess::SwFntAccess( const void* &rMagic, 2316 sal_uInt16 &rIndex, const void *pOwn, ViewShell *pSh, 2317 sal_Bool bCheck ) : 2318 SwCacheAccess( *pFntCache, rMagic, rIndex ), 2319 pShell( pSh ) 2320 { 2321 // Der benutzte CTor von SwCacheAccess sucht anhand rMagic+rIndex im Cache 2322 if ( IsAvail() ) 2323 { 2324 // Der schnellste Fall: ein bekannter Font ( rMagic ), 2325 // bei dem Drucker und Zoom nicht ueberprueft werden brauchen. 2326 if ( !bCheck ) 2327 return; 2328 2329 // Hier ist zwar der Font bekannt, muss aber noch ueberprueft werden. 2330 2331 } 2332 else 2333 // Hier ist der Font nicht bekannt, muss also gesucht werden. 2334 bCheck = sal_False; 2335 2336 2337 { 2338 OutputDevice* pOut = 0; 2339 sal_uInt16 nZoom = USHRT_MAX; 2340 2341 // Get the reference device 2342 if ( pSh ) 2343 { 2344 pOut = &pSh->GetRefDev(); 2345 nZoom = pSh->GetViewOptions()->GetZoom(); 2346 } 2347 2348 SwFntObj *pFntObj; 2349 if ( bCheck ) 2350 { 2351 pFntObj = Get(); 2352 if ( ( pFntObj->GetZoom( ) == nZoom ) && 2353 ( pFntObj->pPrinter == pOut ) && 2354 pFntObj->GetPropWidth() == 2355 ((SwSubFont*)pOwn)->GetPropWidth() ) 2356 return; // Die Ueberpruefung ergab: Drucker+Zoom okay. 2357 pFntObj->Unlock( ); // Vergiss dies Objekt, es wurde leider 2358 pObj = NULL; // eine Drucker/Zoomaenderung festgestellt. 2359 } 2360 2361 // Search by font comparison, quite expensive! 2362 // Look for same font and same printer 2363 pFntObj = pFntCache->First(); 2364 while ( pFntObj && !( pFntObj->aFont == *(Font *)pOwn && 2365 pFntObj->GetZoom() == nZoom && 2366 pFntObj->GetPropWidth() == 2367 ((SwSubFont*)pOwn)->GetPropWidth() && 2368 ( !pFntObj->pPrinter || pFntObj->pPrinter == pOut ) ) ) 2369 pFntObj = pFntCache->Next( pFntObj ); 2370 2371 if( pFntObj && pFntObj->pPrinter != pOut ) 2372 { 2373 // Wir haben zwar einen ohne Drucker gefunden, mal sehen, ob es 2374 // auch noch einen mit identischem Drucker gibt. 2375 SwFntObj *pTmpObj = pFntObj; 2376 while( pTmpObj && !( pTmpObj->aFont == *(Font *)pOwn && 2377 pTmpObj->GetZoom()==nZoom && pTmpObj->pPrinter==pOut && 2378 pTmpObj->GetPropWidth() == 2379 ((SwSubFont*)pOwn)->GetPropWidth() ) ) 2380 pTmpObj = pFntCache->Next( pTmpObj ); 2381 if( pTmpObj ) 2382 pFntObj = pTmpObj; 2383 } 2384 2385 if ( !pFntObj ) // Font has not been found, create one 2386 { 2387 // Das Objekt muss neu angelegt werden, deshalb muss der Owner ein 2388 // SwFont sein, spaeter wird als Owner die "MagicNumber" gehalten. 2389 SwCacheAccess::pOwner = pOwn; 2390 pFntObj = Get(); // hier wird via NewObj() angelegt und gelockt. 2391 ASSERT(pFntObj, "No Font, no Fun."); 2392 } 2393 else // Font has been found, so we lock it. 2394 { 2395 pFntObj->Lock(); 2396 if( pFntObj->pPrinter != pOut ) // Falls bis dato kein Drucker bekannt 2397 { 2398 ASSERT( !pFntObj->pPrinter, "SwFntAccess: Printer Changed" ); 2399 pFntObj->CreatePrtFont( *pOut ); 2400 pFntObj->pPrinter = pOut; 2401 pFntObj->pScrFont = NULL; 2402 pFntObj->nGuessedLeading = USHRT_MAX; 2403 pFntObj->nExtLeading = USHRT_MAX; 2404 pFntObj->nPrtAscent = USHRT_MAX; 2405 pFntObj->nPrtHeight = USHRT_MAX; 2406 } 2407 pObj = pFntObj; 2408 } 2409 2410 // egal, ob neu oder gefunden, ab jetzt ist der Owner vom Objekt eine 2411 // MagicNumber und wird auch dem aufrufenden SwFont bekanntgegeben, 2412 // ebenso der Index fuer spaetere direkte Zugriffe 2413 rMagic = pFntObj->GetOwner(); 2414 SwCacheAccess::pOwner = rMagic; 2415 rIndex = pFntObj->GetCachePos(); 2416 } 2417 } 2418 2419 SwCacheObj *SwFntAccess::NewObj( ) 2420 { 2421 // Ein neuer Font, eine neue "MagicNumber". 2422 return new SwFntObj( *(SwSubFont *)pOwner, ++pMagicNo, pShell ); 2423 } 2424 2425 extern xub_StrLen lcl_CalcCaseMap( const SwFont& rFnt, 2426 const XubString& rOrigString, 2427 xub_StrLen nOfst, 2428 xub_StrLen nLen, 2429 xub_StrLen nIdx ); 2430 2431 xub_StrLen SwFont::GetTxtBreak( SwDrawTextInfo& rInf, long nTextWidth ) 2432 { 2433 ChgFnt( rInf.GetShell(), rInf.GetOut() ); 2434 2435 const sal_Bool bCompress = rInf.GetKanaComp() && rInf.GetLen() && 2436 SW_CJK == GetActual() && 2437 rInf.GetScriptInfo() && 2438 rInf.GetScriptInfo()->CountCompChg() && 2439 lcl_IsMonoSpaceFont( rInf.GetOut() ); 2440 2441 ASSERT( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()-> 2442 CountCompChg()), "Compression without info" ); 2443 2444 sal_uInt16 nTxtBreak = 0; 2445 long nKern = 0; 2446 2447 sal_uInt16 nLn = ( rInf.GetLen() == STRING_LEN ? rInf.GetText().Len() 2448 : rInf.GetLen() ); 2449 2450 if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && 2451 rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() ) 2452 { 2453 GETGRID( rInf.GetFrm()->FindPageFrm() ) 2454 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() ) 2455 { 2456 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 2457 const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc); 2458 2459 sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()]; 2460 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 2461 rInf.GetIdx(), rInf.GetLen() ); 2462 2463 long nWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen(); 2464 2465 const sal_uLong i = nWidthPerChar ? 2466 ( nWidthPerChar - 1 ) / nGridWidth + 1: 2467 1; 2468 2469 nWidthPerChar = i * nGridWidth; 2470 long nCurrPos = nWidthPerChar; 2471 2472 while( nTxtBreak < rInf.GetLen() && nTextWidth >= nCurrPos ) 2473 { 2474 nCurrPos += nWidthPerChar; 2475 ++nTxtBreak; 2476 } 2477 2478 delete[] pKernArray; 2479 return nTxtBreak + rInf.GetIdx(); 2480 } 2481 } 2482 2483 //for text grid enhancement 2484 if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() && 2485 SW_CJK == rInf.GetFont()->GetActual() ) 2486 { 2487 GETGRID( rInf.GetFrm()->FindPageFrm() ) 2488 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() ) 2489 { 2490 const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf ); 2491 2492 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 2493 long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc); 2494 if( SW_LATIN == rInf.GetFont()->GetActual() ) 2495 nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2 ; 2496 else 2497 nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight; 2498 2499 sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()]; 2500 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 2501 rInf.GetIdx(), rInf.GetLen() ); 2502 long nCurrPos = pKernArray[nTxtBreak] + nGridWidthAdd; 2503 while( nTxtBreak < rInf.GetLen() && nTextWidth >= nCurrPos) 2504 { 2505 nTxtBreak++; 2506 nCurrPos = pKernArray[nTxtBreak] + nGridWidthAdd * ( nTxtBreak + 1 ); 2507 } 2508 delete[] pKernArray; 2509 return nTxtBreak + rInf.GetIdx(); 2510 } 2511 } 2512 2513 if( aSub[nActual].IsCapital() && nLn ) 2514 nTxtBreak = GetCapitalBreak( rInf.GetShell(), rInf.GetpOut(), 2515 rInf.GetScriptInfo(), rInf.GetText(), nTextWidth,0, rInf.GetIdx(),nLn ); 2516 else 2517 { 2518 nKern = CheckKerning(); 2519 2520 const XubString* pTmpText; 2521 XubString aTmpText; 2522 xub_StrLen nTmpIdx; 2523 xub_StrLen nTmpLen; 2524 bool bTextReplaced = false; 2525 2526 if ( !aSub[nActual].IsCaseMap() ) 2527 { 2528 pTmpText = &rInf.GetText(); 2529 nTmpIdx = rInf.GetIdx(); 2530 nTmpLen = nLn; 2531 } 2532 else 2533 { 2534 const XubString aSnippet( rInf.GetText(), rInf.GetIdx(), nLn ); 2535 aTmpText = aSub[nActual].CalcCaseMap( aSnippet ); 2536 const bool bTitle = SVX_CASEMAP_TITEL == aSub[nActual].GetCaseMap() && 2537 pBreakIt->GetBreakIter().is(); 2538 2539 // Uaaaaahhhh!!! In title case mode, we would get wrong results 2540 if ( bTitle && nLn ) 2541 { 2542 // check if rInf.GetIdx() is begin of word 2543 if ( !pBreakIt->GetBreakIter()->isBeginWord( 2544 rInf.GetText(), rInf.GetIdx(), 2545 pBreakIt->GetLocale( aSub[nActual].GetLanguage() ), 2546 i18n::WordType::ANYWORD_IGNOREWHITESPACES ) ) 2547 { 2548 // In this case, the beginning of aTmpText is wrong. 2549 XubString aSnippetTmp( aSnippet, 0, 1 ); 2550 aSnippetTmp = aSub[nActual].CalcCaseMap( aSnippetTmp ); 2551 aTmpText.Erase( 0, aSnippetTmp.Len() ); 2552 aTmpText.Insert( aSnippet.GetChar( 0 ), 0 ); 2553 } 2554 } 2555 2556 pTmpText = &aTmpText; 2557 nTmpIdx = 0; 2558 nTmpLen = aTmpText.Len(); 2559 bTextReplaced = true; 2560 } 2561 2562 if( rInf.GetHyphPos() ) 2563 nTxtBreak = rInf.GetOut().GetTextBreak( *pTmpText, nTextWidth, 2564 '-', *rInf.GetHyphPos(), 2565 nTmpIdx, nTmpLen, nKern ); 2566 else 2567 nTxtBreak = rInf.GetOut().GetTextBreak( *pTmpText, nTextWidth, 2568 nTmpIdx, nTmpLen, nKern ); 2569 2570 if ( bTextReplaced && STRING_LEN != nTxtBreak ) 2571 { 2572 if ( nTmpLen != nLn ) 2573 nTxtBreak = lcl_CalcCaseMap( *this, rInf.GetText(), 2574 rInf.GetIdx(), nLn, nTxtBreak ); 2575 else 2576 nTxtBreak = nTxtBreak + rInf.GetIdx(); 2577 } 2578 } 2579 2580 if ( ! bCompress ) 2581 return nTxtBreak; 2582 2583 nTxtBreak = nTxtBreak - rInf.GetIdx(); 2584 2585 if( nTxtBreak < nLn ) 2586 { 2587 if( !nTxtBreak && nLn ) 2588 nLn = 1; 2589 else if( nLn > 2 * nTxtBreak ) 2590 nLn = 2 * nTxtBreak; 2591 sal_Int32 *pKernArray = new sal_Int32[ nLn ]; 2592 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 2593 rInf.GetIdx(), nLn ); 2594 if( rInf.GetScriptInfo()->Compress( pKernArray, rInf.GetIdx(), nLn, 2595 rInf.GetKanaComp(), (sal_uInt16)GetHeight( nActual ) ) ) 2596 { 2597 long nKernAdd = nKern; 2598 xub_StrLen nTmpBreak = nTxtBreak; 2599 if( nKern && nTxtBreak ) 2600 nKern *= nTxtBreak - 1; 2601 while( nTxtBreak<nLn && nTextWidth >= pKernArray[nTxtBreak] +nKern ) 2602 { 2603 nKern += nKernAdd; 2604 ++nTxtBreak; 2605 } 2606 if( rInf.GetHyphPos() ) 2607 *rInf.GetHyphPos() += nTxtBreak - nTmpBreak; // It's not perfect 2608 } 2609 delete[] pKernArray; 2610 } 2611 nTxtBreak = nTxtBreak + rInf.GetIdx(); 2612 2613 return nTxtBreak; 2614 } 2615 2616 extern Color aGlobalRetoucheColor; 2617 2618 sal_Bool SwDrawTextInfo::ApplyAutoColor( Font* pFont ) 2619 { 2620 const Font& rFnt = pFont ? *pFont : GetOut().GetFont(); 2621 sal_Bool bPrt = GetShell() && ! GetShell()->GetWin(); 2622 ColorData nNewColor = COL_BLACK; 2623 sal_Bool bChgFntColor = sal_False; 2624 sal_Bool bChgLineColor = sal_False; 2625 2626 if( bPrt && GetShell() && GetShell()->GetViewOptions()->IsBlackFont() ) 2627 { 2628 if ( COL_BLACK != rFnt.GetColor().GetColor() ) 2629 bChgFntColor = sal_True; 2630 2631 if ( (COL_BLACK != GetOut().GetLineColor().GetColor()) || 2632 (COL_BLACK != GetOut().GetOverlineColor().GetColor()) ) 2633 bChgLineColor = sal_True; 2634 } 2635 else 2636 { 2637 // FontColor has to be changed if: 2638 // 1. FontColor = AUTO or 2. IsAlwaysAutoColor is set 2639 // LineColor has to be changed if: 2640 // 1. IsAlwaysAutoColor is set 2641 2642 bChgLineColor = ! bPrt && GetShell() && 2643 GetShell()->GetAccessibilityOptions()->IsAlwaysAutoColor(); 2644 2645 bChgFntColor = COL_AUTO == rFnt.GetColor().GetColor() || bChgLineColor; 2646 2647 if ( bChgFntColor ) 2648 { 2649 // check if current background has a user defined setting 2650 const Color* pCol = GetFont() ? GetFont()->GetBackColor() : NULL; 2651 if( ! pCol || COL_TRANSPARENT == pCol->GetColor() ) 2652 { 2653 const SvxBrushItem* pItem; 2654 SwRect aOrigBackRect; 2655 2656 /// OD 21.08.2002 2657 /// consider, that [GetBackgroundBrush(...)] can set <pCol> 2658 /// - see implementation in /core/layout/paintfrm.cxx 2659 /// OD 21.08.2002 #99657# 2660 /// There is a user defined setting for the background, if there 2661 /// is a background brush and its color is *not* "no fill"/"auto fill". 2662 if( GetFrm()->GetBackgroundBrush( pItem, pCol, aOrigBackRect, sal_False ) ) 2663 { 2664 if ( !pCol ) 2665 { 2666 pCol = &pItem->GetColor(); 2667 } 2668 2669 /// OD 30.08.2002 #99657# 2670 /// determined color <pCol> can be <COL_TRANSPARENT>. Thus, check it. 2671 if ( pCol->GetColor() == COL_TRANSPARENT) 2672 pCol = NULL; 2673 } 2674 else 2675 pCol = NULL; 2676 } 2677 2678 // no user defined color at paragraph or font background 2679 if ( ! pCol ) 2680 pCol = &aGlobalRetoucheColor; 2681 2682 if( GetShell() && GetShell()->GetWin() ) 2683 { 2684 // here we determine the prefered window text color for painting 2685 const SwViewOption* pViewOption = GetShell()->GetViewOptions(); 2686 if(pViewOption->IsPagePreview() && 2687 !SW_MOD()->GetAccessibilityOptions().GetIsForPagePreviews()) 2688 nNewColor = COL_BLACK; 2689 else 2690 // we take the font color from the appearence page 2691 nNewColor = SwViewOption::GetFontColor().GetColor(); 2692 } 2693 2694 // change painting color depending of dark/bright background 2695 Color aTmpColor( nNewColor ); 2696 if ( pCol->IsDark() && aTmpColor.IsDark() ) 2697 nNewColor = COL_WHITE; 2698 else if ( pCol->IsBright() && aTmpColor.IsBright() ) 2699 nNewColor = COL_BLACK; 2700 } 2701 } 2702 2703 if ( bChgFntColor || bChgLineColor ) 2704 { 2705 Color aNewColor( nNewColor ); 2706 2707 if ( bChgFntColor ) 2708 { 2709 if ( pFont && aNewColor != pFont->GetColor() ) 2710 { 2711 // only set the new color at the font passed as argument 2712 pFont->SetColor( aNewColor ); 2713 } 2714 else if ( aNewColor != GetOut().GetFont().GetColor() ) 2715 { 2716 // set new font with new color at output device 2717 Font aFont( rFnt ); 2718 aFont.SetColor( aNewColor ); 2719 GetOut().SetFont( aFont ); 2720 } 2721 } 2722 2723 // the underline and overline colors have to be set separately 2724 if ( bChgLineColor ) 2725 { 2726 // get current font color or color set at output device 2727 aNewColor = pFont ? pFont->GetColor() : GetOut().GetFont().GetColor(); 2728 if ( aNewColor != GetOut().GetLineColor() ) 2729 GetOut().SetLineColor( aNewColor ); 2730 if ( aNewColor != GetOut().GetOverlineColor() ) 2731 GetOut().SetOverlineColor( aNewColor ); 2732 } 2733 2734 return sal_True; 2735 } 2736 2737 return sal_False; 2738 } 2739 2740