1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include "psputil.hxx"
23 #include "glyphset.hxx"
25 #include "generic/printergfx.hxx"
26 #include "fontmanager.hxx"
27 #include "vcl/helper.hxx"
29 #include "osl/thread.h"
31 #include "sal/alloca.h"
37 container for a font and its helper fonts:
38 1st is the font itself
39 2nd is a fallback font, usually a font with unicode glyph repertoir (e.g. andale)
40 symbol fonts (adobe-fontspecific) may need special glyphmapping
41 (symbol page vc. latin page)
49 fontID mpFont
[Font2Size
];
54 fontID
GetFont (int nIdx
) const
55 { return nIdx
< Font2Size
? mpFont
[nIdx
] : -1 ; }
56 bool IsSymbolFont () const
59 Font2 (const PrinterGfx
&rGfx
);
63 Font2::Font2(const PrinterGfx
&rGfx
)
65 mpFont
[0] = rGfx
.GetFontID();
66 mpFont
[1] = rGfx
.getFallbackID();
68 PrintFontManager
&rMgr
= PrintFontManager::get();
69 mbSymbol
= mpFont
[0] != -1 &&
70 rMgr
.getFontEncoding(mpFont
[0]) == RTL_TEXTENCODING_SYMBOL
;
75 static int getVerticalDeltaAngle( sal_Unicode nChar
)
77 int nRotation
= GetVerticalFlags(nChar
);
78 if (nRotation
== GF_ROTR
)
80 if (nRotation
== GF_ROTL
)
86 PrinterGfx::PSUploadPS1Font (sal_Int32 nFontID
)
88 std::list
< sal_Int32
>::iterator aFont
;
89 // already in the document header ?
90 for (aFont
= maPS1Font
.begin(); aFont
!= maPS1Font
.end(); ++aFont
)
91 if( nFontID
== *aFont
)
94 // no occurrenc yet, mark for download
95 // add the fontid to the list
96 maPS1Font
.push_back (nFontID
);
100 * implement text handling printer routines,
114 // font and encoding will be set by drawText again immediately
117 maVirtualStatus
.maFont
.clear();
118 maVirtualStatus
.maEncoding
= RTL_TEXTENCODING_DONTKNOW
;
119 maVirtualStatus
.mnTextHeight
= nHeight
;
120 maVirtualStatus
.mnTextWidth
= nWidth
;
121 maVirtualStatus
.mbArtItalic
= bArtItalic
;
122 maVirtualStatus
.mbArtBold
= bArtBold
;
123 mnTextAngle
= nAngle
;
124 mbTextVertical
= bVertical
;
129 void PrinterGfx::drawGlyphs(
131 sal_GlyphId
* pGlyphIds
,
132 sal_Unicode
* pUnicodes
,
134 sal_Int32
* pDeltaArray
139 // search for a glyph set matching the set font
140 std::list
< GlyphSet
>::iterator aIter
;
141 for (aIter
= maPS3Font
.begin(); aIter
!= maPS3Font
.end(); ++aIter
)
142 if ( ((*aIter
).GetFontID() == mnFontID
)
143 && ((*aIter
).IsVertical() == mbTextVertical
))
145 (*aIter
).DrawGlyphs (*this, rPoint
, pGlyphIds
, pUnicodes
, nLen
, pDeltaArray
);
149 // not found ? create a new one
150 if (aIter
== maPS3Font
.end())
152 maPS3Font
.push_back (GlyphSet(mnFontID
, mbTextVertical
));
153 maPS3Font
.back().DrawGlyphs (*this, rPoint
, pGlyphIds
, pUnicodes
, nLen
, pDeltaArray
);
157 void PrinterGfx::DrawGlyphs(
159 sal_GlyphId
* pGlyphIds
,
160 sal_Unicode
* pUnicodes
,
162 sal_Int32
* pDeltaArray
168 if ( !mrFontMgr
.isFontDownloadingAllowedForPrinting( mnFontID
) )
170 LicenseWarning(rPoint
, pUnicodes
, nLen
, pDeltaArray
);
174 if( mrFontMgr
.getFontType( mnFontID
) != fonttype::TrueType
)
176 DrawText( rPoint
, pUnicodes
, nLen
, pDeltaArray
);
180 // move and rotate the user coordinate system
181 // avoid the gsave/grestore for the simple cases since it allows
182 // reuse of the current font if it hasn't changed
183 sal_Int32 nCurrentTextAngle
= mnTextAngle
;
184 Point
aPoint( rPoint
);
186 if (nCurrentTextAngle
!= 0)
189 PSTranslate (rPoint
);
190 PSRotate (nCurrentTextAngle
);
192 aPoint
= Point( 0, 0 );
197 // vertical glyphs can have an additional rotation ... sigh.
198 // so break up text in chunks of normal glyphs and print out
199 // specially rotated glyphs extra
200 sal_GlyphId
* pTempGlyphIds
= static_cast<sal_GlyphId
*>(alloca(sizeof(sal_Int32
)*nLen
));
201 sal_Int32
* pTempDelta
= static_cast<sal_Int32
*>(alloca(sizeof(sal_Int32
)*nLen
));
202 sal_Unicode
* pTempUnicodes
= static_cast<sal_Unicode
*>(alloca(sizeof(sal_Unicode
)*nLen
));
203 sal_Int16 nTempLen
= 0;
204 sal_Int32 nTempFirstDelta
= 0;
206 sal_Int32 nTextHeight
= maVirtualStatus
.mnTextHeight
;
207 sal_Int32 nTextWidth
= maVirtualStatus
.mnTextWidth
? maVirtualStatus
.mnTextWidth
: maVirtualStatus
.mnTextHeight
;
208 sal_Int32 nAscend
= mrFontMgr
.getFontAscend( mnFontID
);
209 sal_Int32 nDescend
= mrFontMgr
.getFontDescend( mnFontID
);
211 nDescend
= nDescend
* nTextHeight
/ 1000;
212 nAscend
= nAscend
* nTextHeight
/ 1000;
214 for( sal_Int16 i
= 0; i
< nLen
; i
++ )
216 const sal_GlyphId nRot
= pGlyphIds
[i
] & GF_ROTMASK
;
217 if( nRot
== GF_NONE
)
219 pTempUnicodes
[nTempLen
] = pUnicodes
[i
];
220 pTempGlyphIds
[nTempLen
] = pGlyphIds
[i
];
222 pTempDelta
[nTempLen
-1] = pDeltaArray
[i
-1]-nTempFirstDelta
;
225 // the first element in pDeltaArray shows
226 // the offset of the second character
227 // so if the first glyph is normal
228 // then we do not need to move the delta indices
229 // else we have to move them down by one and
230 // recalculate aPoint and all deltas
232 nTempFirstDelta
= pDeltaArray
[ i
-1 ];
238 sal_Int32 nOffset
= i
> 0 ? pDeltaArray
[i
-1] : 0;
239 sal_Int32 nRotAngle
= 0;
244 aRotPoint
= Point( -nAscend
*nTextWidth
/nTextHeight
, -nDescend
*nTextWidth
/nTextHeight
- nOffset
);
248 aRotPoint
= Point( -nOffset
, (nAscend
+nDescend
) );
252 aRotPoint
= Point( -nDescend
*nTextWidth
/nTextHeight
, nOffset
+ nAscend
*nTextWidth
/nTextHeight
);
255 sal_GlyphId nRotGlyphId
= pGlyphIds
[i
];
256 sal_Unicode nRotUnicode
= pUnicodes
[i
];
257 sal_Int32 nRotDelta
= 0;
259 // transform matrix to new individual direction
261 GraphicsStatus aSaveStatus
= maVirtualStatus
;
262 if( nRot
!= 2 ) // switch font aspect
264 maVirtualStatus
.mnTextWidth
= nTextHeight
;
265 maVirtualStatus
.mnTextHeight
= nTextWidth
;
267 if( aPoint
.X() || aPoint
.Y() )
268 PSTranslate( aPoint
);
269 PSRotate (nRotAngle
);
270 // draw the rotated glyph
271 drawGlyphs( aRotPoint
, &nRotGlyphId
, &nRotUnicode
, 1, &nRotDelta
);
273 // restore previous state
274 maVirtualStatus
= aSaveStatus
;
279 pGlyphIds
= pTempGlyphIds
;
280 pUnicodes
= pTempUnicodes
;
281 pDeltaArray
= pTempDelta
;
284 aPoint
.X() += nTempFirstDelta
;
288 drawGlyphs( aPoint
, pGlyphIds
, pUnicodes
, nLen
, pDeltaArray
);
290 // restore the user coordinate system
291 if (nCurrentTextAngle
!= 0)
294 mnTextAngle
= nCurrentTextAngle
;
299 PrinterGfx::DrawText (
301 const sal_Unicode
* pStr
,
303 const sal_Int32
* pDeltaArray
309 fontID nRestoreFont
= mnFontID
;
311 // setup font[substitutes] and map the string into the symbol area in case of
314 sal_Unicode
*pEffectiveStr
;
315 if ( aFont
.IsSymbolFont() )
317 pEffectiveStr
= static_cast<sal_Unicode
*>(alloca(nLen
* sizeof(pStr
[0])));
318 for (int i
= 0; i
< nLen
; i
++)
319 pEffectiveStr
[i
] = pStr
[i
] < 256 ? pStr
[i
] + 0xF000 : pStr
[i
];
323 pEffectiveStr
= const_cast<sal_Unicode
*>(pStr
);
326 fontID
*pFontMap
= static_cast<fontID
*>(alloca(nLen
* sizeof(fontID
)));
327 sal_Int32
*pCharWidth
= static_cast<sal_Int32
*>(alloca(nLen
* sizeof(sal_Int32
)));
329 for( int n
= 0; n
< nLen
; n
++ )
331 CharacterMetric aBBox
;
332 // coverity[callee_ptr_arith]
333 pFontMap
[n
] = getCharMetric(aFont
, pEffectiveStr
[n
], &aBBox
);
334 pCharWidth
[n
] = getCharWidth(mbTextVertical
, pEffectiveStr
[n
], &aBBox
);
337 // setup a new delta array, use virtual resolution of 1000
338 sal_Int32
* pNewDeltaArray
= static_cast<sal_Int32
*>(alloca( sizeof( sal_Int32
)*nLen
));
339 if ( pDeltaArray
!= 0)
341 for (int i
= 0; i
< nLen
- 1; i
++)
342 pNewDeltaArray
[i
] = 1000 * pDeltaArray
[i
];
343 pNewDeltaArray
[nLen
- 1] = 0;
347 pNewDeltaArray
[0] = pCharWidth
[0];
348 for (int i
= 1; i
< nLen
; i
++)
349 pNewDeltaArray
[i
] = pNewDeltaArray
[i
-1] + pCharWidth
[i
];
352 // move and rotate the user coordinate system
353 // avoid the gsave/grestore for the simple cases since it allows
354 // reuse of the current font if it hasn't changed
355 sal_Int32 nCurrentTextAngle
= mnTextAngle
;
356 sal_Int32 nCurrentPointX
;
357 sal_Int32 nCurrentPointY
;
359 if (nCurrentTextAngle
!= 0)
362 PSTranslate (rPoint
);
363 PSRotate (nCurrentTextAngle
);
371 nCurrentPointX
= rPoint
.X();
372 nCurrentPointY
= rPoint
.Y();
376 sal_Int32 nDelta
= 0;
377 for (int nTo
= 0; nTo
< nLen
; )
380 fontID nFont
= pFontMap
[ nFrom
];
382 while ((nTo
< nLen
) && (nFont
== pFontMap
[nTo
]))
384 pNewDeltaArray
[ nTo
] = (sal_Int32
)(((0.5 + pNewDeltaArray
[ nTo
]) / 1000.0) - nDelta
);
389 maVirtualStatus
.mnTextHeight
, maVirtualStatus
.mnTextWidth
,
392 maVirtualStatus
.mbArtItalic
,
393 maVirtualStatus
.mbArtBold
398 drawVerticalizedText(
399 Point(nCurrentPointX
+ nDelta
, nCurrentPointY
),
400 pEffectiveStr
+ nFrom
, nTo
- nFrom
,
401 pNewDeltaArray
+ nFrom
);
406 Point(nCurrentPointX
+ nDelta
, nCurrentPointY
),
407 pEffectiveStr
+ nFrom
, nTo
- nFrom
,
408 pDeltaArray
== NULL
? NULL
: pNewDeltaArray
+ nFrom
);
410 nDelta
+= pNewDeltaArray
[ nTo
- 1 ];
413 // restore the user coordinate system
414 if (nCurrentTextAngle
!= 0)
417 mnTextAngle
= nCurrentTextAngle
;
420 // restore the original font settings
421 SetFont( nRestoreFont
,
422 maVirtualStatus
.mnTextHeight
, maVirtualStatus
.mnTextWidth
,
423 mnTextAngle
, mbTextVertical
,
424 maVirtualStatus
.mbArtItalic
,
425 maVirtualStatus
.mbArtBold
429 bool PrinterGfx::drawVerticalizedText(
431 const sal_Unicode
* pStr
,
433 const sal_Int32
* pDeltaArray
436 PrintFontManager
&rMgr
= PrintFontManager::get();
438 if (!rMgr
.getFontInfo(mnFontID
, aInfo
))
441 sal_Int32
* pDelta
= static_cast<sal_Int32
*>(alloca( nLen
* sizeof(sal_Int32
) ));
443 int nTextScale
= maVirtualStatus
.mnTextWidth
? maVirtualStatus
.mnTextWidth
: maVirtualStatus
.mnTextHeight
;
444 int nNormalAngle
= mnTextAngle
;
447 double fSin
= sin( -2.0*M_PI
*nNormalAngle
/3600 );
448 double fCos
= cos( -2.0*M_PI
*nNormalAngle
/3600 );
450 bool* pGsubFlags
= static_cast<bool*>(alloca( nLen
* sizeof(bool) ));
451 rMgr
.hasVerticalSubstitutions( mnFontID
, pStr
, nLen
, pGsubFlags
);
453 Point
aPoint( rPoint
);
454 for( int i
= 0; i
< nLen
; )
457 while( ( nDeltaAngle
= getVerticalDeltaAngle( pStr
[i
] ) ) == 0 && i
< nLen
)
459 if( i
<= nLen
&& i
> nLastPos
)
461 for( int n
= nLastPos
; n
< i
; n
++ )
462 pDelta
[n
] = pDeltaArray
[n
] - (aPoint
.X() - rPoint
.X() );
465 maVirtualStatus
.mnTextHeight
, maVirtualStatus
.mnTextWidth
,
466 nNormalAngle
, mbTextVertical
,
467 maVirtualStatus
.mbArtItalic
,
468 maVirtualStatus
.mbArtBold
);
469 drawText( aPoint
, pStr
+ nLastPos
, i
- nLastPos
, pDelta
+ nLastPos
);
471 aPoint
.X() = (sal_Int32
)(rPoint
.X() + ((double)pDeltaArray
[i
-1] * fCos
));
472 aPoint
.Y() = (sal_Int32
)(rPoint
.Y() + ((double)pDeltaArray
[i
-1] * fSin
));
476 int nOldWidth
= maVirtualStatus
.mnTextWidth
;
477 int nOldHeight
= maVirtualStatus
.mnTextHeight
;
480 maVirtualStatus
.mnTextHeight
,
481 nNormalAngle
+ nDeltaAngle
,
483 maVirtualStatus
.mbArtItalic
,
484 maVirtualStatus
.mbArtBold
);
486 double nA
= nTextScale
* aInfo
.m_nAscend
/ 1000.0;
487 double nD
= nTextScale
* aInfo
.m_nDescend
/ 1000.0;
488 double fStretch
= (double)maVirtualStatus
.mnTextWidth
/ maVirtualStatus
.mnTextHeight
;
492 Point
aPos( aPoint
);
493 switch( nDeltaAngle
)
496 aPos
.X() += (sal_Int32
)(+nA
* fCos
+ nD
* fSin
);
497 aPos
.Y() += (sal_Int32
)(-nA
* fSin
+ nD
* fCos
);
500 aPos
.X() += (sal_Int32
)(+nA
* fSin
+ nD
* fCos
);
501 aPos
.Y() += (sal_Int32
)(-(nTextScale
*fStretch
- nD
) * fCos
);
504 drawText( aPos
, pStr
+i
, 1, NULL
);
505 if( i
< nLen
-1 && pDeltaArray
)
507 aPoint
.X() = (sal_Int32
)(rPoint
.X() + ((double)pDeltaArray
[i
] * fCos
));
508 aPoint
.Y() = (sal_Int32
)(rPoint
.Y() + ((double)pDeltaArray
[i
] * fSin
));
511 // swap text width/height again
517 maVirtualStatus
.mbArtItalic
,
518 maVirtualStatus
.mbArtBold
);
523 mnTextAngle
= nNormalAngle
;
528 PrinterGfx::LicenseWarning(const Point
& rPoint
, const sal_Unicode
* pStr
,
529 sal_Int16 nLen
, const sal_Int32
* pDeltaArray
)
531 // treat it like a builtin font in case a user has that font also in the
532 // printer. This is not so unlikely as it may seem; no print embedding
533 // licensed fonts are often used (or so they say) in companies:
534 // they are installed on displays and printers, but get not embedded in
535 // print files or documents because they are not licensed for use outside
537 OString
aMessage( "The font " );
538 aMessage
+= OUStringToOString( mrFontMgr
.getPSName(mnFontID
),
539 RTL_TEXTENCODING_ASCII_US
);
540 aMessage
+= " could not be downloaded\nbecause its license does not allow for that";
541 PSComment( aMessage
.getStr() );
543 OString aFontName
= OUStringToOString(
544 mrFontMgr
.getPSName(mnFontID
),
545 RTL_TEXTENCODING_ASCII_US
);
546 PSSetFont (aFontName
, RTL_TEXTENCODING_ISO_8859_1
);
548 sal_Size nSize
= 4 * nLen
;
549 unsigned char* pBuffer
= static_cast<unsigned char*>(alloca (nSize
* sizeof(unsigned char)));
551 ConverterFactory
&rCvt
= GetConverterFactory ();
552 nSize
= rCvt
.Convert (pStr
, nLen
, pBuffer
, nSize
, RTL_TEXTENCODING_ISO_8859_1
);
555 PSShowText (pBuffer
, nLen
, nSize
, pDeltaArray
);
559 PrinterGfx::drawText(
561 const sal_Unicode
* pStr
,
563 const sal_Int32
* pDeltaArray
569 fonttype::type eType
= mrFontMgr
.getFontType (mnFontID
);
571 if (eType
== fonttype::Type1
)
572 PSUploadPS1Font (mnFontID
);
574 if ( eType
== fonttype::TrueType
575 && !mrFontMgr
.isFontDownloadingAllowedForPrinting(mnFontID
))
577 LicenseWarning(rPoint
, pStr
, nLen
, pDeltaArray
);
581 if( mrFontMgr
.getUseOnlyFontEncoding( mnFontID
) )
583 GlyphSet
aGSet( mnFontID
, mbTextVertical
);
584 aGSet
.DrawText( *this, rPoint
, pStr
, nLen
, pDeltaArray
);
588 // search for a glyph set matching the set font
589 std::list
< GlyphSet
>::iterator aIter
;
590 for (aIter
= maPS3Font
.begin(); aIter
!= maPS3Font
.end(); ++aIter
)
591 if ( ((*aIter
).GetFontID() == mnFontID
)
592 && ((*aIter
).IsVertical() == mbTextVertical
))
594 (*aIter
).DrawText (*this, rPoint
, pStr
, nLen
, pDeltaArray
);
598 // not found ? create a new one
599 if (aIter
== maPS3Font
.end())
601 maPS3Font
.push_back (GlyphSet(mnFontID
, mbTextVertical
));
602 maPS3Font
.back().DrawText (*this, rPoint
, pStr
, nLen
, pDeltaArray
);
607 PrinterGfx::getCharWidth (bool b_vert
, sal_Unicode n_char
, CharacterMetric
*p_bbox
)
609 b_vert
= b_vert
&& (getVerticalDeltaAngle(n_char
) != 0);
610 int w
= b_vert
? p_bbox
->height
: p_bbox
->width
;
611 w
*= maVirtualStatus
.mnTextWidth
? maVirtualStatus
.mnTextWidth
: maVirtualStatus
.mnTextHeight
;
616 PrinterGfx::getCharMetric (const Font2
&rFont
, sal_Unicode n_char
, CharacterMetric
*p_bbox
)
621 for (fontID n
= 0; n
< Font2Size
; n
++)
623 fontID n_font
= rFont
.GetFont(n
);
625 mrFontMgr
.getMetrics( n_font
, n_char
, n_char
, p_bbox
);
626 if (p_bbox
->width
>= 0 && p_bbox
->height
>= 0)
630 return getCharMetric (rFont
, '?', p_bbox
);
632 return rFont
.GetFont(0) != -1 ? rFont
.GetFont(0) : rFont
.GetFont(1);
636 PrinterGfx::GetCharWidth (sal_Unicode nFrom
, sal_Unicode nTo
, long *pWidthArray
)
639 if (aFont
.IsSymbolFont() && (nFrom
< 256) && (nTo
< 256))
645 for( int n
= 0; n
< (nTo
- nFrom
+ 1); n
++ )
647 CharacterMetric aBBox
;
648 // coverity[callee_ptr_arith]
649 getCharMetric(aFont
, n
+ nFrom
, &aBBox
);
650 pWidthArray
[n
] = getCharWidth (mbTextVertical
, n
+ nFrom
, &aBBox
);
653 // returned metrics have postscript precision
658 * spool the converted truetype fonts to the page header after the page body is
660 * for Type1 fonts spool additional reencoding vectors that are necessary to access the
665 PrinterGfx::OnEndJob ()
672 PrinterGfx::writeResources( osl::File
* pFile
, std::list
< OString
>& rSuppliedFonts
)
674 // write all type 1 fonts
675 std::list
< sal_Int32
>::iterator aFont
;
676 // already in the document header ?
677 for (aFont
= maPS1Font
.begin(); aFont
!= maPS1Font
.end(); ++aFont
)
679 const OString
& rSysPath (mrFontMgr
.getFontFileSysPath(*aFont
) );
681 osl::File::getFileURLFromSystemPath (OStringToOUString (rSysPath
, osl_getThreadTextEncoding()), aUNCPath
);
682 osl::File
aFontFile (aUNCPath
);
684 // provide the pfb or pfa font as a (pfa-)font resource
685 OString aPostScriptName
=
686 OUStringToOString ( mrFontMgr
.getPSName(*aFont
),
687 RTL_TEXTENCODING_ASCII_US
);
689 WritePS (pFile
, "%%BeginResource: font ");
690 WritePS (pFile
, aPostScriptName
.getStr());
691 WritePS (pFile
, "\n");
693 osl::File::RC nError
= aFontFile
.open(osl_File_OpenFlag_Read
);
694 if (nError
== osl::File::E_None
)
696 convertPfbToPfa (aFontFile
, *pFile
);
699 char lastchar
= '\n';
701 if (pFile
->setPos(osl_Pos_Current
, -1) == osl::FileBase::E_None
)
703 sal_uInt64
uBytes(1);
704 pFile
->read((void *)(&lastchar
), uBytes
, uBytes
);
707 if (lastchar
!= '\n')
708 WritePS (pFile
, "\n");
710 WritePS (pFile
, "%%EndResource\n");
711 rSuppliedFonts
.push_back( aPostScriptName
);
714 // write glyphsets and reencodings
715 std::list
< GlyphSet
>::iterator aIter
;
716 for (aIter
= maPS3Font
.begin(); aIter
!= maPS3Font
.end(); ++aIter
)
718 if (aIter
->GetFontType() == fonttype::TrueType
)
720 aIter
->PSUploadFont (*pFile
, *this, mbUploadPS42Fonts
, rSuppliedFonts
);
724 aIter
->PSUploadEncoding (pFile
, *this);
728 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */