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
GetFont(int nIdx) const62 fontID GetFont (int nIdx) const
63 { return nIdx < Font3Size ? mpFont[nIdx] : -1 ; }
IsSymbolFont() const64 bool IsSymbolFont () const
65 { return mbSymbol; }
66
67 Font3 (const PrinterGfx &rGfx);
~Font3()68 ~Font3 () {}
69 };
70
Font3(const PrinterGfx & rGfx)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
getVerticalDeltaAngle(sal_Unicode nChar)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
PSUploadPS1Font(sal_Int32 nFontID)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
SetFont(sal_Int32 nFontID,sal_Int32 nHeight,sal_Int32 nWidth,sal_Int32 nAngle,bool bVertical,bool bArtItalic,bool bArtBold)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
SetFallbackFont(sal_Int32 nFontID)159 PrinterGfx::SetFallbackFont ( sal_Int32 nFontID )
160 {
161 mnFallbackID = nFontID;
162 return 0;
163 }
164
drawGlyphs(const Point & rPoint,sal_GlyphId * pGlyphIds,sal_Unicode * pUnicodes,sal_Int16 nLen,sal_Int32 * pDeltaArray)165 void PrinterGfx::drawGlyphs(
166 const Point& rPoint,
167 sal_GlyphId* 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
DrawGlyphs(const Point & rPoint,sal_GlyphId * pGlyphIds,sal_Unicode * pUnicodes,sal_Int16 nLen,sal_Int32 * pDeltaArray)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_GlyphId* pTempGlyphIds = (sal_GlyphId*)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
DrawText(const Point & rPoint,const sal_Unicode * pStr,sal_Int16 nLen,const sal_Int32 * pDeltaArray)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
drawVerticalizedText(const Point & rPoint,const sal_Unicode * pStr,sal_Int16 nLen,const sal_Int32 * pDeltaArray)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
LicenseWarning(const Point & rPoint,const sal_Unicode * pStr,sal_Int16 nLen,const sal_Int32 * pDeltaArray)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
drawText(const Point & rPoint,const sal_Unicode * pStr,sal_Int16 nLen,const sal_Int32 * pDeltaArray)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
getCharWidth(sal_Bool b_vert,sal_Unicode n_char,CharacterMetric * p_bbox)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
getCharMetric(const Font3 & rFont,sal_Unicode n_char,CharacterMetric * p_bbox)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
getFontSubstitute() const697 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
GetCharWidth(sal_Unicode nFrom,sal_Unicode nTo,long * pWidthArray)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
getKernPairs(bool bVertical) const731 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
GetGlyphBoundRect(sal_Unicode,Rectangle &)758 PrinterGfx::GetGlyphBoundRect (sal_Unicode /*c*/, Rectangle& /*rOutRect*/)
759 {
760 return 0;
761 }
762
763 sal_uInt32
GetGlyphOutline(sal_Unicode,sal_uInt16 **,Point **,sal_uInt8 **)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
OnEndPage()778 PrinterGfx::OnEndPage ()
779 {
780 }
781
782 void
OnEndJob()783 PrinterGfx::OnEndJob ()
784 {
785 maPS3Font.clear();
786 maPS1Font.clear();
787 }
788
789 void
writeResources(osl::File * pFile,std::list<rtl::OString> & rSuppliedFonts,std::list<rtl::OString> & rNeededFonts)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
getStrictSO52Compatibility() const850 bool PrinterGfx::getStrictSO52Compatibility() const
851 {
852 return mbStrictSO52Compatibility;
853 }
854
setStrictSO52Compatibility(bool bCompat)855 void PrinterGfx::setStrictSO52Compatibility( bool bCompat)
856 {
857 mbStrictSO52Compatibility = bCompat;
858 }
859