xref: /AOO41X/main/vcl/os2/source/gdi/salgdi3.cxx (revision fc9fd3f14a55d77b35643a64034752a178b2a5b0)
19f62ea84SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
39f62ea84SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
49f62ea84SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
59f62ea84SAndrew Rist  * distributed with this work for additional information
69f62ea84SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
79f62ea84SAndrew Rist  * to you under the Apache License, Version 2.0 (the
89f62ea84SAndrew Rist  * "License"); you may not use this file except in compliance
99f62ea84SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
119f62ea84SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
139f62ea84SAndrew Rist  * Unless required by applicable law or agreed to in writing,
149f62ea84SAndrew Rist  * software distributed under the License is distributed on an
159f62ea84SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
169f62ea84SAndrew Rist  * KIND, either express or implied.  See the License for the
179f62ea84SAndrew Rist  * specific language governing permissions and limitations
189f62ea84SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
209f62ea84SAndrew Rist  *************************************************************/
219f62ea84SAndrew Rist 
229f62ea84SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir #define INCL_GRE_STRINGS
25cdf0e10cSrcweir #define INCL_GPI
26cdf0e10cSrcweir #define INCL_DOS
27cdf0e10cSrcweir 
28cdf0e10cSrcweir #include <string.h>
29*fc9fd3f1SPedro Giffuni //#include <stdlib.h>
30*fc9fd3f1SPedro Giffuni //#include <math.h>
31cdf0e10cSrcweir #include <svpm.h>
32cdf0e10cSrcweir 
33*fc9fd3f1SPedro Giffuni #include <vcl/sysdata.hxx>
34*fc9fd3f1SPedro Giffuni #include "tools/svwin.h"
35*fc9fd3f1SPedro Giffuni 
36*fc9fd3f1SPedro Giffuni #include "os2/saldata.hxx"
37*fc9fd3f1SPedro Giffuni #include "os2/salgdi.h"
38*fc9fd3f1SPedro Giffuni 
39*fc9fd3f1SPedro Giffuni #include "vcl/svapp.hxx"
40*fc9fd3f1SPedro Giffuni #include "outfont.hxx"
41*fc9fd3f1SPedro Giffuni #include "vcl/font.hxx"
42*fc9fd3f1SPedro Giffuni #include "fontsubset.hxx"
43*fc9fd3f1SPedro Giffuni #include "sallayout.hxx"
44*fc9fd3f1SPedro Giffuni 
45*fc9fd3f1SPedro Giffuni #include "rtl/logfile.hxx"
46*fc9fd3f1SPedro Giffuni #include "rtl/tencinfo.h"
47*fc9fd3f1SPedro Giffuni #include "rtl/textcvt.h"
48*fc9fd3f1SPedro Giffuni #include "rtl/bootstrap.hxx"
49*fc9fd3f1SPedro Giffuni 
50*fc9fd3f1SPedro Giffuni 
51*fc9fd3f1SPedro Giffuni #include "osl/module.h"
52*fc9fd3f1SPedro Giffuni #include "osl/file.hxx"
53*fc9fd3f1SPedro Giffuni #include "osl/thread.hxx"
54*fc9fd3f1SPedro Giffuni #include "osl/process.h"
55*fc9fd3f1SPedro Giffuni 
56*fc9fd3f1SPedro Giffuni #include "tools/poly.hxx"
57*fc9fd3f1SPedro Giffuni #include "tools/debug.hxx"
58*fc9fd3f1SPedro Giffuni #include "tools/stream.hxx"
59*fc9fd3f1SPedro Giffuni 
60*fc9fd3f1SPedro Giffuni #include "basegfx/polygon/b2dpolygon.hxx"
61*fc9fd3f1SPedro Giffuni #include "basegfx/polygon/b2dpolypolygon.hxx"
62*fc9fd3f1SPedro Giffuni #include "basegfx/matrix/b2dhommatrix.hxx"
63cdf0e10cSrcweir 
64cdf0e10cSrcweir #ifndef __H_FT2LIB
65*fc9fd3f1SPedro Giffuni #include <os2/wingdi.h>
66cdf0e10cSrcweir #include <ft2lib.h>
67cdf0e10cSrcweir #endif
68cdf0e10cSrcweir 
69cdf0e10cSrcweir #include "sft.hxx"
70cdf0e10cSrcweir 
71cdf0e10cSrcweir #ifdef GCP_KERN_HACK
72cdf0e10cSrcweir #include <algorithm>
73cdf0e10cSrcweir #endif
74cdf0e10cSrcweir 
75cdf0e10cSrcweir using namespace vcl;
76cdf0e10cSrcweir 
77cdf0e10cSrcweir // -----------
78cdf0e10cSrcweir // - Inlines -
79cdf0e10cSrcweir // -----------
80cdf0e10cSrcweir 
81cdf0e10cSrcweir 
82cdf0e10cSrcweir inline W32FIXED FixedFromDouble( double d )
83cdf0e10cSrcweir {
84cdf0e10cSrcweir     const long l = (long) ( d * 65536. );
85cdf0e10cSrcweir     return *(W32FIXED*) &l;
86cdf0e10cSrcweir }
87cdf0e10cSrcweir 
88cdf0e10cSrcweir // -----------------------------------------------------------------------
89cdf0e10cSrcweir 
90cdf0e10cSrcweir inline int IntTimes256FromFixed(W32FIXED f)
91cdf0e10cSrcweir {
92cdf0e10cSrcweir     int nFixedTimes256 = (f.value << 8) + ((f.fract+0x80) >> 8);
93cdf0e10cSrcweir     return nFixedTimes256;
94cdf0e10cSrcweir }
95cdf0e10cSrcweir 
96cdf0e10cSrcweir // -----------
97cdf0e10cSrcweir // - Defines -
98cdf0e10cSrcweir // -----------
99cdf0e10cSrcweir 
100cdf0e10cSrcweir // this is a special codepage code, used to identify OS/2 symbol font.
101cdf0e10cSrcweir #define SYMBOL_CHARSET					65400
102cdf0e10cSrcweir 
103cdf0e10cSrcweir // =======================================================================
104cdf0e10cSrcweir 
105cdf0e10cSrcweir UniString ImplSalGetUniString( const sal_Char* pStr, xub_StrLen nLen = STRING_LEN)
106cdf0e10cSrcweir {
107cdf0e10cSrcweir 	return UniString( pStr, nLen, gsl_getSystemTextEncoding(),
108cdf0e10cSrcweir 					  RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
109cdf0e10cSrcweir 					  RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
110cdf0e10cSrcweir 					  RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
111cdf0e10cSrcweir }
112cdf0e10cSrcweir 
113cdf0e10cSrcweir // =======================================================================
114cdf0e10cSrcweir 
115cdf0e10cSrcweir static USHORT ImplSalToCharSet( CharSet eCharSet )
116cdf0e10cSrcweir {
117cdf0e10cSrcweir 	// !!! Fuer DBCS-Systeme muss dieser Code auskommentiert werden und 0
118cdf0e10cSrcweir 	// !!! zurueckgegeben werden, solange die DBCS-Charsets nicht
119cdf0e10cSrcweir 	// !!! durchgereicht werden
120cdf0e10cSrcweir 
121cdf0e10cSrcweir 	switch ( eCharSet )
122cdf0e10cSrcweir 	{
123cdf0e10cSrcweir 		case RTL_TEXTENCODING_IBM_437:
124cdf0e10cSrcweir 			return 437;
125cdf0e10cSrcweir 
126cdf0e10cSrcweir 		case RTL_TEXTENCODING_IBM_850:
127cdf0e10cSrcweir 			return 850;
128cdf0e10cSrcweir 
129cdf0e10cSrcweir 		case RTL_TEXTENCODING_IBM_860:
130cdf0e10cSrcweir 			return 860;
131cdf0e10cSrcweir 
132cdf0e10cSrcweir 		case RTL_TEXTENCODING_IBM_861:
133cdf0e10cSrcweir 			return 861;
134cdf0e10cSrcweir 
135cdf0e10cSrcweir 		case RTL_TEXTENCODING_IBM_863:
136cdf0e10cSrcweir 			return 863;
137cdf0e10cSrcweir 
138cdf0e10cSrcweir 		case RTL_TEXTENCODING_IBM_865:
139cdf0e10cSrcweir 			return 865;
140cdf0e10cSrcweir 		case RTL_TEXTENCODING_MS_1252:
141cdf0e10cSrcweir 			return 1004;
142cdf0e10cSrcweir 		case RTL_TEXTENCODING_SYMBOL:
143cdf0e10cSrcweir 			return 65400;
144cdf0e10cSrcweir 	}
145cdf0e10cSrcweir 
146cdf0e10cSrcweir 	return 0;
147cdf0e10cSrcweir }
148cdf0e10cSrcweir 
149cdf0e10cSrcweir // -----------------------------------------------------------------------
150cdf0e10cSrcweir 
151cdf0e10cSrcweir static CharSet ImplCharSetToSal( USHORT usCodePage )
152cdf0e10cSrcweir {
153cdf0e10cSrcweir 	switch ( usCodePage )
154cdf0e10cSrcweir 	{
155cdf0e10cSrcweir 		case 437:
156cdf0e10cSrcweir 			return RTL_TEXTENCODING_IBM_437;
157cdf0e10cSrcweir 
158cdf0e10cSrcweir 		case 850:
159cdf0e10cSrcweir 			return RTL_TEXTENCODING_IBM_850;
160cdf0e10cSrcweir 
161cdf0e10cSrcweir 		case 860:
162cdf0e10cSrcweir 			return RTL_TEXTENCODING_IBM_860;
163cdf0e10cSrcweir 
164cdf0e10cSrcweir 		case 861:
165cdf0e10cSrcweir 			return RTL_TEXTENCODING_IBM_861;
166cdf0e10cSrcweir 
167cdf0e10cSrcweir 		case 863:
168cdf0e10cSrcweir 			return RTL_TEXTENCODING_IBM_863;
169cdf0e10cSrcweir 
170cdf0e10cSrcweir 		case 865:
171cdf0e10cSrcweir 			return RTL_TEXTENCODING_IBM_865;
172cdf0e10cSrcweir 		case 1004:
173cdf0e10cSrcweir 			return RTL_TEXTENCODING_MS_1252;
174cdf0e10cSrcweir 		case 65400:
175cdf0e10cSrcweir 			return RTL_TEXTENCODING_SYMBOL;
176cdf0e10cSrcweir 	}
177cdf0e10cSrcweir 
178cdf0e10cSrcweir 	return RTL_TEXTENCODING_DONTKNOW;
179cdf0e10cSrcweir }
180cdf0e10cSrcweir 
181cdf0e10cSrcweir // -----------------------------------------------------------------------
182cdf0e10cSrcweir 
183*fc9fd3f1SPedro Giffuni static FontFamily ImplFamilyToSal( PM_BYTE bFamilyType )
184cdf0e10cSrcweir {
185cdf0e10cSrcweir     switch ( bFamilyType )
186cdf0e10cSrcweir     {
187cdf0e10cSrcweir         case 4:
188cdf0e10cSrcweir             return FAMILY_DECORATIVE;
189cdf0e10cSrcweir         case 3:
190cdf0e10cSrcweir             return FAMILY_SCRIPT;
191cdf0e10cSrcweir     }
192cdf0e10cSrcweir 
193cdf0e10cSrcweir     return FAMILY_DONTKNOW;
194cdf0e10cSrcweir }
195cdf0e10cSrcweir 
196cdf0e10cSrcweir // -----------------------------------------------------------------------
197cdf0e10cSrcweir 
198cdf0e10cSrcweir static FontWeight ImplWeightToSal( USHORT nWeight )
199cdf0e10cSrcweir {
200cdf0e10cSrcweir 	// Falls sich jemand an die alte Doku gehalten hat
201cdf0e10cSrcweir 	if ( nWeight > 999 )
202cdf0e10cSrcweir 		nWeight /= 1000;
203cdf0e10cSrcweir 
204cdf0e10cSrcweir 	switch ( nWeight )
205cdf0e10cSrcweir 	{
206cdf0e10cSrcweir 		case 1:
207cdf0e10cSrcweir 			return WEIGHT_THIN;
208cdf0e10cSrcweir 
209cdf0e10cSrcweir 		case 2:
210cdf0e10cSrcweir 			return WEIGHT_ULTRALIGHT;
211cdf0e10cSrcweir 
212cdf0e10cSrcweir 		case 3:
213cdf0e10cSrcweir 			return WEIGHT_LIGHT;
214cdf0e10cSrcweir 
215cdf0e10cSrcweir 		case 4:
216cdf0e10cSrcweir 			return WEIGHT_SEMILIGHT;
217cdf0e10cSrcweir 
218cdf0e10cSrcweir 		case 5:
219cdf0e10cSrcweir 			return WEIGHT_NORMAL;
220cdf0e10cSrcweir 
221cdf0e10cSrcweir 		case 6:
222cdf0e10cSrcweir 			return WEIGHT_SEMIBOLD;
223cdf0e10cSrcweir 
224cdf0e10cSrcweir 		case 7:
225cdf0e10cSrcweir 			return WEIGHT_BOLD;
226cdf0e10cSrcweir 
227cdf0e10cSrcweir 		case 8:
228cdf0e10cSrcweir 			return WEIGHT_ULTRABOLD;
229cdf0e10cSrcweir 
230cdf0e10cSrcweir 		case 9:
231cdf0e10cSrcweir 			return WEIGHT_BLACK;
232cdf0e10cSrcweir 	}
233cdf0e10cSrcweir 
234cdf0e10cSrcweir 	return WEIGHT_DONTKNOW;
235cdf0e10cSrcweir }
236cdf0e10cSrcweir 
237cdf0e10cSrcweir // -----------------------------------------------------------------------
238cdf0e10cSrcweir 
239cdf0e10cSrcweir static UniString ImpStyleNameToSal( const char* pFamilyName,
240cdf0e10cSrcweir 								   const char* pFaceName,
241cdf0e10cSrcweir 								   USHORT nLen )
242cdf0e10cSrcweir {
243cdf0e10cSrcweir 	if ( !nLen )
244cdf0e10cSrcweir 		nLen = strlen(pFamilyName);
245cdf0e10cSrcweir 
246cdf0e10cSrcweir 	// strip FamilyName from FaceName
247cdf0e10cSrcweir 	if ( strncmp( pFamilyName, pFaceName, nLen ) == 0 )
248cdf0e10cSrcweir 	{
249cdf0e10cSrcweir 		USHORT nFaceLen = (USHORT)strlen( pFaceName+nLen );
250cdf0e10cSrcweir 		// Ist Facename laenger, schneiden wir den FamilyName ab
251cdf0e10cSrcweir 		if ( nFaceLen > 1 )
252cdf0e10cSrcweir 			return UniString( pFaceName+(nLen+1), gsl_getSystemTextEncoding());
253cdf0e10cSrcweir 		else
254cdf0e10cSrcweir 			return UniString();
255cdf0e10cSrcweir 	}
256cdf0e10cSrcweir 	else
257cdf0e10cSrcweir 		return UniString( pFaceName, gsl_getSystemTextEncoding());
258cdf0e10cSrcweir }
259cdf0e10cSrcweir 
260cdf0e10cSrcweir // -----------------------------------------------------------------------
261cdf0e10cSrcweir 
262*fc9fd3f1SPedro Giffuni inline FontPitch ImplLogPitchToSal( PM_BYTE fsType )
263cdf0e10cSrcweir {
264cdf0e10cSrcweir     if ( fsType & FM_TYPE_FIXED )
265cdf0e10cSrcweir         return PITCH_FIXED;
266cdf0e10cSrcweir     else
267cdf0e10cSrcweir         return PITCH_VARIABLE;
268cdf0e10cSrcweir }
269cdf0e10cSrcweir 
270cdf0e10cSrcweir // -----------------------------------------------------------------------
271cdf0e10cSrcweir 
272*fc9fd3f1SPedro Giffuni inline PM_BYTE ImplPitchToWin( FontPitch ePitch )
273cdf0e10cSrcweir {
274cdf0e10cSrcweir     if ( ePitch == PITCH_FIXED )
275cdf0e10cSrcweir         return FM_TYPE_FIXED;
276cdf0e10cSrcweir     //else if ( ePitch == PITCH_VARIABLE )
277cdf0e10cSrcweir 
278cdf0e10cSrcweir 	return 0;
279cdf0e10cSrcweir }
280cdf0e10cSrcweir 
281cdf0e10cSrcweir // -----------------------------------------------------------------------
282cdf0e10cSrcweir 
283cdf0e10cSrcweir static ImplDevFontAttributes Os2Font2DevFontAttributes( const PFONTMETRICS pFontMetric)
284cdf0e10cSrcweir {
285cdf0e10cSrcweir     ImplDevFontAttributes aDFA;
286cdf0e10cSrcweir 
287cdf0e10cSrcweir     // get font face attributes
288cdf0e10cSrcweir     aDFA.meFamily       = ImplFamilyToSal( pFontMetric->panose.bFamilyType);
289cdf0e10cSrcweir     aDFA.meWidthType    = WIDTH_DONTKNOW;
290cdf0e10cSrcweir     aDFA.meWeight       = ImplWeightToSal( pFontMetric->usWeightClass);
291cdf0e10cSrcweir     aDFA.meItalic       = (pFontMetric->fsSelection & FM_SEL_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE;
292cdf0e10cSrcweir     aDFA.mePitch        = ImplLogPitchToSal( pFontMetric->fsType );
293cdf0e10cSrcweir     aDFA.mbSymbolFlag   = (pFontMetric->usCodePage == SYMBOL_CHARSET);
294cdf0e10cSrcweir 
295cdf0e10cSrcweir 	// get the font face name
296cdf0e10cSrcweir 	// the maName field stores the font name without the style, so under OS/2
297cdf0e10cSrcweir 	// we must use the family name
298cdf0e10cSrcweir 	aDFA.maName = UniString( pFontMetric->szFamilyname, gsl_getSystemTextEncoding());
299cdf0e10cSrcweir 
300cdf0e10cSrcweir 	aDFA.maStyleName = ImpStyleNameToSal( pFontMetric->szFamilyname,
301cdf0e10cSrcweir  										  pFontMetric->szFacename,
302cdf0e10cSrcweir  										  strlen( pFontMetric->szFamilyname) );
303cdf0e10cSrcweir 
304cdf0e10cSrcweir     // get device specific font attributes
305cdf0e10cSrcweir     aDFA.mbOrientation  = (pFontMetric->fsDefn & FM_DEFN_OUTLINE) != 0;
306cdf0e10cSrcweir     aDFA.mbDevice       = (pFontMetric->fsDefn & FM_DEFN_GENERIC) ? FALSE : TRUE;
307cdf0e10cSrcweir 
308cdf0e10cSrcweir     aDFA.mbEmbeddable   = false;
309cdf0e10cSrcweir     aDFA.mbSubsettable  = false;
310cdf0e10cSrcweir     DWORD fontType = Ft2QueryFontType( 0, pFontMetric->szFamilyname);
311cdf0e10cSrcweir     if( fontType == FT2_FONTTYPE_TRUETYPE && !aDFA.mbDevice)
312cdf0e10cSrcweir 		aDFA.mbSubsettable = true;
313cdf0e10cSrcweir     // for now we can only embed Type1 fonts
314cdf0e10cSrcweir     if( fontType == FT2_FONTTYPE_TYPE1 )
315cdf0e10cSrcweir         aDFA.mbEmbeddable = true;
316cdf0e10cSrcweir 
317cdf0e10cSrcweir     // heuristics for font quality
318cdf0e10cSrcweir     // -   standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
319cdf0e10cSrcweir     // -   subsetting > embedding > none
320cdf0e10cSrcweir     aDFA.mnQuality = 0;
321cdf0e10cSrcweir     if( fontType == FT2_FONTTYPE_TRUETYPE )
322cdf0e10cSrcweir         aDFA.mnQuality += 50;
323cdf0e10cSrcweir     if( aDFA.mbSubsettable )
324cdf0e10cSrcweir         aDFA.mnQuality += 200;
325cdf0e10cSrcweir     else if( aDFA.mbEmbeddable )
326cdf0e10cSrcweir         aDFA.mnQuality += 100;
327cdf0e10cSrcweir 
328cdf0e10cSrcweir     // #i38665# prefer Type1 versions of the standard postscript fonts
329cdf0e10cSrcweir     if( aDFA.mbEmbeddable )
330cdf0e10cSrcweir     {
331cdf0e10cSrcweir         if( aDFA.maName.EqualsAscii( "AvantGarde" )
332cdf0e10cSrcweir         ||  aDFA.maName.EqualsAscii( "Bookman" )
333cdf0e10cSrcweir         ||  aDFA.maName.EqualsAscii( "Courier" )
334cdf0e10cSrcweir         ||  aDFA.maName.EqualsAscii( "Helvetica" )
335cdf0e10cSrcweir         ||  aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
336cdf0e10cSrcweir         ||  aDFA.maName.EqualsAscii( "Palatino" )
337cdf0e10cSrcweir         ||  aDFA.maName.EqualsAscii( "Symbol" )
338cdf0e10cSrcweir         ||  aDFA.maName.EqualsAscii( "Times" )
339cdf0e10cSrcweir         ||  aDFA.maName.EqualsAscii( "ZapfChancery" )
340cdf0e10cSrcweir         ||  aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
341cdf0e10cSrcweir             aDFA.mnQuality += 500;
342cdf0e10cSrcweir     }
343cdf0e10cSrcweir 
344cdf0e10cSrcweir     // TODO: add alias names
345cdf0e10cSrcweir 
346cdf0e10cSrcweir     return aDFA;
347cdf0e10cSrcweir }
348cdf0e10cSrcweir 
349cdf0e10cSrcweir // =======================================================================
350cdf0e10cSrcweir 
351*fc9fd3f1SPedro Giffuni // raw font data with a scoped lifetime
352*fc9fd3f1SPedro Giffuni class RawFontData
353*fc9fd3f1SPedro Giffuni {
354*fc9fd3f1SPedro Giffuni public:
355*fc9fd3f1SPedro Giffuni     explicit	RawFontData( HDC, DWORD nTableTag=0 );
356*fc9fd3f1SPedro Giffuni     			~RawFontData() { delete[] mpRawBytes; }
357*fc9fd3f1SPedro Giffuni     const unsigned char*	get() const { return mpRawBytes; }
358*fc9fd3f1SPedro Giffuni     const unsigned char*	steal() { unsigned char* p = mpRawBytes; mpRawBytes = NULL; return p; }
359*fc9fd3f1SPedro Giffuni     const int				size() const { return mnByteCount; }
360*fc9fd3f1SPedro Giffuni 
361*fc9fd3f1SPedro Giffuni private:
362*fc9fd3f1SPedro Giffuni     unsigned char*	mpRawBytes;
363*fc9fd3f1SPedro Giffuni     int				mnByteCount;
364*fc9fd3f1SPedro Giffuni };
365*fc9fd3f1SPedro Giffuni 
366*fc9fd3f1SPedro Giffuni RawFontData::RawFontData( HPS hPS, DWORD nTableTag )
367*fc9fd3f1SPedro Giffuni :	mpRawBytes( NULL )
368*fc9fd3f1SPedro Giffuni ,	mnByteCount( 0 )
369*fc9fd3f1SPedro Giffuni {
370*fc9fd3f1SPedro Giffuni 	// get required size in bytes
371*fc9fd3f1SPedro Giffuni     mnByteCount = ::Ft2GetFontData( hPS, nTableTag, 0, NULL, 0 );
372*fc9fd3f1SPedro Giffuni     if( mnByteCount == FT2_ERROR )
373*fc9fd3f1SPedro Giffuni         return;
374*fc9fd3f1SPedro Giffuni     else if( !mnByteCount )
375*fc9fd3f1SPedro Giffuni         return;
376*fc9fd3f1SPedro Giffuni 
377*fc9fd3f1SPedro Giffuni 	// allocate the array
378*fc9fd3f1SPedro Giffuni     mpRawBytes = new unsigned char[ mnByteCount ];
379*fc9fd3f1SPedro Giffuni 
380*fc9fd3f1SPedro Giffuni 	// get raw data in chunks small enough for GetFontData()
381*fc9fd3f1SPedro Giffuni 	int nRawDataOfs = 0;
382*fc9fd3f1SPedro Giffuni 	DWORD nMaxChunkSize = 0x100000;
383*fc9fd3f1SPedro Giffuni 	for(;;)
384*fc9fd3f1SPedro Giffuni 	{
385*fc9fd3f1SPedro Giffuni 		// calculate remaining raw data to get
386*fc9fd3f1SPedro Giffuni 		DWORD nFDGet = mnByteCount - nRawDataOfs;
387*fc9fd3f1SPedro Giffuni 		if( nFDGet <= 0 )
388*fc9fd3f1SPedro Giffuni 			break;
389*fc9fd3f1SPedro Giffuni 		// #i56745# limit GetFontData requests
390*fc9fd3f1SPedro Giffuni 		if( nFDGet > nMaxChunkSize )
391*fc9fd3f1SPedro Giffuni 			nFDGet = nMaxChunkSize;
392*fc9fd3f1SPedro Giffuni 		const DWORD nFDGot = ::Ft2GetFontData( hPS, nTableTag, nRawDataOfs,
393*fc9fd3f1SPedro Giffuni 			(void*)(mpRawBytes + nRawDataOfs), nFDGet );
394*fc9fd3f1SPedro Giffuni 		if( !nFDGot )
395*fc9fd3f1SPedro Giffuni 			break;
396*fc9fd3f1SPedro Giffuni 		else if( nFDGot != FT2_ERROR )
397*fc9fd3f1SPedro Giffuni 			nRawDataOfs += nFDGot;
398*fc9fd3f1SPedro Giffuni 		else
399*fc9fd3f1SPedro Giffuni 		{
400*fc9fd3f1SPedro Giffuni 			// was the chunk too big? reduce it
401*fc9fd3f1SPedro Giffuni 			nMaxChunkSize /= 2;
402*fc9fd3f1SPedro Giffuni 			if( nMaxChunkSize < 0x10000 )
403*fc9fd3f1SPedro Giffuni 				break;
404*fc9fd3f1SPedro Giffuni 		}
405*fc9fd3f1SPedro Giffuni 	}
406*fc9fd3f1SPedro Giffuni 
407*fc9fd3f1SPedro Giffuni 	// cleanup if the raw data is incomplete
408*fc9fd3f1SPedro Giffuni 	if( nRawDataOfs != mnByteCount )
409*fc9fd3f1SPedro Giffuni 	{
410*fc9fd3f1SPedro Giffuni 		delete[] mpRawBytes;
411*fc9fd3f1SPedro Giffuni 		mpRawBytes = NULL;
412*fc9fd3f1SPedro Giffuni 	}
413*fc9fd3f1SPedro Giffuni }
414*fc9fd3f1SPedro Giffuni 
415cdf0e10cSrcweir // -----------------------------------------------------------------------
416cdf0e10cSrcweir 
417cdf0e10cSrcweir // =======================================================================
418cdf0e10cSrcweir 
419cdf0e10cSrcweir ImplOs2FontData::ImplOs2FontData( PFONTMETRICS _pFontMetric,
420*fc9fd3f1SPedro Giffuni     int nHeight, PM_BYTE nPitchAndFamily )
421cdf0e10cSrcweir :	ImplFontData( Os2Font2DevFontAttributes(_pFontMetric), 0 ),
422cdf0e10cSrcweir     pFontMetric( _pFontMetric ),
423cdf0e10cSrcweir 	meOs2CharSet( _pFontMetric->usCodePage),
424cdf0e10cSrcweir     mnPitchAndFamily( nPitchAndFamily ),
425cdf0e10cSrcweir     mpFontCharSets( NULL ),
426cdf0e10cSrcweir     mpUnicodeMap( NULL ),
427cdf0e10cSrcweir     mbDisableGlyphApi( false ),
428cdf0e10cSrcweir     mbHasKoreanRange( false ),
429cdf0e10cSrcweir     mbHasCJKSupport( false ),
430cdf0e10cSrcweir     mbAliasSymbolsLow( false ),
431cdf0e10cSrcweir     mbAliasSymbolsHigh( false ),
432cdf0e10cSrcweir     mnId( 0 )
433cdf0e10cSrcweir {
434cdf0e10cSrcweir     SetBitmapSize( 0, nHeight );
435cdf0e10cSrcweir }
436cdf0e10cSrcweir 
437cdf0e10cSrcweir // -----------------------------------------------------------------------
438cdf0e10cSrcweir 
439cdf0e10cSrcweir ImplOs2FontData::~ImplOs2FontData()
440cdf0e10cSrcweir {
441cdf0e10cSrcweir     delete[] mpFontCharSets;
442cdf0e10cSrcweir 
443cdf0e10cSrcweir     if( mpUnicodeMap )
444cdf0e10cSrcweir         mpUnicodeMap->DeReference();
445cdf0e10cSrcweir }
446cdf0e10cSrcweir 
447cdf0e10cSrcweir // -----------------------------------------------------------------------
448cdf0e10cSrcweir 
449cdf0e10cSrcweir sal_IntPtr ImplOs2FontData::GetFontId() const
450cdf0e10cSrcweir {
451cdf0e10cSrcweir     return mnId;
452cdf0e10cSrcweir }
453cdf0e10cSrcweir 
454cdf0e10cSrcweir // -----------------------------------------------------------------------
455cdf0e10cSrcweir 
456cdf0e10cSrcweir void ImplOs2FontData::UpdateFromHPS( HPS hPS ) const
457cdf0e10cSrcweir {
458cdf0e10cSrcweir     // short circuit if already initialized
459cdf0e10cSrcweir     if( mpUnicodeMap != NULL )
460cdf0e10cSrcweir         return;
461cdf0e10cSrcweir 
462cdf0e10cSrcweir     ReadCmapTable( hPS );
463cdf0e10cSrcweir     ReadOs2Table( hPS );
464cdf0e10cSrcweir 
465cdf0e10cSrcweir     // even if the font works some fonts have problems with the glyph API
466cdf0e10cSrcweir     // => the heuristic below tries to figure out which fonts have the problem
467cdf0e10cSrcweir 	DWORD	fontType = Ft2QueryFontType( 0, pFontMetric->szFacename);
468cdf0e10cSrcweir     if( fontType != FT2_FONTTYPE_TRUETYPE
469cdf0e10cSrcweir 		&& (pFontMetric->fsDefn & FM_DEFN_GENERIC) == 0)
470cdf0e10cSrcweir 		mbDisableGlyphApi = true;
471cdf0e10cSrcweir }
472cdf0e10cSrcweir 
473cdf0e10cSrcweir // -----------------------------------------------------------------------
474cdf0e10cSrcweir 
475cdf0e10cSrcweir bool ImplOs2FontData::HasGSUBstitutions( HPS hPS ) const
476cdf0e10cSrcweir {
477cdf0e10cSrcweir     if( !mbGsubRead )
478cdf0e10cSrcweir         ReadGsubTable( hPS );
479cdf0e10cSrcweir     return !maGsubTable.empty();
480cdf0e10cSrcweir }
481cdf0e10cSrcweir 
482cdf0e10cSrcweir // -----------------------------------------------------------------------
483cdf0e10cSrcweir 
484cdf0e10cSrcweir bool ImplOs2FontData::IsGSUBstituted( sal_Ucs cChar ) const
485cdf0e10cSrcweir {
486cdf0e10cSrcweir     return( maGsubTable.find( cChar ) != maGsubTable.end() );
487cdf0e10cSrcweir }
488cdf0e10cSrcweir 
489cdf0e10cSrcweir // -----------------------------------------------------------------------
490cdf0e10cSrcweir 
491cdf0e10cSrcweir const ImplFontCharMap* ImplOs2FontData::GetImplFontCharMap() const
492cdf0e10cSrcweir {
493*fc9fd3f1SPedro Giffuni     mpUnicodeMap->AddReference();
494cdf0e10cSrcweir     return mpUnicodeMap;
495cdf0e10cSrcweir }
496cdf0e10cSrcweir 
497cdf0e10cSrcweir // -----------------------------------------------------------------------
498cdf0e10cSrcweir 
499cdf0e10cSrcweir static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
500cdf0e10cSrcweir static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
501cdf0e10cSrcweir static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
502cdf0e10cSrcweir static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
503cdf0e10cSrcweir 
504cdf0e10cSrcweir void ImplOs2FontData::ReadOs2Table( HPS hPS ) const
505cdf0e10cSrcweir {
506cdf0e10cSrcweir     const DWORD Os2Tag = CalcTag( "OS/2" );
507cdf0e10cSrcweir     DWORD nLength = Ft2GetFontData( hPS, Os2Tag, 0, NULL, 0 );
508cdf0e10cSrcweir     if( (nLength == FT2_ERROR) || !nLength )
509cdf0e10cSrcweir         return;
510cdf0e10cSrcweir     std::vector<unsigned char> aOS2map( nLength );
511cdf0e10cSrcweir     unsigned char* pOS2map = &aOS2map[0];
512cdf0e10cSrcweir     DWORD nRC = Ft2GetFontData( hPS, Os2Tag, 0, pOS2map, nLength );
513cdf0e10cSrcweir     sal_uInt32 nVersion = GetUShort( pOS2map );
514cdf0e10cSrcweir     if ( nVersion >= 0x0001 && nLength >= 58 )
515cdf0e10cSrcweir     {
516cdf0e10cSrcweir         // We need at least version 0x0001 (TrueType rev 1.66)
517cdf0e10cSrcweir         // to have access to the needed struct members.
518cdf0e10cSrcweir         sal_uInt32 ulUnicodeRange1 = GetUInt( pOS2map + 42 );
519cdf0e10cSrcweir         sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
520*fc9fd3f1SPedro Giffuni #if 0
521cdf0e10cSrcweir         sal_uInt32 ulUnicodeRange3 = GetUInt( pOS2map + 50 );
522cdf0e10cSrcweir         sal_uInt32 ulUnicodeRange4 = GetUInt( pOS2map + 54 );
523*fc9fd3f1SPedro Giffuni #endif
524cdf0e10cSrcweir 
525cdf0e10cSrcweir         // Check for CJK capabilities of the current font
526*fc9fd3f1SPedro Giffuni         mbHasCJKSupport = (ulUnicodeRange2 & 0x2DF00000);
527cdf0e10cSrcweir         mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000)
528cdf0e10cSrcweir                         | (ulUnicodeRange2 & 0x01100000);
529*fc9fd3f1SPedro Giffuni         mbHasArabicSupport = (ulUnicodeRange1 & 0x00002000);
530cdf0e10cSrcweir     }
531cdf0e10cSrcweir }
532cdf0e10cSrcweir 
533cdf0e10cSrcweir 
534cdf0e10cSrcweir // -----------------------------------------------------------------------
535cdf0e10cSrcweir 
536cdf0e10cSrcweir void ImplOs2FontData::ReadGsubTable( HPS hPS ) const
537cdf0e10cSrcweir {
538cdf0e10cSrcweir     mbGsubRead = true;
539cdf0e10cSrcweir 
540cdf0e10cSrcweir     // check the existence of a GSUB table
541cdf0e10cSrcweir     const DWORD GsubTag = CalcTag( "GSUB" );
542cdf0e10cSrcweir     DWORD nRC = Ft2GetFontData( hPS, GsubTag, 0, NULL, 0 );
543cdf0e10cSrcweir     if( (nRC == FT2_ERROR) || !nRC )
544cdf0e10cSrcweir         return;
545cdf0e10cSrcweir 
546*fc9fd3f1SPedro Giffuni     // parse the GSUB table through sft
547*fc9fd3f1SPedro Giffuni     // TODO: parse it directly
548cdf0e10cSrcweir 
549*fc9fd3f1SPedro Giffuni     // sft needs the full font file data => get it
550*fc9fd3f1SPedro Giffuni     const RawFontData aRawFontData( hPS );
551*fc9fd3f1SPedro Giffuni     if( !aRawFontData.get() )
552cdf0e10cSrcweir     	return;
553cdf0e10cSrcweir 
554cdf0e10cSrcweir     // open font file
555cdf0e10cSrcweir     sal_uInt32 nFaceNum = 0;
556*fc9fd3f1SPedro Giffuni     if( !*aRawFontData.get() )  // TTC candidate
557cdf0e10cSrcweir         nFaceNum = ~0U;  // indicate "TTC font extracts only"
558cdf0e10cSrcweir 
559cdf0e10cSrcweir     TrueTypeFont* pTTFont = NULL;
560*fc9fd3f1SPedro Giffuni     ::OpenTTFontBuffer( (void*)aRawFontData.get(), aRawFontData.size(), nFaceNum, &pTTFont );
561cdf0e10cSrcweir     if( !pTTFont )
562cdf0e10cSrcweir         return;
563cdf0e10cSrcweir 
564cdf0e10cSrcweir     // add vertically substituted characters to list
565cdf0e10cSrcweir     static const sal_Unicode aGSUBCandidates[] = {
566cdf0e10cSrcweir         0x0020, 0x0080, // ASCII
567cdf0e10cSrcweir         0x2000, 0x2600, // misc
568cdf0e10cSrcweir         0x3000, 0x3100, // CJK punctutation
569cdf0e10cSrcweir         0x3300, 0x3400, // squared words
570cdf0e10cSrcweir         0xFF00, 0xFFF0, // halfwidth|fullwidth forms
571cdf0e10cSrcweir     0 };
572cdf0e10cSrcweir 
573cdf0e10cSrcweir     for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
574cdf0e10cSrcweir         for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
575cdf0e10cSrcweir             if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
576cdf0e10cSrcweir                 maGsubTable.insert( cChar ); // insert GSUBbed unicodes
577cdf0e10cSrcweir 
578cdf0e10cSrcweir     CloseTTFont( pTTFont );
579cdf0e10cSrcweir }
580cdf0e10cSrcweir 
581cdf0e10cSrcweir // -----------------------------------------------------------------------
582cdf0e10cSrcweir 
583cdf0e10cSrcweir void ImplOs2FontData::ReadCmapTable( HPS hPS ) const
584cdf0e10cSrcweir {
585*fc9fd3f1SPedro Giffuni     if( mpUnicodeMap != NULL )
586*fc9fd3f1SPedro Giffuni         return;
587cdf0e10cSrcweir 
588*fc9fd3f1SPedro Giffuni     bool bIsSymbolFont = (meOs2CharSet == SYMBOL_CHARSET);
589cdf0e10cSrcweir     // get the CMAP table from the font which is selected into the DC
590*fc9fd3f1SPedro Giffuni     const DWORD nCmapTag = CalcTag( "cmap" );
591*fc9fd3f1SPedro Giffuni     const RawFontData aRawFontData( hPS, nCmapTag );
592*fc9fd3f1SPedro Giffuni     // parse the CMAP table if available
593*fc9fd3f1SPedro Giffuni     if( aRawFontData.get() ) {
594*fc9fd3f1SPedro Giffuni         CmapResult aResult;
595*fc9fd3f1SPedro Giffuni         ParseCMAP( aRawFontData.get(), aRawFontData.size(), aResult );
596*fc9fd3f1SPedro Giffuni         mbDisableGlyphApi |= aResult.mbRecoded;
597*fc9fd3f1SPedro Giffuni         aResult.mbSymbolic = bIsSymbolFont;
598*fc9fd3f1SPedro Giffuni         if( aResult.mnRangeCount > 0 )
599*fc9fd3f1SPedro Giffuni             mpUnicodeMap = new ImplFontCharMap( aResult );
600cdf0e10cSrcweir     }
601cdf0e10cSrcweir 
602*fc9fd3f1SPedro Giffuni     if( !mpUnicodeMap )
603*fc9fd3f1SPedro Giffuni         mpUnicodeMap = ImplFontCharMap::GetDefaultMap( bIsSymbolFont );
604cdf0e10cSrcweir }
605cdf0e10cSrcweir 
606cdf0e10cSrcweir // =======================================================================
607cdf0e10cSrcweir 
608cdf0e10cSrcweir void Os2SalGraphics::SetTextColor( SalColor nSalColor )
609cdf0e10cSrcweir {
610cdf0e10cSrcweir 	CHARBUNDLE cb;
611cdf0e10cSrcweir 
612cdf0e10cSrcweir 	cb.lColor = RGBCOLOR( SALCOLOR_RED( nSalColor ),
613cdf0e10cSrcweir 						  SALCOLOR_GREEN( nSalColor ),
614cdf0e10cSrcweir 						  SALCOLOR_BLUE( nSalColor ) );
615cdf0e10cSrcweir 
616cdf0e10cSrcweir 	// set default color attributes
617cdf0e10cSrcweir 	Ft2SetAttrs( mhPS,
618cdf0e10cSrcweir 				 PRIM_CHAR,
619cdf0e10cSrcweir 				 CBB_COLOR,
620cdf0e10cSrcweir 				 0,
621cdf0e10cSrcweir 				 &cb );
622cdf0e10cSrcweir }
623cdf0e10cSrcweir 
624cdf0e10cSrcweir // -----------------------------------------------------------------------
625cdf0e10cSrcweir 
626cdf0e10cSrcweir USHORT Os2SalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, int nFallbackLevel)
627cdf0e10cSrcweir {
628cdf0e10cSrcweir 
629cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>10
630*fc9fd3f1SPedro Giffuni     debug_printf( "Os2SalGraphics::ImplDoSetFont mbPrinter=%d\n", mbPrinter);
631cdf0e10cSrcweir #endif
632cdf0e10cSrcweir 
633cdf0e10cSrcweir 	ImplOs2FontData* pFontData = (ImplOs2FontData*)i_pFont->mpFontData;
634cdf0e10cSrcweir 	PFONTMETRICS 	pFontMetric = NULL;
635cdf0e10cSrcweir 	FATTRS		  	aFAttrs;
636*fc9fd3f1SPedro Giffuni 	PM_BOOL		  	bOutline = FALSE;
637cdf0e10cSrcweir 	APIRET			rc;
638cdf0e10cSrcweir 
639cdf0e10cSrcweir 	memset( &aFAttrs, 0, sizeof( FATTRS ) );
640cdf0e10cSrcweir 	aFAttrs.usRecordLength = sizeof( FATTRS );
641cdf0e10cSrcweir 
642cdf0e10cSrcweir 	aFAttrs.lMaxBaselineExt = i_pFont->mnHeight;
643cdf0e10cSrcweir 	aFAttrs.lAveCharWidth	= i_pFont->mnWidth;
644cdf0e10cSrcweir 
645cdf0e10cSrcweir 	// do we have a pointer to the FONTMETRICS of the selected font? -> use it!
646cdf0e10cSrcweir 	if ( pFontData )
647cdf0e10cSrcweir 	{
648cdf0e10cSrcweir 		pFontMetric = pFontData->GetFontMetrics();
649cdf0e10cSrcweir 
650cdf0e10cSrcweir 		bOutline = (pFontMetric->fsDefn & FM_DEFN_OUTLINE) != 0;
651cdf0e10cSrcweir 
652cdf0e10cSrcweir 		// use match&registry fields to get correct match
653cdf0e10cSrcweir 		aFAttrs.lMatch	     	= pFontMetric->lMatch;
654cdf0e10cSrcweir 		aFAttrs.idRegistry 		= pFontMetric->idRegistry;
655cdf0e10cSrcweir 		aFAttrs.usCodePage 		= pFontMetric->usCodePage;
656cdf0e10cSrcweir 
657cdf0e10cSrcweir 		if ( bOutline )
658cdf0e10cSrcweir 		{
659cdf0e10cSrcweir 			aFAttrs.fsFontUse |= FATTR_FONTUSE_OUTLINE;
660cdf0e10cSrcweir 			if ( i_pFont->mnOrientation )
661cdf0e10cSrcweir 				aFAttrs.fsFontUse |= FATTR_FONTUSE_TRANSFORMABLE;
662cdf0e10cSrcweir 		}
663cdf0e10cSrcweir 		else
664cdf0e10cSrcweir 		{
665cdf0e10cSrcweir 			aFAttrs.lMaxBaselineExt = pFontMetric->lMaxBaselineExt;
666cdf0e10cSrcweir 			aFAttrs.lAveCharWidth	= pFontMetric->lAveCharWidth;
667cdf0e10cSrcweir 		}
668cdf0e10cSrcweir 
669cdf0e10cSrcweir 	}
670*fc9fd3f1SPedro Giffuni #if OSL_DEBUG_LEVEL>1
671*fc9fd3f1SPedro Giffuni 	if (pFontMetric->szFacename[0] == 'D') {
672*fc9fd3f1SPedro Giffuni 		rc = 0; // debugger breakpoint
673*fc9fd3f1SPedro Giffuni 	}
674*fc9fd3f1SPedro Giffuni #endif
675cdf0e10cSrcweir 
676cdf0e10cSrcweir 	// use family name for outline fonts
677cdf0e10cSrcweir     if ( mbPrinter ) {
678cdf0e10cSrcweir 		// use font face name for printers because otherwise ft2lib will fail
679cdf0e10cSrcweir 		// to select the correct font for GPI (ticket#117)
680cdf0e10cSrcweir 		strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFacename, sizeof( aFAttrs.szFacename ) );
681cdf0e10cSrcweir 	} else if ( !pFontMetric) {
682cdf0e10cSrcweir 		// use OOo name if fontmetrics not available!
683cdf0e10cSrcweir 		ByteString aName( i_pFont->maName.GetToken( 0 ), gsl_getSystemTextEncoding());
684cdf0e10cSrcweir 		strncpy( (char*)(aFAttrs.szFacename), aName.GetBuffer(), sizeof( aFAttrs.szFacename ) );
685cdf0e10cSrcweir 	} else if ( bOutline) {
686cdf0e10cSrcweir 		// use fontmetric family name for outline fonts
687cdf0e10cSrcweir 		strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFamilyname, sizeof( aFAttrs.szFacename ) );
688cdf0e10cSrcweir 	} else {
689cdf0e10cSrcweir 		// use real font face name for bitmaps (WarpSans only)
690cdf0e10cSrcweir 		strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFacename, sizeof( aFAttrs.szFacename ) );
691cdf0e10cSrcweir 	}
692cdf0e10cSrcweir 
693cdf0e10cSrcweir 	if ( i_pFont->meItalic != ITALIC_NONE )
694cdf0e10cSrcweir 		aFAttrs.fsSelection |= FATTR_SEL_ITALIC;
695cdf0e10cSrcweir 	if ( i_pFont->meWeight > WEIGHT_MEDIUM )
696cdf0e10cSrcweir 		aFAttrs.fsSelection |= FATTR_SEL_BOLD;
697cdf0e10cSrcweir 
698cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>1
699cdf0e10cSrcweir 	if (pFontMetric->szFacename[0] == 'A') {
700cdf0e10cSrcweir 		debug_printf( "Os2SalGraphics::SetFont hps %x lMatch '%d'\n", mhPS, pFontMetric->lMatch);
701cdf0e10cSrcweir 		debug_printf( "Os2SalGraphics::SetFont hps %x fontmetrics facename '%s'\n", mhPS, pFontMetric->szFacename);
702cdf0e10cSrcweir 		debug_printf( "Os2SalGraphics::SetFont hps %x fattrs facename '%s'\n", mhPS, aFAttrs.szFacename);
703*fc9fd3f1SPedro Giffuni 		debug_printf( "Os2SalGraphics::SetFont hps %x fattrs height '%d'\n", mhPS, aFAttrs.lMaxBaselineExt);
704*fc9fd3f1SPedro Giffuni 		debug_printf( "Os2SalGraphics::SetFont hps %x fattrs width '%d'\n", mhPS, aFAttrs.lAveCharWidth);
705cdf0e10cSrcweir 	}
706cdf0e10cSrcweir #endif
707cdf0e10cSrcweir 
708*fc9fd3f1SPedro Giffuni 	// set default font
709*fc9fd3f1SPedro Giffuni 	rc = Ft2SetCharSet( mhPS, LCID_DEFAULT);
710*fc9fd3f1SPedro Giffuni 	// delete selected font
711*fc9fd3f1SPedro Giffuni 	rc = Ft2DeleteSetId( mhPS, nFallbackLevel + LCID_BASE);
712*fc9fd3f1SPedro Giffuni 
713*fc9fd3f1SPedro Giffuni 	// create new logical font
714cdf0e10cSrcweir 	if ( (rc=Ft2CreateLogFont( mhPS, NULL, nFallbackLevel + LCID_BASE, &aFAttrs)) == GPI_ERROR ) {
715cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>1
716cdf0e10cSrcweir 		ERRORID nLastError = WinGetLastError( GetSalData()->mhAB );
717cdf0e10cSrcweir     	debug_printf( "Os2SalGraphics::SetFont hps %x Ft2CreateLogFont failed err %x\n", mhPS, nLastError );
718cdf0e10cSrcweir #endif
719cdf0e10cSrcweir 		return SAL_SETFONT_REMOVEANDMATCHNEW;
720cdf0e10cSrcweir 	}
721cdf0e10cSrcweir 
722*fc9fd3f1SPedro Giffuni #if OSL_DEBUG_LEVEL>1
723*fc9fd3f1SPedro Giffuni 	// select new font
724*fc9fd3f1SPedro Giffuni 	rc = Ft2SetCharSet( mhPS, nFallbackLevel + LCID_BASE);
725*fc9fd3f1SPedro Giffuni 
726*fc9fd3f1SPedro Giffuni 	// query fontmetric of new font
727*fc9fd3f1SPedro Giffuni 	FONTMETRICS aOS2Metric = {0};
728*fc9fd3f1SPedro Giffuni 	rc = Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
729*fc9fd3f1SPedro Giffuni 
730*fc9fd3f1SPedro Giffuni 	if (pFontMetric->szFacename[0] == 'D') {
731*fc9fd3f1SPedro Giffuni 		debug_printf( "Os2SalGraphics::SetFont Ft2QueryFontMetrics fattrs facename '%s'\n", aOS2Metric.szFacename);
732*fc9fd3f1SPedro Giffuni 		debug_printf( "Os2SalGraphics::SetFont Ft2QueryFontMetrics fattrs height '%d'\n", aOS2Metric.lMaxBaselineExt);
733*fc9fd3f1SPedro Giffuni 		debug_printf( "Os2SalGraphics::SetFont Ft2QueryFontMetrics fattrs width '%d'\n", aOS2Metric.lAveCharWidth);
734*fc9fd3f1SPedro Giffuni 	}
735*fc9fd3f1SPedro Giffuni #endif
736*fc9fd3f1SPedro Giffuni 
737*fc9fd3f1SPedro Giffuni 	// apply font sizing, rotation
738cdf0e10cSrcweir 	CHARBUNDLE aBundle;
739cdf0e10cSrcweir 
740cdf0e10cSrcweir 	ULONG nAttrsDefault = 0;
741cdf0e10cSrcweir 	ULONG nAttrs = CBB_SET;
742cdf0e10cSrcweir 	aBundle.usSet = nFallbackLevel + LCID_BASE;
743cdf0e10cSrcweir 
744cdf0e10cSrcweir 	if ( bOutline )
745cdf0e10cSrcweir 	{
746cdf0e10cSrcweir 		nAttrs |= CBB_BOX;
747cdf0e10cSrcweir 		aBundle.sizfxCell.cy = MAKEFIXED( i_pFont->mnHeight, 0 );
748cdf0e10cSrcweir 
749cdf0e10cSrcweir 		if ( !i_pFont->mnWidth )
750cdf0e10cSrcweir 		{
751cdf0e10cSrcweir 			LONG nXFontRes;
752cdf0e10cSrcweir 			LONG nYFontRes;
753cdf0e10cSrcweir 			LONG nHeight;
754cdf0e10cSrcweir 
755cdf0e10cSrcweir 			// Auf die Aufloesung achten, damit das Ergebnis auch auf
756cdf0e10cSrcweir 			// Drucken mit 180*360 DPI stimmt. Ausserdem muss gerundet
757cdf0e10cSrcweir 			// werden, da auf meinem OS2 beispielsweise als
758cdf0e10cSrcweir 			// Bildschirmaufloesung 3618*3622 PixelPerMeter zurueck-
759cdf0e10cSrcweir 			// gegeben wird
760cdf0e10cSrcweir 			GetResolution( nXFontRes, nYFontRes );
761cdf0e10cSrcweir 			nHeight = i_pFont->mnHeight;
762cdf0e10cSrcweir 			nHeight *= nXFontRes;
763cdf0e10cSrcweir 			nHeight += nYFontRes/2;
764cdf0e10cSrcweir 			nHeight /= nYFontRes;
765cdf0e10cSrcweir 			aBundle.sizfxCell.cx = MAKEFIXED( nHeight, 0 );
766cdf0e10cSrcweir 		}
767cdf0e10cSrcweir 		else
768cdf0e10cSrcweir 			aBundle.sizfxCell.cx = MAKEFIXED( i_pFont->mnWidth, 0 );
769cdf0e10cSrcweir 	}
770cdf0e10cSrcweir 
771cdf0e10cSrcweir 	// set orientation for outlinefonts
772cdf0e10cSrcweir 	if ( i_pFont->mnOrientation )
773cdf0e10cSrcweir 	{
774cdf0e10cSrcweir 		if ( bOutline )
775cdf0e10cSrcweir 		{
776cdf0e10cSrcweir 			nAttrs |= CBB_ANGLE;
777cdf0e10cSrcweir 			double alpha = (double)(i_pFont->mnOrientation);
778cdf0e10cSrcweir 			alpha *= 0.0017453292;	 // *PI / 1800
779cdf0e10cSrcweir 			mnOrientationY = (long) (1000.0 * sin( alpha ));
780cdf0e10cSrcweir 			mnOrientationX = (long) (1000.0 * cos( alpha ));
781cdf0e10cSrcweir 			aBundle.ptlAngle.x = mnOrientationX;
782cdf0e10cSrcweir 			aBundle.ptlAngle.y = mnOrientationY;
783cdf0e10cSrcweir 		}
784cdf0e10cSrcweir 		else
785cdf0e10cSrcweir 		{
786cdf0e10cSrcweir 			mnOrientationX = 1;
787cdf0e10cSrcweir 			mnOrientationY = 0;
788cdf0e10cSrcweir 			nAttrs |= CBB_ANGLE;
789cdf0e10cSrcweir 			aBundle.ptlAngle.x = 1;
790cdf0e10cSrcweir 			aBundle.ptlAngle.y = 0;
791cdf0e10cSrcweir 		}
792cdf0e10cSrcweir 	}
793cdf0e10cSrcweir 	else
794cdf0e10cSrcweir 	{
795cdf0e10cSrcweir 		mnOrientationX = 1;
796cdf0e10cSrcweir 		mnOrientationY = 0;
797cdf0e10cSrcweir 		nAttrs |= CBB_ANGLE;
798cdf0e10cSrcweir 		aBundle.ptlAngle.x = 1;
799cdf0e10cSrcweir 		aBundle.ptlAngle.y = 0;
800cdf0e10cSrcweir 	}
801cdf0e10cSrcweir 
802cdf0e10cSrcweir 	rc = Ft2SetAttrs( mhPS, PRIM_CHAR, nAttrs, nAttrsDefault, &aBundle );
803cdf0e10cSrcweir 
804cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>1
805*fc9fd3f1SPedro Giffuni 	rc = Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
806*fc9fd3f1SPedro Giffuni 	if (pFontMetric->szFacename[0] == 'D') {
807*fc9fd3f1SPedro Giffuni 		debug_printf( "Os2SalGraphics::SetFont Ft2QueryFontMetrics fattrs facename '%s'\n", aOS2Metric.szFacename);
808*fc9fd3f1SPedro Giffuni 		debug_printf( "Os2SalGraphics::SetFont Ft2QueryFontMetrics fattrs height '%d'\n", aOS2Metric.lMaxBaselineExt);
809*fc9fd3f1SPedro Giffuni 		debug_printf( "Os2SalGraphics::SetFont Ft2QueryFontMetrics fattrs width '%d'\n", aOS2Metric.lAveCharWidth);
810*fc9fd3f1SPedro Giffuni 	}
811cdf0e10cSrcweir #endif
812cdf0e10cSrcweir 
813cdf0e10cSrcweir 	return 0;
814cdf0e10cSrcweir }
815cdf0e10cSrcweir 
816cdf0e10cSrcweir 
817cdf0e10cSrcweir USHORT Os2SalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel )
818cdf0e10cSrcweir {
819cdf0e10cSrcweir 
820cdf0e10cSrcweir     // return early if there is no new font
821cdf0e10cSrcweir     if( !pFont )
822cdf0e10cSrcweir     {
823cdf0e10cSrcweir #if 0
824cdf0e10cSrcweir         // deselect still active font
825cdf0e10cSrcweir         if( mhDefFont )
826cdf0e10cSrcweir             Ft2SetCharSet( mhPS, mhDefFont );
827cdf0e10cSrcweir         // release no longer referenced font handles
828cdf0e10cSrcweir         for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
829cdf0e10cSrcweir         {
830cdf0e10cSrcweir             if( mhFonts[i] )
831cdf0e10cSrcweir                 Ft2DeleteSetId( mhPS, mhFonts[i] );
832cdf0e10cSrcweir             mhFonts[ i ] = 0;
833cdf0e10cSrcweir         }
834cdf0e10cSrcweir #endif
835cdf0e10cSrcweir         mhDefFont = 0;
836cdf0e10cSrcweir         return 0;
837cdf0e10cSrcweir     }
838cdf0e10cSrcweir 
839*fc9fd3f1SPedro Giffuni #if OSL_DEBUG_LEVEL>1
840cdf0e10cSrcweir     debug_printf( "Os2SalGraphics::SetFont\n");
841cdf0e10cSrcweir #endif
842cdf0e10cSrcweir 
843cdf0e10cSrcweir     DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL");
844cdf0e10cSrcweir     mpOs2FontEntry[ nFallbackLevel ] = reinterpret_cast<ImplOs2FontEntry*>( pFont->mpFontEntry );
845cdf0e10cSrcweir     mpOs2FontData[ nFallbackLevel ] = static_cast<const ImplOs2FontData*>( pFont->mpFontData );
846cdf0e10cSrcweir 
847cdf0e10cSrcweir 	ImplDoSetFont( pFont, mfFontScale, nFallbackLevel);
848cdf0e10cSrcweir 
849cdf0e10cSrcweir     if( !mhDefFont )
850cdf0e10cSrcweir     {
851cdf0e10cSrcweir         // keep default font
852cdf0e10cSrcweir         mhDefFont = nFallbackLevel + LCID_BASE;
853cdf0e10cSrcweir     }
854cdf0e10cSrcweir     else
855cdf0e10cSrcweir     {
856cdf0e10cSrcweir         // release no longer referenced font handles
857cdf0e10cSrcweir         for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
858cdf0e10cSrcweir         {
859cdf0e10cSrcweir             if( mhFonts[i] )
860cdf0e10cSrcweir             {
861cdf0e10cSrcweir #if 0
862cdf0e10cSrcweir                 Ft2DeleteSetId( mhPS, mhFonts[i] );
863cdf0e10cSrcweir #endif
864cdf0e10cSrcweir                 mhFonts[i] = 0;
865cdf0e10cSrcweir             }
866cdf0e10cSrcweir         }
867cdf0e10cSrcweir     }
868cdf0e10cSrcweir 
869cdf0e10cSrcweir     // store new font in correct layer
870cdf0e10cSrcweir     mhFonts[ nFallbackLevel ] = nFallbackLevel + LCID_BASE;
871cdf0e10cSrcweir 
872cdf0e10cSrcweir     // now the font is live => update font face
873cdf0e10cSrcweir     if( mpOs2FontData[ nFallbackLevel ] )
874cdf0e10cSrcweir         mpOs2FontData[ nFallbackLevel ]->UpdateFromHPS( mhPS );
875cdf0e10cSrcweir 
876cdf0e10cSrcweir     if( !nFallbackLevel )
877cdf0e10cSrcweir     {
878cdf0e10cSrcweir         mbFontKernInit = TRUE;
879cdf0e10cSrcweir         if ( mpFontKernPairs )
880cdf0e10cSrcweir         {
881cdf0e10cSrcweir             delete[] mpFontKernPairs;
882cdf0e10cSrcweir             mpFontKernPairs = NULL;
883cdf0e10cSrcweir         }
884cdf0e10cSrcweir         mnFontKernPairCount = 0;
885cdf0e10cSrcweir     }
886cdf0e10cSrcweir 
887cdf0e10cSrcweir     // some printers have higher internal resolution, so their
888cdf0e10cSrcweir     // text output would be different from what we calculated
889cdf0e10cSrcweir     // => suggest DrawTextArray to workaround this problem
890cdf0e10cSrcweir     if ( mbPrinter )
891cdf0e10cSrcweir         return SAL_SETFONT_USEDRAWTEXTARRAY;
892cdf0e10cSrcweir     else
893cdf0e10cSrcweir         return 0;
894cdf0e10cSrcweir }
895cdf0e10cSrcweir 
896cdf0e10cSrcweir // -----------------------------------------------------------------------
897cdf0e10cSrcweir 
898*fc9fd3f1SPedro Giffuni void Os2SalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel )
899cdf0e10cSrcweir {
900cdf0e10cSrcweir 	FONTMETRICS aOS2Metric;
901cdf0e10cSrcweir 	Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
902cdf0e10cSrcweir 
903*fc9fd3f1SPedro Giffuni 	// @TODO sync , int nFallbackLevel in 340
904*fc9fd3f1SPedro Giffuni 
905cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>1
906cdf0e10cSrcweir 	debug_printf( "Os2SalGraphics::GetFontMetric hps %x\n", mhPS);
907cdf0e10cSrcweir 	if (aOS2Metric.szFacename[0] == 'A') {
908cdf0e10cSrcweir 		debug_printf( "Os2SalGraphics::GetFontMetric hps %x fontmetrics facename '%s'\n", mhPS, aOS2Metric.szFacename);
909cdf0e10cSrcweir 		debug_printf( "Os2SalGraphics::GetFontMetric hps %x fontmetrics lMatch '%d'\n", mhPS, aOS2Metric.lMatch);
910cdf0e10cSrcweir 	}
911cdf0e10cSrcweir #endif
912cdf0e10cSrcweir 
913cdf0e10cSrcweir 	pMetric->maName 			= UniString( aOS2Metric.szFamilyname, gsl_getSystemTextEncoding());
914cdf0e10cSrcweir 	pMetric->maStyleName		= ImpStyleNameToSal( aOS2Metric.szFamilyname,
915cdf0e10cSrcweir 													 aOS2Metric.szFacename,
916cdf0e10cSrcweir 													 strlen( aOS2Metric.szFamilyname ) );
917cdf0e10cSrcweir 
918cdf0e10cSrcweir     // device independent font attributes
919cdf0e10cSrcweir     pMetric->meFamily       = ImplFamilyToSal( aOS2Metric.panose.bFamilyType);
920cdf0e10cSrcweir     pMetric->mbSymbolFlag   = (aOS2Metric.usCodePage == SYMBOL_CHARSET);
921cdf0e10cSrcweir     pMetric->meWeight       = ImplWeightToSal( aOS2Metric.usWeightClass );
922cdf0e10cSrcweir     pMetric->mePitch        = ImplLogPitchToSal( aOS2Metric.fsType );
923cdf0e10cSrcweir     pMetric->meItalic       = (aOS2Metric.fsSelection & FM_SEL_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE;
924cdf0e10cSrcweir     pMetric->mnSlant        = 0;
925cdf0e10cSrcweir 
926cdf0e10cSrcweir     // device dependend font attributes
927cdf0e10cSrcweir     pMetric->mbDevice       = (aOS2Metric.fsDefn & FM_DEFN_GENERIC) ? FALSE : TRUE;
928cdf0e10cSrcweir     pMetric->mbScalableFont = (aOS2Metric.fsDefn & FM_DEFN_OUTLINE) ? true : false;
929cdf0e10cSrcweir     if( pMetric->mbScalableFont )
930cdf0e10cSrcweir     {
931cdf0e10cSrcweir         // check if there are kern pairs
932cdf0e10cSrcweir         // TODO: does this work with GPOS kerning?
933cdf0e10cSrcweir         pMetric->mbKernableFont = (aOS2Metric.sKerningPairs > 0);
934cdf0e10cSrcweir     }
935cdf0e10cSrcweir     else
936cdf0e10cSrcweir     {
937cdf0e10cSrcweir         // bitmap fonts cannot be rotated directly
938cdf0e10cSrcweir         pMetric->mnOrientation  = 0;
939cdf0e10cSrcweir         // bitmap fonts have no kerning
940cdf0e10cSrcweir         pMetric->mbKernableFont = false;
941cdf0e10cSrcweir     }
942cdf0e10cSrcweir 
943cdf0e10cSrcweir     // transformation dependend font metrics
944cdf0e10cSrcweir 	if ( aOS2Metric.fsDefn & FM_DEFN_OUTLINE )
945cdf0e10cSrcweir 	{
946cdf0e10cSrcweir 		pMetric->mnWidth	   = aOS2Metric.lEmInc;
947cdf0e10cSrcweir 	}
948cdf0e10cSrcweir 	else
949cdf0e10cSrcweir 	{
950cdf0e10cSrcweir 		pMetric->mnWidth	   = aOS2Metric.lAveCharWidth;
951cdf0e10cSrcweir 		pMetric->mnOrientation = 0;
952cdf0e10cSrcweir 	}
953cdf0e10cSrcweir 	pMetric->mnIntLeading		= aOS2Metric.lInternalLeading;
954cdf0e10cSrcweir 	pMetric->mnExtLeading		= aOS2Metric.lExternalLeading;
955cdf0e10cSrcweir 	pMetric->mnAscent			= aOS2Metric.lMaxAscender;
956cdf0e10cSrcweir 	pMetric->mnDescent			= aOS2Metric.lMaxDescender;
957cdf0e10cSrcweir 
958cdf0e10cSrcweir     // #107888# improved metric compatibility for Asian fonts...
959cdf0e10cSrcweir     // TODO: assess workaround below for CWS >= extleading
960cdf0e10cSrcweir     // TODO: evaluate use of aWinMetric.sTypo* members for CJK
961cdf0e10cSrcweir     if( mpOs2FontData[0] && mpOs2FontData[0]->SupportsCJK() )
962cdf0e10cSrcweir     {
963cdf0e10cSrcweir         pMetric->mnIntLeading += pMetric->mnExtLeading;
964cdf0e10cSrcweir 
965cdf0e10cSrcweir         // #109280# The line height for Asian fonts is too small.
966cdf0e10cSrcweir         // Therefore we add half of the external leading to the
967cdf0e10cSrcweir         // ascent, the other half is added to the descent.
968cdf0e10cSrcweir         const long nHalfTmpExtLeading = pMetric->mnExtLeading / 2;
969cdf0e10cSrcweir         const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading;
970cdf0e10cSrcweir 
971cdf0e10cSrcweir         // #110641# external leading for Asian fonts.
972cdf0e10cSrcweir         // The factor 0.3 has been confirmed with experiments.
973cdf0e10cSrcweir         long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent));
974cdf0e10cSrcweir         nCJKExtLeading -= pMetric->mnExtLeading;
975cdf0e10cSrcweir         pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0;
976cdf0e10cSrcweir 
977cdf0e10cSrcweir         pMetric->mnAscent   += nHalfTmpExtLeading;
978cdf0e10cSrcweir         pMetric->mnDescent  += nOtherHalfTmpExtLeading;
979cdf0e10cSrcweir 
980cdf0e10cSrcweir         // #109280# HACK korean only: increase descent for wavelines and impr
981cdf0e10cSrcweir 		// YD win9x only
982cdf0e10cSrcweir     }
983cdf0e10cSrcweir 
984cdf0e10cSrcweir }
985cdf0e10cSrcweir 
986cdf0e10cSrcweir // -----------------------------------------------------------------------
987cdf0e10cSrcweir 
988cdf0e10cSrcweir ULONG Os2SalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs )
989cdf0e10cSrcweir {
990cdf0e10cSrcweir 	DBG_ASSERT( sizeof( KERNINGPAIRS ) == sizeof( ImplKernPairData ),
991cdf0e10cSrcweir 				"Os2SalGraphics::GetKernPairs(): KERNINGPAIRS != ImplKernPairData" );
992cdf0e10cSrcweir 
993cdf0e10cSrcweir     if ( mbFontKernInit )
994cdf0e10cSrcweir     {
995cdf0e10cSrcweir         if( mpFontKernPairs )
996cdf0e10cSrcweir         {
997cdf0e10cSrcweir             delete[] mpFontKernPairs;
998cdf0e10cSrcweir             mpFontKernPairs = NULL;
999cdf0e10cSrcweir         }
1000cdf0e10cSrcweir         mnFontKernPairCount = 0;
1001cdf0e10cSrcweir 
1002cdf0e10cSrcweir         {
1003cdf0e10cSrcweir             KERNINGPAIRS* pPairs = NULL;
1004cdf0e10cSrcweir 			FONTMETRICS aOS2Metric;
1005cdf0e10cSrcweir 			Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
1006cdf0e10cSrcweir             int nCount = aOS2Metric.sKerningPairs;
1007cdf0e10cSrcweir             if( nCount )
1008cdf0e10cSrcweir             {
1009cdf0e10cSrcweir #ifdef GCP_KERN_HACK
1010cdf0e10cSrcweir                 pPairs = new KERNINGPAIRS[ nCount+1 ];
1011cdf0e10cSrcweir                 mpFontKernPairs = pPairs;
1012cdf0e10cSrcweir                 mnFontKernPairCount = nCount;
1013cdf0e10cSrcweir 				Ft2QueryKerningPairs( mhPS, nCount, (KERNINGPAIRS*)pPairs );
1014cdf0e10cSrcweir #else // GCP_KERN_HACK
1015cdf0e10cSrcweir 				pPairs = (KERNINGPAIRS*)pKernPairs;
1016cdf0e10cSrcweir 				nCount = (nCount < nPairs) ? nCount : nPairs;
1017cdf0e10cSrcweir 				Ft2QueryKerningPairs( mhPS, nCount, (KERNINGPAIRS*)pPairs );
1018cdf0e10cSrcweir                 return nCount;
1019cdf0e10cSrcweir #endif // GCP_KERN_HACK
1020cdf0e10cSrcweir             }
1021cdf0e10cSrcweir         }
1022cdf0e10cSrcweir 
1023cdf0e10cSrcweir         mbFontKernInit = FALSE;
1024cdf0e10cSrcweir 
1025cdf0e10cSrcweir         std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
1026cdf0e10cSrcweir     }
1027cdf0e10cSrcweir 
1028cdf0e10cSrcweir     if( !pKernPairs )
1029cdf0e10cSrcweir         return mnFontKernPairCount;
1030cdf0e10cSrcweir     else if( mpFontKernPairs )
1031cdf0e10cSrcweir     {
1032cdf0e10cSrcweir         if ( nPairs < mnFontKernPairCount )
1033cdf0e10cSrcweir             nPairs = mnFontKernPairCount;
1034cdf0e10cSrcweir         memcpy( pKernPairs, mpFontKernPairs,
1035cdf0e10cSrcweir                 nPairs*sizeof( ImplKernPairData ) );
1036cdf0e10cSrcweir         return nPairs;
1037cdf0e10cSrcweir     }
1038cdf0e10cSrcweir 
1039cdf0e10cSrcweir     return 0;
1040cdf0e10cSrcweir }
1041cdf0e10cSrcweir 
1042cdf0e10cSrcweir 
1043cdf0e10cSrcweir // -----------------------------------------------------------------------
1044cdf0e10cSrcweir 
1045cdf0e10cSrcweir static const ImplFontCharMap* pOs2DefaultImplFontCharMap = NULL;
1046cdf0e10cSrcweir static const sal_uInt32 pOs2DefaultRangeCodes[] = {0x0020,0x00FF};
1047cdf0e10cSrcweir 
1048cdf0e10cSrcweir const ImplFontCharMap* Os2SalGraphics::GetImplFontCharMap() const
1049cdf0e10cSrcweir {
1050cdf0e10cSrcweir     if( !mpOs2FontData[0] )
1051cdf0e10cSrcweir         return ImplFontCharMap::GetDefaultMap();
1052cdf0e10cSrcweir     return mpOs2FontData[0]->GetImplFontCharMap();
1053cdf0e10cSrcweir }
1054cdf0e10cSrcweir 
1055cdf0e10cSrcweir // -----------------------------------------------------------------------
1056cdf0e10cSrcweir 
1057cdf0e10cSrcweir bool Os2SalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
1058cdf0e10cSrcweir     const String& rFontFileURL, const String& rFontName )
1059cdf0e10cSrcweir {
1060cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>0
1061cdf0e10cSrcweir     debug_printf("Os2SalGraphics::AddTempDevFont\n");
1062cdf0e10cSrcweir #endif
1063cdf0e10cSrcweir     return false;
1064cdf0e10cSrcweir }
1065cdf0e10cSrcweir 
1066cdf0e10cSrcweir // -----------------------------------------------------------------------
1067cdf0e10cSrcweir 
1068cdf0e10cSrcweir void Os2SalGraphics::GetDevFontList( ImplDevFontList* pList )
1069cdf0e10cSrcweir {
1070cdf0e10cSrcweir 	PFONTMETRICS	pFontMetrics;
1071cdf0e10cSrcweir 	ULONG			nFontMetricCount;
1072cdf0e10cSrcweir 	SalData*		pSalData;
1073cdf0e10cSrcweir 
1074cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>0
1075*fc9fd3f1SPedro Giffuni 	debug_printf("Os2SalGraphics::GetDevFontList mbPrinter=%d\n", mbPrinter);
1076cdf0e10cSrcweir #endif
1077cdf0e10cSrcweir 
1078cdf0e10cSrcweir 	// install OpenSymbol
1079cdf0e10cSrcweir 	HMODULE hMod;
1080cdf0e10cSrcweir 	ULONG	ObjNum, Offset, rc;
1081cdf0e10cSrcweir 	CHAR	Buff[2*_MAX_PATH];
1082cdf0e10cSrcweir 	char 	drive[_MAX_DRIVE], dir[_MAX_DIR];
1083cdf0e10cSrcweir 	char 	fname[_MAX_FNAME], ext[_MAX_EXT];
1084cdf0e10cSrcweir 	// get module handle (and name)
1085cdf0e10cSrcweir 	rc = DosQueryModFromEIP( &hMod, &ObjNum, sizeof( Buff), Buff,
1086cdf0e10cSrcweir 							&Offset, (ULONG)ImplSalGetUniString);
1087cdf0e10cSrcweir 	DosQueryModuleName(hMod, sizeof(Buff), Buff);
1088cdf0e10cSrcweir 	// replace module path with font path
1089cdf0e10cSrcweir 	char* slash = strrchr( Buff, '\\');
1090cdf0e10cSrcweir 	*slash = '\0';
1091cdf0e10cSrcweir 	slash = strrchr( Buff, '\\');
1092cdf0e10cSrcweir 	*slash = '\0';
1093*fc9fd3f1SPedro Giffuni 	strcat( Buff, "\\FONTS\\OPENS___.TTF");
1094cdf0e10cSrcweir 	rc = GpiLoadPublicFonts( GetSalData()->mhAB, Buff);
1095cdf0e10cSrcweir 
1096cdf0e10cSrcweir 	if ( !mbPrinter )
1097cdf0e10cSrcweir 	{
1098cdf0e10cSrcweir 		// Bei Bildschirm-Devices cachen wir die Liste global, da
1099cdf0e10cSrcweir 		// dies im unabhaengigen Teil auch so gemacht wird und wir
1100cdf0e10cSrcweir 		// ansonsten auf geloeschten Systemdaten arbeiten koennten
1101cdf0e10cSrcweir 		pSalData = GetSalData();
1102cdf0e10cSrcweir 		nFontMetricCount	= pSalData->mnFontMetricCount;
1103cdf0e10cSrcweir 		pFontMetrics		= pSalData->mpFontMetrics;
1104cdf0e10cSrcweir 		// Bei Bildschirm-Devices holen wir uns die Fontliste jedesmal neu
1105cdf0e10cSrcweir 		if ( pFontMetrics )
1106cdf0e10cSrcweir 		{
1107cdf0e10cSrcweir 			delete pFontMetrics;
1108cdf0e10cSrcweir 			pFontMetrics		= NULL;
1109cdf0e10cSrcweir 			nFontMetricCount	= 0;
1110cdf0e10cSrcweir 		}
1111cdf0e10cSrcweir 	}
1112cdf0e10cSrcweir 	else
1113cdf0e10cSrcweir 	{
1114cdf0e10cSrcweir 		nFontMetricCount	= mnFontMetricCount;
1115cdf0e10cSrcweir 		pFontMetrics		= mpFontMetrics;
1116cdf0e10cSrcweir 	}
1117cdf0e10cSrcweir 
1118cdf0e10cSrcweir 	// do we have to create the cached font list first?
1119cdf0e10cSrcweir 	if ( !pFontMetrics )
1120cdf0e10cSrcweir 	{
1121cdf0e10cSrcweir 		// query the number of fonts available
1122cdf0e10cSrcweir 		LONG nTemp = 0;
1123cdf0e10cSrcweir 		nFontMetricCount = Ft2QueryFonts( mhPS,
1124*fc9fd3f1SPedro Giffuni 										  QF_PUBLIC | QF_PRIVATE | QF_NO_DEVICE,
1125cdf0e10cSrcweir 										  NULL, &nTemp,
1126cdf0e10cSrcweir 										  sizeof( FONTMETRICS ), NULL );
1127cdf0e10cSrcweir 
1128cdf0e10cSrcweir 		// procede only if at least one is available!
1129cdf0e10cSrcweir 		if ( nFontMetricCount )
1130cdf0e10cSrcweir 		{
1131cdf0e10cSrcweir 			// allocate memory for font list
1132cdf0e10cSrcweir 			pFontMetrics = new FONTMETRICS[nFontMetricCount];
1133cdf0e10cSrcweir 
1134cdf0e10cSrcweir 			// query font list
1135cdf0e10cSrcweir 			Ft2QueryFonts( mhPS,
1136*fc9fd3f1SPedro Giffuni 						   QF_PUBLIC | QF_PRIVATE | QF_NO_DEVICE,
1137cdf0e10cSrcweir 						   NULL,
1138cdf0e10cSrcweir 						   (PLONG)&nFontMetricCount,
1139cdf0e10cSrcweir 						   (LONG) sizeof( FONTMETRICS ),
1140cdf0e10cSrcweir 						   pFontMetrics );
1141cdf0e10cSrcweir 		}
1142cdf0e10cSrcweir 
1143cdf0e10cSrcweir 		if ( !mbPrinter )
1144cdf0e10cSrcweir 		{
1145cdf0e10cSrcweir 			pSalData->mnFontMetricCount 		= nFontMetricCount;
1146cdf0e10cSrcweir 			pSalData->mpFontMetrics 			= pFontMetrics;
1147cdf0e10cSrcweir 		}
1148cdf0e10cSrcweir 		else
1149cdf0e10cSrcweir 		{
1150cdf0e10cSrcweir 			mnFontMetricCount	= nFontMetricCount;
1151cdf0e10cSrcweir 			mpFontMetrics		= pFontMetrics;
1152cdf0e10cSrcweir 		}
1153cdf0e10cSrcweir 	}
1154cdf0e10cSrcweir 
1155cdf0e10cSrcweir 	// copy data from the font list
1156cdf0e10cSrcweir 	for( ULONG i = 0; i < nFontMetricCount; i++ )
1157cdf0e10cSrcweir 	{
1158cdf0e10cSrcweir 		PFONTMETRICS pFontMetric = &pFontMetrics[i];
1159cdf0e10cSrcweir 
1160*fc9fd3f1SPedro Giffuni #if OSL_DEBUG_LEVEL>1
1161*fc9fd3f1SPedro Giffuni 		debug_printf("Os2SalGraphics::GetDevFontList #%d,'%s'\n", i, pFontMetric->szFacename);
1162*fc9fd3f1SPedro Giffuni #endif
1163*fc9fd3f1SPedro Giffuni 
1164cdf0e10cSrcweir 		// skip font starting with '@', this is an alias internally
1165cdf0e10cSrcweir 		// used by truetype engine.
1166cdf0e10cSrcweir 		if (pFontMetric->szFacename[0] == '@')
1167cdf0e10cSrcweir 			continue;
1168cdf0e10cSrcweir 
1169cdf0e10cSrcweir 		// skip bitmap fonts (but keep WarpSans)
1170cdf0e10cSrcweir 		if ( (pFontMetric->fsDefn & FM_DEFN_OUTLINE) == 0
1171cdf0e10cSrcweir 			&& strncmp( pFontMetric->szFacename, "WarpSans", 8) )
1172cdf0e10cSrcweir 			// Font nicht aufnehmen
1173cdf0e10cSrcweir 			continue;
1174cdf0e10cSrcweir 
1175cdf0e10cSrcweir 		// replace '-' in facename with ' ' (for ft2lib)
1176cdf0e10cSrcweir 		char* dash = pFontMetric->szFacename;
1177cdf0e10cSrcweir 		while( (dash=strchr( dash, '-')))
1178cdf0e10cSrcweir 			*dash++ = ' ';
1179cdf0e10cSrcweir 
1180cdf0e10cSrcweir 		// create new font list element
1181cdf0e10cSrcweir 		ImplOs2FontData* pData 		= new ImplOs2FontData( pFontMetric, 0, 0 );
1182cdf0e10cSrcweir 
1183*fc9fd3f1SPedro Giffuni 		// ticket#80: font id field is used for pdf font cache code.
1184*fc9fd3f1SPedro Giffuni 		pData->SetFontId( i);
1185*fc9fd3f1SPedro Giffuni 
1186cdf0e10cSrcweir 		// add font list element to font list
1187cdf0e10cSrcweir 		pList->Add( pData );
1188cdf0e10cSrcweir 
1189cdf0e10cSrcweir 	}
1190cdf0e10cSrcweir }
1191cdf0e10cSrcweir 
1192cdf0e10cSrcweir // ----------------------------------------------------------------------------
1193cdf0e10cSrcweir 
1194cdf0e10cSrcweir void Os2SalGraphics::GetDevFontSubstList( OutputDevice* pOutDev )
1195cdf0e10cSrcweir {
1196cdf0e10cSrcweir }
1197cdf0e10cSrcweir 
1198cdf0e10cSrcweir // -----------------------------------------------------------------------
1199cdf0e10cSrcweir 
1200*fc9fd3f1SPedro Giffuni sal_Bool Os2SalGraphics::GetGlyphBoundRect( long nIndex, Rectangle& rRect )
1201cdf0e10cSrcweir {
1202cdf0e10cSrcweir     // use unity matrix
1203cdf0e10cSrcweir     MAT2 aMat;
1204cdf0e10cSrcweir     aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
1205cdf0e10cSrcweir     aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
1206cdf0e10cSrcweir 
1207cdf0e10cSrcweir     UINT nGGOFlags = GGO_METRICS;
1208cdf0e10cSrcweir     if( !(nIndex & GF_ISCHAR) )
1209cdf0e10cSrcweir         nGGOFlags |= GGO_GLYPH_INDEX;
1210cdf0e10cSrcweir     nIndex &= GF_IDXMASK;
1211cdf0e10cSrcweir 
1212cdf0e10cSrcweir     GLYPHMETRICS aGM;
1213cdf0e10cSrcweir     DWORD nSize = FT2_ERROR;
1214cdf0e10cSrcweir     nSize = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat );
1215cdf0e10cSrcweir     if( nSize == FT2_ERROR )
1216cdf0e10cSrcweir         return false;
1217cdf0e10cSrcweir 
1218cdf0e10cSrcweir     rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
1219cdf0e10cSrcweir         Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
1220cdf0e10cSrcweir     rRect.Left()    = static_cast<int>( mfFontScale * rRect.Left() );
1221cdf0e10cSrcweir     rRect.Right()   = static_cast<int>( mfFontScale * rRect.Right() );
1222cdf0e10cSrcweir     rRect.Top()     = static_cast<int>( mfFontScale * rRect.Top() );
1223cdf0e10cSrcweir     rRect.Bottom()  = static_cast<int>( mfFontScale * rRect.Bottom() );
1224cdf0e10cSrcweir     return true;
1225cdf0e10cSrcweir }
1226cdf0e10cSrcweir 
1227cdf0e10cSrcweir // -----------------------------------------------------------------------
1228cdf0e10cSrcweir 
1229*fc9fd3f1SPedro Giffuni sal_Bool Os2SalGraphics::GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
1230cdf0e10cSrcweir {
1231cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>0
1232cdf0e10cSrcweir 	debug_printf("Os2SalGraphics::GetGlyphOutline\n");
1233cdf0e10cSrcweir #endif
1234cdf0e10cSrcweir     rB2DPolyPoly.clear();
1235cdf0e10cSrcweir 
1236*fc9fd3f1SPedro Giffuni     PM_BOOL bRet = FALSE;
1237cdf0e10cSrcweir 
1238cdf0e10cSrcweir     // use unity matrix
1239cdf0e10cSrcweir     MAT2 aMat;
1240cdf0e10cSrcweir     aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
1241cdf0e10cSrcweir     aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
1242cdf0e10cSrcweir 
1243cdf0e10cSrcweir     UINT nGGOFlags = GGO_NATIVE;
1244cdf0e10cSrcweir     if( !(nIndex & GF_ISCHAR) )
1245cdf0e10cSrcweir         nGGOFlags |= GGO_GLYPH_INDEX;
1246cdf0e10cSrcweir     nIndex &= GF_IDXMASK;
1247cdf0e10cSrcweir 
1248cdf0e10cSrcweir     GLYPHMETRICS aGlyphMetrics;
1249cdf0e10cSrcweir     DWORD nSize1 = FT2_ERROR;
1250cdf0e10cSrcweir     nSize1 = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
1251cdf0e10cSrcweir 
1252cdf0e10cSrcweir     if( !nSize1 )       // blank glyphs are ok
1253cdf0e10cSrcweir         bRet = TRUE;
1254cdf0e10cSrcweir     else if( nSize1 != FT2_ERROR )
1255cdf0e10cSrcweir     {
1256*fc9fd3f1SPedro Giffuni         PM_BYTE*   pData = new PM_BYTE[ nSize1 ];
1257cdf0e10cSrcweir         ULONG   nTotalCount = 0;
1258cdf0e10cSrcweir         DWORD   nSize2;
1259cdf0e10cSrcweir         nSize2 = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags,
1260cdf0e10cSrcweir                 &aGlyphMetrics, nSize1, pData, &aMat );
1261cdf0e10cSrcweir 
1262cdf0e10cSrcweir         if( nSize1 == nSize2 )
1263cdf0e10cSrcweir         {
1264cdf0e10cSrcweir             bRet = TRUE;
1265cdf0e10cSrcweir 
1266cdf0e10cSrcweir             int     nPtSize = 512;
1267cdf0e10cSrcweir             Point*  pPoints = new Point[ nPtSize ];
1268*fc9fd3f1SPedro Giffuni             sal_uInt8*   pFlags = new sal_uInt8[ nPtSize ];
1269cdf0e10cSrcweir 
1270cdf0e10cSrcweir             TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData;
1271*fc9fd3f1SPedro Giffuni             while( (PM_BYTE*)pHeader < pData+nSize2 )
1272cdf0e10cSrcweir             {
1273cdf0e10cSrcweir                 // only outline data is interesting
1274cdf0e10cSrcweir                 if( pHeader->dwType != TT_POLYGON_TYPE )
1275cdf0e10cSrcweir                     break;
1276cdf0e10cSrcweir 
1277cdf0e10cSrcweir                 // get start point; next start points are end points
1278cdf0e10cSrcweir                 // of previous segment
1279cdf0e10cSrcweir                 int nPnt = 0;
1280cdf0e10cSrcweir 
1281cdf0e10cSrcweir                 long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
1282cdf0e10cSrcweir                 long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
1283cdf0e10cSrcweir                 pPoints[ nPnt ] = Point( nX, nY );
1284cdf0e10cSrcweir                 pFlags[ nPnt++ ] = POLY_NORMAL;
1285cdf0e10cSrcweir 
1286cdf0e10cSrcweir                 bool bHasOfflinePoints = false;
1287cdf0e10cSrcweir                 TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 );
1288*fc9fd3f1SPedro Giffuni                 pHeader = (TTPOLYGONHEADER*)( (PM_BYTE*)pHeader + pHeader->cb );
1289*fc9fd3f1SPedro Giffuni                 while( (PM_BYTE*)pCurve < (PM_BYTE*)pHeader )
1290cdf0e10cSrcweir                 {
1291cdf0e10cSrcweir                     int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
1292cdf0e10cSrcweir                     if( nPtSize < nNeededSize )
1293cdf0e10cSrcweir                     {
1294cdf0e10cSrcweir                         Point* pOldPoints = pPoints;
1295*fc9fd3f1SPedro Giffuni                         sal_uInt8* pOldFlags = pFlags;
1296cdf0e10cSrcweir                         nPtSize = 2 * nNeededSize;
1297cdf0e10cSrcweir                         pPoints = new Point[ nPtSize ];
1298*fc9fd3f1SPedro Giffuni                         pFlags = new sal_uInt8[ nPtSize ];
1299cdf0e10cSrcweir                         for( int i = 0; i < nPnt; ++i )
1300cdf0e10cSrcweir                         {
1301cdf0e10cSrcweir                             pPoints[ i ] = pOldPoints[ i ];
1302cdf0e10cSrcweir                             pFlags[ i ] = pOldFlags[ i ];
1303cdf0e10cSrcweir                         }
1304cdf0e10cSrcweir                         delete[] pOldPoints;
1305cdf0e10cSrcweir                         delete[] pOldFlags;
1306cdf0e10cSrcweir                     }
1307cdf0e10cSrcweir 
1308cdf0e10cSrcweir                     int i = 0;
1309cdf0e10cSrcweir                     if( TT_PRIM_LINE == pCurve->wType )
1310cdf0e10cSrcweir                     {
1311cdf0e10cSrcweir                         while( i < pCurve->cpfx )
1312cdf0e10cSrcweir                         {
1313cdf0e10cSrcweir                             nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1314cdf0e10cSrcweir                             nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1315cdf0e10cSrcweir                             ++i;
1316cdf0e10cSrcweir                             pPoints[ nPnt ] = Point( nX, nY );
1317cdf0e10cSrcweir                             pFlags[ nPnt ] = POLY_NORMAL;
1318cdf0e10cSrcweir                             ++nPnt;
1319cdf0e10cSrcweir                         }
1320cdf0e10cSrcweir                     }
1321cdf0e10cSrcweir                     else if( TT_PRIM_QSPLINE == pCurve->wType )
1322cdf0e10cSrcweir                     {
1323cdf0e10cSrcweir                         bHasOfflinePoints = true;
1324cdf0e10cSrcweir                         while( i < pCurve->cpfx )
1325cdf0e10cSrcweir                         {
1326cdf0e10cSrcweir                             // get control point of quadratic bezier spline
1327cdf0e10cSrcweir                             nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1328cdf0e10cSrcweir                             nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1329cdf0e10cSrcweir                             ++i;
1330cdf0e10cSrcweir                             Point aControlP( nX, nY );
1331cdf0e10cSrcweir 
1332cdf0e10cSrcweir                             // calculate first cubic control point
1333cdf0e10cSrcweir                             // P0 = 1/3 * (PBeg + 2 * PQControl)
1334cdf0e10cSrcweir                             nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
1335cdf0e10cSrcweir                             nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
1336cdf0e10cSrcweir                             pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
1337cdf0e10cSrcweir                             pFlags[ nPnt+0 ] = POLY_CONTROL;
1338cdf0e10cSrcweir 
1339cdf0e10cSrcweir                             // calculate endpoint of segment
1340cdf0e10cSrcweir                             nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1341cdf0e10cSrcweir                             nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1342cdf0e10cSrcweir 
1343cdf0e10cSrcweir                             if ( i+1 >= pCurve->cpfx )
1344cdf0e10cSrcweir                             {
1345cdf0e10cSrcweir                                 // endpoint is either last point in segment => advance
1346cdf0e10cSrcweir                                 ++i;
1347cdf0e10cSrcweir                             }
1348cdf0e10cSrcweir                             else
1349cdf0e10cSrcweir                             {
1350cdf0e10cSrcweir                                 // or endpoint is the middle of two control points
1351cdf0e10cSrcweir                                 nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
1352cdf0e10cSrcweir                                 nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
1353cdf0e10cSrcweir                                 nX = (nX + 1) / 2;
1354cdf0e10cSrcweir                                 nY = (nY + 1) / 2;
1355cdf0e10cSrcweir                                 // no need to advance, because the current point
1356cdf0e10cSrcweir                                 // is the control point in next bezier spline
1357cdf0e10cSrcweir                             }
1358cdf0e10cSrcweir 
1359cdf0e10cSrcweir                             pPoints[ nPnt+2 ] = Point( nX, nY );
1360cdf0e10cSrcweir                             pFlags[ nPnt+2 ] = POLY_NORMAL;
1361cdf0e10cSrcweir 
1362cdf0e10cSrcweir                             // calculate second cubic control point
1363cdf0e10cSrcweir                             // P1 = 1/3 * (PEnd + 2 * PQControl)
1364cdf0e10cSrcweir                             nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
1365cdf0e10cSrcweir                             nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
1366cdf0e10cSrcweir                             pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
1367cdf0e10cSrcweir                             pFlags[ nPnt+1 ] = POLY_CONTROL;
1368cdf0e10cSrcweir 
1369cdf0e10cSrcweir                             nPnt += 3;
1370cdf0e10cSrcweir                         }
1371cdf0e10cSrcweir                     }
1372cdf0e10cSrcweir 
1373cdf0e10cSrcweir                     // next curve segment
1374cdf0e10cSrcweir                     pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ];
1375cdf0e10cSrcweir                 }
1376cdf0e10cSrcweir 
1377cdf0e10cSrcweir                 // end point is start point for closed contour
1378cdf0e10cSrcweir                 // disabled, because Polygon class closes the contour itself
1379cdf0e10cSrcweir                 // pPoints[nPnt++] = pPoints[0];
1380cdf0e10cSrcweir 				// #i35928#
1381cdf0e10cSrcweir 				// Added again, but add only when not yet closed
1382cdf0e10cSrcweir 				if(pPoints[nPnt - 1] != pPoints[0])
1383cdf0e10cSrcweir 				{
1384cdf0e10cSrcweir                     if( bHasOfflinePoints )
1385cdf0e10cSrcweir                         pFlags[nPnt] = pFlags[0];
1386cdf0e10cSrcweir 
1387cdf0e10cSrcweir 					pPoints[nPnt++] = pPoints[0];
1388cdf0e10cSrcweir 				}
1389cdf0e10cSrcweir 
1390cdf0e10cSrcweir                 // convert y-coordinates W32 -> VCL
1391cdf0e10cSrcweir                 for( int i = 0; i < nPnt; ++i )
1392cdf0e10cSrcweir                     pPoints[i].Y() = -pPoints[i].Y();
1393cdf0e10cSrcweir 
1394cdf0e10cSrcweir                 // insert into polypolygon
1395cdf0e10cSrcweir                 Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) );
1396cdf0e10cSrcweir                 // convert to B2DPolyPolygon
1397cdf0e10cSrcweir                 // TODO: get rid of the intermediate PolyPolygon
1398cdf0e10cSrcweir                 rB2DPolyPoly.append( aPoly.getB2DPolygon() );
1399cdf0e10cSrcweir             }
1400cdf0e10cSrcweir 
1401cdf0e10cSrcweir             delete[] pPoints;
1402cdf0e10cSrcweir             delete[] pFlags;
1403cdf0e10cSrcweir         }
1404cdf0e10cSrcweir 
1405cdf0e10cSrcweir         delete[] pData;
1406cdf0e10cSrcweir     }
1407cdf0e10cSrcweir 
1408cdf0e10cSrcweir     // rescaling needed for the PolyPolygon conversion
1409cdf0e10cSrcweir     if( rB2DPolyPoly.count() )
1410cdf0e10cSrcweir     {
1411*fc9fd3f1SPedro Giffuni         ::basegfx::B2DHomMatrix aMatrix;
1412*fc9fd3f1SPedro Giffuni         aMatrix.scale( 1.0/256, 1.0/256 );
1413*fc9fd3f1SPedro Giffuni         aMatrix.scale( mfFontScale, mfFontScale );
1414*fc9fd3f1SPedro Giffuni         rB2DPolyPoly.transform( aMatrix );
1415cdf0e10cSrcweir     }
1416cdf0e10cSrcweir 
1417cdf0e10cSrcweir     return bRet;
1418cdf0e10cSrcweir }
1419cdf0e10cSrcweir 
1420cdf0e10cSrcweir // -----------------------------------------------------------------------
1421cdf0e10cSrcweir 
1422cdf0e10cSrcweir // TODO:  Replace this class with boost::scoped_array
1423cdf0e10cSrcweir class ScopedCharArray
1424cdf0e10cSrcweir {
1425cdf0e10cSrcweir public:
1426cdf0e10cSrcweir 	inline explicit ScopedCharArray(char * pArray): m_pArray(pArray) {}
1427cdf0e10cSrcweir 
1428cdf0e10cSrcweir 	inline ~ScopedCharArray() { delete[] m_pArray; }
1429cdf0e10cSrcweir 
1430cdf0e10cSrcweir 	inline char * get() const { return m_pArray; }
1431cdf0e10cSrcweir 
1432cdf0e10cSrcweir private:
1433cdf0e10cSrcweir 	char * m_pArray;
1434cdf0e10cSrcweir };
1435cdf0e10cSrcweir 
1436cdf0e10cSrcweir class ScopedFont
1437cdf0e10cSrcweir {
1438cdf0e10cSrcweir public:
1439cdf0e10cSrcweir 	explicit ScopedFont(Os2SalGraphics & rData);
1440cdf0e10cSrcweir 
1441cdf0e10cSrcweir 	~ScopedFont();
1442cdf0e10cSrcweir 
1443cdf0e10cSrcweir private:
1444cdf0e10cSrcweir 	Os2SalGraphics & m_rData;
1445cdf0e10cSrcweir 	ULONG m_hOrigFont;
1446cdf0e10cSrcweir };
1447cdf0e10cSrcweir 
1448cdf0e10cSrcweir ScopedFont::ScopedFont(Os2SalGraphics & rData): m_rData(rData)
1449cdf0e10cSrcweir {
1450cdf0e10cSrcweir #if 0
1451cdf0e10cSrcweir 	m_hOrigFont = m_rData.mhFonts[0];
1452cdf0e10cSrcweir 	m_rData.mhFonts[0] = 0; // avoid deletion of current font
1453cdf0e10cSrcweir #endif
1454cdf0e10cSrcweir }
1455cdf0e10cSrcweir 
1456cdf0e10cSrcweir ScopedFont::~ScopedFont()
1457cdf0e10cSrcweir {
1458cdf0e10cSrcweir #if 0
1459cdf0e10cSrcweir 	if( m_hOrigFont )
1460cdf0e10cSrcweir 	{
1461cdf0e10cSrcweir 		// restore original font, destroy temporary font
1462cdf0e10cSrcweir 		HFONT hTempFont = m_rData.mhFonts[0];
1463cdf0e10cSrcweir 		m_rData.mhFonts[0] = m_hOrigFont;
1464cdf0e10cSrcweir 		SelectObject( m_rData.mhDC, m_hOrigFont );
1465cdf0e10cSrcweir 		DeleteObject( hTempFont );
1466cdf0e10cSrcweir 	}
1467cdf0e10cSrcweir #endif
1468cdf0e10cSrcweir }
1469cdf0e10cSrcweir 
1470cdf0e10cSrcweir class ScopedTrueTypeFont
1471cdf0e10cSrcweir {
1472cdf0e10cSrcweir public:
1473cdf0e10cSrcweir 	inline ScopedTrueTypeFont(): m_pFont(0) {}
1474cdf0e10cSrcweir 
1475cdf0e10cSrcweir 	~ScopedTrueTypeFont();
1476cdf0e10cSrcweir 
1477cdf0e10cSrcweir 	int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
1478cdf0e10cSrcweir 
1479cdf0e10cSrcweir 	inline TrueTypeFont * get() const { return m_pFont; }
1480cdf0e10cSrcweir 
1481cdf0e10cSrcweir private:
1482cdf0e10cSrcweir 	TrueTypeFont * m_pFont;
1483cdf0e10cSrcweir };
1484cdf0e10cSrcweir 
1485cdf0e10cSrcweir ScopedTrueTypeFont::~ScopedTrueTypeFont()
1486cdf0e10cSrcweir {
1487cdf0e10cSrcweir 	if (m_pFont != 0)
1488cdf0e10cSrcweir 		CloseTTFont(m_pFont);
1489cdf0e10cSrcweir }
1490cdf0e10cSrcweir 
1491cdf0e10cSrcweir int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen,
1492cdf0e10cSrcweir 							 sal_uInt32 nFaceNum)
1493cdf0e10cSrcweir {
1494cdf0e10cSrcweir 	OSL_ENSURE(m_pFont == 0, "already open");
1495cdf0e10cSrcweir     return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont);
1496cdf0e10cSrcweir }
1497cdf0e10cSrcweir 
1498*fc9fd3f1SPedro Giffuni sal_Bool Os2SalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
1499cdf0e10cSrcweir 	const ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding,
1500cdf0e10cSrcweir 	sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
1501cdf0e10cSrcweir {
1502*fc9fd3f1SPedro Giffuni 	// TODO: use more of the central font-subsetting code, move stuff there if needed
1503*fc9fd3f1SPedro Giffuni 
1504cdf0e10cSrcweir 	// create matching ImplFontSelectData
1505cdf0e10cSrcweir 	// we need just enough to get to the font file data
1506cdf0e10cSrcweir 	// use height=1000 for easier debugging (to match psprint's font units)
1507cdf0e10cSrcweir 	ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1508cdf0e10cSrcweir 
1509cdf0e10cSrcweir 	// TODO: much better solution: move SetFont and restoration of old font to caller
1510cdf0e10cSrcweir 	ScopedFont aOldFont(*this);
1511cdf0e10cSrcweir 	SetFont( &aIFSD, 0 );
1512cdf0e10cSrcweir 
1513*fc9fd3f1SPedro Giffuni     ImplOs2FontData* pWinFontData = (ImplOs2FontData*)aIFSD.mpFontData;
1514*fc9fd3f1SPedro Giffuni     pWinFontData->UpdateFromHPS( mhPS );
1515*fc9fd3f1SPedro Giffuni     const ImplFontCharMap* pImplFontCharMap = pWinFontData->GetImplFontCharMap();
1516*fc9fd3f1SPedro Giffuni 
1517cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 100
1518cdf0e10cSrcweir 	// get font metrics
1519cdf0e10cSrcweir 	TEXTMETRICA aWinMetric;
1520cdf0e10cSrcweir 	if( !::GetTextMetricsA( mhDC, &aWinMetric ) )
1521cdf0e10cSrcweir 		return FALSE;
1522cdf0e10cSrcweir 
1523cdf0e10cSrcweir 	DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" );
1524cdf0e10cSrcweir 	DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
1525cdf0e10cSrcweir #endif
1526cdf0e10cSrcweir 
1527*fc9fd3f1SPedro Giffuni     rtl::OUString aSysPath;
1528*fc9fd3f1SPedro Giffuni     if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
1529cdf0e10cSrcweir         return FALSE;
1530*fc9fd3f1SPedro Giffuni     const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
1531*fc9fd3f1SPedro Giffuni     const ByteString aToFile( aSysPath.getStr(), (xub_StrLen)aSysPath.getLength(), aThreadEncoding );
1532*fc9fd3f1SPedro Giffuni 
1533*fc9fd3f1SPedro Giffuni 	// check if the font has a CFF-table
1534*fc9fd3f1SPedro Giffuni 	const DWORD nCffTag = CalcTag( "CFF " );
1535*fc9fd3f1SPedro Giffuni 	const RawFontData aRawCffData( mhPS, nCffTag );
1536*fc9fd3f1SPedro Giffuni 	if( aRawCffData.get() )
1537*fc9fd3f1SPedro Giffuni 	{
1538*fc9fd3f1SPedro Giffuni 		long nRealGlyphIds[ 256 ];
1539*fc9fd3f1SPedro Giffuni 		for( int i = 0; i < nGlyphCount; ++i )
1540*fc9fd3f1SPedro Giffuni 		{
1541*fc9fd3f1SPedro Giffuni 			// TODO: remap notdef glyph if needed
1542*fc9fd3f1SPedro Giffuni 			// TODO: use GDI's GetGlyphIndices instead? Does it handle GSUB properly?
1543*fc9fd3f1SPedro Giffuni 			sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
1544*fc9fd3f1SPedro Giffuni 			if( pGlyphIDs[i] & GF_ISCHAR ) // remaining pseudo-glyphs need to be translated
1545*fc9fd3f1SPedro Giffuni 				nGlyphIdx = pImplFontCharMap->GetGlyphIndex( nGlyphIdx );
1546*fc9fd3f1SPedro Giffuni 			if( (pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0)	// TODO: vertical substitution
1547*fc9fd3f1SPedro Giffuni 				{/*####*/}
1548*fc9fd3f1SPedro Giffuni 
1549*fc9fd3f1SPedro Giffuni 			nRealGlyphIds[i] = nGlyphIdx;
1550*fc9fd3f1SPedro Giffuni 		}
1551*fc9fd3f1SPedro Giffuni 
1552*fc9fd3f1SPedro Giffuni 		// provide a font subset from the CFF-table
1553*fc9fd3f1SPedro Giffuni 		FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
1554*fc9fd3f1SPedro Giffuni 		rInfo.LoadFont( FontSubsetInfo::CFF_FONT, aRawCffData.get(), aRawCffData.size() );
1555*fc9fd3f1SPedro Giffuni 		bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
1556*fc9fd3f1SPedro Giffuni 				nRealGlyphIds, pEncoding, nGlyphCount, pGlyphWidths );
1557*fc9fd3f1SPedro Giffuni 		fclose( pOutFile );
1558*fc9fd3f1SPedro Giffuni 		return bRC;
1559*fc9fd3f1SPedro Giffuni 	}
1560*fc9fd3f1SPedro Giffuni 
1561*fc9fd3f1SPedro Giffuni     // get raw font file data
1562*fc9fd3f1SPedro Giffuni     const RawFontData xRawFontData( mhPS, NULL );
1563*fc9fd3f1SPedro Giffuni     if( !xRawFontData.get() )
1564cdf0e10cSrcweir 		return FALSE;
1565cdf0e10cSrcweir 
1566cdf0e10cSrcweir 	// open font file
1567cdf0e10cSrcweir 	sal_uInt32 nFaceNum = 0;
1568cdf0e10cSrcweir 	if( !*xRawFontData.get() )	// TTC candidate
1569cdf0e10cSrcweir 		nFaceNum = ~0U;	 // indicate "TTC font extracts only"
1570cdf0e10cSrcweir 
1571cdf0e10cSrcweir 	ScopedTrueTypeFont aSftTTF;
1572*fc9fd3f1SPedro Giffuni 	int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
1573cdf0e10cSrcweir 	if( nRC != SF_OK )
1574cdf0e10cSrcweir 		return FALSE;
1575cdf0e10cSrcweir 
1576cdf0e10cSrcweir 	TTGlobalFontInfo aTTInfo;
1577cdf0e10cSrcweir 	::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
1578*fc9fd3f1SPedro Giffuni 	rInfo.m_nFontType   = FontSubsetInfo::SFNT_TTF;
1579cdf0e10cSrcweir 	rInfo.m_aPSName		= ImplSalGetUniString( aTTInfo.psname );
1580cdf0e10cSrcweir 	rInfo.m_nAscent		= +aTTInfo.winAscent;
1581cdf0e10cSrcweir 	rInfo.m_nDescent	= -aTTInfo.winDescent;
1582cdf0e10cSrcweir 	rInfo.m_aFontBBox	= Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
1583cdf0e10cSrcweir 									Point( aTTInfo.xMax, aTTInfo.yMax ) );
1584cdf0e10cSrcweir 	rInfo.m_nCapHeight	= aTTInfo.yMax; // Well ...
1585cdf0e10cSrcweir 
1586*fc9fd3f1SPedro Giffuni 	// subset TTF-glyphs and get their properties
1587cdf0e10cSrcweir 	// take care that subset fonts require the NotDef glyph in pos 0
1588cdf0e10cSrcweir 	int nOrigCount = nGlyphCount;
1589cdf0e10cSrcweir 	USHORT	  aShortIDs[ 256 ];
1590cdf0e10cSrcweir 	sal_uInt8 aTempEncs[ 256 ];
1591cdf0e10cSrcweir 
1592cdf0e10cSrcweir 	int nNotDef=-1, i;
1593cdf0e10cSrcweir 	for( i = 0; i < nGlyphCount; ++i )
1594cdf0e10cSrcweir 	{
1595cdf0e10cSrcweir 		aTempEncs[i] = pEncoding[i];
1596cdf0e10cSrcweir 		sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
1597cdf0e10cSrcweir 		if( pGlyphIDs[i] & GF_ISCHAR )
1598cdf0e10cSrcweir 		{
1599*fc9fd3f1SPedro Giffuni 			sal_Unicode cChar = static_cast<sal_Unicode>(nGlyphIdx); // TODO: sal_UCS4
1600*fc9fd3f1SPedro Giffuni 			const bool bVertical = ((pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0);
1601*fc9fd3f1SPedro Giffuni 			nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical );
1602*fc9fd3f1SPedro Giffuni 			if( (nGlyphIdx == 0) && pFont->IsSymbolFont() )
1603cdf0e10cSrcweir 			{
1604cdf0e10cSrcweir 				// #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
1605*fc9fd3f1SPedro Giffuni 				cChar = (cChar & 0xF000) ? (cChar & 0x00FF) : (cChar | 0xF000);
1606*fc9fd3f1SPedro Giffuni 				nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical );
1607cdf0e10cSrcweir 			}
1608cdf0e10cSrcweir 		}
1609cdf0e10cSrcweir 		aShortIDs[i] = static_cast<USHORT>( nGlyphIdx );
1610cdf0e10cSrcweir 		if( !nGlyphIdx )
1611cdf0e10cSrcweir 			if( nNotDef < 0 )
1612cdf0e10cSrcweir 				nNotDef = i; // first NotDef glyph found
1613cdf0e10cSrcweir 	}
1614cdf0e10cSrcweir 
1615cdf0e10cSrcweir 	if( nNotDef != 0 )
1616cdf0e10cSrcweir 	{
1617cdf0e10cSrcweir 		// add fake NotDef glyph if needed
1618cdf0e10cSrcweir 		if( nNotDef < 0 )
1619cdf0e10cSrcweir 			nNotDef = nGlyphCount++;
1620cdf0e10cSrcweir 
1621cdf0e10cSrcweir 		// NotDef glyph must be in pos 0 => swap glyphids
1622cdf0e10cSrcweir 		aShortIDs[ nNotDef ] = aShortIDs[0];
1623cdf0e10cSrcweir 		aTempEncs[ nNotDef ] = aTempEncs[0];
1624cdf0e10cSrcweir 		aShortIDs[0] = 0;
1625cdf0e10cSrcweir 		aTempEncs[0] = 0;
1626cdf0e10cSrcweir 	}
1627cdf0e10cSrcweir 	DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
1628cdf0e10cSrcweir 
1629cdf0e10cSrcweir 	// fill pWidth array
1630cdf0e10cSrcweir 	TTSimpleGlyphMetrics* pMetrics =
1631cdf0e10cSrcweir 		::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical );
1632cdf0e10cSrcweir 	if( !pMetrics )
1633cdf0e10cSrcweir 		return FALSE;
1634cdf0e10cSrcweir 	sal_uInt16 nNotDefAdv	= pMetrics[0].adv;
1635cdf0e10cSrcweir 	pMetrics[0].adv			= pMetrics[nNotDef].adv;
1636cdf0e10cSrcweir 	pMetrics[nNotDef].adv	= nNotDefAdv;
1637cdf0e10cSrcweir 	for( i = 0; i < nOrigCount; ++i )
1638cdf0e10cSrcweir 		pGlyphWidths[i] = pMetrics[i].adv;
1639cdf0e10cSrcweir 	free( pMetrics );
1640cdf0e10cSrcweir 
1641cdf0e10cSrcweir 	// write subset into destination file
1642cdf0e10cSrcweir 	nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs,
1643cdf0e10cSrcweir 			aTempEncs, nGlyphCount, 0, NULL, 0 );
1644*fc9fd3f1SPedro Giffuni 	return (nRC == SF_OK);
1645cdf0e10cSrcweir }
1646cdf0e10cSrcweir 
1647cdf0e10cSrcweir //--------------------------------------------------------------------------
1648cdf0e10cSrcweir 
1649cdf0e10cSrcweir const void* Os2SalGraphics::GetEmbedFontData( const ImplFontData* pFont,
1650cdf0e10cSrcweir 	const sal_Ucs* pUnicodes, sal_Int32* pCharWidths,
1651cdf0e10cSrcweir 	FontSubsetInfo& rInfo, long* pDataLen )
1652cdf0e10cSrcweir {
1653cdf0e10cSrcweir 	// create matching ImplFontSelectData
1654cdf0e10cSrcweir 	// we need just enough to get to the font file data
1655cdf0e10cSrcweir 	ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1656cdf0e10cSrcweir 
1657cdf0e10cSrcweir 	// TODO: much better solution: move SetFont and restoration of old font to caller
1658cdf0e10cSrcweir 	ScopedFont aOldFont(*this);
1659cdf0e10cSrcweir 	SetFont( &aIFSD, 0 );
1660cdf0e10cSrcweir 
1661cdf0e10cSrcweir 	// get the raw font file data
1662*fc9fd3f1SPedro Giffuni 	RawFontData aRawFontData( mhPS );
1663*fc9fd3f1SPedro Giffuni 	*pDataLen = aRawFontData.size();
1664*fc9fd3f1SPedro Giffuni 	if( !aRawFontData.get() )
1665cdf0e10cSrcweir 		return NULL;
1666cdf0e10cSrcweir 
1667cdf0e10cSrcweir 	// get important font properties
1668cdf0e10cSrcweir 	FONTMETRICS aOS2Metric;
1669cdf0e10cSrcweir 	if (Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric ) == GPI_ERROR)
1670cdf0e10cSrcweir 			*pDataLen = 0;
1671*fc9fd3f1SPedro Giffuni 	rInfo.m_nFontType	= FontSubsetInfo::ANY_TYPE1;
1672cdf0e10cSrcweir 	rInfo.m_aPSName		= ImplSalGetUniString( aOS2Metric.szFacename );
1673cdf0e10cSrcweir 	rInfo.m_nAscent		= +aOS2Metric.lMaxAscender;
1674cdf0e10cSrcweir 	rInfo.m_nDescent	= -aOS2Metric.lMaxDescender;
1675cdf0e10cSrcweir 	rInfo.m_aFontBBox	= Rectangle( Point( 0, -aOS2Metric.lMaxDescender ),
1676cdf0e10cSrcweir 			  Point( aOS2Metric.lMaxCharInc, aOS2Metric.lMaxAscender+aOS2Metric.lExternalLeading ) );
1677cdf0e10cSrcweir 	rInfo.m_nCapHeight	= aOS2Metric.lMaxAscender; // Well ...
1678cdf0e10cSrcweir 
1679cdf0e10cSrcweir 	// get individual character widths
1680cdf0e10cSrcweir 	for( int i = 0; i < 256; ++i )
1681cdf0e10cSrcweir 	{
1682cdf0e10cSrcweir 		LONG nCharWidth = 0;
1683cdf0e10cSrcweir 		const sal_Ucs cChar = pUnicodes[i];
1684cdf0e10cSrcweir 		if( !Ft2QueryStringWidthW( mhPS, (LPWSTR)&cChar, 1, &nCharWidth ) )
1685cdf0e10cSrcweir 			*pDataLen = 0;
1686cdf0e10cSrcweir 		pCharWidths[i] = nCharWidth;
1687cdf0e10cSrcweir 	}
1688cdf0e10cSrcweir 
1689cdf0e10cSrcweir 	if( !*pDataLen )
1690*fc9fd3f1SPedro Giffuni 		return NULL;
1691cdf0e10cSrcweir 
1692*fc9fd3f1SPedro Giffuni 	const unsigned char* pData = aRawFontData.steal();
1693*fc9fd3f1SPedro Giffuni 	return (void*)pData;
1694cdf0e10cSrcweir }
1695cdf0e10cSrcweir 
1696cdf0e10cSrcweir //--------------------------------------------------------------------------
1697cdf0e10cSrcweir 
1698cdf0e10cSrcweir void Os2SalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
1699cdf0e10cSrcweir {
1700cdf0e10cSrcweir 	delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
1701cdf0e10cSrcweir }
1702cdf0e10cSrcweir 
1703cdf0e10cSrcweir const Ucs2SIntMap* Os2SalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
1704cdf0e10cSrcweir {
1705cdf0e10cSrcweir     // TODO: even for builtin fonts we get here... why?
1706cdf0e10cSrcweir     if( !pFont->IsEmbeddable() )
1707cdf0e10cSrcweir         return NULL;
1708cdf0e10cSrcweir 
1709cdf0e10cSrcweir     // fill the encoding vector
1710*fc9fd3f1SPedro Giffuni     // currently no nonencoded vector
1711cdf0e10cSrcweir     if( pNonEncoded )
1712cdf0e10cSrcweir         *pNonEncoded = NULL;
1713cdf0e10cSrcweir 
1714*fc9fd3f1SPedro Giffuni     const ImplOs2FontData* pWinFontData = static_cast<const ImplOs2FontData*>(pFont);
1715*fc9fd3f1SPedro Giffuni     const Ucs2SIntMap* pEncoding = pWinFontData->GetEncodingVector();
1716*fc9fd3f1SPedro Giffuni     if( pEncoding == NULL )
1717*fc9fd3f1SPedro Giffuni     {
1718*fc9fd3f1SPedro Giffuni         Ucs2SIntMap* pNewEncoding = new Ucs2SIntMap;
1719*fc9fd3f1SPedro Giffuni         #if 0
1720*fc9fd3f1SPedro Giffuni         // TODO: get correct encoding vector
1721*fc9fd3f1SPedro Giffuni         GLYPHSET aGlyphSet;
1722*fc9fd3f1SPedro Giffuni         aGlyphSet.cbThis = sizeof(aGlyphSet);
1723*fc9fd3f1SPedro Giffuni         DWORD aW = ::GetFontUnicodeRanges( mhPS, &aGlyphSet);
1724*fc9fd3f1SPedro Giffuni         #else
1725*fc9fd3f1SPedro Giffuni         for( sal_Unicode i = 32; i < 256; ++i )
1726*fc9fd3f1SPedro Giffuni             (*pNewEncoding)[i] = i;
1727*fc9fd3f1SPedro Giffuni         #endif
1728*fc9fd3f1SPedro Giffuni         pWinFontData->SetEncodingVector( pNewEncoding );
1729*fc9fd3f1SPedro Giffuni 	pEncoding = pNewEncoding;
1730*fc9fd3f1SPedro Giffuni     }
1731*fc9fd3f1SPedro Giffuni 
1732*fc9fd3f1SPedro Giffuni     return pEncoding;
1733cdf0e10cSrcweir }
1734cdf0e10cSrcweir 
1735cdf0e10cSrcweir //--------------------------------------------------------------------------
1736cdf0e10cSrcweir 
1737cdf0e10cSrcweir void Os2SalGraphics::GetGlyphWidths( const ImplFontData* pFont,
1738cdf0e10cSrcweir                                      bool bVertical,
1739cdf0e10cSrcweir                                      Int32Vector& rWidths,
1740cdf0e10cSrcweir                                      Ucs2UIntMap& rUnicodeEnc )
1741cdf0e10cSrcweir {
1742cdf0e10cSrcweir     // create matching ImplFontSelectData
1743cdf0e10cSrcweir     // we need just enough to get to the font file data
1744cdf0e10cSrcweir     ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1745cdf0e10cSrcweir 
1746cdf0e10cSrcweir     // TODO: much better solution: move SetFont and restoration of old font to caller
1747cdf0e10cSrcweir     ScopedFont aOldFont(*this);
1748cdf0e10cSrcweir 
1749cdf0e10cSrcweir     float fScale = 0.0;
1750cdf0e10cSrcweir     ImplDoSetFont( &aIFSD, fScale, 0);
1751cdf0e10cSrcweir 
1752cdf0e10cSrcweir     if( pFont->IsSubsettable() )
1753cdf0e10cSrcweir     {
1754cdf0e10cSrcweir         // get raw font file data
1755*fc9fd3f1SPedro Giffuni 	const RawFontData xRawFontData( mhPS );
1756*fc9fd3f1SPedro Giffuni 	if( !xRawFontData.get() )
1757cdf0e10cSrcweir 		return;
1758cdf0e10cSrcweir 
1759cdf0e10cSrcweir         // open font file
1760cdf0e10cSrcweir         sal_uInt32 nFaceNum = 0;
1761cdf0e10cSrcweir         if( !*xRawFontData.get() )  // TTC candidate
1762cdf0e10cSrcweir             nFaceNum = ~0U;  // indicate "TTC font extracts only"
1763cdf0e10cSrcweir 
1764cdf0e10cSrcweir         ScopedTrueTypeFont aSftTTF;
1765*fc9fd3f1SPedro Giffuni         int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
1766cdf0e10cSrcweir         if( nRC != SF_OK )
1767cdf0e10cSrcweir             return;
1768cdf0e10cSrcweir 
1769cdf0e10cSrcweir         int nGlyphs = GetTTGlyphCount( aSftTTF.get() );
1770cdf0e10cSrcweir         if( nGlyphs > 0 )
1771cdf0e10cSrcweir         {
1772cdf0e10cSrcweir             rWidths.resize(nGlyphs);
1773cdf0e10cSrcweir             std::vector<sal_uInt16> aGlyphIds(nGlyphs);
1774cdf0e10cSrcweir             for( int i = 0; i < nGlyphs; i++ )
1775cdf0e10cSrcweir                 aGlyphIds[i] = sal_uInt16(i);
1776cdf0e10cSrcweir             TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(),
1777cdf0e10cSrcweir                                                                         &aGlyphIds[0],
1778cdf0e10cSrcweir                                                                         nGlyphs,
1779cdf0e10cSrcweir                                                                         bVertical ? 1 : 0 );
1780cdf0e10cSrcweir             if( pMetrics )
1781cdf0e10cSrcweir             {
1782cdf0e10cSrcweir                 for( int i = 0; i< nGlyphs; i++ )
1783cdf0e10cSrcweir                     rWidths[i] = pMetrics[i].adv;
1784cdf0e10cSrcweir                 free( pMetrics );
1785cdf0e10cSrcweir                 rUnicodeEnc.clear();
1786cdf0e10cSrcweir             }
1787cdf0e10cSrcweir             const ImplOs2FontData* pWinFont = static_cast<const ImplOs2FontData*>(pFont);
1788cdf0e10cSrcweir             const ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap();
1789cdf0e10cSrcweir 			DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" );
1790cdf0e10cSrcweir 
1791cdf0e10cSrcweir 			int nCharCount = pMap->GetCharCount();
1792cdf0e10cSrcweir             sal_uInt32 nChar = pMap->GetFirstChar();
1793cdf0e10cSrcweir 			for( int i = 0; i < nCharCount; i++ )
1794cdf0e10cSrcweir             {
1795cdf0e10cSrcweir                 if( nChar < 0x00010000 )
1796cdf0e10cSrcweir                 {
1797cdf0e10cSrcweir                     sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(),
1798cdf0e10cSrcweir                                                    static_cast<sal_uInt16>(nChar),
1799cdf0e10cSrcweir                                                    bVertical ? 1 : 0 );
1800cdf0e10cSrcweir                     if( nGlyph )
1801cdf0e10cSrcweir                         rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph;
1802cdf0e10cSrcweir                 }
1803cdf0e10cSrcweir 				nChar = pMap->GetNextChar( nChar );
1804cdf0e10cSrcweir             }
1805cdf0e10cSrcweir         }
1806cdf0e10cSrcweir     }
1807cdf0e10cSrcweir     else if( pFont->IsEmbeddable() )
1808cdf0e10cSrcweir     {
1809cdf0e10cSrcweir         // get individual character widths
1810cdf0e10cSrcweir         rWidths.clear();
1811cdf0e10cSrcweir         rUnicodeEnc.clear();
1812cdf0e10cSrcweir         rWidths.reserve( 224 );
1813cdf0e10cSrcweir         for( sal_Unicode i = 32; i < 256; ++i )
1814cdf0e10cSrcweir         {
1815cdf0e10cSrcweir             int nCharWidth = 0;
1816cdf0e10cSrcweir             if( Ft2QueryStringWidthW( mhPS, (LPWSTR)&i, 1, (LONG*)&nCharWidth ) )
1817cdf0e10cSrcweir             {
1818cdf0e10cSrcweir                 rUnicodeEnc[ i ] = rWidths.size();
1819cdf0e10cSrcweir                 rWidths.push_back( nCharWidth );
1820cdf0e10cSrcweir             }
1821cdf0e10cSrcweir         }
1822cdf0e10cSrcweir     }
1823cdf0e10cSrcweir }
1824cdf0e10cSrcweir 
1825cdf0e10cSrcweir //--------------------------------------------------------------------------
1826cdf0e10cSrcweir 
1827cdf0e10cSrcweir void Os2SalGraphics::DrawServerFontLayout( const ServerFontLayout& )
1828cdf0e10cSrcweir {}
1829cdf0e10cSrcweir 
1830cdf0e10cSrcweir //--------------------------------------------------------------------------
1831cdf0e10cSrcweir 
1832cdf0e10cSrcweir SystemFontData Os2SalGraphics::GetSysFontData( int nFallbacklevel ) const
1833cdf0e10cSrcweir {
1834cdf0e10cSrcweir     SystemFontData aSysFontData;
1835cdf0e10cSrcweir 
1836cdf0e10cSrcweir     if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
1837cdf0e10cSrcweir     if (nFallbacklevel < 0 ) nFallbacklevel = 0;
1838cdf0e10cSrcweir 
1839cdf0e10cSrcweir     aSysFontData.nSize = sizeof( SystemFontData );
1840cdf0e10cSrcweir     aSysFontData.hFont = mhFonts[nFallbacklevel];
1841cdf0e10cSrcweir     aSysFontData.bFakeBold = false;
1842cdf0e10cSrcweir     aSysFontData.bFakeItalic = false;
1843cdf0e10cSrcweir     aSysFontData.bAntialias = true;
1844cdf0e10cSrcweir     aSysFontData.bVerticalCharacterType = false;
1845cdf0e10cSrcweir 
1846cdf0e10cSrcweir     return aSysFontData;
1847cdf0e10cSrcweir }
1848cdf0e10cSrcweir 
1849cdf0e10cSrcweir //--------------------------------------------------------------------------
1850