1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 #include <math.h> 32 33 #include "psputil.hxx" 34 #include "glyphset.hxx" 35 36 #include "printergfx.hxx" 37 #include "vcl/fontmanager.hxx" 38 #include "vcl/helper.hxx" 39 40 #include "osl/thread.h" 41 42 #include "sal/alloca.h" 43 44 using namespace psp ; 45 46 namespace psp { 47 /* 48 container for a font and its helper fonts: 49 1st font is the font substitute e.g. helvetica substitutes arial on the printer 50 2nd is the font itself 51 3rd is a fallback font, usually a font with unicode glyph repertoir (e.g. andale) 52 symbol fonts (adobe-fontspecific) may need special glyphmapping 53 (symbol page vc. latin page) 54 */ 55 class Font3 56 { 57 private: 58 59 #define Font3Size 3 60 61 fontID mpFont [Font3Size]; 62 bool mbSymbol; 63 64 public: 65 66 fontID GetFont (int nIdx) const 67 { return nIdx < Font3Size ? mpFont[nIdx] : -1 ; } 68 bool IsSymbolFont () const 69 { return mbSymbol; } 70 71 Font3 (const PrinterGfx &rGfx); 72 ~Font3 () {} 73 }; 74 75 Font3::Font3(const PrinterGfx &rGfx) 76 { 77 mpFont[0] = rGfx.getFontSubstitute(); 78 mpFont[1] = rGfx.GetFontID(); 79 mpFont[2] = rGfx.getFallbackID(); 80 // mpFont[2] = rGfx.GetFontID(); 81 82 PrintFontManager &rMgr = PrintFontManager::get(); 83 mbSymbol = mpFont[1] != -1 ? 84 rMgr.getFontEncoding(mpFont[1]) == RTL_TEXTENCODING_SYMBOL : false; 85 } 86 87 } // namespace psp 88 89 static int getVerticalDeltaAngle( sal_Unicode nChar ) 90 { 91 int nAngle = 0; 92 if( ( nChar >= 0x1100 && nChar < 0x11fa ) || 93 ( nChar >= 0x3000 && nChar < 0xfb00 ) || 94 ( nChar >= 0xfe20 && nChar < 0xfe70 ) || 95 ( nChar >= 0xff00 && nChar < 0xff64 ) 96 ) 97 { 98 /* #i52932# remember: 99 nChar == 0x2010 || nChar == 0x2015 100 nChar == 0x2016 || nChar == 0x2026 101 102 are nAngle = 0 also, but already handled in the first if 103 */ 104 if( ( nChar >= 0x3008 && nChar < 0x3019 && nChar != 0x3012 ) || 105 nChar == 0xff3b || nChar == 0xff3d || 106 (nChar >= 0xff6b && nChar < 0xff64 ) || 107 nChar == 0xffe3 108 ) 109 nAngle = 0; 110 else if( nChar == 0x30fc ) 111 nAngle = -900; 112 else 113 nAngle = 900; 114 } 115 return nAngle; 116 } 117 118 void 119 PrinterGfx::PSUploadPS1Font (sal_Int32 nFontID) 120 { 121 std::list< sal_Int32 >::iterator aFont; 122 // already in the document header ? 123 for (aFont = maPS1Font.begin(); aFont != maPS1Font.end(); ++aFont ) 124 if( nFontID == *aFont ) 125 return; 126 127 // no occurrenc yet, mark for download 128 // add the fontid to the list 129 maPS1Font.push_back (nFontID); 130 } 131 132 /* 133 * implement text handling printer routines, 134 */ 135 136 sal_uInt16 137 PrinterGfx::SetFont( 138 sal_Int32 nFontID, 139 sal_Int32 nHeight, 140 sal_Int32 nWidth, 141 sal_Int32 nAngle, 142 bool bVertical, 143 bool bArtItalic, 144 bool bArtBold 145 ) 146 { 147 // font and encoding will be set by drawText again immediately 148 // before PSShowText 149 mnFontID = nFontID; 150 maVirtualStatus.maFont = rtl::OString(); 151 maVirtualStatus.maEncoding = RTL_TEXTENCODING_DONTKNOW; 152 maVirtualStatus.mnTextHeight = nHeight; 153 maVirtualStatus.mnTextWidth = nWidth; 154 maVirtualStatus.mbArtItalic = bArtItalic; 155 maVirtualStatus.mbArtBold = bArtBold; 156 mnTextAngle = nAngle; 157 mbTextVertical = bVertical; 158 159 return 0; 160 } 161 162 sal_uInt16 163 PrinterGfx::SetFallbackFont ( sal_Int32 nFontID ) 164 { 165 mnFallbackID = nFontID; 166 return 0; 167 } 168 169 void PrinterGfx::drawGlyphs( 170 const Point& rPoint, 171 sal_uInt32* pGlyphIds, 172 sal_Unicode* pUnicodes, 173 sal_Int16 nLen, 174 sal_Int32* pDeltaArray 175 ) 176 { 177 178 // draw the string 179 // search for a glyph set matching the set font 180 std::list< GlyphSet >::iterator aIter; 181 for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); aIter++) 182 if ( ((*aIter).GetFontID() == mnFontID) 183 && ((*aIter).IsVertical() == mbTextVertical)) 184 { 185 (*aIter).DrawGlyphs (*this, rPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray); 186 break; 187 } 188 189 // not found ? create a new one 190 if (aIter == maPS3Font.end()) 191 { 192 maPS3Font.push_back (GlyphSet(mnFontID, mbTextVertical)); 193 maPS3Font.back().DrawGlyphs (*this, rPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray); 194 } 195 } 196 197 void PrinterGfx::DrawGlyphs( 198 const Point& rPoint, 199 sal_GlyphId* pGlyphIds, 200 sal_Unicode* pUnicodes, 201 sal_Int16 nLen, 202 sal_Int32* pDeltaArray 203 ) 204 { 205 if( nLen <= 0 ) 206 return; 207 208 if ( !mrFontMgr.isFontDownloadingAllowed( mnFontID ) ) 209 { 210 LicenseWarning(rPoint, pUnicodes, nLen, pDeltaArray); 211 return; 212 } 213 214 if( mrFontMgr.getFontType( mnFontID ) != fonttype::TrueType ) 215 { 216 DrawText( rPoint, pUnicodes, nLen, pDeltaArray ); 217 return; 218 } 219 220 // move and rotate the user coordinate system 221 // avoid the gsave/grestore for the simple cases since it allows 222 // reuse of the current font if it hasn't changed 223 sal_Int32 nCurrentTextAngle = mnTextAngle; 224 Point aPoint( rPoint ); 225 226 if (nCurrentTextAngle != 0) 227 { 228 PSGSave (); 229 PSTranslate (rPoint); 230 PSRotate (nCurrentTextAngle); 231 mnTextAngle = 0; 232 aPoint = Point( 0, 0 ); 233 } 234 235 if( mbTextVertical ) 236 { 237 // vertical glyphs can have an additional rotation ... sigh. 238 // so break up text in chunks of normal glyphs and print out 239 // specially rotated glyphs extra 240 sal_uInt32* pTempGlyphIds = (sal_uInt32*)alloca(sizeof(sal_Int32)*nLen); 241 sal_Int32* pTempDelta = (sal_Int32*)alloca(sizeof(sal_Int32)*nLen); 242 sal_Unicode* pTempUnicodes = (sal_Unicode*)alloca(sizeof(sal_Unicode)*nLen); 243 sal_Int16 nTempLen = 0; 244 sal_Int32 nTempFirstDelta = 0; 245 Point aRotPoint; 246 sal_Int32 nTextHeight = maVirtualStatus.mnTextHeight; 247 sal_Int32 nTextWidth = maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight; 248 sal_Int32 nAscend = mrFontMgr.getFontAscend( mnFontID ); 249 sal_Int32 nDescend = mrFontMgr.getFontDescend( mnFontID ); 250 251 nDescend = nDescend * nTextHeight / 1000; 252 nAscend = nAscend * nTextHeight / 1000; 253 254 for( sal_Int16 i = 0; i < nLen; i++ ) 255 { 256 const sal_GlyphId nRot = pGlyphIds[i] & GF_ROTMASK; 257 if( nRot == GF_NONE ) 258 { 259 pTempUnicodes[nTempLen] = pUnicodes[i]; 260 pTempGlyphIds[nTempLen] = pGlyphIds[i]; 261 if( nTempLen > 0 ) 262 pTempDelta[nTempLen-1] = pDeltaArray[i-1]-nTempFirstDelta; 263 else 264 { 265 // the first element in pDeltaArray shows 266 // the offset of the second character 267 // so if the first glyph is normal 268 // then we do not need to move the delta indices 269 // else we have to move them down by one and 270 // recalculate aPoint and all deltas 271 if( i != 0 ) 272 nTempFirstDelta = pDeltaArray[ i-1 ]; 273 } 274 nTempLen++; 275 } 276 else 277 { 278 sal_Int32 nOffset = i > 0 ? pDeltaArray[i-1] : 0; 279 sal_Int32 nRotAngle = 0; 280 switch( nRot ) 281 { 282 case GF_ROTR: 283 nRotAngle = 2700; 284 aRotPoint = Point( -nAscend*nTextWidth/nTextHeight, -nDescend*nTextWidth/nTextHeight - nOffset ); 285 break; 286 case GF_VERT: 287 nRotAngle = 1800; 288 aRotPoint = Point( -nOffset, (nAscend+nDescend) ); 289 break; 290 case GF_ROTL: 291 nRotAngle = 900; 292 aRotPoint = Point( -nDescend*nTextWidth/nTextHeight, nOffset + nAscend*nTextWidth/nTextHeight ); 293 break; 294 } 295 sal_GlyphId nRotGlyphId = pGlyphIds[i]; 296 sal_Unicode nRotUnicode = pUnicodes[i]; 297 sal_Int32 nRotDelta = 0; 298 299 // transform matrix to new individual direction 300 PSGSave (); 301 GraphicsStatus aSaveStatus = maVirtualStatus; 302 if( nRot != 2 ) // switch font aspect 303 { 304 maVirtualStatus.mnTextWidth = nTextHeight; 305 maVirtualStatus.mnTextHeight = nTextWidth; 306 } 307 if( aPoint.X() || aPoint.Y() ) 308 PSTranslate( aPoint ); 309 PSRotate (nRotAngle); 310 // draw the rotated glyph 311 drawGlyphs( aRotPoint, &nRotGlyphId, &nRotUnicode, 1, &nRotDelta ); 312 313 // restore previous state 314 maVirtualStatus = aSaveStatus; 315 PSGRestore(); 316 } 317 } 318 319 pGlyphIds = pTempGlyphIds; 320 pUnicodes = pTempUnicodes; 321 pDeltaArray = pTempDelta; 322 nLen = nTempLen; 323 324 aPoint.X() += nTempFirstDelta; 325 } 326 327 if( nLen > 0 ) 328 drawGlyphs( aPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray ); 329 330 // restore the user coordinate system 331 if (nCurrentTextAngle != 0) 332 { 333 PSGRestore (); 334 mnTextAngle = nCurrentTextAngle; 335 } 336 } 337 338 void 339 PrinterGfx::DrawText ( 340 const Point& rPoint, 341 const sal_Unicode* pStr, 342 sal_Int16 nLen, 343 const sal_Int32* pDeltaArray 344 ) 345 { 346 fontID nRestoreFont = mnFontID; 347 348 // setup font[substitutes] and map the string into the symbol area in case of 349 // symbol font 350 Font3 aFont(*this); 351 sal_Unicode *pEffectiveStr; 352 if ( aFont.IsSymbolFont() ) 353 { 354 pEffectiveStr = (sal_Unicode*)alloca(nLen * sizeof(pStr[0])); 355 for (int i = 0; i < nLen; i++) 356 pEffectiveStr[i] = pStr[i] < 256 ? pStr[i] + 0xF000 : pStr[i]; 357 } 358 else 359 { 360 pEffectiveStr = const_cast<sal_Unicode*>(pStr); 361 } 362 363 fontID *pFontMap = (fontID*) alloca(nLen * sizeof(fontID)); 364 sal_Int32 *pCharWidth = (sal_Int32*) alloca(nLen * sizeof(sal_Int32)); 365 366 for( int n = 0; n < nLen; n++ ) 367 { 368 CharacterMetric aBBox; 369 pFontMap[n] = getCharMetric (aFont, pEffectiveStr[n], &aBBox); 370 pCharWidth[n] = getCharWidth (mbTextVertical, pEffectiveStr[n], &aBBox); 371 } 372 373 // setup a new delta array, use virtual resolution of 1000 374 sal_Int32* pNewDeltaArray = (sal_Int32*)alloca( sizeof( sal_Int32 )*nLen ); 375 if ( pDeltaArray != 0) 376 { 377 for (int i = 0; i < nLen - 1; i++) 378 pNewDeltaArray[i] = 1000 * pDeltaArray[i]; 379 pNewDeltaArray[nLen - 1] = 0; 380 } 381 else 382 { 383 pNewDeltaArray[0] = pCharWidth[0]; 384 for (int i = 1; i < nLen; i++) 385 pNewDeltaArray[i] = pNewDeltaArray[i-1] + pCharWidth[i]; 386 } 387 388 // move and rotate the user coordinate system 389 // avoid the gsave/grestore for the simple cases since it allows 390 // reuse of the current font if it hasn't changed 391 sal_Int32 nCurrentTextAngle = mnTextAngle; 392 sal_Int32 nCurrentPointX; 393 sal_Int32 nCurrentPointY; 394 395 if (nCurrentTextAngle != 0) 396 { 397 PSGSave (); 398 PSTranslate (rPoint); 399 PSRotate (nCurrentTextAngle); 400 mnTextAngle = 0; 401 402 nCurrentPointX = 0; 403 nCurrentPointY = 0; 404 } 405 else 406 { 407 nCurrentPointX = rPoint.X(); 408 nCurrentPointY = rPoint.Y(); 409 } 410 411 // draw the string 412 sal_Int32 nDelta = 0; 413 for (int nTo = 0; nTo < nLen; ) 414 { 415 int nFrom = nTo; 416 fontID nFont = pFontMap[ nFrom ]; 417 418 while ((nTo < nLen) && (nFont == pFontMap[nTo])) 419 { 420 pNewDeltaArray[ nTo ] = (sal_Int32)(((0.5 + pNewDeltaArray[ nTo ]) / 1000.0) - nDelta); 421 nTo++ ; 422 } 423 424 SetFont( nFont, 425 maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth, 426 mnTextAngle, 427 mbTextVertical, 428 maVirtualStatus.mbArtItalic, 429 maVirtualStatus.mbArtBold 430 ); 431 432 if (mbTextVertical) 433 { 434 drawVerticalizedText( 435 Point(nCurrentPointX + nDelta, nCurrentPointY), 436 pEffectiveStr + nFrom, nTo - nFrom, 437 pNewDeltaArray + nFrom ); 438 } 439 else 440 { 441 drawText( 442 Point(nCurrentPointX + nDelta, nCurrentPointY), 443 pEffectiveStr + nFrom, nTo - nFrom, 444 pDeltaArray == NULL ? NULL : pNewDeltaArray + nFrom ); 445 } 446 nDelta += pNewDeltaArray[ nTo - 1 ]; 447 } 448 449 // restore the user coordinate system 450 if (nCurrentTextAngle != 0) 451 { 452 PSGRestore (); 453 mnTextAngle = nCurrentTextAngle; 454 } 455 456 // restore the original font settings 457 SetFont( nRestoreFont, 458 maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth, 459 mnTextAngle, mbTextVertical, 460 maVirtualStatus.mbArtItalic, 461 maVirtualStatus.mbArtBold 462 ); 463 } 464 465 void PrinterGfx::drawVerticalizedText( 466 const Point& rPoint, 467 const sal_Unicode* pStr, 468 sal_Int16 nLen, 469 const sal_Int32* pDeltaArray 470 ) 471 { 472 sal_Int32* pDelta = (sal_Int32*)alloca( nLen * sizeof(sal_Int32) ); 473 474 int nTextScale = maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight; 475 int nNormalAngle = mnTextAngle; 476 int nDeltaAngle, nLastPos = 0; 477 478 double fSin = sin( -2.0*M_PI*nNormalAngle/3600 ); 479 double fCos = cos( -2.0*M_PI*nNormalAngle/3600 ); 480 481 PrintFontManager &rMgr = PrintFontManager::get(); 482 PrintFontInfo aInfo; 483 rMgr.getFontInfo( mnFontID, aInfo ); 484 485 bool* pGsubFlags = (bool*)alloca( nLen * sizeof(bool) ); 486 rMgr.hasVerticalSubstitutions( mnFontID, pStr, nLen, pGsubFlags ); 487 488 Point aPoint( rPoint ); 489 for( int i = 0; i < nLen; ) 490 { 491 while( ( nDeltaAngle = getVerticalDeltaAngle( pStr[i] ) ) == 0 && i < nLen ) 492 i++; 493 if( i <= nLen && i > nLastPos ) 494 { 495 for( int n = nLastPos; n < i; n++ ) 496 pDelta[n] = pDeltaArray[n] - (aPoint.X() - rPoint.X() ); 497 498 SetFont( mnFontID, 499 maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth, 500 nNormalAngle, mbTextVertical, 501 maVirtualStatus.mbArtItalic, 502 maVirtualStatus.mbArtBold ); 503 drawText( aPoint, pStr + nLastPos, i - nLastPos, pDelta + nLastPos ); 504 505 aPoint.X() = (sal_Int32)(rPoint.X() + ((double)pDeltaArray[i-1] * fCos)); 506 aPoint.Y() = (sal_Int32)(rPoint.Y() + ((double)pDeltaArray[i-1] * fSin)); 507 } 508 if( i < nLen ) 509 { 510 int nOldWidth = maVirtualStatus.mnTextWidth; 511 int nOldHeight = maVirtualStatus.mnTextHeight; 512 SetFont( mnFontID, 513 nTextScale, 514 maVirtualStatus.mnTextHeight, 515 nNormalAngle + nDeltaAngle, 516 mbTextVertical, 517 maVirtualStatus.mbArtItalic, 518 maVirtualStatus.mbArtBold ); 519 520 double nA = nTextScale * aInfo.m_nAscend / 1000.0; 521 double nD = nTextScale * aInfo.m_nDescend / 1000.0; 522 double fStretch = (double)maVirtualStatus.mnTextWidth / maVirtualStatus.mnTextHeight; 523 if( !pGsubFlags[i] ) 524 nD *= fStretch; 525 526 Point aPos( aPoint ); 527 switch( nDeltaAngle ) 528 { 529 case +900: 530 aPos.X() += (sal_Int32)(+nA * fCos + nD * fSin); 531 aPos.Y() += (sal_Int32)(-nA * fSin + nD * fCos); 532 break; 533 case -900: 534 aPos.X() += (sal_Int32)(+nA * fSin + nD * fCos); 535 aPos.Y() += (sal_Int32)(-(nTextScale*fStretch - nD) * fCos); 536 break; 537 } 538 drawText( aPos, pStr+i, 1, NULL ); 539 if( i < nLen-1 && pDeltaArray ) 540 { 541 aPoint.X() = (sal_Int32)(rPoint.X() + ((double)pDeltaArray[i] * fCos)); 542 aPoint.Y() = (sal_Int32)(rPoint.Y() + ((double)pDeltaArray[i] * fSin)); 543 } 544 545 // swap text width/height again 546 SetFont( mnFontID, 547 nOldHeight, 548 nOldWidth, 549 nNormalAngle, 550 mbTextVertical, 551 maVirtualStatus.mbArtItalic, 552 maVirtualStatus.mbArtBold ); 553 } 554 i++; 555 nLastPos = i; 556 } 557 mnTextAngle = nNormalAngle; 558 } 559 560 void 561 PrinterGfx::LicenseWarning(const Point& rPoint, const sal_Unicode* pStr, 562 sal_Int16 nLen, const sal_Int32* pDeltaArray) 563 { 564 // treat it like a builtin font in case a user has that font also in the 565 // printer. This is not so unlikely as it may seem; no print embedding 566 // licensed fonts are often used (or so they say) in companies: 567 // they are installed on displays and printers, but get not embedded in 568 // they are installed on displays and printers, but get not embedded in 569 // print files or documents because they are not licensed for use outside 570 // the company. 571 rtl::OString aMessage( "The font " ); 572 aMessage += rtl::OUStringToOString( mrFontMgr.getPSName(mnFontID), 573 RTL_TEXTENCODING_ASCII_US ); 574 aMessage += " could not be downloaded\nbecause its license does not allow for that"; 575 PSComment( aMessage.getStr() ); 576 577 rtl::OString aFontName = rtl::OUStringToOString( 578 mrFontMgr.getPSName(mnFontID), 579 RTL_TEXTENCODING_ASCII_US); 580 PSSetFont (aFontName, RTL_TEXTENCODING_ISO_8859_1); 581 582 sal_Size nSize = 4 * nLen; 583 sal_uChar* pBuffer = (sal_uChar*)alloca (nSize* sizeof(sal_uChar)); 584 585 ConverterFactory* pCvt = GetConverterFactory (); 586 nSize = pCvt->Convert (pStr, nLen, pBuffer, nSize, RTL_TEXTENCODING_ISO_8859_1); 587 588 PSMoveTo (rPoint); 589 PSShowText (pBuffer, nLen, nSize, pDeltaArray); 590 } 591 592 void 593 PrinterGfx::drawText( 594 const Point& rPoint, 595 const sal_Unicode* pStr, 596 sal_Int16 nLen, 597 const sal_Int32* pDeltaArray 598 ) 599 { 600 if (!(nLen > 0)) 601 return; 602 603 fonttype::type eType = mrFontMgr.getFontType (mnFontID); 604 605 if (eType == fonttype::Type1) 606 PSUploadPS1Font (mnFontID); 607 608 if ( eType == fonttype::TrueType 609 && !mrFontMgr.isFontDownloadingAllowed(mnFontID)) 610 { 611 LicenseWarning(rPoint, pStr, nLen, pDeltaArray); 612 return; 613 } 614 615 if( mrFontMgr.getUseOnlyFontEncoding( mnFontID ) ) 616 { 617 GlyphSet aGSet( mnFontID, mbTextVertical ); 618 aGSet.DrawText( *this, rPoint, pStr, nLen, pDeltaArray ); 619 return; 620 } 621 622 // search for a glyph set matching the set font 623 std::list< GlyphSet >::iterator aIter; 624 for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); aIter++) 625 if ( ((*aIter).GetFontID() == mnFontID) 626 && ((*aIter).IsVertical() == mbTextVertical)) 627 { 628 (*aIter).DrawText (*this, rPoint, pStr, nLen, pDeltaArray); 629 break; 630 } 631 632 // not found ? create a new one 633 if (aIter == maPS3Font.end()) 634 { 635 maPS3Font.push_back (GlyphSet(mnFontID, mbTextVertical)); 636 maPS3Font.back().DrawText (*this, rPoint, pStr, nLen, pDeltaArray); 637 } 638 } 639 640 int 641 PrinterGfx::getCharWidth (sal_Bool b_vert, sal_Unicode n_char, CharacterMetric *p_bbox) 642 { 643 b_vert = b_vert && (getVerticalDeltaAngle(n_char) != 0); 644 int w = b_vert ? p_bbox->height : p_bbox->width; 645 w *= maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight; 646 return w; 647 } 648 649 fontID 650 PrinterGfx::getCharMetric (const Font3 &rFont, sal_Unicode n_char, CharacterMetric *p_bbox) 651 { 652 p_bbox->width = -1; 653 p_bbox->height = -1; 654 655 for (fontID n = 0; n < 3; n++) 656 { 657 fontID n_font = rFont.GetFont(n); 658 if (n_font != -1) 659 { 660 if( mbStrictSO52Compatibility ) 661 { 662 fonttype::type eType = mrFontMgr.getFontType( n_font ); 663 if( (eType == fonttype::Builtin || eType == fonttype::Type1) ) 664 { 665 // note: any character exchanged here MUST also be changed 666 // in the compatibility ISO encoding vector in the prolog 667 // in printerjob.cxx 668 sal_Unicode aRepl = 0; 669 if( n_char == 0x2d ) 670 aRepl = 0x2212; 671 else if( n_char == 0x27 ) 672 aRepl = 0x2019; 673 /* 674 additional characters that may need backwards compatibility: 675 ISO5589 StdEnc Unicode suggested n_char -> aRepl 676 0264 0302 0x00B4 0x00B4 (acute) -> 0x2019 (quiteright) 677 0246 - 0x00A6 0x00A6 (brokenbar) -> 0x007C (bar) 678 0225 0267 0x0095 0x0095 () -> 0x2022 (bullet) 679 0140 0301 0x0060 0x0060 (grave) -> ? 680 */ 681 if( aRepl ) 682 { 683 mrFontMgr.getMetrics( n_font, aRepl, aRepl, p_bbox ); 684 if (p_bbox->width >= 0 && p_bbox->height >= 0) 685 return n_font; 686 } 687 } 688 } 689 mrFontMgr.getMetrics( n_font, n_char, n_char, p_bbox ); 690 } 691 if (p_bbox->width >= 0 && p_bbox->height >= 0) 692 return n_font; 693 } 694 if (n_char != '?') 695 return getCharMetric (rFont, '?', p_bbox); 696 697 return rFont.GetFont(0) != -1 ? rFont.GetFont(0) : rFont.GetFont(1); 698 } 699 700 fontID 701 PrinterGfx::getFontSubstitute () const 702 { 703 if( mpFontSubstitutes ) 704 { 705 ::std::hash_map< fontID, fontID >::const_iterator it = 706 mpFontSubstitutes->find( mnFontID ); 707 if( it != mpFontSubstitutes->end() ) 708 return it->second; 709 } 710 711 return -1; 712 } 713 714 sal_Int32 715 PrinterGfx::GetCharWidth (sal_Unicode nFrom, sal_Unicode nTo, long *pWidthArray) 716 { 717 Font3 aFont(*this); 718 if (aFont.IsSymbolFont() && (nFrom < 256) && (nTo < 256)) 719 { 720 nFrom += 0xF000; 721 nTo += 0xF000; 722 } 723 724 for( int n = 0; n < (nTo - nFrom + 1); n++ ) 725 { 726 CharacterMetric aBBox; 727 getCharMetric (aFont, n + nFrom, &aBBox); 728 pWidthArray[n] = getCharWidth (mbTextVertical, n + nFrom, &aBBox); 729 } 730 731 // returned metrics have postscript precision 732 return 1000; 733 } 734 735 const ::std::list< KernPair >& PrinterGfx::getKernPairs( bool bVertical ) const 736 { 737 /* 738 * Note: this is only a 80% solution: if a font is only 739 * partially substituted in a string due to missing glyphs 740 * the results may not be perfect; the more so the more the 741 * substitution differs from the original metricwise. But 742 * vcl only asks for KernPairs for each font once and NOT 743 * in a string context this is the best we can do. 744 * In future the kerning should be done on a per string basis. 745 */ 746 fontID nFont = mnFontID; 747 if( mpFontSubstitutes ) 748 { 749 ::std::hash_map< fontID, fontID >::const_iterator it = 750 mpFontSubstitutes->find( mnFontID ); 751 if( it != mpFontSubstitutes->end() ) 752 nFont = it->second; 753 } 754 return mrFontMgr.getKernPairs( nFont, bVertical ); 755 } 756 757 /* 758 * advanced glyph handling 759 */ 760 761 sal_Bool 762 PrinterGfx::GetGlyphBoundRect (sal_Unicode /*c*/, Rectangle& /*rOutRect*/) 763 { 764 return 0; 765 } 766 767 sal_uInt32 768 PrinterGfx::GetGlyphOutline (sal_Unicode /*c*/, 769 sal_uInt16 **/*ppPolySizes*/, Point **/*ppPoints*/, sal_uInt8 **/*ppFlags*/) 770 { 771 return 0; 772 } 773 774 /* 775 * spool the converted truetype fonts to the page header after the page body is 776 * complete 777 * for Type1 fonts spool additional reencoding vectors that are necessary to access the 778 * whole font 779 */ 780 781 void 782 PrinterGfx::OnEndPage () 783 { 784 } 785 786 void 787 PrinterGfx::OnEndJob () 788 { 789 maPS3Font.clear(); 790 maPS1Font.clear(); 791 } 792 793 void 794 PrinterGfx::writeResources( osl::File* pFile, std::list< rtl::OString >& rSuppliedFonts, std::list< rtl::OString >& rNeededFonts ) 795 { 796 // write all type 1 fonts 797 std::list< sal_Int32 >::iterator aFont; 798 // already in the document header ? 799 for (aFont = maPS1Font.begin(); aFont != maPS1Font.end(); ++aFont) 800 { 801 const rtl::OString& rSysPath (mrFontMgr.getFontFileSysPath(*aFont) ); 802 rtl::OUString aUNCPath; 803 osl::File::getFileURLFromSystemPath (OStringToOUString (rSysPath, osl_getThreadTextEncoding()), aUNCPath); 804 osl::File aFontFile (aUNCPath); 805 806 // provide the pfb or pfa font as a (pfa-)font resource 807 rtl::OString aPostScriptName = 808 rtl::OUStringToOString ( mrFontMgr.getPSName(*aFont), 809 RTL_TEXTENCODING_ASCII_US ); 810 811 WritePS (pFile, "%%BeginResource: font "); 812 WritePS (pFile, aPostScriptName.getStr()); 813 WritePS (pFile, "\n"); 814 815 osl::File::RC nError = aFontFile.open (OpenFlag_Read); 816 if (nError == osl::File::E_None) 817 { 818 convertPfbToPfa (aFontFile, *pFile); 819 aFontFile.close (); 820 821 pFile->setPos(osl_Pos_Current, -1); 822 char lastchar = '\n'; 823 sal_uInt64 uBytes(1); 824 pFile->read((void *)(&lastchar), uBytes, uBytes); 825 if (lastchar != '\n') 826 WritePS (pFile, "\n"); 827 } 828 WritePS (pFile, "%%EndResource\n"); 829 rSuppliedFonts.push_back( aPostScriptName ); 830 } 831 832 // write glyphsets and reencodings 833 std::list< GlyphSet >::iterator aIter; 834 for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); ++aIter) 835 { 836 if (aIter->GetFontType() == fonttype::TrueType) 837 { 838 aIter->PSUploadFont (*pFile, *this, mbUploadPS42Fonts ? true : false, rSuppliedFonts ); 839 } 840 else 841 // ( aIter->GetFontType() == fonttype::Type1 842 // || aIter->GetFontType() == fonttype::Builtin ) 843 { 844 aIter->PSUploadEncoding (pFile, *this); 845 if( aIter->GetFontType() == fonttype::Builtin ) 846 rNeededFonts.push_back( 847 rtl::OUStringToOString( 848 mrFontMgr.getPSName( aIter->GetFontID() ), 849 RTL_TEXTENCODING_ASCII_US ) ); 850 } 851 } 852 } 853 854 bool PrinterGfx::getStrictSO52Compatibility() const 855 { 856 return mbStrictSO52Compatibility; 857 } 858 859 void PrinterGfx::setStrictSO52Compatibility( bool bCompat) 860 { 861 mbStrictSO52Compatibility = bCompat; 862 } 863