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) return; 714 715 xub_StrLen nStart = rInf.GetIdx(); 716 xub_StrLen nWrLen = rInf.GetLen(); 717 718 // check if respective data is available in the current text range 719 if (!pWList->Check( nStart, nWrLen )) 720 { 721 return; 722 } 723 724 long nHght = rInf.GetOut().LogicToPixel( rPrtFontSize ).Height(); 725 726 // Draw wavy lines for spell and grammar errors only if font is large enough. 727 // Lines for smart tags will always be drawn. 728 if (pWList != rInf.GetSmartTags() && WRONG_SHOW_MIN >= nHght) 729 { 730 return; 731 } 732 733 SwForbidden::iterator pIter = rForbidden.begin(); 734 if (rInf.GetOut().GetConnectMetaFile()) 735 rInf.GetOut().Push(); 736 737 const Color aCol( rInf.GetOut().GetLineColor() ); 738 739 // iterate over all ranges stored in the respective SwWrongList 740 do 741 { 742 nStart = nStart - rInf.GetIdx(); 743 744 const xub_StrLen nEnd = nStart + nWrLen; 745 xub_StrLen nNext = nStart; 746 while( nNext < nEnd ) 747 { 748 while( pIter != rForbidden.end() && pIter->second <= nNext ) 749 ++pIter; 750 751 xub_StrLen nNextStart = nNext; 752 xub_StrLen nNextEnd = nEnd; 753 754 if( pIter == rForbidden.end() || nNextEnd <= pIter->first ) 755 { 756 // No overlapping mark up found 757 std::pair< xub_StrLen, xub_StrLen > aNew; 758 aNew.first = nNextStart; 759 aNew.second = nNextEnd; 760 rForbidden.insert( pIter, aNew ); 761 pIter = rForbidden.begin(); 762 nNext = nEnd; 763 } 764 else 765 { 766 nNext = pIter->second; 767 if( nNextStart < pIter->first ) 768 { 769 nNextEnd = pIter->first; 770 pIter->first = nNextStart; 771 } 772 else 773 continue; 774 } 775 // determine line pos 776 Point aStart( rInf.GetPos() ); 777 Point aEnd; 778 lcl_calcLinePos( rCalcLinePosData, aStart, aEnd, nNextStart, nNextEnd - nNextStart ); 779 780 781 sal_uInt16 wrongPos = pWList->GetWrongPos(nNextStart + rInf.GetIdx()); 782 783 const SwWrongArea* wrongArea = pWList->GetElement(wrongPos); 784 785 if (wrongArea != 0) 786 { 787 if (WRONGAREA_DASHED == wrongArea->mLineType) 788 { 789 rInf.GetOut().SetLineColor( wrongArea->mColor ); 790 791 aStart.Y() +=30; 792 aEnd.Y() +=30; 793 794 LineInfo aLineInfo( LINE_DASH ); 795 aLineInfo.SetDistance( 40 ); 796 aLineInfo.SetDashLen( 1 ); 797 aLineInfo.SetDashCount(1); 798 799 rInf.GetOut().DrawLine( aStart, aEnd, aLineInfo ); 800 } 801 else if (WRONGAREA_WAVE == wrongArea->mLineType) 802 { 803 rInf.GetOut().SetLineColor( wrongArea->mColor ); 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 else if (WRONGAREA_WAVE_NORMAL == wrongArea->mLineType) 813 { 814 rInf.GetOut().SetLineColor( wrongArea->mColor ); 815 816 rInf.GetOut().DrawWaveLine( aStart, aEnd, WAVE_NORMAL); 817 } 818 819 else if (WRONGAREA_WAVE_SMALL == wrongArea->mLineType) 820 { 821 rInf.GetOut().SetLineColor( wrongArea->mColor ); 822 823 rInf.GetOut().DrawWaveLine( aStart, aEnd, WAVE_SMALL); 824 } 825 else if (WRONGAREA_WAVE_FLAT == wrongArea->mLineType) 826 { 827 rInf.GetOut().SetLineColor( wrongArea->mColor ); 828 829 rInf.GetOut().DrawWaveLine( aStart, aEnd, WAVE_FLAT); 830 } 831 } 832 } 833 834 nStart = nEnd + rInf.GetIdx(); 835 nWrLen = rInf.GetIdx() + rInf.GetLen() - nStart; 836 } 837 while (nWrLen && pWList->Check( nStart, nWrLen )); 838 839 rInf.GetOut().SetLineColor( aCol ); 840 841 if (rInf.GetOut().GetConnectMetaFile()) 842 rInf.GetOut().Pop(); 843 } 844 845 846 void SwFntObj::DrawText( SwDrawTextInfo &rInf ) 847 { 848 ASSERT( rInf.GetShell(), "SwFntObj::DrawText without shell" ) 849 850 OutputDevice& rRefDev = rInf.GetShell()->GetRefDev(); 851 OutputDevice* pWin = rInf.GetShell()->GetWin(); 852 853 // true if pOut is the printer and the printer has been used for formatting 854 const sal_Bool bPrt = OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() && 855 OUTDEV_PRINTER == rRefDev.GetOutDevType(); 856 const sal_Bool bBrowse = ( pWin && 857 rInf.GetShell()->GetViewOptions()->getBrowseMode() && 858 !rInf.GetShell()->GetViewOptions()->IsPrtFormat() && 859 !rInf.GetBullet() && 860 ( rInf.GetSpace() || !rInf.GetKern() ) && 861 !rInf.GetWrong() && 862 !rInf.GetGrammarCheck() && 863 !rInf.GetSmartTags() && 864 !rInf.GetGreyWave() ); 865 866 // bDirectPrint indicates that we can enter the branch which calls 867 // the DrawText functions instead of calling the DrawTextArray functions 868 const sal_Bool bDirectPrint = bPrt || bBrowse; 869 870 // Condition for output font / refdev font adjustment 871 const sal_Bool bUseScrFont = 872 lcl_IsFontAdjustNecessary( rInf.GetOut(), rRefDev ); 873 874 Font* pTmpFont = bUseScrFont ? pScrFont : pPrtFont; 875 876 // 877 // bDirectPrint and bUseScrFont should have these values: 878 // 879 // Outdev / RefDef | Printer | VirtPrinter | Window 880 // ---------------------------------------------------- 881 // Printer | 1 - 0 | 0 - 1 | - 882 // ---------------------------------------------------- 883 // VirtPrinter/PDF | 0 - 1 | 0 - 1 | - 884 // ---------------------------------------------------- 885 // Window/VirtWindow| 0 - 1 | 0 - 1 | 1 - 0 886 // 887 // Exception: During painting of a Writer OLE object, we do not have 888 // a window. Therefore bUseSrcFont is always 0 in this case. 889 // 890 891 #ifdef DBG_UTIL 892 893 const sal_Bool bNoAdjust = bPrt || 894 ( pWin && 895 rInf.GetShell()->GetViewOptions()->getBrowseMode() && 896 !rInf.GetShell()->GetViewOptions()->IsPrtFormat() ); 897 898 if ( OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() ) 899 { 900 // Printer output 901 if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() ) 902 { 903 ASSERT( bNoAdjust == 1 && bUseScrFont == 0, "Outdev Check failed" ) 904 } 905 else if ( OUTDEV_VIRDEV == rRefDev.GetOutDevType() ) 906 { 907 ASSERT( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" ) 908 } 909 else 910 { 911 ASSERT( sal_False, "Outdev Check failed" ) 912 } 913 } 914 else if ( OUTDEV_VIRDEV == rInf.GetOut().GetOutDevType() && ! pWin ) 915 { 916 // PDF export 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 926 { 927 ASSERT( sal_False, "Outdev Check failed" ) 928 } 929 } 930 else if ( OUTDEV_WINDOW == rInf.GetOut().GetOutDevType() || 931 ( OUTDEV_VIRDEV == rInf.GetOut().GetOutDevType() && pWin ) ) 932 { 933 // Window or virtual window 934 if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() ) 935 { 936 ASSERT( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" ) 937 } 938 else if ( OUTDEV_VIRDEV == rRefDev.GetOutDevType() ) 939 { 940 ASSERT( bNoAdjust == 0 && bUseScrFont == 1, "Outdev Check failed" ) 941 } 942 else if ( OUTDEV_WINDOW == rRefDev.GetOutDevType() ) 943 { 944 ASSERT( bNoAdjust == 1 && bUseScrFont == 0, "Outdev Check failed" ) 945 } 946 else 947 { 948 ASSERT( sal_False, "Outdev Check failed" ) 949 } 950 } 951 else 952 { 953 ASSERT( sal_False, "Outdev Check failed" ) 954 } 955 956 #endif 957 958 // robust: better use the printer font instead of using no font at all 959 ASSERT( pTmpFont, "No screen or printer font?" ); 960 if ( ! pTmpFont ) 961 pTmpFont = pPrtFont; 962 963 // HACK: UNDERLINE_WAVE darf nicht mehr missbraucht werden, daher 964 // wird die graue Wellenlinie des ExtendedAttributSets zunaechst 965 // in der Fontfarbe erscheinen. 966 967 const sal_Bool bSwitchH2V = rInf.GetFrm() && rInf.GetFrm()->IsVertical(); 968 const sal_Bool bSwitchL2R = rInf.GetFrm() && rInf.GetFrm()->IsRightToLeft() && 969 ! rInf.IsIgnoreFrmRTL(); 970 const sal_uLong nMode = rInf.GetOut().GetLayoutMode(); 971 const sal_Bool bBidiPor = ( bSwitchL2R != 972 ( 0 != ( TEXT_LAYOUT_BIDI_RTL & nMode ) ) ); 973 974 // be sure to have the correct layout mode at the printer 975 if ( pPrinter ) 976 { 977 pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() ); 978 pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() ); 979 } 980 981 Point aPos( rInf.GetPos() ); 982 if( !bPrt ) 983 { 984 if( rInf.GetpOut() != pPixOut || rInf.GetOut().GetMapMode() != *pPixMap ) 985 { 986 *pPixMap = rInf.GetOut().GetMapMode(); 987 pPixOut = rInf.GetpOut(); 988 Size aTmp( 1, 1 ); 989 nPixWidth = rInf.GetOut().PixelToLogic( aTmp ).Width(); 990 } 991 992 aPos.X() += rInf.GetFrm()->IsRightToLeft() ? 0 : nPixWidth; 993 } 994 995 Color aOldColor( pTmpFont->GetColor() ); 996 sal_Bool bChgColor = rInf.ApplyAutoColor( pTmpFont ); 997 if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) ) 998 rInf.GetOut().SetFont( *pTmpFont ); 999 if ( bChgColor ) 1000 pTmpFont->SetColor( aOldColor ); 1001 1002 if ( STRING_LEN == rInf.GetLen() ) 1003 rInf.SetLen( rInf.GetText().Len() ); 1004 1005 1006 // 1007 // ASIAN LINE AND CHARACTER GRID MODE START: snap to characters 1008 // 1009 1010 if ( rInf.GetFrm() && rInf.SnapToGrid() && rInf.GetFont() && 1011 SW_CJK == rInf.GetFont()->GetActual() ) 1012 { 1013 GETGRID( rInf.GetFrm()->FindPageFrm() ) 1014 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars()) 1015 { 1016 //for textgrid refactor 1017 //const sal_uInt16 nGridWidth = pGrid->GetBaseHeight(); 1018 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 1019 const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc); 1020 sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()]; 1021 1022 if ( pPrinter ) 1023 pPrinter->GetTextArray( rInf.GetText(), pKernArray, 1024 rInf.GetIdx(), rInf.GetLen() ); 1025 else 1026 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 1027 rInf.GetIdx(), rInf.GetLen() ); 1028 1029 long nWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen(); 1030 1031 const sal_uLong i = nWidthPerChar ? 1032 ( nWidthPerChar - 1 ) / nGridWidth + 1: 1033 1; 1034 1035 nWidthPerChar = i * nGridWidth; 1036 1037 // position of first character, we take the printer position 1038 long nCharWidth = pKernArray[ 0 ]; 1039 sal_uLong nHalfWidth = nWidthPerChar / 2; 1040 1041 long nNextFix; 1042 1043 // punctuation characters are not centered 1044 xub_Unicode cChar = rInf.GetText().GetChar( rInf.GetIdx() ); 1045 sal_uInt8 nType = lcl_WhichPunctuation( cChar ); 1046 switch ( nType ) 1047 { 1048 case SwScriptInfo::NONE : 1049 aPos.X() += ( nWidthPerChar - nCharWidth ) / 2; 1050 nNextFix = nCharWidth / 2; 1051 break; 1052 case SwScriptInfo::SPECIAL_RIGHT : 1053 nNextFix = nHalfWidth; 1054 break; 1055 default: 1056 aPos.X() += nWidthPerChar - nCharWidth; 1057 nNextFix = nCharWidth - nHalfWidth; 1058 } 1059 1060 // calculate offsets 1061 for ( xub_StrLen j = 1; j < rInf.GetLen(); ++j ) 1062 { 1063 long nScr = pKernArray[ j ] - pKernArray[ j - 1 ]; 1064 nNextFix += nWidthPerChar; 1065 1066 // punctuation characters are not centered 1067 cChar = rInf.GetText().GetChar( rInf.GetIdx() + j ); 1068 nType = lcl_WhichPunctuation( cChar ); 1069 switch ( nType ) 1070 { 1071 case SwScriptInfo::NONE : 1072 pKernArray[ j - 1 ] = nNextFix - ( nScr / 2 ); 1073 break; 1074 case SwScriptInfo::SPECIAL_RIGHT : 1075 pKernArray[ j - 1 ] = nNextFix - nHalfWidth; 1076 break; 1077 default: 1078 pKernArray[ j - 1 ] = nNextFix + nHalfWidth - nScr; 1079 } 1080 } 1081 1082 // the layout engine requires the total width of the output 1083 pKernArray[ rInf.GetLen() - 1 ] = rInf.GetWidth() - 1084 aPos.X() + rInf.GetPos().X() ; 1085 1086 if ( bSwitchH2V ) 1087 rInf.GetFrm()->SwitchHorizontalToVertical( aPos ); 1088 1089 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1090 pKernArray, rInf.GetIdx(), rInf.GetLen() ); 1091 1092 delete[] pKernArray; 1093 return; 1094 } 1095 } 1096 1097 // For text grid refactor 1098 // ASIAN LINE AND CHARACTER GRID MODE START: not snap to characters 1099 // 1100 if ( rInf.GetFrm() && rInf.SnapToGrid() && rInf.GetFont() && 1101 SW_CJK == rInf.GetFont()->GetActual() ) 1102 { 1103 GETGRID( rInf.GetFrm()->FindPageFrm() ) 1104 1105 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() ) 1106 { 1107 const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf ); 1108 1109 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 1110 long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc); 1111 if( SW_LATIN == rInf.GetFont()->GetActual() ) 1112 nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2; 1113 else 1114 nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight; 1115 1116 sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()]; 1117 1118 if ( pPrinter ) 1119 pPrinter->GetTextArray( rInf.GetText(), pKernArray, 1120 rInf.GetIdx(), rInf.GetLen() ); 1121 else 1122 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 1123 rInf.GetIdx(), rInf.GetLen() ); 1124 if ( bSwitchH2V ) 1125 rInf.GetFrm()->SwitchHorizontalToVertical( aPos ); 1126 if ( rInf.GetSpace() || rInf.GetKanaComp()) 1127 { 1128 long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR; 1129 sal_Bool bSpecialJust = sal_False; 1130 if ( rInf.GetFont() && rInf.GetLen() ) 1131 { 1132 const SwScriptInfo* pSI = rInf.GetScriptInfo(); 1133 const sal_uInt8 nActual = rInf.GetFont()->GetActual(); 1134 ///Kana Compression 1135 if( SW_CJK == nActual && rInf.GetKanaComp() && 1136 pSI && pSI->CountCompChg() && 1137 lcl_IsMonoSpaceFont( *(rInf.GetpOut()) ) ) 1138 { 1139 pSI->Compress( pKernArray,rInf.GetIdx(), rInf.GetLen(), 1140 rInf.GetKanaComp(), (sal_uInt16)aFont.GetSize().Height(),&aPos ); 1141 bSpecialJust = sal_True; 1142 } 1143 ///Asian Justification 1144 if ( ( SW_CJK == nActual || SW_LATIN == nActual ) && nSpaceAdd ) 1145 { 1146 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK ); 1147 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang) 1148 { 1149 long nSpaceSum = nSpaceAdd; 1150 for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI ) 1151 { 1152 pKernArray[ nI ] += nSpaceSum; 1153 nSpaceSum += nSpaceAdd; 1154 } 1155 bSpecialJust = sal_True; 1156 nSpaceAdd = 0; 1157 } 1158 } 1159 long nGridAddSum = nGridWidthAdd; 1160 for(xub_StrLen i = 0; i < rInf.GetLen(); i++,nGridAddSum += nGridWidthAdd ) 1161 { 1162 pKernArray[i] += nGridAddSum; 1163 } 1164 long nKernSum = rInf.GetKern(); 1165 if ( bSpecialJust || rInf.GetKern() ) 1166 { 1167 for( xub_StrLen i = 0; i < rInf.GetLen(); i++, nKernSum += rInf.GetKern() ) 1168 { 1169 if ( CH_BLANK == rInf.GetText().GetChar(rInf.GetIdx()+i) ) 1170 nKernSum += nSpaceAdd; 1171 pKernArray[i] += nKernSum; 1172 } 1173 ///With through/uderstr. Grouped style requires a blank at the end 1174 ///of a text edition special measures: 1175 if( bPaintBlank && rInf.GetLen() && (CH_BLANK == 1176 rInf.GetText().GetChar( rInf.GetIdx() + rInf.GetLen() - 1) ) ) 1177 { 1178 ///If it concerns a singular, underlined space acts, 1179 ///we must spend two: 1180 if( 1 == rInf.GetLen() ) 1181 { 1182 pKernArray[0] = rInf.GetWidth() + nSpaceAdd; 1183 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1184 pKernArray, rInf.GetIdx(), 1 ); 1185 } 1186 else 1187 { 1188 pKernArray[ rInf.GetLen() - 2] += nSpaceAdd; 1189 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1190 pKernArray, rInf.GetIdx(), rInf.GetLen() ); 1191 } 1192 } 1193 else 1194 { 1195 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1196 pKernArray, rInf.GetIdx(), rInf.GetLen() ); 1197 } 1198 } 1199 else 1200 { 1201 Point aTmpPos( aPos ); 1202 xub_StrLen i; 1203 xub_StrLen j = 0; 1204 long nSpaceSum = 0; 1205 for( i = 0; i < rInf.GetLen(); i++ ) 1206 { 1207 if( CH_BLANK == rInf.GetText().GetChar( rInf.GetIdx() + i) ) 1208 { 1209 nSpaceSum += nSpaceAdd; 1210 if( j < i) 1211 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(), 1212 rInf.GetIdx() + j, i - j ); 1213 j = i + 1; 1214 pKernArray[i] = pKernArray[i] + nSpaceSum; 1215 aTmpPos.X() = aPos.X() + pKernArray[ i ] + nKernSum; 1216 } 1217 } 1218 if( j < i ) 1219 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(), 1220 rInf.GetIdx() +j , i - j ); 1221 } 1222 } 1223 } 1224 else 1225 { 1226 //long nKernAdd = rInf.GetKern(); 1227 long nKernAdd = 0; 1228 long nGridAddSum = nGridWidthAdd + nKernAdd; 1229 for(xub_StrLen i = 0; i < rInf.GetLen(); i++,nGridAddSum += nGridWidthAdd + nKernAdd ) 1230 { 1231 pKernArray[i] += nGridAddSum; 1232 } 1233 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1234 pKernArray, rInf.GetIdx(), rInf.GetLen() ); 1235 } 1236 delete[] pKernArray; 1237 return; 1238 } 1239 } 1240 1241 // 1242 // DIRECT PAINTING WITHOUT SCREEN ADJUSTMENT 1243 // 1244 1245 if ( bDirectPrint ) 1246 { 1247 const Fraction aTmp( 1, 1 ); 1248 sal_Bool bStretch = rInf.GetWidth() && ( rInf.GetLen() > 1 ) && bPrt 1249 && ( aTmp != rInf.GetOut().GetMapMode().GetScaleX() ); 1250 1251 if ( bSwitchL2R ) 1252 rInf.GetFrm()->SwitchLTRtoRTL( aPos ); 1253 1254 if ( bSwitchH2V ) 1255 rInf.GetFrm()->SwitchHorizontalToVertical( aPos ); 1256 1257 // In the good old days we used to have a simple DrawText if the 1258 // output device is the printer. Now we need a DrawTextArray if 1259 // 1. KanaCompression is enabled 1260 // 2. Justified alignment 1261 // Simple kerning is handled by DrawStretchText 1262 if( rInf.GetSpace() || rInf.GetKanaComp() ) 1263 { 1264 sal_Int32 *pKernArray = new sal_Int32[ rInf.GetLen() ]; 1265 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 1266 rInf.GetIdx(), rInf.GetLen() ); 1267 1268 if( bStretch ) 1269 { 1270 xub_StrLen nZwi = rInf.GetLen() - 1; 1271 long nDiff = rInf.GetWidth() - pKernArray[ nZwi ] 1272 - rInf.GetLen() * rInf.GetKern(); 1273 long nRest = nDiff % nZwi; 1274 long nAdd; 1275 if( nRest < 0 ) 1276 { 1277 nAdd = -1; 1278 nRest += nZwi; 1279 } 1280 else 1281 { 1282 nAdd = +1; 1283 nRest = nZwi - nRest; 1284 } 1285 nDiff /= nZwi; 1286 long nSum = nDiff; 1287 for( xub_StrLen i = 0; i < nZwi; ) 1288 { 1289 pKernArray[ i ] += nSum; 1290 if( ++i == nRest ) 1291 nDiff += nAdd; 1292 nSum += nDiff; 1293 } 1294 } 1295 1296 // 1297 // Modify Array for special justifications 1298 // 1299 long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR; 1300 sal_Bool bSpecialJust = sal_False; 1301 1302 if ( rInf.GetFont() && rInf.GetLen() ) 1303 { 1304 const SwScriptInfo* pSI = rInf.GetScriptInfo(); 1305 const sal_uInt8 nActual = rInf.GetFont()->GetActual(); 1306 1307 // Kana Compression 1308 if ( SW_CJK == nActual && rInf.GetKanaComp() && 1309 pSI && pSI->CountCompChg() && 1310 lcl_IsMonoSpaceFont( rInf.GetOut() ) ) 1311 { 1312 pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(), 1313 rInf.GetKanaComp(), 1314 (sal_uInt16)aFont.GetSize().Height(), &aPos ); 1315 bSpecialJust = sal_True; 1316 } 1317 1318 // Asian Justification 1319 if ( SW_CJK == nActual && nSpaceAdd ) 1320 { 1321 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK ); 1322 1323 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang ) 1324 { 1325 long nSpaceSum = nSpaceAdd; 1326 for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI ) 1327 { 1328 pKernArray[ nI ] += nSpaceSum; 1329 nSpaceSum += nSpaceAdd; 1330 } 1331 1332 bSpecialJust = sal_True; 1333 nSpaceAdd = 0; 1334 } 1335 } 1336 1337 // Kashida Justification 1338 if ( SW_CTL == nActual && nSpaceAdd ) 1339 { 1340 if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) 1341 { 1342 if ( pSI && pSI->CountKashida() && 1343 pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), 1344 rInf.GetLen(), nSpaceAdd ) != STRING_LEN ) 1345 { 1346 bSpecialJust = sal_True; 1347 nSpaceAdd = 0; 1348 } 1349 } 1350 } 1351 1352 // Thai Justification 1353 if ( SW_CTL == nActual && nSpaceAdd ) 1354 { 1355 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL ); 1356 1357 if ( LANGUAGE_THAI == aLang ) 1358 { 1359 // Use rInf.GetSpace() because it has more precision than 1360 // nSpaceAdd: 1361 SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray, 0, 1362 rInf.GetIdx(), rInf.GetLen(), 1363 rInf.GetNumberOfBlanks(), 1364 rInf.GetSpace() ); 1365 1366 // adding space to blanks is already done 1367 bSpecialJust = sal_True; 1368 nSpaceAdd = 0; 1369 } 1370 } 1371 } 1372 1373 long nKernSum = rInf.GetKern(); 1374 1375 if ( bStretch || bPaintBlank || rInf.GetKern() || bSpecialJust ) 1376 { 1377 for( xub_StrLen i = 0; i < rInf.GetLen(); i++, 1378 nKernSum += rInf.GetKern() ) 1379 { 1380 if ( CH_BLANK == rInf.GetText().GetChar(rInf.GetIdx()+i) ) 1381 nKernSum += nSpaceAdd; 1382 pKernArray[i] += nKernSum; 1383 } 1384 1385 // Bei durch/unterstr. Blocksatz erfordert ein Blank am Ende 1386 // einer Textausgabe besondere Massnahmen: 1387 if( bPaintBlank && rInf.GetLen() && ( CH_BLANK == 1388 rInf.GetText().GetChar( rInf.GetIdx()+rInf.GetLen()-1 ) ) ) 1389 { 1390 // Wenn es sich um ein singulaeres, unterstrichenes Space 1391 // handelt, muessen wir zwei ausgeben: 1392 if( 1 == rInf.GetLen() ) 1393 { 1394 pKernArray[0] = rInf.GetWidth() + nSpaceAdd; 1395 1396 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1397 pKernArray, rInf.GetIdx(), 1 ); 1398 } 1399 else 1400 { 1401 pKernArray[ rInf.GetLen() - 2 ] += nSpaceAdd; 1402 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1403 pKernArray, rInf.GetIdx(), rInf.GetLen() ); 1404 } 1405 } 1406 else 1407 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1408 pKernArray, rInf.GetIdx(), rInf.GetLen() ); 1409 } 1410 else 1411 { 1412 Point aTmpPos( aPos ); 1413 xub_StrLen j = 0; 1414 xub_StrLen i; 1415 for( i = 0; i < rInf.GetLen(); i++ ) 1416 { 1417 if( CH_BLANK == rInf.GetText().GetChar( rInf.GetIdx()+i ) ) 1418 { 1419 nKernSum += nSpaceAdd; 1420 if( j < i ) 1421 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(), 1422 rInf.GetIdx() + j, i - j ); 1423 j = i + 1; 1424 SwTwips nAdd = pKernArray[ i ] + nKernSum; 1425 if ( ( TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL ) == nMode ) 1426 nAdd *= -1; 1427 aTmpPos.X() = aPos.X() + nAdd; 1428 } 1429 } 1430 if( j < i ) 1431 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(), 1432 rInf.GetIdx() + j, i - j ); 1433 } 1434 delete[] pKernArray; 1435 } 1436 else if( bStretch ) 1437 { 1438 long nTmpWidth = rInf.GetWidth(); 1439 if( rInf.GetKern() && rInf.GetLen() && nTmpWidth > rInf.GetKern() ) 1440 nTmpWidth -= rInf.GetKern(); 1441 rInf.GetOut().DrawStretchText( aPos, nTmpWidth, 1442 rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ); 1443 } 1444 else if( rInf.GetKern() ) 1445 { 1446 const long nTmpWidth = GetTextSize( rInf ).Width(); 1447 1448 const Color aSaveColor( pTmpFont->GetColor() ); 1449 const sal_Bool bColorChanged = rInf.ApplyAutoColor( pTmpFont ); 1450 1451 if( bColorChanged ) 1452 { 1453 if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) ) 1454 rInf.GetOut().SetFont( *pTmpFont ); 1455 pTmpFont->SetColor( aSaveColor ); 1456 } 1457 1458 rInf.GetOut().DrawStretchText( aPos, (sal_uInt16)nTmpWidth, 1459 rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ); 1460 } 1461 else 1462 rInf.GetOut().DrawText( aPos, rInf.GetText(), 1463 rInf.GetIdx(), rInf.GetLen() ); 1464 } 1465 1466 // 1467 // PAINTING WITH FORMATTING DEVICE/SCREEN ADJUSTMENT 1468 // 1469 1470 else 1471 { 1472 const String* pStr = &rInf.GetText(); 1473 String aStr( aEmptyStr ); 1474 sal_Bool bBullet = rInf.GetBullet(); 1475 if( bSymbol ) 1476 bBullet = sal_False; 1477 sal_Int32 *pKernArray = new sal_Int32[ rInf.GetLen() ]; 1478 CreateScrFont( *rInf.GetShell(), rInf.GetOut() ); 1479 long nScrPos; 1480 1481 // get screen array 1482 sal_Int32* pScrArray = new sal_Int32[ rInf.GetLen() ]; 1483 rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray, 1484 rInf.GetIdx(), rInf.GetLen() ); 1485 1486 // OLE: no printer available 1487 // ASSERT( pPrinter, "DrawText needs pPrinter" ) 1488 if ( pPrinter ) 1489 { 1490 // pTmpFont has already been set as current font for rInf.GetOut() 1491 if ( pPrinter != rInf.GetpOut() || pTmpFont != pPrtFont ) 1492 { 1493 if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) ) 1494 pPrinter->SetFont( *pPrtFont ); 1495 } 1496 pPrinter->GetTextArray( rInf.GetText(), pKernArray, rInf.GetIdx(), 1497 rInf.GetLen() ); 1498 } 1499 else 1500 { 1501 // sal_Bool bRestore = sal_False; 1502 // MapMode aOld( rInf.GetOut().GetMapMode() ); 1503 // if( rInf.GetZoom().GetNumerator() && 1504 // rInf.GetZoom() != aOld.GetScaleX() ) 1505 // { 1506 // MapMode aNew( aOld ); 1507 // aNew.SetScaleX( rInf.GetZoom() ); 1508 // aNew.SetScaleY( rInf.GetZoom() ); 1509 // rInf.GetOut().SetMapMode( aNew ); 1510 // bRestore = sal_True; 1511 // } 1512 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 1513 rInf.GetIdx(), rInf.GetLen() ); 1514 // if( bRestore ) 1515 // rInf.GetOut().SetMapMode( aOld ); 1516 } 1517 1518 // 1519 // Modify Printer and ScreenArrays for special justifications 1520 // 1521 long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR; 1522 bool bNoHalfSpace = false; 1523 1524 if ( rInf.GetFont() && rInf.GetLen() ) 1525 { 1526 const sal_uInt8 nActual = rInf.GetFont()->GetActual(); 1527 const SwScriptInfo* pSI = rInf.GetScriptInfo(); 1528 1529 // Kana Compression 1530 if ( SW_CJK == nActual && rInf.GetKanaComp() && 1531 pSI && pSI->CountCompChg() && 1532 lcl_IsMonoSpaceFont( rInf.GetOut() ) ) 1533 { 1534 Point aTmpPos( aPos ); 1535 pSI->Compress( pScrArray, rInf.GetIdx(), rInf.GetLen(), 1536 rInf.GetKanaComp(), 1537 (sal_uInt16)aFont.GetSize().Height(), &aTmpPos ); 1538 pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(), 1539 rInf.GetKanaComp(), 1540 (sal_uInt16)aFont.GetSize().Height(), &aPos ); 1541 } 1542 1543 // Asian Justification 1544 if ( SW_CJK == nActual && nSpaceAdd ) 1545 { 1546 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK ); 1547 1548 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang ) 1549 { 1550 long nSpaceSum = nSpaceAdd; 1551 for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI ) 1552 { 1553 pKernArray[ nI ] += nSpaceSum; 1554 pScrArray[ nI ] += nSpaceSum; 1555 nSpaceSum += nSpaceAdd; 1556 } 1557 1558 nSpaceAdd = 0; 1559 } 1560 } 1561 1562 // Kashida Justification 1563 if ( SW_CTL == nActual && nSpaceAdd ) 1564 { 1565 if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) 1566 { 1567 if ( pSI && pSI->CountKashida() && 1568 pSI->KashidaJustify( pKernArray, pScrArray, rInf.GetIdx(), 1569 rInf.GetLen(), nSpaceAdd ) != STRING_LEN ) 1570 nSpaceAdd = 0; 1571 else 1572 bNoHalfSpace = true; 1573 } 1574 } 1575 1576 // Thai Justification 1577 if ( SW_CTL == nActual && nSpaceAdd ) 1578 { 1579 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL ); 1580 1581 if ( LANGUAGE_THAI == aLang ) 1582 { 1583 SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray, 1584 pScrArray, rInf.GetIdx(), 1585 rInf.GetLen(), 1586 rInf.GetNumberOfBlanks(), 1587 rInf.GetSpace() ); 1588 1589 // adding space to blanks is already done 1590 nSpaceAdd = 0; 1591 } 1592 } 1593 } 1594 1595 nScrPos = pScrArray[ 0 ]; 1596 1597 if( bBullet ) 1598 { 1599 // !!! HACK !!! 1600 // The Arabic layout engine requires some context of the string 1601 // which should be painted. 1602 xub_StrLen nCopyStart = rInf.GetIdx(); 1603 if ( nCopyStart ) 1604 --nCopyStart; 1605 1606 xub_StrLen nCopyLen = rInf.GetLen(); 1607 if ( nCopyStart + nCopyLen < rInf.GetText().Len() ) 1608 ++nCopyLen; 1609 1610 aStr = rInf.GetText().Copy( nCopyStart, nCopyLen ); 1611 pStr = &aStr; 1612 1613 for( xub_StrLen i = 0; i < aStr.Len(); ++i ) 1614 if( CH_BLANK == aStr.GetChar( i ) ) 1615 aStr.SetChar( i, CH_BULLET ); 1616 } 1617 1618 xub_StrLen nCnt = rInf.GetText().Len(); 1619 if ( nCnt < rInf.GetIdx() ) 1620 nCnt = 0; 1621 else 1622 nCnt = nCnt - rInf.GetIdx(); 1623 nCnt = Min( nCnt, rInf.GetLen() ); 1624 long nKernSum = rInf.GetKern(); 1625 xub_Unicode cChPrev = rInf.GetText().GetChar( rInf.GetIdx() ); 1626 1627 // Wenn es sich um ein singulaeres, unterstrichenes Space 1628 // im Blocksatz handelt, muessen wir zwei ausgeben: 1629 if ( ( nCnt == 1 ) && rInf.GetSpace() && ( cChPrev == CH_BLANK ) ) 1630 { 1631 pKernArray[0] = rInf.GetWidth() + 1632 rInf.GetKern() + 1633 ( rInf.GetSpace() / SPACING_PRECISION_FACTOR ); 1634 1635 if ( bSwitchL2R ) 1636 rInf.GetFrm()->SwitchLTRtoRTL( aPos ); 1637 1638 if ( bSwitchH2V ) 1639 rInf.GetFrm()->SwitchHorizontalToVertical( aPos ); 1640 1641 rInf.GetOut().DrawTextArray( aPos, rInf.GetText(), 1642 pKernArray, rInf.GetIdx(), 1 ); 1643 if( bBullet ) 1644 rInf.GetOut().DrawTextArray( aPos, *pStr, pKernArray, 1645 rInf.GetIdx() ? 1 : 0, 1 ); 1646 } 1647 else 1648 { 1649 xub_Unicode nCh; 1650 1651 // Bei Pairkerning waechst der Printereinfluss auf die Positionierung 1652 sal_uInt16 nMul = 3; 1653 1654 if ( pPrtFont->GetKerning() ) 1655 nMul = 1; 1656 1657 const sal_uInt16 nDiv = nMul+1; 1658 1659 // In nSpaceSum wird der durch Blocksatz auf die Spaces verteilte 1660 // Zwischenraum aufsummiert. 1661 // Die Spaces selbst werden im Normalfall in der Mitte des 1662 // Zwischenraums positioniert, deshalb die nSpace/2-Mimik. 1663 // Bei wortweiser Unterstreichung muessen sie am Anfang des 1664 // Zwischenraums stehen, damit dieser nicht unterstrichen wird. 1665 // Ein Space am Anfang oder am Ende des Textes muss allerdings 1666 // vor bzw. hinter den kompletten Zwischenraum gesetzt werden, 1667 // sonst wuerde das Durch-/Unterstreichen Luecken aufweisen. 1668 long nSpaceSum = 0; 1669 // in word line mode and for Arabic, we disable the half space trick: 1670 const long nHalfSpace = pPrtFont->IsWordLineMode() || bNoHalfSpace ? 0 : nSpaceAdd / 2; 1671 const long nOtherHalf = nSpaceAdd - nHalfSpace; 1672 if ( nSpaceAdd && ( cChPrev == CH_BLANK ) ) 1673 nSpaceSum = nHalfSpace; 1674 for ( xub_StrLen i=1; i<nCnt; ++i,nKernSum += rInf.GetKern() ) 1675 { 1676 nCh = rInf.GetText().GetChar( rInf.GetIdx() + i ); 1677 1678 ASSERT( pScrArray, "Where is the screen array?" ) 1679 long nScr; 1680 nScr = pScrArray[ i ] - pScrArray[ i - 1 ]; 1681 1682 // Wenn vor uns ein (Ex-)SPACE ist, positionieren wir uns optimal, 1683 // d.h. unseren rechten Rand auf die 100% Druckerposition, 1684 // sind wir sogar selbst ein Ex-SPACE, so positionieren wir uns 1685 // linksbuendig zur Druckerposition. 1686 if ( nCh == CH_BLANK ) 1687 { 1688 #ifdef FONT_TEST_DEBUG 1689 lcl_Pos( 3, nScrPos, nScr, pKernArray[i-1], pKernArray[i] ); 1690 #else 1691 nScrPos = pKernArray[i-1] + nScr; 1692 #endif 1693 if ( cChPrev == CH_BLANK ) 1694 nSpaceSum += nOtherHalf; 1695 if ( i + 1 == nCnt ) 1696 nSpaceSum += nSpaceAdd; 1697 else 1698 nSpaceSum += nHalfSpace; 1699 } 1700 else 1701 { 1702 if ( cChPrev == CH_BLANK ) 1703 { 1704 #ifdef FONT_TEST_DEBUG 1705 lcl_Pos( 6, nScrPos, nScr, pKernArray[i-1], pKernArray[i] ); 1706 #else 1707 nScrPos = pKernArray[i-1] + nScr; 1708 #endif 1709 // kein Pixel geht verloren: 1710 nSpaceSum += nOtherHalf; 1711 } 1712 else if ( cChPrev == '-' ) 1713 #ifdef FONT_TEST_DEBUG 1714 lcl_Pos( 6, nScrPos, nScr, pKernArray[i-1], pKernArray[i] ); 1715 #else 1716 nScrPos = pKernArray[i-1] + nScr; 1717 #endif 1718 else 1719 { 1720 #ifdef FONT_TEST_DEBUG 1721 lcl_Pos( 0, nScrPos, nScr, pKernArray[i-1], pKernArray[i] ); 1722 #else 1723 nScrPos += nScr; 1724 nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv; 1725 #endif 1726 } 1727 } 1728 cChPrev = nCh; 1729 pKernArray[i-1] = nScrPos - nScr + nKernSum + nSpaceSum; 1730 // In word line mode and for Arabic, we disabled the half space trick. If a portion 1731 // ends with a blank, the full nSpaceAdd value has been added to the character in 1732 // front of the blank. This leads to painting artifacts, therefore we remove the 1733 // nSpaceAdd value again: 1734 if ( (bNoHalfSpace || pPrtFont->IsWordLineMode()) && i+1 == nCnt && nCh == CH_BLANK ) 1735 pKernArray[i-1] = pKernArray[i-1] - nSpaceAdd; 1736 } 1737 1738 // the layout engine requires the total width of the output 1739 pKernArray[ rInf.GetLen() - 1 ] += nKernSum + nSpaceSum; 1740 1741 if( rInf.GetGreyWave() ) 1742 { 1743 if( rInf.GetLen() ) 1744 { 1745 long nHght = rInf.GetOut().LogicToPixel( 1746 pPrtFont->GetSize() ).Height(); 1747 if( WRONG_SHOW_MIN < nHght ) 1748 { 1749 if ( rInf.GetOut().GetConnectMetaFile() ) 1750 rInf.GetOut().Push(); 1751 1752 sal_uInt16 nWave = 1753 WRONG_SHOW_MEDIUM < nHght ? WAVE_NORMAL : 1754 ( WRONG_SHOW_SMALL < nHght ? WAVE_SMALL : 1755 WAVE_FLAT ); 1756 Color aCol( rInf.GetOut().GetLineColor() ); 1757 sal_Bool bColSave = aCol != *pWaveCol; 1758 if ( bColSave ) 1759 rInf.GetOut().SetLineColor( *pWaveCol ); 1760 1761 Point aEnd; 1762 long nKernVal = pKernArray[ sal_uInt16( rInf.GetLen() - 1 ) ]; 1763 1764 sal_uInt16 nDir = bBidiPor ? 1765 1800 : 1766 UnMapDirection( 1767 GetFont()->GetOrientation(), 1768 bSwitchH2V ); 1769 1770 switch ( nDir ) 1771 { 1772 case 0 : 1773 aEnd.X() = rInf.GetPos().X() + nKernVal; 1774 aEnd.Y() = rInf.GetPos().Y(); 1775 break; 1776 case 900 : 1777 aEnd.X() = rInf.GetPos().X(); 1778 aEnd.Y() = rInf.GetPos().Y() - nKernVal; 1779 break; 1780 case 1800 : 1781 aEnd.X() = rInf.GetPos().X() - nKernVal; 1782 aEnd.Y() = rInf.GetPos().Y(); 1783 break; 1784 case 2700 : 1785 aEnd.X() = rInf.GetPos().X(); 1786 aEnd.Y() = rInf.GetPos().Y() + nKernVal; 1787 break; 1788 } 1789 1790 Point aCurrPos( rInf.GetPos() ); 1791 1792 if ( bSwitchL2R ) 1793 { 1794 rInf.GetFrm()->SwitchLTRtoRTL( aCurrPos ); 1795 rInf.GetFrm()->SwitchLTRtoRTL( aEnd ); 1796 } 1797 1798 if ( bSwitchH2V ) 1799 { 1800 rInf.GetFrm()->SwitchHorizontalToVertical( aCurrPos ); 1801 rInf.GetFrm()->SwitchHorizontalToVertical( aEnd ); 1802 } 1803 rInf.GetOut().DrawWaveLine( aCurrPos, aEnd, nWave ); 1804 1805 if ( bColSave ) 1806 rInf.GetOut().SetLineColor( aCol ); 1807 1808 if ( rInf.GetOut().GetConnectMetaFile() ) 1809 rInf.GetOut().Pop(); 1810 } 1811 } 1812 } 1813 else if( !bSymbol && rInf.GetLen() ) 1814 { 1815 // anything to do? 1816 if (rInf.GetWrong() || rInf.GetGrammarCheck() || rInf.GetSmartTags()) 1817 { 1818 CalcLinePosData aCalcLinePosData(rInf, *GetFont(), 1819 nCnt, bSwitchH2V, bSwitchL2R, 1820 nHalfSpace, pKernArray, bBidiPor); 1821 1822 SwForbidden aForbidden; 1823 // draw line for smart tag data 1824 lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetSmartTags(), aCalcLinePosData, Size() ); 1825 // draw wave line for spell check errors 1826 // draw them BEFORE the grammar check lines to 'override' the latter in case of conflict. 1827 // reason: some grammar errors can only be found if spelling errors are fixed, 1828 // therefore we don't want the user to miss a spelling error. 1829 lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetWrong(), aCalcLinePosData, pPrtFont->GetSize() ); 1830 // draw wave line for grammar check errors 1831 lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetGrammarCheck(), aCalcLinePosData, pPrtFont->GetSize() ); 1832 } 1833 } 1834 1835 xub_StrLen nOffs = 0; 1836 xub_StrLen nLen = rInf.GetLen(); 1837 #ifdef COMING_SOON 1838 if( aPos.X() < rInf.GetLeft() ) 1839 { 1840 while( nOffs < nLen && 1841 aPos.X() + pKernArray[ nOffs ] < rInf.GetLeft() ) 1842 ++nOffs; 1843 if( nOffs < nLen ) 1844 { 1845 --nLen; 1846 while( nLen > nOffs && 1847 aPos.X() + pKernArray[ nLen ] > rInf.GetRight() ) 1848 --nLen; 1849 ++nLen; 1850 if( nOffs ) 1851 --nOffs; 1852 } 1853 if( nOffs ) 1854 { 1855 long nDiff = pKernArray[ nOffs - 1 ]; 1856 aPos.X() += nDiff; 1857 for( xub_StrLen nX = nOffs; nX < nLen; ++nX ) 1858 pKernArray[ nX ] -= nDiff; 1859 } 1860 } 1861 #endif 1862 if( nOffs < nLen ) 1863 { 1864 // If we paint bullets instead of spaces, we use a copy of 1865 // the paragraph string. For the layout engine, the copy 1866 // of the string has to be an environment of the range which 1867 // is painted 1868 xub_StrLen nTmpIdx = bBullet ? 1869 ( rInf.GetIdx() ? 1 : 0 ) : 1870 rInf.GetIdx(); 1871 1872 if ( bSwitchL2R ) 1873 rInf.GetFrm()->SwitchLTRtoRTL( aPos ); 1874 1875 if ( bSwitchH2V ) 1876 rInf.GetFrm()->SwitchHorizontalToVertical( aPos ); 1877 1878 rInf.GetOut().DrawTextArray( aPos, *pStr, pKernArray + nOffs, 1879 nTmpIdx + nOffs , nLen - nOffs ); 1880 } 1881 } 1882 delete[] pScrArray; 1883 delete[] pKernArray; 1884 } 1885 } 1886 1887 1888 // Optimierung war fuer DrawText() ausgeschaltet 1889 #ifdef _MSC_VER 1890 #pragma optimize("",on) 1891 #endif 1892 1893 1894 /************************************************************************* 1895 * 1896 * Size SwFntObj::GetTextSize( const OutputDevice *pOut, const String &rTxt, 1897 * const sal_uInt16 nIdx, const sal_uInt16 nLen, const short nKern = 0 ); 1898 * 1899 * Ersterstellung AMA 16. Dez. 94 1900 * Letzte Aenderung AMA 16. Dez. 94 1901 * 1902 * Beschreibung: ermittelt die TextSize (des Druckers) 1903 * 1904 *************************************************************************/ 1905 1906 Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf ) 1907 { 1908 Size aTxtSize; 1909 const xub_StrLen nLn = ( STRING_LEN != rInf.GetLen() ) ? rInf.GetLen() : 1910 rInf.GetText().Len(); 1911 1912 // be sure to have the correct layout mode at the printer 1913 if ( pPrinter ) 1914 { 1915 pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() ); 1916 pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() ); 1917 } 1918 1919 if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() && 1920 SW_CJK == rInf.GetFont()->GetActual() ) 1921 { 1922 GETGRID( rInf.GetFrm()->FindPageFrm() ) 1923 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() ) 1924 { 1925 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 1926 const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc); 1927 1928 OutputDevice* pOutDev; 1929 1930 if ( pPrinter ) 1931 { 1932 if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) ) 1933 pPrinter->SetFont(*pPrtFont); 1934 pOutDev = pPrinter; 1935 } 1936 else 1937 pOutDev = rInf.GetpOut(); 1938 1939 aTxtSize.Width() = 1940 pOutDev->GetTextWidth( rInf.GetText(), rInf.GetIdx(), nLn ); 1941 1942 ASSERT( !rInf.GetShell() || 1943 ( USHRT_MAX != GetGuessedLeading() && USHRT_MAX != GetExtLeading() ), 1944 "Leading values should be already calculated" ) 1945 aTxtSize.Height() = pOutDev->GetTextHeight() + 1946 GetFontLeading( rInf.GetShell(), rInf.GetOut() ); 1947 1948 long nWidthPerChar = aTxtSize.Width() / nLn; 1949 1950 const sal_uLong i = nWidthPerChar ? 1951 ( nWidthPerChar - 1 ) / nGridWidth + 1: 1952 1; 1953 1954 aTxtSize.Width() = i * nGridWidth * nLn; 1955 rInf.SetKanaDiff( 0 ); 1956 return aTxtSize; 1957 } 1958 } 1959 1960 //for textgrid refactor 1961 if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() && 1962 SW_CJK == rInf.GetFont()->GetActual() ) 1963 { 1964 GETGRID( rInf.GetFrm()->FindPageFrm() ) 1965 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() ) 1966 { 1967 const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf ); 1968 1969 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 1970 long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc); 1971 if( SW_LATIN == rInf.GetFont()->GetActual() ) 1972 nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2; 1973 else 1974 nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight; 1975 OutputDevice* pOutDev; 1976 if ( pPrinter ) 1977 { 1978 if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) ) 1979 pPrinter->SetFont(*pPrtFont); 1980 pOutDev = pPrinter; 1981 } 1982 else 1983 pOutDev = rInf.GetpOut(); 1984 aTxtSize.Width() = pOutDev->GetTextWidth( rInf.GetText(), rInf.GetIdx(), nLn ); 1985 aTxtSize.Height() = pOutDev->GetTextHeight() + 1986 GetFontLeading( rInf.GetShell(), rInf.GetOut() ); 1987 aTxtSize.Width() += (nLn) * long( nGridWidthAdd ); 1988 //if ( rInf.GetKern() && nLn ) 1989 // aTxtSize.Width() += ( nLn ) * long( rInf.GetKern() ); 1990 1991 rInf.SetKanaDiff( 0 ); 1992 return aTxtSize; 1993 } 1994 } 1995 1996 const sal_Bool bCompress = rInf.GetKanaComp() && nLn && 1997 rInf.GetFont() && 1998 SW_CJK == rInf.GetFont()->GetActual() && 1999 rInf.GetScriptInfo() && 2000 rInf.GetScriptInfo()->CountCompChg() && 2001 lcl_IsMonoSpaceFont( rInf.GetOut() ); 2002 2003 ASSERT( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()-> 2004 CountCompChg()), "Compression without info" ); 2005 2006 // This is the part used e.g., for cursor travelling 2007 // See condition for DrawText or DrawTextArray (bDirectPrint) 2008 if ( pPrinter && pPrinter != rInf.GetpOut() ) 2009 { 2010 if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) ) 2011 pPrinter->SetFont(*pPrtFont); 2012 aTxtSize.Width() = pPrinter->GetTextWidth( rInf.GetText(), 2013 rInf.GetIdx(), nLn ); 2014 aTxtSize.Height() = pPrinter->GetTextHeight(); 2015 sal_Int32 *pKernArray = new sal_Int32[nLn]; 2016 CreateScrFont( *rInf.GetShell(), rInf.GetOut() ); 2017 if( !GetScrFont()->IsSameInstance( rInf.GetOut().GetFont() ) ) 2018 rInf.GetOut().SetFont( *pScrFont ); 2019 long nScrPos; 2020 2021 pPrinter->GetTextArray( rInf.GetText(), pKernArray, rInf.GetIdx(),nLn ); 2022 if( bCompress ) 2023 rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray, 2024 rInf.GetIdx(), nLn, rInf.GetKanaComp(), 2025 (sal_uInt16)aFont.GetSize().Height() ) ); 2026 else 2027 rInf.SetKanaDiff( 0 ); 2028 2029 if ( rInf.GetKanaDiff() ) 2030 nScrPos = pKernArray[ nLn - 1 ]; 2031 else 2032 { 2033 sal_Int32* pScrArray = new sal_Int32[ rInf.GetLen() ]; 2034 rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray, 2035 rInf.GetIdx(), rInf.GetLen() ); 2036 nScrPos = pScrArray[ 0 ]; 2037 xub_StrLen nCnt = rInf.GetText().Len(); 2038 if ( nCnt < rInf.GetIdx() ) 2039 nCnt=0; 2040 else 2041 nCnt = nCnt - rInf.GetIdx(); 2042 nCnt = Min (nCnt, nLn); 2043 xub_Unicode nChPrev = rInf.GetText().GetChar( rInf.GetIdx() ); 2044 2045 xub_Unicode nCh; 2046 2047 // Bei Pairkerning waechst der Printereinfluss auf die Positionierung 2048 sal_uInt16 nMul = 3; 2049 if ( pPrtFont->GetKerning() ) 2050 nMul = 1; 2051 const sal_uInt16 nDiv = nMul+1; 2052 for( xub_StrLen i=1; i<nCnt; i++ ) 2053 { 2054 nCh = rInf.GetText().GetChar( rInf.GetIdx() + i ); 2055 long nScr; 2056 nScr = pScrArray[ i ] - pScrArray[ i - 1 ]; 2057 if ( nCh == CH_BLANK ) 2058 nScrPos = pKernArray[i-1]+nScr; 2059 else 2060 { 2061 if ( nChPrev == CH_BLANK || nChPrev == '-' ) 2062 nScrPos = pKernArray[i-1]+nScr; 2063 else 2064 { 2065 nScrPos += nScr; 2066 nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv; 2067 } 2068 } 2069 nChPrev = nCh; 2070 pKernArray[i-1] = nScrPos - nScr; 2071 } 2072 delete[] pScrArray; 2073 } 2074 2075 delete[] pKernArray; 2076 aTxtSize.Width() = nScrPos; 2077 } 2078 else 2079 { 2080 if( !pPrtFont->IsSameInstance( rInf.GetOut().GetFont() ) ) 2081 rInf.GetOut().SetFont( *pPrtFont ); 2082 if( bCompress ) 2083 { 2084 sal_Int32 *pKernArray = new sal_Int32[nLn]; 2085 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 2086 rInf.GetIdx(), nLn ); 2087 rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray, 2088 rInf.GetIdx(), nLn, rInf.GetKanaComp(), 2089 (sal_uInt16) aFont.GetSize().Height() ) ); 2090 aTxtSize.Width() = pKernArray[ nLn - 1 ]; 2091 delete[] pKernArray; 2092 } 2093 else 2094 { 2095 aTxtSize.Width() = rInf.GetOut().GetTextWidth( rInf.GetText(), 2096 rInf.GetIdx(), nLn ); 2097 rInf.SetKanaDiff( 0 ); 2098 } 2099 2100 aTxtSize.Height() = rInf.GetOut().GetTextHeight(); 2101 } 2102 2103 if ( rInf.GetKern() && nLn ) 2104 aTxtSize.Width() += ( nLn - 1 ) * long( rInf.GetKern() ); 2105 2106 ASSERT( !rInf.GetShell() || 2107 ( USHRT_MAX != GetGuessedLeading() && USHRT_MAX != GetExtLeading() ), 2108 "Leading values should be already calculated" ) 2109 aTxtSize.Height() += GetFontLeading( rInf.GetShell(), rInf.GetOut() ); 2110 return aTxtSize; 2111 } 2112 2113 2114 xub_StrLen SwFntObj::GetCrsrOfst( SwDrawTextInfo &rInf ) 2115 { 2116 long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR; 2117 const long nSperren = -rInf.GetSperren() / SPACING_PRECISION_FACTOR; 2118 long nKern = rInf.GetKern(); 2119 2120 if( 0 != nSperren ) 2121 nKern -= nSperren; 2122 2123 sal_Int32 *pKernArray = new sal_Int32[ rInf.GetLen() ]; 2124 2125 // be sure to have the correct layout mode at the printer 2126 if ( pPrinter ) 2127 { 2128 pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() ); 2129 pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() ); 2130 pPrinter->GetTextArray( rInf.GetText(), pKernArray, 2131 rInf.GetIdx(), rInf.GetLen() ); 2132 } 2133 else 2134 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 2135 rInf.GetIdx(), rInf.GetLen() ); 2136 2137 const SwScriptInfo* pSI = rInf.GetScriptInfo(); 2138 if ( rInf.GetFont() && rInf.GetLen() ) 2139 { 2140 const sal_uInt8 nActual = rInf.GetFont()->GetActual(); 2141 2142 // Kana Compression 2143 if ( SW_CJK == nActual && rInf.GetKanaComp() && 2144 pSI && pSI->CountCompChg() && 2145 lcl_IsMonoSpaceFont( rInf.GetOut() ) ) 2146 { 2147 pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(), 2148 rInf.GetKanaComp(), 2149 (sal_uInt16) aFont.GetSize().Height() ); 2150 } 2151 2152 // Asian Justification 2153 if ( SW_CJK == rInf.GetFont()->GetActual() ) 2154 { 2155 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK ); 2156 2157 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang ) 2158 { 2159 long nSpaceSum = nSpaceAdd; 2160 for ( sal_uInt16 nI = 0; nI < rInf.GetLen(); ++nI ) 2161 { 2162 pKernArray[ nI ] += nSpaceSum; 2163 nSpaceSum += nSpaceAdd; 2164 } 2165 2166 nSpaceAdd = 0; 2167 } 2168 2169 } 2170 2171 // Kashida Justification 2172 if ( SW_CTL == nActual && rInf.GetSpace() ) 2173 { 2174 if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) 2175 { 2176 if ( pSI && pSI->CountKashida() && 2177 pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), rInf.GetLen(), 2178 nSpaceAdd ) != STRING_LEN ) 2179 nSpaceAdd = 0; 2180 } 2181 } 2182 2183 // Thai Justification 2184 if ( SW_CTL == nActual && nSpaceAdd ) 2185 { 2186 LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL ); 2187 2188 if ( LANGUAGE_THAI == aLang ) 2189 { 2190 SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray, 0, 2191 rInf.GetIdx(), rInf.GetLen(), 2192 rInf.GetNumberOfBlanks(), 2193 rInf.GetSpace() ); 2194 2195 // adding space to blanks is already done 2196 nSpaceAdd = 0; 2197 } 2198 } 2199 } 2200 2201 long nLeft = 0; 2202 long nRight = 0; 2203 xub_StrLen nCnt = 0; 2204 long nSpaceSum = 0; 2205 long nKernSum = 0; 2206 2207 if ( rInf.GetFrm() && rInf.GetLen() && rInf.SnapToGrid() && 2208 rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() ) 2209 { 2210 GETGRID( rInf.GetFrm()->FindPageFrm() ) 2211 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() ) 2212 { 2213 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 2214 const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc); 2215 2216 long nWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen(); 2217 2218 sal_uLong i = nWidthPerChar ? 2219 ( nWidthPerChar - 1 ) / nGridWidth + 1: 2220 1; 2221 2222 nWidthPerChar = i * nGridWidth; 2223 2224 nCnt = (sal_uInt16)(rInf.GetOfst() / nWidthPerChar); 2225 if ( 2 * ( rInf.GetOfst() - nCnt * nWidthPerChar ) > nWidthPerChar ) 2226 ++nCnt; 2227 2228 delete[] pKernArray; 2229 return nCnt; 2230 } 2231 } 2232 2233 //for textgrid refactor 2234 if ( rInf.GetFrm() && rInf.GetLen() && rInf.SnapToGrid() && 2235 rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() ) 2236 { 2237 GETGRID( rInf.GetFrm()->FindPageFrm() ) 2238 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() ) 2239 { 2240 2241 const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf ); 2242 2243 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 2244 long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc); 2245 if( SW_LATIN == rInf.GetFont()->GetActual() ) 2246 nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2; 2247 else 2248 nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight; 2249 2250 for(xub_StrLen j = 0; j < rInf.GetLen(); j++) 2251 { 2252 long nScr = pKernArray[ j ] + ( nSpaceAdd + nGridWidthAdd ) * ( j + 1 ); 2253 if( nScr >= rInf.GetOfst()) 2254 { 2255 nCnt = j; 2256 break; 2257 } 2258 } 2259 delete[] pKernArray; 2260 return nCnt; 2261 } 2262 } 2263 2264 sal_uInt16 nItrMode = i18n::CharacterIteratorMode::SKIPCELL; 2265 sal_Int32 nDone = 0; 2266 LanguageType aLang = LANGUAGE_NONE; 2267 bool bSkipCharacterCells = false; 2268 xub_StrLen nIdx = rInf.GetIdx(); 2269 xub_StrLen nLastIdx = nIdx; 2270 const xub_StrLen nEnd = rInf.GetIdx() + rInf.GetLen(); 2271 2272 // --> OD 2009-12-29 #i105901# 2273 // skip character cells for all script types 2274 if ( pBreakIt->GetBreakIter().is() ) 2275 // <-- 2276 { 2277 aLang = rInf.GetFont()->GetLanguage(); 2278 bSkipCharacterCells = true; 2279 } 2280 2281 while ( ( nRight < long( rInf.GetOfst() ) ) && ( nIdx < nEnd ) ) 2282 { 2283 if ( nSpaceAdd && CH_BLANK == rInf.GetText().GetChar( nIdx ) ) 2284 nSpaceSum += nSpaceAdd; 2285 2286 // go to next character (cell). 2287 nLastIdx = nIdx; 2288 2289 if ( bSkipCharacterCells ) 2290 { 2291 nIdx = (xub_StrLen)pBreakIt->GetBreakIter()->nextCharacters( rInf.GetText(), 2292 nIdx, pBreakIt->GetLocale( aLang ), nItrMode, 1, nDone ); 2293 if ( nIdx <= nLastIdx ) 2294 break; 2295 } 2296 else 2297 ++nIdx; 2298 2299 nLeft = nRight; 2300 nRight = pKernArray[ nIdx - rInf.GetIdx() - 1 ] + nKernSum + nSpaceSum; 2301 2302 nKernSum += nKern; 2303 } 2304 2305 // step back if position is before the middle of the character 2306 // or if we do not want to go to the next character 2307 if ( nIdx > rInf.GetIdx() && 2308 ( rInf.IsPosMatchesBounds() || 2309 ( ( nRight > long( rInf.GetOfst() ) ) && 2310 ( nRight - rInf.GetOfst() > rInf.GetOfst() - nLeft ) ) ) ) 2311 nCnt = nLastIdx - rInf.GetIdx(); // first half 2312 else 2313 nCnt = nIdx - rInf.GetIdx(); // second half 2314 2315 if ( pSI ) 2316 rInf.SetCursorBidiLevel( pSI->DirType( nLastIdx ) ); 2317 2318 delete[] pKernArray; 2319 return nCnt; 2320 } 2321 2322 2323 /************************************************************************* 2324 |* 2325 |* SwFntAccess::SwFntAccess() 2326 |* 2327 |* Ersterstellung AMA 9. Nov. 94 2328 |* Letzte Aenderung AMA 9. Nov. 94 2329 |* 2330 |*************************************************************************/ 2331 2332 SwFntAccess::SwFntAccess( const void* &rMagic, 2333 sal_uInt16 &rIndex, const void *pOwn, ViewShell *pSh, 2334 sal_Bool bCheck ) : 2335 SwCacheAccess( *pFntCache, rMagic, rIndex ), 2336 pShell( pSh ) 2337 { 2338 // Der benutzte CTor von SwCacheAccess sucht anhand rMagic+rIndex im Cache 2339 if ( IsAvail() ) 2340 { 2341 // Der schnellste Fall: ein bekannter Font ( rMagic ), 2342 // bei dem Drucker und Zoom nicht ueberprueft werden brauchen. 2343 if ( !bCheck ) 2344 return; 2345 2346 // Hier ist zwar der Font bekannt, muss aber noch ueberprueft werden. 2347 2348 } 2349 else 2350 // Hier ist der Font nicht bekannt, muss also gesucht werden. 2351 bCheck = sal_False; 2352 2353 2354 { 2355 OutputDevice* pOut = 0; 2356 sal_uInt16 nZoom = USHRT_MAX; 2357 2358 // Get the reference device 2359 if ( pSh ) 2360 { 2361 pOut = &pSh->GetRefDev(); 2362 nZoom = pSh->GetViewOptions()->GetZoom(); 2363 } 2364 2365 SwFntObj *pFntObj; 2366 if ( bCheck ) 2367 { 2368 pFntObj = Get(); 2369 if ( ( pFntObj->GetZoom( ) == nZoom ) && 2370 ( pFntObj->pPrinter == pOut ) && 2371 pFntObj->GetPropWidth() == 2372 ((SwSubFont*)pOwn)->GetPropWidth() ) 2373 return; // Die Ueberpruefung ergab: Drucker+Zoom okay. 2374 pFntObj->Unlock( ); // Vergiss dies Objekt, es wurde leider 2375 pObj = NULL; // eine Drucker/Zoomaenderung festgestellt. 2376 } 2377 2378 // Search by font comparison, quite expensive! 2379 // Look for same font and same printer 2380 pFntObj = pFntCache->First(); 2381 while ( pFntObj && !( pFntObj->aFont == *(Font *)pOwn && 2382 pFntObj->GetZoom() == nZoom && 2383 pFntObj->GetPropWidth() == 2384 ((SwSubFont*)pOwn)->GetPropWidth() && 2385 ( !pFntObj->pPrinter || pFntObj->pPrinter == pOut ) ) ) 2386 pFntObj = pFntCache->Next( pFntObj ); 2387 2388 if( pFntObj && pFntObj->pPrinter != pOut ) 2389 { 2390 // Wir haben zwar einen ohne Drucker gefunden, mal sehen, ob es 2391 // auch noch einen mit identischem Drucker gibt. 2392 SwFntObj *pTmpObj = pFntObj; 2393 while( pTmpObj && !( pTmpObj->aFont == *(Font *)pOwn && 2394 pTmpObj->GetZoom()==nZoom && pTmpObj->pPrinter==pOut && 2395 pTmpObj->GetPropWidth() == 2396 ((SwSubFont*)pOwn)->GetPropWidth() ) ) 2397 pTmpObj = pFntCache->Next( pTmpObj ); 2398 if( pTmpObj ) 2399 pFntObj = pTmpObj; 2400 } 2401 2402 if ( !pFntObj ) // Font has not been found, create one 2403 { 2404 // Das Objekt muss neu angelegt werden, deshalb muss der Owner ein 2405 // SwFont sein, spaeter wird als Owner die "MagicNumber" gehalten. 2406 SwCacheAccess::pOwner = pOwn; 2407 pFntObj = Get(); // hier wird via NewObj() angelegt und gelockt. 2408 ASSERT(pFntObj, "No Font, no Fun."); 2409 } 2410 else // Font has been found, so we lock it. 2411 { 2412 pFntObj->Lock(); 2413 if( pFntObj->pPrinter != pOut ) // Falls bis dato kein Drucker bekannt 2414 { 2415 ASSERT( !pFntObj->pPrinter, "SwFntAccess: Printer Changed" ); 2416 pFntObj->CreatePrtFont( *pOut ); 2417 pFntObj->pPrinter = pOut; 2418 pFntObj->pScrFont = NULL; 2419 pFntObj->nGuessedLeading = USHRT_MAX; 2420 pFntObj->nExtLeading = USHRT_MAX; 2421 pFntObj->nPrtAscent = USHRT_MAX; 2422 pFntObj->nPrtHeight = USHRT_MAX; 2423 } 2424 pObj = pFntObj; 2425 } 2426 2427 // egal, ob neu oder gefunden, ab jetzt ist der Owner vom Objekt eine 2428 // MagicNumber und wird auch dem aufrufenden SwFont bekanntgegeben, 2429 // ebenso der Index fuer spaetere direkte Zugriffe 2430 rMagic = pFntObj->GetOwner(); 2431 SwCacheAccess::pOwner = rMagic; 2432 rIndex = pFntObj->GetCachePos(); 2433 } 2434 } 2435 2436 SwCacheObj *SwFntAccess::NewObj( ) 2437 { 2438 // Ein neuer Font, eine neue "MagicNumber". 2439 return new SwFntObj( *(SwSubFont *)pOwner, ++pMagicNo, pShell ); 2440 } 2441 2442 extern xub_StrLen lcl_CalcCaseMap( const SwFont& rFnt, 2443 const XubString& rOrigString, 2444 xub_StrLen nOfst, 2445 xub_StrLen nLen, 2446 xub_StrLen nIdx ); 2447 2448 xub_StrLen SwFont::GetTxtBreak( SwDrawTextInfo& rInf, long nTextWidth ) 2449 { 2450 ChgFnt( rInf.GetShell(), rInf.GetOut() ); 2451 2452 const sal_Bool bCompress = rInf.GetKanaComp() && rInf.GetLen() && 2453 SW_CJK == GetActual() && 2454 rInf.GetScriptInfo() && 2455 rInf.GetScriptInfo()->CountCompChg() && 2456 lcl_IsMonoSpaceFont( rInf.GetOut() ); 2457 2458 ASSERT( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()-> 2459 CountCompChg()), "Compression without info" ); 2460 2461 sal_uInt16 nTxtBreak = 0; 2462 long nKern = 0; 2463 2464 sal_uInt16 nLn = ( rInf.GetLen() == STRING_LEN ? rInf.GetText().Len() 2465 : rInf.GetLen() ); 2466 2467 if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && 2468 rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() ) 2469 { 2470 GETGRID( rInf.GetFrm()->FindPageFrm() ) 2471 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() ) 2472 { 2473 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 2474 const sal_uInt16 nGridWidth = GETGRIDWIDTH(pGrid, pDoc); 2475 2476 sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()]; 2477 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 2478 rInf.GetIdx(), rInf.GetLen() ); 2479 2480 long nWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen(); 2481 2482 const sal_uLong i = nWidthPerChar ? 2483 ( nWidthPerChar - 1 ) / nGridWidth + 1: 2484 1; 2485 2486 nWidthPerChar = i * nGridWidth; 2487 long nCurrPos = nWidthPerChar; 2488 2489 while( nTxtBreak < rInf.GetLen() && nTextWidth >= nCurrPos ) 2490 { 2491 nCurrPos += nWidthPerChar; 2492 ++nTxtBreak; 2493 } 2494 2495 delete[] pKernArray; 2496 return nTxtBreak + rInf.GetIdx(); 2497 } 2498 } 2499 2500 //for text grid enhancement 2501 if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() && 2502 SW_CJK == rInf.GetFont()->GetActual() ) 2503 { 2504 GETGRID( rInf.GetFrm()->FindPageFrm() ) 2505 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() ) 2506 { 2507 const sal_uInt16 nDefaultFontHeight = GetDefaultFontHeight( rInf ); 2508 2509 const SwDoc* pDoc = rInf.GetShell()->GetDoc(); 2510 long nGridWidthAdd = GETGRIDWIDTH(pGrid, pDoc); 2511 if( SW_LATIN == rInf.GetFont()->GetActual() ) 2512 nGridWidthAdd = ( nGridWidthAdd - nDefaultFontHeight ) / 2 ; 2513 else 2514 nGridWidthAdd = nGridWidthAdd - nDefaultFontHeight; 2515 2516 sal_Int32* pKernArray = new sal_Int32[rInf.GetLen()]; 2517 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 2518 rInf.GetIdx(), rInf.GetLen() ); 2519 long nCurrPos = pKernArray[nTxtBreak] + nGridWidthAdd; 2520 while( nTxtBreak < rInf.GetLen() && nTextWidth >= nCurrPos) 2521 { 2522 nTxtBreak++; 2523 nCurrPos = pKernArray[nTxtBreak] + nGridWidthAdd * ( nTxtBreak + 1 ); 2524 } 2525 delete[] pKernArray; 2526 return nTxtBreak + rInf.GetIdx(); 2527 } 2528 } 2529 2530 if( aSub[nActual].IsCapital() && nLn ) 2531 nTxtBreak = GetCapitalBreak( rInf.GetShell(), rInf.GetpOut(), 2532 rInf.GetScriptInfo(), rInf.GetText(), nTextWidth,0, rInf.GetIdx(),nLn ); 2533 else 2534 { 2535 nKern = CheckKerning(); 2536 2537 const XubString* pTmpText; 2538 XubString aTmpText; 2539 xub_StrLen nTmpIdx; 2540 xub_StrLen nTmpLen; 2541 bool bTextReplaced = false; 2542 2543 if ( !aSub[nActual].IsCaseMap() ) 2544 { 2545 pTmpText = &rInf.GetText(); 2546 nTmpIdx = rInf.GetIdx(); 2547 nTmpLen = nLn; 2548 } 2549 else 2550 { 2551 const XubString aSnippet( rInf.GetText(), rInf.GetIdx(), nLn ); 2552 aTmpText = aSub[nActual].CalcCaseMap( aSnippet ); 2553 const bool bTitle = SVX_CASEMAP_TITEL == aSub[nActual].GetCaseMap() && 2554 pBreakIt->GetBreakIter().is(); 2555 2556 // Uaaaaahhhh!!! In title case mode, we would get wrong results 2557 if ( bTitle && nLn ) 2558 { 2559 // check if rInf.GetIdx() is begin of word 2560 if ( !pBreakIt->GetBreakIter()->isBeginWord( 2561 rInf.GetText(), rInf.GetIdx(), 2562 pBreakIt->GetLocale( aSub[nActual].GetLanguage() ), 2563 i18n::WordType::ANYWORD_IGNOREWHITESPACES ) ) 2564 { 2565 // In this case, the beginning of aTmpText is wrong. 2566 XubString aSnippetTmp( aSnippet, 0, 1 ); 2567 aSnippetTmp = aSub[nActual].CalcCaseMap( aSnippetTmp ); 2568 aTmpText.Erase( 0, aSnippetTmp.Len() ); 2569 aTmpText.Insert( aSnippet.GetChar( 0 ), 0 ); 2570 } 2571 } 2572 2573 pTmpText = &aTmpText; 2574 nTmpIdx = 0; 2575 nTmpLen = aTmpText.Len(); 2576 bTextReplaced = true; 2577 } 2578 2579 if( rInf.GetHyphPos() ) 2580 nTxtBreak = rInf.GetOut().GetTextBreak( *pTmpText, nTextWidth, 2581 '-', *rInf.GetHyphPos(), 2582 nTmpIdx, nTmpLen, nKern ); 2583 else 2584 nTxtBreak = rInf.GetOut().GetTextBreak( *pTmpText, nTextWidth, 2585 nTmpIdx, nTmpLen, nKern ); 2586 2587 if ( bTextReplaced && STRING_LEN != nTxtBreak ) 2588 { 2589 if ( nTmpLen != nLn ) 2590 nTxtBreak = lcl_CalcCaseMap( *this, rInf.GetText(), 2591 rInf.GetIdx(), nLn, nTxtBreak ); 2592 else 2593 nTxtBreak = nTxtBreak + rInf.GetIdx(); 2594 } 2595 } 2596 2597 if ( ! bCompress ) 2598 return nTxtBreak; 2599 2600 nTxtBreak = nTxtBreak - rInf.GetIdx(); 2601 2602 if( nTxtBreak < nLn ) 2603 { 2604 if( !nTxtBreak && nLn ) 2605 nLn = 1; 2606 else if( nLn > 2 * nTxtBreak ) 2607 nLn = 2 * nTxtBreak; 2608 sal_Int32 *pKernArray = new sal_Int32[ nLn ]; 2609 rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray, 2610 rInf.GetIdx(), nLn ); 2611 if( rInf.GetScriptInfo()->Compress( pKernArray, rInf.GetIdx(), nLn, 2612 rInf.GetKanaComp(), (sal_uInt16)GetHeight( nActual ) ) ) 2613 { 2614 long nKernAdd = nKern; 2615 xub_StrLen nTmpBreak = nTxtBreak; 2616 if( nKern && nTxtBreak ) 2617 nKern *= nTxtBreak - 1; 2618 while( nTxtBreak<nLn && nTextWidth >= pKernArray[nTxtBreak] +nKern ) 2619 { 2620 nKern += nKernAdd; 2621 ++nTxtBreak; 2622 } 2623 if( rInf.GetHyphPos() ) 2624 *rInf.GetHyphPos() += nTxtBreak - nTmpBreak; // It's not perfect 2625 } 2626 delete[] pKernArray; 2627 } 2628 nTxtBreak = nTxtBreak + rInf.GetIdx(); 2629 2630 return nTxtBreak; 2631 } 2632 2633 extern Color aGlobalRetoucheColor; 2634 2635 sal_Bool SwDrawTextInfo::ApplyAutoColor( Font* pFont ) 2636 { 2637 const Font& rFnt = pFont ? *pFont : GetOut().GetFont(); 2638 sal_Bool bPrt = GetShell() && ! GetShell()->GetWin(); 2639 ColorData nNewColor = COL_BLACK; 2640 sal_Bool bChgFntColor = sal_False; 2641 sal_Bool bChgLineColor = sal_False; 2642 2643 if( bPrt && GetShell() && GetShell()->GetViewOptions()->IsBlackFont() ) 2644 { 2645 if ( COL_BLACK != rFnt.GetColor().GetColor() ) 2646 bChgFntColor = sal_True; 2647 2648 if ( (COL_BLACK != GetOut().GetLineColor().GetColor()) || 2649 (COL_BLACK != GetOut().GetOverlineColor().GetColor()) ) 2650 bChgLineColor = sal_True; 2651 } 2652 else 2653 { 2654 // FontColor has to be changed if: 2655 // 1. FontColor = AUTO or 2. IsAlwaysAutoColor is set 2656 // LineColor has to be changed if: 2657 // 1. IsAlwaysAutoColor is set 2658 2659 bChgLineColor = ! bPrt && GetShell() && 2660 GetShell()->GetAccessibilityOptions()->IsAlwaysAutoColor(); 2661 2662 bChgFntColor = COL_AUTO == rFnt.GetColor().GetColor() || bChgLineColor; 2663 2664 if ( bChgFntColor ) 2665 { 2666 // check if current background has a user defined setting 2667 const Color* pCol = GetFont() ? GetFont()->GetBackColor() : NULL; 2668 if( ! pCol || COL_TRANSPARENT == pCol->GetColor() ) 2669 { 2670 const SvxBrushItem* pItem; 2671 SwRect aOrigBackRect; 2672 2673 //UUUU 2674 FillAttributesPtr aFillAttributes; 2675 2676 /// OD 21.08.2002 2677 /// consider, that [GetBackgroundBrush(...)] can set <pCol> 2678 /// - see implementation in /core/layout/paintfrm.cxx 2679 /// OD 21.08.2002 #99657# 2680 /// There is a user defined setting for the background, if there 2681 /// is a background brush and its color is *not* "no fill"/"auto fill". 2682 if( GetFrm()->GetBackgroundBrush( aFillAttributes, pItem, pCol, aOrigBackRect, sal_False ) ) 2683 { 2684 if ( !pCol ) 2685 { 2686 pCol = &pItem->GetColor(); 2687 } 2688 2689 /// OD 30.08.2002 #99657# 2690 /// determined color <pCol> can be <COL_TRANSPARENT>. Thus, check it. 2691 if ( pCol->GetColor() == COL_TRANSPARENT) 2692 pCol = NULL; 2693 } 2694 else 2695 pCol = NULL; 2696 } 2697 2698 // no user defined color at paragraph or font background 2699 if ( ! pCol ) 2700 pCol = &aGlobalRetoucheColor; 2701 2702 if( GetShell() && GetShell()->GetWin() ) 2703 { 2704 // here we determine the prefered window text color for painting 2705 const SwViewOption* pViewOption = GetShell()->GetViewOptions(); 2706 if(pViewOption->IsPagePreview() && 2707 !SW_MOD()->GetAccessibilityOptions().GetIsForPagePreviews()) 2708 nNewColor = COL_BLACK; 2709 else 2710 // we take the font color from the appearence page 2711 nNewColor = SwViewOption::GetFontColor().GetColor(); 2712 } 2713 2714 // change painting color depending of dark/bright background 2715 Color aTmpColor( nNewColor ); 2716 if ( pCol->IsDark() && aTmpColor.IsDark() ) 2717 nNewColor = COL_WHITE; 2718 else if ( pCol->IsBright() && aTmpColor.IsBright() ) 2719 nNewColor = COL_BLACK; 2720 } 2721 } 2722 2723 if ( bChgFntColor || bChgLineColor ) 2724 { 2725 Color aNewColor( nNewColor ); 2726 2727 if ( bChgFntColor ) 2728 { 2729 if ( pFont && aNewColor != pFont->GetColor() ) 2730 { 2731 // only set the new color at the font passed as argument 2732 pFont->SetColor( aNewColor ); 2733 } 2734 else if ( aNewColor != GetOut().GetFont().GetColor() ) 2735 { 2736 // set new font with new color at output device 2737 Font aFont( rFnt ); 2738 aFont.SetColor( aNewColor ); 2739 GetOut().SetFont( aFont ); 2740 } 2741 } 2742 2743 // the underline and overline colors have to be set separately 2744 if ( bChgLineColor ) 2745 { 2746 // get current font color or color set at output device 2747 aNewColor = pFont ? pFont->GetColor() : GetOut().GetFont().GetColor(); 2748 if ( aNewColor != GetOut().GetLineColor() ) 2749 GetOut().SetLineColor( aNewColor ); 2750 if ( aNewColor != GetOut().GetOverlineColor() ) 2751 GetOut().SetOverlineColor( aNewColor ); 2752 } 2753 2754 return sal_True; 2755 } 2756 2757 return sal_False; 2758 } 2759 2760