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 "glyphset.hxx" 32 #include "psputil.hxx" 33 34 #include "sft.hxx" 35 36 #include "printergfx.hxx" 37 #include "fontsubset.hxx" 38 #include "vcl/fontmanager.hxx" 39 40 #include "osl/thread.h" 41 42 #include "sal/alloca.h" 43 44 #include "rtl/ustring.hxx" 45 #include "rtl/strbuf.hxx" 46 47 #include <set> 48 #include <map> 49 #include <algorithm> 50 51 using namespace vcl; 52 using namespace psp; 53 using namespace rtl; 54 55 GlyphSet::GlyphSet () 56 : mnFontID (-1), 57 mbVertical (0), 58 mbUseFontEncoding (false) 59 {} 60 61 GlyphSet::GlyphSet (sal_Int32 nFontID, sal_Bool bVertical) 62 : mnFontID (nFontID), 63 mbVertical (bVertical) 64 { 65 PrintFontManager &rMgr = PrintFontManager::get(); 66 meBaseType = rMgr.getFontType (mnFontID); 67 maBaseName = OUStringToOString (rMgr.getPSName(mnFontID), 68 RTL_TEXTENCODING_ASCII_US); 69 mnBaseEncoding = rMgr.getFontEncoding(mnFontID); 70 mbUseFontEncoding = rMgr.getUseOnlyFontEncoding(mnFontID); 71 } 72 73 GlyphSet::~GlyphSet () 74 { 75 /* FIXME delete the glyphlist ??? */ 76 } 77 78 sal_Int32 79 GlyphSet::GetFontID () 80 { 81 return mnFontID; 82 } 83 84 fonttype::type 85 GlyphSet::GetFontType () 86 { 87 return meBaseType; 88 } 89 90 sal_Bool 91 GlyphSet::IsVertical () 92 { 93 return mbVertical; 94 } 95 96 sal_Bool 97 GlyphSet::SetFont (sal_Int32 nFontID, sal_Bool bVertical) 98 { 99 if (mnFontID != -1) 100 return sal_False; 101 102 mnFontID = nFontID; 103 mbVertical = bVertical; 104 105 PrintFontManager &rMgr = PrintFontManager::get(); 106 meBaseType = rMgr.getFontType (mnFontID); 107 maBaseName = OUStringToOString (rMgr.getPSName(mnFontID), 108 RTL_TEXTENCODING_ASCII_US); 109 mnBaseEncoding = rMgr.getFontEncoding(mnFontID); 110 mbUseFontEncoding = rMgr.getUseOnlyFontEncoding(mnFontID); 111 112 return sal_True; 113 } 114 115 sal_Bool 116 GlyphSet::GetCharID ( 117 sal_Unicode nChar, 118 sal_uChar* nOutGlyphID, 119 sal_Int32* nOutGlyphSetID 120 ) 121 { 122 return LookupCharID (nChar, nOutGlyphID, nOutGlyphSetID) 123 || AddCharID (nChar, nOutGlyphID, nOutGlyphSetID); 124 } 125 126 sal_Bool 127 GlyphSet::GetGlyphID ( 128 sal_uInt32 nGlyph, 129 sal_Unicode nUnicode, 130 sal_uChar* nOutGlyphID, 131 sal_Int32* nOutGlyphSetID 132 ) 133 { 134 return LookupGlyphID (nGlyph, nOutGlyphID, nOutGlyphSetID) 135 || AddGlyphID (nGlyph, nUnicode, nOutGlyphID, nOutGlyphSetID); 136 } 137 138 sal_Bool 139 GlyphSet::LookupCharID ( 140 sal_Unicode nChar, 141 sal_uChar* nOutGlyphID, 142 sal_Int32* nOutGlyphSetID 143 ) 144 { 145 char_list_t::iterator aGlyphSet; 146 sal_Int32 nGlyphSetID; 147 148 // loop thru all the font subsets 149 for (aGlyphSet = maCharList.begin(), nGlyphSetID = 1; 150 aGlyphSet != maCharList.end(); 151 ++aGlyphSet, nGlyphSetID++) 152 { 153 // check every subset if it contains the queried unicode char 154 char_map_t::const_iterator aGlyph = (*aGlyphSet).find (nChar); 155 if (aGlyph != (*aGlyphSet).end()) 156 { 157 // success: found the unicode char, return the glyphid and the glyphsetid 158 *nOutGlyphSetID = nGlyphSetID; 159 *nOutGlyphID = (*aGlyph).second; 160 return sal_True; 161 } 162 } 163 164 *nOutGlyphSetID = -1; 165 *nOutGlyphID = 0; 166 return sal_False; 167 } 168 169 sal_Bool 170 GlyphSet::LookupGlyphID ( 171 sal_uInt32 nGlyph, 172 sal_uChar* nOutGlyphID, 173 sal_Int32* nOutGlyphSetID 174 ) 175 { 176 glyph_list_t::iterator aGlyphSet; 177 sal_Int32 nGlyphSetID; 178 179 // loop thru all the font subsets 180 for (aGlyphSet = maGlyphList.begin(), nGlyphSetID = 1; 181 aGlyphSet != maGlyphList.end(); 182 ++aGlyphSet, nGlyphSetID++) 183 { 184 // check every subset if it contains the queried unicode char 185 glyph_map_t::const_iterator aGlyph = (*aGlyphSet).find (nGlyph); 186 if (aGlyph != (*aGlyphSet).end()) 187 { 188 // success: found the glyph id, return the mapped glyphid and the glyphsetid 189 *nOutGlyphSetID = nGlyphSetID; 190 *nOutGlyphID = (*aGlyph).second; 191 return sal_True; 192 } 193 } 194 195 *nOutGlyphSetID = -1; 196 *nOutGlyphID = 0; 197 return sal_False; 198 } 199 200 sal_uChar 201 GlyphSet::GetAnsiMapping (sal_Unicode nUnicodeChar) 202 { 203 static rtl_UnicodeToTextConverter aConverter = 204 rtl_createUnicodeToTextConverter(RTL_TEXTENCODING_MS_1252); 205 static rtl_UnicodeToTextContext aContext = 206 rtl_createUnicodeToTextContext( aConverter ); 207 208 sal_Char nAnsiChar; 209 sal_uInt32 nCvtInfo; 210 sal_Size nCvtChars; 211 const sal_uInt32 nCvtFlags = RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR 212 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR; 213 214 sal_Size nSize = rtl_convertUnicodeToText( aConverter, aContext, 215 &nUnicodeChar, 1, &nAnsiChar, 1, 216 nCvtFlags, &nCvtInfo, &nCvtChars ); 217 218 return nSize == 1 ? (sal_uChar)nAnsiChar : (sal_uChar)0; 219 } 220 221 sal_uChar 222 GlyphSet::GetSymbolMapping (sal_Unicode nUnicodeChar) 223 { 224 if (0x0000 < nUnicodeChar && nUnicodeChar < 0x0100) 225 return (sal_uChar)nUnicodeChar; 226 if (0xf000 < nUnicodeChar && nUnicodeChar < 0xf100) 227 return (sal_uChar)nUnicodeChar; 228 229 return 0; 230 } 231 232 void 233 GlyphSet::AddNotdef (char_map_t &rCharMap) 234 { 235 if (rCharMap.size() == 0) 236 rCharMap[0] = 0; 237 } 238 239 void 240 GlyphSet::AddNotdef (glyph_map_t &rGlyphMap) 241 { 242 if (rGlyphMap.size() == 0) 243 rGlyphMap[0] = 0; 244 } 245 sal_Bool 246 GlyphSet::AddCharID ( 247 sal_Unicode nChar, 248 sal_uChar* nOutGlyphID, 249 sal_Int32* nOutGlyphSetID 250 ) 251 { 252 sal_uChar nMappedChar; 253 254 // XXX important: avoid to reencode type1 symbol fonts 255 if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL) 256 nMappedChar = GetSymbolMapping (nChar); 257 else 258 nMappedChar = GetAnsiMapping (nChar); 259 260 // create an empty glyphmap that is reserved for iso1252 encoded glyphs 261 // (or -- unencoded -- symbol glyphs) and a second map that takes any other 262 if (maCharList.empty()) 263 { 264 char_map_t aMap, aMapp; 265 266 maCharList.push_back (aMap); 267 maCharList.push_back (aMapp); 268 } 269 // if the last map is full, create a new one 270 if ((!nMappedChar) && (maCharList.back().size() == 255)) 271 { 272 char_map_t aMap; 273 maCharList.push_back (aMap); 274 } 275 276 // insert a new glyph in the font subset 277 if (nMappedChar) 278 { 279 // always put iso1252 chars into the first map, map them on itself 280 char_map_t& aGlyphSet = maCharList.front(); 281 AddNotdef (aGlyphSet); 282 283 aGlyphSet [nChar] = nMappedChar; 284 *nOutGlyphSetID = 1; 285 *nOutGlyphID = nMappedChar; 286 } 287 else 288 { 289 // other chars are just appended to the list 290 char_map_t& aGlyphSet = maCharList.back(); 291 AddNotdef (aGlyphSet); 292 293 int nSize = aGlyphSet.size(); 294 295 aGlyphSet [nChar] = nSize; 296 *nOutGlyphSetID = maCharList.size(); 297 *nOutGlyphID = aGlyphSet [nChar]; 298 } 299 300 return sal_True; 301 } 302 303 sal_Bool 304 GlyphSet::AddGlyphID ( 305 sal_uInt32 nGlyph, 306 sal_Unicode nUnicode, 307 sal_uChar* nOutGlyphID, 308 sal_Int32* nOutGlyphSetID 309 ) 310 { 311 sal_uChar nMappedChar; 312 313 // XXX important: avoid to reencode type1 symbol fonts 314 if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL) 315 nMappedChar = GetSymbolMapping (nUnicode); 316 else 317 nMappedChar = GetAnsiMapping (nUnicode); 318 319 // create an empty glyphmap that is reserved for iso1252 encoded glyphs 320 // (or -- unencoded -- symbol glyphs) and a second map that takes any other 321 if (maGlyphList.empty()) 322 { 323 glyph_map_t aMap, aMapp; 324 325 maGlyphList.push_back (aMap); 326 maGlyphList.push_back (aMapp); 327 } 328 // if the last map is full, create a new one 329 if ((!nMappedChar) && (maGlyphList.back().size() == 255)) 330 { 331 glyph_map_t aMap; 332 maGlyphList.push_back (aMap); 333 } 334 335 // insert a new glyph in the font subset 336 if (nMappedChar) 337 { 338 // always put iso1252 chars into the first map, map them on itself 339 glyph_map_t& aGlyphSet = maGlyphList.front(); 340 AddNotdef (aGlyphSet); 341 342 aGlyphSet [nGlyph] = nMappedChar; 343 *nOutGlyphSetID = 1; 344 *nOutGlyphID = nMappedChar; 345 } 346 else 347 { 348 // other chars are just appended to the list 349 glyph_map_t& aGlyphSet = maGlyphList.back(); 350 AddNotdef (aGlyphSet); 351 352 int nSize = aGlyphSet.size(); 353 354 aGlyphSet [nGlyph] = nSize; 355 *nOutGlyphSetID = maGlyphList.size(); 356 *nOutGlyphID = aGlyphSet [nGlyph]; 357 } 358 359 return sal_True; 360 } 361 362 OString 363 GlyphSet::GetCharSetName (sal_Int32 nGlyphSetID) 364 { 365 if (meBaseType == fonttype::TrueType) 366 { 367 OStringBuffer aSetName( maBaseName.getLength() + 32 ); 368 aSetName.append( maBaseName ); 369 aSetName.append( "FID" ); 370 aSetName.append( mnFontID ); 371 aSetName.append( mbVertical ? "VCSet" : "HCSet" ); 372 aSetName.append( nGlyphSetID ); 373 return aSetName.makeStringAndClear(); 374 } 375 else 376 /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */ 377 { 378 return maBaseName; 379 } 380 } 381 382 OString 383 GlyphSet::GetGlyphSetName (sal_Int32 nGlyphSetID) 384 { 385 if (meBaseType == fonttype::TrueType) 386 { 387 OStringBuffer aSetName( maBaseName.getLength() + 32 ); 388 aSetName.append( maBaseName ); 389 aSetName.append( "FID" ); 390 aSetName.append( mnFontID ); 391 aSetName.append( mbVertical ? "VGSet" : "HGSet" ); 392 aSetName.append( nGlyphSetID ); 393 return aSetName.makeStringAndClear(); 394 } 395 else 396 /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */ 397 { 398 return maBaseName; 399 } 400 } 401 402 sal_Int32 403 GlyphSet::GetGlyphSetEncoding (sal_Int32 nGlyphSetID) 404 { 405 if (meBaseType == fonttype::TrueType) 406 return RTL_TEXTENCODING_DONTKNOW; 407 else 408 { 409 /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */ 410 if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL) 411 return RTL_TEXTENCODING_SYMBOL; 412 else 413 return nGlyphSetID == 1 ? RTL_TEXTENCODING_MS_1252 414 : RTL_TEXTENCODING_USER_START + nGlyphSetID; 415 } 416 } 417 418 OString 419 GlyphSet::GetGlyphSetEncodingName (rtl_TextEncoding nEnc, const OString &rFontName) 420 { 421 if ( nEnc == RTL_TEXTENCODING_MS_1252 422 || nEnc == RTL_TEXTENCODING_ISO_8859_1) 423 { 424 return OString("ISO1252Encoding"); 425 } 426 else 427 if (nEnc >= RTL_TEXTENCODING_USER_START && nEnc <= RTL_TEXTENCODING_USER_END) 428 { 429 return rFontName 430 + OString("Enc") 431 + OString::valueOf ((sal_Int32)(nEnc - RTL_TEXTENCODING_USER_START)); 432 } 433 else 434 { 435 return OString(); 436 } 437 } 438 439 OString 440 GlyphSet::GetGlyphSetEncodingName (sal_Int32 nGlyphSetID) 441 { 442 return GetGlyphSetEncodingName (GetGlyphSetEncoding(nGlyphSetID), maBaseName); 443 } 444 445 void 446 GlyphSet::PSDefineReencodedFont (osl::File* pOutFile, sal_Int32 nGlyphSetID) 447 { 448 // only for ps fonts 449 if ((meBaseType != fonttype::Builtin) && (meBaseType != fonttype::Type1)) 450 return; 451 452 sal_Char pEncodingVector [256]; 453 sal_Int32 nSize = 0; 454 455 nSize += psp::appendStr ("(", pEncodingVector + nSize); 456 nSize += psp::appendStr (GetReencodedFontName(nGlyphSetID), 457 pEncodingVector + nSize); 458 nSize += psp::appendStr (") cvn (", pEncodingVector + nSize); 459 nSize += psp::appendStr (maBaseName.getStr(), 460 pEncodingVector + nSize); 461 nSize += psp::appendStr (") cvn ", pEncodingVector + nSize); 462 nSize += psp::appendStr (GetGlyphSetEncodingName(nGlyphSetID), 463 pEncodingVector + nSize); 464 nSize += psp::appendStr (" psp_definefont\n", 465 pEncodingVector + nSize); 466 467 psp::WritePS (pOutFile, pEncodingVector); 468 } 469 470 OString 471 GlyphSet::GetReencodedFontName (rtl_TextEncoding nEnc, const OString &rFontName) 472 { 473 if ( nEnc == RTL_TEXTENCODING_MS_1252 474 || nEnc == RTL_TEXTENCODING_ISO_8859_1) 475 { 476 return rFontName 477 + OString("-iso1252"); 478 } 479 else 480 if (nEnc >= RTL_TEXTENCODING_USER_START && nEnc <= RTL_TEXTENCODING_USER_END) 481 { 482 return rFontName 483 + OString("-enc") 484 + OString::valueOf ((sal_Int32)(nEnc - RTL_TEXTENCODING_USER_START)); 485 } 486 else 487 { 488 return OString(); 489 } 490 } 491 492 OString 493 GlyphSet::GetReencodedFontName (sal_Int32 nGlyphSetID) 494 { 495 return GetReencodedFontName (GetGlyphSetEncoding(nGlyphSetID), maBaseName); 496 } 497 498 void GlyphSet::DrawGlyphs( 499 PrinterGfx& rGfx, 500 const Point& rPoint, 501 const sal_uInt32* pGlyphIds, 502 const sal_Unicode* pUnicodes, 503 sal_Int16 nLen, 504 const sal_Int32* pDeltaArray ) 505 { 506 sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar)); 507 sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32)); 508 std::set< sal_Int32 > aGlyphSet; 509 510 // convert unicode to font glyph id and font subset 511 for (int nChar = 0; nChar < nLen; nChar++) 512 { 513 GetGlyphID (pGlyphIds[nChar], pUnicodes[nChar], pGlyphID + nChar, pGlyphSetID + nChar); 514 aGlyphSet.insert (pGlyphSetID[nChar]); 515 } 516 517 // loop over all glyph sets to detect substrings that can be xshown together 518 // without changing the postscript font 519 sal_Int32 *pDeltaSubset = (sal_Int32*)alloca (nLen * sizeof(sal_Int32)); 520 sal_uChar *pGlyphSubset = (sal_uChar*)alloca (nLen * sizeof(sal_uChar)); 521 522 std::set< sal_Int32 >::iterator aSet; 523 for (aSet = aGlyphSet.begin(); aSet != aGlyphSet.end(); ++aSet) 524 { 525 Point aPoint = rPoint; 526 sal_Int32 nOffset = 0; 527 sal_Int32 nGlyphs = 0; 528 sal_Int32 nChar; 529 530 // get offset to first glyph 531 for (nChar = 0; (nChar < nLen) && (pGlyphSetID[nChar] != *aSet); nChar++) 532 { 533 nOffset = pDeltaArray [nChar]; 534 } 535 536 // loop over all chars to extract those that share the current glyph set 537 for (nChar = 0; nChar < nLen; nChar++) 538 { 539 if (pGlyphSetID[nChar] == *aSet) 540 { 541 pGlyphSubset [nGlyphs] = pGlyphID [nChar]; 542 // the offset to the next glyph is determined by the glyph in 543 // front of the next glyph with the same glyphset id 544 // most often, this will be the current glyph 545 while ((nChar + 1) < nLen) 546 { 547 if (pGlyphSetID[nChar + 1] == *aSet) 548 break; 549 else 550 nChar += 1; 551 } 552 pDeltaSubset [nGlyphs] = pDeltaArray[nChar] - nOffset; 553 554 nGlyphs += 1; 555 } 556 } 557 558 // show the text using the PrinterGfx text api 559 aPoint.Move (nOffset, 0); 560 561 OString aGlyphSetName(GetGlyphSetName(*aSet)); 562 rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(*aSet)); 563 rGfx.PSMoveTo (aPoint); 564 rGfx.PSShowText (pGlyphSubset, nGlyphs, nGlyphs, nGlyphs > 1 ? pDeltaSubset : NULL); 565 } 566 } 567 568 void 569 GlyphSet::DrawText (PrinterGfx &rGfx, const Point& rPoint, 570 const sal_Unicode* pStr, sal_Int16 nLen, const sal_Int32* pDeltaArray) 571 { 572 // dispatch to the impl method 573 if (pDeltaArray == NULL) 574 ImplDrawText (rGfx, rPoint, pStr, nLen); 575 else 576 ImplDrawText (rGfx, rPoint, pStr, nLen, pDeltaArray); 577 } 578 579 void 580 GlyphSet::ImplDrawText (PrinterGfx &rGfx, const Point& rPoint, 581 const sal_Unicode* pStr, sal_Int16 nLen) 582 { 583 rGfx.PSMoveTo (rPoint); 584 585 if( mbUseFontEncoding ) 586 { 587 OString aPSName( OUStringToOString( rGfx.GetFontMgr().getPSName( mnFontID ), RTL_TEXTENCODING_ISO_8859_1 ) ); 588 OString aBytes( OUStringToOString( OUString( pStr, nLen ), mnBaseEncoding ) ); 589 rGfx.PSSetFont( aPSName, mnBaseEncoding ); 590 rGfx.PSShowText( (const unsigned char*)aBytes.getStr(), nLen, aBytes.getLength() ); 591 return; 592 } 593 594 int nChar; 595 sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar)); 596 sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32)); 597 598 // convert unicode to glyph id and char set (font subset) 599 for (nChar = 0; nChar < nLen; nChar++) 600 GetCharID (pStr[nChar], pGlyphID + nChar, pGlyphSetID + nChar); 601 602 // loop over the string to draw subsequent pieces of chars 603 // with the same postscript font 604 for (nChar = 0; nChar < nLen; /* atend */) 605 { 606 sal_Int32 nGlyphSetID = pGlyphSetID [nChar]; 607 sal_Int32 nGlyphs = 1; 608 for (int nNextChar = nChar + 1; nNextChar < nLen; nNextChar++) 609 { 610 if (pGlyphSetID[nNextChar] == nGlyphSetID) 611 nGlyphs++; 612 else 613 break; 614 } 615 616 // show the text using the PrinterGfx text api 617 OString aGlyphSetName(GetCharSetName(nGlyphSetID)); 618 rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(nGlyphSetID)); 619 rGfx.PSShowText (pGlyphID + nChar, nGlyphs, nGlyphs); 620 621 nChar += nGlyphs; 622 } 623 } 624 625 void 626 GlyphSet::ImplDrawText (PrinterGfx &rGfx, const Point& rPoint, 627 const sal_Unicode* pStr, sal_Int16 nLen, const sal_Int32* pDeltaArray) 628 { 629 if( mbUseFontEncoding ) 630 { 631 OString aPSName( OUStringToOString( rGfx.GetFontMgr().getPSName( mnFontID ), RTL_TEXTENCODING_ISO_8859_1 ) ); 632 OString aBytes( OUStringToOString( OUString( pStr, nLen ), mnBaseEncoding ) ); 633 rGfx.PSMoveTo( rPoint ); 634 rGfx.PSSetFont( aPSName, mnBaseEncoding ); 635 rGfx.PSShowText( (const unsigned char*)aBytes.getStr(), nLen, aBytes.getLength(), pDeltaArray ); 636 return; 637 } 638 639 sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar)); 640 sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32)); 641 std::set< sal_Int32 > aGlyphSet; 642 643 // convert unicode to font glyph id and font subset 644 for (int nChar = 0; nChar < nLen; nChar++) 645 { 646 GetCharID (pStr[nChar], pGlyphID + nChar, pGlyphSetID + nChar); 647 aGlyphSet.insert (pGlyphSetID[nChar]); 648 } 649 650 // loop over all glyph sets to detect substrings that can be xshown together 651 // without changing the postscript font 652 sal_Int32 *pDeltaSubset = (sal_Int32*)alloca (nLen * sizeof(sal_Int32)); 653 sal_uChar *pGlyphSubset = (sal_uChar*)alloca (nLen * sizeof(sal_uChar)); 654 655 std::set< sal_Int32 >::iterator aSet; 656 for (aSet = aGlyphSet.begin(); aSet != aGlyphSet.end(); ++aSet) 657 { 658 Point aPoint = rPoint; 659 sal_Int32 nOffset = 0; 660 sal_Int32 nGlyphs = 0; 661 sal_Int32 nChar; 662 663 // get offset to first glyph 664 for (nChar = 0; (nChar < nLen) && (pGlyphSetID[nChar] != *aSet); nChar++) 665 { 666 nOffset = pDeltaArray [nChar]; 667 } 668 669 // loop over all chars to extract those that share the current glyph set 670 for (nChar = 0; nChar < nLen; nChar++) 671 { 672 if (pGlyphSetID[nChar] == *aSet) 673 { 674 pGlyphSubset [nGlyphs] = pGlyphID [nChar]; 675 // the offset to the next glyph is determined by the glyph in 676 // front of the next glyph with the same glyphset id 677 // most often, this will be the current glyph 678 while ((nChar + 1) < nLen) 679 { 680 if (pGlyphSetID[nChar + 1] == *aSet) 681 break; 682 else 683 nChar += 1; 684 } 685 pDeltaSubset [nGlyphs] = pDeltaArray[nChar] - nOffset; 686 687 nGlyphs += 1; 688 } 689 } 690 691 // show the text using the PrinterGfx text api 692 aPoint.Move (nOffset, 0); 693 694 OString aGlyphSetName(GetCharSetName(*aSet)); 695 rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(*aSet)); 696 rGfx.PSMoveTo (aPoint); 697 rGfx.PSShowText (pGlyphSubset, nGlyphs, nGlyphs, nGlyphs > 1 ? pDeltaSubset : NULL); 698 } 699 } 700 701 sal_Bool 702 GlyphSet::PSUploadEncoding(osl::File* pOutFile, PrinterGfx &rGfx) 703 { 704 // only for ps fonts 705 if ((meBaseType != fonttype::Builtin) && (meBaseType != fonttype::Type1)) 706 return sal_False; 707 if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL) 708 return sal_False; 709 710 PrintFontManager &rMgr = rGfx.GetFontMgr(); 711 712 // loop thru all the font subsets 713 sal_Int32 nGlyphSetID = 0; 714 char_list_t::iterator aGlyphSet; 715 for (aGlyphSet = maCharList.begin(); aGlyphSet != maCharList.end(); aGlyphSet++) 716 { 717 ++nGlyphSetID; 718 719 if (nGlyphSetID == 1) // latin1 page uses global reencoding table 720 { 721 PSDefineReencodedFont (pOutFile, nGlyphSetID); 722 continue; 723 } 724 if ((*aGlyphSet).size() == 0) // empty set, doesn't need reencoding 725 { 726 continue; 727 } 728 729 // create reencoding table 730 731 sal_Char pEncodingVector [256]; 732 sal_Int32 nSize = 0; 733 734 nSize += psp::appendStr ("/", 735 pEncodingVector + nSize); 736 nSize += psp::appendStr (GetGlyphSetEncodingName(nGlyphSetID), 737 pEncodingVector + nSize); 738 nSize += psp::appendStr (" [ ", 739 pEncodingVector + nSize); 740 741 // need a list of glyphs, sorted by glyphid 742 typedef std::map< sal_uInt8, sal_Unicode > ps_mapping_t; 743 typedef ps_mapping_t::value_type ps_value_t; 744 ps_mapping_t aSortedGlyphSet; 745 746 char_map_t::const_iterator aUnsortedGlyph; 747 for (aUnsortedGlyph = (*aGlyphSet).begin(); 748 aUnsortedGlyph != (*aGlyphSet).end(); 749 ++aUnsortedGlyph) 750 { 751 aSortedGlyphSet.insert(ps_value_t((*aUnsortedGlyph).second, 752 (*aUnsortedGlyph).first)); 753 } 754 755 ps_mapping_t::const_iterator aSortedGlyph; 756 // loop thru all the glyphs in the subset 757 for (aSortedGlyph = (aSortedGlyphSet).begin(); 758 aSortedGlyph != (aSortedGlyphSet).end(); 759 ++aSortedGlyph) 760 { 761 nSize += psp::appendStr ("/", 762 pEncodingVector + nSize); 763 764 std::list< OString > aName( rMgr.getAdobeNameFromUnicode((*aSortedGlyph).second) ); 765 766 if( aName.begin() != aName.end() ) 767 nSize += psp::appendStr ( aName.front(), pEncodingVector + nSize); 768 else 769 nSize += psp::appendStr (".notdef", pEncodingVector + nSize ); 770 nSize += psp::appendStr (" ", pEncodingVector + nSize); 771 // flush line 772 if (nSize >= 70) 773 { 774 nSize += psp::appendStr ("\n", pEncodingVector + nSize); 775 psp::WritePS (pOutFile, pEncodingVector); 776 nSize = 0; 777 } 778 } 779 780 nSize += psp::appendStr ("] def\n", pEncodingVector + nSize); 781 psp::WritePS (pOutFile, pEncodingVector); 782 783 PSDefineReencodedFont (pOutFile, nGlyphSetID); 784 } 785 786 return sal_True; 787 } 788 789 struct EncEntry 790 { 791 sal_uChar aEnc; 792 long aGID; 793 794 EncEntry() : aEnc( 0 ), aGID( 0 ) {} 795 796 bool operator<( const EncEntry& rRight ) const 797 { return aEnc < rRight.aEnc; } 798 }; 799 800 static void CreatePSUploadableFont( TrueTypeFont* pSrcFont, FILE* pTmpFile, 801 const char* pGlyphSetName, int nGlyphCount, 802 /*const*/ sal_uInt16* pRequestedGlyphs, /*const*/ sal_uChar* pEncoding, 803 bool bAllowType42, bool /*bAllowCID*/ ) 804 { 805 // match the font-subset to the printer capabilities 806 // TODO: allow CFF for capable printers 807 int nTargetMask = FontSubsetInfo::TYPE1_PFA | FontSubsetInfo::TYPE3_FONT; 808 if( bAllowType42 ) 809 nTargetMask |= FontSubsetInfo::TYPE42_FONT; 810 811 std::vector< EncEntry > aSorted( nGlyphCount, EncEntry() ); 812 for( int i = 0; i < nGlyphCount; i++ ) 813 { 814 aSorted[i].aEnc = pEncoding[i]; 815 aSorted[i].aGID = pRequestedGlyphs[i]; 816 } 817 818 std::stable_sort( aSorted.begin(), aSorted.end() ); 819 820 std::vector< sal_uChar > aEncoding( nGlyphCount ); 821 std::vector< long > aRequestedGlyphs( nGlyphCount ); 822 823 for( int i = 0; i < nGlyphCount; i++ ) 824 { 825 aEncoding[i] = aSorted[i].aEnc; 826 aRequestedGlyphs[i] = aSorted[i].aGID; 827 } 828 829 FontSubsetInfo aInfo; 830 aInfo.LoadFont( pSrcFont ); 831 832 aInfo.CreateFontSubset( nTargetMask, pTmpFile, pGlyphSetName, 833 &aRequestedGlyphs[0], &aEncoding[0], nGlyphCount, NULL ); 834 } 835 836 sal_Bool 837 GlyphSet::PSUploadFont (osl::File& rOutFile, PrinterGfx &rGfx, bool bAllowType42, std::list< OString >& rSuppliedFonts ) 838 { 839 // only for truetype fonts 840 if (meBaseType != fonttype::TrueType) 841 return sal_False; 842 843 TrueTypeFont *pTTFont; 844 OString aTTFileName (rGfx.GetFontMgr().getFontFileSysPath(mnFontID)); 845 int nFace = rGfx.GetFontMgr().getFontFaceNumber(mnFontID); 846 sal_Int32 nSuccess = OpenTTFontFile(aTTFileName.getStr(), nFace < 0 ? 0 : nFace, &pTTFont); 847 if (nSuccess != SF_OK) 848 return sal_False; 849 FILE* pTmpFile = tmpfile(); 850 if (pTmpFile == NULL) 851 return sal_False; 852 853 // array of unicode source characters 854 sal_Unicode pUChars[256]; 855 856 // encoding vector maps character encoding to the ordinal number 857 // of the glyph in the output file 858 sal_uChar pEncoding[256]; 859 sal_uInt16 pTTGlyphMapping[256]; 860 const bool bAllowCID = false; // TODO: nPSLanguageLevel>=3 861 862 // loop thru all the font subsets 863 sal_Int32 nCharSetID; 864 char_list_t::iterator aCharSet; 865 for (aCharSet = maCharList.begin(), nCharSetID = 1; 866 aCharSet != maCharList.end(); 867 ++aCharSet, nCharSetID++) 868 { 869 if ((*aCharSet).size() == 0) 870 continue; 871 872 // loop thru all the chars in the subset 873 char_map_t::const_iterator aChar; 874 sal_Int32 n = 0; 875 for (aChar = (*aCharSet).begin(); aChar != (*aCharSet).end(); aChar++) 876 { 877 pUChars [n] = (*aChar).first; 878 pEncoding [n] = (*aChar).second; 879 n++; 880 } 881 // create a mapping from the unicode chars to the char encoding in 882 // source TrueType font 883 MapString (pTTFont, pUChars, (*aCharSet).size(), pTTGlyphMapping, mbVertical); 884 885 // create the current subset 886 OString aCharSetName = GetCharSetName(nCharSetID); 887 fprintf( pTmpFile, "%%%%BeginResource: font %s\n", aCharSetName.getStr() ); 888 CreatePSUploadableFont( pTTFont, pTmpFile, aCharSetName.getStr(), (*aCharSet).size(), 889 pTTGlyphMapping, pEncoding, bAllowType42, bAllowCID ); 890 fprintf( pTmpFile, "%%%%EndResource\n" ); 891 rSuppliedFonts.push_back( aCharSetName ); 892 } 893 894 // loop thru all the font glyph subsets 895 sal_Int32 nGlyphSetID; 896 glyph_list_t::iterator aGlyphSet; 897 for (aGlyphSet = maGlyphList.begin(), nGlyphSetID = 1; 898 aGlyphSet != maGlyphList.end(); 899 ++aGlyphSet, nGlyphSetID++) 900 { 901 if ((*aGlyphSet).size() == 0) 902 continue; 903 904 // loop thru all the glyphs in the subset 905 glyph_map_t::const_iterator aGlyph; 906 sal_Int32 n = 0; 907 for (aGlyph = (*aGlyphSet).begin(); aGlyph != (*aGlyphSet).end(); aGlyph++) 908 { 909 pTTGlyphMapping [n] = (*aGlyph).first; 910 pEncoding [n] = (*aGlyph).second; 911 n++; 912 } 913 914 // create the current subset 915 OString aGlyphSetName = GetGlyphSetName(nGlyphSetID); 916 fprintf( pTmpFile, "%%%%BeginResource: font %s\n", aGlyphSetName.getStr() ); 917 CreatePSUploadableFont( pTTFont, pTmpFile, aGlyphSetName.getStr(), (*aGlyphSet).size(), 918 pTTGlyphMapping, pEncoding, bAllowType42, bAllowCID ); 919 fprintf( pTmpFile, "%%%%EndResource\n" ); 920 rSuppliedFonts.push_back( aGlyphSetName ); 921 } 922 923 // copy the file into the page header 924 rewind(pTmpFile); 925 fflush(pTmpFile); 926 927 sal_uChar pBuffer[0x2000]; 928 sal_uInt64 nIn; 929 sal_uInt64 nOut; 930 do 931 { 932 nIn = fread(pBuffer, 1, sizeof(pBuffer), pTmpFile); 933 rOutFile.write (pBuffer, nIn, nOut); 934 } 935 while ((nIn == nOut) && !feof(pTmpFile)); 936 937 // cleanup 938 CloseTTFont (pTTFont); 939 fclose (pTmpFile); 940 941 return sal_True; 942 } 943