merge the formfield patch from ooo-build
[ooovba.git] / vcl / os2 / source / gdi / salgdi3.cxx
blobc50d7a9e42dc68363e1d2cf0bd803692d09ea801
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: salgdi3.cxx,v $
10 * $Revision: 1.8 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #define INCL_GRE_STRINGS
32 #define INCL_GPI
33 #define INCL_DOS
35 #include <string.h>
36 #include <stdlib.h>
37 #include <math.h>
38 #include <svpm.h>
40 #define _SV_SALGDI3_CXX
41 #include <tools/svwin.h>
42 #include <rtl/tencinfo.h>
43 #ifndef _OSL_FILE_HXX
44 #include <osl/file.hxx>
45 #endif
46 #ifndef _OSL_THREAD_HXX
47 #include <osl/thread.hxx>
48 #endif
49 #ifndef _OSL_PROCESS_HXX
50 #include <osl/process.h>
51 #endif
52 #include <vcl/svapp.hxx>
53 #include <saldata.hxx>
54 #include <salgdi.h>
55 #include <vcl/font.hxx>
56 #include <vcl/sallayout.hxx>
57 #include <tools/poly.hxx>
58 #include <tools/debug.hxx>
59 #include <rtl/textcvt.h>
60 #include <tools/debug.hxx>
61 #include <saldata.hxx>
62 #include <salgdi.h>
63 #ifndef _SV_OUTFONT_HXX
64 #include <vcl/outfont.hxx>
65 #endif
66 #include <sallayout.h>
67 #include <tools/poly.hxx>
68 #include <basegfx/polygon/b2dpolygon.hxx>
69 #include <basegfx/polygon/b2dpolypolygon.hxx>
70 #include <basegfx/matrix/b2dhommatrix.hxx>
72 #ifndef __H_FT2LIB
73 #include <wingdi.h>
74 #include <ft2lib.h>
75 #endif
77 #include "sft.hxx"
79 #ifdef GCP_KERN_HACK
80 #include <algorithm>
81 #endif
83 using namespace vcl;
85 // -----------
86 // - Inlines -
87 // -----------
90 inline W32FIXED FixedFromDouble( double d )
92 const long l = (long) ( d * 65536. );
93 return *(W32FIXED*) &l;
96 // -----------------------------------------------------------------------
98 inline int IntTimes256FromFixed(W32FIXED f)
100 int nFixedTimes256 = (f.value << 8) + ((f.fract+0x80) >> 8);
101 return nFixedTimes256;
104 // -----------
105 // - Defines -
106 // -----------
108 // this is a special codepage code, used to identify OS/2 symbol font.
109 #define SYMBOL_CHARSET 65400
111 // =======================================================================
113 UniString ImplSalGetUniString( const sal_Char* pStr, xub_StrLen nLen = STRING_LEN)
115 return UniString( pStr, nLen, gsl_getSystemTextEncoding(),
116 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
117 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
118 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
121 // =======================================================================
123 static USHORT ImplSalToCharSet( CharSet eCharSet )
125 // !!! Fuer DBCS-Systeme muss dieser Code auskommentiert werden und 0
126 // !!! zurueckgegeben werden, solange die DBCS-Charsets nicht
127 // !!! durchgereicht werden
129 switch ( eCharSet )
131 case RTL_TEXTENCODING_IBM_437:
132 return 437;
134 case RTL_TEXTENCODING_IBM_850:
135 return 850;
137 case RTL_TEXTENCODING_IBM_860:
138 return 860;
140 case RTL_TEXTENCODING_IBM_861:
141 return 861;
143 case RTL_TEXTENCODING_IBM_863:
144 return 863;
146 case RTL_TEXTENCODING_IBM_865:
147 return 865;
148 case RTL_TEXTENCODING_MS_1252:
149 return 1004;
150 case RTL_TEXTENCODING_SYMBOL:
151 return 65400;
154 return 0;
157 // -----------------------------------------------------------------------
159 static CharSet ImplCharSetToSal( USHORT usCodePage )
161 switch ( usCodePage )
163 case 437:
164 return RTL_TEXTENCODING_IBM_437;
166 case 850:
167 return RTL_TEXTENCODING_IBM_850;
169 case 860:
170 return RTL_TEXTENCODING_IBM_860;
172 case 861:
173 return RTL_TEXTENCODING_IBM_861;
175 case 863:
176 return RTL_TEXTENCODING_IBM_863;
178 case 865:
179 return RTL_TEXTENCODING_IBM_865;
180 case 1004:
181 return RTL_TEXTENCODING_MS_1252;
182 case 65400:
183 return RTL_TEXTENCODING_SYMBOL;
186 return RTL_TEXTENCODING_DONTKNOW;
189 // -----------------------------------------------------------------------
191 static FontFamily ImplFamilyToSal( BYTE bFamilyType )
193 switch ( bFamilyType )
195 case 4:
196 return FAMILY_DECORATIVE;
197 case 3:
198 return FAMILY_SCRIPT;
201 return FAMILY_DONTKNOW;
204 // -----------------------------------------------------------------------
206 static FontWeight ImplWeightToSal( USHORT nWeight )
208 // Falls sich jemand an die alte Doku gehalten hat
209 if ( nWeight > 999 )
210 nWeight /= 1000;
212 switch ( nWeight )
214 case 1:
215 return WEIGHT_THIN;
217 case 2:
218 return WEIGHT_ULTRALIGHT;
220 case 3:
221 return WEIGHT_LIGHT;
223 case 4:
224 return WEIGHT_SEMILIGHT;
226 case 5:
227 return WEIGHT_NORMAL;
229 case 6:
230 return WEIGHT_SEMIBOLD;
232 case 7:
233 return WEIGHT_BOLD;
235 case 8:
236 return WEIGHT_ULTRABOLD;
238 case 9:
239 return WEIGHT_BLACK;
242 return WEIGHT_DONTKNOW;
245 // -----------------------------------------------------------------------
247 static UniString ImpStyleNameToSal( const char* pFamilyName,
248 const char* pFaceName,
249 USHORT nLen )
251 if ( !nLen )
252 nLen = strlen(pFamilyName);
254 // strip FamilyName from FaceName
255 if ( strncmp( pFamilyName, pFaceName, nLen ) == 0 )
257 USHORT nFaceLen = (USHORT)strlen( pFaceName+nLen );
258 // Ist Facename laenger, schneiden wir den FamilyName ab
259 if ( nFaceLen > 1 )
260 return UniString( pFaceName+(nLen+1), gsl_getSystemTextEncoding());
261 else
262 return UniString();
264 else
265 return UniString( pFaceName, gsl_getSystemTextEncoding());
268 // -----------------------------------------------------------------------
270 inline FontPitch ImplLogPitchToSal( BYTE fsType )
272 if ( fsType & FM_TYPE_FIXED )
273 return PITCH_FIXED;
274 else
275 return PITCH_VARIABLE;
278 // -----------------------------------------------------------------------
280 inline BYTE ImplPitchToWin( FontPitch ePitch )
282 if ( ePitch == PITCH_FIXED )
283 return FM_TYPE_FIXED;
284 //else if ( ePitch == PITCH_VARIABLE )
286 return 0;
289 // -----------------------------------------------------------------------
291 static ImplDevFontAttributes Os2Font2DevFontAttributes( const PFONTMETRICS pFontMetric)
293 ImplDevFontAttributes aDFA;
295 // get font face attributes
296 aDFA.meFamily = ImplFamilyToSal( pFontMetric->panose.bFamilyType);
297 aDFA.meWidthType = WIDTH_DONTKNOW;
298 aDFA.meWeight = ImplWeightToSal( pFontMetric->usWeightClass);
299 aDFA.meItalic = (pFontMetric->fsSelection & FM_SEL_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE;
300 aDFA.mePitch = ImplLogPitchToSal( pFontMetric->fsType );
301 aDFA.mbSymbolFlag = (pFontMetric->usCodePage == SYMBOL_CHARSET);
303 // get the font face name
304 // the maName field stores the font name without the style, so under OS/2
305 // we must use the family name
306 aDFA.maName = UniString( pFontMetric->szFamilyname, gsl_getSystemTextEncoding());
308 aDFA.maStyleName = ImpStyleNameToSal( pFontMetric->szFamilyname,
309 pFontMetric->szFacename,
310 strlen( pFontMetric->szFamilyname) );
312 // get device specific font attributes
313 aDFA.mbOrientation = (pFontMetric->fsDefn & FM_DEFN_OUTLINE) != 0;
314 aDFA.mbDevice = (pFontMetric->fsDefn & FM_DEFN_GENERIC) ? FALSE : TRUE;
316 aDFA.mbEmbeddable = false;
317 aDFA.mbSubsettable = false;
318 DWORD fontType = Ft2QueryFontType( 0, pFontMetric->szFamilyname);
319 if( fontType == FT2_FONTTYPE_TRUETYPE && !aDFA.mbDevice)
320 aDFA.mbSubsettable = true;
321 // for now we can only embed Type1 fonts
322 if( fontType == FT2_FONTTYPE_TYPE1 )
323 aDFA.mbEmbeddable = true;
325 // heuristics for font quality
326 // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
327 // - subsetting > embedding > none
328 aDFA.mnQuality = 0;
329 if( fontType == FT2_FONTTYPE_TRUETYPE )
330 aDFA.mnQuality += 50;
331 if( aDFA.mbSubsettable )
332 aDFA.mnQuality += 200;
333 else if( aDFA.mbEmbeddable )
334 aDFA.mnQuality += 100;
336 // #i38665# prefer Type1 versions of the standard postscript fonts
337 if( aDFA.mbEmbeddable )
339 if( aDFA.maName.EqualsAscii( "AvantGarde" )
340 || aDFA.maName.EqualsAscii( "Bookman" )
341 || aDFA.maName.EqualsAscii( "Courier" )
342 || aDFA.maName.EqualsAscii( "Helvetica" )
343 || aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
344 || aDFA.maName.EqualsAscii( "Palatino" )
345 || aDFA.maName.EqualsAscii( "Symbol" )
346 || aDFA.maName.EqualsAscii( "Times" )
347 || aDFA.maName.EqualsAscii( "ZapfChancery" )
348 || aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
349 aDFA.mnQuality += 500;
352 aDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW;
353 aDFA.meAntiAlias = ANTIALIAS_DONTKNOW;
355 // TODO: add alias names
357 return aDFA;
360 // =======================================================================
362 // -----------------------------------------------------------------------
364 // =======================================================================
366 ImplOs2FontData::ImplOs2FontData( PFONTMETRICS _pFontMetric,
367 int nHeight, BYTE nPitchAndFamily )
368 : ImplFontData( Os2Font2DevFontAttributes(_pFontMetric), 0 ),
369 pFontMetric( _pFontMetric ),
370 meOs2CharSet( _pFontMetric->usCodePage),
371 mnPitchAndFamily( nPitchAndFamily ),
372 mpFontCharSets( NULL ),
373 mpUnicodeMap( NULL ),
374 mbDisableGlyphApi( false ),
375 mbHasKoreanRange( false ),
376 mbHasCJKSupport( false ),
377 mbAliasSymbolsLow( false ),
378 mbAliasSymbolsHigh( false ),
379 mnId( 0 )
381 SetBitmapSize( 0, nHeight );
384 // -----------------------------------------------------------------------
386 ImplOs2FontData::~ImplOs2FontData()
388 delete[] mpFontCharSets;
390 if( mpUnicodeMap )
391 mpUnicodeMap->DeReference();
394 // -----------------------------------------------------------------------
396 sal_IntPtr ImplOs2FontData::GetFontId() const
398 return mnId;
401 // -----------------------------------------------------------------------
403 void ImplOs2FontData::UpdateFromHPS( HPS hPS ) const
405 // short circuit if already initialized
406 if( mpUnicodeMap != NULL )
407 return;
409 ReadCmapTable( hPS );
410 ReadOs2Table( hPS );
412 // even if the font works some fonts have problems with the glyph API
413 // => the heuristic below tries to figure out which fonts have the problem
414 DWORD fontType = Ft2QueryFontType( 0, pFontMetric->szFacename);
415 if( fontType != FT2_FONTTYPE_TRUETYPE
416 && (pFontMetric->fsDefn & FM_DEFN_GENERIC) == 0)
417 mbDisableGlyphApi = true;
420 // -----------------------------------------------------------------------
422 #ifdef GNG_VERT_HACK
423 bool ImplOs2FontData::HasGSUBstitutions( HPS hPS ) const
425 if( !mbGsubRead )
426 ReadGsubTable( hPS );
427 return !maGsubTable.empty();
430 // -----------------------------------------------------------------------
432 bool ImplOs2FontData::IsGSUBstituted( sal_Ucs cChar ) const
434 return( maGsubTable.find( cChar ) != maGsubTable.end() );
436 #endif // GNG_VERT_HACK
438 // -----------------------------------------------------------------------
440 ImplFontCharMap* ImplOs2FontData::GetImplFontCharMap() const
442 mpUnicodeMap->AddReference();
443 return mpUnicodeMap;
446 // -----------------------------------------------------------------------
448 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
449 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
450 static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
451 static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
453 void ImplOs2FontData::ReadOs2Table( HPS hPS ) const
455 const DWORD Os2Tag = CalcTag( "OS/2" );
456 DWORD nLength = Ft2GetFontData( hPS, Os2Tag, 0, NULL, 0 );
457 if( (nLength == FT2_ERROR) || !nLength )
458 return;
459 std::vector<unsigned char> aOS2map( nLength );
460 unsigned char* pOS2map = &aOS2map[0];
461 DWORD nRC = Ft2GetFontData( hPS, Os2Tag, 0, pOS2map, nLength );
462 sal_uInt32 nVersion = GetUShort( pOS2map );
463 if ( nVersion >= 0x0001 && nLength >= 58 )
465 // We need at least version 0x0001 (TrueType rev 1.66)
466 // to have access to the needed struct members.
467 sal_uInt32 ulUnicodeRange1 = GetUInt( pOS2map + 42 );
468 sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
469 sal_uInt32 ulUnicodeRange3 = GetUInt( pOS2map + 50 );
470 sal_uInt32 ulUnicodeRange4 = GetUInt( pOS2map + 54 );
472 // Check for CJK capabilities of the current font
473 mbHasCJKSupport = (ulUnicodeRange2 & 0x2fff0000)
474 | (ulUnicodeRange3 & 0x00000001);
475 mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000)
476 | (ulUnicodeRange2 & 0x01100000);
481 // -----------------------------------------------------------------------
483 #ifdef GNG_VERT_HACK
484 void ImplOs2FontData::ReadGsubTable( HPS hPS ) const
486 mbGsubRead = true;
488 // check the existence of a GSUB table
489 const DWORD GsubTag = CalcTag( "GSUB" );
490 DWORD nRC = Ft2GetFontData( hPS, GsubTag, 0, NULL, 0 );
491 if( (nRC == FT2_ERROR) || !nRC )
492 return;
494 // TODO: directly read the GSUB table instead of going through sft
496 // get raw font file data
497 DWORD nFontSize = Ft2GetFontData( hPS, 0, 0, NULL, 0 );
498 if( nFontSize == FT2_ERROR )
499 return;
500 std::vector<char> aRawFont( nFontSize+1 );
501 aRawFont[ nFontSize ] = 0;
502 DWORD nFontSize2 = Ft2GetFontData( hPS, 0, 0, (void*)&aRawFont[0], nFontSize );
503 if( nFontSize != nFontSize2 )
504 return;
506 // open font file
507 sal_uInt32 nFaceNum = 0;
508 if( !aRawFont[0] ) // TTC candidate
509 nFaceNum = ~0U; // indicate "TTC font extracts only"
511 TrueTypeFont* pTTFont = NULL;
512 ::OpenTTFontBuffer( &aRawFont[0], nFontSize, nFaceNum, &pTTFont );
513 if( !pTTFont )
514 return;
516 // add vertically substituted characters to list
517 static const sal_Unicode aGSUBCandidates[] = {
518 0x0020, 0x0080, // ASCII
519 0x2000, 0x2600, // misc
520 0x3000, 0x3100, // CJK punctutation
521 0x3300, 0x3400, // squared words
522 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
523 0 };
525 for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
526 for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
527 if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
528 maGsubTable.insert( cChar ); // insert GSUBbed unicodes
530 CloseTTFont( pTTFont );
532 #if 0
533 TrueTypeFont* pTTFont = NULL;
534 ::OpenTTFont( &aRawFont[0], nFontSize, nFaceNum, &pTTFont );
535 if( !pTTFont )
536 return;
538 // add vertically substituted characters to list
539 static const sal_Unicode aGSUBCandidates[] = {
540 0x0020, 0x0080, // ASCII
541 0x2000, 0x2600, // misc
542 0x3000, 0x3100, // CJK punctutation
543 0x3300, 0x3400, // squared words
544 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
545 0 };
547 for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
548 for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
549 if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
550 maGsubTable.insert( cChar ); // insert GSUBbed unicodes
552 CloseTTFont( pTTFont );
553 #endif
555 #endif // GNG_VERT_HACK
557 // -----------------------------------------------------------------------
559 void ImplOs2FontData::ReadCmapTable( HPS hPS ) const
561 CmapResult aResult;
562 aResult.mnPairCount = 0;
563 aResult.mbSymbolic = (meOs2CharSet == SYMBOL_CHARSET);
564 aResult.mbRecoded = true;
566 // get the CMAP table from the font which is selected into the DC
567 const DWORD CmapTag = CalcTag( "cmap" );
568 DWORD nRC = Ft2GetFontData( hPS, CmapTag, 0, NULL, 0 );
569 // read the CMAP table if available
570 if( nRC != FT2_ERROR )
572 const int nLength = nRC;
573 std::vector<unsigned char> aCmap( nLength );
574 unsigned char* pCmap = &aCmap[0];
575 nRC = Ft2GetFontData( hPS, CmapTag, 0, pCmap, nLength );
576 // parse the CMAP table
577 if( nRC == nLength )
578 ParseCMAP( pCmap, nLength, aResult );
579 } else {
580 // we need to define at least a simple charmap, otherwise this font
581 // will be mapped to default charmap, and OOo doesn't accept the
582 // system font to match the default charmap
583 aResult.mnPairCount = 1;
584 // ImplFontCharMap destructor will free this memory
585 aResult.mpPairCodes = new sal_uInt32[ 2 * aResult.mnPairCount ];
586 aResult.mpPairCodes[0] = 0x0020;
587 aResult.mpPairCodes[1] = 0x00FF;
588 aResult.mpStartGlyphs = NULL;
591 mbDisableGlyphApi |= aResult.mbRecoded;
593 if( aResult.mnPairCount > 0 )
594 mpUnicodeMap = new ImplFontCharMap( aResult.mnPairCount,
595 aResult.mpPairCodes, aResult.mpStartGlyphs );
596 else
597 mpUnicodeMap = ImplFontCharMap::GetDefaultMap();
600 // =======================================================================
602 void Os2SalGraphics::SetTextColor( SalColor nSalColor )
604 CHARBUNDLE cb;
606 cb.lColor = RGBCOLOR( SALCOLOR_RED( nSalColor ),
607 SALCOLOR_GREEN( nSalColor ),
608 SALCOLOR_BLUE( nSalColor ) );
610 // set default color attributes
611 Ft2SetAttrs( mhPS,
612 PRIM_CHAR,
613 CBB_COLOR,
615 &cb );
618 // -----------------------------------------------------------------------
620 USHORT Os2SalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, int nFallbackLevel)
623 #if OSL_DEBUG_LEVEL>10
624 debug_printf( "Os2SalGraphics::ImplDoSetFont\n");
625 #endif
627 ImplOs2FontData* pFontData = (ImplOs2FontData*)i_pFont->mpFontData;
628 PFONTMETRICS pFontMetric = NULL;
629 FATTRS aFAttrs;
630 BOOL bOutline = FALSE;
631 APIRET rc;
633 memset( &aFAttrs, 0, sizeof( FATTRS ) );
634 aFAttrs.usRecordLength = sizeof( FATTRS );
636 aFAttrs.lMaxBaselineExt = i_pFont->mnHeight;
637 aFAttrs.lAveCharWidth = i_pFont->mnWidth;
639 // do we have a pointer to the FONTMETRICS of the selected font? -> use it!
640 if ( pFontData )
642 pFontMetric = pFontData->GetFontMetrics();
644 bOutline = (pFontMetric->fsDefn & FM_DEFN_OUTLINE) != 0;
646 // use match&registry fields to get correct match
647 aFAttrs.lMatch = pFontMetric->lMatch;
648 aFAttrs.idRegistry = pFontMetric->idRegistry;
649 aFAttrs.usCodePage = pFontMetric->usCodePage;
651 if ( bOutline )
653 aFAttrs.fsFontUse |= FATTR_FONTUSE_OUTLINE;
654 if ( i_pFont->mnOrientation )
655 aFAttrs.fsFontUse |= FATTR_FONTUSE_TRANSFORMABLE;
657 else
659 aFAttrs.lMaxBaselineExt = pFontMetric->lMaxBaselineExt;
660 aFAttrs.lAveCharWidth = pFontMetric->lAveCharWidth;
665 // use family name for outline fonts
666 if ( mbPrinter ) {
667 // use font face name for printers because otherwise ft2lib will fail
668 // to select the correct font for GPI (ticket#117)
669 strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFacename, sizeof( aFAttrs.szFacename ) );
670 } else if ( !pFontMetric) {
671 // use OOo name if fontmetrics not available!
672 ByteString aName( i_pFont->maName.GetToken( 0 ), gsl_getSystemTextEncoding());
673 strncpy( (char*)(aFAttrs.szFacename), aName.GetBuffer(), sizeof( aFAttrs.szFacename ) );
674 } else if ( bOutline) {
675 // use fontmetric family name for outline fonts
676 strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFamilyname, sizeof( aFAttrs.szFacename ) );
677 } else {
678 // use real font face name for bitmaps (WarpSans only)
679 strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFacename, sizeof( aFAttrs.szFacename ) );
682 if ( i_pFont->meItalic != ITALIC_NONE )
683 aFAttrs.fsSelection |= FATTR_SEL_ITALIC;
684 if ( i_pFont->meWeight > WEIGHT_MEDIUM )
685 aFAttrs.fsSelection |= FATTR_SEL_BOLD;
687 #if OSL_DEBUG_LEVEL>1
688 if (pFontMetric->szFacename[0] == 'A') {
689 debug_printf( "Os2SalGraphics::SetFont hps %x lMatch '%d'\n", mhPS, pFontMetric->lMatch);
690 debug_printf( "Os2SalGraphics::SetFont hps %x fontmetrics facename '%s'\n", mhPS, pFontMetric->szFacename);
691 debug_printf( "Os2SalGraphics::SetFont hps %x fattrs facename '%s'\n", mhPS, aFAttrs.szFacename);
693 #endif
695 Ft2DeleteSetId( mhPS, nFallbackLevel + LCID_BASE);
696 if ( (rc=Ft2CreateLogFont( mhPS, NULL, nFallbackLevel + LCID_BASE, &aFAttrs)) == GPI_ERROR ) {
697 #if OSL_DEBUG_LEVEL>1
698 ERRORID nLastError = WinGetLastError( GetSalData()->mhAB );
699 debug_printf( "Os2SalGraphics::SetFont hps %x Ft2CreateLogFont failed err %x\n", mhPS, nLastError );
700 #endif
701 return SAL_SETFONT_REMOVEANDMATCHNEW;
704 CHARBUNDLE aBundle;
706 ULONG nAttrsDefault = 0;
707 ULONG nAttrs = CBB_SET;
708 aBundle.usSet = nFallbackLevel + LCID_BASE;
710 if ( bOutline )
712 nAttrs |= CBB_BOX;
713 aBundle.sizfxCell.cy = MAKEFIXED( i_pFont->mnHeight, 0 );
715 if ( !i_pFont->mnWidth )
717 LONG nXFontRes;
718 LONG nYFontRes;
719 LONG nHeight;
721 // Auf die Aufloesung achten, damit das Ergebnis auch auf
722 // Drucken mit 180*360 DPI stimmt. Ausserdem muss gerundet
723 // werden, da auf meinem OS2 beispielsweise als
724 // Bildschirmaufloesung 3618*3622 PixelPerMeter zurueck-
725 // gegeben wird
726 GetResolution( nXFontRes, nYFontRes );
727 nHeight = i_pFont->mnHeight;
728 nHeight *= nXFontRes;
729 nHeight += nYFontRes/2;
730 nHeight /= nYFontRes;
731 aBundle.sizfxCell.cx = MAKEFIXED( nHeight, 0 );
733 else
734 aBundle.sizfxCell.cx = MAKEFIXED( i_pFont->mnWidth, 0 );
737 // set orientation for outlinefonts
738 if ( i_pFont->mnOrientation )
740 if ( bOutline )
742 nAttrs |= CBB_ANGLE;
743 double alpha = (double)(i_pFont->mnOrientation);
744 alpha *= 0.0017453292; // *PI / 1800
745 mnOrientationY = (long) (1000.0 * sin( alpha ));
746 mnOrientationX = (long) (1000.0 * cos( alpha ));
747 aBundle.ptlAngle.x = mnOrientationX;
748 aBundle.ptlAngle.y = mnOrientationY;
750 else
752 mnOrientationX = 1;
753 mnOrientationY = 0;
754 nAttrs |= CBB_ANGLE;
755 aBundle.ptlAngle.x = 1;
756 aBundle.ptlAngle.y = 0;
759 else
761 mnOrientationX = 1;
762 mnOrientationY = 0;
763 nAttrs |= CBB_ANGLE;
764 aBundle.ptlAngle.x = 1;
765 aBundle.ptlAngle.y = 0;
768 rc = Ft2SetAttrs( mhPS, PRIM_CHAR, nAttrs, nAttrsDefault, &aBundle );
770 #if OSL_DEBUG_LEVEL>1
771 FONTMETRICS aOS2Metric = {0};
772 Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
773 #endif
775 return 0;
779 USHORT Os2SalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel )
782 // return early if there is no new font
783 if( !pFont )
785 #if 0
786 // deselect still active font
787 if( mhDefFont )
788 Ft2SetCharSet( mhPS, mhDefFont );
789 // release no longer referenced font handles
790 for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
792 if( mhFonts[i] )
793 Ft2DeleteSetId( mhPS, mhFonts[i] );
794 mhFonts[ i ] = 0;
796 #endif
797 mhDefFont = 0;
798 return 0;
801 #if OSL_DEBUG_LEVEL>10
802 debug_printf( "Os2SalGraphics::SetFont\n");
803 #endif
805 DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL");
806 mpOs2FontEntry[ nFallbackLevel ] = reinterpret_cast<ImplOs2FontEntry*>( pFont->mpFontEntry );
807 mpOs2FontData[ nFallbackLevel ] = static_cast<const ImplOs2FontData*>( pFont->mpFontData );
809 ImplDoSetFont( pFont, mfFontScale, nFallbackLevel);
811 if( !mhDefFont )
813 // keep default font
814 mhDefFont = nFallbackLevel + LCID_BASE;
816 else
818 // release no longer referenced font handles
819 for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
821 if( mhFonts[i] )
823 #if 0
824 Ft2DeleteSetId( mhPS, mhFonts[i] );
825 #endif
826 mhFonts[i] = 0;
831 // store new font in correct layer
832 mhFonts[ nFallbackLevel ] = nFallbackLevel + LCID_BASE;
834 // now the font is live => update font face
835 if( mpOs2FontData[ nFallbackLevel ] )
836 mpOs2FontData[ nFallbackLevel ]->UpdateFromHPS( mhPS );
838 if( !nFallbackLevel )
840 mbFontKernInit = TRUE;
841 if ( mpFontKernPairs )
843 delete[] mpFontKernPairs;
844 mpFontKernPairs = NULL;
846 mnFontKernPairCount = 0;
849 // some printers have higher internal resolution, so their
850 // text output would be different from what we calculated
851 // => suggest DrawTextArray to workaround this problem
852 if ( mbPrinter )
853 return SAL_SETFONT_USEDRAWTEXTARRAY;
854 else
855 return 0;
858 // -----------------------------------------------------------------------
860 void Os2SalGraphics::GetFontMetric( ImplFontMetricData* pMetric )
862 FONTMETRICS aOS2Metric;
863 Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
865 #if OSL_DEBUG_LEVEL>1
866 debug_printf( "Os2SalGraphics::GetFontMetric hps %x\n", mhPS);
867 if (aOS2Metric.szFacename[0] == 'A') {
868 debug_printf( "Os2SalGraphics::GetFontMetric hps %x fontmetrics facename '%s'\n", mhPS, aOS2Metric.szFacename);
869 debug_printf( "Os2SalGraphics::GetFontMetric hps %x fontmetrics lMatch '%d'\n", mhPS, aOS2Metric.lMatch);
871 #endif
873 pMetric->maName = UniString( aOS2Metric.szFamilyname, gsl_getSystemTextEncoding());
874 pMetric->maStyleName = ImpStyleNameToSal( aOS2Metric.szFamilyname,
875 aOS2Metric.szFacename,
876 strlen( aOS2Metric.szFamilyname ) );
878 // device independent font attributes
879 pMetric->meFamily = ImplFamilyToSal( aOS2Metric.panose.bFamilyType);
880 pMetric->mbSymbolFlag = (aOS2Metric.usCodePage == SYMBOL_CHARSET);
881 pMetric->meWeight = ImplWeightToSal( aOS2Metric.usWeightClass );
882 pMetric->mePitch = ImplLogPitchToSal( aOS2Metric.fsType );
883 pMetric->meItalic = (aOS2Metric.fsSelection & FM_SEL_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE;
884 pMetric->mnSlant = 0;
886 // device dependend font attributes
887 pMetric->mbDevice = (aOS2Metric.fsDefn & FM_DEFN_GENERIC) ? FALSE : TRUE;
888 pMetric->mbScalableFont = (aOS2Metric.fsDefn & FM_DEFN_OUTLINE) ? true : false;
889 if( pMetric->mbScalableFont )
891 // check if there are kern pairs
892 // TODO: does this work with GPOS kerning?
893 pMetric->mbKernableFont = (aOS2Metric.sKerningPairs > 0);
895 else
897 // bitmap fonts cannot be rotated directly
898 pMetric->mnOrientation = 0;
899 // bitmap fonts have no kerning
900 pMetric->mbKernableFont = false;
903 // transformation dependend font metrics
904 if ( aOS2Metric.fsDefn & FM_DEFN_OUTLINE )
906 pMetric->mnWidth = aOS2Metric.lEmInc;
908 else
910 pMetric->mnWidth = aOS2Metric.lAveCharWidth;
911 pMetric->mnOrientation = 0;
913 pMetric->mnIntLeading = aOS2Metric.lInternalLeading;
914 pMetric->mnExtLeading = aOS2Metric.lExternalLeading;
915 pMetric->mnAscent = aOS2Metric.lMaxAscender;
916 pMetric->mnDescent = aOS2Metric.lMaxDescender;
918 // #107888# improved metric compatibility for Asian fonts...
919 // TODO: assess workaround below for CWS >= extleading
920 // TODO: evaluate use of aWinMetric.sTypo* members for CJK
921 if( mpOs2FontData[0] && mpOs2FontData[0]->SupportsCJK() )
923 pMetric->mnIntLeading += pMetric->mnExtLeading;
925 // #109280# The line height for Asian fonts is too small.
926 // Therefore we add half of the external leading to the
927 // ascent, the other half is added to the descent.
928 const long nHalfTmpExtLeading = pMetric->mnExtLeading / 2;
929 const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading;
931 // #110641# external leading for Asian fonts.
932 // The factor 0.3 has been confirmed with experiments.
933 long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent));
934 nCJKExtLeading -= pMetric->mnExtLeading;
935 pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0;
937 pMetric->mnAscent += nHalfTmpExtLeading;
938 pMetric->mnDescent += nOtherHalfTmpExtLeading;
940 // #109280# HACK korean only: increase descent for wavelines and impr
941 // YD win9x only
946 // -----------------------------------------------------------------------
948 ULONG Os2SalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs )
950 DBG_ASSERT( sizeof( KERNINGPAIRS ) == sizeof( ImplKernPairData ),
951 "Os2SalGraphics::GetKernPairs(): KERNINGPAIRS != ImplKernPairData" );
953 if ( mbFontKernInit )
955 if( mpFontKernPairs )
957 delete[] mpFontKernPairs;
958 mpFontKernPairs = NULL;
960 mnFontKernPairCount = 0;
963 KERNINGPAIRS* pPairs = NULL;
964 FONTMETRICS aOS2Metric;
965 Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
966 int nCount = aOS2Metric.sKerningPairs;
967 if( nCount )
969 #ifdef GCP_KERN_HACK
970 pPairs = new KERNINGPAIRS[ nCount+1 ];
971 mpFontKernPairs = pPairs;
972 mnFontKernPairCount = nCount;
973 Ft2QueryKerningPairs( mhPS, nCount, (KERNINGPAIRS*)pPairs );
974 #else // GCP_KERN_HACK
975 pPairs = (KERNINGPAIRS*)pKernPairs;
976 nCount = (nCount < nPairs) ? nCount : nPairs;
977 Ft2QueryKerningPairs( mhPS, nCount, (KERNINGPAIRS*)pPairs );
978 return nCount;
979 #endif // GCP_KERN_HACK
983 mbFontKernInit = FALSE;
985 std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
988 if( !pKernPairs )
989 return mnFontKernPairCount;
990 else if( mpFontKernPairs )
992 if ( nPairs < mnFontKernPairCount )
993 nPairs = mnFontKernPairCount;
994 memcpy( pKernPairs, mpFontKernPairs,
995 nPairs*sizeof( ImplKernPairData ) );
996 return nPairs;
999 return 0;
1003 // -----------------------------------------------------------------------
1005 static ImplFontCharMap* pOs2DefaultImplFontCharMap = NULL;
1006 static const sal_uInt32 pOs2DefaultRangeCodes[] = {0x0020,0x00FF};
1008 ImplFontCharMap* Os2SalGraphics::GetImplFontCharMap() const
1010 if( !mpOs2FontData[0] )
1011 return ImplFontCharMap::GetDefaultMap();
1012 return mpOs2FontData[0]->GetImplFontCharMap();
1015 // -----------------------------------------------------------------------
1017 bool Os2SalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
1018 const String& rFontFileURL, const String& rFontName )
1020 #if OSL_DEBUG_LEVEL>0
1021 debug_printf("Os2SalGraphics::AddTempDevFont\n");
1022 #endif
1023 return false;
1026 // -----------------------------------------------------------------------
1028 void Os2SalGraphics::GetDevFontList( ImplDevFontList* pList )
1030 PFONTMETRICS pFontMetrics;
1031 ULONG nFontMetricCount;
1032 SalData* pSalData;
1034 #if OSL_DEBUG_LEVEL>0
1035 debug_printf("Os2SalGraphics::GetDevFontList\n");
1036 #endif
1038 // install OpenSymbol
1039 HMODULE hMod;
1040 ULONG ObjNum, Offset, rc;
1041 CHAR Buff[2*_MAX_PATH];
1042 char drive[_MAX_DRIVE], dir[_MAX_DIR];
1043 char fname[_MAX_FNAME], ext[_MAX_EXT];
1044 // get module handle (and name)
1045 rc = DosQueryModFromEIP( &hMod, &ObjNum, sizeof( Buff), Buff,
1046 &Offset, (ULONG)ImplSalGetUniString);
1047 DosQueryModuleName(hMod, sizeof(Buff), Buff);
1048 // replace module path with font path
1049 char* slash = strrchr( Buff, '\\');
1050 *slash = '\0';
1051 slash = strrchr( Buff, '\\');
1052 *slash = '\0';
1053 strcat( Buff, "\\SHARE\\FONTS\\TRUETYPE\\OPENS___.TTF");
1054 rc = GpiLoadPublicFonts( GetSalData()->mhAB, Buff);
1056 if ( !mbPrinter )
1058 // Bei Bildschirm-Devices cachen wir die Liste global, da
1059 // dies im unabhaengigen Teil auch so gemacht wird und wir
1060 // ansonsten auf geloeschten Systemdaten arbeiten koennten
1061 pSalData = GetSalData();
1062 nFontMetricCount = pSalData->mnFontMetricCount;
1063 pFontMetrics = pSalData->mpFontMetrics;
1064 // Bei Bildschirm-Devices holen wir uns die Fontliste jedesmal neu
1065 if ( pFontMetrics )
1067 delete pFontMetrics;
1068 pFontMetrics = NULL;
1069 nFontMetricCount = 0;
1072 else
1074 nFontMetricCount = mnFontMetricCount;
1075 pFontMetrics = mpFontMetrics;
1078 // do we have to create the cached font list first?
1079 if ( !pFontMetrics )
1081 // query the number of fonts available
1082 LONG nTemp = 0;
1083 nFontMetricCount = Ft2QueryFonts( mhPS,
1084 QF_PUBLIC | QF_PRIVATE,
1085 NULL, &nTemp,
1086 sizeof( FONTMETRICS ), NULL );
1088 // procede only if at least one is available!
1089 if ( nFontMetricCount )
1091 // allocate memory for font list
1092 pFontMetrics = new FONTMETRICS[nFontMetricCount];
1094 // query font list
1095 Ft2QueryFonts( mhPS,
1096 QF_PUBLIC | QF_PRIVATE,
1097 NULL,
1098 (PLONG)&nFontMetricCount,
1099 (LONG) sizeof( FONTMETRICS ),
1100 pFontMetrics );
1103 if ( !mbPrinter )
1105 pSalData->mnFontMetricCount = nFontMetricCount;
1106 pSalData->mpFontMetrics = pFontMetrics;
1108 else
1110 mnFontMetricCount = nFontMetricCount;
1111 mpFontMetrics = pFontMetrics;
1115 // copy data from the font list
1116 for( ULONG i = 0; i < nFontMetricCount; i++ )
1118 PFONTMETRICS pFontMetric = &pFontMetrics[i];
1120 // skip font starting with '@', this is an alias internally
1121 // used by truetype engine.
1122 if (pFontMetric->szFacename[0] == '@')
1123 continue;
1125 // skip bitmap fonts (but keep WarpSans)
1126 if ( (pFontMetric->fsDefn & FM_DEFN_OUTLINE) == 0
1127 && strncmp( pFontMetric->szFacename, "WarpSans", 8) )
1128 // Font nicht aufnehmen
1129 continue;
1131 // replace '-' in facename with ' ' (for ft2lib)
1132 char* dash = pFontMetric->szFacename;
1133 while( (dash=strchr( dash, '-')))
1134 *dash++ = ' ';
1136 // create new font list element
1137 ImplOs2FontData* pData = new ImplOs2FontData( pFontMetric, 0, 0 );
1139 // add font list element to font list
1140 pList->Add( pData );
1145 // ----------------------------------------------------------------------------
1147 void Os2SalGraphics::GetDevFontSubstList( OutputDevice* pOutDev )
1151 // -----------------------------------------------------------------------
1153 BOOL Os2SalGraphics::GetGlyphBoundRect( long nIndex, Rectangle& rRect )
1155 // use unity matrix
1156 MAT2 aMat;
1157 aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
1158 aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
1160 UINT nGGOFlags = GGO_METRICS;
1161 if( !(nIndex & GF_ISCHAR) )
1162 nGGOFlags |= GGO_GLYPH_INDEX;
1163 nIndex &= GF_IDXMASK;
1165 GLYPHMETRICS aGM;
1166 DWORD nSize = FT2_ERROR;
1167 nSize = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat );
1168 if( nSize == FT2_ERROR )
1169 return false;
1171 rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
1172 Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
1173 rRect.Left() = static_cast<int>( mfFontScale * rRect.Left() );
1174 rRect.Right() = static_cast<int>( mfFontScale * rRect.Right() );
1175 rRect.Top() = static_cast<int>( mfFontScale * rRect.Top() );
1176 rRect.Bottom() = static_cast<int>( mfFontScale * rRect.Bottom() );
1177 return true;
1180 // -----------------------------------------------------------------------
1182 BOOL Os2SalGraphics::GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
1184 #if OSL_DEBUG_LEVEL>0
1185 debug_printf("Os2SalGraphics::GetGlyphOutline\n");
1186 #endif
1187 rB2DPolyPoly.clear();
1189 BOOL bRet = FALSE;
1191 // use unity matrix
1192 MAT2 aMat;
1193 aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
1194 aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
1196 UINT nGGOFlags = GGO_NATIVE;
1197 if( !(nIndex & GF_ISCHAR) )
1198 nGGOFlags |= GGO_GLYPH_INDEX;
1199 nIndex &= GF_IDXMASK;
1201 GLYPHMETRICS aGlyphMetrics;
1202 DWORD nSize1 = FT2_ERROR;
1203 nSize1 = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
1205 if( !nSize1 ) // blank glyphs are ok
1206 bRet = TRUE;
1207 else if( nSize1 != FT2_ERROR )
1209 BYTE* pData = new BYTE[ nSize1 ];
1210 ULONG nTotalCount = 0;
1211 DWORD nSize2;
1212 nSize2 = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags,
1213 &aGlyphMetrics, nSize1, pData, &aMat );
1215 if( nSize1 == nSize2 )
1217 bRet = TRUE;
1219 int nPtSize = 512;
1220 Point* pPoints = new Point[ nPtSize ];
1221 BYTE* pFlags = new BYTE[ nPtSize ];
1223 TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData;
1224 while( (BYTE*)pHeader < pData+nSize2 )
1226 // only outline data is interesting
1227 if( pHeader->dwType != TT_POLYGON_TYPE )
1228 break;
1230 // get start point; next start points are end points
1231 // of previous segment
1232 int nPnt = 0;
1234 long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
1235 long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
1236 pPoints[ nPnt ] = Point( nX, nY );
1237 pFlags[ nPnt++ ] = POLY_NORMAL;
1239 bool bHasOfflinePoints = false;
1240 TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 );
1241 pHeader = (TTPOLYGONHEADER*)( (BYTE*)pHeader + pHeader->cb );
1242 while( (BYTE*)pCurve < (BYTE*)pHeader )
1244 int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
1245 if( nPtSize < nNeededSize )
1247 Point* pOldPoints = pPoints;
1248 BYTE* pOldFlags = pFlags;
1249 nPtSize = 2 * nNeededSize;
1250 pPoints = new Point[ nPtSize ];
1251 pFlags = new BYTE[ nPtSize ];
1252 for( int i = 0; i < nPnt; ++i )
1254 pPoints[ i ] = pOldPoints[ i ];
1255 pFlags[ i ] = pOldFlags[ i ];
1257 delete[] pOldPoints;
1258 delete[] pOldFlags;
1261 int i = 0;
1262 if( TT_PRIM_LINE == pCurve->wType )
1264 while( i < pCurve->cpfx )
1266 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1267 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1268 ++i;
1269 pPoints[ nPnt ] = Point( nX, nY );
1270 pFlags[ nPnt ] = POLY_NORMAL;
1271 ++nPnt;
1274 else if( TT_PRIM_QSPLINE == pCurve->wType )
1276 bHasOfflinePoints = true;
1277 while( i < pCurve->cpfx )
1279 // get control point of quadratic bezier spline
1280 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1281 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1282 ++i;
1283 Point aControlP( nX, nY );
1285 // calculate first cubic control point
1286 // P0 = 1/3 * (PBeg + 2 * PQControl)
1287 nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
1288 nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
1289 pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
1290 pFlags[ nPnt+0 ] = POLY_CONTROL;
1292 // calculate endpoint of segment
1293 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1294 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1296 if ( i+1 >= pCurve->cpfx )
1298 // endpoint is either last point in segment => advance
1299 ++i;
1301 else
1303 // or endpoint is the middle of two control points
1304 nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
1305 nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
1306 nX = (nX + 1) / 2;
1307 nY = (nY + 1) / 2;
1308 // no need to advance, because the current point
1309 // is the control point in next bezier spline
1312 pPoints[ nPnt+2 ] = Point( nX, nY );
1313 pFlags[ nPnt+2 ] = POLY_NORMAL;
1315 // calculate second cubic control point
1316 // P1 = 1/3 * (PEnd + 2 * PQControl)
1317 nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
1318 nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
1319 pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
1320 pFlags[ nPnt+1 ] = POLY_CONTROL;
1322 nPnt += 3;
1326 // next curve segment
1327 pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ];
1330 // end point is start point for closed contour
1331 // disabled, because Polygon class closes the contour itself
1332 // pPoints[nPnt++] = pPoints[0];
1333 // #i35928#
1334 // Added again, but add only when not yet closed
1335 if(pPoints[nPnt - 1] != pPoints[0])
1337 if( bHasOfflinePoints )
1338 pFlags[nPnt] = pFlags[0];
1340 pPoints[nPnt++] = pPoints[0];
1343 // convert y-coordinates W32 -> VCL
1344 for( int i = 0; i < nPnt; ++i )
1345 pPoints[i].Y() = -pPoints[i].Y();
1347 // insert into polypolygon
1348 Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) );
1349 // convert to B2DPolyPolygon
1350 // TODO: get rid of the intermediate PolyPolygon
1351 rB2DPolyPoly.append( aPoly.getB2DPolygon() );
1354 delete[] pPoints;
1355 delete[] pFlags;
1358 delete[] pData;
1361 // rescaling needed for the PolyPolygon conversion
1362 if( rB2DPolyPoly.count() )
1364 ::basegfx::B2DHomMatrix aMatrix;
1365 aMatrix.scale( 1.0/256, 1.0/256 );
1366 aMatrix.scale( mfFontScale, mfFontScale );
1367 rB2DPolyPoly.transform( aMatrix );
1370 return bRet;
1373 // -----------------------------------------------------------------------
1375 // TODO: Replace this class with boost::scoped_array
1376 class ScopedCharArray
1378 public:
1379 inline explicit ScopedCharArray(char * pArray): m_pArray(pArray) {}
1381 inline ~ScopedCharArray() { delete[] m_pArray; }
1383 inline char * get() const { return m_pArray; }
1385 private:
1386 char * m_pArray;
1389 class ScopedFont
1391 public:
1392 explicit ScopedFont(Os2SalGraphics & rData);
1394 ~ScopedFont();
1396 private:
1397 Os2SalGraphics & m_rData;
1398 ULONG m_hOrigFont;
1401 ScopedFont::ScopedFont(Os2SalGraphics & rData): m_rData(rData)
1403 #if 0
1404 m_hOrigFont = m_rData.mhFonts[0];
1405 m_rData.mhFonts[0] = 0; // avoid deletion of current font
1406 #endif
1409 ScopedFont::~ScopedFont()
1411 #if 0
1412 if( m_hOrigFont )
1414 // restore original font, destroy temporary font
1415 HFONT hTempFont = m_rData.mhFonts[0];
1416 m_rData.mhFonts[0] = m_hOrigFont;
1417 SelectObject( m_rData.mhDC, m_hOrigFont );
1418 DeleteObject( hTempFont );
1420 #endif
1423 class ScopedTrueTypeFont
1425 public:
1426 inline ScopedTrueTypeFont(): m_pFont(0) {}
1428 ~ScopedTrueTypeFont();
1430 int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
1432 inline TrueTypeFont * get() const { return m_pFont; }
1434 private:
1435 TrueTypeFont * m_pFont;
1438 ScopedTrueTypeFont::~ScopedTrueTypeFont()
1440 if (m_pFont != 0)
1441 CloseTTFont(m_pFont);
1444 int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen,
1445 sal_uInt32 nFaceNum)
1447 OSL_ENSURE(m_pFont == 0, "already open");
1448 return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont);
1451 BOOL Os2SalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
1452 const ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding,
1453 sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
1455 // create matching ImplFontSelectData
1456 // we need just enough to get to the font file data
1457 // use height=1000 for easier debugging (to match psprint's font units)
1458 ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1460 // TODO: much better solution: move SetFont and restoration of old font to caller
1461 ScopedFont aOldFont(*this);
1462 SetFont( &aIFSD, 0 );
1464 #if OSL_DEBUG_LEVEL > 100
1465 // get font metrics
1466 TEXTMETRICA aWinMetric;
1467 if( !::GetTextMetricsA( mhDC, &aWinMetric ) )
1468 return FALSE;
1470 DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" );
1471 DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
1472 #endif
1474 // get raw font file data
1475 DWORD nFontSize1 = Ft2GetFontData( mhPS, 0, 0, NULL, 0 );
1476 if( nFontSize1 == FT2_ERROR )
1477 return FALSE;
1478 ScopedCharArray xRawFontData(new char[ nFontSize1 ]);
1479 DWORD nFontSize2 = Ft2GetFontData( mhPS, 0, 0, (void*)xRawFontData.get(), nFontSize1 );
1480 if( nFontSize1 != nFontSize2 )
1481 return FALSE;
1483 // open font file
1484 sal_uInt32 nFaceNum = 0;
1485 if( !*xRawFontData.get() ) // TTC candidate
1486 nFaceNum = ~0U; // indicate "TTC font extracts only"
1488 ScopedTrueTypeFont aSftTTF;
1489 int nRC = aSftTTF.open( xRawFontData.get(), nFontSize1, nFaceNum );
1490 if( nRC != SF_OK )
1491 return FALSE;
1493 TTGlobalFontInfo aTTInfo;
1494 ::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
1495 rInfo.m_nFontType = SAL_FONTSUBSETINFO_TYPE_TRUETYPE;
1496 rInfo.m_aPSName = ImplSalGetUniString( aTTInfo.psname );
1497 rInfo.m_nAscent = +aTTInfo.winAscent;
1498 rInfo.m_nDescent = -aTTInfo.winDescent;
1499 rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
1500 Point( aTTInfo.xMax, aTTInfo.yMax ) );
1501 rInfo.m_nCapHeight = aTTInfo.yMax; // Well ...
1503 // subset glyphs and get their properties
1504 // take care that subset fonts require the NotDef glyph in pos 0
1505 int nOrigCount = nGlyphCount;
1506 USHORT aShortIDs[ 256 ];
1507 sal_uInt8 aTempEncs[ 256 ];
1509 int nNotDef=-1, i;
1510 for( i = 0; i < nGlyphCount; ++i )
1512 aTempEncs[i] = pEncoding[i];
1513 sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
1514 if( pGlyphIDs[i] & GF_ISCHAR )
1516 bool bVertical = (pGlyphIDs[i] & GF_ROTMASK) != 0;
1517 nGlyphIdx = ::MapChar( aSftTTF.get(), sal::static_int_cast<sal_uInt16>(nGlyphIdx), bVertical );
1518 if( nGlyphIdx == 0 && pFont->IsSymbolFont() )
1520 // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
1521 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
1522 nGlyphIdx = (nGlyphIdx & 0xF000) ? (nGlyphIdx & 0x00FF) : (nGlyphIdx | 0xF000 );
1523 nGlyphIdx = ::MapChar( aSftTTF.get(), sal::static_int_cast<sal_uInt16>(nGlyphIdx), bVertical );
1526 aShortIDs[i] = static_cast<USHORT>( nGlyphIdx );
1527 if( !nGlyphIdx )
1528 if( nNotDef < 0 )
1529 nNotDef = i; // first NotDef glyph found
1532 if( nNotDef != 0 )
1534 // add fake NotDef glyph if needed
1535 if( nNotDef < 0 )
1536 nNotDef = nGlyphCount++;
1538 // NotDef glyph must be in pos 0 => swap glyphids
1539 aShortIDs[ nNotDef ] = aShortIDs[0];
1540 aTempEncs[ nNotDef ] = aTempEncs[0];
1541 aShortIDs[0] = 0;
1542 aTempEncs[0] = 0;
1544 DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
1546 // fill pWidth array
1547 TTSimpleGlyphMetrics* pMetrics =
1548 ::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical );
1549 if( !pMetrics )
1550 return FALSE;
1551 sal_uInt16 nNotDefAdv = pMetrics[0].adv;
1552 pMetrics[0].adv = pMetrics[nNotDef].adv;
1553 pMetrics[nNotDef].adv = nNotDefAdv;
1554 for( i = 0; i < nOrigCount; ++i )
1555 pGlyphWidths[i] = pMetrics[i].adv;
1556 free( pMetrics );
1558 // write subset into destination file
1559 rtl::OUString aSysPath;
1560 if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
1561 return FALSE;
1562 rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
1563 ByteString aToFile( rtl::OUStringToOString( aSysPath, aThreadEncoding ) );
1564 nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs,
1565 aTempEncs, nGlyphCount, 0, NULL, 0 );
1566 return nRC == SF_OK;
1569 //--------------------------------------------------------------------------
1571 const void* Os2SalGraphics::GetEmbedFontData( const ImplFontData* pFont,
1572 const sal_Ucs* pUnicodes, sal_Int32* pCharWidths,
1573 FontSubsetInfo& rInfo, long* pDataLen )
1575 // create matching ImplFontSelectData
1576 // we need just enough to get to the font file data
1577 ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1579 // TODO: much better solution: move SetFont and restoration of old font to caller
1580 ScopedFont aOldFont(*this);
1581 SetFont( &aIFSD, 0 );
1583 // get the raw font file data
1584 DWORD nFontSize1 = Ft2GetFontData( mhPS, 0, 0, NULL, 0 );
1585 if( nFontSize1 == FT2_ERROR || nFontSize1 <= 0 )
1586 return NULL;
1587 *pDataLen = nFontSize1;
1588 void* pData = reinterpret_cast<void*>(new char[ nFontSize1 ]);
1589 DWORD nFontSize2 = Ft2GetFontData( mhPS, 0, 0, pData, nFontSize1 );
1590 if( nFontSize1 != nFontSize2 )
1591 *pDataLen = 0;
1593 // get important font properties
1594 FONTMETRICS aOS2Metric;
1595 if (Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric ) == GPI_ERROR)
1596 *pDataLen = 0;
1597 rInfo.m_nFontType = SAL_FONTSUBSETINFO_TYPE_TYPE1;
1598 rInfo.m_aPSName = ImplSalGetUniString( aOS2Metric.szFacename );
1599 rInfo.m_nAscent = +aOS2Metric.lMaxAscender;
1600 rInfo.m_nDescent = -aOS2Metric.lMaxDescender;
1601 rInfo.m_aFontBBox = Rectangle( Point( 0, -aOS2Metric.lMaxDescender ),
1602 Point( aOS2Metric.lMaxCharInc, aOS2Metric.lMaxAscender+aOS2Metric.lExternalLeading ) );
1603 rInfo.m_nCapHeight = aOS2Metric.lMaxAscender; // Well ...
1605 // get individual character widths
1606 for( int i = 0; i < 256; ++i )
1608 LONG nCharWidth = 0;
1609 const sal_Ucs cChar = pUnicodes[i];
1610 if( !Ft2QueryStringWidthW( mhPS, (LPWSTR)&cChar, 1, &nCharWidth ) )
1611 *pDataLen = 0;
1612 pCharWidths[i] = nCharWidth;
1615 if( !*pDataLen )
1617 FreeEmbedFontData( pData, nFontSize1 );
1618 pData = NULL;
1621 return pData;
1624 //--------------------------------------------------------------------------
1626 void Os2SalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
1628 delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
1631 const Ucs2SIntMap* Os2SalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
1633 // TODO: even for builtin fonts we get here... why?
1634 if( !pFont->IsEmbeddable() )
1635 return NULL;
1637 // fill the encoding vector
1638 Ucs2SIntMap& rMap = *new Ucs2SIntMap;
1639 #if 0
1640 // TODO: get correct encoding vector
1641 ImplWinFontData* pWinFontData = reinterpret_cast<ImplWinFontData*>(pFont);
1643 GLYPHSET aGlyphSet;
1644 aGlyphSet.cbThis = sizeof(aGlyphSet);
1645 DWORD aW = ::GetFontUnicodeRanges( mhDC, &aGlyphSet);
1646 #else
1647 for( sal_Unicode i = 32; i < 256; ++i )
1648 rMap[i] = i;
1649 if( pNonEncoded )
1650 *pNonEncoded = NULL;
1651 #endif
1653 return &rMap;
1656 //--------------------------------------------------------------------------
1658 void Os2SalGraphics::GetGlyphWidths( const ImplFontData* pFont,
1659 bool bVertical,
1660 Int32Vector& rWidths,
1661 Ucs2UIntMap& rUnicodeEnc )
1663 // create matching ImplFontSelectData
1664 // we need just enough to get to the font file data
1665 ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1667 // TODO: much better solution: move SetFont and restoration of old font to caller
1668 ScopedFont aOldFont(*this);
1670 float fScale = 0.0;
1671 ImplDoSetFont( &aIFSD, fScale, 0);
1673 if( pFont->IsSubsettable() )
1675 // get raw font file data
1676 DWORD nFontSize1 = ::Ft2GetFontData( mhPS, 0, 0, NULL, 0 );
1677 if( nFontSize1 == FT2_ERROR )
1678 return;
1679 ScopedCharArray xRawFontData(new char[ nFontSize1 ]);
1680 DWORD nFontSize2 = ::Ft2GetFontData( mhPS, 0, 0, (void*)xRawFontData.get(), nFontSize1 );
1681 if( nFontSize1 != nFontSize2 )
1682 return;
1684 // open font file
1685 sal_uInt32 nFaceNum = 0;
1686 if( !*xRawFontData.get() ) // TTC candidate
1687 nFaceNum = ~0U; // indicate "TTC font extracts only"
1689 ScopedTrueTypeFont aSftTTF;
1690 int nRC = aSftTTF.open( xRawFontData.get(), nFontSize1, nFaceNum );
1691 if( nRC != SF_OK )
1692 return;
1694 int nGlyphs = GetTTGlyphCount( aSftTTF.get() );
1695 if( nGlyphs > 0 )
1697 rWidths.resize(nGlyphs);
1698 std::vector<sal_uInt16> aGlyphIds(nGlyphs);
1699 for( int i = 0; i < nGlyphs; i++ )
1700 aGlyphIds[i] = sal_uInt16(i);
1701 TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(),
1702 &aGlyphIds[0],
1703 nGlyphs,
1704 bVertical ? 1 : 0 );
1705 if( pMetrics )
1707 for( int i = 0; i< nGlyphs; i++ )
1708 rWidths[i] = pMetrics[i].adv;
1709 free( pMetrics );
1710 rUnicodeEnc.clear();
1712 const ImplOs2FontData* pWinFont = static_cast<const ImplOs2FontData*>(pFont);
1713 ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap();
1714 DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" );
1716 int nCharCount = pMap->GetCharCount();
1717 sal_uInt32 nChar = pMap->GetFirstChar();
1718 for( int i = 0; i < nCharCount; i++ )
1720 if( nChar < 0x00010000 )
1722 sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(),
1723 static_cast<sal_uInt16>(nChar),
1724 bVertical ? 1 : 0 );
1725 if( nGlyph )
1726 rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph;
1728 nChar = pMap->GetNextChar( nChar );
1732 else if( pFont->IsEmbeddable() )
1734 // get individual character widths
1735 rWidths.clear();
1736 rUnicodeEnc.clear();
1737 rWidths.reserve( 224 );
1738 for( sal_Unicode i = 32; i < 256; ++i )
1740 int nCharWidth = 0;
1741 if( Ft2QueryStringWidthW( mhPS, (LPWSTR)&i, 1, (LONG*)&nCharWidth ) )
1743 rUnicodeEnc[ i ] = rWidths.size();
1744 rWidths.push_back( nCharWidth );
1750 //--------------------------------------------------------------------------
1752 void Os2SalGraphics::DrawServerFontLayout( const ServerFontLayout& )
1755 //--------------------------------------------------------------------------
1757 SystemFontData Os2SalGraphics::GetSysFontData( int nFallbacklevel ) const
1759 SystemFontData aSysFontData;
1761 if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
1762 if (nFallbacklevel < 0 ) nFallbacklevel = 0;
1764 aSysFontData.nSize = sizeof( SystemFontData );
1765 aSysFontData.hFont = mhFonts[nFallbacklevel];
1766 aSysFontData.bFakeBold = false;
1767 aSysFontData.bFakeItalic = false;
1768 aSysFontData.bAntialias = true;
1769 aSysFontData.bVerticalCharacterType = false;
1771 return aSysFontData;
1774 //--------------------------------------------------------------------------