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