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