summaryrefslogtreecommitdiff
path: root/vcl/os2/source/gdi/salgdi3.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/os2/source/gdi/salgdi3.cxx')
-rw-r--r--vcl/os2/source/gdi/salgdi3.cxx1756
1 files changed, 1756 insertions, 0 deletions
diff --git a/vcl/os2/source/gdi/salgdi3.cxx b/vcl/os2/source/gdi/salgdi3.cxx
new file mode 100644
index 000000000000..546f4bf2b7cd
--- /dev/null
+++ b/vcl/os2/source/gdi/salgdi3.cxx
@@ -0,0 +1,1756 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: salgdi3.cxx,v $
+ * $Revision: 1.8 $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#define INCL_GRE_STRINGS
+#define INCL_GPI
+#define INCL_DOS
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <svpm.h>
+
+#define _SV_SALGDI3_CXX
+#include <tools/svwin.h>
+#include <rtl/tencinfo.h>
+#ifndef _OSL_FILE_HXX
+#include <osl/file.hxx>
+#endif
+#ifndef _OSL_THREAD_HXX
+#include <osl/thread.hxx>
+#endif
+#ifndef _OSL_PROCESS_HXX
+#include <osl/process.h>
+#endif
+#include <vcl/svapp.hxx>
+#include <saldata.hxx>
+#include <salgdi.h>
+#include <vcl/font.hxx>
+#include <vcl/sallayout.hxx>
+#include <tools/poly.hxx>
+#include <tools/debug.hxx>
+#include <rtl/textcvt.h>
+#include <tools/debug.hxx>
+#include <saldata.hxx>
+#include <salgdi.h>
+#ifndef _SV_OUTFONT_HXX
+#include <vcl/outfont.hxx>
+#endif
+#include <sallayout.h>
+#include <tools/poly.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+#ifndef __H_FT2LIB
+#include <wingdi.h>
+#include <ft2lib.h>
+#endif
+
+#include "sft.hxx"
+
+#ifdef GCP_KERN_HACK
+#include <algorithm>
+#endif
+
+using namespace vcl;
+
+// -----------
+// - Inlines -
+// -----------
+
+
+inline W32FIXED FixedFromDouble( double d )
+{
+ const long l = (long) ( d * 65536. );
+ return *(W32FIXED*) &l;
+}
+
+// -----------------------------------------------------------------------
+
+inline int IntTimes256FromFixed(W32FIXED f)
+{
+ int nFixedTimes256 = (f.value << 8) + ((f.fract+0x80) >> 8);
+ return nFixedTimes256;
+}
+
+// -----------
+// - Defines -
+// -----------
+
+// this is a special codepage code, used to identify OS/2 symbol font.
+#define SYMBOL_CHARSET 65400
+
+// =======================================================================
+
+UniString ImplSalGetUniString( const sal_Char* pStr, xub_StrLen nLen = STRING_LEN)
+{
+ return UniString( pStr, nLen, gsl_getSystemTextEncoding(),
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
+}
+
+// =======================================================================
+
+static USHORT ImplSalToCharSet( CharSet eCharSet )
+{
+ // !!! Fuer DBCS-Systeme muss dieser Code auskommentiert werden und 0
+ // !!! zurueckgegeben werden, solange die DBCS-Charsets nicht
+ // !!! durchgereicht werden
+
+ switch ( eCharSet )
+ {
+ case RTL_TEXTENCODING_IBM_437:
+ return 437;
+
+ case RTL_TEXTENCODING_IBM_850:
+ return 850;
+
+ case RTL_TEXTENCODING_IBM_860:
+ return 860;
+
+ case RTL_TEXTENCODING_IBM_861:
+ return 861;
+
+ case RTL_TEXTENCODING_IBM_863:
+ return 863;
+
+ case RTL_TEXTENCODING_IBM_865:
+ return 865;
+ case RTL_TEXTENCODING_MS_1252:
+ return 1004;
+ case RTL_TEXTENCODING_SYMBOL:
+ return 65400;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static CharSet ImplCharSetToSal( USHORT usCodePage )
+{
+ switch ( usCodePage )
+ {
+ case 437:
+ return RTL_TEXTENCODING_IBM_437;
+
+ case 850:
+ return RTL_TEXTENCODING_IBM_850;
+
+ case 860:
+ return RTL_TEXTENCODING_IBM_860;
+
+ case 861:
+ return RTL_TEXTENCODING_IBM_861;
+
+ case 863:
+ return RTL_TEXTENCODING_IBM_863;
+
+ case 865:
+ return RTL_TEXTENCODING_IBM_865;
+ case 1004:
+ return RTL_TEXTENCODING_MS_1252;
+ case 65400:
+ return RTL_TEXTENCODING_SYMBOL;
+ }
+
+ return RTL_TEXTENCODING_DONTKNOW;
+}
+
+// -----------------------------------------------------------------------
+
+static FontFamily ImplFamilyToSal( BYTE bFamilyType )
+{
+ switch ( bFamilyType )
+ {
+ case 4:
+ return FAMILY_DECORATIVE;
+ case 3:
+ return FAMILY_SCRIPT;
+ }
+
+ return FAMILY_DONTKNOW;
+}
+
+// -----------------------------------------------------------------------
+
+static FontWeight ImplWeightToSal( USHORT nWeight )
+{
+ // Falls sich jemand an die alte Doku gehalten hat
+ if ( nWeight > 999 )
+ nWeight /= 1000;
+
+ switch ( nWeight )
+ {
+ case 1:
+ return WEIGHT_THIN;
+
+ case 2:
+ return WEIGHT_ULTRALIGHT;
+
+ case 3:
+ return WEIGHT_LIGHT;
+
+ case 4:
+ return WEIGHT_SEMILIGHT;
+
+ case 5:
+ return WEIGHT_NORMAL;
+
+ case 6:
+ return WEIGHT_SEMIBOLD;
+
+ case 7:
+ return WEIGHT_BOLD;
+
+ case 8:
+ return WEIGHT_ULTRABOLD;
+
+ case 9:
+ return WEIGHT_BLACK;
+ }
+
+ return WEIGHT_DONTKNOW;
+}
+
+// -----------------------------------------------------------------------
+
+static UniString ImpStyleNameToSal( const char* pFamilyName,
+ const char* pFaceName,
+ USHORT nLen )
+{
+ if ( !nLen )
+ nLen = strlen(pFamilyName);
+
+ // strip FamilyName from FaceName
+ if ( strncmp( pFamilyName, pFaceName, nLen ) == 0 )
+ {
+ USHORT nFaceLen = (USHORT)strlen( pFaceName+nLen );
+ // Ist Facename laenger, schneiden wir den FamilyName ab
+ if ( nFaceLen > 1 )
+ return UniString( pFaceName+(nLen+1), gsl_getSystemTextEncoding());
+ else
+ return UniString();
+ }
+ else
+ return UniString( pFaceName, gsl_getSystemTextEncoding());
+}
+
+// -----------------------------------------------------------------------
+
+inline FontPitch ImplLogPitchToSal( BYTE fsType )
+{
+ if ( fsType & FM_TYPE_FIXED )
+ return PITCH_FIXED;
+ else
+ return PITCH_VARIABLE;
+}
+
+// -----------------------------------------------------------------------
+
+inline BYTE ImplPitchToWin( FontPitch ePitch )
+{
+ if ( ePitch == PITCH_FIXED )
+ return FM_TYPE_FIXED;
+ //else if ( ePitch == PITCH_VARIABLE )
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static ImplDevFontAttributes Os2Font2DevFontAttributes( const PFONTMETRICS pFontMetric)
+{
+ ImplDevFontAttributes aDFA;
+
+ // get font face attributes
+ aDFA.meFamily = ImplFamilyToSal( pFontMetric->panose.bFamilyType);
+ aDFA.meWidthType = WIDTH_DONTKNOW;
+ aDFA.meWeight = ImplWeightToSal( pFontMetric->usWeightClass);
+ aDFA.meItalic = (pFontMetric->fsSelection & FM_SEL_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE;
+ aDFA.mePitch = ImplLogPitchToSal( pFontMetric->fsType );
+ aDFA.mbSymbolFlag = (pFontMetric->usCodePage == SYMBOL_CHARSET);
+
+ // get the font face name
+ // the maName field stores the font name without the style, so under OS/2
+ // we must use the family name
+ aDFA.maName = UniString( pFontMetric->szFamilyname, gsl_getSystemTextEncoding());
+
+ aDFA.maStyleName = ImpStyleNameToSal( pFontMetric->szFamilyname,
+ pFontMetric->szFacename,
+ strlen( pFontMetric->szFamilyname) );
+
+ // get device specific font attributes
+ aDFA.mbOrientation = (pFontMetric->fsDefn & FM_DEFN_OUTLINE) != 0;
+ aDFA.mbDevice = (pFontMetric->fsDefn & FM_DEFN_GENERIC) ? FALSE : TRUE;
+
+ aDFA.mbEmbeddable = false;
+ aDFA.mbSubsettable = false;
+ DWORD fontType = Ft2QueryFontType( 0, pFontMetric->szFamilyname);
+ if( fontType == FT2_FONTTYPE_TRUETYPE && !aDFA.mbDevice)
+ aDFA.mbSubsettable = true;
+ // for now we can only embed Type1 fonts
+ if( fontType == FT2_FONTTYPE_TYPE1 )
+ aDFA.mbEmbeddable = true;
+
+ // heuristics for font quality
+ // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
+ // - subsetting > embedding > none
+ aDFA.mnQuality = 0;
+ if( fontType == FT2_FONTTYPE_TRUETYPE )
+ aDFA.mnQuality += 50;
+ if( aDFA.mbSubsettable )
+ aDFA.mnQuality += 200;
+ else if( aDFA.mbEmbeddable )
+ aDFA.mnQuality += 100;
+
+ // #i38665# prefer Type1 versions of the standard postscript fonts
+ if( aDFA.mbEmbeddable )
+ {
+ if( aDFA.maName.EqualsAscii( "AvantGarde" )
+ || aDFA.maName.EqualsAscii( "Bookman" )
+ || aDFA.maName.EqualsAscii( "Courier" )
+ || aDFA.maName.EqualsAscii( "Helvetica" )
+ || aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
+ || aDFA.maName.EqualsAscii( "Palatino" )
+ || aDFA.maName.EqualsAscii( "Symbol" )
+ || aDFA.maName.EqualsAscii( "Times" )
+ || aDFA.maName.EqualsAscii( "ZapfChancery" )
+ || aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
+ aDFA.mnQuality += 500;
+ }
+
+ aDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW;
+ aDFA.meAntiAlias = ANTIALIAS_DONTKNOW;
+
+ // TODO: add alias names
+
+ return aDFA;
+}
+
+// =======================================================================
+
+// -----------------------------------------------------------------------
+
+// =======================================================================
+
+ImplOs2FontData::ImplOs2FontData( PFONTMETRICS _pFontMetric,
+ int nHeight, BYTE nPitchAndFamily )
+: ImplFontData( Os2Font2DevFontAttributes(_pFontMetric), 0 ),
+ pFontMetric( _pFontMetric ),
+ meOs2CharSet( _pFontMetric->usCodePage),
+ mnPitchAndFamily( nPitchAndFamily ),
+ mpFontCharSets( NULL ),
+ mpUnicodeMap( NULL ),
+ mbDisableGlyphApi( false ),
+ mbHasKoreanRange( false ),
+ mbHasCJKSupport( false ),
+ mbAliasSymbolsLow( false ),
+ mbAliasSymbolsHigh( false ),
+ mnId( 0 )
+{
+ SetBitmapSize( 0, nHeight );
+}
+
+// -----------------------------------------------------------------------
+
+ImplOs2FontData::~ImplOs2FontData()
+{
+ delete[] mpFontCharSets;
+
+ if( mpUnicodeMap )
+ mpUnicodeMap->DeReference();
+}
+
+// -----------------------------------------------------------------------
+
+sal_IntPtr ImplOs2FontData::GetFontId() const
+{
+ return mnId;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplOs2FontData::UpdateFromHPS( HPS hPS ) const
+{
+ // short circuit if already initialized
+ if( mpUnicodeMap != NULL )
+ return;
+
+ ReadCmapTable( hPS );
+ ReadOs2Table( hPS );
+
+ // even if the font works some fonts have problems with the glyph API
+ // => the heuristic below tries to figure out which fonts have the problem
+ DWORD fontType = Ft2QueryFontType( 0, pFontMetric->szFacename);
+ if( fontType != FT2_FONTTYPE_TRUETYPE
+ && (pFontMetric->fsDefn & FM_DEFN_GENERIC) == 0)
+ mbDisableGlyphApi = true;
+}
+
+// -----------------------------------------------------------------------
+
+#ifdef GNG_VERT_HACK
+bool ImplOs2FontData::HasGSUBstitutions( HPS hPS ) const
+{
+ if( !mbGsubRead )
+ ReadGsubTable( hPS );
+ return !maGsubTable.empty();
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplOs2FontData::IsGSUBstituted( sal_Ucs cChar ) const
+{
+ return( maGsubTable.find( cChar ) != maGsubTable.end() );
+}
+#endif // GNG_VERT_HACK
+
+// -----------------------------------------------------------------------
+
+ImplFontCharMap* ImplOs2FontData::GetImplFontCharMap() const
+{
+ mpUnicodeMap->AddReference();
+ return mpUnicodeMap;
+}
+
+// -----------------------------------------------------------------------
+
+static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
+static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
+static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
+static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
+
+void ImplOs2FontData::ReadOs2Table( HPS hPS ) const
+{
+ const DWORD Os2Tag = CalcTag( "OS/2" );
+ DWORD nLength = Ft2GetFontData( hPS, Os2Tag, 0, NULL, 0 );
+ if( (nLength == FT2_ERROR) || !nLength )
+ return;
+ std::vector<unsigned char> aOS2map( nLength );
+ unsigned char* pOS2map = &aOS2map[0];
+ DWORD nRC = Ft2GetFontData( hPS, Os2Tag, 0, pOS2map, nLength );
+ sal_uInt32 nVersion = GetUShort( pOS2map );
+ if ( nVersion >= 0x0001 && nLength >= 58 )
+ {
+ // We need at least version 0x0001 (TrueType rev 1.66)
+ // to have access to the needed struct members.
+ sal_uInt32 ulUnicodeRange1 = GetUInt( pOS2map + 42 );
+ sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
+ sal_uInt32 ulUnicodeRange3 = GetUInt( pOS2map + 50 );
+ sal_uInt32 ulUnicodeRange4 = GetUInt( pOS2map + 54 );
+
+ // Check for CJK capabilities of the current font
+ mbHasCJKSupport = (ulUnicodeRange2 & 0x2fff0000)
+ | (ulUnicodeRange3 & 0x00000001);
+ mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000)
+ | (ulUnicodeRange2 & 0x01100000);
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+#ifdef GNG_VERT_HACK
+void ImplOs2FontData::ReadGsubTable( HPS hPS ) const
+{
+ mbGsubRead = true;
+
+ // check the existence of a GSUB table
+ const DWORD GsubTag = CalcTag( "GSUB" );
+ DWORD nRC = Ft2GetFontData( hPS, GsubTag, 0, NULL, 0 );
+ if( (nRC == FT2_ERROR) || !nRC )
+ return;
+
+ // TODO: directly read the GSUB table instead of going through sft
+
+ // get raw font file data
+ DWORD nFontSize = Ft2GetFontData( hPS, 0, 0, NULL, 0 );
+ if( nFontSize == FT2_ERROR )
+ return;
+ std::vector<char> aRawFont( nFontSize+1 );
+ aRawFont[ nFontSize ] = 0;
+ DWORD nFontSize2 = Ft2GetFontData( hPS, 0, 0, (void*)&aRawFont[0], nFontSize );
+ if( nFontSize != nFontSize2 )
+ return;
+
+ // open font file
+ sal_uInt32 nFaceNum = 0;
+ if( !aRawFont[0] ) // TTC candidate
+ nFaceNum = ~0U; // indicate "TTC font extracts only"
+
+ TrueTypeFont* pTTFont = NULL;
+ ::OpenTTFontBuffer( &aRawFont[0], nFontSize, nFaceNum, &pTTFont );
+ if( !pTTFont )
+ return;
+
+ // add vertically substituted characters to list
+ static const sal_Unicode aGSUBCandidates[] = {
+ 0x0020, 0x0080, // ASCII
+ 0x2000, 0x2600, // misc
+ 0x3000, 0x3100, // CJK punctutation
+ 0x3300, 0x3400, // squared words
+ 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
+ 0 };
+
+ for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
+ for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
+ if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
+ maGsubTable.insert( cChar ); // insert GSUBbed unicodes
+
+ CloseTTFont( pTTFont );
+
+#if 0
+ TrueTypeFont* pTTFont = NULL;
+ ::OpenTTFont( &aRawFont[0], nFontSize, nFaceNum, &pTTFont );
+ if( !pTTFont )
+ return;
+
+ // add vertically substituted characters to list
+ static const sal_Unicode aGSUBCandidates[] = {
+ 0x0020, 0x0080, // ASCII
+ 0x2000, 0x2600, // misc
+ 0x3000, 0x3100, // CJK punctutation
+ 0x3300, 0x3400, // squared words
+ 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
+ 0 };
+
+ for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
+ for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
+ if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
+ maGsubTable.insert( cChar ); // insert GSUBbed unicodes
+
+ CloseTTFont( pTTFont );
+#endif
+}
+#endif // GNG_VERT_HACK
+
+// -----------------------------------------------------------------------
+
+void ImplOs2FontData::ReadCmapTable( HPS hPS ) const
+{
+ CmapResult aResult;
+ aResult.mnPairCount = 0;
+ aResult.mbSymbolic = (meOs2CharSet == SYMBOL_CHARSET);
+ aResult.mbRecoded = true;
+
+ // get the CMAP table from the font which is selected into the DC
+ const DWORD CmapTag = CalcTag( "cmap" );
+ DWORD nRC = Ft2GetFontData( hPS, CmapTag, 0, NULL, 0 );
+ // read the CMAP table if available
+ if( nRC != FT2_ERROR )
+ {
+ const int nLength = nRC;
+ std::vector<unsigned char> aCmap( nLength );
+ unsigned char* pCmap = &aCmap[0];
+ nRC = Ft2GetFontData( hPS, CmapTag, 0, pCmap, nLength );
+ // parse the CMAP table
+ if( nRC == nLength )
+ ParseCMAP( pCmap, nLength, aResult );
+ } else {
+ // we need to define at least a simple charmap, otherwise this font
+ // will be mapped to default charmap, and OOo doesn't accept the
+ // system font to match the default charmap
+ aResult.mnPairCount = 1;
+ // ImplFontCharMap destructor will free this memory
+ aResult.mpPairCodes = new sal_uInt32[ 2 * aResult.mnPairCount ];
+ aResult.mpPairCodes[0] = 0x0020;
+ aResult.mpPairCodes[1] = 0x00FF;
+ aResult.mpStartGlyphs = NULL;
+ }
+
+ mbDisableGlyphApi |= aResult.mbRecoded;
+
+ if( aResult.mnPairCount > 0 )
+ mpUnicodeMap = new ImplFontCharMap( aResult.mnPairCount,
+ aResult.mpPairCodes, aResult.mpStartGlyphs );
+ else
+ mpUnicodeMap = ImplFontCharMap::GetDefaultMap();
+}
+
+// =======================================================================
+
+void Os2SalGraphics::SetTextColor( SalColor nSalColor )
+{
+ CHARBUNDLE cb;
+
+ cb.lColor = RGBCOLOR( SALCOLOR_RED( nSalColor ),
+ SALCOLOR_GREEN( nSalColor ),
+ SALCOLOR_BLUE( nSalColor ) );
+
+ // set default color attributes
+ Ft2SetAttrs( mhPS,
+ PRIM_CHAR,
+ CBB_COLOR,
+ 0,
+ &cb );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Os2SalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, int nFallbackLevel)
+{
+
+#if OSL_DEBUG_LEVEL>10
+ debug_printf( "Os2SalGraphics::ImplDoSetFont\n");
+#endif
+
+ ImplOs2FontData* pFontData = (ImplOs2FontData*)i_pFont->mpFontData;
+ PFONTMETRICS pFontMetric = NULL;
+ FATTRS aFAttrs;
+ BOOL bOutline = FALSE;
+ APIRET rc;
+
+ memset( &aFAttrs, 0, sizeof( FATTRS ) );
+ aFAttrs.usRecordLength = sizeof( FATTRS );
+
+ aFAttrs.lMaxBaselineExt = i_pFont->mnHeight;
+ aFAttrs.lAveCharWidth = i_pFont->mnWidth;
+
+ // do we have a pointer to the FONTMETRICS of the selected font? -> use it!
+ if ( pFontData )
+ {
+ pFontMetric = pFontData->GetFontMetrics();
+
+ bOutline = (pFontMetric->fsDefn & FM_DEFN_OUTLINE) != 0;
+
+ // use match&registry fields to get correct match
+ aFAttrs.lMatch = pFontMetric->lMatch;
+ aFAttrs.idRegistry = pFontMetric->idRegistry;
+ aFAttrs.usCodePage = pFontMetric->usCodePage;
+
+ if ( bOutline )
+ {
+ aFAttrs.fsFontUse |= FATTR_FONTUSE_OUTLINE;
+ if ( i_pFont->mnOrientation )
+ aFAttrs.fsFontUse |= FATTR_FONTUSE_TRANSFORMABLE;
+ }
+ else
+ {
+ aFAttrs.lMaxBaselineExt = pFontMetric->lMaxBaselineExt;
+ aFAttrs.lAveCharWidth = pFontMetric->lAveCharWidth;
+ }
+
+ }
+
+ // use family name for outline fonts
+ if ( mbPrinter ) {
+ // use font face name for printers because otherwise ft2lib will fail
+ // to select the correct font for GPI (ticket#117)
+ strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFacename, sizeof( aFAttrs.szFacename ) );
+ } else if ( !pFontMetric) {
+ // use OOo name if fontmetrics not available!
+ ByteString aName( i_pFont->maName.GetToken( 0 ), gsl_getSystemTextEncoding());
+ strncpy( (char*)(aFAttrs.szFacename), aName.GetBuffer(), sizeof( aFAttrs.szFacename ) );
+ } else if ( bOutline) {
+ // use fontmetric family name for outline fonts
+ strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFamilyname, sizeof( aFAttrs.szFacename ) );
+ } else {
+ // use real font face name for bitmaps (WarpSans only)
+ strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFacename, sizeof( aFAttrs.szFacename ) );
+ }
+
+ if ( i_pFont->meItalic != ITALIC_NONE )
+ aFAttrs.fsSelection |= FATTR_SEL_ITALIC;
+ if ( i_pFont->meWeight > WEIGHT_MEDIUM )
+ aFAttrs.fsSelection |= FATTR_SEL_BOLD;
+
+#if OSL_DEBUG_LEVEL>1
+ if (pFontMetric->szFacename[0] == 'A') {
+ debug_printf( "Os2SalGraphics::SetFont hps %x lMatch '%d'\n", mhPS, pFontMetric->lMatch);
+ debug_printf( "Os2SalGraphics::SetFont hps %x fontmetrics facename '%s'\n", mhPS, pFontMetric->szFacename);
+ debug_printf( "Os2SalGraphics::SetFont hps %x fattrs facename '%s'\n", mhPS, aFAttrs.szFacename);
+ }
+#endif
+
+ Ft2DeleteSetId( mhPS, nFallbackLevel + LCID_BASE);
+ if ( (rc=Ft2CreateLogFont( mhPS, NULL, nFallbackLevel + LCID_BASE, &aFAttrs)) == GPI_ERROR ) {
+#if OSL_DEBUG_LEVEL>1
+ ERRORID nLastError = WinGetLastError( GetSalData()->mhAB );
+ debug_printf( "Os2SalGraphics::SetFont hps %x Ft2CreateLogFont failed err %x\n", mhPS, nLastError );
+#endif
+ return SAL_SETFONT_REMOVEANDMATCHNEW;
+ }
+
+ CHARBUNDLE aBundle;
+
+ ULONG nAttrsDefault = 0;
+ ULONG nAttrs = CBB_SET;
+ aBundle.usSet = nFallbackLevel + LCID_BASE;
+
+ if ( bOutline )
+ {
+ nAttrs |= CBB_BOX;
+ aBundle.sizfxCell.cy = MAKEFIXED( i_pFont->mnHeight, 0 );
+
+ if ( !i_pFont->mnWidth )
+ {
+ LONG nXFontRes;
+ LONG nYFontRes;
+ LONG nHeight;
+
+ // Auf die Aufloesung achten, damit das Ergebnis auch auf
+ // Drucken mit 180*360 DPI stimmt. Ausserdem muss gerundet
+ // werden, da auf meinem OS2 beispielsweise als
+ // Bildschirmaufloesung 3618*3622 PixelPerMeter zurueck-
+ // gegeben wird
+ GetResolution( nXFontRes, nYFontRes );
+ nHeight = i_pFont->mnHeight;
+ nHeight *= nXFontRes;
+ nHeight += nYFontRes/2;
+ nHeight /= nYFontRes;
+ aBundle.sizfxCell.cx = MAKEFIXED( nHeight, 0 );
+ }
+ else
+ aBundle.sizfxCell.cx = MAKEFIXED( i_pFont->mnWidth, 0 );
+ }
+
+ // set orientation for outlinefonts
+ if ( i_pFont->mnOrientation )
+ {
+ if ( bOutline )
+ {
+ nAttrs |= CBB_ANGLE;
+ double alpha = (double)(i_pFont->mnOrientation);
+ alpha *= 0.0017453292; // *PI / 1800
+ mnOrientationY = (long) (1000.0 * sin( alpha ));
+ mnOrientationX = (long) (1000.0 * cos( alpha ));
+ aBundle.ptlAngle.x = mnOrientationX;
+ aBundle.ptlAngle.y = mnOrientationY;
+ }
+ else
+ {
+ mnOrientationX = 1;
+ mnOrientationY = 0;
+ nAttrs |= CBB_ANGLE;
+ aBundle.ptlAngle.x = 1;
+ aBundle.ptlAngle.y = 0;
+ }
+ }
+ else
+ {
+ mnOrientationX = 1;
+ mnOrientationY = 0;
+ nAttrs |= CBB_ANGLE;
+ aBundle.ptlAngle.x = 1;
+ aBundle.ptlAngle.y = 0;
+ }
+
+ rc = Ft2SetAttrs( mhPS, PRIM_CHAR, nAttrs, nAttrsDefault, &aBundle );
+
+#if OSL_DEBUG_LEVEL>1
+ FONTMETRICS aOS2Metric = {0};
+ Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
+#endif
+
+ return 0;
+}
+
+
+USHORT Os2SalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel )
+{
+
+ // return early if there is no new font
+ if( !pFont )
+ {
+#if 0
+ // deselect still active font
+ if( mhDefFont )
+ Ft2SetCharSet( mhPS, mhDefFont );
+ // release no longer referenced font handles
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( mhFonts[i] )
+ Ft2DeleteSetId( mhPS, mhFonts[i] );
+ mhFonts[ i ] = 0;
+ }
+#endif
+ mhDefFont = 0;
+ return 0;
+ }
+
+#if OSL_DEBUG_LEVEL>10
+ debug_printf( "Os2SalGraphics::SetFont\n");
+#endif
+
+ DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL");
+ mpOs2FontEntry[ nFallbackLevel ] = reinterpret_cast<ImplOs2FontEntry*>( pFont->mpFontEntry );
+ mpOs2FontData[ nFallbackLevel ] = static_cast<const ImplOs2FontData*>( pFont->mpFontData );
+
+ ImplDoSetFont( pFont, mfFontScale, nFallbackLevel);
+
+ if( !mhDefFont )
+ {
+ // keep default font
+ mhDefFont = nFallbackLevel + LCID_BASE;
+ }
+ else
+ {
+ // release no longer referenced font handles
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( mhFonts[i] )
+ {
+#if 0
+ Ft2DeleteSetId( mhPS, mhFonts[i] );
+#endif
+ mhFonts[i] = 0;
+ }
+ }
+ }
+
+ // store new font in correct layer
+ mhFonts[ nFallbackLevel ] = nFallbackLevel + LCID_BASE;
+
+ // now the font is live => update font face
+ if( mpOs2FontData[ nFallbackLevel ] )
+ mpOs2FontData[ nFallbackLevel ]->UpdateFromHPS( mhPS );
+
+ if( !nFallbackLevel )
+ {
+ mbFontKernInit = TRUE;
+ if ( mpFontKernPairs )
+ {
+ delete[] mpFontKernPairs;
+ mpFontKernPairs = NULL;
+ }
+ mnFontKernPairCount = 0;
+ }
+
+ // some printers have higher internal resolution, so their
+ // text output would be different from what we calculated
+ // => suggest DrawTextArray to workaround this problem
+ if ( mbPrinter )
+ return SAL_SETFONT_USEDRAWTEXTARRAY;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::GetFontMetric( ImplFontMetricData* pMetric )
+{
+ FONTMETRICS aOS2Metric;
+ Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
+
+#if OSL_DEBUG_LEVEL>1
+ debug_printf( "Os2SalGraphics::GetFontMetric hps %x\n", mhPS);
+ if (aOS2Metric.szFacename[0] == 'A') {
+ debug_printf( "Os2SalGraphics::GetFontMetric hps %x fontmetrics facename '%s'\n", mhPS, aOS2Metric.szFacename);
+ debug_printf( "Os2SalGraphics::GetFontMetric hps %x fontmetrics lMatch '%d'\n", mhPS, aOS2Metric.lMatch);
+ }
+#endif
+
+ pMetric->maName = UniString( aOS2Metric.szFamilyname, gsl_getSystemTextEncoding());
+ pMetric->maStyleName = ImpStyleNameToSal( aOS2Metric.szFamilyname,
+ aOS2Metric.szFacename,
+ strlen( aOS2Metric.szFamilyname ) );
+
+ // device independent font attributes
+ pMetric->meFamily = ImplFamilyToSal( aOS2Metric.panose.bFamilyType);
+ pMetric->mbSymbolFlag = (aOS2Metric.usCodePage == SYMBOL_CHARSET);
+ pMetric->meWeight = ImplWeightToSal( aOS2Metric.usWeightClass );
+ pMetric->mePitch = ImplLogPitchToSal( aOS2Metric.fsType );
+ pMetric->meItalic = (aOS2Metric.fsSelection & FM_SEL_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE;
+ pMetric->mnSlant = 0;
+
+ // device dependend font attributes
+ pMetric->mbDevice = (aOS2Metric.fsDefn & FM_DEFN_GENERIC) ? FALSE : TRUE;
+ pMetric->mbScalableFont = (aOS2Metric.fsDefn & FM_DEFN_OUTLINE) ? true : false;
+ if( pMetric->mbScalableFont )
+ {
+ // check if there are kern pairs
+ // TODO: does this work with GPOS kerning?
+ pMetric->mbKernableFont = (aOS2Metric.sKerningPairs > 0);
+ }
+ else
+ {
+ // bitmap fonts cannot be rotated directly
+ pMetric->mnOrientation = 0;
+ // bitmap fonts have no kerning
+ pMetric->mbKernableFont = false;
+ }
+
+ // transformation dependend font metrics
+ if ( aOS2Metric.fsDefn & FM_DEFN_OUTLINE )
+ {
+ pMetric->mnWidth = aOS2Metric.lEmInc;
+ }
+ else
+ {
+ pMetric->mnWidth = aOS2Metric.lAveCharWidth;
+ pMetric->mnOrientation = 0;
+ }
+ pMetric->mnIntLeading = aOS2Metric.lInternalLeading;
+ pMetric->mnExtLeading = aOS2Metric.lExternalLeading;
+ pMetric->mnAscent = aOS2Metric.lMaxAscender;
+ pMetric->mnDescent = aOS2Metric.lMaxDescender;
+
+ // #107888# improved metric compatibility for Asian fonts...
+ // TODO: assess workaround below for CWS >= extleading
+ // TODO: evaluate use of aWinMetric.sTypo* members for CJK
+ if( mpOs2FontData[0] && mpOs2FontData[0]->SupportsCJK() )
+ {
+ pMetric->mnIntLeading += pMetric->mnExtLeading;
+
+ // #109280# The line height for Asian fonts is too small.
+ // Therefore we add half of the external leading to the
+ // ascent, the other half is added to the descent.
+ const long nHalfTmpExtLeading = pMetric->mnExtLeading / 2;
+ const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading;
+
+ // #110641# external leading for Asian fonts.
+ // The factor 0.3 has been confirmed with experiments.
+ long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent));
+ nCJKExtLeading -= pMetric->mnExtLeading;
+ pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0;
+
+ pMetric->mnAscent += nHalfTmpExtLeading;
+ pMetric->mnDescent += nOtherHalfTmpExtLeading;
+
+ // #109280# HACK korean only: increase descent for wavelines and impr
+ // YD win9x only
+ }
+
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Os2SalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs )
+{
+ DBG_ASSERT( sizeof( KERNINGPAIRS ) == sizeof( ImplKernPairData ),
+ "Os2SalGraphics::GetKernPairs(): KERNINGPAIRS != ImplKernPairData" );
+
+ if ( mbFontKernInit )
+ {
+ if( mpFontKernPairs )
+ {
+ delete[] mpFontKernPairs;
+ mpFontKernPairs = NULL;
+ }
+ mnFontKernPairCount = 0;
+
+ {
+ KERNINGPAIRS* pPairs = NULL;
+ FONTMETRICS aOS2Metric;
+ Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
+ int nCount = aOS2Metric.sKerningPairs;
+ if( nCount )
+ {
+#ifdef GCP_KERN_HACK
+ pPairs = new KERNINGPAIRS[ nCount+1 ];
+ mpFontKernPairs = pPairs;
+ mnFontKernPairCount = nCount;
+ Ft2QueryKerningPairs( mhPS, nCount, (KERNINGPAIRS*)pPairs );
+#else // GCP_KERN_HACK
+ pPairs = (KERNINGPAIRS*)pKernPairs;
+ nCount = (nCount < nPairs) ? nCount : nPairs;
+ Ft2QueryKerningPairs( mhPS, nCount, (KERNINGPAIRS*)pPairs );
+ return nCount;
+#endif // GCP_KERN_HACK
+ }
+ }
+
+ mbFontKernInit = FALSE;
+
+ std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
+ }
+
+ if( !pKernPairs )
+ return mnFontKernPairCount;
+ else if( mpFontKernPairs )
+ {
+ if ( nPairs < mnFontKernPairCount )
+ nPairs = mnFontKernPairCount;
+ memcpy( pKernPairs, mpFontKernPairs,
+ nPairs*sizeof( ImplKernPairData ) );
+ return nPairs;
+ }
+
+ return 0;
+}
+
+
+// -----------------------------------------------------------------------
+
+static ImplFontCharMap* pOs2DefaultImplFontCharMap = NULL;
+static const sal_uInt32 pOs2DefaultRangeCodes[] = {0x0020,0x00FF};
+
+ImplFontCharMap* Os2SalGraphics::GetImplFontCharMap() const
+{
+ if( !mpOs2FontData[0] )
+ return ImplFontCharMap::GetDefaultMap();
+ return mpOs2FontData[0]->GetImplFontCharMap();
+}
+
+// -----------------------------------------------------------------------
+
+bool Os2SalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
+ const String& rFontFileURL, const String& rFontName )
+{
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalGraphics::AddTempDevFont\n");
+#endif
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::GetDevFontList( ImplDevFontList* pList )
+{
+ PFONTMETRICS pFontMetrics;
+ ULONG nFontMetricCount;
+ SalData* pSalData;
+
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalGraphics::GetDevFontList\n");
+#endif
+
+ // install OpenSymbol
+ HMODULE hMod;
+ ULONG ObjNum, Offset, rc;
+ CHAR Buff[2*_MAX_PATH];
+ char drive[_MAX_DRIVE], dir[_MAX_DIR];
+ char fname[_MAX_FNAME], ext[_MAX_EXT];
+ // get module handle (and name)
+ rc = DosQueryModFromEIP( &hMod, &ObjNum, sizeof( Buff), Buff,
+ &Offset, (ULONG)ImplSalGetUniString);
+ DosQueryModuleName(hMod, sizeof(Buff), Buff);
+ // replace module path with font path
+ char* slash = strrchr( Buff, '\\');
+ *slash = '\0';
+ slash = strrchr( Buff, '\\');
+ *slash = '\0';
+ strcat( Buff, "\\SHARE\\FONTS\\TRUETYPE\\OPENS___.TTF");
+ rc = GpiLoadPublicFonts( GetSalData()->mhAB, Buff);
+
+ if ( !mbPrinter )
+ {
+ // Bei Bildschirm-Devices cachen wir die Liste global, da
+ // dies im unabhaengigen Teil auch so gemacht wird und wir
+ // ansonsten auf geloeschten Systemdaten arbeiten koennten
+ pSalData = GetSalData();
+ nFontMetricCount = pSalData->mnFontMetricCount;
+ pFontMetrics = pSalData->mpFontMetrics;
+ // Bei Bildschirm-Devices holen wir uns die Fontliste jedesmal neu
+ if ( pFontMetrics )
+ {
+ delete pFontMetrics;
+ pFontMetrics = NULL;
+ nFontMetricCount = 0;
+ }
+ }
+ else
+ {
+ nFontMetricCount = mnFontMetricCount;
+ pFontMetrics = mpFontMetrics;
+ }
+
+ // do we have to create the cached font list first?
+ if ( !pFontMetrics )
+ {
+ // query the number of fonts available
+ LONG nTemp = 0;
+ nFontMetricCount = Ft2QueryFonts( mhPS,
+ QF_PUBLIC | QF_PRIVATE,
+ NULL, &nTemp,
+ sizeof( FONTMETRICS ), NULL );
+
+ // procede only if at least one is available!
+ if ( nFontMetricCount )
+ {
+ // allocate memory for font list
+ pFontMetrics = new FONTMETRICS[nFontMetricCount];
+
+ // query font list
+ Ft2QueryFonts( mhPS,
+ QF_PUBLIC | QF_PRIVATE,
+ NULL,
+ (PLONG)&nFontMetricCount,
+ (LONG) sizeof( FONTMETRICS ),
+ pFontMetrics );
+ }
+
+ if ( !mbPrinter )
+ {
+ pSalData->mnFontMetricCount = nFontMetricCount;
+ pSalData->mpFontMetrics = pFontMetrics;
+ }
+ else
+ {
+ mnFontMetricCount = nFontMetricCount;
+ mpFontMetrics = pFontMetrics;
+ }
+ }
+
+ // copy data from the font list
+ for( ULONG i = 0; i < nFontMetricCount; i++ )
+ {
+ PFONTMETRICS pFontMetric = &pFontMetrics[i];
+
+ // skip font starting with '@', this is an alias internally
+ // used by truetype engine.
+ if (pFontMetric->szFacename[0] == '@')
+ continue;
+
+ // skip bitmap fonts (but keep WarpSans)
+ if ( (pFontMetric->fsDefn & FM_DEFN_OUTLINE) == 0
+ && strncmp( pFontMetric->szFacename, "WarpSans", 8) )
+ // Font nicht aufnehmen
+ continue;
+
+ // replace '-' in facename with ' ' (for ft2lib)
+ char* dash = pFontMetric->szFacename;
+ while( (dash=strchr( dash, '-')))
+ *dash++ = ' ';
+
+ // create new font list element
+ ImplOs2FontData* pData = new ImplOs2FontData( pFontMetric, 0, 0 );
+
+ // add font list element to font list
+ pList->Add( pData );
+
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void Os2SalGraphics::GetDevFontSubstList( OutputDevice* pOutDev )
+{
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalGraphics::GetGlyphBoundRect( long nIndex, Rectangle& rRect )
+{
+ // use unity matrix
+ MAT2 aMat;
+ aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
+ aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
+
+ UINT nGGOFlags = GGO_METRICS;
+ if( !(nIndex & GF_ISCHAR) )
+ nGGOFlags |= GGO_GLYPH_INDEX;
+ nIndex &= GF_IDXMASK;
+
+ GLYPHMETRICS aGM;
+ DWORD nSize = FT2_ERROR;
+ nSize = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat );
+ if( nSize == FT2_ERROR )
+ return false;
+
+ rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
+ Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
+ rRect.Left() = static_cast<int>( mfFontScale * rRect.Left() );
+ rRect.Right() = static_cast<int>( mfFontScale * rRect.Right() );
+ rRect.Top() = static_cast<int>( mfFontScale * rRect.Top() );
+ rRect.Bottom() = static_cast<int>( mfFontScale * rRect.Bottom() );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalGraphics::GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
+{
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalGraphics::GetGlyphOutline\n");
+#endif
+ rB2DPolyPoly.clear();
+
+ BOOL bRet = FALSE;
+
+ // use unity matrix
+ MAT2 aMat;
+ aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
+ aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
+
+ UINT nGGOFlags = GGO_NATIVE;
+ if( !(nIndex & GF_ISCHAR) )
+ nGGOFlags |= GGO_GLYPH_INDEX;
+ nIndex &= GF_IDXMASK;
+
+ GLYPHMETRICS aGlyphMetrics;
+ DWORD nSize1 = FT2_ERROR;
+ nSize1 = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
+
+ if( !nSize1 ) // blank glyphs are ok
+ bRet = TRUE;
+ else if( nSize1 != FT2_ERROR )
+ {
+ BYTE* pData = new BYTE[ nSize1 ];
+ ULONG nTotalCount = 0;
+ DWORD nSize2;
+ nSize2 = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags,
+ &aGlyphMetrics, nSize1, pData, &aMat );
+
+ if( nSize1 == nSize2 )
+ {
+ bRet = TRUE;
+
+ int nPtSize = 512;
+ Point* pPoints = new Point[ nPtSize ];
+ BYTE* pFlags = new BYTE[ nPtSize ];
+
+ TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData;
+ while( (BYTE*)pHeader < pData+nSize2 )
+ {
+ // only outline data is interesting
+ if( pHeader->dwType != TT_POLYGON_TYPE )
+ break;
+
+ // get start point; next start points are end points
+ // of previous segment
+ int nPnt = 0;
+
+ long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
+ long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
+ pPoints[ nPnt ] = Point( nX, nY );
+ pFlags[ nPnt++ ] = POLY_NORMAL;
+
+ bool bHasOfflinePoints = false;
+ TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 );
+ pHeader = (TTPOLYGONHEADER*)( (BYTE*)pHeader + pHeader->cb );
+ while( (BYTE*)pCurve < (BYTE*)pHeader )
+ {
+ int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
+ if( nPtSize < nNeededSize )
+ {
+ Point* pOldPoints = pPoints;
+ BYTE* pOldFlags = pFlags;
+ nPtSize = 2 * nNeededSize;
+ pPoints = new Point[ nPtSize ];
+ pFlags = new BYTE[ nPtSize ];
+ for( int i = 0; i < nPnt; ++i )
+ {
+ pPoints[ i ] = pOldPoints[ i ];
+ pFlags[ i ] = pOldFlags[ i ];
+ }
+ delete[] pOldPoints;
+ delete[] pOldFlags;
+ }
+
+ int i = 0;
+ if( TT_PRIM_LINE == pCurve->wType )
+ {
+ while( i < pCurve->cpfx )
+ {
+ nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
+ nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
+ ++i;
+ pPoints[ nPnt ] = Point( nX, nY );
+ pFlags[ nPnt ] = POLY_NORMAL;
+ ++nPnt;
+ }
+ }
+ else if( TT_PRIM_QSPLINE == pCurve->wType )
+ {
+ bHasOfflinePoints = true;
+ while( i < pCurve->cpfx )
+ {
+ // get control point of quadratic bezier spline
+ nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
+ nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
+ ++i;
+ Point aControlP( nX, nY );
+
+ // calculate first cubic control point
+ // P0 = 1/3 * (PBeg + 2 * PQControl)
+ nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
+ nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
+ pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
+ pFlags[ nPnt+0 ] = POLY_CONTROL;
+
+ // calculate endpoint of segment
+ nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
+ nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
+
+ if ( i+1 >= pCurve->cpfx )
+ {
+ // endpoint is either last point in segment => advance
+ ++i;
+ }
+ else
+ {
+ // or endpoint is the middle of two control points
+ nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
+ nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
+ nX = (nX + 1) / 2;
+ nY = (nY + 1) / 2;
+ // no need to advance, because the current point
+ // is the control point in next bezier spline
+ }
+
+ pPoints[ nPnt+2 ] = Point( nX, nY );
+ pFlags[ nPnt+2 ] = POLY_NORMAL;
+
+ // calculate second cubic control point
+ // P1 = 1/3 * (PEnd + 2 * PQControl)
+ nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
+ nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
+ pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
+ pFlags[ nPnt+1 ] = POLY_CONTROL;
+
+ nPnt += 3;
+ }
+ }
+
+ // next curve segment
+ pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ];
+ }
+
+ // end point is start point for closed contour
+ // disabled, because Polygon class closes the contour itself
+ // pPoints[nPnt++] = pPoints[0];
+ // #i35928#
+ // Added again, but add only when not yet closed
+ if(pPoints[nPnt - 1] != pPoints[0])
+ {
+ if( bHasOfflinePoints )
+ pFlags[nPnt] = pFlags[0];
+
+ pPoints[nPnt++] = pPoints[0];
+ }
+
+ // convert y-coordinates W32 -> VCL
+ for( int i = 0; i < nPnt; ++i )
+ pPoints[i].Y() = -pPoints[i].Y();
+
+ // insert into polypolygon
+ Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) );
+ // convert to B2DPolyPolygon
+ // TODO: get rid of the intermediate PolyPolygon
+ rB2DPolyPoly.append( aPoly.getB2DPolygon() );
+ }
+
+ delete[] pPoints;
+ delete[] pFlags;
+ }
+
+ delete[] pData;
+ }
+
+ // rescaling needed for the PolyPolygon conversion
+ if( rB2DPolyPoly.count() )
+ {
+ ::basegfx::B2DHomMatrix aMatrix;
+ aMatrix.scale( 1.0/256, 1.0/256 );
+ aMatrix.scale( mfFontScale, mfFontScale );
+ rB2DPolyPoly.transform( aMatrix );
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+// TODO: Replace this class with boost::scoped_array
+class ScopedCharArray
+{
+public:
+ inline explicit ScopedCharArray(char * pArray): m_pArray(pArray) {}
+
+ inline ~ScopedCharArray() { delete[] m_pArray; }
+
+ inline char * get() const { return m_pArray; }
+
+private:
+ char * m_pArray;
+};
+
+class ScopedFont
+{
+public:
+ explicit ScopedFont(Os2SalGraphics & rData);
+
+ ~ScopedFont();
+
+private:
+ Os2SalGraphics & m_rData;
+ ULONG m_hOrigFont;
+};
+
+ScopedFont::ScopedFont(Os2SalGraphics & rData): m_rData(rData)
+{
+#if 0
+ m_hOrigFont = m_rData.mhFonts[0];
+ m_rData.mhFonts[0] = 0; // avoid deletion of current font
+#endif
+}
+
+ScopedFont::~ScopedFont()
+{
+#if 0
+ if( m_hOrigFont )
+ {
+ // restore original font, destroy temporary font
+ HFONT hTempFont = m_rData.mhFonts[0];
+ m_rData.mhFonts[0] = m_hOrigFont;
+ SelectObject( m_rData.mhDC, m_hOrigFont );
+ DeleteObject( hTempFont );
+ }
+#endif
+}
+
+class ScopedTrueTypeFont
+{
+public:
+ inline ScopedTrueTypeFont(): m_pFont(0) {}
+
+ ~ScopedTrueTypeFont();
+
+ int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
+
+ inline TrueTypeFont * get() const { return m_pFont; }
+
+private:
+ TrueTypeFont * m_pFont;
+};
+
+ScopedTrueTypeFont::~ScopedTrueTypeFont()
+{
+ if (m_pFont != 0)
+ CloseTTFont(m_pFont);
+}
+
+int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen,
+ sal_uInt32 nFaceNum)
+{
+ OSL_ENSURE(m_pFont == 0, "already open");
+ return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont);
+}
+
+BOOL Os2SalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding,
+ sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
+{
+ // create matching ImplFontSelectData
+ // we need just enough to get to the font file data
+ // use height=1000 for easier debugging (to match psprint's font units)
+ ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
+
+ // TODO: much better solution: move SetFont and restoration of old font to caller
+ ScopedFont aOldFont(*this);
+ SetFont( &aIFSD, 0 );
+
+#if OSL_DEBUG_LEVEL > 100
+ // get font metrics
+ TEXTMETRICA aWinMetric;
+ if( !::GetTextMetricsA( mhDC, &aWinMetric ) )
+ return FALSE;
+
+ DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" );
+ DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
+#endif
+
+ // get raw font file data
+ DWORD nFontSize1 = Ft2GetFontData( mhPS, 0, 0, NULL, 0 );
+ if( nFontSize1 == FT2_ERROR )
+ return FALSE;
+ ScopedCharArray xRawFontData(new char[ nFontSize1 ]);
+ DWORD nFontSize2 = Ft2GetFontData( mhPS, 0, 0, (void*)xRawFontData.get(), nFontSize1 );
+ if( nFontSize1 != nFontSize2 )
+ return FALSE;
+
+ // open font file
+ sal_uInt32 nFaceNum = 0;
+ if( !*xRawFontData.get() ) // TTC candidate
+ nFaceNum = ~0U; // indicate "TTC font extracts only"
+
+ ScopedTrueTypeFont aSftTTF;
+ int nRC = aSftTTF.open( xRawFontData.get(), nFontSize1, nFaceNum );
+ if( nRC != SF_OK )
+ return FALSE;
+
+ TTGlobalFontInfo aTTInfo;
+ ::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
+ rInfo.m_nFontType = SAL_FONTSUBSETINFO_TYPE_TRUETYPE;
+ rInfo.m_aPSName = ImplSalGetUniString( aTTInfo.psname );
+ rInfo.m_nAscent = +aTTInfo.winAscent;
+ rInfo.m_nDescent = -aTTInfo.winDescent;
+ rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
+ Point( aTTInfo.xMax, aTTInfo.yMax ) );
+ rInfo.m_nCapHeight = aTTInfo.yMax; // Well ...
+
+ // subset glyphs and get their properties
+ // take care that subset fonts require the NotDef glyph in pos 0
+ int nOrigCount = nGlyphCount;
+ USHORT aShortIDs[ 256 ];
+ sal_uInt8 aTempEncs[ 256 ];
+
+ int nNotDef=-1, i;
+ for( i = 0; i < nGlyphCount; ++i )
+ {
+ aTempEncs[i] = pEncoding[i];
+ sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
+ if( pGlyphIDs[i] & GF_ISCHAR )
+ {
+ bool bVertical = (pGlyphIDs[i] & GF_ROTMASK) != 0;
+ nGlyphIdx = ::MapChar( aSftTTF.get(), sal::static_int_cast<sal_uInt16>(nGlyphIdx), bVertical );
+ if( nGlyphIdx == 0 && pFont->IsSymbolFont() )
+ {
+ // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
+ nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
+ nGlyphIdx = (nGlyphIdx & 0xF000) ? (nGlyphIdx & 0x00FF) : (nGlyphIdx | 0xF000 );
+ nGlyphIdx = ::MapChar( aSftTTF.get(), sal::static_int_cast<sal_uInt16>(nGlyphIdx), bVertical );
+ }
+ }
+ aShortIDs[i] = static_cast<USHORT>( nGlyphIdx );
+ if( !nGlyphIdx )
+ if( nNotDef < 0 )
+ nNotDef = i; // first NotDef glyph found
+ }
+
+ if( nNotDef != 0 )
+ {
+ // add fake NotDef glyph if needed
+ if( nNotDef < 0 )
+ nNotDef = nGlyphCount++;
+
+ // NotDef glyph must be in pos 0 => swap glyphids
+ aShortIDs[ nNotDef ] = aShortIDs[0];
+ aTempEncs[ nNotDef ] = aTempEncs[0];
+ aShortIDs[0] = 0;
+ aTempEncs[0] = 0;
+ }
+ DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
+
+ // fill pWidth array
+ TTSimpleGlyphMetrics* pMetrics =
+ ::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical );
+ if( !pMetrics )
+ return FALSE;
+ sal_uInt16 nNotDefAdv = pMetrics[0].adv;
+ pMetrics[0].adv = pMetrics[nNotDef].adv;
+ pMetrics[nNotDef].adv = nNotDefAdv;
+ for( i = 0; i < nOrigCount; ++i )
+ pGlyphWidths[i] = pMetrics[i].adv;
+ free( pMetrics );
+
+ // write subset into destination file
+ rtl::OUString aSysPath;
+ if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
+ return FALSE;
+ rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
+ ByteString aToFile( rtl::OUStringToOString( aSysPath, aThreadEncoding ) );
+ nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs,
+ aTempEncs, nGlyphCount, 0, NULL, 0 );
+ return nRC == SF_OK;
+}
+
+//--------------------------------------------------------------------------
+
+const void* Os2SalGraphics::GetEmbedFontData( const ImplFontData* pFont,
+ const sal_Ucs* pUnicodes, sal_Int32* pCharWidths,
+ FontSubsetInfo& rInfo, long* pDataLen )
+{
+ // create matching ImplFontSelectData
+ // we need just enough to get to the font file data
+ ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
+
+ // TODO: much better solution: move SetFont and restoration of old font to caller
+ ScopedFont aOldFont(*this);
+ SetFont( &aIFSD, 0 );
+
+ // get the raw font file data
+ DWORD nFontSize1 = Ft2GetFontData( mhPS, 0, 0, NULL, 0 );
+ if( nFontSize1 == FT2_ERROR || nFontSize1 <= 0 )
+ return NULL;
+ *pDataLen = nFontSize1;
+ void* pData = reinterpret_cast<void*>(new char[ nFontSize1 ]);
+ DWORD nFontSize2 = Ft2GetFontData( mhPS, 0, 0, pData, nFontSize1 );
+ if( nFontSize1 != nFontSize2 )
+ *pDataLen = 0;
+
+ // get important font properties
+ FONTMETRICS aOS2Metric;
+ if (Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric ) == GPI_ERROR)
+ *pDataLen = 0;
+ rInfo.m_nFontType = SAL_FONTSUBSETINFO_TYPE_TYPE1;
+ rInfo.m_aPSName = ImplSalGetUniString( aOS2Metric.szFacename );
+ rInfo.m_nAscent = +aOS2Metric.lMaxAscender;
+ rInfo.m_nDescent = -aOS2Metric.lMaxDescender;
+ rInfo.m_aFontBBox = Rectangle( Point( 0, -aOS2Metric.lMaxDescender ),
+ Point( aOS2Metric.lMaxCharInc, aOS2Metric.lMaxAscender+aOS2Metric.lExternalLeading ) );
+ rInfo.m_nCapHeight = aOS2Metric.lMaxAscender; // Well ...
+
+ // get individual character widths
+ for( int i = 0; i < 256; ++i )
+ {
+ LONG nCharWidth = 0;
+ const sal_Ucs cChar = pUnicodes[i];
+ if( !Ft2QueryStringWidthW( mhPS, (LPWSTR)&cChar, 1, &nCharWidth ) )
+ *pDataLen = 0;
+ pCharWidths[i] = nCharWidth;
+ }
+
+ if( !*pDataLen )
+ {
+ FreeEmbedFontData( pData, nFontSize1 );
+ pData = NULL;
+ }
+
+ return pData;
+}
+
+//--------------------------------------------------------------------------
+
+void Os2SalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
+{
+ delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
+}
+
+const Ucs2SIntMap* Os2SalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
+{
+ // TODO: even for builtin fonts we get here... why?
+ if( !pFont->IsEmbeddable() )
+ return NULL;
+
+ // fill the encoding vector
+ Ucs2SIntMap& rMap = *new Ucs2SIntMap;
+#if 0
+ // TODO: get correct encoding vector
+ ImplWinFontData* pWinFontData = reinterpret_cast<ImplWinFontData*>(pFont);
+
+ GLYPHSET aGlyphSet;
+ aGlyphSet.cbThis = sizeof(aGlyphSet);
+ DWORD aW = ::GetFontUnicodeRanges( mhDC, &aGlyphSet);
+#else
+ for( sal_Unicode i = 32; i < 256; ++i )
+ rMap[i] = i;
+ if( pNonEncoded )
+ *pNonEncoded = NULL;
+#endif
+
+ return &rMap;
+}
+
+//--------------------------------------------------------------------------
+
+void Os2SalGraphics::GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ // create matching ImplFontSelectData
+ // we need just enough to get to the font file data
+ ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
+
+ // TODO: much better solution: move SetFont and restoration of old font to caller
+ ScopedFont aOldFont(*this);
+
+ float fScale = 0.0;
+ ImplDoSetFont( &aIFSD, fScale, 0);
+
+ if( pFont->IsSubsettable() )
+ {
+ // get raw font file data
+ DWORD nFontSize1 = ::Ft2GetFontData( mhPS, 0, 0, NULL, 0 );
+ if( nFontSize1 == FT2_ERROR )
+ return;
+ ScopedCharArray xRawFontData(new char[ nFontSize1 ]);
+ DWORD nFontSize2 = ::Ft2GetFontData( mhPS, 0, 0, (void*)xRawFontData.get(), nFontSize1 );
+ if( nFontSize1 != nFontSize2 )
+ return;
+
+ // open font file
+ sal_uInt32 nFaceNum = 0;
+ if( !*xRawFontData.get() ) // TTC candidate
+ nFaceNum = ~0U; // indicate "TTC font extracts only"
+
+ ScopedTrueTypeFont aSftTTF;
+ int nRC = aSftTTF.open( xRawFontData.get(), nFontSize1, nFaceNum );
+ if( nRC != SF_OK )
+ return;
+
+ int nGlyphs = GetTTGlyphCount( aSftTTF.get() );
+ if( nGlyphs > 0 )
+ {
+ rWidths.resize(nGlyphs);
+ std::vector<sal_uInt16> aGlyphIds(nGlyphs);
+ for( int i = 0; i < nGlyphs; i++ )
+ aGlyphIds[i] = sal_uInt16(i);
+ TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(),
+ &aGlyphIds[0],
+ nGlyphs,
+ bVertical ? 1 : 0 );
+ if( pMetrics )
+ {
+ for( int i = 0; i< nGlyphs; i++ )
+ rWidths[i] = pMetrics[i].adv;
+ free( pMetrics );
+ rUnicodeEnc.clear();
+ }
+ const ImplOs2FontData* pWinFont = static_cast<const ImplOs2FontData*>(pFont);
+ ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap();
+ DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" );
+
+ int nCharCount = pMap->GetCharCount();
+ sal_uInt32 nChar = pMap->GetFirstChar();
+ for( int i = 0; i < nCharCount; i++ )
+ {
+ if( nChar < 0x00010000 )
+ {
+ sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(),
+ static_cast<sal_uInt16>(nChar),
+ bVertical ? 1 : 0 );
+ if( nGlyph )
+ rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph;
+ }
+ nChar = pMap->GetNextChar( nChar );
+ }
+ }
+ }
+ else if( pFont->IsEmbeddable() )
+ {
+ // get individual character widths
+ rWidths.clear();
+ rUnicodeEnc.clear();
+ rWidths.reserve( 224 );
+ for( sal_Unicode i = 32; i < 256; ++i )
+ {
+ int nCharWidth = 0;
+ if( Ft2QueryStringWidthW( mhPS, (LPWSTR)&i, 1, (LONG*)&nCharWidth ) )
+ {
+ rUnicodeEnc[ i ] = rWidths.size();
+ rWidths.push_back( nCharWidth );
+ }
+ }
+ }
+}
+
+//--------------------------------------------------------------------------
+
+void Os2SalGraphics::DrawServerFontLayout( const ServerFontLayout& )
+{}
+
+//--------------------------------------------------------------------------
+