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