summaryrefslogtreecommitdiff
path: root/vcl/unx/generic/printergfx/text_gfx.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/generic/printergfx/text_gfx.cxx')
-rw-r--r--vcl/unx/generic/printergfx/text_gfx.cxx862
1 files changed, 862 insertions, 0 deletions
diff --git a/vcl/unx/generic/printergfx/text_gfx.cxx b/vcl/unx/generic/printergfx/text_gfx.cxx
new file mode 100644
index 000000000000..7934821d4d70
--- /dev/null
+++ b/vcl/unx/generic/printergfx/text_gfx.cxx
@@ -0,0 +1,862 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <math.h>
+
+#include "psputil.hxx"
+#include "glyphset.hxx"
+
+#include "printergfx.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/helper.hxx"
+
+#include "osl/thread.h"
+
+#include "sal/alloca.h"
+
+using namespace psp ;
+
+namespace psp {
+/*
+ container for a font and its helper fonts:
+ 1st font is the font substitute e.g. helvetica substitutes arial on the printer
+ 2nd is the font itself
+ 3rd is a fallback font, usually a font with unicode glyph repertoir (e.g. andale)
+ symbol fonts (adobe-fontspecific) may need special glyphmapping
+ (symbol page vc. latin page)
+*/
+class Font3
+{
+ private:
+
+ #define Font3Size 3
+
+ fontID mpFont [Font3Size];
+ bool mbSymbol;
+
+ public:
+
+ fontID GetFont (int nIdx) const
+ { return nIdx < Font3Size ? mpFont[nIdx] : -1 ; }
+ bool IsSymbolFont () const
+ { return mbSymbol; }
+
+ Font3 (const PrinterGfx &rGfx);
+ ~Font3 () {}
+};
+
+Font3::Font3(const PrinterGfx &rGfx)
+{
+ mpFont[0] = rGfx.getFontSubstitute();
+ mpFont[1] = rGfx.GetFontID();
+ mpFont[2] = rGfx.getFallbackID();
+ // mpFont[2] = rGfx.GetFontID();
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ mbSymbol = mpFont[1] != -1 ?
+ rMgr.getFontEncoding(mpFont[1]) == RTL_TEXTENCODING_SYMBOL : false;
+}
+
+} // namespace psp
+
+static int getVerticalDeltaAngle( sal_Unicode nChar )
+{
+ int nAngle = 0;
+ if( ( nChar >= 0x1100 && nChar < 0x11fa ) ||
+ ( nChar >= 0x3000 && nChar < 0xfb00 ) ||
+ ( nChar >= 0xfe20 && nChar < 0xfe70 ) ||
+ ( nChar >= 0xff00 && nChar < 0xff64 )
+ )
+ {
+ /* #i52932# remember:
+ nChar == 0x2010 || nChar == 0x2015
+ nChar == 0x2016 || nChar == 0x2026
+
+ are nAngle = 0 also, but already handled in the first if
+ */
+ if( ( nChar >= 0x3008 && nChar < 0x3019 && nChar != 0x3012 ) ||
+ nChar == 0xff3b || nChar == 0xff3d ||
+ (nChar >= 0xff6b && nChar < 0xff64 ) ||
+ nChar == 0xffe3
+ )
+ nAngle = 0;
+ else if( nChar == 0x30fc )
+ nAngle = -900;
+ else
+ nAngle = 900;
+ }
+ return nAngle;
+}
+
+void
+PrinterGfx::PSUploadPS1Font (sal_Int32 nFontID)
+{
+ std::list< sal_Int32 >::iterator aFont;
+ // already in the document header ?
+ for (aFont = maPS1Font.begin(); aFont != maPS1Font.end(); ++aFont )
+ if( nFontID == *aFont )
+ return;
+
+ // no occurrenc yet, mark for download
+ // add the fontid to the list
+ maPS1Font.push_back (nFontID);
+}
+
+/*
+ * implement text handling printer routines,
+ */
+
+sal_uInt16
+PrinterGfx::SetFont(
+ sal_Int32 nFontID,
+ sal_Int32 nHeight,
+ sal_Int32 nWidth,
+ sal_Int32 nAngle,
+ bool bVertical,
+ bool bArtItalic,
+ bool bArtBold
+ )
+{
+ // font and encoding will be set by drawText again immediately
+ // before PSShowText
+ mnFontID = nFontID;
+ maVirtualStatus.maFont = rtl::OString();
+ maVirtualStatus.maEncoding = RTL_TEXTENCODING_DONTKNOW;
+ maVirtualStatus.mnTextHeight = nHeight;
+ maVirtualStatus.mnTextWidth = nWidth;
+ maVirtualStatus.mbArtItalic = bArtItalic;
+ maVirtualStatus.mbArtBold = bArtBold;
+ mnTextAngle = nAngle;
+ mbTextVertical = bVertical;
+
+ return 0;
+}
+
+sal_uInt16
+PrinterGfx::SetFallbackFont ( sal_Int32 nFontID )
+{
+ mnFallbackID = nFontID;
+ return 0;
+}
+
+void PrinterGfx::drawGlyphs(
+ const Point& rPoint,
+ sal_uInt32* pGlyphIds,
+ sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ sal_Int32* pDeltaArray
+ )
+{
+
+ // draw the string
+ // search for a glyph set matching the set font
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); aIter++)
+ if ( ((*aIter).GetFontID() == mnFontID)
+ && ((*aIter).IsVertical() == mbTextVertical))
+ {
+ (*aIter).DrawGlyphs (*this, rPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray);
+ break;
+ }
+
+ // not found ? create a new one
+ if (aIter == maPS3Font.end())
+ {
+ maPS3Font.push_back (GlyphSet(mnFontID, mbTextVertical));
+ maPS3Font.back().DrawGlyphs (*this, rPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray);
+ }
+}
+
+void PrinterGfx::DrawGlyphs(
+ const Point& rPoint,
+ sal_GlyphId* pGlyphIds,
+ sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ sal_Int32* pDeltaArray
+ )
+{
+ if( nLen <= 0 )
+ return;
+
+ if ( !mrFontMgr.isFontDownloadingAllowed( mnFontID ) )
+ {
+ LicenseWarning(rPoint, pUnicodes, nLen, pDeltaArray);
+ return;
+ }
+
+ if( mrFontMgr.getFontType( mnFontID ) != fonttype::TrueType )
+ {
+ DrawText( rPoint, pUnicodes, nLen, pDeltaArray );
+ return;
+ }
+
+ // move and rotate the user coordinate system
+ // avoid the gsave/grestore for the simple cases since it allows
+ // reuse of the current font if it hasn't changed
+ sal_Int32 nCurrentTextAngle = mnTextAngle;
+ Point aPoint( rPoint );
+
+ if (nCurrentTextAngle != 0)
+ {
+ PSGSave ();
+ PSTranslate (rPoint);
+ PSRotate (nCurrentTextAngle);
+ mnTextAngle = 0;
+ aPoint = Point( 0, 0 );
+ }
+
+ if( mbTextVertical )
+ {
+ // vertical glyphs can have an additional rotation ... sigh.
+ // so break up text in chunks of normal glyphs and print out
+ // specially rotated glyphs extra
+ sal_uInt32* pTempGlyphIds = (sal_uInt32*)alloca(sizeof(sal_Int32)*nLen);
+ sal_Int32* pTempDelta = (sal_Int32*)alloca(sizeof(sal_Int32)*nLen);
+ sal_Unicode* pTempUnicodes = (sal_Unicode*)alloca(sizeof(sal_Unicode)*nLen);
+ sal_Int16 nTempLen = 0;
+ sal_Int32 nTempFirstDelta = 0;
+ Point aRotPoint;
+ sal_Int32 nTextHeight = maVirtualStatus.mnTextHeight;
+ sal_Int32 nTextWidth = maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ sal_Int32 nAscend = mrFontMgr.getFontAscend( mnFontID );
+ sal_Int32 nDescend = mrFontMgr.getFontDescend( mnFontID );
+
+ nDescend = nDescend * nTextHeight / 1000;
+ nAscend = nAscend * nTextHeight / 1000;
+
+ for( sal_Int16 i = 0; i < nLen; i++ )
+ {
+ const sal_GlyphId nRot = pGlyphIds[i] & GF_ROTMASK;
+ if( nRot == GF_NONE )
+ {
+ pTempUnicodes[nTempLen] = pUnicodes[i];
+ pTempGlyphIds[nTempLen] = pGlyphIds[i];
+ if( nTempLen > 0 )
+ pTempDelta[nTempLen-1] = pDeltaArray[i-1]-nTempFirstDelta;
+ else
+ {
+ // the first element in pDeltaArray shows
+ // the offset of the second character
+ // so if the first glyph is normal
+ // then we do not need to move the delta indices
+ // else we have to move them down by one and
+ // recalculate aPoint and all deltas
+ if( i != 0 )
+ nTempFirstDelta = pDeltaArray[ i-1 ];
+ }
+ nTempLen++;
+ }
+ else
+ {
+ sal_Int32 nOffset = i > 0 ? pDeltaArray[i-1] : 0;
+ sal_Int32 nRotAngle = 0;
+ switch( nRot )
+ {
+ case GF_ROTR:
+ nRotAngle = 2700;
+ aRotPoint = Point( -nAscend*nTextWidth/nTextHeight, -nDescend*nTextWidth/nTextHeight - nOffset );
+ break;
+ case GF_VERT:
+ nRotAngle = 1800;
+ aRotPoint = Point( -nOffset, (nAscend+nDescend) );
+ break;
+ case GF_ROTL:
+ nRotAngle = 900;
+ aRotPoint = Point( -nDescend*nTextWidth/nTextHeight, nOffset + nAscend*nTextWidth/nTextHeight );
+ break;
+ }
+ sal_GlyphId nRotGlyphId = pGlyphIds[i];
+ sal_Unicode nRotUnicode = pUnicodes[i];
+ sal_Int32 nRotDelta = 0;
+
+ // transform matrix to new individual direction
+ PSGSave ();
+ GraphicsStatus aSaveStatus = maVirtualStatus;
+ if( nRot != 2 ) // switch font aspect
+ {
+ maVirtualStatus.mnTextWidth = nTextHeight;
+ maVirtualStatus.mnTextHeight = nTextWidth;
+ }
+ if( aPoint.X() || aPoint.Y() )
+ PSTranslate( aPoint );
+ PSRotate (nRotAngle);
+ // draw the rotated glyph
+ drawGlyphs( aRotPoint, &nRotGlyphId, &nRotUnicode, 1, &nRotDelta );
+
+ // restore previous state
+ maVirtualStatus = aSaveStatus;
+ PSGRestore();
+ }
+ }
+
+ pGlyphIds = pTempGlyphIds;
+ pUnicodes = pTempUnicodes;
+ pDeltaArray = pTempDelta;
+ nLen = nTempLen;
+
+ aPoint.X() += nTempFirstDelta;
+ }
+
+ if( nLen > 0 )
+ drawGlyphs( aPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray );
+
+ // restore the user coordinate system
+ if (nCurrentTextAngle != 0)
+ {
+ PSGRestore ();
+ mnTextAngle = nCurrentTextAngle;
+ }
+}
+
+void
+PrinterGfx::DrawText (
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ fontID nRestoreFont = mnFontID;
+
+ // setup font[substitutes] and map the string into the symbol area in case of
+ // symbol font
+ Font3 aFont(*this);
+ sal_Unicode *pEffectiveStr;
+ if ( aFont.IsSymbolFont() )
+ {
+ pEffectiveStr = (sal_Unicode*)alloca(nLen * sizeof(pStr[0]));
+ for (int i = 0; i < nLen; i++)
+ pEffectiveStr[i] = pStr[i] < 256 ? pStr[i] + 0xF000 : pStr[i];
+ }
+ else
+ {
+ pEffectiveStr = const_cast<sal_Unicode*>(pStr);
+ }
+
+ fontID *pFontMap = (fontID*) alloca(nLen * sizeof(fontID));
+ sal_Int32 *pCharWidth = (sal_Int32*) alloca(nLen * sizeof(sal_Int32));
+
+ for( int n = 0; n < nLen; n++ )
+ {
+ CharacterMetric aBBox;
+ pFontMap[n] = getCharMetric (aFont, pEffectiveStr[n], &aBBox);
+ pCharWidth[n] = getCharWidth (mbTextVertical, pEffectiveStr[n], &aBBox);
+ }
+
+ // setup a new delta array, use virtual resolution of 1000
+ sal_Int32* pNewDeltaArray = (sal_Int32*)alloca( sizeof( sal_Int32 )*nLen );
+ if ( pDeltaArray != 0)
+ {
+ for (int i = 0; i < nLen - 1; i++)
+ pNewDeltaArray[i] = 1000 * pDeltaArray[i];
+ pNewDeltaArray[nLen - 1] = 0;
+ }
+ else
+ {
+ pNewDeltaArray[0] = pCharWidth[0];
+ for (int i = 1; i < nLen; i++)
+ pNewDeltaArray[i] = pNewDeltaArray[i-1] + pCharWidth[i];
+ }
+
+ // move and rotate the user coordinate system
+ // avoid the gsave/grestore for the simple cases since it allows
+ // reuse of the current font if it hasn't changed
+ sal_Int32 nCurrentTextAngle = mnTextAngle;
+ sal_Int32 nCurrentPointX;
+ sal_Int32 nCurrentPointY;
+
+ if (nCurrentTextAngle != 0)
+ {
+ PSGSave ();
+ PSTranslate (rPoint);
+ PSRotate (nCurrentTextAngle);
+ mnTextAngle = 0;
+
+ nCurrentPointX = 0;
+ nCurrentPointY = 0;
+ }
+ else
+ {
+ nCurrentPointX = rPoint.X();
+ nCurrentPointY = rPoint.Y();
+ }
+
+ // draw the string
+ sal_Int32 nDelta = 0;
+ for (int nTo = 0; nTo < nLen; )
+ {
+ int nFrom = nTo;
+ fontID nFont = pFontMap[ nFrom ];
+
+ while ((nTo < nLen) && (nFont == pFontMap[nTo]))
+ {
+ pNewDeltaArray[ nTo ] = (sal_Int32)(((0.5 + pNewDeltaArray[ nTo ]) / 1000.0) - nDelta);
+ nTo++ ;
+ }
+
+ SetFont( nFont,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ mnTextAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold
+ );
+
+ if (mbTextVertical)
+ {
+ drawVerticalizedText(
+ Point(nCurrentPointX + nDelta, nCurrentPointY),
+ pEffectiveStr + nFrom, nTo - nFrom,
+ pNewDeltaArray + nFrom );
+ }
+ else
+ {
+ drawText(
+ Point(nCurrentPointX + nDelta, nCurrentPointY),
+ pEffectiveStr + nFrom, nTo - nFrom,
+ pDeltaArray == NULL ? NULL : pNewDeltaArray + nFrom );
+ }
+ nDelta += pNewDeltaArray[ nTo - 1 ];
+ }
+
+ // restore the user coordinate system
+ if (nCurrentTextAngle != 0)
+ {
+ PSGRestore ();
+ mnTextAngle = nCurrentTextAngle;
+ }
+
+ // restore the original font settings
+ SetFont( nRestoreFont,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ mnTextAngle, mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold
+ );
+}
+
+void PrinterGfx::drawVerticalizedText(
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ sal_Int32* pDelta = (sal_Int32*)alloca( nLen * sizeof(sal_Int32) );
+
+ int nTextScale = maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ int nNormalAngle = mnTextAngle;
+ int nDeltaAngle, nLastPos = 0;
+
+ double fSin = sin( -2.0*M_PI*nNormalAngle/3600 );
+ double fCos = cos( -2.0*M_PI*nNormalAngle/3600 );
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ PrintFontInfo aInfo;
+ rMgr.getFontInfo( mnFontID, aInfo );
+
+ bool* pGsubFlags = (bool*)alloca( nLen * sizeof(bool) );
+ rMgr.hasVerticalSubstitutions( mnFontID, pStr, nLen, pGsubFlags );
+
+ Point aPoint( rPoint );
+ for( int i = 0; i < nLen; )
+ {
+ while( ( nDeltaAngle = getVerticalDeltaAngle( pStr[i] ) ) == 0 && i < nLen )
+ i++;
+ if( i <= nLen && i > nLastPos )
+ {
+ for( int n = nLastPos; n < i; n++ )
+ pDelta[n] = pDeltaArray[n] - (aPoint.X() - rPoint.X() );
+
+ SetFont( mnFontID,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ nNormalAngle, mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+ drawText( aPoint, pStr + nLastPos, i - nLastPos, pDelta + nLastPos );
+
+ aPoint.X() = (sal_Int32)(rPoint.X() + ((double)pDeltaArray[i-1] * fCos));
+ aPoint.Y() = (sal_Int32)(rPoint.Y() + ((double)pDeltaArray[i-1] * fSin));
+ }
+ if( i < nLen )
+ {
+ int nOldWidth = maVirtualStatus.mnTextWidth;
+ int nOldHeight = maVirtualStatus.mnTextHeight;
+ SetFont( mnFontID,
+ nTextScale,
+ maVirtualStatus.mnTextHeight,
+ nNormalAngle + nDeltaAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+
+ double nA = nTextScale * aInfo.m_nAscend / 1000.0;
+ double nD = nTextScale * aInfo.m_nDescend / 1000.0;
+ double fStretch = (double)maVirtualStatus.mnTextWidth / maVirtualStatus.mnTextHeight;
+ if( !pGsubFlags[i] )
+ nD *= fStretch;
+
+ Point aPos( aPoint );
+ switch( nDeltaAngle )
+ {
+ case +900:
+ aPos.X() += (sal_Int32)(+nA * fCos + nD * fSin);
+ aPos.Y() += (sal_Int32)(-nA * fSin + nD * fCos);
+ break;
+ case -900:
+ aPos.X() += (sal_Int32)(+nA * fSin + nD * fCos);
+ aPos.Y() += (sal_Int32)(-(nTextScale*fStretch - nD) * fCos);
+ break;
+ }
+ drawText( aPos, pStr+i, 1, NULL );
+ if( i < nLen-1 && pDeltaArray )
+ {
+ aPoint.X() = (sal_Int32)(rPoint.X() + ((double)pDeltaArray[i] * fCos));
+ aPoint.Y() = (sal_Int32)(rPoint.Y() + ((double)pDeltaArray[i] * fSin));
+ }
+
+ // swap text width/height again
+ SetFont( mnFontID,
+ nOldHeight,
+ nOldWidth,
+ nNormalAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+ }
+ i++;
+ nLastPos = i;
+ }
+ mnTextAngle = nNormalAngle;
+}
+
+void
+PrinterGfx::LicenseWarning(const Point& rPoint, const sal_Unicode* pStr,
+ sal_Int16 nLen, const sal_Int32* pDeltaArray)
+{
+ // treat it like a builtin font in case a user has that font also in the
+ // printer. This is not so unlikely as it may seem; no print embedding
+ // licensed fonts are often used (or so they say) in companies:
+ // they are installed on displays and printers, but get not embedded in
+ // they are installed on displays and printers, but get not embedded in
+ // print files or documents because they are not licensed for use outside
+ // the company.
+ rtl::OString aMessage( "The font " );
+ aMessage += rtl::OUStringToOString( mrFontMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US );
+ aMessage += " could not be downloaded\nbecause its license does not allow for that";
+ PSComment( aMessage.getStr() );
+
+ rtl::OString aFontName = rtl::OUStringToOString(
+ mrFontMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US);
+ PSSetFont (aFontName, RTL_TEXTENCODING_ISO_8859_1);
+
+ sal_Size nSize = 4 * nLen;
+ sal_uChar* pBuffer = (sal_uChar*)alloca (nSize* sizeof(sal_uChar));
+
+ ConverterFactory* pCvt = GetConverterFactory ();
+ nSize = pCvt->Convert (pStr, nLen, pBuffer, nSize, RTL_TEXTENCODING_ISO_8859_1);
+
+ PSMoveTo (rPoint);
+ PSShowText (pBuffer, nLen, nSize, pDeltaArray);
+}
+
+void
+PrinterGfx::drawText(
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ if (!(nLen > 0))
+ return;
+
+ fonttype::type eType = mrFontMgr.getFontType (mnFontID);
+
+ if (eType == fonttype::Type1)
+ PSUploadPS1Font (mnFontID);
+
+ if ( eType == fonttype::TrueType
+ && !mrFontMgr.isFontDownloadingAllowed(mnFontID))
+ {
+ LicenseWarning(rPoint, pStr, nLen, pDeltaArray);
+ return;
+ }
+
+ if( mrFontMgr.getUseOnlyFontEncoding( mnFontID ) )
+ {
+ GlyphSet aGSet( mnFontID, mbTextVertical );
+ aGSet.DrawText( *this, rPoint, pStr, nLen, pDeltaArray );
+ return;
+ }
+
+ // search for a glyph set matching the set font
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); aIter++)
+ if ( ((*aIter).GetFontID() == mnFontID)
+ && ((*aIter).IsVertical() == mbTextVertical))
+ {
+ (*aIter).DrawText (*this, rPoint, pStr, nLen, pDeltaArray);
+ break;
+ }
+
+ // not found ? create a new one
+ if (aIter == maPS3Font.end())
+ {
+ maPS3Font.push_back (GlyphSet(mnFontID, mbTextVertical));
+ maPS3Font.back().DrawText (*this, rPoint, pStr, nLen, pDeltaArray);
+ }
+}
+
+int
+PrinterGfx::getCharWidth (sal_Bool b_vert, sal_Unicode n_char, CharacterMetric *p_bbox)
+{
+ b_vert = b_vert && (getVerticalDeltaAngle(n_char) != 0);
+ int w = b_vert ? p_bbox->height : p_bbox->width;
+ w *= maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ return w;
+}
+
+fontID
+PrinterGfx::getCharMetric (const Font3 &rFont, sal_Unicode n_char, CharacterMetric *p_bbox)
+{
+ p_bbox->width = -1;
+ p_bbox->height = -1;
+
+ for (fontID n = 0; n < 3; n++)
+ {
+ fontID n_font = rFont.GetFont(n);
+ if (n_font != -1)
+ {
+ if( mbStrictSO52Compatibility )
+ {
+ fonttype::type eType = mrFontMgr.getFontType( n_font );
+ if( (eType == fonttype::Builtin || eType == fonttype::Type1) )
+ {
+ // note: any character exchanged here MUST also be changed
+ // in the compatibility ISO encoding vector in the prolog
+ // in printerjob.cxx
+ sal_Unicode aRepl = 0;
+ if( n_char == 0x2d )
+ aRepl = 0x2212;
+ else if( n_char == 0x27 )
+ aRepl = 0x2019;
+ /*
+ additional characters that may need backwards compatibility:
+ ISO5589 StdEnc Unicode suggested n_char -> aRepl
+ 0264 0302 0x00B4 0x00B4 (acute) -> 0x2019 (quiteright)
+ 0246 - 0x00A6 0x00A6 (brokenbar) -> 0x007C (bar)
+ 0225 0267 0x0095 0x0095 () -> 0x2022 (bullet)
+ 0140 0301 0x0060 0x0060 (grave) -> ?
+ */
+ if( aRepl )
+ {
+ mrFontMgr.getMetrics( n_font, aRepl, aRepl, p_bbox );
+ if (p_bbox->width >= 0 && p_bbox->height >= 0)
+ return n_font;
+ }
+ }
+ }
+ mrFontMgr.getMetrics( n_font, n_char, n_char, p_bbox );
+ }
+ if (p_bbox->width >= 0 && p_bbox->height >= 0)
+ return n_font;
+ }
+ if (n_char != '?')
+ return getCharMetric (rFont, '?', p_bbox);
+
+ return rFont.GetFont(0) != -1 ? rFont.GetFont(0) : rFont.GetFont(1);
+}
+
+fontID
+PrinterGfx::getFontSubstitute () const
+{
+ if( mpFontSubstitutes )
+ {
+ ::std::hash_map< fontID, fontID >::const_iterator it =
+ mpFontSubstitutes->find( mnFontID );
+ if( it != mpFontSubstitutes->end() )
+ return it->second;
+ }
+
+ return -1;
+}
+
+sal_Int32
+PrinterGfx::GetCharWidth (sal_Unicode nFrom, sal_Unicode nTo, long *pWidthArray)
+{
+ Font3 aFont(*this);
+ if (aFont.IsSymbolFont() && (nFrom < 256) && (nTo < 256))
+ {
+ nFrom += 0xF000;
+ nTo += 0xF000;
+ }
+
+ for( int n = 0; n < (nTo - nFrom + 1); n++ )
+ {
+ CharacterMetric aBBox;
+ getCharMetric (aFont, n + nFrom, &aBBox);
+ pWidthArray[n] = getCharWidth (mbTextVertical, n + nFrom, &aBBox);
+ }
+
+ // returned metrics have postscript precision
+ return 1000;
+}
+
+const ::std::list< KernPair >& PrinterGfx::getKernPairs( bool bVertical ) const
+{
+ /*
+ * Note: this is only a 80% solution: if a font is only
+ * partially substituted in a string due to missing glyphs
+ * the results may not be perfect; the more so the more the
+ * substitution differs from the original metricwise. But
+ * vcl only asks for KernPairs for each font once and NOT
+ * in a string context this is the best we can do.
+ * In future the kerning should be done on a per string basis.
+ */
+ fontID nFont = mnFontID;
+ if( mpFontSubstitutes )
+ {
+ ::std::hash_map< fontID, fontID >::const_iterator it =
+ mpFontSubstitutes->find( mnFontID );
+ if( it != mpFontSubstitutes->end() )
+ nFont = it->second;
+ }
+ return mrFontMgr.getKernPairs( nFont, bVertical );
+}
+
+/*
+ * advanced glyph handling
+ */
+
+sal_Bool
+PrinterGfx::GetGlyphBoundRect (sal_Unicode /*c*/, Rectangle& /*rOutRect*/)
+{
+ return 0;
+}
+
+sal_uInt32
+PrinterGfx::GetGlyphOutline (sal_Unicode /*c*/,
+ sal_uInt16 **/*ppPolySizes*/, Point **/*ppPoints*/, sal_uInt8 **/*ppFlags*/)
+{
+ return 0;
+}
+
+/*
+ * spool the converted truetype fonts to the page header after the page body is
+ * complete
+ * for Type1 fonts spool additional reencoding vectors that are necessary to access the
+ * whole font
+ */
+
+void
+PrinterGfx::OnEndPage ()
+{
+}
+
+void
+PrinterGfx::OnEndJob ()
+{
+ maPS3Font.clear();
+ maPS1Font.clear();
+}
+
+void
+PrinterGfx::writeResources( osl::File* pFile, std::list< rtl::OString >& rSuppliedFonts, std::list< rtl::OString >& rNeededFonts )
+{
+ // write all type 1 fonts
+ std::list< sal_Int32 >::iterator aFont;
+ // already in the document header ?
+ for (aFont = maPS1Font.begin(); aFont != maPS1Font.end(); ++aFont)
+ {
+ const rtl::OString& rSysPath (mrFontMgr.getFontFileSysPath(*aFont) );
+ rtl::OUString aUNCPath;
+ osl::File::getFileURLFromSystemPath (OStringToOUString (rSysPath, osl_getThreadTextEncoding()), aUNCPath);
+ osl::File aFontFile (aUNCPath);
+
+ // provide the pfb or pfa font as a (pfa-)font resource
+ rtl::OString aPostScriptName =
+ rtl::OUStringToOString ( mrFontMgr.getPSName(*aFont),
+ RTL_TEXTENCODING_ASCII_US );
+
+ WritePS (pFile, "%%BeginResource: font ");
+ WritePS (pFile, aPostScriptName.getStr());
+ WritePS (pFile, "\n");
+
+ osl::File::RC nError = aFontFile.open (OpenFlag_Read);
+ if (nError == osl::File::E_None)
+ {
+ convertPfbToPfa (aFontFile, *pFile);
+ aFontFile.close ();
+
+ pFile->setPos(osl_Pos_Current, -1);
+ char lastchar = '\n';
+ sal_uInt64 uBytes(1);
+ pFile->read((void *)(&lastchar), uBytes, uBytes);
+ if (lastchar != '\n')
+ WritePS (pFile, "\n");
+ }
+ WritePS (pFile, "%%EndResource\n");
+ rSuppliedFonts.push_back( aPostScriptName );
+ }
+
+ // write glyphsets and reencodings
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); ++aIter)
+ {
+ if (aIter->GetFontType() == fonttype::TrueType)
+ {
+ aIter->PSUploadFont (*pFile, *this, mbUploadPS42Fonts ? true : false, rSuppliedFonts );
+ }
+ else
+ // ( aIter->GetFontType() == fonttype::Type1
+ // || aIter->GetFontType() == fonttype::Builtin )
+ {
+ aIter->PSUploadEncoding (pFile, *this);
+ if( aIter->GetFontType() == fonttype::Builtin )
+ rNeededFonts.push_back(
+ rtl::OUStringToOString(
+ mrFontMgr.getPSName( aIter->GetFontID() ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ }
+ }
+}
+
+bool PrinterGfx::getStrictSO52Compatibility() const
+{
+ return mbStrictSO52Compatibility;
+}
+
+void PrinterGfx::setStrictSO52Compatibility( bool bCompat)
+{
+ mbStrictSO52Compatibility = bCompat;
+}