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