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