| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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_GlyphId* 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_GlyphId* pTempGlyphIds = (sal_GlyphId*)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; |
| } |