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