Commits

Anonymous committed 63781ed

CWS-TOOLING: integrate CWS otf01
2009-08-26 15:25:19 +0200 hdu r275426 : #i10000# make ubuntu-8.10 buildbot happy
2009-08-21 11:58:07 +0200 hdu r275230 : #i43029# another compile fix for 64bit platforms
2009-08-21 09:00:26 +0200 hdu r275216 : #i43029# sal_Int32 is defined differently on some platforms
2009-08-19 13:41:07 +0200 hdu r275149 : #i43029# fix use of sft-based subsetting in centralized code
2009-08-19 10:42:23 +0200 hdu r275140 : #i43029# --amend previous commit with omitted files
2009-08-19 10:14:54 +0200 hdu r275137 : #i43029# finishing touches for CWS otf01
start to centralize the previously open-coded font-subset/font-embed requests
do the rest when the SCM allows source-file moves and commits with finer granularity
2009-08-17 15:11:24 +0200 hdu r275057 : CWS-TOOLING: rebase CWS otf01 to trunk@275001 (milestone: DEV300:m55)
2009-08-14 17:07:06 +0200 hdu r274998 : #i43029# CFF-subsetting now works on all platforms for PDF-export and PS-printing
2009-08-14 15:13:23 +0200 hdu r274984 : #i43029# OOo-build-baseline allows avoiding brute-forcing codepoint coverage calculation
2009-08-14 14:33:36 +0200 hdu r274981 : #i43029# CmapResult becomes a class
2009-08-13 15:57:55 +0200 hdu r274948 : #i43029# start implementing glue-code for CFF-subsetting on WIN
2009-08-10 17:10:46 +0200 hdu r274828 : #100000# WAE: signedness-warning
2009-08-10 14:08:05 +0200 hdu r274810 : #100000#
2009-08-10 13:34:55 +0200 hdu r274807 : #i43029# update ParseCmap() as we need to handle glyph-mapping ourselves on win for non-sft-supported fonts
2009-07-11 11:32:37 +0200 hdu r273909 : CWS-TOOLING: rebase CWS otf01 to trunk@273858 (milestone: DEV300:m52)
2009-07-03 17:14:55 +0200 hdu r273714 : #i43029# last step before centralizing UNX fontsubset code into platform independent layer
2009-07-03 17:00:14 +0200 hdu r273712 : #i10000# remove compile warning when debug=t
2009-07-03 16:28:29 +0200 hdu r273710 : #i43029# another step to centralize fontsubset code
2009-07-03 15:23:45 +0200 hdu r273705 : #i43029# PDF-export on UNX now starts to support OTF/CFF
2009-07-02 16:19:46 +0200 hdu r273663 : #i43029# warn when subsetting encounters glyph with deprecated SEAC-like endchar
2009-06-25 11:40:55 +0200 hdu r273372 : #i43029# ensure validity of cff-subsetted glyph name
2009-06-24 10:22:13 +0200 hdu r273318 : #i43029# check validity of exported sfnt subtable
2009-06-23 16:25:54 +0200 hdu r273292 : #i43029# use direct CFF->PFA font subsetting
2009-06-23 16:24:33 +0200 hdu r273289 : #i43029# allow font subset directly into a provided FILE handle
2009-06-23 16:22:44 +0200 hdu r273286 : #i43029# implement direct CFF->PFA font subsetting
2009-06-19 17:13:02 +0200 hdu r273171 : #i43029# CFF subsetting starts to work for psprinting
2009-06-18 15:48:42 +0200 hdu r273122 : #i43029# psprint requires explicit control of font subset name
2009-06-18 15:43:21 +0200 hdu r273121 : #i43029# psprint requires explicit control of font subset name
2009-06-16 18:15:43 +0200 hdu r273033 : #i43029# minor reshuffling to prepare CFF->PS font uploading
2009-06-16 16:25:21 +0200 hdu r273025 : #i43029# minimal-invasive change to sft.cxx to access a SFNT's CFF subtable
2009-06-12 15:51:42 +0200 hdu r272925 : #i43029# support OT/CFF subsetting for our PDF export on MacOSX
2009-06-12 15:43:26 +0200 hdu r272924 : #i43029# provide subset metrics as required by subset requesters
2009-05-27 13:58:59 +0200 hdu r272342 : #i43029# TripleInt is already reserved by OSX Carbon
2009-05-27 13:41:12 +0200 hdu r272339 : #i43029# fix warnings and make it compile on different platforms
2009-05-26 18:18:38 +0200 hdu r272315 : #i43029# start moving font subsetting into specialized class
2009-05-26 17:23:55 +0200 hdu r272312 : #i43029# improve name for CFF->PFB subsetted font
2009-05-25 17:12:27 +0200 hdu r272264 : #i43029# PDF-export: get type1-subsetting of the ground
2009-05-25 11:15:39 +0200 hdu r272227 : #i43029# fix BlueValues/FontBBox topdict entries
2009-05-25 10:59:16 +0200 hdu r272222 : #i43029# better PFB-DICT entries for FontBBox and BlueValues
2009-05-25 10:26:46 +0200 hdu r272219 : #i43029# emit other PRIVDICT hints for CFF->PFB subsetting
2009-05-25 10:10:25 +0200 hdu r272218 : #i43029# sign-extend shortint/longint typeopts/dictops
2009-05-25 09:38:33 +0200 hdu r272217 : #i43029# better glyph names for CFF-subsetted PFB
2009-05-20 18:57:11 +0200 hdu r272147 : #i43029# a CFF-subsetter gets the Blues
2009-05-20 14:05:35 +0200 hdu r272127 : #i43029# implement CreateFontSubsetFromCff()
2009-05-18 12:33:05 +0200 hdu r272012 : #i43029# add and use CffSubsetterContext::writeCurveTo()
2009-05-15 11:38:08 +0200 hdu r271931 : CffTable: allow charwidth parameter for type2 endchar operator
2009-05-14 18:55:25 +0200 hdu r271916 : #i43029# implement flex/flex1/hflex/hflex1 typeop conversion, fix type1val writing
2009-05-11 09:53:26 +0200 hdu r271750 : #i101695# improve import of ghostscript-PDF font names
2009-05-07 11:35:12 +0200 hdu r271644 : #i43029# adusted whitespace conventions from previously private code
2009-05-06 12:33:11 +0200 hdu r271579 : #i43029# change copyright header, fix warnings on some compilers
2009-05-06 10:50:50 +0200 hdu r271576 : improve whitespace and constness in some POS code
2009-05-05 16:10:56 +0200 hdu r271532 : #i43029# makefile support for new cff subsetter code
2009-05-05 14:56:29 +0200 hdu r271519 : #i43029# start integrating my CFF->Type1 subsetter code
2009-05-04 17:07:14 +0200 hdu r271474 : #i100140# remove obsoleted tables used for encoding conversion
2009-05-04 17:05:20 +0200 hdu r271473 : #i100140# use generic encoding converters in xlat.cxx
2009-04-15 11:58:25 +0200 hdu r270829 : #i101102# remove build dependency to removed module psprint
2009-04-14 15:57:13 +0200 hdu r270788 : CWS-TOOLING: rebase CWS otf01 to trunk@270723 (milestone: DEV300:m46)
2009-03-11 14:49:56 +0100 hdu r269335 : CWS-TOOLING: rebase CWS otf01 to trunk@269297 (milestone: DEV300:m43)
2009-02-06 12:32:22 +0100 hdu r267451 : resync CWS across CVS->SVN change
2009-02-06 12:32:04 +0100 hdu r267450 : resync CWS across CVS->SVN change

  • Participants
  • Parent commits 86dffb1

Comments (0)

Files changed (48)

File vcl/aqua/source/gdi/salatsuifontutils.cxx

  *
  * OpenOffice.org - a multi-platform office productivity suite
  *
- * $RCSfile: salatsuifontutils.cxx,v $
- * $Revision: 1.13.138.6 $
- *
  * This file is part of OpenOffice.org.
  *
  * OpenOffice.org is free software: you can redistribute it and/or modify
     rDFA.meItalic     = ITALIC_NONE;
     rDFA.mbSymbolFlag = false;
 
-	// get the embeddable + subsettable status
-	// TODO: remove test after PS-OpenType subsetting is implemented
-	ATSFontRef rATSFontRef = FMGetATSFontRefFromFont( nFontID );
-	ByteCount nGlyfLen	= 0;
-    OSStatus rc = ATSFontGetTable( rATSFontRef, 0x676c7966/*glyf*/, 0, 0, NULL, &nGlyfLen);
-	rDFA.mbSubsettable	= ((rc == noErr) && (nGlyfLen > 0));
+	// all scalable fonts on this platform are subsettable
+	rDFA.mbSubsettable	= true;
 	rDFA.mbEmbeddable	= false;
 	// TODO: these members are needed only for our X11 platform targets
 	rDFA.meAntiAlias	= ANTIALIAS_DONTKNOW;
 
 	// prepare iterating over all name strings of the font	
     ItemCount nFontNameCount = 0;
-    rc = ATSUCountFontNames( nFontID, &nFontNameCount );
+    OSStatus rc = ATSUCountFontNames( nFontID, &nFontNameCount );
     if( rc != noErr )
         return false;
     int nBestNameValue = 0;
             case 0x30A: nNameValue += 0;            // Win-UCS-4
                         eEncoding = RTL_TEXTENCODING_UCS4;
                         break;
-            case 0x100: nNameValue += 21; 	    // Mac Roman
+            case 0x100: nNameValue += 21; 	        // Mac Roman
                         eEncoding = RTL_TEXTENCODING_APPLE_ROMAN;
                         break;
             case 0x300: nNameValue =  0;            // Win Symbol encoded name!

File vcl/aqua/source/gdi/salgdi.cxx

  *
  * OpenOffice.org - a multi-platform office productivity suite
  *
- * $RCSfile: salgdi.cxx,v $
- * $Revision: 1.81.14.1 $
- *
  * This file is part of OpenOffice.org.
  *
  * OpenOffice.org is free software: you can redistribute it and/or modify
 #include "salatsuifontutils.hxx"
 
 #include "vcl/impfont.hxx"
+#include "vcl/fontsubset.hxx"
 #include "vcl/sysdata.hxx"
 #include "vcl/sallayout.hxx"
 #include "vcl/svapp.hxx"
 	if( !ParseCMAP( &aBuffer[0], nRawLength, aCmapResult ) )
 		return mpCharMap;
 
-	mpCharMap = new ImplFontCharMap( aCmapResult.mnPairCount, aCmapResult.mpPairCodes, aCmapResult.mpStartGlyphs );
+	mpCharMap = new ImplFontCharMap( aCmapResult );
 	return mpCharMap;
 }
 
 		return;
 
 	// allocate a buffer for the OS/2 raw data
-	ByteVector aBuffer;
-	aBuffer.resize( nBufSize );
+	ByteVector aBuffer( nBufSize );
 
 	// get the OS/2 raw data
 	ByteCount nRawLength = 0;
     if( eStatus != noErr )
         return;
 
-    ByteVector aBuffer;
-    aBuffer.resize( nBufSize );
+    ByteVector aBuffer( nBufSize );
 
     ByteCount nRawLength = 0;
     eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
 }
 
 static bool GetRawFontData( const ImplFontData* pFontData,
-	ByteVector& rBuffer )
+	ByteVector& rBuffer, bool* pJustCFF )
 {
 	const ImplMacFontData* pMacFont = static_cast<const ImplMacFontData*>(pFontData);
 	const ATSUFontID nFontId = static_cast<ATSUFontID>(pMacFont->GetFontId());
 	ATSFontRef rFont = FMGetATSFontRefFromFont( nFontId );
 
+	ByteCount nCffLen = 0;
+	OSStatus eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, 0, NULL, &nCffLen);
+	if( pJustCFF != NULL )
+	{
+		*pJustCFF = (eStatus == noErr) && (nCffLen > 0);
+		if( *pJustCFF )
+		{
+			rBuffer.resize( nCffLen );
+			eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, nCffLen, (void*)&rBuffer[0], &nCffLen);
+			if( (eStatus != noErr) || (nCffLen <= 0) )
+				return false;
+			return true;
+		}
+	}
+
 	// get font table availability and size in bytes
 	ByteCount nHeadLen	= 0;
-	OSStatus eStatus = ATSFontGetTable( rFont, GetTag("head"), 0, 0, NULL, &nHeadLen);
+	eStatus = ATSFontGetTable( rFont, GetTag("head"), 0, 0, NULL, &nHeadLen);
 	if( (eStatus != noErr) || (nHeadLen <= 0) )
 		return false;
 	ByteCount nMaxpLen	= 0;
     eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nCmapLen);
 	if( (eStatus != noErr) || (nCmapLen <= 0) )
 		return false;
-	ByteCount nLocaLen	= 0;
-    eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, 0, NULL, &nLocaLen);
-	if( (eStatus != noErr) || (nLocaLen <= 0) )
-		return false;
-	ByteCount nGlyfLen	= 0;
-    eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, 0, NULL, &nGlyfLen);
-	if( (eStatus != noErr) || (nGlyfLen <= 0) )
-		return false;
 	ByteCount nNameLen	= 0;
     eStatus = ATSFontGetTable( rFont, GetTag("name"), 0, 0, NULL, &nNameLen);
 	if( (eStatus != noErr) || (nNameLen <= 0) )
 	if( (eStatus != noErr) || (nHmtxLen <= 0) )
 		return false;
 
+	// get the glyph outline tables
+	ByteCount nLocaLen	= 0;
+	ByteCount nGlyfLen	= 0;
+	if( (eStatus != noErr) || (nCffLen <= 0) )
+	{
+		eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, 0, NULL, &nLocaLen);
+		if( (eStatus != noErr) || (nLocaLen <= 0) )
+			return false;
+		eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, 0, NULL, &nGlyfLen);
+		if( (eStatus != noErr) || (nGlyfLen <= 0) )
+			return false;
+	}
+
 	ByteCount nPrepLen=0, nCvtLen=0, nFpgmLen=0;
-	if( 1 )	// TODO: reduce PDF size by making hint subsetting optional
+	if( nGlyfLen )	// TODO: reduce PDF size by making hint subsetting optional
 	{
 		eStatus = ATSFontGetTable( rFont, GetTag("prep"), 0, 0, NULL, &nPrepLen);
 		eStatus = ATSFontGetTable( rFont, GetTag("cvt "), 0, 0, NULL, &nCvtLen);
 	}
 	
 	// prepare a byte buffer for a fake font
-	int nTableCount = 8;
-	nTableCount += (nPrepLen>0) + (nCvtLen>0) + (nFpgmLen>0);
+	int nTableCount = 7;
+	nTableCount += (nPrepLen>0) + (nCvtLen>0) + (nFpgmLen>0) + (nGlyfLen>0);
 	const ByteCount nFdirLen = 12 + 16*nTableCount;
 	ByteCount nTotalLen = nFdirLen;
-	nTotalLen += nHeadLen + nMaxpLen + nNameLen + nCmapLen + nLocaLen + nGlyfLen;
+	nTotalLen += nHeadLen + nMaxpLen + nNameLen + nCmapLen;
+	if( nGlyfLen )
+		nTotalLen += nLocaLen + nGlyfLen;
+	else
+		nTotalLen += nCffLen;
 	nTotalLen += nHheaLen + nHmtxLen;
 	nTotalLen += nPrepLen + nCvtLen + nFpgmLen;
 	rBuffer.resize( nTotalLen );
 		FakeDirEntry( GetTag("fpgm"), nOfs, nFpgmLen, &rBuffer[0], pFakeEntry );
 		nOfs += nFpgmLen;
 	}
-    eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, nGlyfLen, (void*)&rBuffer[nOfs], &nGlyfLen);
-	FakeDirEntry( GetTag("glyf"), nOfs, nGlyfLen, &rBuffer[0], pFakeEntry );
-	nOfs += nGlyfLen;
+	if( nCffLen ) {
+	    eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, nCffLen, (void*)&rBuffer[nOfs], &nCffLen);
+		FakeDirEntry( GetTag("CFF "), nOfs, nCffLen, &rBuffer[0], pFakeEntry );
+		nOfs += nGlyfLen;
+	} else {
+	    eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, nGlyfLen, (void*)&rBuffer[nOfs], &nGlyfLen);
+		FakeDirEntry( GetTag("glyf"), nOfs, nGlyfLen, &rBuffer[0], pFakeEntry );
+		nOfs += nGlyfLen;
+		eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, nLocaLen, (void*)&rBuffer[nOfs], &nLocaLen);
+		FakeDirEntry( GetTag("loca"), nOfs, nLocaLen, &rBuffer[0], pFakeEntry );
+		nOfs += nLocaLen;
+	}
 	eStatus = ATSFontGetTable( rFont, GetTag("head"), 0, nHeadLen, (void*)&rBuffer[nOfs], &nHeadLen);
 	FakeDirEntry( GetTag("head"), nOfs, nHeadLen, &rBuffer[0], pFakeEntry );
 	nOfs += nHeadLen;
 	eStatus = ATSFontGetTable( rFont, GetTag("hmtx"), 0, nHmtxLen, (void*)&rBuffer[nOfs], &nHmtxLen);
 	FakeDirEntry( GetTag("hmtx"), nOfs, nHmtxLen, &rBuffer[0], pFakeEntry );
 	nOfs += nHmtxLen;
-    eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, nLocaLen, (void*)&rBuffer[nOfs], &nLocaLen);
-	FakeDirEntry( GetTag("loca"), nOfs, nLocaLen, &rBuffer[0], pFakeEntry );
-	nOfs += nLocaLen;
     eStatus = ATSFontGetTable( rFont, GetTag("maxp"), 0, nMaxpLen, (void*)&rBuffer[nOfs], &nMaxpLen);
 	FakeDirEntry( GetTag("maxp"), nOfs, nMaxpLen, &rBuffer[0], pFakeEntry );
 	nOfs += nMaxpLen;
 	const ImplFontData* pFontData, long* pGlyphIDs, sal_uInt8* pEncoding,
 	sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
 {
+	// TODO: move more of the functionality here into the generic subsetter code
+
+	// prepare the requested file name for writing the font-subset file
+    rtl::OUString aSysPath;
+    if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
+        return FALSE;
+    const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
+    const ByteString aToFile( rtl::OUStringToOString( aSysPath, aThreadEncoding ) );
+
+	// get the raw-bytes from the font to be subset
 	ByteVector aBuffer;
-	if( !GetRawFontData( pFontData, aBuffer ) )
+	bool bCffOnly = false;
+	if( !GetRawFontData( pFontData, aBuffer, &bCffOnly ) )
 		return sal_False;
 
+	// handle CFF-subsetting
+	if( bCffOnly )
+	{
+		// provide the raw-CFF data to the subsetter
+		ByteCount nCffLen = aBuffer.size();
+		rInfo.LoadFont( FontSubsetInfo::CFF_FONT, &aBuffer[0], nCffLen );
+
+		// NOTE: assuming that all glyphids requested on Aqua are fully translated
+
+		// make the subsetter provide the requested subset
+		FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
+		bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
+			pGlyphIDs, pEncoding, nGlyphCount, pGlyphWidths );
+		fclose( pOutFile );
+		return bRC;
+	}
+
 	// TODO: modernize psprint's horrible fontsubset C-API
 	// this probably only makes sense after the switch to another SCM
 	// that can preserve change history after file renames
 	// get details about the subsetted font
 	TTGlobalFontInfo aTTInfo;
 	::GetTTGlobalFontInfo( pSftFont, &aTTInfo );
-    rInfo.m_nFontType   = SAL_FONTSUBSETINFO_TYPE_TRUETYPE;
-    rInfo.m_aPSName     = String( aTTInfo.psname, RTL_TEXTENCODING_UTF8 );
-    rInfo.m_aFontBBox	= Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
+	rInfo.m_nFontType   = FontSubsetInfo::SFNT_TTF;
+	rInfo.m_aPSName     = String( aTTInfo.psname, RTL_TEXTENCODING_UTF8 );
+	rInfo.m_aFontBBox	= Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
                                     Point( aTTInfo.xMax, aTTInfo.yMax ) );
-    rInfo.m_nCapHeight	= aTTInfo.yMax; // Well ...
-    rInfo.m_nAscent	    = +aTTInfo.winAscent;
-    rInfo.m_nDescent    = -aTTInfo.winDescent;
+	rInfo.m_nCapHeight	= aTTInfo.yMax; // Well ...
+	rInfo.m_nAscent	    = +aTTInfo.winAscent;
+	rInfo.m_nDescent    = -aTTInfo.winDescent;
 	// mac fonts usually do not have an OS2-table
 	// => get valid ascent/descent values from other tables
 	if( !rInfo.m_nAscent )
     free( pGlyphMetrics );
 
     // write subset into destination file
-    rtl::OUString aSysPath;
-    if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
-        return FALSE;
-    rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
-    ByteString aToFile( rtl::OUStringToOString( aSysPath, aThreadEncoding ) );
     nRC = ::CreateTTFromTTGlyphs( pSftFont, aToFile.GetBuffer(), aShortIDs,
             aTempEncs, nGlyphCount, 0, NULL, 0 );
 	::CloseTTFont(pSftFont);
 	if( pFontData->IsSubsettable() )
     {
 		ByteVector aBuffer;
-		if( !GetRawFontData( pFontData, aBuffer ) )
+		if( !GetRawFontData( pFontData, aBuffer, NULL ) )
 			return;
 
 		// TODO: modernize psprint's horrible fontsubset C-API
                               FontSubsetInfo& rInfo,
                               long* pDataLen )
 {
-	// TODO: are the non-subsettable fonts on OSX that are embeddable?
     return NULL;
 }
 

File vcl/inc/list.h

  *
  * OpenOffice.org - a multi-platform office productivity suite
  *
- * $RCSfile: list.h,v $
- * $Revision: 1.4 $
- *
  * This file is part of OpenOffice.org.
  *
  * OpenOffice.org is free software: you can redistribute it and/or modify
  *
  ************************************************************************/
 
-/* $Id: list.h,v 1.4 2008-06-25 14:20:01 kz Exp $ */
-
 /*[]---------------------------------------------------[]*/
 /*|                                                     |*/
 /*|  Implementation of the list data type               |*/

File vcl/inc/sft.hxx

  *
  * OpenOffice.org - a multi-platform office productivity suite
  *
- * $RCSfile: sft.h,v $
- * $Revision: 1.21 $
- *
  * This file is part of OpenOffice.org.
  *
  * OpenOffice.org is free software: you can redistribute it and/or modify
  *
  ************************************************************************/
 
-/* $Id: sft.h,v 1.21 2008-06-25 14:20:49 kz Exp $ */
-
 /**
-
- *
  * @file sft.h
  * @brief Sun Font Tools
  * @author Alexander Gelfenbain
         sal_uInt32 ur3;               /**< bits 64 - 95 of Unicode Range flags                     */
         sal_uInt32 ur4;               /**< bits 96 - 127 of Unicode Range flags                    */
         sal_uInt8   panose[10];        /**< PANOSE classification number                            */
-        sal_uInt16 typeFlags;		  /**< type flags (copyright information)                      */
+        sal_uInt32 typeFlags;         /**< type flags (copyright bits + PS-OpenType flag)       */
     } TTGlobalFontInfo;
 
+#define TYPEFLAG_INVALID        0x8000000
+#define TYPEFLAG_COPYRIGHT_MASK 0x000000E
+#define TYPEFLAG_PS_OPENTYPE    0x0010000
+
 /** Structure used by KernGlyphs()      */
     typedef struct {
         int x;                    /**< positive: right, negative: left                        */
  * returns the number of glyphs in a font
  */
  int GetTTGlyphCount( TrueTypeFont* ttf );
+ 
+/**
+ * provide access to the raw data of a SFNT-container's subtable
+ */
+ bool GetSfntTable( TrueTypeFont* ttf, int nSubtableIndex,
+ 	const sal_uInt8** ppRawBytes, int* pRawLength );
     
 /*- private definitions */ /*FOLD00*/
 
         sal_uInt32  unitsPerEm;
         sal_uInt32  numberOfHMetrics;
         sal_uInt32  numOfLongVerMetrics;                   /* if this number is not 0, font has vertical metrics information */
-        sal_uInt8   *cmap;
+        const sal_uInt8* cmap;
         int         cmapType;
         sal_uInt32 (*mapper)(const sal_uInt8 *, sal_uInt32); /* character to glyphID translation function                          */
-        sal_uInt8   **tables;                              /* array of pointers to raw subtables in SFNT file                    */
+        const sal_uInt8   **tables;                        /* array of pointers to raw subtables in SFNT file                    */
         sal_uInt32  *tlens;                                /* array of table lengths                                             */
         int         kerntype;                              /* Defined in the KernType enum                                       */
         sal_uInt32  nkern;                                 /* number of kern subtables                                           */
-        sal_uInt8   **kerntables;                          /* array of pointers to kern subtables                                */
+        const sal_uInt8** kerntables;                      /* array of pointers to kern subtables                                */
         void        *pGSubstitution;                       /* info provided by GSUB for UseGSUB()                                */
     };
 
 #define O_prep 14    /* 'prep' - only used in TT->TT generation */
 #define O_fpgm 15    /* 'fpgm' - only used in TT->TT generation */
 #define O_gsub 16    /* 'GSUB' */
-#define NUM_TAGS 17
+#define O_CFF  17    /* 'CFF' */
+#define NUM_TAGS 18
 
 } // namespace vcl
 

File vcl/inc/vcl/fontmanager.hxx

  *
  * OpenOffice.org - a multi-platform office productivity suite
  *
- * $RCSfile: fontmanager.hxx,v $
- * $Revision: 1.36 $
- *
  * This file is part of OpenOffice.org.
  *
  * OpenOffice.org is free software: you can redistribute it and/or modify
 
 // forward declarations
 namespace utl { class MultiAtomProvider; } // see unotools/atom.hxx
+class FontSubsetInfo;
 
 namespace psp {
 class PPDParser; // see ppdparser.hxx
     rtl_TextEncoding        			m_aEncoding;
     fcstatus::type                      m_eEmbeddedbitmap;
     fcstatus::type                      m_eAntialias;
+    bool                                m_bSubsettable;
+    bool                                m_bEmbeddable;
 
     FastPrintFontInfo() :
             m_nID( 0 ),
         rtl::OString          m_aFontFile;        // relative to directory
         rtl::OString          m_aXLFD;            // mainly for administration, contains the XLFD from fonts.dir
         int                     m_nCollectionEntry; // -1 for regular fonts, 0 to ... for fonts stemming from collections
-        unsigned int           m_nTypeFlags;		// from TrueType file; only known use is for copyright flags
+        unsigned int           m_nTypeFlags;		// copyright bits and PS-OpenType flag
 
-        TrueTypeFontFile() : PrintFont( fonttype::TrueType ), m_nDirectory( 0 ), m_nCollectionEntry(-1), m_nTypeFlags( 0x80000000 ) {}
+        TrueTypeFontFile();
         virtual ~TrueTypeFontFile();
         virtual bool queryMetricPage( int nPage, utl::MultiAtomProvider* pProvider );
     };
     // nGlyphs: number of glyphs in arrays
     // pCapHeight:: capital height of the produced font
     // pXMin, pYMin, pXMax, pYMax: outgoing font bounding box
-    bool createFontSubset( fontID nFont,
+    // TODO: callers of this method should use its FontSubsetInfo counterpart directly
+    bool createFontSubset( FontSubsetInfo&,
+                           fontID nFont,
                            const rtl::OUString& rOutFile,
                            sal_Int32* pGlyphIDs,
                            sal_uInt8* pNewEncoding,

File vcl/inc/vcl/fontsubset.hxx

+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org.  If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _SV_FONTSUBSET_HXX
+#define _SV_FONTSUBSET_HXX
+
+#include <tools/gen.hxx>
+#include <tools/string.hxx>
+#include <cstdio>
+
+namespace vcl { struct _TrueTypeFont; } // SFT's idea of a TTF font
+
+class FontSubsetInfo
+{
+public:
+	explicit	FontSubsetInfo( void );
+	virtual		~FontSubsetInfo( void );
+
+	enum FontType {
+		NO_FONT		= 0,
+		SFNT_TTF	= 1<<1,		// SFNT container with TrueType glyphs
+		SFNT_CFF	= 1<<2,		// SFNT container with CFF-container
+		TYPE1_PFA	= 1<<3,		// PSType1 Postscript Font Ascii
+		TYPE1_PFB	= 1<<4,		// PSType1 Postscript Font Binary
+		CFF_FONT	= 1<<5,		// CFF-container with PSType2 glyphs
+		TYPE3_FONT	= 1<<6,		// PSType3 Postscript font
+		TYPE42_FONT	= 1<<7,		// PSType42 wrapper for an SFNT_TTF
+		ANY_SFNT	= SFNT_TTF | SFNT_CFF,
+		ANY_TYPE1	= TYPE1_PFA | TYPE1_PFB,
+		ANY_FONT	= 0xFF
+	};
+
+	bool		LoadFont( FontType eInFontType,
+					const unsigned char* pFontBytes, int nByteLength );
+	bool		LoadFont( vcl::_TrueTypeFont* pSftTrueTypeFont );
+
+	bool		CreateFontSubset( int nOutFontTypeMask,
+					FILE* pOutFile, const char* pOutFontName,
+					const long* pReqGlyphIds, const sal_uInt8* pEncodedIds,
+					int nReqGlyphCount, sal_Int32* pOutGlyphWidths = NULL );
+
+public: // TODO: make subsetter results private and provide accessor methods instead
+	// subsetter-provided subset details needed by e.g. Postscript or PDF
+	String		m_aPSName;
+	int			m_nAscent; // all metrics in PS font units
+	int			m_nDescent;
+	int			m_nCapHeight;
+	Rectangle	m_aFontBBox;
+	FontType	m_nFontType;	// font-type of subset result
+
+private:
+	// input-font-specific details
+	unsigned const char*	mpInFontBytes;
+	int						mnInByteLength;
+	FontType				meInFontType;	// allowed mask of input font-types
+	vcl::_TrueTypeFont*		mpSftTTFont;
+
+	// subset-request details
+	int						mnReqFontTypeMask;	// allowed subset-target font types
+	FILE*					mpOutFile;
+	const char*				mpReqFontName;
+	const long*				mpReqGlyphIds;
+	const sal_uInt8*		mpReqEncodedIds;
+	int						mnReqGlyphCount;
+
+protected:
+	bool	CreateFontSubsetFromCff( sal_Int32* pOutGlyphWidths = NULL );
+	bool	CreateFontSubsetFromSfnt( sal_Int32* pOutGlyphWidths = NULL );
+	bool	CreateFontSubsetFromType1( sal_Int32* pOutGlyphWidths = NULL );
+};
+
+#endif // _SV_FONTSUBSET_HXX
+

File vcl/inc/vcl/glyphcache.hxx

 namespace basegfx { class B2DPolyPolygon; }
 
 class RawBitmap;
+class CmapResult;
 
 #include <vcl/outfont.hxx>
 
     virtual void                FetchFontMetric( ImplFontMetricData&, long& rFactor ) const = 0;
     virtual ULONG               GetKernPairs( ImplKernPairData** ) const      { return 0; }
     virtual int                 GetGlyphKernValue( int, int ) const           { return 0; }
-    virtual ULONG               GetFontCodeRanges( sal_uInt32* ) const { return 0; }
+    virtual bool                GetFontCodeRanges( CmapResult& ) const        { return false; }
     Point                       TransformPoint( const Point& ) const;
 
     GlyphData&                  GetGlyphData( int nGlyphIndex );

File vcl/inc/vcl/impfont.hxx

  *
  * OpenOffice.org - a multi-platform office productivity suite
  *
- * $RCSfile: impfont.hxx,v $
- * $Revision: 1.3.134.1 $
- *
  * This file is part of OpenOffice.org.
  *
  * OpenOffice.org is free software: you can redistribute it and/or modify
 // - ImplFontCharMap -
 // -------------------
 
+class CmapResult;
+
 class VCL_DLLPUBLIC ImplFontCharMap
 {
 public:
-                        ImplFontCharMap( int nRangePairs,
-                            const sal_uInt32* pRangeCodes,
-                            const int* pStartGlyphs = NULL );
+   explicit             ImplFontCharMap( const CmapResult& );
 
-static ImplFontCharMap* GetDefaultMap();
+	static ImplFontCharMap* GetDefaultMap( bool bSymbols=false);
+
     bool                IsDefaultMap() const;
     bool                HasChar( sal_uInt32 ) const;
     int                 CountCharsInRange( sal_uInt32 cMin, sal_uInt32 cMax ) const;
     void                AddReference();
     void                DeReference();
 
-    int                 GetGlyphIndex( sal_uInt32 );
+    int                 GetGlyphIndex( sal_uInt32 ) const;
 
 private:
-                        ~ImplFontCharMap();
+    /*virtual*/         ~ImplFontCharMap();
     int                 ImplFindRangeIndex( sal_uInt32 ) const;
 
     // prevent assignment and copy construction
-                        ImplFontCharMap( const ImplFontCharMap& );
+    explicit            ImplFontCharMap( const ImplFontCharMap& );
     void                operator=( const ImplFontCharMap& );
 
 private:
     const sal_uInt32*   mpRangeCodes;     // pairs of StartCode/(EndCode+1)
-    const int*          mpStartGlyphs;    // index of the first glyph of the ranges
+    const int*          mpStartGlyphs;    // range-specific mapper to glyphs
+    const USHORT*       mpGlyphIds;       // individual glyphid mappings
     int                 mnRangeCount;
     int                 mnCharCount;
     int                 mnRefCount;
 };
 
 // CmapResult is a normalized version of the many CMAP formats
-struct CmapResult
+class
+#ifdef UNX
+	VCL_DLLPUBLIC // vcl-plugins need it
+#endif // UNX
+CmapResult
 {
-    sal_uInt32* mpPairCodes;
-    int*        mpStartGlyphs;
-    int         mnPairCount;
-    bool        mbRecoded;
-    bool        mbSymbolic;
+public:
+	explicit	CmapResult( bool bSymbolic = false,
+					const sal_uInt32* pRangeCodes = NULL, int nRangeCount = 0,
+					const int* pStartGlyphs = 0, const USHORT* pGlyphIds = NULL );
+
+	const sal_uInt32* mpRangeCodes;
+	const int*        mpStartGlyphs;
+	const USHORT*     mpGlyphIds;
+	int			      mnRangeCount;
+	bool		      mbSymbolic;
+	bool			  mbRecoded;
 };
 
 bool ParseCMAP( const unsigned char* pRawData, int nRawLength, CmapResult& );
 
 #endif // _SV_IMPFONT_HXX
+

File vcl/inc/vcl/outfont.hxx

  *
  * OpenOffice.org - a multi-platform office productivity suite
  *
- * $RCSfile: outfont.hxx,v $
- * $Revision: 1.6.14.2 $
- *
  * This file is part of OpenOffice.org.
  *
  * OpenOffice.org is free software: you can redistribute it and/or modify
     ImplMultiTextLineInfo&  operator=( const ImplMultiTextLineInfo& );
 };
 
-#define SAL_FONTSUBSETINFO_TYPE_TRUETYPE 0
-#define SAL_FONTSUBSETINFO_TYPE_TYPE1    1
+#endif // _SV_OUTFONT_HXX
 
-struct FontSubsetInfo
-{
-    String		m_aPSName;
-    int			m_nFontType;
-    int			m_nAscent; // all lengths in PS font units
-    int			m_nDescent;
-    int			m_nCapHeight;
-    Rectangle	m_aFontBBox;
-};
-
-#endif // _SV_OUTFONT_HXX

File vcl/inc/vcl/printergfx.hxx

  *
  * OpenOffice.org - a multi-platform office productivity suite
  *
- * $RCSfile: printergfx.hxx,v $
- * $Revision: 1.19.18.1 $
- *
  * This file is part of OpenOffice.org.
  *
  * OpenOffice.org is free software: you can redistribute it and/or modify
 #define _PSPRINT_PRINTERGFX_HXX_
 
 #include "vcl/helper.hxx"
+#include "vcl/sallayout.hxx"
 #include "osl/file.hxx"
 #include "tools/gen.hxx"
 
                               const sal_Int32* pDeltaArray = NULL);
 
     void			drawGlyphs( const Point& rPoint,
-                                sal_uInt32* pGlyphIds,
+                                sal_GlyphId* pGlyphIds,
                                 sal_Unicode* pUnicodes,
                                 sal_Int16 nLen,
                                 sal_Int32* pDeltaArray );
 
     // for CTL
     void			DrawGlyphs( const Point& rPoint,
-                                sal_uInt32* pGlyphIds,
+                                sal_GlyphId* pGlyphIds,
                                 sal_Unicode* pUnicodes,
                                 sal_Int16 nLen,
                                 sal_Int32* pDeltaArray );

File vcl/inc/vcl/salgdi.hxx

 class SalLayout;
 class ImplLayoutArgs;
 class Rectangle;
-struct FontSubsetInfo;
+class FontSubsetInfo;
 class OutputDevice;
 class ServerFontLayout;
 struct SystemGraphicsData;

File vcl/inc/vcl/sallayout.hxx

  *
  * OpenOffice.org - a multi-platform office productivity suite
  *
- * $RCSfile: sallayout.hxx,v $
- * $Revision: 1.8.54.1 $
- *
  * This file is part of OpenOffice.org.
  *
  * OpenOffice.org is free software: you can redistribute it and/or modify

File vcl/source/fontsubset/cff.cxx

+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2009 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org.  If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <cstdio>
+#include <cstring>
+#include <assert.h>
+
+#include <vcl/fontsubset.hxx>
+
+//#define IGNORE_HINTS
+
+typedef unsigned char U8;
+typedef unsigned short U16;
+typedef long long S64;
+
+typedef sal_Int32 GlyphWidth;
+
+#include <vector>
+typedef std::vector<int> IntVector;
+
+// ====================================================================
+
+static const char* pStringIds[] = {
+/*0*/	".notdef",		"space",			"exclam",			"quotedbl",
+	"numbersign",		"dollar",			"percent",			"ampersand",
+	"quoteright",		"parenleft",		"parenright",		"asterisk",
+	"plus",				"comma",			"hyphen",			"period",
+/*16*/	"slash",		"zero",				"one",				"two",
+	"three",			"four",				"five",				"six",
+	"seven",			"eight",			"nine",				"colon",
+	"semicolon",		"less",				"equal",			"greater",
+/*32*/	"question",		"at",				"A",				"B",
+	"C",				"D",				"E",				"F",
+	"G",				"H",				"I",				"J",
+	"K",				"L",				"M",				"N",
+/*48*/	"O",			"P",				"Q",				"R",
+	"S",				"T",				"U",				"V",
+	"W",				"X",				"Y",				"Z",
+	"bracketleft",		"backslash",		"bracketright",		"asciicircum",
+/*64*/	"underscore",	"quoteleft",		"a",				"b",
+	"c",				"d",				"e",				"f",
+	"g",				"h",				"i",				"j",
+	"k",				"l",				"m",				"n",
+/*80*/	"o",			"p",				"q",				"r",
+	"s",				"t",				"u",				"v",
+	"w",				"x",				"y",				"z",
+	"braceleft",		"bar",				"braceright",		"asciitilde",
+/*96*/	"exclamdown",	"cent",				"sterlin",			"fraction",
+	"yen",				"florin",			"section",			"currency",
+	"quotesingle",		"quotedblleft",		"guillemotleft",	"guilsinglleft",
+	"guilsinglright",	"fi",				"fl",				"endash",
+/*112*/	"dagger",		"daggerdbl",		"periodcentered",	"paragraph",
+	"bullet",			"quotesinglbase",	"quotedblbase",		"quotedblright",
+	"guillemotright",	"ellipsis",			"perthousand",		"questiondown",
+	"grave",			"acute",			"circumflex",		"tilde",
+/*128*/	"macron",		"breve",			"dotaccent",		"dieresis",
+	"ring",				"cedilla",			"hungarumlaut",		"ogonek",
+	"caron",			"endash",			"AE",				"ordfeminine",
+	"Lslash",			"Oslash",			"OE",				"ordmasculine",
+/*144*/	"ae",			"dotlessi",			"lslash",			"oslash",
+	"oe",				"germandbls",		"onesuperior",		"logicalnot",
+	"mu",				"trademark",		"Eth",				"onehalf",
+	"plusminus",		"Thorn",			"onequarter",		"divide",
+/*160*/	"brokenbar",	"degree",			"thorn",			"threequarters",
+	"twosuperior",		"registered",		"minus",			"eth",
+	"multiply",			"threesuperior",	"copyright",		"Aacute",
+	"Acircumflex",		"Adieresis",		"Agrave",			"Aring",
+/*176*/	"Atilde",		"Ccedilla",			"Eacute",			"Ecircumflex",
+	"Edieresis",		"Egrave",			"Iacute",			"Icircumflex",
+	"Idieresis",		"Igrave",			"Ntilde",			"Oacute",
+	"Ocircumflex",		"Odieresis",		"Ograve",			"Otilde",
+/*192*/	"Scaron",		"Uacute",			"Ucircumflex",		"Udieresis",
+	"Ugrave",			"Yacute",			"Ydieresis",		"Zcaron",
+	"aacute",			"acircumflex",		"adieresis",		"agrave",
+	"aring",			"atilde",			"ccedilla",			"eacute",
+/*208*/	"ecircumflex",	"edieresis",		"egrave",			"iacute",
+	"icircumflex",		"idieresis",		"igrave",			"ntilde",
+	"oacute",			"ocircumflex",		"odieresis",		"ograve",
+	"otilde",			"scaron",			"uacute",			"ucircumflex",
+/*224*/	"udieresis",	"ugrave",			"yacute",			"ydieresis",
+	"zcaron",			"exclamsmall",		"Hungarumlautsmall","dollaroldstyle",
+	"dollarsuperior",	"ampersandsmall",	"Acutesmall",		"parenleftsuperior",
+	"parenrightsuperior","twodotenleader",	"onedotenleader",	"zerooldstyle",
+/*240*/	"oneoldstyle",	"twooldstyle",		"threeoldstyle",	"fouroldstyle",
+	"fiveoldstyle",		"sixoldstyle",		"sevenoldstyle",	"eightoldstyle",
+	"nineoldstile",		"commasuperior",	"threequartersemdash","periodsuperior",
+	"questionsmall",	"asuperior",		"bsuperior",		"centsuperior",
+/*256*/	"dsuperior",	"esuperior",		"isuperior",		"lsuperior",
+	"msuperior",		"nsuperior",		"osuperior",		"rsuperior",
+	"ssuperior",		"tsuperior",		"ff",				"ffi",
+	"ffl",				"parenleftinferior","parenrightinferior","Circumflexsmall",
+/*272*/	"hyphensuperior","Gravesmall",		"Asmall",			"Bsmall",
+	"Csmall",			"Dsmall",			"Esmall",			"Fsmall",
+	"Gsmall",			"Hsmall",			"Ismall",			"Jsmall",
+	"Ksmall",			"Lsmall",			"Msmall",			"Nsmall",
+/*288*/	"Osmall",		"Psmall",			"Qsmall",			"Rsmall",
+	"Ssmall",			"Tsmall",			"Usmall",			"Vsmall",
+	"Wsmall",			"Xsmall",			"Ysmall",			"Zsmall",
+	"colonmonetary",	"onefitted",		"rupia",			"Tildesmall",
+/*304*/	"exclamdownsmall","centoldstyle",	"Lslashsmall",		"Scaronsmall",
+	"Zcaronsmall",		"Dieresissmall",	"Brevesmall",		"Caronsmall",
+	"Dotaccentsmall",	"Macronsmall",		"figuredash",		"hypheninferior",
+	"Ogoneksmall",		"Ringsmall",		"Cedillasmall",		"questiondownsmall",
+/*320*/	"oneeight",		"threeeights",		"fiveeights",		"seveneights",
+	"onethird",			"twothirds",		"zerosuperior",		"foursuperior",
+	"fivesuperior",		"sixsuperior",		"sevensuperior",	"eightsuperior",
+	"ninesuperior",		"zeroinferior",		"oneinferior",		"twoinferior",
+/*336*/	"threeinferior","fourinferior",		"fiveinferior",		"sixinferior",
+	"seveninferior",	"eightinferior",	"nineinferior",		"centinferior",
+	"dollarinferior",	"periodinferior",	"commainferior",	"Agravesmall",
+	"Aacutesmall",		"Acircumflexsmall",	"Atildesmall",		"Adieresissmall",
+/*352*/	"Aringsmall",	"AEsmall",			"Ccedillasmall",	"Egravesmall",
+	"Eacutesmall",		"Ecircumflexsmall",	"Edieresissmall",	"Igravesmall",
+	"Iacutesmall",		"Icircumflexsmall",	"Idieresissmall",	"Ethsmall",
+	"Ntildesmall",		"Ogravesmall",		"Oacutesmall",		"Ocircumflexsmall",
+/*368*/	"Otildesmall",	"Odieressissmall",	"OEsmall",			"Oslashsmall",
+	"Ugravesmall",		"Uacutesmall",		"Ucircumflexsmall",	"Udieresissmall",
+	"Yacutesmall",		"Thornsmall",		"Ydieresissmall",	"001.000",
+	"001.001",			"001.002",			"001.003",			"Black",
+/*384*/	"Bold",			"Book",				"Light",			"Medium",
+	"Regular",			"Roman",			"Semibold"
+};
+
+// --------------------------------------------------------------------
+
+#if 0 // TODO: use them
+static const char* pStdEncNames[] = {
+	"ISOAdobe",	"Expert",	"ExpertSubSet"
+};
+#endif
+
+// --------------------------------------------------------------------
+
+// TOP DICT keywords (also covers PRIV DICT keywords)
+static const char* pDictOps[] = {
+	"sVersion",			"sNotice",				"sFullName",		"sFamilyName",
+	"sWeight",			"aFontBBox",			"dBlueValues",		"dOtherBlues",
+	"dFamilyBlues",		"dFamilyOtherBlues",	"nStdHW",			"nStdVW",
+	"xESC",				"nUniqueID",			"aXUID",			"nCharset",
+	"nEncoding",		"nCharStrings",			"PPrivate",			"nSubrs",
+	"nDefaultWidthX",	"nNominalWidthX",		NULL,				NULL,
+	NULL,				NULL,					NULL,				NULL,
+	"shortint",			"longint",				"BCD",				NULL
+};
+
+// --------------------------------------------------------------------
+
+// TOP DICT escapes (also covers PRIV DICT escapes)
+static const char* pDictEscs[] = {
+	"sCopyright",			"bIsFixedPitch",	"nItalicAngle",		"nUnderlinePosition",
+	"nUnderlineThickness",	"nPaintType",		"tCharstringType",	"aFontMatrix",
+	"nStrokeWidth",			"nBlueScale",		"nBlueShift",		"nBlueFuzz",
+	"dStemSnapH",			"dStemSnapV",		"bForceBold",		NULL,
+	NULL,					"nLanguageGroup",	"nExpansionFactor",	"nInitialRandomSeed",
+	"nSyntheticBase",		"sPostScript",		"sBaseFontName",	"dBaseFontBlend",
+	NULL,					NULL,				NULL,				NULL,
+	NULL,					NULL,				"rROS",				"nCIDFontVersion",
+	"nCIDFontRevision",		"nCIDFontType",		"nCIDCount",		"nUIDBase",
+	"nFDArray",				"nFDSelect",		"sFontName"
+};
+
+// --------------------------------------------------------------------
+
+static const char* pType1Ops[] = {
+	NULL,				"2hstem",			NULL,				"2vstem",
+	"1vmoveto",			"Arlineto",			"1hlineto",			"1vlineto",
+	"Crrcurveto",		"0closepath",		"Lcallsubr",		"0return",
+	"xT1ESC",			"2hsbw",			"0endchar",			NULL,
+	NULL,				NULL,				NULL,				NULL,
+	NULL,				"2rmoveto",			"1hmoveto",			NULL,
+	NULL,				NULL,				NULL,				NULL,
+	NULL,				NULL,				"4vhcurveto",		"4hvcurveto"
+};
+
+// --------------------------------------------------------------------
+
+static const char* pT1EscOps[] = {
+	"0dotsection",		"6vstem3",			"6hstem3",			NULL,
+	NULL,				NULL,				"5seac",			"4sbw",
+	NULL,				"1abs",				"2add",				"2sub",
+	"2div",				NULL,				NULL,				NULL,
+	"Gcallothersubr",	"1pop",				NULL,				NULL,
+	NULL,				NULL,				NULL,				NULL,
+	NULL,				NULL,				NULL,				NULL,
+	NULL,				NULL,				NULL,				NULL,
+	NULL,				"2setcurrentpoint"
+};
+
+// --------------------------------------------------------------------
+
+struct TYPE1OP
+{
+	enum OPS
+	{
+		HSTEM=1,		VSTEM=3,		VMOVETO=4,		RLINETO=5,
+		HLINETO=6,		VLINETO=7,		RCURVETO=8,		CLOSEPATH=9,
+		CALLSUBR=10,	RETURN=11,		T1ESC=12,		HSBW=13,
+		ENDCHAR=14,		RMOVETO=21,		HMOVETO=22,		VHCURVETO=30,
+		HVCURVETO=31
+	};
+
+	enum ESCS
+	{
+		DOTSECTION=0,	VSTEM3=1,			HSTEM3=2,	SEAC=6,
+		SBW=7,			ABS=9,				ADD=10,		SUB=11,
+		DIV=12,			CALLOTHERSUBR=16,	POP=17,		SETCURRENTPOINT=33
+	};
+};
+
+// --------------------------------------------------------------------
+
+static const char* pType2Ops[] = {
+	NULL,			"hhstem",		NULL,			"vvstem",
+	"mvmoveto",		"Arlineto",		"Ehlineto",		"Evlineto",
+	"Crrcurveto",	NULL,			"Lcallsubr",	"Xreturn",
+	"xT2ESC",		NULL,			"eendchar",		NULL,
+	NULL,			NULL,			"Hhstemhm",		"Khintmask",
+	"Kcntrmask",	"Mrmoveto",		"mhmoveto",		"Vvstemhm",
+	".rcurveline",	".rlinecurve",	".vvcurveto",	".hhcurveto",
+	".shortint",	"Gcallgsubr",	".vhcurveto",	".hvcurveto"
+};
+
+// --------------------------------------------------------------------
+
+static const char* pT2EscOps[] = {
+	NULL,		NULL,		NULL,		"2and",
+	"2or",		"1not",		NULL,		NULL,
+	NULL,		"1abs",		"2add",		"2sub",
+	"2div",		NULL,		"1neg",		"2eq",
+	NULL,		NULL,		"1drop",	NULL,
+	"1put",		"1get",		"4ifelse",	"0random",
+	"2mul",		NULL,		"1sqrt",	"1dup",
+	"2exch",	"Iindex",	"Rroll",	NULL,
+	NULL,		NULL,		"7hflex",	"Fflex",
+	"9hflex1",	"fflex1"
+};
+
+// --------------------------------------------------------------------
+
+struct TYPE2OP
+{
+	enum OPS
+	{
+		HSTEM=1,		VSTEM=3,		VMOVETO=4,		RLINETO=5,
+		HLINETO=6,		VLINETO=7,		RCURVETO=8,		CALLSUBR=10,
+		RETURN=11,		T2ESC=12,		ENDCHAR=14,		HSTEMHM=18,
+		HINTMASK=19,	CNTRMASK=20,	RMOVETO=21,		HMOVETO=22,
+		VSTEMHM=23,		RCURVELINE=24,	RLINECURVE=25,	VVCURVETO=26,
+		HHCURVETO=27,	SHORTINT=28,	CALLGSUBR=29,	VHCURVETO=30,
+		HVCURVETO=31
+	};
+
+	enum ESCS
+	{
+		AND=3,		OR=4,		NOT=5,		ABS=9,
+		ADD=10,		SUB=11,		DIV=12,		NEG=14,
+		EQ=15,		DROP=18,	PUT=20,		GET=21,
+		IFELSE=22,	RANDOM=23,	MUL=24,		SQRT=26,
+		DUP=27,		EXCH=28,	INDEX=29,	ROLL=30,
+		HFLEX=34,	FLEX=35,	HFLEX1=36,	FLEX1=37
+	};
+};
+
+// ====================================================================
+
+struct CffGlobal
+{
+	explicit CffGlobal();
+
+	int		mnNameIdxBase;
+	int		mnNameIdxCount;
+	int		mnStringIdxBase;
+	int		mnStringIdxCount;
+	bool 	mbCIDFont;
+	int		mnCharStrBase;
+	int		mnCharStrCount;
+	int		mnEncodingBase;
+	int		mnCharsetBase;
+	int		mnGlobalSubrBase;
+	int		mnGlobalSubrCount;
+	int		mnGlobalSubrBias;
+	int		mnFDSelectBase;
+	int		mnFontDictBase;
+	int		mnFDAryCount;
+
+	IntVector	maFontBBox;
+	//FloatVector	maFontMatrix;
+
+	int		mnFontNameSID;
+	int		mnFullNameSID;
+	int		mnFamilyNameSID;
+};
+
+// ====================================================================
+
+struct CffLocal
+{
+	explicit CffLocal();
+
+	int		mnPrivDictBase;
+	int		mnPrivDictSize;
+	int		mnLocalSubrOffs;
+	int		mnLocalSubrBase;
+	int		mnLocalSubrCount;
+	int		mnLocalSubrBias;
+	int		mnNominalWidth;
+	int		mnDefaultWidth;
+
+	// ATM hinting related values
+	int			mnStemStdHW;
+	int			mnStemStdVW;
+	IntVector	maStemSnapH;
+	IntVector	maStemSnapV;
+	IntVector	maBlueValues;
+	IntVector	maOtherBlues;
+	IntVector	maFamilyBlues;
+	IntVector	maFamilyOtherBlues;
+	double		mfBlueScale;
+	double		mfBlueShift;
+	double		mfBlueFuzz;
+	double		mfExpFactor;
+	int			mnLangGroup;
+	bool		mbForceBold;
+};
+
+// ====================================================================
+
+class SubsetterContext
+{
+public:
+	virtual ~SubsetterContext( void);
+	virtual bool emitAsType1( class Type1Emitter&,
+				const long* pGlyphIDs, const U8* pEncoding,
+				GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& ) = 0;
+};
+
+// --------------------------------------------------------------------
+
+SubsetterContext::~SubsetterContext( void)
+{}
+
+// ====================================================================
+
+class CffSubsetterContext
+:	public SubsetterContext
+,	private CffGlobal
+{
+public:
+	static const int NMAXSTACK = 48;	// see CFF.appendixB
+	static const int NMAXHINTS = 2*96;	// see CFF.appendixB
+	static const int NMAXTRANS = 32;	// see CFF.appendixB
+public:
+	explicit CffSubsetterContext( const U8* pBasePtr, int nBaseLen);
+	virtual	~CffSubsetterContext( void);
+
+	void	initialCffRead( void);
+	bool	emitAsType1( class Type1Emitter&,
+				const long* pGlyphIDs, const U8* pEncoding,
+				GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& );
+
+	// used by charstring converter
+	void	setCharStringType( int);
+	void	fakeLocalSubrCount( int nLocalSubrs ) { maCffLocal[0].mnLocalSubrCount=nLocalSubrs;}
+	void	readCharString( const U8* pTypeOps, int nTypeLen);
+protected:
+	int		convert2Type1Ops( CffLocal*, const U8* pType2Ops, int nType2Len, U8* pType1Ops);
+private:
+	void	readTypeOp( CffSubsetterContext&);
+	void	convertOneTypeOp( void);
+	void	convertOneTypeEsc( void);
+	void	callType2Subr( bool bGlobal, int nSubrNumber);
+	long	getReadOfs( void) const { return (long)(mpReadPtr - mpBasePtr);}
+
+	const U8* mpBasePtr;
+	const U8* mpBaseEnd;
+
+	const U8* mpReadPtr;
+	const U8* mpReadEnd;
+
+	U8*		mpWritePtr;
+	bool	mbSawError;
+	bool	mbNeedClose;
+	bool	mbIgnoreHints;
+	long	mnCntrMask;
+
+private:
+	int		seekIndexData( int nIndexBase, int nDataIndex);
+	void	seekIndexEnd( int nIndexBase);
+
+private:
+	const char**	mpCharStringOps;
+	const char**	mpCharStringEscs;
+
+	CffLocal	maCffLocal[16];
+	CffLocal*	mpCffLocal;
+
+	void		readDictOp( void);
+	double		readRealVal( void);
+	const char*	getString( int nStringID);
+	int			getFDSelect( int nGlyphIndex) const;
+	int			getGlyphSID( int nGlyphIndex) const;
+	const char* getGlyphName( int nGlyphIndex);
+
+	void	readTypeOp( void);
+	void	read2push( void);
+	void	pop2write( void);
+	void	writeType1Val( int/*TODO: double*/ nVal);
+	void	writeTypeOp( int nTypeOp);
+	void	writeTypeEsc( int nTypeOp);
+	void	writeCurveTo( int nStackPos, int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3);
+	void	pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor=0);
+	void	popAll2Write( int nTypeOp);
+
+public: // TODO: is public really needed?
+	// accessing the value stack
+	// TODO: add more checks
+	void	push( int nVal) { mnValStack[ mnStackIdx++] = nVal;}
+	int		pop( void) { return ((mnStackIdx>0) ? mnValStack[ --mnStackIdx] : 0);}
+	int		peek( void) { return ((mnStackIdx>0) ? mnValStack[ mnStackIdx-1] : 0);}
+	int		get( int nIndex) { return mnValStack[ nIndex];}
+	int		size( void) const { return mnStackIdx;}
+	bool	empty( void) const { return !mnStackIdx;}
+	void	clear( void) { mnStackIdx = 0;}
+
+	// accessing the charstring hints
+	void	addHints( bool bVerticalHints);
+	int		getHorzHintCount( void) const { return (mnHorzHintSize/2);}
+	int		getVertHintCount( void) const { return (mnHintSize-mnHorzHintSize)/2;}
+	void	getHintPair( int nIndex, int* nMin, int* nEnd) const;
+
+	// accessing other charstring specifics
+	bool	hasCharWidth( void) const { return (mnCharWidth != -1);}
+	int		getCharWidth( void) const { return mnCharWidth;}
+	void	setNominalWidth( int nWidth) { mpCffLocal->mnNominalWidth = nWidth;}
+	void	setDefaultWidth( int nWidth) { mpCffLocal->mnDefaultWidth = nWidth;}
+	void	updateWidth( bool bUseFirstVal);
+
+private:
+	// typeop exceution context
+	int	mnStackIdx;
+	int	mnValStack[ NMAXSTACK];
+	int	mnTransVals[ NMAXTRANS];
+
+	int	mnHintSize;
+	int	mnHorzHintSize;
+	int	mnHintStack[ NMAXHINTS];
+
+	int	mnCharWidth;
+};
+
+// --------------------------------------------------------------------
+
+CffSubsetterContext::CffSubsetterContext( const U8* pBasePtr, int nBaseLen)
+:	mpBasePtr( pBasePtr)
+,	mpBaseEnd( pBasePtr+nBaseLen)
+,	mnStackIdx(0)
+,	mnHintSize(0)
+,	mnHorzHintSize(0)
+,	mnCharWidth(-1)
+{
+//	setCharStringType( 1);
+	// TODO: new CffLocal[ mnFDAryCount];
+	mpCffLocal = &maCffLocal[0];
+}
+
+// --------------------------------------------------------------------
+
+CffSubsetterContext::~CffSubsetterContext( void)
+{
+	// TODO: delete[] maCffLocal;
+}
+
+// --------------------------------------------------------------------
+
+inline void CffSubsetterContext::updateWidth( bool bUseFirstVal)
+{
+#if 1 // TODO: is this still needed?
+	// the first value is not a hint but the charwidth
+	if( hasCharWidth())
+		return;
+#endif
+	if( bUseFirstVal) {
+		mnCharWidth = mpCffLocal->mnNominalWidth + mnValStack[0];
+		// remove bottom stack entry
+		--mnStackIdx;
+		for( int i = 0; i < mnStackIdx; ++i)
+			mnValStack[ i] = mnValStack[ i+1];
+	} else {
+		mnCharWidth = mpCffLocal->mnDefaultWidth;
+	}
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::addHints( bool bVerticalHints)
+{
+	// the first charstring value may a charwidth instead of a charwidth
+	updateWidth( (mnStackIdx & 1) != 0);
+	// return early (e.g. no implicit hints for hintmask)
+	if( !mnStackIdx)
+		return;
+
+	// copy the remaining values to the hint arrays
+	// assert( (mnStackIdx & 1) == 0); // depends on called subrs
+	if( mnStackIdx & 1) --mnStackIdx;//#######
+	// TODO: if( !bSubr) assert( mnStackIdx >= 2);
+
+	assert( (mnHintSize + mnStackIdx) <= 2*NMAXHINTS);
+
+#ifdef IGNORE_HINTS
+	mnHorzHintSize += mnStackIdx;
+#else
+	int nHintOfs = 0;
+	for( int i = 0; i < mnStackIdx; ++i) {
+		nHintOfs += mnValStack[ i];
+		mnHintStack[ mnHintSize++] = nHintOfs;
+	}
+	if( !bVerticalHints)
+		mnHorzHintSize = mnHintSize;
+#endif // IGNORE_HINTS
+
+	// clear all values from the stack
+	mnStackIdx = 0;
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::getHintPair( int nIndex, int* pMin, int* pEnd) const
+{
+	nIndex *= 2;
+	assert( nIndex < mnHintSize);
+	assert( nIndex >= 0);
+	const int* pHint = &mnHintStack[ nIndex];
+	*pMin = pHint[0];
+	*pEnd = pHint[1];
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::setCharStringType( int nVal)
+{
+	switch( nVal) {
+		case 1: mpCharStringOps=pType1Ops; mpCharStringEscs=pT1EscOps; break;
+		case 2: mpCharStringOps=pType2Ops; mpCharStringEscs=pT2EscOps; break;
+		default: fprintf( stderr, "Unknown CharstringType=%d\n",nVal); break;
+	}
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::readCharString( const U8* pTypeOps, int nTypeLen)
+{
+	mnStackIdx = 0;
+	mnHintSize = 0;
+	mnHorzHintSize = 0;
+	mnCharWidth = -1;
+
+	assert( nTypeLen >= 0);
+//	assert( nEnd <= getLength());
+	mpReadPtr = pTypeOps;
+	mpReadEnd = mpReadPtr + nTypeLen;
+	// reset the execution context
+	while( mpReadPtr < mpReadEnd)
+		readTypeOp();
+//###	assert( tellRel() == nEnd);
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::readDictOp( void)
+{
+	int nVal = 0;
+	const U8 c = *mpReadPtr;
+	if( c <= 21 ) {
+		int nOpId = *(mpReadPtr++);
+		const char* pCmdName;
+		if( nOpId != 12)
+			pCmdName = pDictOps[ nOpId];
+		else {
+			const U8 nExtId = *(mpReadPtr++);
+			pCmdName = pDictEscs[ nExtId];
+			nOpId = 900 + nExtId;
+		}
+
+		//TODO: if( nStackIdx > 0)
+		switch( *pCmdName) {
+		default: fprintf( stderr, "unsupported DictOp.type=\'%c\'\n", *pCmdName); break;
+		case 'b':	// bool
+			nVal = pop();
+			switch( nOpId) {
+			case 915: mpCffLocal->mbForceBold = nVal; break;    // "ForceBold"
+			default: break; // TODO: handle more boolean dictops?
+			}
+			break;
+		case 'n':	// dict-op number
+			nVal = pop();
+			switch( nOpId) {
+			case  10: mpCffLocal->mnStemStdHW = nVal;  break; 	// "StdHW"
+			case  11: mpCffLocal->mnStemStdVW = nVal; break; 	// "StdVW"
+			case  15: mnCharsetBase = nVal; break;				// "charset"
+			case  16: mnEncodingBase = nVal; break;				// "nEncoding"
+			case  17: mnCharStrBase = nVal; break;				// "nCharStrings"
+			case  19: mpCffLocal->mnLocalSubrOffs = nVal; break;// "nSubrs"
+			case  20: setDefaultWidth( nVal); break;			// "defaultWidthX"
+			case  21: setNominalWidth( nVal); break;			// "nominalWidthX"
+			case 909: mpCffLocal->mfBlueScale = nVal; break; 	// "BlueScale"
+			case 910: mpCffLocal->mfBlueShift = nVal; break; 	// "BlueShift"
+			case 911: mpCffLocal->mfBlueFuzz = nVal; break; 	// "BlueFuzz"
+			case 912: mpCffLocal->mfExpFactor = nVal; break;	// "ExpansionFactor"
+			case 917: mpCffLocal->mnLangGroup = nVal; break;	// "LanguageGroup"
+			case 936: mnFontDictBase = nVal; break;				// "nFDArray"
+			case 937: mnFDSelectBase = nVal; break;				// "nFDSelect"
+			default: break; // TODO: handle more numeric dictops?
+			}
+			break;
+		case 'a': {	// array
+			for( int i = 0; i < size(); ++i ) {
+				nVal = get(i);
+				switch( nOpId) {
+				case   5: maFontBBox.push_back( nVal); break;     // "FontBBox"
+#if 0 // TODO
+				case 907: maFontMatrix.push_back( nVal); break; // "FontMatrix"
+#endif
+				default: break; // TODO: handle more array dictops?
+				}
+			}
+			clear();
+			} break;
+		case 'd': {	// delta array
+			nVal = 0;
+			for( int i = 0; i < size(); ++i ) {
+				nVal += get(i);
+				switch( nOpId) {
+				case   6: mpCffLocal->maBlueValues.push_back( nVal); break;		// "BlueValues"
+				case   7: mpCffLocal->maOtherBlues.push_back( nVal); break;		// "OtherBlues"
+				case   8: mpCffLocal->maFamilyBlues.push_back( nVal); break;	// "FamilyBlues"
+				case   9: mpCffLocal->maFamilyOtherBlues.push_back( nVal); break;// "FamilyOtherBlues"
+				case 912: mpCffLocal->maStemSnapH.push_back( nVal); break;		// "StemSnapH"
+				case 913: mpCffLocal->maStemSnapV.push_back( nVal); break;		// "StemSnapV"
+				default: break; // TODO: handle more delta-array dictops?
+				}
+			}
+			clear();
+			} break;
+		case 's':	// stringid (SID)
+			nVal = pop();
+			switch( nOpId) {
+			case   2: mnFullNameSID = nVal; break;		// "FullName"
+			case   3: mnFamilyNameSID = nVal; break;	// "FamilyName"
+			case 938: mnFontNameSID = nVal; break;		// "FontName"
+			default: break; // TODO: handle more string dictops?
+			}
+			break;
+		case 'P': 	// private dict
+			mpCffLocal->mnPrivDictBase = pop();
+			mpCffLocal->mnPrivDictSize = pop();
+			break;
+		case 'r': {	// ROS operands
+			int nSid1 = pop();
+			int nSid2 = pop();
+			(void)nSid1; // TODO: use
+			(void)nSid2; // TODO: use
+			nVal = pop();
+			mbCIDFont = true;
+			} break;
+		case 't':	// CharstringType
+			nVal = pop();
+			setCharStringType( nVal);
+			break;
+		}
+
+		return;
+	}
+
+	if( (c >= 32) || (c == 28)) {
+//		--mpReadPtr;
+		read2push();
+	} else if( c == 29) {		// longint
+		++mpReadPtr;			// skip 29
+		int nS32 = mpReadPtr[0] << 24;
+		nS32 += mpReadPtr[1] << 16;
+		nS32 += mpReadPtr[2] << 8;
+		nS32 += mpReadPtr[3] << 0;
+		if( (sizeof(nS32) != 4) && (nS32 & (1<<31)))
+			nS32 |= (~0U) << 31;	// assuming 2s complement
+		mpReadPtr += 4;
+		nVal = nS32;
+		push( nVal);
+	} else if( c == 30) {		// real number
+		++mpReadPtr; // skip 30
+		const double fReal = readRealVal();
+		// push value onto stack
+		nVal = static_cast<int>(fReal+0.5);	//TODO!!! allow float on operand stack!
+		push( nVal);
+	}
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::readTypeOp( void)
+{
+	int nVal = 0;
+	const U8 c = *mpReadPtr;
+	if( (c <= 31) && (c != 28) ) {
+		const int nOpId = *(mpReadPtr++);
+		const char* pCmdName;
+		if( nOpId != 12)
+			pCmdName = mpCharStringOps[ nOpId];
+		else {
+			const int nExtId = *(mpReadPtr++);
+			pCmdName = mpCharStringEscs[ nExtId];
+		}
+
+		if( !pCmdName )
+			pCmdName = ".NULL";
+		// handle typeop parameters
+		int nMinStack = -1, nMaxStack = -1;
+		switch( *pCmdName) {
+		default: fprintf( stderr, "unsupported TypeOp.type=\'%c\'\n", *pCmdName); break;
+		case '.': nMinStack = 0; nMaxStack = 999; break;
+		case '0': nMinStack = nMaxStack = 0; break;
+		case '1': nMinStack = nMaxStack = 1; break;
+		case '2': nMinStack = nMaxStack = 2; break;
+		case '4': nMinStack = nMaxStack = 4; break;
+		case '5': nMinStack = nMaxStack = 5; break;	// not used for Type2 ops
+		case '6': nMinStack = nMaxStack = 6; break;
+		case '7': nMinStack = nMaxStack = 7; break;
+		case '9': nMinStack = nMaxStack = 9; break;
+		case 'f': nMinStack = nMaxStack = 11; break;
+		case 'F': nMinStack = nMaxStack = 13; break;
+		case 'A': nMinStack = 2; nMaxStack = 999; break;	
+		case 'C': nMinStack = 6; nMaxStack = 999; break;
+		case 'E': nMinStack = 1; nMaxStack = 999; break;
+		case 'G': nMinStack = 1; nMaxStack = 999; // global subr
+			nVal = peek();
+			// TODO global subr
+			break;
+		case 'L':	// local subr
+			nMinStack = 1; nMaxStack = 999;
+			nVal = peek();
+			// TODO local subr
+			break;
+		case 'I':	// operands for "index"
+#if 0
+			nMinStack = nValStack[ nStackIdx-1];
+			if( nMinStack < 0) nMinStack = 0;
+			nMinStack += 1;
+#else
+			fprintf( stderr, "TODO: Iindex op\n");
+#endif
+			break;
+		case 'R':	// operands for "rol"
+#if 0
+			nMinStack = nValStack[ nStackIdx-2];
+#else
+			fprintf( stderr, "TODO: Rrol op\n");
+#endif
+		case 'X':	// operands for "return"
+			nMinStack = 0;
+			nMaxStack = /*### (!bInSubrs)? 0 :###*/999;
+			break;
+		case 'H':	// "hstemhm"
+		case 'h':	// "hstem"
+			addHints( false);
+			nMinStack = nMaxStack = 0;
+			break;			
+		case 'V':	// "vstemhm"
+		case 'v':	// "vstem"
+			addHints( true);
+			nMinStack = nMaxStack = 0;
+			break;			
+		case 'K':	// "hintmask" or "cntrmask"
+			addHints( true);	// implicit vstemhm
+			nMinStack = nMaxStack = 0;
+			break;			
+		case 'e':	// endchar
+			updateWidth( (size() >= 1) && (size() != 4));
+			nMinStack = nMaxStack = 0;
+			if( size() == 4)
+				fprintf( stderr,"Deprecated SEAC-like endchar is not supported for CFF subsetting!\n"); // TODO: handle deprecated op
+			break;
+		case 'm':	// hmoveto or vmoveto
+			updateWidth( size() > 1);
+			nMinStack = 1;
+			nMaxStack = nMinStack;
+			break;
+		case 'M':	// rmoveto
+			updateWidth( size() > 2);
+			nMinStack = 2;
+			nMaxStack = nMinStack;
+			break;
+		}
+
+		clear();
+		return;
+	}
+
+	if( (c >= 32) || (c == 28)) {
+//		--mpReadPtr;
+		read2push();
+	}
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::read2push( void)
+{
+	int nVal = 0;
+
+	const U8*& p = mpReadPtr;
+	const U8 c = *p;
+	if( c == 28) {
+		short nS16 = (p[1] << 8) + p[2];
+		if( (sizeof(nS16) != 2) && (nS16 & (1<<15)))
+			nS16 |= (~0U) << 15;	// assuming 2s complement
+		nVal = nS16;
+		p += 3;
+	} else if( c <= 246) {		// -107..+107
+		nVal = p[0] - 139;
+		p += 1;
+	} else if( c <= 250) {		// +108..+1131
+		nVal = ((p[0] << 8) + p[1]) - 63124;
+		p += 2;
+	} else if( c <= 254) {		// -108..-1131
+		nVal = 64148 - ((p[0] << 8) + p[1]);
+		p += 2;
+	} else /*if( c == 255)*/ {	// Fixed16.16
+		nVal = (p[1] << 8) + p[2];
+		// TODO: read non-integer part
+		p += 5;
+	}
+
+	push( nVal);
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::writeType1Val( int/*TODO: double*/ nVal)
+{
+	U8* pOut = mpWritePtr;
+	if( (nVal >= -107) && (nVal <= +107)) {
+		*(pOut++) = static_cast<U8>(nVal + 139);	// -107..+107
+	} else if( (nVal >= -1131) && (nVal <= +1131)) {
+		if( nVal >= 0)
+			nVal += 63124;							// +108..+1131
+		else
+			nVal = 64148 - nVal;					// -108..-1131
+		*(pOut++) = static_cast<U8>(nVal >> 8);
+		*(pOut++) = static_cast<U8>(nVal);
+	} else {
+		// numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
+		*(pOut++) = 255;
+        *(pOut++) = static_cast<U8>(nVal >> 24);
+        *(pOut++) = static_cast<U8>(nVal >> 16);
+        *(pOut++) = static_cast<U8>(nVal >> 8);
+        *(pOut++) = static_cast<U8>(nVal);
+	}
+
+	mpWritePtr = pOut;
+}
+
+// --------------------------------------------------------------------
+
+inline void CffSubsetterContext::pop2write( void)
+{
+	int nVal = pop();
+	writeType1Val( nVal);
+}
+
+// --------------------------------------------------------------------
+
+inline void CffSubsetterContext::writeTypeOp( int nTypeOp)
+{
+	*(mpWritePtr++) = static_cast<U8>(nTypeOp);
+}
+
+// --------------------------------------------------------------------
+
+inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc)
+{
+	*(mpWritePtr++) = TYPE1OP::T1ESC;
+	*(mpWritePtr++) = static_cast<U8>(nTypeEsc);
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor)
+{
+	for( int i = 0; i < mnStackIdx;) {
+		for( int j = 0; j < nArgsPerTypo; ++j) {
+			int nVal = mnValStack[i+j];
+			writeType1Val( nVal);
+		}
+		i += nArgsPerTypo;
+		writeTypeOp( nTypeOp);
+		nTypeOp ^= nTypeXor;	// for toggling vlineto/hlineto
+	}
+	clear();
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::popAll2Write( int nTypeOp)
+{
+	// pop in reverse order, then write
+	for( int i = 0; i < mnStackIdx; ++i) {
+		int nVal = mnValStack[i];
+		writeType1Val( nVal);
+	}
+	clear();
+	writeTypeOp( nTypeOp);
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::writeCurveTo( int nStackPos,
+	int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3)
+{
+	// get the values from the stack
+	const int nDX1 = nIX1 ? mnValStack[ nStackPos+nIX1] : 0;
+	const int nDY1 = nIY1 ? mnValStack[ nStackPos+nIY1] : 0;
+	const int nDX2 = nIX2 ? mnValStack[ nStackPos+nIX2] : 0;
+	const int nDY2 = nIY2 ? mnValStack[ nStackPos+nIY2] : 0;
+	const int nDX3 = nIX3 ? mnValStack[ nStackPos+nIX3] : 0;
+	const int nDY3 = nIY3 ? mnValStack[ nStackPos+nIY3] : 0;
+
+	// emit the curveto operator and operands
+	// TODO: determine the most efficient curveto operator
+	// TODO: depending on type1op or type2op target
+	writeType1Val( nDX1);
+	writeType1Val( nDY1);
+	writeType1Val( nDX2);
+	writeType1Val( nDY2);
+	writeType1Val( nDX3);
+	writeType1Val( nDY3);
+	writeTypeOp( TYPE1OP::RCURVETO);
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::convertOneTypeOp( void)
+{
+	const int nType2Op = *(mpReadPtr++);
+
+	int i, nVal; // prevent WAE for declarations inside switch cases
+	// convert each T2op
+	switch( nType2Op) {
+	case TYPE2OP::T2ESC:
+		convertOneTypeEsc();
+		break;
+	case TYPE2OP::HSTEM:
+	case TYPE2OP::VSTEM:
+		addHints( nType2Op == TYPE2OP::VSTEM);
+#ifndef IGNORE_HINTS
+		for( i = 0; i < mnHintSize; i+=2) {
+			writeType1Val( mnHintStack[i]);
+			writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
+			writeTypeOp( nType2Op);
+		}
+#endif // IGNORE_HINTS
+		break;
+	case TYPE2OP::HSTEMHM:
+	case TYPE2OP::VSTEMHM:
+		addHints( nType2Op == TYPE2OP::VSTEMHM);
+		break;
+	case TYPE2OP::CNTRMASK:
+		// TODO: replace cntrmask with vstem3/hstem3
+		addHints( true);
+#ifdef IGNORE_HINTS
+		mpReadPtr += (mnHintSize + 15) / 16;
+		mbIgnoreHints = true;
+#else
+		{
+		U8 nMaskBit = 0;
+		U8 nMaskByte = 0;
+		for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
+			if( !nMaskBit) {
+				nMaskByte = *(mpReadPtr++);
+				nMaskBit = 0x80;
+			}
+			if( !(nMaskByte & nMaskBit))
+				continue;
+			if( i >= 8*(int)sizeof(mnCntrMask))
+				mbIgnoreHints = true;
+			if( mbIgnoreHints)
+				continue;
+			mnCntrMask |= (1U << i);
+		}
+		}
+#endif
+		break;
+	case TYPE2OP::HINTMASK:
+		addHints( true);
+#ifdef IGNORE_HINTS
+		mpReadPtr += (mnHintSize + 15) / 16;
+#else
+		{
+		long nHintMask = 0;
+		int nCntrBits[2] = {0,0};
+		U8 nMaskBit = 0;
+		U8 nMaskByte = 0;
+		for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
+			if( !nMaskBit) {
+				nMaskByte = *(mpReadPtr++);
+				nMaskBit = 0x80;
+			}
+			if( !(nMaskByte & nMaskBit))
+				continue;
+			if( i >= 8*(int)sizeof(nHintMask))
+				mbIgnoreHints = true;
+			if( mbIgnoreHints)
+				continue;
+			nHintMask |= (1U << i);
+			nCntrBits[ i < mnHorzHintSize] += (mnCntrMask >> i) & 1;
+		}
+
+		mbIgnoreHints |= (nCntrBits[0] && (nCntrBits[0] != 3));
+		mbIgnoreHints |= (nCntrBits[1] && (nCntrBits[1] != 3));
+		if( mbIgnoreHints)
+			break;
+
+		for( i = 0; i < mnHintSize; i+=2) {
+			if( !(nHintMask & (1U << i)))
+				continue;
+			writeType1Val( mnHintStack[i]);
+			writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
+			const bool bHorz = (i < mnHorzHintSize);
+			if( !nCntrBits[ bHorz])
+				writeTypeOp( bHorz ? TYPE1OP::HSTEM : TYPE1OP::VSTEM);
+			else if( !--nCntrBits[ bHorz])
+				writeTypeEsc( bHorz ? TYPE1OP::HSTEM3 : TYPE1OP::VSTEM3);
+		}
+		}
+#endif
+		break;
+	case TYPE2OP::CALLSUBR:
+	case TYPE2OP::CALLGSUBR:
+		{
+		nVal = pop();
+		const bool bGlobal = (nType2Op == TYPE2OP::CALLGSUBR);
+		callType2Subr( bGlobal, nVal);
+		}
+		break;
+	case TYPE2OP::RETURN:
+		// TODO: check that we are in a subroutine
+		return;
+	case TYPE2OP::VMOVETO:
+	case TYPE2OP::HMOVETO:
+		if( mbNeedClose)
+			writeTypeOp( TYPE1OP::CLOSEPATH);
+		else
+			updateWidth( size() > 1);
+		mbNeedClose = true;
+		pop2MultiWrite( 1, nType2Op);
+		break;
+	case TYPE2OP::VLINETO:
+	case TYPE2OP::HLINETO:
+		pop2MultiWrite( 1, nType2Op,
+			TYPE1OP::VLINETO ^ TYPE1OP::HLINETO);
+		break;
+	case TYPE2OP::RMOVETO:
+		// TODO: convert rmoveto to vlineto/hlineto if possible
+		if( mbNeedClose)
+			writeTypeOp( TYPE1OP::CLOSEPATH);
+		else
+			updateWidth( size() > 2);
+		mbNeedClose = true;
+		pop2MultiWrite( 2, nType2Op);
+		break;
+	case TYPE2OP::RLINETO:
+		// TODO: convert rlineto to vlineto/hlineto if possible
+		pop2MultiWrite( 2, nType2Op);
+		break;
+	case TYPE2OP::RCURVETO:
+		// TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
+		pop2MultiWrite( 6, nType2Op);
+		break;
+	case TYPE2OP::RCURVELINE:
+		i = 0;
+		while( (i += 6) <= mnStackIdx)
+			writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
+		i -= 6;
+		while( (i += 2) <= mnStackIdx) {
+			writeType1Val( mnValStack[i-2]);
+			writeType1Val( mnValStack[i-1]);
+			writeTypeOp( TYPE2OP::RLINETO);
+		}
+		clear();
+		break;
+	case TYPE2OP::RLINECURVE:
+		i = 0;
+		while( (i += 2) <= mnStackIdx-6) {
+			writeType1Val( mnValStack[i-2]);
+			writeType1Val( mnValStack[i-1]);
+			writeTypeOp( TYPE2OP::RLINETO);
+		}
+		i -= 2;
+		while( (i += 6) <= mnStackIdx)
+			writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
+		clear();
+		break;
+	case TYPE2OP::VHCURVETO:
+	case TYPE2OP::HVCURVETO:
+		{
+		bool bVert = (nType2Op == TYPE2OP::VHCURVETO);
+		i = 0;
+		nVal = 0;
+		if( mnStackIdx & 1)
+			nVal = mnValStack[ --mnStackIdx];
+		while( (i += 4) <= mnStackIdx) {
+			// TODO: use writeCurveTo()
+			if( bVert) writeType1Val( 0);
+			writeType1Val( mnValStack[i-4]);
+			if( !bVert) writeType1Val( 0);
+			writeType1Val( mnValStack[i-3]);
+			writeType1Val( mnValStack[i-2]);
+			if( !bVert) writeType1Val( (i==mnStackIdx) ? nVal : 0);
+			writeType1Val( mnValStack[i-1]);
+			if( bVert) writeType1Val( (i==mnStackIdx) ? nVal : 0 );
+			bVert = !bVert;
+			writeTypeOp( TYPE2OP::RCURVETO);
+		}
+		}
+		clear();
+		break;
+	case TYPE2OP::HHCURVETO:
+		i = (mnStackIdx & 1);
+		while( (i += 4) <= mnStackIdx) {
+			if( i != 5)
+				writeCurveTo( i, -4,  0, -3, -2, -1, 0);
+			else
+				writeCurveTo( i, -4, -5, -3, -2, -1, 0);
+		}
+		clear();
+		break;
+	case TYPE2OP::VVCURVETO:
+		i = (mnStackIdx & 1);
+		while( (i += 4) <= mnStackIdx) {
+			if( i != 5)
+				writeCurveTo( i,  0, -4, -3, -2, 0, -1);
+			else
+				writeCurveTo( i, -5, -4, -3, -2, 0, -1);
+		}
+		clear();
+		break;
+	case TYPE2OP::ENDCHAR:
+		if( mbNeedClose)
+			writeTypeOp( TYPE1OP::CLOSEPATH);
+		else
+			updateWidth( size() >= 1);
+		// mbNeedClose = true;
+		writeTypeOp( TYPE1OP::ENDCHAR);
+		break;
+	default:
+		if( ((nType2Op >= 32) && (nType2Op <= 255)) || (nType2Op == 28)) {
+			--mpReadPtr;
+			read2push();
+		} else {
+			popAll2Write( nType2Op);
+			assert( false); // TODO?
+		}
+		break;
+	}
+}
+
+// --------------------------------------------------------------------
+
+void CffSubsetterContext::convertOneTypeEsc( void)
+{
+	const int nType2Esc = *(mpReadPtr++);
+	int* pTop = &mnValStack[ mnStackIdx-1];
+	// convert each T2op
+	switch( nType2Esc) {
+	case TYPE2OP::AND:
+		assert( mnStackIdx >= 2);
+		pTop[0] &= pTop[-1];
+		--mnStackIdx;
+		break;
+	case TYPE2OP::OR:
+		assert( mnStackIdx >= 2);
+		pTop[0] |= pTop[-1];
+		--mnStackIdx;
+		break;
+	case TYPE2OP::NOT:
+		assert( mnStackIdx >= 1);
+		pTop[0] = !pTop[0];
+		break;
+	case TYPE2OP::ABS:
+		assert( mnStackIdx >= 1);
+		if( pTop[0] >= 0)
+			break;
+		// fall through