diff options
50 files changed, 31572 insertions, 0 deletions
diff --git a/psprint/inc/psprint/fontmanager.hxx b/psprint/inc/psprint/fontmanager.hxx new file mode 100644 index 000000000000..e454849863fb --- /dev/null +++ b/psprint/inc/psprint/fontmanager.hxx @@ -0,0 +1,513 @@ +/************************************************************************* + * + * $RCSfile: fontmanager.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:33 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _PSPRINT_FONTMANAGER_HXX_ +#define _PSPRINT_FONTMANAGER_HXX_ + +#ifndef __SGI_STL_HASH_MAP +#include <hash_map> +#endif +#ifndef __SGI_STL_LIST +#include <list> +#endif +#ifndef _PSPRINT_HELPER_HXX_ +#include <psprint/helper.hxx> +#endif + +#define ATOM_FAMILYNAME 2 +#define ATOM_PSNAME 3 + +/* + * some words on metrics: every length returned by PrintFontManager and + * friends are PostScript afm style, that is they are 1/1000 font height + */ + +// forward declarations + +namespace utl { class MultiAtomProvider; } // see unotools/atom.hxx + +namespace psp { +class PPDParser; // see ppdparser.hxx + +namespace italic +{ +enum type { + Upright = 0, + Oblique = 1, + Italic = 2, + Unknown = 3 +}; +} + +namespace width +{ +enum type { + Unknown = 0, + UltraCondensed = 1, + ExtraCondensed = 2, + Condensed = 3, + SemiCondensed = 4, + Normal = 5, + SemiExpanded = 6, + Expanded = 7, + ExtraExpanded = 8, + UltraExpanded = 9 +}; +} + +namespace pitch +{ +enum type { + Unknown = 0, + Fixed = 1, + Variable = 2 +}; +} + +namespace weight +{ +enum type { + Unknown = 0, + Thin = 1, + UltraLight = 2, + Light = 3, + SemiLight = 4, + Normal = 5, + Medium = 6, + SemiBold = 7, + Bold = 8, + UltraBold = 9, + Black = 10 +}; +} + +namespace family +{ +enum type { + Unknown = 0, + Decorative = 1, + Modern = 2, + Roman = 3, + Script = 4, + Swiss = 5, + System = 6 +}; +} + +namespace fonttype +{ +enum type { + Unknown = 0, + Type1 = 1, + TrueType = 2, + Builtin = 3 +}; +} + +/* + * the difference between FastPrintFontInfo and PrintFontInfo + * is that the information in FastPrintFontInfo can usually + * be gathered without openening either the font file or + * an afm metric file. they are gathered from fonts.dir alone. + * if only FastPrintFontInfo is gathered and PrintFontInfo + * on demand and for less fonts, then performance in startup + * increases considerably + */ + +struct FastPrintFontInfo +{ + fontID m_nID; // FontID + fonttype::type m_eType; + + // font attributes + ::rtl::OUString m_aFamilyName; + family::type m_eFamilyStyle; + italic::type m_eItalic; + width::type m_eWidth; + weight::type m_eWeight; + pitch::type m_ePitch; + rtl_TextEncoding m_aEncoding; +}; + +struct PrintFontInfo : public FastPrintFontInfo +{ + int m_nAscend; + int m_nDescend; + int m_nLeading; + int m_nWidth; +}; + +// the values are per thousand of the font size +// note: width, height contain advances, not bounding box +struct CharacterMetric +{ + short int width, height; + + CharacterMetric() : width( 0 ), height( 0 ) {} +}; + +struct KernPair +{ + sal_Unicode first, second; + short int kern_x, kern_y; + + KernPair() : first( 0 ), second( 0 ), kern_x( 0 ), kern_y( 0 ) {} +}; + +// a class to manage printable fonts +// aims are type1 and truetype fonts + +class PrintFontManager +{ + struct PrintFont; + struct TrueTypeFontFile; + struct Type1FontFile; + struct BuiltinFont; + friend class PrintFont; + friend class TrueTypeFontFile; + friend class Type1FontFile; + friend class BuiltinFont; + + struct PrintFontMetrics + { + // character metrics are stored by the following keys: + // lower two bytes contain a sal_Unicode (a UCS2 character) + // upper byte contains: 0 for horizontal metric + // 1 for vertical metric + // highest byte: 0 for now + ::std::hash_map< int, CharacterMetric > m_aMetrics; + // contains the unicode blocks for which metrics were queried + // this implies that metrics should be queried in terms of + // unicode blocks. here a unicode block is identified + // by the upper byte of the UCS2 encoding. + // note that the corresponding bit should be set even + // if the font does not support a single character of that page + // this map shows, which pages were queried already + // if (like in AFM metrics) all metrics are queried in + // a single pass, then all bits should be set + char m_aPages[32]; + + bool m_bKernPairsQueried; + ::std::list< KernPair > m_aXKernPairs; + ::std::list< KernPair > m_aYKernPairs; + + PrintFontMetrics() : m_bKernPairsQueried( false ) {} + }; + + struct PrintFont + { + fonttype::type m_eType; + + // font attributes + int m_nFamilyName; // atom + int m_nPSName; // atom + italic::type m_eItalic; + width::type m_eWidth; + weight::type m_eWeight; + pitch::type m_ePitch; + rtl_TextEncoding m_aEncoding; + CharacterMetric m_aGlobalMetricX; + CharacterMetric m_aGlobalMetricY; + PrintFontMetrics* m_pMetrics; + int m_nAscend; + int m_nDescend; + int m_nLeading; + + PrintFont( fonttype::type eType ); + virtual ~PrintFont(); + virtual bool queryMetricPage( int nPage, ::utl::MultiAtomProvider* pProvider ) = 0; + + bool readAfmMetrics( const ::rtl::OString& rFileName, ::utl::MultiAtomProvider* pProvider ); + }; + + struct Type1FontFile : public PrintFont + { + int m_nDirectory; // atom containing system dependent path + ::rtl::OString m_aFontFile; // relative to directory + ::rtl::OString m_aMetricFile; // dito + ::rtl::OString m_aXLFD; // mainly for administration, contains the XLFD from fonts.dir + + /* note: m_aFontFile and Metric file are not atoms + because they should be fairly unique */ + + Type1FontFile() : PrintFont( fonttype::Type1 ) {} + virtual ~Type1FontFile(); + virtual bool queryMetricPage( int nPage, ::utl::MultiAtomProvider* pProvider ); + }; + + struct TrueTypeFontFile : public PrintFont + { + int m_nDirectory; // atom containing system dependent path + ::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 + + TrueTypeFontFile() : PrintFont( fonttype::TrueType ) {} + virtual ~TrueTypeFontFile(); + virtual bool queryMetricPage( int nPage, ::utl::MultiAtomProvider* pProvider ); + }; + + struct BuiltinFont : public PrintFont + { + int m_nDirectory; // atom containing system dependent path + ::rtl::OString m_aMetricFile; + + BuiltinFont() : PrintFont( fonttype::Builtin ) {} + virtual ~BuiltinFont(); + virtual bool queryMetricPage( int nPage, ::utl::MultiAtomProvider* pProvider ); + }; + + fontID m_nNextFontID; + ::std::hash_map< fontID, PrintFont* > m_aFonts; + ::std::hash_map< int, family::type > m_aFamilyTypes; + ::std::list< ::rtl::OUString > m_aPrinterDrivers; + ::std::list< ::rtl::OString > m_aFontDirectories; + ::utl::MultiAtomProvider* m_pAtoms; + + ::std::hash_map< ::rtl::OString, int, ::rtl::OStringHash > + m_aDirToAtom; + ::std::hash_map< int, ::rtl::OString > m_aAtomToDir; + int m_nNextDirAtom; + + + ::rtl::OString getAfmFile( PrintFont* pFont ) const; + ::rtl::OString getFontFile( PrintFont* pFont ) const; + + void getFontAttributesFromXLFD( PrintFont* pFont, const ByteString& rXLFD ) const; + + bool analyzeFontFile( int nDirID, const ::rtl::OString& rFileName, bool bReadFile, const ::rtl::OString& rXLFD, ::std::list< PrintFont* >& rNewFonts ) const; + bool analyzeTrueTypeFile( PrintFont* pFont ) const; + // finds the FIRST id for this font file; there may be more + // for TrueType collections + fontID findFontFileID( int nDirID, const ::rtl::OString& rFile ) const; + fontID findFontBuiltinID( int nPSNameAtom ) const; + + family::type matchFamilyName( const ::rtl::OUString& rFamily ) const; + + PrintFont* getFont( fontID nID ) const + { + ::std::hash_map< int, PrintFont* >::const_iterator it; + it = m_aFonts.find( nID ); + return it == m_aFonts.end() ? NULL : it->second; + } + ByteString getXLFD( PrintFont* pFont ) const; + void fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const; + void fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const; + + const ::rtl::OString& getDirectory( int nAtom ) const; + int getDirectoryAtom( const ::rtl::OString& rDirectory, bool bCreate = false ); + + PrintFontManager(); + ~PrintFontManager(); +public: + static PrintFontManager& get(); // one instance only + + int addFontFile( const ::rtl::OString& rFileName, int nFaceNum ); + + // initialize takes an X Display* + // if NULL then an XOpendDisplay( NULL ) is performed + // the Display connection is used to get the font path + void initialize( void* pDisplay = NULL ); + + // returns the number of managed fonts + int getFontCount() const { return m_aFonts.size(); } + // returns the ids of all managed fonts. on pParser != NULL + // all fonttype::Builtin type fonts are not listed + // which do not occur in the PPD of pParser + void getFontList( ::std::list< fontID >& rFontIDs, const PPDParser* pParser = NULL ) const; + // get the font list and detailed font info. see getFontList for pParser + void getFontListWithInfo( ::std::list< PrintFontInfo >& rFonts, const PPDParser* pParser = NULL ) const; + // get the font list and fast font info. see getFontList for pParser + void getFontListWithFastInfo( ::std::list< FastPrintFontInfo >& rFonts, const PPDParser* pParser = NULL ) const; + + // get font info for a specific font + bool getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const; + // get fast font info for a specific font + bool getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const; + + // routines to get font info in small pieces + + // get a specific fonts family name + const ::rtl::OUString& getFontFamily( fontID nFontID ) const; + // get a specific fonts PSName name + const ::rtl::OUString& getPSName( fontID nFontID ) const; + + // get a specific fonts style family + family::type PrintFontManager::getFontFamilyType( fontID nFontID ) const; + + // get a specific fonts type + fonttype::type getFontType( fontID nFontID ) const + { + PrintFont* pFont = getFont( nFontID ); + return pFont ? pFont->m_eType : fonttype::Unknown; + } + + // get a specific fonts italic type + italic::type getFontItalic( fontID nFontID ) const + { + PrintFont* pFont = getFont( nFontID ); + return pFont ? pFont->m_eItalic : italic::Unknown; + } + + // get a specific fonts width type + width::type getFontWidth( fontID nFontID ) const + { + PrintFont* pFont = getFont( nFontID ); + return pFont ? pFont->m_eWidth : width::Unknown; + } + + // get a specific fonts weight type + weight::type getFontWeight( fontID nFontID ) const + { + PrintFont* pFont = getFont( nFontID ); + return pFont ? pFont->m_eWeight : weight::Unknown; + } + + // get a specific fonts pitch type + pitch::type getFontPitch( fontID nFontID ) const + { + PrintFont* pFont = getFont( nFontID ); + return pFont ? pFont->m_ePitch : pitch::Unknown; + } + + // get a specific fonts encoding + rtl_TextEncoding getFontEncoding( fontID nFontID ) const + { + PrintFont* pFont = getFont( nFontID ); + return pFont ? pFont->m_aEncoding : RTL_TEXTENCODING_DONTKNOW; + } + + // get a specific fonts system dependent filename + ::rtl::OString getFontFileSysPath( fontID nFontID ) const + { + return getFontFile( getFont( nFontID ) ); + } + + // get the ttc face number + int getFontFaceNumber( fontID nFontID ) const + { + int nRet = -1; + PrintFont* pFont = getFont( nFontID ); + if( pFont->m_eType == fonttype::TrueType ) + nRet = static_cast< TrueTypeFontFile* >(pFont)->m_nCollectionEntry; + return nRet; + } + + // get a specific fonts global metrics + const CharacterMetric& getGlobalFontMetric( fontID nFontID, bool bHorizontal ) const; + + // get a specific fonts ascend + int getFontAscend( fontID nFontID ) const; + + // get a specific fonts descent + int getFontDescend( fontID nFontID ) const; + + // get a specific fonts leading + int getFontLeading( fontID nFontID ) const; + + // get the XLFD for a font that originated from the X fontpath + // note: this may not be the original line that was in the fonts.dir + // returns a string for every font, but only TrueType and Type1 + // fonts originated from the X font path, so check for the font type + ::rtl::OUString getFontXLFD( fontID nFontID ) const; + + // get a specific fonts metrics + + // get metrics for a sal_Unicode range + // the user is responsible to allocate pArray large enough + bool getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical = false ) const; + // get metrics for an array of sal_Unicode characters + // the user is responsible to allocate pArray large enough + bool getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical = false ) const; + + // to get font substitution transparently use the + // getKernPairs method of PrinterGfx + const ::std::list< KernPair >& getKernPairs( fontID nFontID, bool bVertical = false ) const; + + // font administration functions + + // for importFonts to provide the user feedback + class ImportFontCallback + { + public: + enum FailCondition { NoWritableDirectory, NoAfmMetric, AfmCopyFailed, FontCopyFailed }; + virtual void importFontsFailed( FailCondition eReason ) = 0; + virtual void progress( const ::rtl::OUString& rFile ) = 0; + virtual bool queryOverwriteFile( const ::rtl::OUString& rFile ) = 0; + virtual void importFontFailed( const ::rtl::OUString& rFile, FailCondition ) = 0; + virtual bool isCanceled() = 0; + }; + + // checks wether font import would fail due to no writeable directory + bool checkImportPossible() const; + // expects system paths not UNC paths + // returns the number of fonts successfully imported + int importFonts( const ::std::list< ::rtl::OUString >& rFiles, ImportFontCallback* pCallback = NULL ); + + // check wether changeFontProperties would fail due to not writable fonts.dir + bool checkChangeFontPropertiesPossible( fontID nFont ) const; + // change fonts.dir entry for font + bool changeFontProperties( fontID nFont, const ::rtl::OUString& rXLFD ); +}; + +} // namespace + +#endif // _PSPRINT_FONTMANAGER_HXX_ diff --git a/psprint/inc/psprint/helper.hxx b/psprint/inc/psprint/helper.hxx new file mode 100644 index 000000000000..99b4cd9e58fa --- /dev/null +++ b/psprint/inc/psprint/helper.hxx @@ -0,0 +1,88 @@ +/************************************************************************* + * + * $RCSfile: helper.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:33 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _PSPRINT_HELPER_HXX_ +#define _PSPRINT_HELPER_HXX_ + +#ifndef __SGI_STL_HASH_MAP +#include <hash_map> +#endif +#ifndef _RTL_USTRING_ +#include <rtl/ustring> +#endif + + +// forwards +namespace osl { class File; } + +#ifndef _RTL_USTRING_ +#include <rtl/ustring> +#endif + +namespace psp { +typedef int fontID; + +const ::rtl::OUString& getPrinterPath(); + +bool convertPfbToPfa( ::osl::File& rInFile, ::osl::File& rOutFile ); +} // namespace + +#endif // _PSPRINT_HELPER_HXX_ diff --git a/psprint/inc/psprint/jobdata.hxx b/psprint/inc/psprint/jobdata.hxx new file mode 100644 index 000000000000..8e6b6597e118 --- /dev/null +++ b/psprint/inc/psprint/jobdata.hxx @@ -0,0 +1,116 @@ +/************************************************************************* + * + * $RCSfile: jobdata.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:33 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _PSPRINT_JOBDATA_HXX_ +#define _PSPRINT_JOBDATA_HXX_ + +#ifndef _PSPRINT_PPDPARSER_HXX_ +#include <psprint/ppdparser.hxx> +#endif + +namespace psp { + +namespace orientation { +enum type { + Portrait, + Landscape +}; +} + +struct JobData +{ + int m_nCopies; + int m_nScale; // in percent + int m_nLeftMarginAdjust; + int m_nRightMarginAdjust; + int m_nTopMarginAdjust; + int m_nBottomMarginAdjust; + // user overrides for PPD + int m_nColorDepth; + int m_nPSLevel; // 0: no override, else languaglevel to use + int m_nColorDevice; // 0: no override, -1 grey scale, +1 color + orientation::type m_eOrientation; + ::rtl::OUString m_aPrinterName; + const PPDParser* m_pParser; + PPDContext m_aContext; + + JobData() : + m_nCopies( 1 ), + m_nScale( 100 ), + m_nLeftMarginAdjust( 0 ), + m_nRightMarginAdjust( 0 ), + m_nTopMarginAdjust( 0 ), + m_nBottomMarginAdjust( 0 ), + m_nColorDepth( 24 ), + m_nPSLevel( 0 ), + m_nColorDevice( 0 ), + m_eOrientation( orientation::Portrait ), + m_pParser( NULL ) {} + + // creates a new buffer using new + // it is up to the user to delete it again + bool getStreamBuffer( void*& pData, int& bytes ); + static bool constructFromStreamBuffer( void* pData, int bytes, JobData& rJobData ); +}; + +} // namespace + +#endif // PSPRINT_JOBDATA_HXX diff --git a/psprint/inc/psprint/ppdparser.hxx b/psprint/inc/psprint/ppdparser.hxx new file mode 100644 index 000000000000..bdee073180d5 --- /dev/null +++ b/psprint/inc/psprint/ppdparser.hxx @@ -0,0 +1,336 @@ +/************************************************************************* + * + * $RCSfile: ppdparser.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:33 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ +#ifndef _PSPRINT_PPDPARSER_HXX_ +#define _PSPRINT_PPDPARSER_HXX_ + +#ifndef __SGI_STL_LIST +#include <list> +#endif +#ifndef _PSPRINT_HELPER_HXX_ +#include <psprint/helper.hxx> // hash_map and OUString hash +#endif +#ifndef _STRING_HXX +#include <tools/string.hxx> +#endif +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif + +namespace psp { + +class PPDParser; + +enum PPDValueType { eInvocation, eQuoted, eSymbol, eString, eNo }; + +struct PPDValue +{ + PPDValueType m_eType; + String m_aOption; + String m_aOptionTranslation; + String m_aValue; + String m_aValueTranslation; +}; + +// ---------------------------------------------------------------------- + +/* + * PPDKey - a container for the available options (=values) of a PPD keyword + */ + +class PPDKey +{ + friend class PPDParser; + + String m_aKey; + ::std::hash_map< ::rtl::OUString, PPDValue, ::rtl::OUStringHash > + m_aValues; + const PPDValue* m_pDefaultValue; + bool m_bQueryValue; + PPDValue m_aQueryValue; + +public: + enum UIType { PickOne, PickMany, Boolean }; + enum SetupType { ExitServer, Prolog, DocumentSetup, PageSetup, JCLSetup, AnySetup }; +private: + + bool m_bUIOption; + String m_aUITranslation; + UIType m_eUIType; + int m_nOrderDependency; + SetupType m_eSetupType; +public: + PPDKey( const String& rKey ); + ~PPDKey(); + + PPDValue* insertValue( const String& rOption ); + int countValues() const + { return m_aValues.size(); } + // neither getValue will return the query option + const PPDValue* getValue( int n ) const; + const PPDValue* getValue( const String& rOption ) const; + const PPDValue* getDefaultValue() const { return m_pDefaultValue; } + const PPDValue* getQueryValue() const { return m_bQueryValue ? &m_aQueryValue : NULL; } + + const String& getKey() const { return m_aKey; } + bool isUIKey() const { return m_bUIOption; } + const String& getUITranslation() const { return m_aUITranslation; } + UIType getUIType() const { return m_eUIType; } + SetupType getSetupType() const { return m_eSetupType; } + int getOrderDependency() const { return m_nOrderDependency; } +}; + +// ---------------------------------------------------------------------- + +/* + * PPDParser - parses a PPD file and contains all available keys from it + */ + +class PPDContext; + +class PPDParser +{ + friend class PPDContext; +public: + struct PPDConstraint + { + const PPDKey* m_pKey1; + const PPDValue* m_pOption1; + const PPDKey* m_pKey2; + const PPDValue* m_pOption2; + + PPDConstraint() : m_pKey1( NULL ), m_pOption1( NULL ), m_pKey2( NULL ), m_pOption2( NULL ) {} + }; + + static ::std::list< PPDParser* > aAllParsers; + + ::std::hash_map< ::rtl::OUString, PPDKey*, ::rtl::OUStringHash > + m_aKeys; + ::std::list< PPDConstraint > m_aConstraints; + + // some identifying fields + String m_aPrinterName; + String m_aNickName; + // the full path of the PPD file + String m_aFile; + // some basic attributes + bool m_bColorDevice; + bool m_bType42Capable; + ULONG m_nLanguageLevel; + + + // shortcuts to important keys and their default values + // imageable area + const PPDValue* m_pDefaultImageableArea; + const PPDKey* m_pImageableAreas; + // paper dimensions + const PPDValue* m_pDefaultPaperDimension; + const PPDKey* m_pPaperDimensions; + // paper trays + const PPDValue* m_pDefaultInputSlot; + const PPDKey* m_pInputSlots; + // resolutions + const PPDValue* m_pDefaultResolution; + const PPDKey* m_pResolutions; + // duplex commands + const PPDValue* m_pDefaultDuplexType; + const PPDKey* m_pDuplexTypes; + + // fonts + const PPDKey* m_pFontList; + + PPDParser( const String& rFile ); + ~PPDParser(); + + void parseOrderDependency( const String& rLine ); + void parseOpenUI( const String& rLine ); + void parseConstraint( const String& rLine ); + void parse( ::std::list< String >& rLines ); +public: + static const PPDParser* getParser( String aFile ); + static String getPPDPrinterName( const String& rFile ); + static void freeAll(); + + const String& getFilename() const { return m_aFile; } + + const PPDKey* getKey( int n ) const; + const PPDKey* getKey( const String& rKey ) const; + int getKeys() const { return m_aKeys.size(); } + bool hasKey( const PPDKey* ) const; + + const ::std::list< PPDConstraint >& getConstraints() const { return m_aConstraints; } + + const String& getPrinterName() const + { return m_aPrinterName.Len() ? m_aPrinterName : m_aNickName; } + const String& getNickName() const + { return m_aNickName.Len() ? m_aNickName : m_aPrinterName; } + + bool isColorDevice() const { return m_bColorDevice; } + bool isType42Capable() const { return m_bType42Capable; } + ULONG getLanguageLevel() const { return m_nLanguageLevel; } + + const String& getDefaultPaperDimension() const; + const void getDefaultPaperDimension( int& rWidth, int& rHeight ) const + { getPaperDimension( getDefaultPaperDimension(), rWidth, rHeight ); } + bool getPaperDimension( const String& rPaperName, + int& rWidth, int& rHeight ) const; + // width and height in pt + // returns false if paper not found + int getPaperDimensions() const + { return m_pPaperDimensions ? m_pPaperDimensions->countValues() : 0; } + const String& getPaperDimension( int ) const; + const String& getPaperDimensionCommand( int ) const; + const String& getPaperDimensionCommand( const String & ) const; + + // match the best paper for width and height + const String& matchPaper( int nWidth, int nHeight ) const; + + bool getMargins( const String& rPaperName, + int &rLeft, int& rRight, + int &rUpper, int& rLower ) const; + // values in pt + // returns true if paper found + + // values int pt + + const String& getDefaultInputSlot() const; + int getInputSlots() const + { return m_pInputSlots ? m_pInputSlots->countValues() : 0; } + const String& getSlot( int ) const; + const String& getSlotCommand( int ) const; + const String& getSlotCommand( const String& ) const; + + void getDefaultResolution( int& rXRes, int& rYRes ) const; + int getResolutions() const; + void getResolution( int, int& rXRes, int& rYRes ) const; + const String& getResolutionCommand( int nXRes, int nYRes ) const; + // values in dpi + void getResolutionFromString( const String&, int&, int& ) const; + // helper function + + const String& getDefaultDuplexType() const; + int getDuplexTypes() const + { return m_pDuplexTypes ? m_pDuplexTypes->countValues() : 0; } + const String& getDuplex( int ) const; + const String& getDuplexCommand( int ) const; + const String& getDuplexCommand( const String& ) const; + + int getFonts() const + { return m_pFontList ? m_pFontList->countValues() : 0; } + void getFontAttributes( int, + String& rEncoding, + String& rCharset ) const; + void getFontAttributes( const String&, + String& rEncoding, + String& rCharset ) const; + const String& getFont( int ) const; +}; + +// ---------------------------------------------------------------------- + +/* + * PPDContext - a class to manage user definable states based on the + * contents of a PPDParser. + */ + +class PPDContext +{ + ::std::hash_map< const PPDKey*, const PPDValue* > m_aCurrentValues; + const PPDParser* m_pParser; + + // returns false: check failed, new value is constrained + // true: check succeded, new value can be set + bool checkConstraints( const PPDKey*, const PPDValue*, bool bDoReset ); + bool resetValue( const PPDKey*, bool bDefaultable = false ); +public: + PPDContext( const PPDParser* pParser = NULL ); + PPDContext( const PPDContext& rContext ) { operator=( rContext ); } + PPDContext& operator=( const PPDContext& rContext ); + ~PPDContext(); + + void setParser( const PPDParser* ); + const PPDParser* getParser() const { return m_pParser; } + + const PPDValue* getValue( const PPDKey* ) const; + const PPDValue* setValue( const PPDKey*, const PPDValue*, bool bDontCareForConstraints = false ); + + int countValuesModified() const { return m_aCurrentValues.size(); } + const PPDKey* getModifiedKey( int n ) const; + + // public wrapper for the private method + bool checkConstraints( const PPDKey*, const PPDValue* ); + + void getUnconstrainedValues( const PPDKey*, ::std::list< const PPDValue* >& rValues ); + + // for printer setup + void* getStreamableBuffer( ULONG& rBytes ) const; + void rebuildFromStreamBuffer( void* pBuffer, ULONG nBytes ); + + // convenience + void getResolution( int& rDPIx, int& rDPIy ) const; + + // width, height in points, paper will contain the name of the selected + // paper after the call + void getPageSize( String& rPaper, int& rWidth, int& rHeight ) const; +}; + +} // namespace + +#endif // _PSPRINT_PPDPARSER_HXX_ diff --git a/psprint/inc/psprint/printergfx.hxx b/psprint/inc/psprint/printergfx.hxx new file mode 100644 index 000000000000..286e95be492f --- /dev/null +++ b/psprint/inc/psprint/printergfx.hxx @@ -0,0 +1,408 @@ +/************************************************************************* + * + * $RCSfile: printergfx.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:33 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _PSPRINT_PRINTERGFX_HXX_ +#define _PSPRINT_PRINTERGFX_HXX_ + +#ifndef _PSPRINT_HELPER_HXX_ +#include <psprint/helper.hxx> +#endif +#ifndef _OSL_FILE_HXX_ +#include <osl/file.hxx> +#endif +#ifndef _SV_GEN_HXX +#include <tools/gen.hxx> +#endif +#ifndef __SGI_STL_LIST +#include <list> +#endif +#ifndef __SGI_STL_HASH_MAP +#include <hash_map> +#endif + +namespace psp { + +// forwards +class JobData; + +/* + * lightweight container to handle RGB values + */ + +class PrinterColor +{ +public: + + typedef enum ColorSpace { eInvalid, eRGB }; + +private: + + sal_uInt8 mnRed; + sal_uInt8 mnGreen; + sal_uInt8 mnBlue; + ColorSpace meColorspace; + +public: + + PrinterColor () : + meColorspace(eInvalid) + {} + PrinterColor (sal_uInt16 nRed, sal_uInt16 nGreen, + sal_uInt16 nBlue) : + mnRed (nRed), + mnGreen (nGreen), + mnBlue (nBlue), + meColorspace (eRGB) + {} + PrinterColor (sal_uInt32 nRGB) : + meColorspace (eRGB), + mnBlue ((nRGB & 0x000000ff) ), + mnGreen ((nRGB & 0x0000ff00) >> 8), + mnRed ((nRGB & 0x00ff0000) >> 16) + {} + ~PrinterColor () + {} + + sal_Bool Is () const + { return meColorspace != eInvalid; } + + ColorSpace GetColorSpace () const + { return meColorspace; } + sal_uInt16 GetRed () const + { return mnRed; } + sal_uInt16 GetGreen () const + { return mnGreen; } + sal_uInt16 GetBlue () const + { return mnBlue; } + sal_Bool operator== (const PrinterColor& aColor) const + { + return aColor.Is() && this->Is() + && mnRed == aColor.mnRed + && mnGreen == aColor.mnGreen + && mnBlue == aColor.mnBlue; + } + PrinterColor& operator= (const PrinterColor& aColor) + { + meColorspace = aColor.meColorspace; + mnRed = aColor.mnRed; + mnGreen = aColor.mnGreen; + mnBlue = aColor.mnBlue; + + return *this; + } + + PrinterColor& operator= (sal_uInt32 nRGB) + { + meColorspace = eRGB; + mnBlue = (nRGB & 0x000000ff); + mnGreen = (nRGB & 0x0000ff00) >> 8; + mnRed = (nRGB & 0x00ff0000) >> 16; + + return *this; + } +}; + +/* + * forward declarations + */ + +class GlyphSet; +class PrinterJob; +class PrintFontManager; +class KernPair; +struct CharacterMetric; + +/* + * Bitmap Interface, this has to be filled with your actual bitmap implementation + * sample implementations can be found in: + * psprint/workben/cui/pspdem.cxx + * vcl/unx/source/gdi/salgdi2.cxx + */ + +class PrinterBmp +{ +public: + + virtual ~PrinterBmp () = 0; + virtual sal_uInt32 GetPaletteColor (sal_uInt32 nIdx) const = 0; + virtual sal_uInt32 GetPaletteEntryCount () const = 0; + virtual sal_uInt32 GetPixelRGB (sal_uInt32 nRow, sal_uInt32 nColumn) const = 0; + virtual sal_uInt8 GetPixelGray (sal_uInt32 nRow, sal_uInt32 nColumn) const = 0; + virtual sal_uInt8 GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const = 0; + virtual sal_uInt32 GetWidth () const = 0; + virtual sal_uInt32 GetHeight () const = 0; + virtual sal_uInt32 GetDepth () const = 0; +}; + +/* + * printer raster operations + */ + +class PrinterGfx +{ +private: + + /* common settings */ + + double mfScaleX; + double mfScaleY; + + sal_uInt32 mnDpiX; + sal_uInt32 mnDpiY; + sal_uInt16 mnDepth; + + sal_uInt16 mnPSLevel; + sal_Bool mbColor; + sal_Bool mbUploadPS42Fonts; + + osl::File* mpPageHeader; + osl::File* mpPageBody; + + void TranslateCoordinates (sal_Int32 &rXOut, sal_Int32 &rYOut, + sal_Int32 nXIn, sal_Int32 nYIn ) + { rXOut = nXIn; rYOut = nYIn; } + void TranslateCoordinates (Point& rOut, const Point& rIn) + { rOut = rIn; } + + /* text/font related data, for a type1 font it has to be checked + whether this font has already been downloaded. A TrueType font + will be converted into one or more Type3 fonts, containing glyphs + in no particular order. In addition to the existence of the + glyph in one of the subfonts, the mapping from unicode to the + glyph has to be remembered */ + + std::list< sal_Int32 > maPS1Font; + std::list< GlyphSet > maPS3Font; + + sal_Int32 mnFontID; + sal_Int32 mnFallbackID; + sal_Int32 mnTextHeight; + sal_Int32 mnTextWidth; + sal_Int32 mnTextAngle; + bool mbTextVertical; + rtl::OString maCurrentFont; + PrintFontManager& mrFontMgr; + + /* bitmap drawing implementation */ + + sal_Bool mbCompressBmp; + + void DrawPS1GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea); + void DrawPS2GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea); + void DrawPS2PaletteImage (const PrinterBmp& rBitmap, const Rectangle& rArea); + void DrawPS2TrueColorImage (const PrinterBmp& rBitmap, const Rectangle& rArea); + + /* clip region */ + + std::list< Rectangle > maClipRegion; + sal_Bool JoinVerticalClipRectangles( std::list< Rectangle >::iterator& it, + Point& aOldPoint, sal_Int32& nColumn ); + + /* color settings */ + + sal_Bool mbCurrentColorValid; + PrinterColor maCurrentColor; + + sal_Bool mbCurrentLineWidthValid; + double mfLineWidth; + + PrinterColor maFillColor; + PrinterColor maTextColor; + PrinterColor maLineColor; + + /* font / font substitution */ + const ::std::hash_map< fontID, fontID >* mpFontSubstitutes; + int getCharWidth (sal_Bool b_vert, sal_Unicode n_char, + CharacterMetric *p_bbox); + fontID getCharMetric (fontID p_font[3], sal_Unicode n_char, + CharacterMetric *p_bbox); + fontID getFontSubstitute (); + +public: + + enum pspath_t { moveto = 0, lineto = 1 }; + void PSBinLineTo (const Point& rCurrent, Point& rOld, + sal_Int32& nColumn); + void PSBinMoveTo (const Point& rCurrent, Point& rOld, + sal_Int32& nColumn); + void PSBinStartPath (); + void PSBinEndPath (); + void PSBinCurrentPath (sal_uInt32 nPoints, const Point* pPath); + void PSBinPath (const Point& rCurrent, Point& rOld, + pspath_t eType, sal_Int32& nColumn); + + void PSSetColor (const PrinterColor& rColor); + void PSSetLineWidth (); + + void PSUploadPS1Font (sal_Int32 nFontID); + void PSSetFont (rtl::OString& rName, + rtl_TextEncoding nEncoding = RTL_TEXTENCODING_DONTKNOW); + void PSRotate (sal_Int32 nAngle); + void PSTranslate (const Point& rPoint); + void PSMoveTo (const Point& rPoint); + void PSRMoveTo (sal_Int32 nDx, sal_Int32 nDy = 0); + void PSScale (double fScaleX, double fScaleY); + void PSLineTo(const Point& rPoint ); + void PSPointOp (const Point& rPoint, const sal_Char* pOperator); + void PSHexString (const sal_uChar* pString, sal_Int16 nLen); + void PSDeltaArray (const sal_Int32 *pArray, sal_Int16 nEntries); + void PSShowText (const sal_uChar* pString, + sal_Int16 nGlyphs, sal_Int16 nBytes, + const sal_Int32* pDeltaArray = NULL); + void PSGSave (); + void PSGRestore (); + + void OnEndPage (); + PrintFontManager& GetFontMgr (); + + void drawVerticalizedText (const Point& rPoint, + const sal_Unicode* pStr, + sal_Int16 nLen, + const sal_Int32* pDeltaArray ); + void drawText (const Point& rPoint, + const sal_Unicode* pStr, sal_Int16 nLen, + const sal_Int32* pDeltaArray = NULL); +public: + PrinterGfx(); + ~PrinterGfx(); + sal_Bool Init (PrinterJob &rPrinterSpec); + sal_Bool Init (const JobData& rData); + void Clear(); + + // query depth and size + void GetResolution (sal_Int32 &rDpiX, sal_Int32 &rDpiY) const; + void GetScreenFontResolution (sal_Int32 &rDpiX, sal_Int32 &rDpiY) const; + sal_uInt16 GetBitCount (); + + // clip region + void ResetClipRegion (); + void BeginSetClipRegion (sal_uInt32); + sal_Bool UnionClipRegion (sal_Int32 nX, sal_Int32 nY, + sal_Int32 nDX, sal_Int32 nDY); + void EndSetClipRegion (); + + // set xy color + void SetLineColor (const PrinterColor& rLineColor = PrinterColor()) + { maLineColor = rLineColor; } + void SetFillColor (const PrinterColor& rFillColor = PrinterColor()) + { maFillColor = rFillColor; } + + // drawing primitives + void DrawPixel (const Point& rPoint, const PrinterColor& rPixelColor); + void DrawPixel (const Point& rPoint) + { DrawPixel (rPoint, maLineColor); } + void DrawLine (const Point& rFrom, const Point& rTo); + void DrawRect (const Rectangle& rRectangle); + void DrawPolyLine (sal_uInt32 nPoints, const Point* pPath ); + void DrawPolygon (sal_uInt32 nPoints, const Point* pPath); + void DrawPolyPolygon (sal_uInt32 nPoly, + const sal_uInt32 *pPolygonSize, + const Point** pPolygonList); + + // eps + sal_Bool DrawEPS ( const Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize); + + // image drawing + void DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc, + const PrinterBmp& rBitmap); + void DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc, + const PrinterBmp& rBitmap, + const PrinterBmp& rTransBitmap); + void DrawMask (const Rectangle& rDest, const Rectangle& rSrc, + const PrinterBmp &rBitmap, PrinterColor& rMaskColor); + + // font and text handling + sal_uInt16 SetFont ( + sal_Int32 nFontID, + sal_Int32 nPointHeight, + sal_Int32 nPointWidth, + sal_Int32 nAngle, + bool bVertical + ); + sal_uInt16 SetFallbackFont ( sal_Int32 nFontID ); + sal_Int32 GetFontAngle () const + { return mnTextAngle; } + sal_Int32 GetFontID () const + { return mnFontID; } + sal_Int32 GetFontHeight () const + { return mnTextHeight; } + sal_Int32 GetFontWidth () const + { return mnTextWidth; } + void DrawText (const Point& rPoint, + const sal_Unicode* pStr, sal_Int16 nLen, + const sal_Int32* pDeltaArray = NULL); + void SetTextColor (PrinterColor& rTextColor) + { maTextColor = rTextColor; } + sal_Int32 GetCharWidth (sal_uInt16 nFrom, sal_uInt16 nTo, + long *pWidthArray); + const ::std::list< KernPair >& getKernPairs( bool bVertical = false ) const; + // advanced font handling + sal_Bool GetGlyphBoundRect (sal_Unicode c, Rectangle& rOutRect); + sal_uInt32 GetGlyphOutline (sal_Unicode c, + sal_uInt16 **ppPolySizes, Point **ppPoints, + sal_uInt8 **ppFlags); +}; + +} /* namespace psp */ + + +#endif /* _PSPRINT_PRINTERGFX_HXX_ */ + diff --git a/psprint/inc/psprint/printerinfomanager.hxx b/psprint/inc/psprint/printerinfomanager.hxx new file mode 100644 index 000000000000..2e8d473a3218 --- /dev/null +++ b/psprint/inc/psprint/printerinfomanager.hxx @@ -0,0 +1,211 @@ +/************************************************************************* + * + * $RCSfile: printerinfomanager.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:32 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _PSPRINT_PRINTERINFOMANAGER_HXX_ +#define _PSPRINT_PRINTERINFOMANAGER_HXX_ + +#ifndef __SGI_STL_HASH_MAP +#include <hash_map> +#endif +#ifndef __SGI_STL_LIST +#include <list> +#endif +#ifndef _PSPRINT_HELPER_HXX_ +#include <psprint/helper.hxx> +#endif +#ifndef _PSPRINT_JOBDATA_HXX_ +#include <psprint/jobdata.hxx> +#endif +#ifndef _OSL_FILE_HXX_ +#include <osl/file.hxx> +#endif +#ifndef _PSPRINT_HELPER_HXX_ +#include <psprint/helper.hxx> +#endif + +namespace psp +{ +struct PrinterInfo : JobData +{ + // basename of PPD + ::rtl::OUString m_aDriverName; + // can be the queue + ::rtl::OUString m_aLocation; + // a user defined comment + ::rtl::OUString m_aComment; + // a command line to pipe a PS-file to + ::rtl::OUString m_aCommand; + // a list of special features separated by ',' not used by psprint + // but assigned from the outside (currently only for "fax") + ::rtl::OUString m_aFeatures; + // a mapping of fonts to other fonts. + // this provides a method for the user + // to replace arbitrary fonts by printer builtin fonts + // currently this is only a mapping between font names + // assuming that only adbobe standard encoding fonts are + // built into the printer. in future it may be necessary + // to map to a font name and UCS2 vector which should be mapped + // this vector is currently implicitly given by the adobe + // standard encoding + bool m_bPerformFontSubstitution; + ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash > + m_aFontSubstitutes; + ::std::hash_map< fontID, fontID > + m_aFontSubstitutions; +}; + +class PrinterInfoManager +{ + // needed for checkPrintersChanged: files (not necessarily existant) + // and their last known modification time + struct WatchFile + { + // the file in question + ::rtl::OUString m_aFilePath; + // the last know modification time or 0, if file did not exist + TimeValue m_aModified; + }; + + // internal data to describe a printer + struct Printer + { + // configuration file containing this printer + // empty means a freshly added printer that has to be saved yet + ::rtl::OUString m_aFile; + // group in m_aFile containing the printer + // this must be unique over all configuration files + // it usually should be the printer name + ::rtl::OString m_aGroup; + // wether changes need to be saved + bool m_bModified; + // the corresponding info and job data + PrinterInfo m_aInfo; + }; + + ::std::hash_map< ::rtl::OUString, Printer, ::rtl::OUStringHash > m_aPrinters; + PrinterInfo m_aGlobalDefaults; + ::std::list< WatchFile > m_aWatchFiles; + ::rtl::OUString m_aDefaultPrinter; + ::rtl::OUString m_aSystemPrintCommand; + ::std::list< ::rtl::OUString > m_aSystemPrintQueues; + + PrinterInfoManager(); + ~PrinterInfoManager(); + + void initialize(); + + // fill in font substitutions + // the resulting hash_map maps from source to target font ids + void fillFontSubstitutions( PrinterInfo& rInfo ) const; +public: + + // there can only be one + static PrinterInfoManager& get(); + + // lists the names of all known printers + void listPrinters( ::std::list< ::rtl::OUString >& rList ) const; + + // gets the number of known printers + int countPrinters() const { return m_aPrinters.size(); } + + // gets info about a named printer + const PrinterInfo& getPrinterInfo( const ::rtl::OUString& rPrinter ) const; + + // gets the name of the default printer + const ::rtl::OUString& getDefaultPrinter() const { return m_aDefaultPrinter; } + + // changes the info about a named printer + void changePrinterInfo( const ::rtl::OUString& rPrinter, const PrinterInfo& rNewInfo ); + + // check if the printer configuration has changed + bool checkPrintersChanged(); + + // members for administration (->padmin) + + // add a named printer + // addPrinter fails if a printer with the same name already exists + // or the driver does not exist + bool addPrinter( const ::rtl::OUString& rPrinterName, const ::rtl::OUString& rDriverName ); + + // remove a namend printer + // this fails if the config file belonging to this printer + // is not writeable + bool removePrinter( const ::rtl::OUString& rPrinterName ); + + // save the changes to all printers. this fails if there + // is no writable config file at all + bool writePrinterConfig(); + + // set a new default printer + // fails if the specified printer does not exist + bool setDefaultPrinter( const ::rtl::OUString& rPrinterName ); + + // primarily used internally but also by padmin + // returns the printer queue names + const ::std::list< ::rtl::OUString >& getSystemPrintQueues(); + + // similar but returnse whole commandlines + void getSystemPrintCommands( ::std::list< ::rtl::OUString >& rCommands ); +}; + +} // namespace + +#endif // _PSPRINT_PRINTERINFOMANAGER_HXX_ diff --git a/psprint/inc/psprint/printerjob.hxx b/psprint/inc/psprint/printerjob.hxx new file mode 100644 index 000000000000..9191b5be7dd0 --- /dev/null +++ b/psprint/inc/psprint/printerjob.hxx @@ -0,0 +1,161 @@ +/************************************************************************* + * + * $RCSfile: printerjob.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:33 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _PSPRINT_PRINTERJOB_HXX_ +#define _PSPRINT_PRINTERJOB_HXX_ + +#ifndef __SGI_STL_LIST +#include <list> +#endif +#ifndef _PSPRINT_JOBDATA_HXX_ +#include <psprint/jobdata.hxx> +#endif +#ifndef _OSL_FILE_HXX_ +#include <osl/file.hxx> +#endif +#ifndef _RTL_STRING_HXX_ +#include <rtl/string.hxx> +#endif + +// forward declarations +class SalGraphics; + +namespace psp { + + +class PrinterJob +{ +private: // private data + + rtl::OUString maSpoolDirName; + rtl::OUString maFileName; // empty: spool to command, else spool to named file + + osl::File* mpJobHeader; + osl::File* mpJobTrailer; + + std::list< osl::File* > maPageList; + std::list< osl::File* > maHeaderList; + + JobData m_aLastJobData; + + sal_uInt32 mnResX; + sal_uInt32 mnResY; + + sal_uInt32 mnWidthPt; + sal_uInt32 mnHeightPt; + + sal_uInt32 mnLMarginPt; + sal_uInt32 mnRMarginPt; + sal_uInt32 mnTMarginPt; + sal_uInt32 mnBMarginPt; + + double mfXScale; + double mfYScale; + + sal_Int32 mnErrorCode; + +private: // private methods + + osl::File* CreateSpoolFile (const rtl::OUString& rName, + const rtl::OUString& rExtension); + void InitPaperSize (const JobData& rJobSetup); + + bool writeSetup( osl::File* pFile, const JobData& ); + bool writePageSetup( osl::File* pFile, const JobData& ); + bool writeProlog (osl::File* pFile); + +public: // for usage in PrinterGfx + + void GetResolution (sal_uInt32 &rDpiX, sal_uInt32 &rDpiY) const; + void GetScale (double &rXScale, double &rYScale) const; + sal_uInt16 GetDepth () const; + sal_uInt16 GetPostscriptLevel (const JobData *pJobData = NULL) const; + sal_Bool IsColorPrinter () const; + + osl::File* GetDocumentHeader (); + osl::File* GetDocumentTrailer (); + osl::File* GetCurrentPageHeader (); + osl::File* GetCurrentPageBody (); + + const ::rtl::OUString& GetPrinterName() const { return m_aLastJobData.m_aPrinterName; } + +public: + PrinterJob (); + ~PrinterJob (); + + sal_Bool StartJob (const rtl::OUString& rFileName, + const rtl::OUString& rJobName, + const rtl::OUString& rAppName, + const JobData& rSetupData); + sal_Bool EndJob (); + + sal_Bool AbortJob (); + + SalGraphics* StartPage (const JobData& rJobSetup, sal_Bool bNewJobData); + sal_Bool EndPage (); + + sal_uInt32 GetErrorCode (); +}; + +} /* namespace psp */ + +#endif /* _PSPRINT_PRINTERJOB_HXX_ */ + diff --git a/psprint/inc/psprint/strhelper.hxx b/psprint/inc/psprint/strhelper.hxx new file mode 100644 index 000000000000..b4f9a4523677 --- /dev/null +++ b/psprint/inc/psprint/strhelper.hxx @@ -0,0 +1,101 @@ +/************************************************************************* + * + * $RCSfile: strhelper.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:33 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ +#ifndef _PSPRINT_STRHELPER_HXX_ +#define _PSPRINT_STRHELPER_HXX_ + +#ifndef _STRING_HXX +#include <tools/string.hxx> +#endif + +namespace psp { + +String GetCommandLineToken( int, const String& ); +ByteString GetCommandLineToken( int, const ByteString& ); +// gets one token of a unix command line style string +// doublequote, singlequote and singleleftquote protect their respective +// contents + +int GetCommandLineTokenCount( const String& ); +int GetCommandLineTokenCount( const ByteString& ); +// returns number of tokens (zero if empty or whitespace only) + +String WhitespaceToSpace( const String&, BOOL bProtect = TRUE ); +ByteString WhitespaceToSpace( const ByteString&, BOOL bProtect = TRUE ); +// returns a string with multiple adjacent occurences of whitespace +// converted to a single space. if bProtect is TRUE (nonzero), then +// doublequote, singlequote and singleleftquote protect their respective +// contents + +double StringToDouble( const String& rStr ); +double StringToDouble( const ByteString& rStr ); +// parses the first double in the string; decimal is '.' only + +// fills a character buffer with the string representation of a double +// the buffer has to be long enough (e.g. 128 bytes) +// returns the string len +int getValueOfDouble( char* pBuffer, double f, int nPrecision = 0 ); +// corresponding convenience functions +ByteString DoubleToByteString( double f, int nPrecision = 0 ); +String DoubleToString( double f, int nPrecision = 0 ); + +} // namespace + +#endif // _PSPRINT_STRHELPER_HXX_ diff --git a/psprint/prj/build.lst b/psprint/prj/build.lst new file mode 100644 index 000000000000..f95e2a2600c5 --- /dev/null +++ b/psprint/prj/build.lst @@ -0,0 +1,8 @@ +pp psprint : tools unotools NULL +pp psprint usr1 - all pp_mkout NULL +pp psprint\source\fontsubset nmake - u pp_fontsset NULL +pp psprint\source\printer nmake - u pp_printer NULL +pp psprint\source\fontmanager nmake - u pp_fontmgr NULL +pp psprint\source\helper nmake - u pp_helper NULL +pp psprint\source\printergfx nmake - u pp_printergfx NULL +pp psprint\util nmake - u pp_util pp_fontmgr pp_fontsset pp_helper pp_printer pp_printergfx NULL diff --git a/psprint/prj/d.lst b/psprint/prj/d.lst new file mode 100644 index 000000000000..cfe51cb4419b --- /dev/null +++ b/psprint/prj/d.lst @@ -0,0 +1,12 @@ +mkdir: %_DEST%\inc%_EXT%\psprint + +..\%__SRC%\lib\*.so %_DEST%\lib%_EXT%\*.so + +..\inc\psprint\*.hxx %_DEST%\inc%_EXT%\psprint\*.hxx + +..\%__SRC%\lib\lib*static*.dylib %_DEST%\lib%_EXT%\lib*static*.dylib +..\%__SRC%\misc\*staticdatamembers.cxx %_DEST%\inc%_EXT%\*staticdatamembers.cxx +..\%__SRC%\misc\*staticdatamembers.h* %_DEST%\inc%_EXT%\*staticdatamembers.h* + +dos: sh -c "if test %OS% = MACOSX; then create-bundle %_DEST%\lib%_EXT%\*.dylib; fi" +dos: sh -c "if test %OS% = MACOSX; then create-libstatic-link %_DEST%\lib%_EXT%; fi" diff --git a/psprint/source/fontmanager/adobeenc.tab b/psprint/source/fontmanager/adobeenc.tab new file mode 100644 index 000000000000..d03f92573a45 --- /dev/null +++ b/psprint/source/fontmanager/adobeenc.tab @@ -0,0 +1,658 @@ +/************************************************************************* + * + * $RCSfile: adobeenc.tab,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:34 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +struct AdobeConvEntry +{ + sal_Unicode aUnicode; + sal_uInt8 aAdobecode; + const char* pAdobename; +}; + +static AdobeConvEntry aAdobeStandardNoneCodes[] = +{ + { 0x00A6, 0, "brokenbar" }, + { 0x00A9, 0, "copyright" }, + { 0x00AC, 0, "logicalnot" }, + { 0x00AE, 0, "registered" }, + { 0x00B1, 0, "plusminus" }, + { 0x00B2, 0, "twosuperior" }, + { 0x00B3, 0, "threesuperior" }, + { 0x00B5, 0, "mu" }, + { 0x00B9, 0, "onesuperior" }, + { 0x00BC, 0, "onequarter" }, + { 0x00BD, 0, "onehalf" }, + { 0x00BE, 0, "threequarters" }, + { 0x00C0, 0, "Agrave" }, + { 0x00C1, 0, "Aacute" }, + { 0x00C2, 0, "Acircumflex" }, + { 0x00C3, 0, "Atilde" }, + { 0x00C4, 0, "Adieresis" }, + { 0x00C5, 0, "Aring" }, + { 0x00C7, 0, "Ccedilla" }, + { 0x00C8, 0, "Egrave" }, + { 0x00C9, 0, "Eacute" }, + { 0x00CA, 0, "Ecircumflex" }, + { 0x00CB, 0, "Edieresis" }, + { 0x00CC, 0, "Igrave" }, + { 0x00CD, 0, "Iacute" }, + { 0x00CE, 0, "Icircumflex" }, + { 0x00CF, 0, "Idieresis" }, + { 0x00D0, 0, "Eth" }, + { 0x00D1, 0, "Ntilde" }, + { 0x00D2, 0, "Ograve" }, + { 0x00D3, 0, "Oacute" }, + { 0x00D4, 0, "Ocircumflex" }, + { 0x00D5, 0, "Otilde" }, + { 0x00D6, 0, "Odieresis" }, + { 0x00D7, 0, "multiply" }, + { 0x00D9, 0, "Ugrave" }, + { 0x00DA, 0, "Uacute" }, + { 0x00DB, 0, "Ucircumflex" }, + { 0x00DC, 0, "Udieresis" }, + { 0x00DD, 0, "Yacute" }, + { 0x00DE, 0, "Thorn" }, + { 0x00E0, 0, "agrave" }, + { 0x00E1, 0, "aacute" }, + { 0x00E2, 0, "acircumflex" }, + { 0x00E3, 0, "atilde" }, + { 0x00E4, 0, "adieresis" }, + { 0x00E5, 0, "aring" }, + { 0x00E7, 0, "ccedilla" }, + { 0x00E8, 0, "egrave" }, + { 0x00E9, 0, "eacute" }, + { 0x00EA, 0, "ecircumflex" }, + { 0x00EB, 0, "edieresis" }, + { 0x00EC, 0, "igrave" }, + { 0x00ED, 0, "iacute" }, + { 0x00EE, 0, "icircumflex" }, + { 0x00EF, 0, "idieresis" }, + { 0x00F0, 0, "eth" }, + { 0x00F1, 0, "ntilde" }, + { 0x00F2, 0, "ograve" }, + { 0x00F3, 0, "oacute" }, + { 0x00F4, 0, "ocircumflex" }, + { 0x00F5, 0, "otilde" }, + { 0x00F6, 0, "odieresis" }, + { 0x00F7, 0, "divide" }, + { 0x00F9, 0, "ugrave" }, + { 0x00FA, 0, "uacute" }, + { 0x00FB, 0, "ucircumflex" }, + { 0x00FC, 0, "udieresis" }, + { 0x00FD, 0, "yacute" }, + { 0x00FE, 0, "thorn" }, + { 0x00FF, 0, "ydieresis" } +}; + + +static const AdobeConvEntry aAdobeStandardConvTable[] = +{ + { 0x0020, 0x20, "space" }, + { 0x0021, 0x21, "exclam" }, + { 0x0022, 0x22, "quotedbl" }, + { 0x0023, 0x23, "numbersign" }, + { 0x0024, 0x24, "dollar" }, + { 0x0025, 0x25, "percent" }, + { 0x0026, 0x26, "ampersand" }, + { 0x0027, 0xA9, "quotesingle" }, + { 0x0028, 0x28, "parenleft" }, + { 0x0029, 0x29, "parenright" }, + { 0x002A, 0x2A, "asterisk" }, + { 0x002B, 0x2B, "plus" }, + { 0x002C, 0x2C, "comma" }, + { 0x002D, 0x2D, "hyphen" }, + { 0x002E, 0x2E, "period" }, + { 0x002F, 0x2F, "slash" }, + { 0x0030, 0x30, "zero" }, + { 0x0031, 0x31, "one" }, + { 0x0032, 0x32, "two" }, + { 0x0033, 0x33, "three" }, + { 0x0034, 0x34, "four" }, + { 0x0035, 0x35, "five" }, + { 0x0036, 0x36, "six" }, + { 0x0037, 0x37, "seven" }, + { 0x0038, 0x38, "eight" }, + { 0x0039, 0x39, "nine" }, + { 0x003A, 0x3A, "colon" }, + { 0x003B, 0x3B, "semicolon" }, + { 0x003C, 0x3C, "less" }, + { 0x003D, 0x3D, "equal" }, + { 0x003E, 0x3E, "greater" }, + { 0x003F, 0x3F, "question" }, + { 0x0040, 0x40, "at" }, + { 0x0041, 0x41, "A" }, + { 0x0042, 0x42, "B" }, + { 0x0043, 0x43, "C" }, + { 0x0044, 0x44, "D" }, + { 0x0045, 0x45, "E" }, + { 0x0046, 0x46, "F" }, + { 0x0047, 0x47, "G" }, + { 0x0048, 0x48, "H" }, + { 0x0049, 0x49, "I" }, + { 0x004A, 0x4A, "J" }, + { 0x004B, 0x4B, "K" }, + { 0x004C, 0x4C, "L" }, + { 0x004D, 0x4D, "M" }, + { 0x004E, 0x4E, "N" }, + { 0x004F, 0x4F, "O" }, + { 0x0050, 0x50, "P" }, + { 0x0051, 0x51, "Q" }, + { 0x0052, 0x52, "R" }, + { 0x0053, 0x53, "S" }, + { 0x0054, 0x54, "T" }, + { 0x0055, 0x55, "U" }, + { 0x0056, 0x56, "V" }, + { 0x0057, 0x57, "W" }, + { 0x0058, 0x58, "X" }, + { 0x0059, 0x59, "Y" }, + { 0x005A, 0x5A, "Z" }, + { 0x005B, 0x5B, "bracketleft" }, + { 0x005C, 0x5C, "backslash" }, + { 0x005D, 0x5D, "bracketright" }, + { 0x005E, 0x5E, "asciicircum" }, + { 0x005F, 0x5F, "underscore" }, + { 0x0060, 0xC1, "grave" }, + { 0x0061, 0x61, "a" }, + { 0x0062, 0x62, "b" }, + { 0x0063, 0x63, "c" }, + { 0x0064, 0x64, "d" }, + { 0x0065, 0x65, "e" }, + { 0x0066, 0x66, "f" }, + { 0x0067, 0x67, "g" }, + { 0x0068, 0x68, "h" }, + { 0x0069, 0x69, "i" }, + { 0x006A, 0x6A, "j" }, + { 0x006B, 0x6B, "k" }, + { 0x006C, 0x6C, "l" }, + { 0x006D, 0x6D, "m" }, + { 0x006E, 0x6E, "n" }, + { 0x006F, 0x6F, "o" }, + { 0x0070, 0x70, "p" }, + { 0x0071, 0x71, "q" }, + { 0x0072, 0x72, "r" }, + { 0x0073, 0x73, "s" }, + { 0x0074, 0x74, "t" }, + { 0x0075, 0x75, "u" }, + { 0x0076, 0x76, "v" }, + { 0x0077, 0x77, "w" }, + { 0x0078, 0x78, "x" }, + { 0x0079, 0x79, "y" }, + { 0x007A, 0x7A, "z" }, + { 0x007B, 0x7B, "braceleft" }, + { 0x007C, 0x7C, "bar" }, + { 0x007D, 0x7D, "braceright" }, + { 0x007E, 0x7E, "asciitilde" }, + { 0x00A1, 0xA1, "exclamdown" }, + { 0x00A2, 0xA2, "cent" }, + { 0x00A3, 0xA3, "sterling" }, + { 0x00A4, 0xA8, "currency" }, + { 0x00A5, 0xA5, "yen" }, + { 0x00A7, 0xA7, "section" }, + { 0x00A8, 0xC8, "dieresis" }, + { 0x00AA, 0xE3, "ordfeminine" }, + { 0x00AB, 0xAB, "guillemotleft" }, + { 0x00AF, 0xC5, "macron" }, + { 0x00B4, 0xC2, "acute" }, + { 0x00B6, 0xB6, "paragraph" }, + { 0x00B7, 0xB4, "periodcentered" }, + { 0x00B8, 0xCB, "cedilla" }, + { 0x00BA, 0xEB, "ordmasculine" }, + { 0x00BB, 0xBB, "guillemotright" }, + { 0x00BF, 0xBF, "questiondown" }, + { 0x00C6, 0xE1, "AE" }, + { 0x00D8, 0xE9, "Oslash" }, + { 0x00DF, 0xFB, "germandbls" }, + { 0x00E6, 0xF1, "ae" }, + { 0x00F8, 0xF9, "oslash" }, + { 0x0131, 0xF5, "dotlessi" }, + { 0x0141, 0xE8, "Lslash" }, + { 0x0142, 0xF8, "lslash" }, + { 0x0152, 0xEA, "OE" }, + { 0x0153, 0xFA, "oe" }, + { 0x0192, 0xA6, "florin" }, + { 0x02C6, 0xC3, "circumflex" }, + { 0x02C7, 0xCF, "caron" }, + { 0x02D8, 0xC6, "breve" }, + { 0x02D9, 0xC7, "dotaccent" }, + { 0x02DA, 0xCA, "ring" }, + { 0x02DB, 0xCE, "ogonek" }, + { 0x02DC, 0xC4, "tilde" }, + { 0x02DD, 0xCD, "hungarumlaut" }, + { 0x2013, 0xB1, "endash" }, + { 0x2014, 0xD0, "emdash" }, + { 0x2018, 0x60, "quoteleft" }, + { 0x2019, 0x27, "quoteright" }, + { 0x201A, 0xB8, "quotesinglbase" }, + { 0x201C, 0xAA, "quotedblleft" }, + { 0x201D, 0xBA, "quotedblright" }, + { 0x201E, 0xB9, "quotedblbase" }, + { 0x2020, 0xB2, "dagger" }, + { 0x2021, 0xB3, "daggerdbl" }, + { 0x2022, 0xB7, "bullet" }, + { 0x2026, 0xBC, "ellipsis" }, + { 0x2030, 0xBD, "perthousand" }, + { 0x2039, 0xAC, "guilsinglleft" }, + { 0x203A, 0xAD, "guilsinglright" }, + { 0x2044, 0xA4, "fraction" }, + { 0xFB01, 0xAE, "fi" }, + { 0xFB02, 0xAF, "fl" }, +}; + +static const AdobeConvEntry aAdobeSymbolConvTable[] = +{ + { 0x0020, 0x20, "space" }, + { 0x0021, 0x21, "exclam" }, + { 0x0023, 0x23, "numbersign" }, + { 0x0025, 0x25, "percent" }, + { 0x0026, 0x26, "ampersand" }, + { 0x0028, 0x28, "parenleft" }, + { 0x0029, 0x29, "parenright" }, + { 0x002B, 0x2B, "plus" }, + { 0x002C, 0x2C, "comma" }, + { 0x002E, 0x2E, "period" }, + { 0x002F, 0x2F, "slash" }, + { 0x0030, 0x30, "zero" }, + { 0x0031, 0x31, "one" }, + { 0x0032, 0x32, "two" }, + { 0x0033, 0x33, "three" }, + { 0x0034, 0x34, "four" }, + { 0x0035, 0x35, "five" }, + { 0x0036, 0x36, "six" }, + { 0x0037, 0x37, "seven" }, + { 0x0038, 0x38, "eight" }, + { 0x0039, 0x39, "nine" }, + { 0x003A, 0x3A, "colon" }, + { 0x003B, 0x3B, "semicolon" }, + { 0x003C, 0x3C, "less" }, + { 0x003D, 0x3D, "equal" }, + { 0x003E, 0x3E, "greater" }, + { 0x003F, 0x3F, "question" }, + { 0x005B, 0x5B, "bracketleft" }, + { 0x005D, 0x5D, "bracketright" }, + { 0x005F, 0x5F, "underscore" }, + { 0x007B, 0x7B, "braceleft" }, + { 0x007C, 0x7C, "bar" }, + { 0x007D, 0x7D, "braceright" }, + { 0x00A9, 0xD3, "copyrightserif" }, + { 0x00A9, 0xE3, "copyrightsans" }, + { 0x00AC, 0xD8, "logicalnot" }, + { 0x00AE, 0xD2, "registeredserif" }, + { 0x00AE, 0xE2, "registeredsans" }, + { 0x00B0, 0xB0, "degree" }, + { 0x00B1, 0xB1, "plusminus" }, + { 0x00D7, 0xB4, "multiply" }, + { 0x00F7, 0xB8, "divide" }, + { 0x0192, 0xA6, "florin" }, + { 0x0391, 0x41, "Alpha" }, + { 0x0392, 0x42, "Beta" }, + { 0x0393, 0x47, "Gamma" }, + { 0x0394, 0x44, "Delta" }, + { 0x0395, 0x45, "Epsilon" }, + { 0x0396, 0x5A, "Zeta" }, + { 0x0397, 0x48, "Eta" }, + { 0x0398, 0x51, "Theta" }, + { 0x0399, 0x49, "Iota" }, + { 0x039A, 0x4B, "Kappa" }, + { 0x039B, 0x4C, "Lambda" }, + { 0x039C, 0x4D, "Mu" }, + { 0x039D, 0x4E, "Nu" }, + { 0x039E, 0x58, "Xi" }, + { 0x039F, 0x4F, "Omicron" }, + { 0x03A0, 0x50, "Pi" }, + { 0x03A1, 0x52, "Rho" }, + { 0x03A3, 0x53, "Sigma" }, + { 0x03A4, 0x54, "Tau" }, + { 0x03A5, 0x55, "Upsilon" }, + { 0x03A6, 0x46, "Phi" }, + { 0x03A7, 0x43, "Chi" }, + { 0x03A8, 0x59, "Psi" }, + { 0x03A9, 0x57, "Omega" }, + { 0x03B1, 0x61, "alpha" }, + { 0x03B2, 0x62, "beta" }, + { 0x03B3, 0x67, "gamma" }, + { 0x03B4, 0x64, "delta" }, + { 0x03B5, 0x65, "epsilon" }, + { 0x03B6, 0x7A, "zeta" }, + { 0x03B7, 0x68, "eta" }, + { 0x03B8, 0x71, "theta" }, + { 0x03B9, 0x69, "iota" }, + { 0x03BA, 0x6B, "kappa" }, + { 0x03BB, 0x6C, "lambda" }, + { 0x03BC, 0x6D, "mu" }, + { 0x03BD, 0x6E, "nu" }, + { 0x03BE, 0x78, "xi" }, + { 0x03BF, 0x6F, "omicron" }, + { 0x03C0, 0x70, "pi" }, + { 0x03C1, 0x72, "rho" }, + { 0x03C2, 0x56, "sigma1" }, + { 0x03C3, 0x73, "sigma" }, + { 0x03C4, 0x74, "tau" }, + { 0x03C5, 0x75, "upsilon" }, + { 0x03C6, 0x66, "phi" }, + { 0x03C7, 0x63, "chi" }, + { 0x03C8, 0x79, "psi" }, + { 0x03C9, 0x77, "omega" }, + { 0x03D1, 0x4A, "theta1" }, + { 0x03D2, 0xA1, "Upsilon1" }, + { 0x03D5, 0x6A, "phi1" }, + { 0x03D6, 0x76, "omega1" }, + { 0x2022, 0xB7, "bullet" }, + { 0x2026, 0xBC, "ellipsis" }, + { 0x2032, 0xA2, "minute" }, + { 0x2033, 0xB2, "second" }, + { 0x203E, 0x60, "radicalex" }, + { 0x2044, 0xA4, "fraction" }, + { 0x2111, 0xC1, "Ifraktur" }, + { 0x2118, 0xC3, "weierstrass" }, + { 0x211C, 0xC2, "Rfraktur" }, + { 0x2122, 0xD4, "trademarkserif" }, + { 0x2122, 0xE4, "trademarksans" }, + { 0x2126, 0x57, "Omega" }, + { 0x2135, 0xC0, "aleph" }, + { 0x2190, 0xAC, "arrowleft" }, + { 0x2191, 0xAD, "arrowup" }, + { 0x2192, 0xAE, "arrowright" }, + { 0x2193, 0xAF, "arrowdown" }, + { 0x2194, 0xAB, "arrowboth" }, + { 0x21B5, 0xBF, "carriagereturn" }, + { 0x21D0, 0xDC, "arrowdblleft" }, + { 0x21D1, 0xDD, "arrowdblup" }, + { 0x21D2, 0xDE, "arrowdblright" }, + { 0x21D3, 0xDF, "arrowdbldown" }, + { 0x21D4, 0xDB, "arrowdblboth" }, + { 0x2200, 0x22, "universal" }, + { 0x2202, 0xB6, "partialdiff" }, + { 0x2203, 0x24, "existential" }, + { 0x2205, 0xC6, "emptyset" }, + { 0x2206, 0x44, "Delta" }, + { 0x2207, 0xD1, "gradient" }, + { 0x2208, 0xCE, "element" }, + { 0x2209, 0xCF, "notelement" }, + { 0x220B, 0x27, "suchthat" }, + { 0x220F, 0xD5, "product" }, + { 0x2211, 0xE5, "summation" }, + { 0x2212, 0x2D, "minus" }, + { 0x2215, 0xA4, "fraction" }, + { 0x2217, 0x2A, "asteriskmath" }, + { 0x221A, 0xD6, "radical" }, + { 0x221D, 0xB5, "proportional" }, + { 0x221E, 0xA5, "infinity" }, + { 0x2220, 0xD0, "angle" }, + { 0x2227, 0xD9, "logicaland" }, + { 0x2228, 0xDA, "logicalor" }, + { 0x2229, 0xC7, "intersection" }, + { 0x222A, 0xC8, "union" }, + { 0x222B, 0xF2, "integral" }, + { 0x2234, 0x5C, "therefore" }, + { 0x223C, 0x7E, "similar" }, + { 0x2245, 0x40, "congruent" }, + { 0x2248, 0xBB, "approxequal" }, + { 0x2260, 0xB9, "notequal" }, + { 0x2261, 0xBA, "equivalence" }, + { 0x2264, 0xA3, "lessequal" }, + { 0x2265, 0xB3, "greaterequal" }, + { 0x2282, 0xCC, "propersubset" }, + { 0x2283, 0xC9, "propersuperset" }, + { 0x2284, 0xCB, "notsubset" }, + { 0x2286, 0xCD, "reflexsubset" }, + { 0x2287, 0xCA, "reflexsuperset" }, + { 0x2295, 0xC5, "circleplus" }, + { 0x2297, 0xC4, "circlemultiply" }, + { 0x22A5, 0x5E, "perpendicular" }, + { 0x22C5, 0xD7, "dotmath" }, + { 0x2320, 0xF3, "integraltp" }, + { 0x2321, 0xF5, "integralbt" }, + { 0x2329, 0xE1, "angleleft" }, + { 0x232A, 0xF1, "angleright" }, + { 0x25CA, 0xE0, "lozenge" }, + { 0x2660, 0xAA, "spade" }, + { 0x2663, 0xA7, "club" }, + { 0x2665, 0xA9, "heart" }, + { 0x2666, 0xA8, "diamond" }, +}; + +static const AdobeConvEntry aAdobeDingBatsTable[] = +{ + { 0x2192, 0xD5, "a161" }, + { 0x2194, 0xD6, "a163" }, + { 0x2195, 0xD7, "a164" }, + { 0x2460, 0xAC, "a120" }, + { 0x2461, 0xAD, "a121" }, + { 0x2462, 0xAE, "a122" }, + { 0x2463, 0xAF, "a123" }, + { 0x2464, 0xB0, "a124" }, + { 0x2465, 0xB1, "a125" }, + { 0x2466, 0xB2, "a126" }, + { 0x2467, 0xB3, "a127" }, + { 0x2468, 0xB4, "a128" }, + { 0x2469, 0xB5, "a129" }, + { 0x25A0, 0x6E, "a73" }, + { 0x25B2, 0x73, "a76" }, + { 0x25BC, 0x74, "a77" }, + { 0x25C6, 0x75, "a78" }, + { 0x2605, 0x48, "a35" }, + { 0x260E, 0x25, "a4" }, + { 0x261B, 0x2A, "a11" }, + { 0x261E, 0x2B, "a12" }, + { 0x2660, 0xAB, "a109" }, + { 0x2663, 0xA8, "a112" }, + { 0x2665, 0xAA, "a110" }, + { 0x2666, 0xA9, "a111" }, + { 0x2701, 0x21, "a1" }, + { 0x2702, 0x22, "a2" }, + { 0x2703, 0x23, "a202" }, + { 0x2704, 0x24, "a3" }, + { 0x2706, 0x26, "a5" }, + { 0x2707, 0x27, "a119" }, + { 0x2708, 0x28, "a118" }, + { 0x2709, 0x29, "a117" }, + { 0x270C, 0x2C, "a13" }, + { 0x270D, 0x2D, "a14" }, + { 0x270E, 0x2E, "a15" }, + { 0x270F, 0x2F, "a16" }, + { 0x2710, 0x30, "a105" }, + { 0x2711, 0x31, "a17" }, + { 0x2712, 0x32, "a18" }, + { 0x2713, 0x33, "a19" }, + { 0x2714, 0x34, "a20" }, + { 0x2715, 0x35, "a21" }, + { 0x2716, 0x36, "a22" }, + { 0x2717, 0x37, "a23" }, + { 0x2718, 0x38, "a24" }, + { 0x2719, 0x39, "a25" }, + { 0x271A, 0x3A, "a26" }, + { 0x271B, 0x3B, "a27" }, + { 0x271C, 0x3C, "a28" }, + { 0x271D, 0x3D, "a6" }, + { 0x271E, 0x3E, "a7" }, + { 0x271F, 0x3F, "a8" }, + { 0x2720, 0x40, "a9" }, + { 0x2721, 0x41, "a10" }, + { 0x2722, 0x42, "a29" }, + { 0x2723, 0x43, "a30" }, + { 0x2724, 0x44, "a31" }, + { 0x2725, 0x45, "a32" }, + { 0x2726, 0x46, "a33" }, + { 0x2727, 0x47, "a34" }, + { 0x2729, 0x49, "a36" }, + { 0x272A, 0x4A, "a37" }, + { 0x272B, 0x4B, "a38" }, + { 0x272C, 0x4C, "a39" }, + { 0x272D, 0x4D, "a40" }, + { 0x272E, 0x4E, "a41" }, + { 0x272F, 0x4F, "a42" }, + { 0x2730, 0x50, "a43" }, + { 0x2731, 0x51, "a44" }, + { 0x2732, 0x52, "a45" }, + { 0x2733, 0x53, "a46" }, + { 0x2734, 0x54, "a47" }, + { 0x2735, 0x55, "a48" }, + { 0x2736, 0x56, "a49" }, + { 0x2737, 0x57, "a50" }, + { 0x2738, 0x58, "a51" }, + { 0x2739, 0x59, "a52" }, + { 0x273A, 0x5A, "a53" }, + { 0x273B, 0x5B, "a54" }, + { 0x273C, 0x5C, "a55" }, + { 0x273D, 0x5D, "a56" }, + { 0x273E, 0x5E, "a57" }, + { 0x273F, 0x5F, "a58" }, + { 0x2740, 0x60, "a59" }, + { 0x2741, 0x61, "a60" }, + { 0x2742, 0x62, "a61" }, + { 0x2743, 0x63, "a62" }, + { 0x2744, 0x64, "a63" }, + { 0x2745, 0x65, "a64" }, + { 0x2746, 0x66, "a65" }, + { 0x2747, 0x67, "a66" }, + { 0x2748, 0x68, "a67" }, + { 0x2749, 0x69, "a68" }, + { 0x274A, 0x6A, "a69" }, + { 0x274B, 0x6B, "a70" }, + { 0x274D, 0x6D, "a72" }, + { 0x274F, 0x6F, "a74" }, + { 0x2750, 0x70, "a203" }, + { 0x2751, 0x71, "a75" }, + { 0x2752, 0x72, "a204" }, + { 0x2756, 0x76, "a79" }, + { 0x2758, 0x78, "a82" }, + { 0x2759, 0x79, "a83" }, + { 0x275A, 0x7A, "a84" }, + { 0x275B, 0x7B, "a97" }, + { 0x275C, 0x7C, "a98" }, + { 0x275D, 0x7D, "a99" }, + { 0x275E, 0x7E, "a100" }, + { 0x2761, 0xA1, "a101" }, + { 0x2762, 0xA2, "a102" }, + { 0x2763, 0xA3, "a103" }, + { 0x2764, 0xA4, "a104" }, + { 0x2765, 0xA5, "a105" }, + { 0x2766, 0xA6, "a106" }, + { 0x2767, 0xA7, "a107" }, + { 0x2776, 0xB6, "a130" }, + { 0x2777, 0xB7, "a131" }, + { 0x2778, 0xB8, "a132" }, + { 0x2779, 0xB9, "a133" }, + { 0x277A, 0xBA, "a134" }, + { 0x277B, 0xBB, "a135" }, + { 0x277C, 0xBC, "a136" }, + { 0x277D, 0xBD, "a137" }, + { 0x277E, 0xBE, "a138" }, + { 0x277F, 0xBF, "a139" }, + { 0x2780, 0xC0, "a140" }, + { 0x2781, 0xC1, "a141" }, + { 0x2782, 0xC2, "a142" }, + { 0x2783, 0xC3, "a143" }, + { 0x2784, 0xC4, "a144" }, + { 0x2785, 0xC5, "a145" }, + { 0x2786, 0xC6, "a146" }, + { 0x2787, 0xC7, "a147" }, + { 0x2788, 0xC8, "a148" }, + { 0x2789, 0xC9, "a149" }, + { 0x278A, 0xCA, "a150" }, + { 0x278B, 0xCB, "a151" }, + { 0x278C, 0xCC, "a152" }, + { 0x278D, 0xCD, "a153" }, + { 0x278E, 0xCE, "a154" }, + { 0x278F, 0xCF, "a155" }, + { 0x2790, 0xD0, "a156" }, + { 0x2791, 0xD1, "a157" }, + { 0x2792, 0xD2, "a158" }, + { 0x2793, 0xD3, "a159" }, + { 0x2794, 0xD4, "a160" }, + { 0x2798, 0xD8, "a196" }, + { 0x2799, 0xD9, "a165" }, + { 0x279A, 0xDA, "a192" }, + { 0x279B, 0xDB, "a166" }, + { 0x279C, 0xDC, "a167" }, + { 0x279D, 0xDD, "a168" }, + { 0x279E, 0xDE, "a169" }, + { 0x279F, 0xDF, "a170" }, + { 0x27A0, 0xE0, "a171" }, + { 0x27A1, 0xE1, "a172" }, + { 0x27A2, 0xE2, "a173" }, + { 0x27A3, 0xE3, "a162" }, + { 0x27A4, 0xE4, "a174" }, + { 0x27A5, 0xE5, "a175" }, + { 0x27A6, 0xE6, "a176" }, + { 0x27A7, 0xE7, "a177" }, + { 0x27A8, 0xE8, "a178" }, + { 0x27A9, 0xE9, "a179" }, + { 0x27AA, 0xEA, "a193" }, + { 0x27AB, 0xEB, "a180" }, + { 0x27AC, 0xEC, "a199" }, + { 0x27AD, 0xED, "a181" }, + { 0x27AE, 0xEE, "a200" }, + { 0x27AF, 0xEF, "a182" }, + { 0x27B1, 0xF1, "a201" }, + { 0x27B2, 0xF2, "a183" }, + { 0x27B3, 0xF3, "a184" }, + { 0x27B4, 0xF4, "a197" }, + { 0x27B5, 0xF5, "a185" }, + { 0x27B6, 0xF6, "a194" }, + { 0x27B7, 0xF7, "a198" }, + { 0x27B8, 0xF8, "a186" }, + { 0x27B9, 0xF9, "a195" }, + { 0x27BA, 0xFA, "a187" }, + { 0x27BB, 0xFB, "a188" }, + { 0x27BC, 0xFC, "a189" }, + { 0x27BD, 0xFD, "a190" }, + { 0x27BE, 0xFE, "a191" }, +}; diff --git a/psprint/source/fontmanager/fontmanager.cxx b/psprint/source/fontmanager/fontmanager.cxx new file mode 100644 index 000000000000..a23f70901fd4 --- /dev/null +++ b/psprint/source/fontmanager/fontmanager.cxx @@ -0,0 +1,2435 @@ +/************************************************************************* + * + * $RCSfile: fontmanager.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:35 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define Window XLIB_Window +#include <X11/Xlib.h> +#undef Window +#include <unistd.h> +#include <sys/stat.h> +#include <dirent.h> + +#ifndef _OSL_THREAD_H_ +#include <osl/thread.h> +#endif +#ifndef _UTL_ATOM_HXX_ +#include <unotools/atom.hxx> +#endif +#ifndef _PSPRINT_FONTMANAGER_HXX_ +#include <psprint/fontmanager.hxx> +#endif +#ifndef _URLOBJ_HXX +#include <tools/urlobj.hxx> +#endif +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif +#ifndef _PSPRINT_HELPER_HXX_ +#include <psprint/helper.hxx> +#endif +#ifndef _OSL_FILE_HXX_ +#include <osl/file.hxx> +#endif +#ifndef _PSPRINT_STRHELPER_HXX_ +#include <psprint/strhelper.hxx> +#endif +#ifndef _PSPRINT_PPDPARSER_HXX_ +#include <psprint/ppdparser.hxx> +#endif +#ifndef _RTL_TENCINFO_H +#include <rtl/tencinfo.h> +#endif +#ifndef _TOOLS_DEBUG_HXX +#include <tools/debug.hxx> +#endif +#ifndef _CONFIG_HXX +#include <tools/config.hxx> +#endif + +#include <parseAFM.hxx> +#include <sft.h> + +#ifdef DEBUG +#include <sys/times.h> +#include <stdio.h> +#endif + +#ifdef SOLARIS +#include <alloca.h> +#endif + +#include <adobeenc.tab> // get encoding table for AFM metrics + +#define PRINTER_METRICDIR "fontmetric" + +using namespace utl; +using namespace psp; +using namespace osl; +using namespace rtl; + +/* + * static helpers + */ + +inline sal_uInt16 getUInt16BE( const byte*& pBuffer ) +{ + sal_uInt16 nRet = (sal_uInt16)pBuffer[1] | + (((sal_uInt16)pBuffer[0]) << 8); + pBuffer+=2; + return nRet; +} + +static italic::type parseItalic( const ByteString& rItalic ) +{ + italic::type eItalic = italic::Unknown; + if( rItalic.EqualsIgnoreCaseAscii( "i" ) ) + eItalic = italic::Italic; + else if( rItalic.EqualsIgnoreCaseAscii( "o" ) ) + eItalic = italic::Oblique; + else + eItalic = italic::Upright; + return eItalic; +} + +// ------------------------------------------------------------------------- + +static weight::type parseWeight( const ByteString& rWeight ) +{ + weight::type eWeight = weight::Unknown; + if( rWeight.Search( "bold" ) != STRING_NOTFOUND ) + { + if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi + eWeight = weight::SemiBold; + else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND ) + eWeight = weight::UltraBold; + else + eWeight = weight::Bold; + } + else if( rWeight.Search( "light" ) != STRING_NOTFOUND ) + { + if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi + eWeight = weight::SemiLight; + else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND ) + eWeight = weight::UltraLight; + else + eWeight = weight::Light; + } + else if( rWeight.Search( "black" ) != STRING_NOTFOUND ) + eWeight = weight::Black; + else if( rWeight.Equals( "demi" ) ) + eWeight = weight::SemiBold; + else if( rWeight.Equals( "book" ) || + rWeight.Equals( "semicondensed" ) ) + eWeight = weight::Light; + else if( rWeight.Equals( "medium" ) || rWeight.Equals( "roman" ) ) + eWeight = weight::Medium; + else + eWeight = weight::Normal; + return eWeight; +} + +// ------------------------------------------------------------------------- + +static width::type parseWidth( const ByteString& rWidth ) +{ + width::type eWidth = width::Unknown; + if( rWidth.Equals( "bold" ) || + rWidth.Equals( "semiexpanded" ) ) + eWidth = width::SemiExpanded; + else if( rWidth.Equals( "condensed" ) || + rWidth.Equals( "narrow" ) ) + eWidth = width::Condensed; + else if( rWidth.Equals( "double wide" ) || + rWidth.Equals( "extraexpanded" ) || + rWidth.Equals( "ultraexpanded" ) ) + eWidth = width::UltraExpanded; + else if( rWidth.Equals( "expanded" ) || + rWidth.Equals( "wide" ) ) + eWidth = width::Expanded; + else if( rWidth.Equals( "extracondensed" ) ) + eWidth = width::ExtraCondensed; + else if( rWidth.Equals( "semicondensed" ) ) + eWidth = width::SemiCondensed; + else if( rWidth.Equals( "ultracondensed" ) ) + eWidth = width::UltraCondensed; + else + eWidth = width::Normal; + + return eWidth; +} + +// ------------------------------------------------------------------------- + +/* + * PrintFont implementations + */ +PrintFontManager::PrintFont::PrintFont( fonttype::type eType ) : + m_eType( eType ), + m_nFamilyName( 0 ), + m_nPSName( 0 ), + m_eItalic( italic::Unknown ), + m_eWidth( width::Unknown ), + m_eWeight( weight::Unknown ), + m_ePitch( pitch::Unknown ), + m_aEncoding( RTL_TEXTENCODING_DONTKNOW ), + m_pMetrics( NULL ), + m_nAscend( 0 ), + m_nDescend( 0 ), + m_nLeading( 0 ) +{ +} + +// ------------------------------------------------------------------------- + +PrintFontManager::PrintFont::~PrintFont() +{ + if( m_pMetrics ) + delete m_pMetrics; +} + +// ------------------------------------------------------------------------- + +PrintFontManager::Type1FontFile::~Type1FontFile() +{ +} + +// ------------------------------------------------------------------------- + +PrintFontManager::TrueTypeFontFile::~TrueTypeFontFile() +{ +} + +// ------------------------------------------------------------------------- + +PrintFontManager::BuiltinFont::~BuiltinFont() +{ +} + +// ------------------------------------------------------------------------- + +bool PrintFontManager::Type1FontFile::queryMetricPage( int nPage, MultiAtomProvider* pProvider ) +{ + return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider ); +} + +// ------------------------------------------------------------------------- + +bool PrintFontManager::BuiltinFont::queryMetricPage( int nPage, MultiAtomProvider* pProvider ) +{ + return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider ); +} + +// ------------------------------------------------------------------------- + +bool PrintFontManager::TrueTypeFontFile::queryMetricPage( int nPage, MultiAtomProvider* pProvider ) +{ + bool bSuccess = false; + + ByteString aFile( PrintFontManager::get().getFontFile( this ) ); + + TrueTypeFont* pTTFont = NULL; + + if( OpenTTFont( aFile.GetBuffer(), m_nCollectionEntry < 0 ? 0 : m_nCollectionEntry, &pTTFont ) == SF_OK ) + { + if( ! m_pMetrics ) + { + m_pMetrics = new PrintFontMetrics; + memset (m_pMetrics->m_aPages, 0, sizeof(m_pMetrics->m_aPages)); + } + m_pMetrics->m_aPages[ nPage/8 ] |= (1 << ( nPage & 7 )); + int i; + uint16 table[256]; + + for( i = 0; i < 256; i++ ) + table[ i ] = 256*nPage + i; + + int nCharacters = nPage < 255 ? 256 : 254; + MapString( pTTFont, table, nCharacters, NULL, 0 ); + TTSimpleGlyphMetrics* pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 0 ); + if( pMetrics ) + { + for( i = 0; i < nCharacters; i++ ) + { + if( table[i] ) + { + CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i ]; + rChar.width = pMetrics[ i ].adv; + rChar.height = m_aGlobalMetricX.height; + } + } + + free( pMetrics ); + } + + for( i = 0; i < 256; i++ ) + table[ i ] = 256*nPage + i; + MapString( pTTFont, table, nCharacters, NULL, 1 ); + pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 1 ); + if( pMetrics ) + { + for( i = 0; i < nCharacters; i++ ) + { + if( table[i] ) + { + CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i + ( 1 << 16 ) ]; + rChar.width = m_aGlobalMetricY.width; + rChar.height = pMetrics[ i ].adv; + } + } + free( pMetrics ); + } + + if( ! m_pMetrics->m_bKernPairsQueried ) + { + m_pMetrics->m_bKernPairsQueried = true; + // this is really a hack + // in future MapString/KernGlyphs should be used + // but vcl is not in a state where that could be used + // so currently we get kernpairs by accessing the raw data + struct _TrueTypeFont* pImplTTFont = (struct _TrueTypeFont*)pTTFont; + + if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_MICROSOFT ) + { + // create a glyph -> character mapping + ::std::hash_map< sal_uInt16, sal_Unicode > aGlyphMap; + ::std::hash_map< sal_uInt16, sal_Unicode >::iterator left, right; + for( i = 21; i < 0xfffd; i++ ) + { + sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only + if( nGlyph != 0 ) + aGlyphMap[ nGlyph ] = (sal_Unicode)i; + } + + + KernPair aPair; + for( i = 0; i < pImplTTFont->nkern; i++ ) + { + const byte* pTable = pImplTTFont->kerntables[i]; + + sal_uInt16 nVersion = getUInt16BE( pTable ); + sal_uInt16 nLength = getUInt16BE( pTable ); + sal_uInt16 nCoverage = getUInt16BE( pTable ); + + aPair.kern_x = 0; + aPair.kern_y = 0; + switch( nCoverage >> 8 ) + { + case 0: + { + sal_uInt16 nPairs = getUInt16BE( pTable ); + pTable += 6; + for( int n = 0; n < nPairs; n++ ) + { + sal_uInt16 nLeftGlyph = getUInt16BE( pTable ); + sal_uInt16 nRightGlyph = getUInt16BE( pTable ); + sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable ); + + left = aGlyphMap.find( nLeftGlyph ); + right = aGlyphMap.find( nRightGlyph ); + if( left != aGlyphMap.end() && right != aGlyphMap.end() ) + { + aPair.first = left->second; + aPair.second = right->second; + switch( nCoverage & 1 ) + { + case 1: + aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm; + m_pMetrics->m_aXKernPairs.push_back( aPair ); + break; + case 0: + aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm; + m_pMetrics->m_aYKernPairs.push_back( aPair ); + break; + } + } + } + } + break; + case 2: + + { + const byte* pSubTable = pTable; + sal_uInt16 nRowWidth = getUInt16BE( pTable ); + sal_uInt16 nOfLeft = getUInt16BE( pTable ); + sal_uInt16 nOfRight = getUInt16BE( pTable ); + sal_uInt16 nOfArray = getUInt16BE( pTable ); + const byte* pTmp = pSubTable + nOfLeft; + sal_uInt16 nFirstLeft = getUInt16BE( pTmp ); + sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1; + pTmp = pSubTable + nOfRight; + sal_uInt16 nFirstRight = getUInt16BE( pTmp ); + sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1; + + int nPairs = (int)(nLastLeft-nFirstLeft+1)*(int)(nLastRight-nFirstRight+1); + for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ ) + { + for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ ) + { + sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp ); + switch( nCoverage & 1 ) + { + case 1: + aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm; + m_pMetrics->m_aXKernPairs.push_back( aPair ); + break; + case 0: + aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm; + m_pMetrics->m_aYKernPairs.push_back( aPair ); + break; + } + } + } + } + break; + } + } + } +#ifdef DEBUG + fprintf( stderr, "found %d/%d kern pairs for %s\n", + m_pMetrics->m_aXKernPairs.size(), + m_pMetrics->m_aYKernPairs.size(), + OUStringToOString( pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName ), RTL_TEXTENCODING_MS_1252 ).getStr() ); +#endif + } + + CloseTTFont( pTTFont ); + bSuccess = true; + } + return bSuccess; +} + +// ------------------------------------------------------------------------- + +bool PrintFontManager::PrintFont::readAfmMetrics( const OString& rFileName, MultiAtomProvider* pProvider ) +{ + int i; + FILE* fp = fopen( rFileName.getStr(), "r" ); + if( ! fp ) + return false; + FontInfo* pInfo = NULL; + int nResult = parseFile( fp, &pInfo, P_ALL ); + fclose( fp ); + if( nResult != ok ) + { + if( pInfo ) + freeFontInfo( pInfo ); + return false; + } + + // fill in global info + + // family name (if not already set) + if( ! m_nFamilyName ) + { + OUString aFamily( OStringToOUString( pInfo->gfi->familyName, RTL_TEXTENCODING_ISO_8859_1 ) ); + if( ! aFamily.getLength() ) + aFamily = OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ); + m_nFamilyName = pProvider->getAtom( ATOM_FAMILYNAME, aFamily, sal_True ); + } + + // PSName + OUString aPSName( OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ) ); + m_nPSName = pProvider->getAtom( ATOM_PSNAME, aPSName, sal_True ); + + // italic + if( pInfo->gfi->italicAngle > 0 ) + m_eItalic = italic::Oblique; + else if( pInfo->gfi->italicAngle < 0 ) + m_eItalic = italic::Italic; + else + m_eItalic = italic::Upright; + + // weight + m_eWeight = parseWeight( ByteString( pInfo->gfi->weight ).ToLowerAscii() ); + + // pitch + m_ePitch = pInfo->gfi->isFixedPitch ? pitch::Fixed : pitch::Variable; + + // encoding - only set if unknown + // try to parse the font name and decide wether it might be a + // japanese font. Who invented this PITA ? + int nTokens = aPSName.getTokenCount( '-' ); + if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW && nTokens > 2 && + ( ! aPSName.getToken( nTokens-1, '-' ).compareToAscii( "H" ) || + ! aPSName.getToken( nTokens-1, '-' ).compareToAscii( "V" ) ) + ) + { + static const char* pEncs[] = + { + "EUC", + "RKSJ", + "SJ" + }; + static const rtl_TextEncoding aEncs[] = + { + RTL_TEXTENCODING_EUC_JP, + RTL_TEXTENCODING_SHIFT_JIS, + RTL_TEXTENCODING_JIS_X_0208 + }; + + for( int enc = 0; enc < sizeof( aEncs )/sizeof(aEncs[0]) && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; enc++ ) + for( int i = 1; i < nTokens-1 && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; i++ ) + { + OUString aEncoding( aPSName.getToken( i, '-' ) ); + if( ! aEncoding.compareToAscii( pEncs[enc] ) ) + m_aEncoding = aEncs[ enc ]; + } + + // default is jis + if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW ) + m_aEncoding = RTL_TEXTENCODING_JIS_X_0208; +#ifdef DEBUG + fprintf( stderr, "Encoding %d for %s\n", m_aEncoding, pInfo->gfi->fontName ); +#endif + } + int nAdobeEncoding = 0; + if( pInfo->gfi->encodingScheme ) + { + if( !strcmp( pInfo->gfi->encodingScheme, "AdobeStandardEncoding" ) ) + nAdobeEncoding = 1; + else if( !strcmp( pInfo->gfi->encodingScheme, "Symbol") ) + nAdobeEncoding = 2; + else if( !strcmp( pInfo->gfi->encodingScheme, "FontSpecific") ) + nAdobeEncoding = 3; + + if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW ) + m_aEncoding = nAdobeEncoding == 1 ? + RTL_TEXTENCODING_MS_1252 : RTL_TEXTENCODING_SYMBOL; + } + else if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW ) + m_aEncoding = RTL_TEXTENCODING_MS_1252; + + // ascend + m_nAscend = pInfo->gfi->fontBBox.ury; + + // descend + // descends have opposite sign of our definition + m_nDescend = -pInfo->gfi->fontBBox.lly; + + // fallback to ascender, descender + // interestigly the BBox seems to describe Ascender and Descender better + // as we understand it + if( m_nAscend == 0 ) + m_nAscend = pInfo->gfi->ascender; + if( m_nDescend == 0) + m_nDescend = -pInfo->gfi->descender; + + m_nLeading = m_nAscend + m_nDescend - 1000; + + if( m_pMetrics ) + delete m_pMetrics; + m_pMetrics = new PrintFontMetrics; + // mark all pages as queried + memset( m_pMetrics->m_aPages, 0xff, sizeof( m_pMetrics->m_aPages ) ); + + m_aGlobalMetricX.width = m_aGlobalMetricY.width = + pInfo->gfi->charwidth ? pInfo->gfi->charwidth : pInfo->gfi->fontBBox.urx; + m_aGlobalMetricX.height = m_aGlobalMetricY.height = + pInfo->gfi->capHeight ? pInfo->gfi->capHeight : pInfo->gfi->fontBBox.ury; + + // fill in character metrics + + // first transform the character codes to unicode + // note: this only works with single byte encodings + sal_Unicode* pUnicodes = (sal_Unicode*)alloca( pInfo->numOfChars * sizeof(sal_Unicode)); + CharMetricInfo* pChar = pInfo->cmi; + + for( i = 0; i < pInfo->numOfChars; i++, pChar++ ) + { + if( pChar->code != -1 ) + { + ByteString aTranslate; + if( pChar->code & 0xff000000 ) + aTranslate += (char)(pChar->code >> 24 ); + if( pChar->code & 0xffff0000 ) + aTranslate += (char)((pChar->code & 0x00ff0000) >> 16 ); + if( pChar->code & 0xffffff00 ) + aTranslate += (char)((pChar->code & 0x0000ff00) >> 8 ); + aTranslate += (char)(pChar->code & 0xff); + String aUni( aTranslate, m_aEncoding ); + pUnicodes[i] = *aUni.GetBuffer(); + } + else + pUnicodes[i] = 0; + } + + // now fill in the character metrics + // parseAFM.cxx effectively only supports direction 0 (horizontal) + pChar = pInfo->cmi; + CharacterMetric aMetric; + for( i = 0; i < pInfo->numOfChars; i++, pChar++ ) + { + if( pChar->code == -1 && ! pChar->name ) + continue; + + aMetric.width = pChar->wx ? pChar->wx : pChar->charBBox.urx; + aMetric.height = pChar->wy ? pChar->wy : pChar->charBBox.ury - pChar->charBBox.lly; + if( aMetric.width == 0 && aMetric.height == 0 ) + // guess something for e.g. space + aMetric.width = m_aGlobalMetricX.width/4; + + if( ( nAdobeEncoding == 0 ) || + ( ( nAdobeEncoding == 3 ) && ( m_aEncoding != RTL_TEXTENCODING_SYMBOL ) ) ) + { + if( pChar->code != -1 ) + { + m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric; + } + else if( pChar->name ) + { + for( int n = 0; n < sizeof(aAdobeStandardNoneCodes)/sizeof(aAdobeStandardNoneCodes[0]); n++ ) + { + if( ! strcmp( pChar->name, aAdobeStandardNoneCodes[n].pAdobename ) ) + { + m_pMetrics->m_aMetrics[ aAdobeStandardNoneCodes[n].aUnicode ] = aMetric; + } + } + } + } + else if( nAdobeEncoding == 1 ) + { + if( pChar->code == -1 ) + { + if( pChar->name ) + { + + for( int n = 0; n < sizeof(aAdobeStandardNoneCodes)/sizeof(aAdobeStandardNoneCodes[0]); n++ ) + { + if( ! strcmp( pChar->name, aAdobeStandardNoneCodes[n].pAdobename ) ) + { + m_pMetrics->m_aMetrics[ aAdobeStandardNoneCodes[n].aUnicode ] = aMetric; + } + } + } + } + else + { + for( int n = 0; n < sizeof(aAdobeStandardConvTable)/sizeof(aAdobeStandardConvTable[0]); n++ ) + { + if( pChar->code == aAdobeStandardConvTable[n].aAdobecode ) + { + m_pMetrics->m_aMetrics[ aAdobeStandardConvTable[n].aUnicode ] = aMetric; + break; + } + } + } + } + else if( nAdobeEncoding == 2 ) + { + if( pChar->code == -1 ) + { + if( pChar->name ) + { + for( int n = 0; n < sizeof(aAdobeSymbolConvTable)/sizeof(aAdobeSymbolConvTable[0]); n++ ) + { + if( ! strcmp( pChar->name, aAdobeStandardNoneCodes[n].pAdobename ) ) + { + m_pMetrics->m_aMetrics[ aAdobeStandardNoneCodes[n].aUnicode ] = aMetric; + } + } + } + } + else + { + for( int n = 0; n < sizeof(aAdobeSymbolConvTable)/sizeof(aAdobeSymbolConvTable[0]); n++ ) + { + if( pChar->code == aAdobeSymbolConvTable[n].aAdobecode ) + { + m_pMetrics->m_aMetrics[ aAdobeSymbolConvTable[n].aUnicode ] = aMetric; + break; + } + } + } + } + else if( nAdobeEncoding == 3 ) + { + if( pChar->code != -1 ) + { + sal_Unicode code = 0xf000 + pChar->code; + m_pMetrics->m_aMetrics[ code ] = aMetric; + // maybe should try to find the name in the convtabs ? + } + } + } + + m_pMetrics->m_aXKernPairs.clear(); + m_pMetrics->m_aYKernPairs.clear(); + + // now fill in the kern pairs + // parseAFM.cxx effectively only supports direction 0 (horizontal) + PairKernData* pKern = pInfo->pkd; + KernPair aPair; + for( i = 0; i < pInfo->numOfPairs; i++, pKern++ ) + { + aPair.first = 0; + aPair.second = 0; + // currently we have to find the adobe character names + // in the already parsed character metrics to find + // the corresponding UCS2 code which is a bit dangerous + // since the character names are not required + // in the metric descriptions + pChar = pInfo->cmi; + for( int j = 0; + j < pInfo->numOfChars && ( aPair.first == 0 || aPair.second == 0 ); + j++, pChar++ ) + { + if( pChar->code != -1 ) + { + if( ! strcmp( pKern->name1, pChar->name ? pChar->name : "" ) ) + aPair.first = pUnicodes[ j ]; + if( ! strcmp( pKern->name2, pChar->name ? pChar->name : "" ) ) + aPair.second = pUnicodes[ j ]; + } + } + if( aPair.first && aPair.second ) + { + aPair.kern_x = pKern->xamt; + aPair.kern_y = pKern->yamt; + m_pMetrics->m_aXKernPairs.push_back( aPair ); + } + } + m_pMetrics->m_bKernPairsQueried = true; + + freeFontInfo( pInfo ); + return true; +} + +// ------------------------------------------------------------------------- + +/* + * one instance only + */ +PrintFontManager& PrintFontManager::get() +{ + static PrintFontManager* theManager = NULL; + if( ! theManager ) + { + theManager = new PrintFontManager(); + theManager->initialize(); + } + return *theManager; +} + +// ------------------------------------------------------------------------- + +/* + * the PrintFontManager + */ + +PrintFontManager::PrintFontManager() : + m_pAtoms( new MultiAtomProvider() ), + m_nNextFontID( 1 ), + m_nNextDirAtom( 1 ) +{ +} + +// ------------------------------------------------------------------------- + +PrintFontManager::~PrintFontManager() +{ + for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it ) + delete (*it).second; + delete m_pAtoms; +} + +// ------------------------------------------------------------------------- + +const OString& PrintFontManager::getDirectory( int nAtom ) const +{ + static OString aEmpty; + ::std::hash_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) ); + return it != m_aAtomToDir.end() ? it->second : aEmpty; +} + +// ------------------------------------------------------------------------- + +int PrintFontManager::getDirectoryAtom( const OString& rDirectory, bool bCreate ) +{ + int nAtom = 0; + ::std::hash_map< OString, int, OStringHash >::const_iterator it + ( m_aDirToAtom.find( rDirectory ) ); + if( it != m_aDirToAtom.end() ) + nAtom = it->second; + else if( bCreate ) + { + nAtom = m_nNextDirAtom++; + m_aDirToAtom[ rDirectory ] = nAtom; + m_aAtomToDir[ nAtom ] = rDirectory; + } + return nAtom; +} + +// ------------------------------------------------------------------------- + +int PrintFontManager::addFontFile( const ::rtl::OString& rFileName, int nFaceNum ) +{ + rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); + INetURLObject aPath( OStringToOUString( rFileName, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL ); + OString aName( OUStringToOString( aPath.GetName(), aEncoding ) ); + OString aDir( OUStringToOString( aPath.GetPath(), aEncoding ) ); + + int nDirID = getDirectoryAtom( aDir, true ); + fontID nFontId = findFontFileID( nDirID, aName ); + if( !nFontId ) + { + ::std::list< PrintFont* > aNewFonts; + if( analyzeFontFile( nDirID, aName, false, OString(), aNewFonts ) ) + { + for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin(); + it != aNewFonts.end(); ++it ) + m_aFonts[ nFontId = m_nNextFontID++ ] = *it; + } + } + return nFontId; +} +// ------------------------------------------------------------------------- + +bool PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, bool bReadFile, const OString& rXLFD, ::std::list< PrintFontManager::PrintFont* >& rNewFonts ) const +{ + rNewFonts.clear(); + rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); + + OString aDir( getDirectory( nDirID ) ); + + ByteString aExt( rFontFile.getToken( rFontFile.getTokenCount( '.' )-1, '.' ) ); + if( aExt.EqualsIgnoreCaseAscii( "pfb" ) || aExt.EqualsIgnoreCaseAscii( "pfa" ) ) + { + // check for corresponding afm metric + // first look for an adjacent file + + ByteString aName( rFontFile ); + aName.Erase( aName.Len()-4 ); + aName.Append( ".afm" ); + + ByteString aFilePath( aDir ); + aFilePath.Append( '/' ); + aFilePath.Append( aName ); + + ByteString aAfmFile; + if( access( aFilePath.GetBuffer(), F_OK ) ) + { + // try in subdirectory afm instead + aFilePath = aDir; + aFilePath.Append( "/afm/" ); + aFilePath.Append( aName ); + + if( ! access( aFilePath.GetBuffer(), F_OK ) ) + { + aAfmFile = "afm/"; + aAfmFile += aName; + } + } + else + aAfmFile = aName; + + if( aAfmFile.Len() ) + { + Type1FontFile* pFont = new Type1FontFile(); + pFont->m_nDirectory = nDirID; + + pFont->m_aFontFile = rFontFile; + pFont->m_aMetricFile = aAfmFile; + + if( bReadFile ) + { + if( ! pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms ) ) + { + delete pFont; + pFont = NULL; + } + } + else + getFontAttributesFromXLFD( pFont, rXLFD ); + if( pFont ) + rNewFonts.push_back( pFont ); + } + } + else if( aExt.EqualsIgnoreCaseAscii( "ttf" ) ) + { + TrueTypeFontFile* pFont = new TrueTypeFontFile(); + pFont->m_nDirectory = nDirID; + pFont->m_aFontFile = rFontFile; + pFont->m_nCollectionEntry = -1; + + if( bReadFile ) + { + if( ! analyzeTrueTypeFile( pFont ) ) + { + delete pFont; + pFont = NULL; + } + } + else + getFontAttributesFromXLFD( pFont, rXLFD ); + if( pFont ) + rNewFonts.push_back( pFont ); + } + else if( aExt.EqualsIgnoreCaseAscii( "ttc" ) ) + { + OString aFullPath( aDir ); + aFullPath += "/"; + aFullPath += rFontFile; + + // get number of ttc entries + int nLength = CountTTCFonts( aFullPath.getStr() ); + if( nLength ) + { +#ifdef DEBUG + fprintf( stderr, "%s contains %d fonts\n XLFD=\"%s\"\n", aFullPath.getStr(), nLength, rXLFD.getStr() ); +#endif + for( int i = 0; i < nLength; i++ ) + { + TrueTypeFontFile* pFont = new TrueTypeFontFile(); + pFont->m_nDirectory = nDirID; + pFont->m_aFontFile = rFontFile; + pFont->m_nCollectionEntry = i; + getFontAttributesFromXLFD( pFont, rXLFD ); + if( ! analyzeTrueTypeFile( pFont ) ) + { + delete pFont; + pFont = NULL; + } + else + rNewFonts.push_back( pFont ); + } + } +#ifdef DEBUG + else + fprintf( stderr, "CountTTCFonts( \"%s/%s\" ) failed\n", getDirectory(nDirID).getStr(), rFontFile.getStr() ); +#endif + } + return ! rNewFonts.empty(); +} + +// ------------------------------------------------------------------------- + +fontID PrintFontManager::findFontBuiltinID( int nPSNameAtom ) const +{ + fontID nID = 0; + ::std::hash_map< int, PrintFont* >::const_iterator it; + for( it = m_aFonts.begin(); nID == 0 && it != m_aFonts.end(); ++it ) + { + if( it->second->m_eType == fonttype::Builtin && + it->second->m_nPSName == nPSNameAtom ) + nID = it->first; + } + return nID; +} + +// ------------------------------------------------------------------------- + +fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile ) const +{ + fontID nID = 0; + ::std::hash_map< int, PrintFont* >::const_iterator it; + for( it = m_aFonts.begin(); nID == 0 && it != m_aFonts.end(); ++it ) + { + switch( it->second->m_eType ) + { + case fonttype::Type1: + { + Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second); + if( pFont->m_nDirectory == nDirID && + pFont->m_aFontFile == rFontFile ) + nID = it->first; + } + break; + case fonttype::TrueType: + { + TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second); + if( pFont->m_nDirectory == nDirID && + pFont->m_aFontFile == rFontFile ) + nID = it->first; + } + break; + default: + break; + } + } + return nID; +} + +// ------------------------------------------------------------------------- + +void PrintFontManager::getFontAttributesFromXLFD( PrintFont* pFont, const ByteString& rXLFD ) const +{ + if( rXLFD.GetTokenCount( '-' ) != 15 ) + return; + + ByteString aFamilyXLFD( WhitespaceToSpace( rXLFD.GetToken( 2, '-' ) ) ); + int nTokens = aFamilyXLFD.GetTokenCount( ' ' ); + ByteString aFamilyName; + for( int nToken = 0; nToken < nTokens; nToken++ ) + { + ByteString aToken( aFamilyXLFD.GetToken( nToken, ' ' ) ); + ByteString aNewToken( aToken.GetChar( 0 ) ); + aNewToken.ToUpperAscii(); + aNewToken += aToken.Copy( 1 ); + if( nToken > 0 ) + aFamilyName.Append( ' ' ); + aFamilyName += aNewToken; + } + + pFont->m_nFamilyName = + m_pAtoms->getAtom( ATOM_FAMILYNAME, + String( aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ), + sal_True ); + ByteString aToken; + + // evaluate weight + aToken = rXLFD.GetToken( 3, '-' ).ToLowerAscii(); + pFont->m_eWeight = parseWeight( aToken ); + + // evaluate slant + aToken = rXLFD.GetToken( 4, '-' ); + pFont->m_eItalic = parseItalic( aToken ); + + // evaluate width + aToken = rXLFD.GetToken( 5, '-' ).ToLowerAscii(); + pFont->m_eWidth = parseWidth( aToken ); + + // evaluate pitch + aToken = rXLFD.GetToken( 11, '-' ).ToLowerAscii(); + if( aToken.Equals( "c" ) || aToken.Equals( "m" ) ) + pFont->m_ePitch = pitch::Fixed; + else + pFont->m_ePitch = pitch::Variable; + + // get encoding + aToken = rXLFD.GetToken( 6, '-' ).ToLowerAscii(); + if( aToken.Search( "symbol" ) != STRING_NOTFOUND ) + pFont->m_aEncoding = RTL_TEXTENCODING_SYMBOL; + else + { + aToken =WhitespaceToSpace( rXLFD.GetToken( 14 ) ); + if( aToken.EqualsIgnoreCaseAscii( "symbol" ) ) + pFont->m_aEncoding = RTL_TEXTENCODING_SYMBOL; + else + { + aToken = rXLFD.GetToken( 13, '-' ); + aToken += '-'; + aToken += WhitespaceToSpace( rXLFD.GetToken( 14, '-' ) ); + pFont->m_aEncoding = rtl_getTextEncodingFromUnixCharset( aToken.GetBuffer() ); + } + } + + // handle iso8859-1 as ms1252 to fill the "gap" starting at 0x80 + if( pFont->m_aEncoding == RTL_TEXTENCODING_ISO_8859_1 ) + pFont->m_aEncoding = RTL_TEXTENCODING_MS_1252; + + switch( pFont->m_eType ) + { + case fonttype::Type1: + static_cast<Type1FontFile*>(pFont)->m_aXLFD = rXLFD; + break; + case fonttype::TrueType: + static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD = rXLFD; + break; + } +} + +// ------------------------------------------------------------------------- + +ByteString PrintFontManager::getXLFD( PrintFont* pFont ) const +{ + if( pFont->m_eType == fonttype::Type1 ) + { + if( static_cast<Type1FontFile*>(pFont)->m_aXLFD.getLength() ) + return static_cast<Type1FontFile*>(pFont)->m_aXLFD; + } + if( pFont->m_eType == fonttype::TrueType ) + { + if( static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD.getLength() ) + return static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD; + } + + ByteString aXLFD( "-misc-" ); + aXLFD += ByteString( String( m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ) ), RTL_TEXTENCODING_ISO_8859_1 ); + aXLFD += '-'; + switch( pFont->m_eWeight ) + { + case weight::Thin: aXLFD += "thin";break; + case weight::UltraLight: aXLFD += "ultralight";break; + case weight::Light: aXLFD += "light";break; + case weight::SemiLight: aXLFD += "semilight";break; + case weight::Normal: aXLFD += "normal";break; + case weight::Medium: aXLFD += "medium";break; + case weight::SemiBold: aXLFD += "semibold";break; + case weight::Bold: aXLFD += "bold";break; + case weight::UltraBold: aXLFD += "ultrabold";break; + case weight::Black: aXLFD += "black";break; + } + aXLFD += '-'; + switch( pFont->m_eItalic ) + { + case italic::Upright: aXLFD += 'r';break; + case italic::Oblique: aXLFD += 'o';break; + case italic::Italic: aXLFD += 'i';break; + } + aXLFD += '-'; + switch( pFont->m_eWidth ) + { + case width::UltraCondensed: aXLFD += "ultracondensed";break; + case width::ExtraCondensed: aXLFD += "extracondensed";break; + case width::Condensed: aXLFD += "condensed";break; + case width::SemiCondensed: aXLFD += "semicondensed";break; + case width::Normal: aXLFD += "normal";break; + case width::SemiExpanded: aXLFD += "semiexpanded";break; + case width::Expanded: aXLFD += "expanded";break; + case width::ExtraExpanded: aXLFD += "extraexpanded";break; + case width::UltraExpanded: aXLFD += "ultraexpanded";break; + } + aXLFD += "--0-0-0-0-"; + aXLFD += pFont->m_ePitch == pitch::Fixed ? "m" : "p"; + aXLFD += "-0-"; + aXLFD += rtl_getBestUnixCharsetFromTextEncoding( pFont->m_aEncoding ); + + return aXLFD; +} + +// ------------------------------------------------------------------------- + +bool PrintFontManager::analyzeTrueTypeFile( PrintFont* pFont ) const +{ + bool bSuccess = false; + rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); + ByteString aFile = getFontFile( pFont ); + TrueTypeFont* pTTFont = NULL; + + TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont); + int nFace = pTTFontFile->m_nCollectionEntry; + if( OpenTTFont( aFile.GetBuffer(), nFace < 0 ? 0 : nFace, &pTTFont ) == SF_OK ) + { + TTGlobalFontInfo aInfo; + GetTTGlobalFontInfo( pTTFont, & aInfo ); + + // set family name from XLFD if possible + if( ! pFont->m_nFamilyName ) + { + if( ! aInfo.family || ! *aInfo.family ) + // poor font does not have a family name + // name it to file name minus ".tt{f|c}" + pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, pTTFontFile->m_aFontFile.getLength()-4 ), aEncoding ) ); + else + pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, String( ByteString( aInfo.family ), aEncoding ), sal_True ); + } + + + pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, String( ByteString( aInfo.psname ), aEncoding ), sal_True ); + switch( aInfo.weight ) + { + case FW_THIN: pFont->m_eWeight = weight::Thin; break; + case FW_EXTRALIGHT: pFont->m_eWeight = weight::UltraLight; break; + case FW_LIGHT: pFont->m_eWeight = weight::Light; break; + case FW_MEDIUM: pFont->m_eWeight = weight::Medium; break; + case FW_SEMIBOLD: pFont->m_eWeight = weight::SemiBold; break; + case FW_BOLD: pFont->m_eWeight = weight::Bold; break; + case FW_EXTRABOLD: pFont->m_eWeight = weight::UltraBold; break; + case FW_BLACK: pFont->m_eWeight = weight::Black; break; + + case FW_NORMAL: + default: pFont->m_eWeight = weight::Normal; break; + } + + switch( aInfo.width ) + { + case FWIDTH_ULTRA_CONDENSED: pFont->m_eWidth = width::UltraCondensed; break; + case FWIDTH_EXTRA_CONDENSED: pFont->m_eWidth = width::ExtraCondensed; break; + case FWIDTH_CONDENSED: pFont->m_eWidth = width::Condensed; break; + case FWIDTH_SEMI_CONDENSED: pFont->m_eWidth = width::SemiCondensed; break; + case FWIDTH_SEMI_EXPANDED: pFont->m_eWidth = width::SemiExpanded; break; + case FWIDTH_EXPANDED: pFont->m_eWidth = width::Expanded; break; + case FWIDTH_EXTRA_EXPANDED: pFont->m_eWidth = width::ExtraExpanded; break; + case FWIDTH_ULTRA_EXPANDED: pFont->m_eWidth = width::UltraExpanded; break; + + case FWIDTH_NORMAL: + default: pFont->m_eWidth = width::Normal; break; + } + + pFont->m_ePitch = aInfo.pitch ? pitch::Fixed : pitch::Variable; + pFont->m_eItalic = aInfo.italicAngle == 0 ? italic::Upright : ( aInfo.italicAngle < 0 ? italic::Italic : italic::Oblique ); + + pFont->m_aEncoding = aInfo.symbolEncoded ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UCS2; + + pFont->m_aGlobalMetricY.width = pFont->m_aGlobalMetricX.width = aInfo.xMax - aInfo.xMin; + pFont->m_aGlobalMetricY.height = pFont->m_aGlobalMetricX.height = aInfo.yMax - aInfo.yMin; + + if( aInfo.winAscent && aInfo.winDescent ) + { + pFont->m_nAscend = aInfo.winAscent; + pFont->m_nDescend = aInfo.winDescent; + pFont->m_nLeading = pFont->m_nAscend + pFont->m_nDescend - 1000; + } + else if( aInfo.typoAscender && aInfo.typoDescender ) + { + pFont->m_nLeading = aInfo.typoLineGap; + pFont->m_nAscend = aInfo.typoAscender; + pFont->m_nDescend = -aInfo.typoDescender; + } + else + { + pFont->m_nLeading = aInfo.linegap; + pFont->m_nAscend = aInfo.ascender; + pFont->m_nDescend = -aInfo.descender; + } + + // last try: font bounding box + if( pFont->m_nAscend == 0 ) + pFont->m_nAscend = aInfo.yMax; + if( pFont->m_nDescend == 0 ) + pFont->m_nDescend = -aInfo.yMin; + if( pFont->m_nLeading == 0 ) + pFont->m_nLeading = 15 * (pFont->m_nAscend+pFont->m_nDescend) / 100; + + if( pFont->m_nAscend && pFont->m_nDescend ) + pFont->m_aGlobalMetricX.height = pFont->m_aGlobalMetricY.height = pFont->m_nAscend + pFont->m_nDescend; + + CloseTTFont( pTTFont ); + bSuccess = true; + } +#ifdef DEBUG + else + fprintf( stderr, "could not OpenTTFont \"%s\"\n", aFile.GetBuffer() ); +#endif + + return bSuccess; +} + +// ------------------------------------------------------------------------- + +static void normPath( ByteString& rPath ) +{ + while( rPath.SearchAndReplace( "//", "/" ) != STRING_NOTFOUND ) + ; + if( rPath.Len() > 0 && rPath.GetChar( rPath.Len()-1 ) == '/' ) + rPath.Erase( rPath.Len()-1 ); +} + + +void PrintFontManager::initialize( void* pInitDisplay ) +{ + long aDirEntBuffer[ (sizeof(struct dirent)+_PC_NAME_MAX)+1 ]; + + // initialize may be called twice in the future + { + for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it ) + delete (*it).second; + m_nNextFontID = 1; + m_aFonts.clear(); + m_aFontDirectories.clear(); + } + +#ifdef DEBUG + clock_t aStart; + clock_t aStep1; + clock_t aStep2; + clock_t aStep3; + int nBuiltinFonts = 0; + + struct tms tms; + + aStart = times( &tms ); +#endif + + // part one - look for downloadable fonts + rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); + static const char* pSalPrivatePath = getenv( "SAL_FONTPATH_PRIVATE" ); + + // search for the fonts in SAL_PRIVATE_FONTPATH first; those are + // the TrueType fonts installed with the office + if( pSalPrivatePath ) + { + ByteString aPath( pSalPrivatePath ); + int nTokens = aPath.GetTokenCount( ';' ); + for( int i = 0; i < nTokens; i++ ) + { + ByteString aToken( aPath.GetToken( i, ';' ) ); + normPath( aToken ); + m_aFontDirectories.push_back( aToken ); + } + } + + Display *pDisplay = (Display*)pInitDisplay; + + if( ! pDisplay ) + pDisplay = XOpenDisplay( NULL ); + + + // get font paths to look for fonts + int nPaths = 0, i; + char** pPaths = XGetFontPath( pDisplay, &nPaths ); + + for( i = 0; i < nPaths; i++ ) + { + ByteString aPath( pPaths[i] ); + normPath( aPath ); + m_aFontDirectories.push_back( aPath ); + } + + if( nPaths ) + XFreeFontPath( pPaths ); + + if( ! pInitDisplay ) + XCloseDisplay( pDisplay ); + + // insert some standard directories + m_aFontDirectories.push_back( "/usr/openwin/lib/X11/fonts/Type1" ); + m_aFontDirectories.push_back( "/usr/openwin/lib/X11/fonts/Type1/sun" ); + m_aFontDirectories.push_back( "/usr/X11R6/lib/X11/fonts/Type1" ); +#ifdef SOLARIS + + /* cde specials, from /usr/dt/bin/Xsession: here are the good fonts, + the OWfontpath file may contain as well multiple lines as a comma + separated list of fonts in each line. to make it even more weird + environment variables are allowed as well */ + + const char* lang = getenv("LANG"); + if ( lang != NULL ) + { + String aOpenWinDir( String::CreateFromAscii( "/usr/openwin/lib/locale/" ) ); + aOpenWinDir.AppendAscii( lang ); + aOpenWinDir.AppendAscii( "/OWfontpath" ); + + SvFileStream aStream( aOpenWinDir, STREAM_READ ); + + // TODO: replace environment variables + while( aStream.IsOpen() && ! aStream.IsEof() ) + { + ByteString aLine; + aStream.ReadLine( aLine ); + normPath( aLine ); + m_aFontDirectories.push_back( aLine ); + } + } + +#endif /* SOLARIS */ + + // search for font files in each path + ::std::list< OString >::iterator dir_it; + for( dir_it = m_aFontDirectories.begin(); dir_it != m_aFontDirectories.end(); ++dir_it ) + { + OString aPath( *dir_it ); + // there may be ":unscaled" directories (see XFree86) + // it should be safe to ignore them since they should not + // contain any of our recognbizeable fonts + OUString aUniPath; + FileBase::normalizePath( OStringToOUString( aPath, aEncoding ), aUniPath ); + + // read fonts.dir if possible + ::std::hash_map< OString, ByteString, OStringHash > aFontsDir; + ByteString aGccDummy( aPath ); + String aFontsDirPath( aGccDummy, aEncoding ); + aFontsDirPath.AppendAscii( "/fonts.dir" ); + int nDirID = getDirectoryAtom( aPath, true ); + SvFileStream aStream( aFontsDirPath, STREAM_READ ); + if( aStream.IsOpen() ) + { + ByteString aLine; + while( ! aStream.IsEof() ) + { + aStream.ReadLine( aLine ); + ByteString aFileName( GetCommandLineToken( 0, aLine ) ); + ByteString aXLFD( aLine.Copy( aFileName.Len() ) ); + if( aFileName.Len() && aXLFD.Len() ) + aFontsDir[ aFileName ] = aXLFD; + } + } + + DIR* pDIR = opendir( aPath.getStr() ); + struct dirent* pEntry = (struct dirent*)aDirEntBuffer; + if( pDIR ) + { + while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pEntry ) && pEntry ) + { + OString aFileName( pEntry->d_name ); + struct stat aStat; + ByteString aFilePath( aPath ); + aFilePath.Append( '/' ); + aFilePath.Append( ByteString( aFileName ) ); + if( ! stat( aFilePath.GetBuffer(), &aStat ) && + S_ISREG( aStat.st_mode ) ) + { + if( findFontFileID( nDirID, aFileName ) == 0 ) + { + ByteString aXLFD; + ::std::hash_map< OString, ByteString, OStringHash >::const_iterator it = + aFontsDir.find( aFileName ); + if( it != aFontsDir.end() ) + aXLFD = (*it).second; + + // fill in font attributes from XLFD rather + // than reading every file + ::std::list< PrintFont* > aNewFonts; + if( analyzeFontFile( nDirID, aFileName, aXLFD.Len() ? false : true, aXLFD, aNewFonts ) ) + { + for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin(); it != aNewFonts.end(); ++it ) + { + m_aFonts[ m_nNextFontID++ ] = *it; +#ifdef DEBUG + fprintf( stderr, "adding font \"%s\" from file \"%s/%s\"\n", OUStringToOString( m_pAtoms->getString( ATOM_FAMILYNAME, (*it)->m_nFamilyName ), RTL_TEXTENCODING_MS_1252 ).getStr(), aPath.getStr(), aFileName.getStr() ); +#endif + } + } + } + } + } + closedir( pDIR ); + } + } + +#ifdef DEBUG + aStep1 = times( &tms ); +#endif + + // part two - look for metrics for builtin printer fonts + OUString aPath( getPrinterPath() ); + nPaths = aPath.getTokenCount( ':' ); + for( i = 0; i < nPaths; i++ ) + { + OString aDir( OUStringToOString( aPath.getToken( i, ':' ), aEncoding ) ); + aDir += "/"PRINTER_METRICDIR; + DIR* pDIR = opendir( aDir.getStr() ); + if( pDIR ) + { + struct dirent* pDirEntry = (struct dirent*)aDirEntBuffer; + OString aSysDir( aDir ); + int nDirAtom = getDirectoryAtom( aDir, true ); + + // get cache information + aSysDir += "/builtincache"; + struct stat aStat; + time_t nCacheDate = 0; + if( ! stat( aSysDir.getStr(), &aStat ) ) + nCacheDate = aStat.st_mtime; + Config aCache( OStringToOUString( aSysDir, aEncoding ) ); + + while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pDirEntry ) && pDirEntry ) + { + ByteString aFile( aDir ); + aFile += '/'; + aFile += pDirEntry->d_name; + if( ! stat( aFile.GetBuffer(), &aStat ) + && S_ISREG( aStat.st_mode ) + ) + { + OString aFileName( pDirEntry->d_name, strlen( pDirEntry->d_name ) ); + OString aExt( aFileName.getToken( aFileName.getTokenCount( '.' )-1, '.' ) ); + if( aExt.equalsIgnoreCase( "afm" ) ) + { + BuiltinFont* pFont = new BuiltinFont; + pFont->m_nDirectory = nDirAtom; + pFont->m_aMetricFile = aFileName; + + // first try the cache + bool bWasCached = false; + if( aCache.HasGroup( aFileName ) ) + { + aCache.SetGroup( aFileName ); + if( aStat.st_mtime <= nCacheDate ) + { + bWasCached = true; + pFont->m_nFamilyName= m_pAtoms->getAtom( ATOM_FAMILYNAME, String( aCache.ReadKey( "FamilyName" ), RTL_TEXTENCODING_UTF8 ), sal_True ); + pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, String( aCache.ReadKey( "PSName" ), RTL_TEXTENCODING_UTF8 ), sal_True ); + pFont->m_eItalic = (italic::type)aCache.ReadKey( "Italic" ).ToInt32(); + pFont->m_eWidth = (width::type)aCache.ReadKey( "Width" ).ToInt32(); + pFont->m_ePitch = (pitch::type)aCache.ReadKey( "Pitch" ).ToInt32(); + pFont->m_eWeight = (weight::type)aCache.ReadKey( "Weight" ).ToInt32(); + pFont->m_aEncoding = (rtl_TextEncoding)aCache.ReadKey( "Encoding" ).ToInt32(); + pFont->m_nAscend = aCache.ReadKey( "Ascend" ).ToInt32(); + pFont->m_nDescend = aCache.ReadKey( "Descend" ).ToInt32(); + pFont->m_nLeading = aCache.ReadKey( "Leading" ).ToInt32(); + ByteString aValue = aCache.ReadKey( "GlobalMetrics" ); + pFont->m_aGlobalMetricX.width = aValue.GetToken( 0, ',' ).ToInt32(); + pFont->m_aGlobalMetricX.height = aValue.GetToken( 1, ',' ).ToInt32(); + pFont->m_aGlobalMetricY.width = aValue.GetToken( 2, ',' ).ToInt32(); + pFont->m_aGlobalMetricY.height = aValue.GetToken( 3, ',' ).ToInt32(); + m_aFonts[ m_nNextFontID++ ] = pFont; +#ifdef DEBUG + nBuiltinFonts++; +#endif + } + } + + if( ! bWasCached ) + { + if( pFont->readAfmMetrics( aFile, m_pAtoms ) && + findFontBuiltinID( pFont->m_nPSName ) == 0 + ) + { + m_aFonts[ m_nNextFontID++ ] = pFont; +#ifdef DEBUG + nBuiltinFonts++; +#endif + + // update the cache + aCache.SetGroup( aFileName ); + aCache.WriteKey( "FamilyName", ByteString( String( m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ) ), RTL_TEXTENCODING_UTF8 ) ); + aCache.WriteKey( "PSName", ByteString( String( m_pAtoms->getString( ATOM_PSNAME, pFont->m_nPSName ) ), RTL_TEXTENCODING_UTF8 ) ); + aCache.WriteKey( "Italic", ByteString::CreateFromInt32( (int)pFont->m_eItalic ) ); + aCache.WriteKey( "Width", ByteString::CreateFromInt32( (int)pFont->m_eWidth ) ); + aCache.WriteKey( "Weight", ByteString::CreateFromInt32( (int)pFont->m_eWeight ) ); + aCache.WriteKey( "Pitch", ByteString::CreateFromInt32( (int)pFont->m_ePitch ) ); + aCache.WriteKey( "Encoding", ByteString::CreateFromInt32( (int)pFont->m_aEncoding ) ); + aCache.WriteKey( "Ascend", ByteString::CreateFromInt32( pFont->m_nAscend ) ); + aCache.WriteKey( "Descend", ByteString::CreateFromInt32( pFont->m_nDescend ) ); + aCache.WriteKey( "Leading", ByteString::CreateFromInt32( pFont->m_nLeading ) ); + ByteString aValue( ByteString::CreateFromInt32( pFont->m_aGlobalMetricX.width ) ); + aValue += ','; + aValue += ByteString::CreateFromInt32( pFont->m_aGlobalMetricX.height ); + aValue += ','; + aValue += ByteString::CreateFromInt32( pFont->m_aGlobalMetricY.width ); + aValue += ','; + aValue += ByteString::CreateFromInt32( pFont->m_aGlobalMetricY.height ); + aCache.WriteKey( "GlobalMetrics", aValue ); + } + else + delete pFont; + } + } + } + } + closedir( pDIR ); + } + } + +#ifdef DEBUG + aStep2 = times( &tms ); +#endif + + // part three - fill in family styles + ::std::hash_map< fontID, PrintFont* >::iterator font_it; + for (font_it = m_aFonts.begin(); font_it != m_aFonts.end(); ++font_it) + { + ::std::hash_map< int, family::type >::const_iterator it = + m_aFamilyTypes.find( font_it->second->m_nFamilyName ); + if (it != m_aFamilyTypes.end()) + continue; + const ::rtl::OUString& rFamily = + m_pAtoms->getString( ATOM_FAMILYNAME, font_it->second->m_nFamilyName); + family::type eType = matchFamilyName( rFamily ); + m_aFamilyTypes[ font_it->second->m_nFamilyName ] = eType; + } + +#ifdef DEBUG + aStep3 = times( &tms ); + fprintf( stderr, "PrintFontManager::initialize: collected %d fonts (%d builtin)\n", m_aFonts.size(), nBuiltinFonts ); + fprintf( stderr, "Step 1 took %lf seconds\n", (double)(aStep1 - aStart)/(double)CLK_TCK ); + fprintf( stderr, "Step 2 took %lf seconds\n", (double)(aStep2 - aStep1)/(double)CLK_TCK ); + fprintf( stderr, "Step 3 took %lf seconds\n", (double)(aStep3 - aStep2)/(double)CLK_TCK ); +#endif +} + +// ------------------------------------------------------------------------- +inline bool +equalPitch (psp::pitch::type from, psp::pitch::type to) +{ + return from == to; +} + +inline bool +equalWeight (psp::weight::type from, psp::weight::type to) +{ + return from > to ? (from - to) <= 3 : (to - from) <= 3; +} + +inline bool +equalItalic (psp::italic::type from, psp::italic::type to) +{ + if ( (from == psp::italic::Italic) || (from == psp::italic::Oblique) ) + return (to == psp::italic::Italic) || (to == psp::italic::Oblique); + return to == from; +} +inline bool +equalEncoding (rtl_TextEncoding from, rtl_TextEncoding to) +{ + if ((from == RTL_TEXTENCODING_ISO_8859_1) || (from == RTL_TEXTENCODING_MS_1252)) + return (to == RTL_TEXTENCODING_ISO_8859_1) || (to == RTL_TEXTENCODING_MS_1252); + return from == to; +} + +void PrintFontManager::getFontList( ::std::list< fontID >& rFontIDs, const PPDParser* pParser ) const +{ + rFontIDs.clear(); + ::std::hash_map< fontID, PrintFont* >::const_iterator it; + ::std::list< PrintFont* > aBuiltinFonts; + + for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it ) + { + if( pParser && it->second->m_eType == fonttype::Builtin ) + { + int nFonts = pParser->getFonts(); + String aPSName = m_pAtoms->getString( ATOM_PSNAME, it->second->m_nPSName ); + for( int j = 0; j < nFonts; j++ ) + { + if( aPSName.Equals( pParser->getFont( j ) ) ) + { + rFontIDs.push_back( it->first ); + aBuiltinFonts.push_back( it->second ); + break; + } + } + } + else + rFontIDs.push_back( it->first ); + } + + if( pParser ) + { + // remove doubles for builtins + ::std::list< fontID >::iterator font_it; + ::std::list< fontID >::iterator temp_it; + font_it = rFontIDs.begin(); + while( font_it != rFontIDs.end() ) + { + temp_it = font_it; + ++temp_it; + PrintFont* pFont = getFont( *font_it ); + if( pFont->m_eType != fonttype::Builtin ) + { + const OUString& rFontFamily( m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ) ); + + for( ::std::list< PrintFont* >::const_iterator bit = aBuiltinFonts.begin(); + bit != aBuiltinFonts.end(); ++bit ) + { + if( ! equalItalic (pFont->m_eItalic, (*bit)->m_eItalic) ) + continue; + if( ! equalWeight (pFont->m_eWeight, (*bit)->m_eWeight) ) + continue; + if( ! equalPitch (pFont->m_ePitch, (*bit)->m_ePitch) ) + continue; + if( ! equalEncoding(pFont->m_aEncoding, (*bit)->m_aEncoding) ) + continue; + const OUString& rBuiltinFamily( m_pAtoms->getString( ATOM_FAMILYNAME, (*bit)->m_nFamilyName ) ); + if( rFontFamily.equalsIgnoreCase( rBuiltinFamily ) ) + { + // remove double + rFontIDs.erase( font_it ); + break; + } + } + } + font_it = temp_it; + } + } +} + +// ------------------------------------------------------------------------- + +void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const +{ + ::std::hash_map< int, family::type >::const_iterator style_it = + m_aFamilyTypes.find( pFont->m_nFamilyName ); + rInfo.m_eType = pFont->m_eType; + rInfo.m_aFamilyName = m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ); + rInfo.m_eFamilyStyle = style_it != m_aFamilyTypes.end() ? style_it->second : family::Unknown; + rInfo.m_eItalic = pFont->m_eItalic; + rInfo.m_eWidth = pFont->m_eWidth; + rInfo.m_eWeight = pFont->m_eWeight; + rInfo.m_ePitch = pFont->m_ePitch; + rInfo.m_aEncoding = pFont->m_aEncoding; +} + +// ------------------------------------------------------------------------- + +void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const +{ + if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) + { + // might be a truetype font not analyzed or type1 without metrics read + if( pFont->m_eType == fonttype::Type1 ) + pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms ); + else if( pFont->m_eType == fonttype::TrueType ) + analyzeTrueTypeFile( pFont ); + } + + fillPrintFontInfo( pFont, static_cast< FastPrintFontInfo& >( rInfo ) ); + + rInfo.m_nAscend = pFont->m_nAscend; + rInfo.m_nDescend = pFont->m_nDescend; + rInfo.m_nLeading = pFont->m_nLeading; + rInfo.m_nWidth = pFont->m_aGlobalMetricX.width < pFont->m_aGlobalMetricY.width ? pFont->m_aGlobalMetricY.width : pFont->m_aGlobalMetricX.width; +} + +// ------------------------------------------------------------------------- + +void PrintFontManager::getFontListWithInfo( ::std::list< PrintFontInfo >& rFonts, const PPDParser* pParser ) const +{ + rFonts.clear(); + ::std::list< fontID > aFontList; + getFontList( aFontList, pParser ); + + ::std::list< fontID >::iterator it; + for( it = aFontList.begin(); it != aFontList.end(); ++it ) + { + PrintFontInfo aInfo; + aInfo.m_nID = *it; + fillPrintFontInfo( getFont( *it ), aInfo ); + rFonts.push_back( aInfo ); + } +} + +// ------------------------------------------------------------------------- + +void PrintFontManager::getFontListWithFastInfo( ::std::list< FastPrintFontInfo >& rFonts, const PPDParser* pParser ) const +{ + rFonts.clear(); + ::std::list< fontID > aFontList; + getFontList( aFontList, pParser ); + + ::std::list< fontID >::iterator it; + for( it = aFontList.begin(); it != aFontList.end(); ++it ) + { + FastPrintFontInfo aInfo; + aInfo.m_nID = *it; + fillPrintFontInfo( getFont( *it ), aInfo ); + rFonts.push_back( aInfo ); + } +} + +// ------------------------------------------------------------------------- + +bool PrintFontManager::getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const +{ + PrintFont* pFont = getFont( nFontID ); + if( pFont ) + { + rInfo.m_nID = nFontID; + fillPrintFontInfo( pFont, rInfo ); + } + return pFont ? true : false; +} + +// ------------------------------------------------------------------------- + +bool PrintFontManager::getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const +{ + PrintFont* pFont = getFont( nFontID ); + if( pFont ) + { + rInfo.m_nID = nFontID; + fillPrintFontInfo( pFont, rInfo ); + } + return pFont ? true : false; +} + +// ------------------------------------------------------------------------- + +family::type PrintFontManager::matchFamilyName( const ::rtl::OUString& rFamily ) const +{ + typedef struct { + const char* mpName; + sal_uInt16 mnLength; + family::type meType; + } family_t; + +#define InitializeClass( p, a ) p, sizeof(p) - 1, a + const family_t pFamilyMatch[] = { + { InitializeClass( "arial", family::Swiss ) }, + { InitializeClass( "arioso", family::Script ) }, + { InitializeClass( "avant garde", family::Swiss ) }, + { InitializeClass( "avantgarde", family::Swiss ) }, + { InitializeClass( "bembo", family::Roman ) }, + { InitializeClass( "bookman", family::Roman ) }, + { InitializeClass( "conga", family::Roman ) }, + { InitializeClass( "courier", family::Modern ) }, + { InitializeClass( "curl", family::Script ) }, + { InitializeClass( "fixed", family::Modern ) }, + { InitializeClass( "gill", family::Swiss ) }, + { InitializeClass( "helmet", family::Modern ) }, + { InitializeClass( "helvetica", family::Swiss ) }, + { InitializeClass( "international", family::Modern ) }, + { InitializeClass( "lucida", family::Swiss ) }, + { InitializeClass( "new century schoolbook", family::Roman ) }, + { InitializeClass( "palatino", family::Roman ) }, + { InitializeClass( "roman", family::Roman ) }, + { InitializeClass( "sans serif", family::Swiss ) }, + { InitializeClass( "sansserif", family::Swiss ) }, + { InitializeClass( "serf", family::Roman ) }, + { InitializeClass( "serif", family::Roman ) }, + { InitializeClass( "times", family::Roman ) }, + { InitializeClass( "utopia", family::Roman ) }, + { InitializeClass( "zapf chancery", family::Script ) }, + { InitializeClass( "zapfchancery", family::Script ) } + }; + + rtl::OString aFamily = rtl::OUStringToOString( rFamily, RTL_TEXTENCODING_ISO_8859_1 ); + sal_uInt32 nLower = 0; + sal_uInt32 nUpper = sizeof(pFamilyMatch) / sizeof(pFamilyMatch[0]); + + while( nLower < nUpper ) + { + sal_uInt32 nCurrent = (nLower + nUpper) / 2; + const family_t* pHaystack = pFamilyMatch + nCurrent; + sal_Int32 nComparison = rtl_str_compareIgnoreCase_WithLength( + aFamily.getStr(), pHaystack->mpName, pHaystack->mnLength ); + + if( nComparison < 0 ) + nUpper = nCurrent; + else + if( nComparison > 0 ) + nLower = nCurrent + 1; + else + return pHaystack->meType; + } + + return family::Unknown; +} + +// ------------------------------------------------------------------------- + +family::type PrintFontManager::getFontFamilyType( fontID nFontID ) const +{ + PrintFont* pFont = getFont( nFontID ); + if( !pFont ) + return family::Unknown; + + ::std::hash_map< int, family::type >::const_iterator it = + m_aFamilyTypes.find( pFont->m_nFamilyName ); + return (it != m_aFamilyTypes.end()) ? it->second : family::Unknown; +} + + +// ------------------------------------------------------------------------- + +const ::rtl::OUString& PrintFontManager::getFontFamily( fontID nFontID ) const +{ + PrintFont* pFont = getFont( nFontID ); + return m_pAtoms->getString( ATOM_FAMILYNAME, pFont ? pFont->m_nFamilyName : INVALID_ATOM ); +} + +// ------------------------------------------------------------------------- + +OString PrintFontManager::getAfmFile( PrintFont* pFont ) const +{ + OString aMetricPath; + if( pFont && pFont->m_eType == fonttype::Type1 ) + { + Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont); + ::std::hash_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory ); + aMetricPath = it->second; + aMetricPath += "/"; + aMetricPath += pPSFont->m_aMetricFile; + } + return aMetricPath; +} + +// ------------------------------------------------------------------------- + +OString PrintFontManager::getFontFile( PrintFont* pFont ) const +{ + OString aPath; + + if( pFont && pFont->m_eType == fonttype::Type1 ) + { + Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont); + ::std::hash_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory ); + aPath = it->second; + aPath += "/"; + aPath += pPSFont->m_aFontFile; + } + else if( pFont && pFont->m_eType == fonttype::TrueType ) + { + TrueTypeFontFile* pTTFont = static_cast< TrueTypeFontFile* >(pFont); + ::std::hash_map< int, OString >::const_iterator it = m_aAtomToDir.find( pTTFont->m_nDirectory ); + aPath = it->second; + aPath += "/"; + aPath += pTTFont->m_aFontFile; + } + return aPath; +} + +// ------------------------------------------------------------------------- + +const ::rtl::OUString& PrintFontManager::getPSName( fontID nFontID ) const +{ + PrintFont* pFont = getFont( nFontID ); + if( pFont && pFont->m_nPSName == 0 ) + { + if( pFont->m_eType == fonttype::TrueType ) + analyzeTrueTypeFile( pFont ); + } + + return m_pAtoms->getString( ATOM_PSNAME, pFont ? pFont->m_nPSName : INVALID_ATOM ); +} + +// ------------------------------------------------------------------------- + +const CharacterMetric& PrintFontManager::getGlobalFontMetric( fontID nFontID, bool bHorizontal ) const +{ + static CharacterMetric aMetric; + PrintFont* pFont = getFont( nFontID ); + return pFont ? ( bHorizontal ? pFont->m_aGlobalMetricX : pFont->m_aGlobalMetricY ) : aMetric; +} + +// ------------------------------------------------------------------------- + +int PrintFontManager::getFontAscend( fontID nFontID ) const +{ + PrintFont* pFont = getFont( nFontID ); + if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) + { + // might be a truetype font not yet analyzed + if( pFont->m_eType == fonttype::TrueType ) + analyzeTrueTypeFile( pFont ); + } + return pFont->m_nAscend; +} + +// ------------------------------------------------------------------------- + +int PrintFontManager::getFontDescend( fontID nFontID ) const +{ + PrintFont* pFont = getFont( nFontID ); + if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) + { + // might be a truetype font not yet analyzed + if( pFont->m_eType == fonttype::TrueType ) + analyzeTrueTypeFile( pFont ); + } + return pFont->m_nDescend; +} + +// ------------------------------------------------------------------------- + +int PrintFontManager::getFontLeading( fontID nFontID ) const +{ + PrintFont* pFont = getFont( nFontID ); + if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) + { + // might be a truetype font not yet analyzed + if( pFont->m_eType == fonttype::TrueType ) + analyzeTrueTypeFile( pFont ); + } + return pFont->m_nLeading; +} + +// ------------------------------------------------------------------------- + +OUString PrintFontManager::getFontXLFD( fontID nFontID ) const +{ + PrintFont* pFont = getFont( nFontID ); + return pFont ? OStringToOUString( getXLFD( pFont ), RTL_TEXTENCODING_ISO_8859_1 ) : OUString(); +} + +// ------------------------------------------------------------------------- + +const ::std::list< KernPair >& PrintFontManager::getKernPairs( fontID nFontID, bool bVertical ) const +{ + static ::std::list< KernPair > aEmpty; + + PrintFont* pFont = getFont( nFontID ); + if( ! pFont ) + return aEmpty; + + if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried ) + pFont->queryMetricPage( 0, m_pAtoms ); + if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried ) + return aEmpty; + return bVertical ? pFont->m_pMetrics->m_aYKernPairs : pFont->m_pMetrics->m_aXKernPairs; +} + +// ------------------------------------------------------------------------- + +bool PrintFontManager::getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical ) const +{ + PrintFont* pFont = getFont( nFontID ); + if( ! pFont ) + return false; + + if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) + { + // might be a font not yet analyzed + if( pFont->m_eType == fonttype::Type1 ) + pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms ); + else if( pFont->m_eType == fonttype::TrueType ) + analyzeTrueTypeFile( pFont ); + } + + for( int i = 0; i < nLen; i++ ) + { + if( ! pFont->m_pMetrics || + ! ( pFont->m_pMetrics->m_aPages[ pString[i] >> 11 ] & ( 1 << ( ( pString[i] >> 8 ) & 7 ) ) ) ) + pFont->queryMetricPage( pString[i] >> 8, m_pAtoms ); + pArray[i].width = pArray[i].height = -1; + if( pFont->m_pMetrics ) + { + int effectiveCode = pString[i]; + effectiveCode |= bVertical ? 1 << 16 : 0; + ::std::hash_map< int, CharacterMetric >::const_iterator it = + pFont->m_pMetrics->m_aMetrics.find( effectiveCode ); + if( it != pFont->m_pMetrics->m_aMetrics.end() ) + pArray[ i ] = it->second; + } + } + + return true; +} + +// ------------------------------------------------------------------------- + +bool PrintFontManager::getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical ) const +{ + PrintFont* pFont = getFont( nFontID ); + if( ! pFont ) + return false; + + if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) + { + // might be a font not yet analyzed + if( pFont->m_eType == fonttype::Type1 ) + pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms ); + else if( pFont->m_eType == fonttype::TrueType ) + analyzeTrueTypeFile( pFont ); + } + + for( sal_Unicode code = minCharacter; code <= maxCharacter; code++ ) + { + if( ! pFont->m_pMetrics || + ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) ) + pFont->queryMetricPage( code >> 8, m_pAtoms ); + pArray[ code - minCharacter ].width = -1; + pArray[ code - minCharacter ].height = -1; + if( pFont->m_pMetrics ) + { + int effectiveCode = code; + effectiveCode |= bVertical ? 1 << 16 : 0; + ::std::hash_map< int, CharacterMetric >::const_iterator it = + pFont->m_pMetrics->m_aMetrics.find( effectiveCode ); + if( it != pFont->m_pMetrics->m_aMetrics.end() ) + pArray[ code - minCharacter ] = it->second; + } + } + return true; +} + +// ------------------------------------------------------------------------- + +static bool createPath( const ByteString& rPath ) +{ + bool bSuccess = false; +#ifdef DEBUG + fprintf( stderr, "createPath( %s )\n", rPath.GetBuffer() ); +#endif + + if( access( rPath.GetBuffer(), F_OK ) ) + { + int nPos = rPath.SearchBackward( '/' ); + if( nPos != STRING_NOTFOUND ) + while( nPos > 0 && rPath.GetChar( nPos ) == '/' ) + nPos--; + + if( nPos != STRING_NOTFOUND && nPos != 0 && createPath( rPath.Copy( 0, nPos+1 ) ) ) + { +#ifdef DEBUG + fprintf( stderr, "mkdir ", rPath.GetBuffer() ); +#endif + bSuccess = mkdir( rPath.GetBuffer(), 0777 ) ? false : true; +#ifdef DEBUG + fprintf( stderr, "%s\n", bSuccess ? "succeeded" : "failed" ); +#endif + } + } + else + bSuccess = true; + + return bSuccess; +} + + +// ------------------------------------------------------------------------- + +int PrintFontManager::importFonts( const ::std::list< OUString >& rFiles, ImportFontCallback* pCallback ) +{ + int nSuccess = 0; + + // find a directory with write access + rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); + SvFileStream aFontsDir; + int nDirID; + INetURLObject aDir; + for( ::std::list< OString >::const_iterator dir_it = m_aFontDirectories.begin(); + ! ( aFontsDir.IsOpen() && aFontsDir.IsWritable() ) && dir_it != m_aFontDirectories.end(); ++dir_it ) + { + // there must be a writable fonts.dir in that directory + aDir = INetURLObject( OStringToOUString( *dir_it, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL ); + nDirID = getDirectoryAtom( *dir_it, false ); + INetURLObject aFDir( aDir ); + ByteString aDirPath( aFDir.PathToFileName(), aEncoding ); + if( createPath( aDirPath ) ) + { + aFDir.Append( String( RTL_CONSTASCII_USTRINGPARAM( "fonts.dir" ) ) ); + aFontsDir.Open( aFDir.PathToFileName(), STREAM_READ | STREAM_WRITE ); + } + } + if( aFontsDir.IsOpen() ) + { + aFontsDir.SetLineDelimiter( LINEEND_LF ); + // we have a suitable path + // read the fonts.dir + ::std::list< ByteString > aLines; + ::std::list< ByteString >::iterator line_it; + ByteString aLine; + while( ! aFontsDir.IsEof() ) + { + aFontsDir.ReadLine( aLine ); + if( aLine.Len() ) + aLines.push_back( aLine ); + } + if( aLines.begin() != aLines.end() ) + aLines.pop_front(); // not interested in the number of lines + + // copy the font files and add them to fonts.dir + // do not overwrite existing files unless user wants it that way + for( ::std::list< OUString >::const_iterator font_it = rFiles.begin(); + font_it != rFiles.end(); ++font_it ) + { + INetURLObject aFrom( *font_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL ); + INetURLObject aTo( aDir ); + aTo.Append( aFrom.GetName() ); + + if( pCallback ) + pCallback->progress( aTo.PathToFileName() ); + + if( pCallback && pCallback->isCanceled() ) + break; + + if( ! access( ByteString( aTo.PathToFileName(), aEncoding ).GetBuffer(), F_OK ) ) + { + if( ! ( pCallback ? pCallback->queryOverwriteFile( aTo.PathToFileName() ) : false ) ) + continue; + } + // look for afm if necessary + OUString aAfmCopied; + if( aFrom.getExtension().EqualsIgnoreCaseAscii( "pfa" ) || + aFrom.getExtension().EqualsIgnoreCaseAscii( "pfb" ) ) + { + INetURLObject aFromAfm( aFrom ); + aFromAfm.setExtension( String( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) ); + if( access( ByteString( aFromAfm.PathToFileName(), aEncoding ).GetBuffer(), F_OK ) ) + { + aFromAfm.setExtension( String( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) ); + if( access( ByteString( aFromAfm.PathToFileName(), aEncoding ).GetBuffer(), F_OK ) ) + { + aFromAfm.removeSegment(); + aFromAfm.Append( String( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) ); + aFromAfm.Append( aTo.GetName() ); + aFromAfm.setExtension( String( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) ); + if( access( ByteString( aFromAfm.PathToFileName(), aEncoding ).GetBuffer(), F_OK ) ) + { + aFromAfm.setExtension( String( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) ); + if( access( ByteString( aFromAfm.PathToFileName(), aEncoding ).GetBuffer(), F_OK ) ) + { + // give up + if( pCallback ) + pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::NoAfmMetric ); + continue; + } + } + } + } + INetURLObject aToAfm( aTo ); + aToAfm.setExtension( String( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) ); + OUString aFromPath, aToPath; + FileBase::normalizePath( aFromAfm.PathToFileName(), aFromPath ); + FileBase::normalizePath( aToAfm.PathToFileName(), aToPath ); + + FileBase::RC nError = File::copy( aFromPath, aToPath ); + if( nError ) + { + if( pCallback ) + pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::AfmCopyFailed ); + continue; + } + aAfmCopied = aToPath; + } + // copy font file + OUString aFontFrom, aFontTo; + FileBase::normalizePath( aFrom.PathToFileName(), aFontFrom ); + FileBase::normalizePath( aTo.PathToFileName(), aFontTo ); + if( File::copy( aFontFrom, aFontTo ) ) + { + if( aAfmCopied.getLength() ) + File::remove( aAfmCopied ); + if( pCallback ) + pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::FontCopyFailed ); + continue; + } + + ::std::list< PrintFont* > aNewFonts; + ::std::list< PrintFont* >::iterator it; + if( analyzeFontFile( nDirID, OUStringToOString( aTo.GetName(), aEncoding ), true, OString(), aNewFonts ) ) + { + // remove all fonts for the same file + // discarding their font ids + ::std::hash_map< fontID, PrintFont* >::iterator current, next; + current = m_aFonts.begin(); + OString aFileName( OUStringToOString( aTo.GetName(), aEncoding ) ); + while( current != m_aFonts.end() ) + { + bool bRemove = false; + switch( current->second->m_eType ) + { + case fonttype::Type1: + if( static_cast<Type1FontFile*>(current->second)->m_aFontFile == aFileName ) + bRemove = true; + break; + case fonttype::TrueType: + if( static_cast<TrueTypeFontFile*>(current->second)->m_aFontFile == aFileName ) + bRemove = true; + break; + } + if( bRemove ) + { + next = current; + ++next; + delete current->second; + m_aFonts.erase( current ); + current = next; + } + else + ++current; + } + + DBG_ASSERT( !findFontFileID( nDirID, aFileName ), "not all fonts removed for file" ); + + nSuccess++; + for( it = aNewFonts.begin(); it != aNewFonts.end(); ++it ) + { + m_aFonts[ m_nNextFontID++ ] = *it; + aLine = ByteString( aTo.GetName(), aEncoding ); + aLine += ' '; + aLine += getXLFD( *it ); + + ByteString aFile( aTo.GetName(), aEncoding ); + for( line_it = aLines.begin(); line_it != aLines.end(); ++line_it ) + { + if( line_it->GetToken( 0, ' ' ).Equals( aFile ) ) + { + *line_it = aLine; + break; + } + } + if( line_it == aLines.end() ) + aLines.push_back( aLine ); + } + } + } + aFontsDir.Seek( STREAM_SEEK_TO_BEGIN ); + aFontsDir.SetStreamSize( 0 ); + aFontsDir.WriteLine( ByteString::CreateFromInt32( aLines.size() ) ); + for( line_it = aLines.begin(); line_it != aLines.end(); ++line_it ) + aFontsDir.WriteLine( *line_it ); + + // rehash X font path + Display* pDisplay = XOpenDisplay( NULL ); + if( pDisplay ) + { + int nPaths = 0; + char** pFontPaths = XGetFontPath( pDisplay, &nPaths ); + XSetFontPath( pDisplay, pFontPaths, nPaths ); + if( pFontPaths && nPaths ) + XFreeFontPath( pFontPaths ); + XCloseDisplay( pDisplay ); + } + } + else if( pCallback ) + pCallback->importFontsFailed( ImportFontCallback::NoWritableDirectory ); + + return nSuccess; +} + +// ------------------------------------------------------------------------- + +bool PrintFontManager::checkImportPossible() const +{ + bool bSuccess = false; + + // find a directory with write access + SvFileStream aFontsDir; + INetURLObject aDir; + rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); + for( ::std::list< OString >::const_iterator dir_it = m_aFontDirectories.begin(); + ! ( aFontsDir.IsOpen() && aFontsDir.IsWritable() ) && dir_it != m_aFontDirectories.end(); ++dir_it ) + { + // there must be a writable fonts.dir in that directory + aDir = INetURLObject( OStringToOUString( *dir_it, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL ); + INetURLObject aFDir( aDir ); + ByteString aDirPath( aFDir.PathToFileName(), aEncoding ); + if( createPath( aDirPath ) ) + { + aFDir.Append( String( RTL_CONSTASCII_USTRINGPARAM( "fonts.dir" ) ) ); + aFontsDir.Open( aFDir.PathToFileName(), STREAM_READ | STREAM_WRITE ); + } + } + if( aFontsDir.IsOpen() && aFontsDir.IsWritable() ) + { +#ifdef DEBUG + fprintf( stderr, "found writable %s\n", ByteString( aFontsDir.GetFileName(), osl_getThreadTextEncoding() ).GetBuffer() ); +#endif + bSuccess = true; + } + + return bSuccess; +} + +// ------------------------------------------------------------------------- + +bool PrintFontManager::checkChangeFontPropertiesPossible( fontID nFontID ) const +{ + bool bSuccess = false; + PrintFont* pFont = getFont( nFontID ); + if( pFont ) + { + OString aFontsDirPath; + switch( pFont->m_eType ) + { + case fonttype::Type1: + aFontsDirPath = getDirectory( static_cast< Type1FontFile* >(pFont)->m_nDirectory ); + break; + case fonttype::TrueType: + aFontsDirPath = getDirectory( static_cast< TrueTypeFontFile* >(pFont)->m_nDirectory ); + break; + } + if( aFontsDirPath.getLength() ) + { + OUString aUniPath, aFDPath; + FileBase::normalizePath( OStringToOUString( aFontsDirPath, osl_getThreadTextEncoding() ), aUniPath ); + aUniPath += OUString::createFromAscii( "/fonts.dir" ); + FileBase::getSystemPathFromNormalizedPath( aUniPath, aFDPath ); + SvFileStream aFontsDir( aFDPath, STREAM_READ | STREAM_WRITE ); + if( aFontsDir.IsOpen() && aFontsDir.IsWritable() ) + bSuccess = true; + } + } + return bSuccess; +} + +// ------------------------------------------------------------------------- + +bool PrintFontManager::changeFontProperties( fontID nFontID, const ::rtl::OUString& rXLFD ) +{ + bool bSuccess = false; + if( ! checkChangeFontPropertiesPossible( nFontID ) ) + return bSuccess; + + rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); + PrintFont* pFont = getFont( nFontID ); + OString aFontsDirPath; + ByteString aFontFile; + + switch( pFont->m_eType ) + { + case fonttype::Type1: + aFontsDirPath = getDirectory( static_cast< Type1FontFile* >(pFont)->m_nDirectory ); + aFontFile = static_cast< Type1FontFile* >(pFont)->m_aFontFile; + break; + case fonttype::TrueType: + aFontsDirPath = getDirectory( static_cast< TrueTypeFontFile* >(pFont)->m_nDirectory ); + aFontFile = static_cast< TrueTypeFontFile* >(pFont)->m_aFontFile; + break; + } + OUString aUniPath, aFDPath; + FileBase::normalizePath( OStringToOUString( aFontsDirPath, aEncoding ), aUniPath ); + aUniPath += OUString::createFromAscii( "/fonts.dir" ); + FileBase::getSystemPathFromNormalizedPath( aUniPath, aFDPath ); + + SvFileStream aFontsDir( aFDPath, STREAM_READ | STREAM_WRITE ); + aFontsDir.SetLineDelimiter( LINEEND_LF ); + if( aFontsDir.IsOpen() && aFontsDir.IsWritable() ) + { + ByteString aXLFD( OUStringToOString( rXLFD, RTL_TEXTENCODING_ISO_8859_1 ) ); + ::std::list< ByteString > aLines; + ByteString aLine; + aFontsDir.ReadLine( aLine ); // pop line count + while( ! aFontsDir.IsEof() ) + { + aFontsDir.ReadLine( aLine ); + if( GetCommandLineToken( 0, aLine ) == aFontFile ) + { + bSuccess = true; + aLine = aFontFile; + aLine += ' '; + aLine += aXLFD; + } + if( aLine.Len() ) + aLines.push_back( aLine ); + } + if( ! bSuccess ) // ??? this should not happen + { + bSuccess = true; + aLine = aFontFile; + aLine += ' '; + aLine += aXLFD; + aLines.push_back( aLine ); + } + // write the file + aFontsDir.Seek( STREAM_SEEK_TO_BEGIN ); + aFontsDir.SetStreamSize( 0 ); + // write number of fonts + aFontsDir.WriteLine( ByteString::CreateFromInt32( aLines.size() ) ); + while( aLines.begin() != aLines.end() ) + { + aFontsDir.WriteLine( aLines.front() ); + aLines.pop_front(); + } + getFontAttributesFromXLFD( pFont, aXLFD ); + } + return bSuccess; +} diff --git a/psprint/source/fontmanager/makefile.mk b/psprint/source/fontmanager/makefile.mk new file mode 100644 index 000000000000..1f98f93fa4a0 --- /dev/null +++ b/psprint/source/fontmanager/makefile.mk @@ -0,0 +1,92 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: pl $ $Date: 2001-05-08 11:45:34 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +ENABLE_EXCEPTIONS=TRUE +PRJNAME=psprint +TARGET=fontman + +ENVCFLAGS+= -I..$/fontsubset + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Files -------------------------------------------------------- + +.IF "$(OS)"=="MACOSX" + +dummy: + @echo "Nothing to build for Mac OS X" + +.ELSE # "$(OS)"=="MACOSX" + +SLOFILES=\ + $(SLO)$/fontmanager.obj \ + $(SLO)$/parseAFM.obj + +.ENDIF # "$(OS)"=="MACOSX" + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/psprint/source/fontmanager/parseAFM.cxx b/psprint/source/fontmanager/parseAFM.cxx new file mode 100644 index 000000000000..77398980652d --- /dev/null +++ b/psprint/source/fontmanager/parseAFM.cxx @@ -0,0 +1,1464 @@ +/* + * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved. + * + * This file may be freely copied and redistributed as long as: + * 1) This entire notice continues to be included in the file, + * 2) If the file has been modified in any way, a notice of such + * modification is conspicuously indicated. + * + * PostScript, Display PostScript, and Adobe are registered trademarks of + * Adobe Systems Incorporated. + * + * ************************************************************************ + * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT + * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS + * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR + * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY + * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION, + * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + * ************************************************************************ + */ + +/* + * Changes made for OpenOffice.org + * + * 10/24/2000 pl - changed code to compile with c++-compilers + * - added namespace to avoid symbol clashes + * - replaced BOOL by bool + * - added function to free space allocated by parseFile + * 10/26/2000 pl - added additional keys + * - added ability to parse slightly broken files + * - added charwidth member to GlobalFontInfo + * 04/26/2001 pl - added OpenOffice header + */ + +/************************************************************************* + * + * $RCSfile: parseAFM.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:36 $ + * + ************************************************************************/ + +/* parseAFM.c + * + * This file is used in conjuction with the parseAFM.h header file. + * This file contains several procedures that are used to parse AFM + * files. It is intended to work with an application program that needs + * font metric information. The program can be used as is by making a + * procedure call to "parseFile" (passing in the expected parameters) + * and having it fill in a data structure with the data from the + * AFM file, or an application developer may wish to customize this + * code. + * + * There is also a file, parseAFMclient.c, that is a sample application + * showing how to call the "parseFile" procedure and how to use the data + * after "parseFile" has returned. + * + * Please read the comments in parseAFM.h and parseAFMclient.c. + * + * History: + * original: DSM Thu Oct 20 17:39:59 PDT 1988 + * modified: DSM Mon Jul 3 14:17:50 PDT 1989 + * - added 'storageProblem' return code + * - fixed bug of not allocating extra byte for string duplication + * - fixed typos + * modified: DSM Tue Apr 3 11:18:34 PDT 1990 + * - added free(ident) at end of parseFile routine + * modified: DSM Tue Jun 19 10:16:29 PDT 1990 + * - changed (width == 250) to (width = 250) in initializeArray + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/file.h> +#include <math.h> +#include <parseAFM.hxx> +#include <psprint/strhelper.hxx> + +#define lineterm EOL /* line terminating character */ +#define normalEOF 1 /* return code from parsing routines used only */ +/* in this module */ +#define Space "space" /* used in string comparison to look for the width */ +/* of the space character to init the widths array */ +#define False "false" /* used in string comparison to check the value of */ +/* boolean keys (e.g. IsFixedPitch) */ + +#define MATCH(A,B) (strncmp((A),(B), MAX_NAME) == 0) + +namespace psp { + +/*************************** GLOBALS ***********************/ + +static char *ident = NULL; /* storage buffer for keywords */ + + +/* "shorts" for fast case statement + * The values of each of these enumerated items correspond to an entry in the + * table of strings defined below. Therefore, if you add a new string as + * new keyword into the keyStrings table, you must also add a corresponding + * parseKey AND it MUST be in the same position! + * + * IMPORTANT: since the sorting algorithm is a binary search, the strings of + * keywords must be placed in lexicographical order, below. [Therefore, the + * enumerated items are not necessarily in lexicographical order, depending + * on the name chosen. BUT, they must be placed in the same position as the + * corresponding key string.] The NOPE shall remain in the last position, + * since it does not correspond to any key string, and it is used in the + * "recognize" procedure to calculate how many possible keys there are. + */ + +// some metrics have Ascent, Descent instead Ascender, Descender or Em +// which is not allowed per afm spcification, but let us handle +// this gently +enum parseKey { + ASCENDER, ASCENT, CHARBBOX, CODE, COMPCHAR, CODEHEX, CAPHEIGHT, CHARWIDTH, CHARACTERS, COMMENT, + DESCENDER, DESCENT, EM, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES, ENDDIRECTION, + ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN, + FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISBASEFONT, ISFIXEDPITCH, + ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, MAPPINGSCHEME, METRICSSETS, CHARNAME, + NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES, STARTDIRECTION, + STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS, + STARTTRACKKERN, TRACKKERN, UNDERLINEPOSITION, + UNDERLINETHICKNESS, VVECTOR, VERSION, XYWIDTH, X0WIDTH, XWIDTH, WEIGHT, XHEIGHT, + NOPE +}; + +/* keywords for the system: + * This a table of all of the current strings that are vaild AFM keys. + * Each entry can be referenced by the appropriate parseKey value (an + * enumerated data type defined above). If you add a new keyword here, + * a corresponding parseKey MUST be added to the enumerated data type + * defined above, AND it MUST be added in the same position as the + * string is in this table. + * + * IMPORTANT: since the sorting algorithm is a binary search, the keywords + * must be placed in lexicographical order. And, NULL should remain at the + * end. + */ + +static char *keyStrings[] = { + "Ascender", "Ascent", "B", "C", "CC", "CH", "CapHeight", "CharWidth", "Characters", "Comment", + "Descender", "Descent", "Em", "EncodingScheme", "EndCharMetrics", "EndComposites", "EndDirection", + "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern", + "FamilyName", "FontBBox", "FontName", "FullName", "IsBaseFont", "IsFixedPitch", + "ItalicAngle", "KP", "KPX", "L", "MappingScheme", "MetricsSets", "N", + "Notice", "PCC", "StartCharMetrics", "StartComposites", "StartDirection", + "StartFontMetrics", "StartKernData", "StartKernPairs", + "StartTrackKern", "TrackKern", "UnderlinePosition", + "UnderlineThickness", "V", "Version", "W", "W0X", "WX", "Weight", "XHeight", + NULL}; + +/*************************** PARSING ROUTINES **************/ + +/*************************** token *************************/ + +/* A "AFM File Conventions" tokenizer. That means that it will + * return the next token delimited by white space. See also + * the `linetoken' routine, which does a similar thing but + * reads all tokens until the next end-of-line. + */ + +static char *token( FILE* stream ) +{ + int ch, idx; + + /* skip over white space */ + while ((ch = fgetc(stream)) == ' ' || ch == lineterm || ch == '\r' || + ch == ',' || ch == '\t' || ch == ';'); + + idx = 0; + while (ch != EOF && ch != ' ' && ch != lineterm && ch != '\r' + && ch != '\t' && ch != ':' && ch != ';') + { + ident[idx++] = ch; + ch = fgetc(stream); + } /* while */ + + if (ch == EOF && idx < 1) return ((char *)NULL); + if (idx >= 1 && ch != ':' ) ungetc(ch, stream); + if (idx < 1 ) ident[idx++] = ch; /* single-character token */ + ident[idx] = 0; + + return(ident); /* returns pointer to the token */ + +} /* token */ + + +/*************************** linetoken *************************/ + +/* "linetoken" will get read all tokens until the EOL character from + * the given stream. This is used to get any arguments that can be + * more than one word (like Comment lines and FullName). + */ + +static char *linetoken( FILE* stream ) +{ + int ch, idx; + + while ((ch = fgetc(stream)) == ' ' || ch == '\t' ); + + idx = 0; + while (ch != EOF && ch != lineterm && ch != '\r') + { + ident[idx++] = ch; + ch = fgetc(stream); + } /* while */ + + ungetc(ch, stream); + ident[idx] = 0; + + return(ident); /* returns pointer to the token */ + +} /* linetoken */ + + +/*************************** recognize *************************/ + +/* This function tries to match a string to a known list of + * valid AFM entries (check the keyStrings array above). + * "ident" contains everything from white space through the + * next space, tab, or ":" character. + * + * The algorithm is a standard Knuth binary search. + */ + +static enum parseKey recognize( register char* ident) +{ + int lower = 0, upper = (int) NOPE, midpoint, cmpvalue; + bool found = false; + + while ((upper >= lower) && !found) + { + midpoint = (lower + upper)/2; + if (keyStrings[midpoint] == NULL) break; + cmpvalue = strncmp(ident, keyStrings[midpoint], MAX_NAME); + if (cmpvalue == 0) found = true; + else if (cmpvalue < 0) upper = midpoint - 1; + else lower = midpoint + 1; + } /* while */ + + if (found) return (enum parseKey) midpoint; + else return NOPE; + +} /* recognize */ + + +/************************* parseGlobals *****************************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "StartCharMetrics" keyword, which essentially marks the + * end of the Global Font Information and the beginning of the character + * metrics information. + * + * If the caller of "parseFile" specified that it wanted the Global + * Font Information (as defined by the "AFM File Specification" + * document), then that information will be stored in the returned + * data structure. + * + * Any Global Font Information entries that are not found in a + * given file, will have the usual default initialization value + * for its type (i.e. entries of type int will be 0, etc). + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static bool parseGlobals( FILE* fp, register GlobalFontInfo* gfi ) +{ + bool cont = true, save = (gfi != NULL); + int error = ok; + register char *keyword; + int direction = -1; + + while (cont) + { + keyword = token(fp); + + if (keyword == NULL) + /* Have reached an early and unexpected EOF. */ + /* Set flag and stop parsing */ + { + error = earlyEOF; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Global Font info section */ + /* without saving any of the data */ + switch (recognize(keyword)) + { + case STARTCHARMETRICS: + cont = false; + break; + case ENDFONTMETRICS: + cont = false; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire global font info section, */ + /* saving the data */ + switch(recognize(keyword)) + { + case STARTFONTMETRICS: + keyword = token(fp); + gfi->afmVersion = strdup( keyword ); + break; + case COMMENT: + keyword = linetoken(fp); + break; + case FONTNAME: + keyword = token(fp); + gfi->fontName = strdup( keyword ); + break; + case ENCODINGSCHEME: + keyword = token(fp); + gfi->encodingScheme = strdup( keyword ); + break; + case FULLNAME: + keyword = linetoken(fp); + gfi->fullName = strdup( keyword ); + break; + case FAMILYNAME: + keyword = linetoken(fp); + gfi->familyName = strdup( keyword ); + break; + case WEIGHT: + keyword = token(fp); + gfi->weight = strdup( keyword ); + break; + case ITALICANGLE: + keyword = token(fp); + gfi->italicAngle = StringToDouble( keyword ); + break; + case ISFIXEDPITCH: + keyword = token(fp); + if (MATCH(keyword, False)) + gfi->isFixedPitch = 0; + else + gfi->isFixedPitch = 1; + break; + case UNDERLINEPOSITION: + keyword = token(fp); + gfi->underlinePosition = atoi(keyword); + break; + case UNDERLINETHICKNESS: + keyword = token(fp); + gfi->underlineThickness = atoi(keyword); + break; + case VERSION: + keyword = token(fp); + gfi->version = strdup( keyword ); + break; + case NOTICE: + keyword = linetoken(fp); + gfi->notice = strdup( keyword ); + break; + case FONTBBOX: + keyword = token(fp); + gfi->fontBBox.llx = atoi(keyword); + keyword = token(fp); + gfi->fontBBox.lly = atoi(keyword); + keyword = token(fp); + gfi->fontBBox.urx = atoi(keyword); + keyword = token(fp); + gfi->fontBBox.ury = atoi(keyword); + break; + case CAPHEIGHT: + keyword = token(fp); + gfi->capHeight = atoi(keyword); + break; + case XHEIGHT: + keyword = token(fp); + gfi->xHeight = atoi(keyword); + break; + case DESCENT: + keyword = token(fp); + gfi->descender = -atoi(keyword); + break; + case DESCENDER: + keyword = token(fp); + gfi->descender = atoi(keyword); + break; + case ASCENT: + case ASCENDER: + keyword = token(fp); + gfi->ascender = atoi(keyword); + break; + case STARTCHARMETRICS: + cont = false; + break; + case ENDFONTMETRICS: + cont = false; + error = normalEOF; + break; + case EM: + // skip one token + keyword = token(fp); + break; + case STARTDIRECTION: + keyword = token(fp); + direction = atoi(keyword); + break; /* ignore this for now */ + case ENDDIRECTION: + break; /* ignore this for now */ + case MAPPINGSCHEME: + keyword = token(fp); + break; /* ignore this for now */ + case CHARACTERS: + keyword = token(fp); + break; /* ignore this for now */ + case ISBASEFONT: + keyword = token(fp); + break; /* ignore this for now */ + case CHARWIDTH: + keyword = token(fp); + if (direction == 0) + gfi->charwidth = atoi(keyword); + keyword = token(fp); + /* ignore y-width for now */ + break; + case METRICSSETS: + keyword = token(fp); + break; /* ignore this for now */ + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + return(error); + +} /* parseGlobals */ + + + +/************************* initializeArray ************************/ + +/* Unmapped character codes are (at Adobe Systems) assigned the + * width of the space character (if one exists) else they get the + * value of 250 ems. This function initializes all entries in the + * char widths array to have this value. Then any mapped character + * codes will be replaced with the width of the appropriate character + * when parsing the character metric section. + + * This function parses the Character Metrics Section looking + * for a space character (by comparing character names). If found, + * the width of the space character will be used to initialize the + * values in the array of character widths. + * + * Before returning, the position of the read/write pointer of the + * file is reset to be where it was upon entering this function. + */ + +static int initializeArray( FILE* fp, register int* cwi) +{ + bool cont = true, found = false; + long opos = ftell(fp); + int code = 0, width = 0, i = 0, error = 0; + register char *keyword; + + while (cont) + { + keyword = token(fp); + if (keyword == NULL) + { + error = earlyEOF; + break; /* get out of loop */ + } + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case CODE: + code = atoi(token(fp)); + break; + case CODEHEX: + sscanf(token(fp),"<%x>", &code); + break; + case XWIDTH: + width = atoi(token(fp)); + break; + case X0WIDTH: + (void) token(fp); + break; + case CHARNAME: + keyword = token(fp); + if (MATCH(keyword, Space)) + { + cont = false; + found = true; + } + break; + case ENDCHARMETRICS: + cont = false; + break; + case ENDFONTMETRICS: + cont = false; + error = normalEOF; + break; + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + if (!found) + width = 250; + + for (i = 0; i < 256; ++i) + cwi[i] = width; + + fseek(fp, opos, 0); + + return(error); + +} /* initializeArray */ + + +/************************* parseCharWidths **************************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "EndCharMetrics" keyword. It will save the character + * width info (as opposed to all of the character metric information) + * if requested by the caller of parseFile. Otherwise, it will just + * parse through the section without saving any information. + * + * If data is to be saved, parseCharWidths is passed in a pointer + * to an array of widths that has already been initialized by the + * standard value for unmapped character codes. This function parses + * the Character Metrics section only storing the width information + * for the encoded characters into the array using the character code + * as the index into that array. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static parseCharWidths( FILE* fp, register int* cwi) +{ + bool cont = true, save = (cwi != NULL); + int pos = 0, error = ok; + register char *keyword; + + while (cont) + { + keyword = token(fp); + /* Have reached an early and unexpected EOF. */ + /* Set flag and stop parsing */ + if (keyword == NULL) + { + error = earlyEOF; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Char Metrics section without */ + /* saving any of the data*/ + switch (recognize(keyword)) + { + case ENDCHARMETRICS: + cont = false; + break; + case ENDFONTMETRICS: + cont = false; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire char metrics section, saving */ + /* only the char x-width info */ + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case CODE: + keyword = token(fp); + pos = atoi(keyword); + break; + case XYWIDTH: + /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */ + keyword = token(fp); keyword = token(fp); /* eat values */ + error = parseError; + break; + case CODEHEX: + keyword = token(fp); + sscanf(keyword, "<%x>", &pos); + break; + case X0WIDTH: + (void) token(fp); + break; + case XWIDTH: + keyword = token(fp); + if (pos >= 0) /* ignore unmapped chars */ + cwi[pos] = atoi(keyword); + break; + case ENDCHARMETRICS: + cont = false; + break; + case ENDFONTMETRICS: + cont = false; + error = normalEOF; + break; + case CHARNAME: /* eat values (so doesn't cause parseError) */ + keyword = token(fp); + break; + case CHARBBOX: + keyword = token(fp); keyword = token(fp); + keyword = token(fp); keyword = token(fp); + break; + case LIGATURE: + keyword = token(fp); keyword = token(fp); + break; + case VVECTOR: + keyword = token(fp); + keyword = token(fp); + break; + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + return(error); + +} /* parseCharWidths */ + + +/* + * number of char metrics is almost allways inaccurate, so be gentle and try to + * adapt our internal storage by adjusting the allocated list + */ + +static int +reallocFontMetrics( void **pp_fontmetrics, int *p_oldcount, unsigned int n_newcount, + unsigned int n_size ) +{ + char *p_tmpmetrics = NULL; + + if ((pp_fontmetrics == NULL) || (*pp_fontmetrics == NULL)) + return storageProblem; + + if (*p_oldcount == n_newcount) + return ok; + + p_tmpmetrics = (char*)realloc(*pp_fontmetrics, n_newcount * n_size); + if (p_tmpmetrics == NULL) + return storageProblem; + + if ( n_newcount > *p_oldcount ) + { + char *p_inimetrics = p_tmpmetrics + n_size * *p_oldcount; + int n_inimetrics = n_size * (n_newcount - *p_oldcount); + memset( p_inimetrics, 0, n_inimetrics ); + } + + *pp_fontmetrics = p_tmpmetrics; + *p_oldcount = n_newcount; + + return ok; +} + +static unsigned int +enlargeCount( unsigned int n_oldcount ) +{ + unsigned int n_newcount = n_oldcount + n_oldcount / 5; + if (n_oldcount == n_newcount ) + n_newcount = n_oldcount + 5; + + return n_newcount; +} + +/************************* parseCharMetrics ************************/ + +/* This function is called by parseFile if the caller of parseFile + * requested that all character metric information be saved + * (as opposed to only the character width information). + * + * parseCharMetrics is passed in a pointer to an array of records + * to hold information on a per character basis. This function + * parses the Character Metrics section storing all character + * metric information for the ALL characters (mapped and unmapped) + * into the array. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static parseCharMetrics( FILE* fp, register FontInfo* fi) +{ + bool cont = true, firstTime = true; + int error = ok, count = 0; + register CharMetricInfo *temp = fi->cmi; + register char *keyword; + + while (cont) + { + keyword = token(fp); + if (keyword == NULL) + { + error = earlyEOF; + break; /* get out of loop */ + } + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case CODE: + if (!(count < fi->numOfChars)) + { + reallocFontMetrics( (void**)&(fi->cmi), + &(fi->numOfChars), enlargeCount(fi->numOfChars), + sizeof(CharMetricInfo) ); + temp = &(fi->cmi[ count - 1 ]); + } + if (count < fi->numOfChars) + { + if (firstTime) firstTime = false; + else temp++; + temp->code = atoi(token(fp)); + if (fi->gfi && fi->gfi->charwidth) + temp->wx = fi->gfi->charwidth; + count++; + } + else + { + error = parseError; + cont = false; + } + break; + case CODEHEX: + if (!(count < fi->numOfChars )) + { + reallocFontMetrics( (void**)&(fi->cmi), + &(fi->numOfChars), enlargeCount(fi->numOfChars), + sizeof(CharMetricInfo) ); + temp = &(fi->cmi[ count - 1 ]); + } + if (count < fi->numOfChars) { + if (firstTime) + firstTime = FALSE; + else + temp++; + sscanf(token(fp),"<%x>", &temp->code); + if (fi->gfi && fi->gfi->charwidth) + temp->wx = fi->gfi->charwidth; + count++; + } + else { + error = parseError; + cont = FALSE; + } + break; + case XYWIDTH: + temp->wx = atoi(token(fp)); + temp->wy = atoi(token(fp)); + break; + case X0WIDTH: + temp->wx = atoi(token(fp)); + break; + case XWIDTH: + temp->wx = atoi(token(fp)); + break; + case CHARNAME: + keyword = token(fp); + temp->name = (char *) malloc(strlen(keyword) + 1); + strcpy(temp->name, keyword); + break; + case CHARBBOX: + temp->charBBox.llx = atoi(token(fp)); + temp->charBBox.lly = atoi(token(fp)); + temp->charBBox.urx = atoi(token(fp)); + temp->charBBox.ury = atoi(token(fp)); + break; + case LIGATURE: { + Ligature **tail = &(temp->ligs); + Ligature *node = *tail; + + if (*tail != NULL) + { + while (node->next != NULL) + node = node->next; + tail = &(node->next); + } + + *tail = (Ligature *) calloc(1, sizeof(Ligature)); + keyword = token(fp); + (*tail)->succ = (char *) malloc(strlen(keyword) + 1); + strcpy((*tail)->succ, keyword); + keyword = token(fp); + (*tail)->lig = (char *) malloc(strlen(keyword) + 1); + strcpy((*tail)->lig, keyword); + break; } + case ENDCHARMETRICS: + cont = false;; + break; + case ENDFONTMETRICS: + cont = false; + error = normalEOF; + break; + case VVECTOR: + keyword = token(fp); + keyword = token(fp); + break; + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + if ((error == ok) && (count != fi->numOfChars)) + error = reallocFontMetrics( (void**)&(fi->cmi), &(fi->numOfChars), + count, sizeof(CharMetricInfo) ); + + if ((error == ok) && (count != fi->numOfChars)) + error = parseError; + + return(error); + +} /* parseCharMetrics */ + + + +/************************* parseTrackKernData ***********************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "EndTrackKern" or "EndKernData" keywords. It will save the + * track kerning data if requested by the caller of parseFile. + * + * parseTrackKernData is passed in a pointer to the FontInfo record. + * If data is to be saved, the FontInfo record will already contain + * a valid pointer to storage for the track kerning data. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static parseTrackKernData( FILE* fp, register FontInfo* fi) +{ + bool cont = true, save = (fi->tkd != NULL); + int pos = 0, error = ok, tcount = 0; + register char *keyword; + + while (cont) + { + keyword = token(fp); + + if (keyword == NULL) + { + error = earlyEOF; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Track Kerning Data */ + /* section without saving any of the data */ + switch(recognize(keyword)) + { + case ENDTRACKKERN: + case ENDKERNDATA: + cont = false; + break; + case ENDFONTMETRICS: + cont = false; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire Track Kerning Data section, */ + /* saving the data */ + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case TRACKKERN: + if (!(tcount < fi->numOfTracks)) + { + reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks), + enlargeCount(fi->numOfTracks), sizeof(TrackKernData) ); + } + + if (tcount < fi->numOfTracks) + { + keyword = token(fp); + fi->tkd[pos].degree = atoi(keyword); + keyword = token(fp); + fi->tkd[pos].minPtSize = StringToDouble(keyword); + keyword = token(fp); + fi->tkd[pos].minKernAmt = StringToDouble(keyword); + keyword = token(fp); + fi->tkd[pos].maxPtSize = StringToDouble(keyword); + keyword = token(fp); + fi->tkd[pos++].maxKernAmt = StringToDouble(keyword); + tcount++; + } + else + { + error = parseError; + cont = false; + } + break; + case ENDTRACKKERN: + case ENDKERNDATA: + cont = false; + break; + case ENDFONTMETRICS: + cont = false; + error = normalEOF; + break; + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + if (error == ok && tcount != fi->numOfTracks) + error = reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks), + tcount, sizeof(TrackKernData) ); + + if (error == ok && tcount != fi->numOfTracks) + error = parseError; + + return(error); + +} /* parseTrackKernData */ + + +/************************* parsePairKernData ************************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "EndKernPairs" or "EndKernData" keywords. It will save + * the pair kerning data if requested by the caller of parseFile. + * + * parsePairKernData is passed in a pointer to the FontInfo record. + * If data is to be saved, the FontInfo record will already contain + * a valid pointer to storage for the pair kerning data. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static parsePairKernData( FILE* fp, register FontInfo* fi) +{ + bool cont = true, save = (fi->pkd != NULL); + int pos = 0, error = ok, pcount = 0; + register char *keyword; + + while (cont) + { + keyword = token(fp); + + if (keyword == NULL) + { + error = earlyEOF; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Pair Kerning Data */ + /* section without saving any of the data */ + switch(recognize(keyword)) + { + case ENDKERNPAIRS: + case ENDKERNDATA: + cont = false; + break; + case ENDFONTMETRICS: + cont = false; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire Pair Kerning Data section, */ + /* saving the data */ + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case KERNPAIR: + if (!(pcount < fi->numOfPairs)) + { + reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs), + enlargeCount(fi->numOfPairs), sizeof(PairKernData) ); + } + if (pcount < fi->numOfPairs) + { + keyword = token(fp); + fi->pkd[pos].name1 = strdup( keyword ); + keyword = token(fp); + fi->pkd[pos].name2 = strdup( keyword ); + keyword = token(fp); + fi->pkd[pos].xamt = atoi(keyword); + keyword = token(fp); + fi->pkd[pos++].yamt = atoi(keyword); + pcount++; + } + else + { + error = parseError; + cont = false; + } + break; + case KERNPAIRXAMT: + if (!(pcount < fi->numOfPairs)) + { + reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs), + enlargeCount(fi->numOfPairs), sizeof(PairKernData) ); + } + if (pcount < fi->numOfPairs) + { + keyword = token(fp); + fi->pkd[pos].name1 = strdup( keyword ); + keyword = token(fp); + fi->pkd[pos].name2 = strdup( keyword ); + keyword = token(fp); + fi->pkd[pos++].xamt = atoi(keyword); + pcount++; + } + else + { + error = parseError; + cont = false; + } + break; + case ENDKERNPAIRS: + case ENDKERNDATA: + cont = false; + break; + case ENDFONTMETRICS: + cont = false; + error = normalEOF; + break; + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + if ((error == ok) && (pcount != fi->numOfPairs)) + error = reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs), + pcount, sizeof(PairKernData) ); + + if (error == ok && pcount != fi->numOfPairs) + error = parseError; + + return(error); + +} /* parsePairKernData */ + + +/************************* parseCompCharData **************************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "EndComposites" keyword. It will save the composite + * character data if requested by the caller of parseFile. + * + * parseCompCharData is passed in a pointer to the FontInfo record, and + * a boolean representing if the data should be saved. + * + * This function will create the appropriate amount of storage for + * the composite character data and store a pointer to the storage + * in the FontInfo record. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static parseCompCharData( FILE* fp, register FontInfo* fi) +{ + bool cont = true, firstTime = true, save = (fi->ccd != NULL); + int pos = 0, j = 0, error = ok, ccount = 0, pcount = 0; + register char *keyword; + + while (cont) + { + keyword = token(fp); + if (keyword == NULL) + /* Have reached an early and unexpected EOF. */ + /* Set flag and stop parsing */ + { + error = earlyEOF; + break; /* get out of loop */ + } + if (ccount > fi->numOfComps) + { + reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps), + enlargeCount(fi->numOfComps), sizeof(CompCharData) ); + } + if (ccount > fi->numOfComps) + { + error = parseError; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Composite Character info */ + /* section without saving any of the data */ + switch(recognize(keyword)) + { + case ENDCOMPOSITES: + cont = false; + break; + case ENDFONTMETRICS: + cont = false; + error = normalEOF; + break; + case COMMENT: + case COMPCHAR: + keyword = linetoken(fp); + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire Composite Character info section, */ + /* saving the data */ + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case COMPCHAR: + if (!(ccount < fi->numOfComps)) + { + reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps), + enlargeCount(fi->numOfComps), sizeof(CompCharData) ); + } + if (ccount < fi->numOfComps) + { + keyword = token(fp); + if (pcount != fi->ccd[pos].numOfPieces) + error = parseError; + pcount = 0; + if (firstTime) firstTime = false; + else pos++; + fi->ccd[pos].ccName = strdup( keyword ); + keyword = token(fp); + fi->ccd[pos].numOfPieces = atoi(keyword); + fi->ccd[pos].pieces = (Pcc *) + calloc(fi->ccd[pos].numOfPieces, sizeof(Pcc)); + j = 0; + ccount++; + } + else + { + error = parseError; + cont = false; + } + break; + case COMPCHARPIECE: + if (pcount < fi->ccd[pos].numOfPieces) + { + keyword = token(fp); + fi->ccd[pos].pieces[j].pccName = strdup( keyword ); + keyword = token(fp); + fi->ccd[pos].pieces[j].deltax = atoi(keyword); + keyword = token(fp); + fi->ccd[pos].pieces[j++].deltay = atoi(keyword); + pcount++; + } + else + error = parseError; + break; + case ENDCOMPOSITES: + cont = false; + break; + case ENDFONTMETRICS: + cont = false; + error = normalEOF; + break; + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + if (error == ok && ccount != fi->numOfComps) + reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps), + ccount, sizeof(CompCharData) ); + + if (error == ok && ccount != fi->numOfComps) + error = parseError; + + return(error); + +} /* parseCompCharData */ + + + + +/*************************** 'PUBLIC' FUNCTION ********************/ + + +/*************************** parseFile *****************************/ + +/* parseFile is the only 'public' procedure available. It is called + * from an application wishing to get information from an AFM file. + * The caller of this function is responsible for locating and opening + * an AFM file and handling all errors associated with that task. + * + * parseFile expects 3 parameters: a vaild file pointer, a pointer + * to a (FontInfo *) variable (for which storage will be allocated and + * the data requested filled in), and a mask specifying which + * data from the AFM File should be saved in the FontInfo structure. + * + * The file will be parsed and the requested data will be stored in + * a record of type FontInfo (refer to ParseAFM.h). + * + * parseFile returns an error code as defined in parseAFM.h. + * + * The position of the read/write pointer associated with the file + * pointer upon return of this function is undefined. + */ + +int parseFile ( FILE* fp, FontInfo** fi, FLAGS flags) +{ + + int code = ok; /* return code from each of the parsing routines */ + int error = ok; /* used as the return code from this function */ + + register char *keyword; /* used to store a token */ + + + /* storage data for the global variable ident */ + ident = (char *) calloc(MAX_NAME, sizeof(char)); + if (ident == NULL) {error = storageProblem; return(error);} + + (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo)); + if ((*fi) == NULL) {error = storageProblem; return(error);} + + if (flags & P_G) + { + (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo)); + if ((*fi)->gfi == NULL) {error = storageProblem; return(error);} + } + + /* The AFM File begins with Global Font Information. This section */ + /* will be parsed whether or not information should be saved. */ + code = parseGlobals(fp, (*fi)->gfi); + + if (code < 0) error = code; + + /* The Global Font Information is followed by the Character Metrics */ + /* section. Which procedure is used to parse this section depends on */ + /* how much information should be saved. If all of the metrics info */ + /* is wanted, parseCharMetrics is called. If only the character widths */ + /* is wanted, parseCharWidths is called. parseCharWidths will also */ + /* be called in the case that no character data is to be saved, just */ + /* to parse through the section. */ + + if ((code != normalEOF) && (code != earlyEOF)) + { + (*fi)->numOfChars = atoi(token(fp)); + if (flags & (P_M ^ P_W)) + { + (*fi)->cmi = (CharMetricInfo *) + calloc((*fi)->numOfChars, sizeof(CharMetricInfo)); + if ((*fi)->cmi == NULL) {error = storageProblem; return(error);} + code = parseCharMetrics(fp, *fi); + } + else + { + if (flags & P_W) + { + (*fi)->cwi = (int *) calloc(256, sizeof(int)); + if ((*fi)->cwi == NULL) + { + error = storageProblem; + return(error); + } + } + /* parse section regardless */ + code = parseCharWidths(fp, (*fi)->cwi); + } /* else */ + } /* if */ + + if ((error != earlyEOF) && (code < 0)) error = code; + + /* The remaining sections of the AFM are optional. This code will */ + /* look at the next keyword in the file to determine what section */ + /* is next, and then allocate the appropriate amount of storage */ + /* for the data (if the data is to be saved) and call the */ + /* appropriate parsing routine to parse the section. */ + + while ((code != normalEOF) && (code != earlyEOF)) + { + keyword = token(fp); + if (keyword == NULL) + /* Have reached an early and unexpected EOF. */ + /* Set flag and stop parsing */ + { + code = earlyEOF; + break; /* get out of loop */ + } + switch(recognize(keyword)) + { + case STARTKERNDATA: + break; + case ENDKERNDATA: + break; + case STARTTRACKKERN: + keyword = token(fp); + if (flags & P_T) + { + (*fi)->numOfTracks = atoi(keyword); + (*fi)->tkd = (TrackKernData *) + calloc((*fi)->numOfTracks, sizeof(TrackKernData)); + if ((*fi)->tkd == NULL) + { + error = storageProblem; + return(error); + } + } /* if */ + code = parseTrackKernData(fp, *fi); + break; + case STARTKERNPAIRS: + keyword = token(fp); + if (flags & P_P) + { + (*fi)->numOfPairs = atoi(keyword); + (*fi)->pkd = (PairKernData *) + calloc((*fi)->numOfPairs, sizeof(PairKernData)); + if ((*fi)->pkd == NULL) + { + error = storageProblem; + return(error); + } + } /* if */ + code = parsePairKernData(fp, *fi); + break; + case STARTCOMPOSITES: + keyword = token(fp); + if (flags & P_C) + { + (*fi)->numOfComps = atoi(keyword); + (*fi)->ccd = (CompCharData *) + calloc((*fi)->numOfComps, sizeof(CompCharData)); + if ((*fi)->ccd == NULL) + { + error = storageProblem; + return(error); + } + } /* if */ + code = parseCompCharData(fp, *fi); + break; + case ENDFONTMETRICS: + code = normalEOF; + break; + case COMMENT: + linetoken(fp); + break; + case NOPE: + default: + code = parseError; + break; + } /* switch */ + + if ((error != earlyEOF) && (code < 0)) error = code; + + } /* while */ + + if ((error != earlyEOF) && (code < 0)) error = code; + + if (ident != NULL) { free(ident); ident = NULL; } + + return(error); + +} /* parseFile */ + +void +freeFontInfo (FontInfo *fi) +{ + int i, j; + + if (fi->gfi) + { + free (fi->gfi->afmVersion); + free (fi->gfi->fontName); + free (fi->gfi->fullName); + free (fi->gfi->familyName); + free (fi->gfi->weight); + free (fi->gfi->version); + free (fi->gfi->notice); + free (fi->gfi->encodingScheme); + free (fi->gfi); + } + + free (fi->cwi); + + if (fi->cmi) + { + for (i = 0; i < fi->numOfChars; i++) + { + Ligature *ligs; + free (fi->cmi[i].name); + ligs = fi->cmi[i].ligs; + while (ligs) + { + Ligature *tmp; + tmp = ligs; + ligs = ligs->next; + free (tmp->succ); + free (tmp->lig); + free (tmp); + } + } + free (fi->cmi); + } + + free (fi->tkd); + + if (fi->pkd) + { + for (int i = 0; i < fi->numOfPairs; i++) + { + free (fi->pkd[i].name1); + free (fi->pkd[i].name2); + } + free (fi->pkd); + } + + if (fi->ccd) + { + for (i = 0; i < fi->numOfComps; i++) + { + free (fi->ccd[i].ccName); + for (j = 0; j < fi->ccd[i].numOfPieces; j++) + free (fi->ccd[i].pieces[j].pccName); + + free (fi->ccd[i].pieces); + } + free (fi->ccd); + } + + free (fi); +} + +} // namspace diff --git a/psprint/source/fontmanager/parseAFM.hxx b/psprint/source/fontmanager/parseAFM.hxx new file mode 100644 index 000000000000..ab0d1d961448 --- /dev/null +++ b/psprint/source/fontmanager/parseAFM.hxx @@ -0,0 +1,343 @@ +/* + * (C) 1988, 1989 by Adobe Systems Incorporated. All rights reserved. + * + * This file may be freely copied and redistributed as long as: + * 1) This entire notice continues to be included in the file, + * 2) If the file has been modified in any way, a notice of such + * modification is conspicuously indicated. + * + * PostScript, Display PostScript, and Adobe are registered trademarks of + * Adobe Systems Incorporated. + * + * ************************************************************************ + * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT + * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS + * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR + * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY + * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION, + * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + * ************************************************************************ + */ + +/* + * Changes made for OpenOffice.org + * + * 10/24/2000 pl - changed code to compile with c++-compilers + * - added namespace to avoid symbol clashes + * - replaced BOOL by bool + * - added function to free space allocated by parseFile + * 10/26/2000 pl - added additional keys + * - added ability to parse slightly broken files + * - added charwidth member to GlobalFontInfo + * 04/26/2001 pl - added OpenOffice header + */ + +/************************************************************************* + * + * $RCSfile: parseAFM.hxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:36 $ + * + ************************************************************************/ + +/* ParseAFM.h + * + * This header file is used in conjuction with the parseAFM.c file. + * Together these files provide the functionality to parse Adobe Font + * Metrics files and store the information in predefined data structures. + * It is intended to work with an application program that needs font metric + * information. The program can be used as is by making a procedure call to + * parse an AFM file and have the data stored, or an application developer + * may wish to customize the code. + * + * This header file defines the data structures used as well as the key + * strings that are currently recognized by this version of the AFM parser. + * This program is based on the document "Adobe Font Metrics Files, + * Specification Version 2.0". + * + * AFM files are separated into distinct sections of different data. Because + * of this, the parseAFM program can parse a specified file to only save + * certain sections of information based on the application's needs. A record + * containing the requested information will be returned to the application. + * + * AFM files are divided into five sections of data: + * 1) The Global Font Information + * 2) The Character Metrics Information + * 3) The Track Kerning Data + * 4) The Pair-Wise Kerning Data + * 5) The Composite Character Data + * + * Basically, the application can request any of these sections independent + * of what other sections are requested. In addition, in recognizing that + * many applications will want ONLY the x-width of characters and not all + * of the other character metrics information, there is a way to receive + * only the width information so as not to pay the storage cost for the + * unwanted data. An application should never request both the + * "quick and dirty" char metrics (widths only) and the Character Metrics + * Information since the Character Metrics Information will contain all + * of the character widths as well. + * + * There is a procedure in parseAFM.c, called parseFile, that can be + * called from any application wishing to get information from the AFM File. + * This procedure expects 3 parameters: a vaild file descriptor, a pointer + * to a (FontInfo *) variable (for which space will be allocated and then + * will be filled in with the data requested), and a mask specifying + * which data from the AFM File should be saved in the FontInfo structure. + * + * The flags that can be used to set the appropriate mask are defined below. + * In addition, several commonly used masks have already been defined. + * + * History: + * original: DSM Thu Oct 20 17:39:59 PDT 1988 + * modified: DSM Mon Jul 3 14:17:50 PDT 1989 + * - added 'storageProblem' return code + * - fixed typos + */ + +#include <stdio.h> + +namespace psp { + +/* your basic constants */ +#define EOL '\n' /* end-of-line indicator */ +#define MAX_NAME 4096 /* max length for identifiers */ +#define FLAGS int + + + +/* Flags that can be AND'ed together to specify exactly what + * information from the AFM file should be saved. + */ +#define P_G 0x01 /* 0000 0001 */ /* Global Font Info */ +#define P_W 0x02 /* 0000 0010 */ /* Character Widths ONLY */ +#define P_M 0x06 /* 0000 0110 */ /* All Char Metric Info */ +#define P_P 0x08 /* 0000 1000 */ /* Pair Kerning Info */ +#define P_T 0x10 /* 0001 0000 */ /* Track Kerning Info */ +#define P_C 0x20 /* 0010 0000 */ /* Composite Char Info */ + + +/* Commonly used flags + */ +#define P_GW (P_G | P_W) +#define P_GM (P_G | P_M) +#define P_GMP (P_G | P_M | P_P) +#define P_GMK (P_G | P_M | P_P | P_T) +#define P_ALL (P_G | P_M | P_P | P_T | P_C) + + + +/* Possible return codes from the parseFile procedure. + * + * ok means there were no problems parsing the file. + * + * parseError means that there was some kind of parsing error, but the + * parser went on. This could include problems like the count for any given + * section does not add up to how many entries there actually were, or + * there was a key that was not recognized. The return record may contain + * vaild data or it may not. + * + * earlyEOF means that an End of File was encountered before expected. This + * may mean that the AFM file had been truncated, or improperly formed. + * + * storageProblem means that there were problems allocating storage for + * the data structures that would have contained the AFM data. + */ + +enum afmError { ok = 0, parseError = -1, earlyEOF = -2, storageProblem = -3 }; + + +/************************* TYPES *********************************/ +/* Below are all of the data structure definitions. These structures + * try to map as closely as possible to grouping and naming of data + * in the AFM Files. + */ + + +/* Bounding box definition. Used for the Font BBox as well as the + * Character BBox. + */ +typedef struct +{ + int llx; /* lower left x-position */ + int lly; /* lower left y-position */ + int urx; /* upper right x-position */ + int ury; /* upper right y-position */ +} BBox; + + +/* Global Font information. + * The key that each field is associated with is in comments. For an + * explanation about each key and its value please refer to the AFM + * documentation (full title & version given above). + */ +typedef struct +{ + char *afmVersion; /* key: StartFontMetrics */ + char *fontName; /* key: FontName */ + char *fullName; /* key: FullName */ + char *familyName; /* key: FamilyName */ + char *weight; /* key: Weight */ + float italicAngle; /* key: ItalicAngle */ + bool isFixedPitch; /* key: IsFixedPitch */ + BBox fontBBox; /* key: FontBBox */ + int underlinePosition; /* key: UnderlinePosition */ + int underlineThickness; /* key: UnderlineThickness */ + char *version; /* key: Version */ + char *notice; /* key: Notice */ + char *encodingScheme; /* key: EncodingScheme */ + int capHeight; /* key: CapHeight */ + int xHeight; /* key: XHeight */ + int ascender; /* key: Ascender */ + int descender; /* key: Descender */ + int charwidth; /* key: CharWidth */ +} GlobalFontInfo; + + +/* Ligature definition is a linked list since any character can have + * any number of ligatures. + */ +typedef struct _t_ligature +{ + char *succ, *lig; + struct _t_ligature *next; +} Ligature; + + +/* Character Metric Information. This structure is used only if ALL + * character metric information is requested. If only the character + * widths is requested, then only an array of the character x-widths + * is returned. + * + * The key that each field is associated with is in comments. For an + * explanation about each key and its value please refer to the + * Character Metrics section of the AFM documentation (full title + * & version given above). + */ +typedef struct +{ + int code, /* key: C */ + wx, /* key: WX */ + w0x, /* key: W0X */ + wy; /* together wx and wy are associated with key: W */ + char *name; /* key: N */ + BBox charBBox; /* key: B */ + Ligature *ligs; /* key: L (linked list; not a fixed number of Ls */ +} CharMetricInfo; + + +/* Track kerning data structure. + * The fields of this record are the five values associated with every + * TrackKern entry. + * + * For an explanation about each value please refer to the + * Track Kerning section of the AFM documentation (full title + * & version given above). + */ +typedef struct +{ + int degree; + float minPtSize, + minKernAmt, + maxPtSize, + maxKernAmt; +} TrackKernData; + + +/* Pair Kerning data structure. + * The fields of this record are the four values associated with every + * KP entry. For KPX entries, the yamt will be zero. + * + * For an explanation about each value please refer to the + * Pair Kerning section of the AFM documentation (full title + * & version given above). + */ +typedef struct +{ + char *name1; + char *name2; + int xamt, + yamt; +} PairKernData; + + +/* PCC is a piece of a composite character. This is a sub structure of a + * compCharData described below. + * These fields will be filled in with the values from the key PCC. + * + * For an explanation about each key and its value please refer to the + * Composite Character section of the AFM documentation (full title + * & version given above). + */ +typedef struct +{ + char *pccName; + int deltax, + deltay; +} Pcc; + + +/* Composite Character Information data structure. + * The fields ccName and numOfPieces are filled with the values associated + * with the key CC. The field pieces points to an array (size = numOfPieces) + * of information about each of the parts of the composite character. That + * array is filled in with the values from the key PCC. + * + * For an explanation about each key and its value please refer to the + * Composite Character section of the AFM documentation (full title + * & version given above). + */ +typedef struct +{ + char *ccName; + int numOfPieces; + Pcc *pieces; +} CompCharData; + + +/* FontInfo + * Record type containing pointers to all of the other data + * structures containing information about a font. + * A a record of this type is filled with data by the + * parseFile function. + */ +typedef struct +{ + GlobalFontInfo *gfi; /* ptr to a GlobalFontInfo record */ + int *cwi; /* ptr to 256 element array of just char widths */ + int numOfChars; /* number of entries in char metrics array */ + CharMetricInfo *cmi; /* ptr to char metrics array */ + int numOfTracks; /* number to entries in track kerning array */ + TrackKernData *tkd; /* ptr to track kerning array */ + int numOfPairs; /* number to entries in pair kerning array */ + PairKernData *pkd; /* ptr to pair kerning array */ + int numOfComps; /* number to entries in comp char array */ + CompCharData *ccd; /* ptr to comp char array */ +} FontInfo; + + + +/************************* PROCEDURES ****************************/ + +/* Call this procedure to do the grunt work of parsing an AFM file. + * + * "fp" should be a valid file pointer to an AFM file. + * + * "fi" is a pointer to a pointer to a FontInfo record sturcture + * (defined above). Storage for the FontInfo structure will be + * allocated in parseFile and the structure will be filled in + * with the requested data from the AFM File. + * + * "flags" is a mask with bits set representing what data should + * be saved. Defined above are valid flags that can be used to set + * the mask, as well as a few commonly used masks. + * + * The possible return codes from parseFile are defined above. + */ + +int parseFile( FILE *fp, FontInfo **fi, FLAGS flags ); +void freeFontInfo(FontInfo *fi); + +} // namespace diff --git a/psprint/source/fontsubset/crc32.c b/psprint/source/fontsubset/crc32.c new file mode 100644 index 000000000000..f614696fa5e6 --- /dev/null +++ b/psprint/source/fontsubset/crc32.c @@ -0,0 +1,120 @@ +/************************************************************************* + * + * $RCSfile: crc32.c,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:36 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Alexander Gelfenbain + * + * + ************************************************************************/ + +/* $Id: crc32.c,v 1.1.1.1 2001-05-08 11:45:36 pl Exp $ */ + +/** + * + * @file crc32.c + * @brief CRC-32 calculation function + * @author Alexander Gelfenbain + */ + +#include "sft.h" +#include "crc32.h" + +static uint32 crcTable[256] = { + 0x00000000UL, 0x77073096UL, 0xEE0E612CUL, 0x990951BAUL, 0x076DC419UL, 0x706AF48FUL, 0xE963A535UL, 0x9E6495A3UL, + 0x0EDB8832UL, 0x79DCB8A4UL, 0xE0D5E91EUL, 0x97D2D988UL, 0x09B64C2BUL, 0x7EB17CBDUL, 0xE7B82D07UL, 0x90BF1D91UL, + 0x1DB71064UL, 0x6AB020F2UL, 0xF3B97148UL, 0x84BE41DEUL, 0x1ADAD47DUL, 0x6DDDE4EBUL, 0xF4D4B551UL, 0x83D385C7UL, + 0x136C9856UL, 0x646BA8C0UL, 0xFD62F97AUL, 0x8A65C9ECUL, 0x14015C4FUL, 0x63066CD9UL, 0xFA0F3D63UL, 0x8D080DF5UL, + 0x3B6E20C8UL, 0x4C69105EUL, 0xD56041E4UL, 0xA2677172UL, 0x3C03E4D1UL, 0x4B04D447UL, 0xD20D85FDUL, 0xA50AB56BUL, + 0x35B5A8FAUL, 0x42B2986CUL, 0xDBBBC9D6UL, 0xACBCF940UL, 0x32D86CE3UL, 0x45DF5C75UL, 0xDCD60DCFUL, 0xABD13D59UL, + 0x26D930ACUL, 0x51DE003AUL, 0xC8D75180UL, 0xBFD06116UL, 0x21B4F4B5UL, 0x56B3C423UL, 0xCFBA9599UL, 0xB8BDA50FUL, + 0x2802B89EUL, 0x5F058808UL, 0xC60CD9B2UL, 0xB10BE924UL, 0x2F6F7C87UL, 0x58684C11UL, 0xC1611DABUL, 0xB6662D3DUL, + 0x76DC4190UL, 0x01DB7106UL, 0x98D220BCUL, 0xEFD5102AUL, 0x71B18589UL, 0x06B6B51FUL, 0x9FBFE4A5UL, 0xE8B8D433UL, + 0x7807C9A2UL, 0x0F00F934UL, 0x9609A88EUL, 0xE10E9818UL, 0x7F6A0DBBUL, 0x086D3D2DUL, 0x91646C97UL, 0xE6635C01UL, + 0x6B6B51F4UL, 0x1C6C6162UL, 0x856530D8UL, 0xF262004EUL, 0x6C0695EDUL, 0x1B01A57BUL, 0x8208F4C1UL, 0xF50FC457UL, + 0x65B0D9C6UL, 0x12B7E950UL, 0x8BBEB8EAUL, 0xFCB9887CUL, 0x62DD1DDFUL, 0x15DA2D49UL, 0x8CD37CF3UL, 0xFBD44C65UL, + 0x4DB26158UL, 0x3AB551CEUL, 0xA3BC0074UL, 0xD4BB30E2UL, 0x4ADFA541UL, 0x3DD895D7UL, 0xA4D1C46DUL, 0xD3D6F4FBUL, + 0x4369E96AUL, 0x346ED9FCUL, 0xAD678846UL, 0xDA60B8D0UL, 0x44042D73UL, 0x33031DE5UL, 0xAA0A4C5FUL, 0xDD0D7CC9UL, + 0x5005713CUL, 0x270241AAUL, 0xBE0B1010UL, 0xC90C2086UL, 0x5768B525UL, 0x206F85B3UL, 0xB966D409UL, 0xCE61E49FUL, + 0x5EDEF90EUL, 0x29D9C998UL, 0xB0D09822UL, 0xC7D7A8B4UL, 0x59B33D17UL, 0x2EB40D81UL, 0xB7BD5C3BUL, 0xC0BA6CADUL, + 0xEDB88320UL, 0x9ABFB3B6UL, 0x03B6E20CUL, 0x74B1D29AUL, 0xEAD54739UL, 0x9DD277AFUL, 0x04DB2615UL, 0x73DC1683UL, + 0xE3630B12UL, 0x94643B84UL, 0x0D6D6A3EUL, 0x7A6A5AA8UL, 0xE40ECF0BUL, 0x9309FF9DUL, 0x0A00AE27UL, 0x7D079EB1UL, + 0xF00F9344UL, 0x8708A3D2UL, 0x1E01F268UL, 0x6906C2FEUL, 0xF762575DUL, 0x806567CBUL, 0x196C3671UL, 0x6E6B06E7UL, + 0xFED41B76UL, 0x89D32BE0UL, 0x10DA7A5AUL, 0x67DD4ACCUL, 0xF9B9DF6FUL, 0x8EBEEFF9UL, 0x17B7BE43UL, 0x60B08ED5UL, + 0xD6D6A3E8UL, 0xA1D1937EUL, 0x38D8C2C4UL, 0x4FDFF252UL, 0xD1BB67F1UL, 0xA6BC5767UL, 0x3FB506DDUL, 0x48B2364BUL, + 0xD80D2BDAUL, 0xAF0A1B4CUL, 0x36034AF6UL, 0x41047A60UL, 0xDF60EFC3UL, 0xA867DF55UL, 0x316E8EEFUL, 0x4669BE79UL, + 0xCB61B38CUL, 0xBC66831AUL, 0x256FD2A0UL, 0x5268E236UL, 0xCC0C7795UL, 0xBB0B4703UL, 0x220216B9UL, 0x5505262FUL, + 0xC5BA3BBEUL, 0xB2BD0B28UL, 0x2BB45A92UL, 0x5CB36A04UL, 0xC2D7FFA7UL, 0xB5D0CF31UL, 0x2CD99E8BUL, 0x5BDEAE1DUL, + 0x9B64C2B0UL, 0xEC63F226UL, 0x756AA39CUL, 0x026D930AUL, 0x9C0906A9UL, 0xEB0E363FUL, 0x72076785UL, 0x05005713UL, + 0x95BF4A82UL, 0xE2B87A14UL, 0x7BB12BAEUL, 0x0CB61B38UL, 0x92D28E9BUL, 0xE5D5BE0DUL, 0x7CDCEFB7UL, 0x0BDBDF21UL, + 0x86D3D2D4UL, 0xF1D4E242UL, 0x68DDB3F8UL, 0x1FDA836EUL, 0x81BE16CDUL, 0xF6B9265BUL, 0x6FB077E1UL, 0x18B74777UL, + 0x88085AE6UL, 0xFF0F6A70UL, 0x66063BCAUL, 0x11010B5CUL, 0x8F659EFFUL, 0xF862AE69UL, 0x616BFFD3UL, 0x166CCF45UL, + 0xA00AE278UL, 0xD70DD2EEUL, 0x4E048354UL, 0x3903B3C2UL, 0xA7672661UL, 0xD06016F7UL, 0x4969474DUL, 0x3E6E77DBUL, + 0xAED16A4AUL, 0xD9D65ADCUL, 0x40DF0B66UL, 0x37D83BF0UL, 0xA9BCAE53UL, 0xDEBB9EC5UL, 0x47B2CF7FUL, 0x30B5FFE9UL, + 0xBDBDF21CUL, 0xCABAC28AUL, 0x53B39330UL, 0x24B4A3A6UL, 0xBAD03605UL, 0xCDD70693UL, 0x54DE5729UL, 0x23D967BFUL, + 0xB3667A2EUL, 0xC4614AB8UL, 0x5D681B02UL, 0x2A6F2B94UL, 0xB40BBE37UL, 0xC30C8EA1UL, 0x5A05DF1BUL, 0x2D02EF8DUL +}; + +uint32 crc32(const void *ptr, size_t len) +{ + uint32 crc = 0xFFFFFFFF; + const byte *bp = (const byte *) ptr; + size_t i; + + for (i=0; i<len; i++) { + crc = crcTable[(crc ^ bp[i]) & 0xFF] ^ (crc >> 8); + } + + return crc ^ 0xFFFFFFFF; +} diff --git a/psprint/source/fontsubset/crc32.h b/psprint/source/fontsubset/crc32.h new file mode 100644 index 000000000000..8fe50e1076dd --- /dev/null +++ b/psprint/source/fontsubset/crc32.h @@ -0,0 +1,79 @@ +/************************************************************************* + * + * $RCSfile: crc32.h,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:36 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Alexander Gelfenbain + * + * + ************************************************************************/ + +/* $Id: crc32.h,v 1.1.1.1 2001-05-08 11:45:36 pl Exp $ */ + +/** + * + * @file crc32.h + * @brief CRC-32 calculation function + * @author Alexander Gelfenbain + */ + +#include <sys/types.h> + +#ifdef __cplusplus +extern "C"{ +#endif + uint32 crc32(const void *ptr, size_t len); +#ifdef __cplusplus +} +#endif diff --git a/psprint/source/fontsubset/gsub.cxx b/psprint/source/fontsubset/gsub.cxx new file mode 100644 index 000000000000..95a4209268ae --- /dev/null +++ b/psprint/source/fontsubset/gsub.cxx @@ -0,0 +1,319 @@ +/************************************************************************* + * + * $RCSfile: gsub.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:36 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +extern "C" +{ +#include "sft.h" +#undef true +#undef false + +#include "gsub.h" +} + +#include <vector> +#include <map> +#include <algorithm> + +typedef uint32 ULONG; +typedef uint16 USHORT; +typedef uint8 FT_Byte; + +typedef std::map<USHORT,USHORT> GlyphSubstitution; + + +inline long NEXT_Long( const unsigned char* &p ) +{ + long nVal = (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; + p += 4; + return nVal; +} + +inline long NEXT_UShort( const unsigned char* &p ) +{ + long nVal = (p[0]<<8) + p[1]; + p += 2; + return nVal; +} + +#define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3]) + +int ReadGSUB( struct _TrueTypeFont* pTTFile, unsigned char* pGsubBase, + int nRequestedScript, int nRequestedLangsys ) +{ + if( !pGsubBase ) + return -1; + + typedef std::vector<ULONG> ReqFeatureTagList; + ReqFeatureTagList aReqFeatureTagList; + + aReqFeatureTagList.push_back( MKTAG("vert") ); + + // parse GSUB header + const FT_Byte* pGsubHeader = pGsubBase; + const ULONG nVersion = NEXT_Long( pGsubHeader ); + const USHORT nOfsScriptList = NEXT_UShort( pGsubHeader ); + const USHORT nOfsFeatureTable = NEXT_UShort( pGsubHeader ); + const USHORT nOfsLookupList = NEXT_UShort( pGsubHeader ); + + typedef std::vector<USHORT> UshortList; + UshortList aFeatureIndexList; + UshortList aFeatureOffsetList; + + // parse Script Table + const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList; + const USHORT nCntScript = NEXT_UShort( pScriptHeader ); + for( USHORT nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex ) + { + const ULONG nTag = NEXT_Long( pScriptHeader ); // e.g. hani/arab/kana/hang + const USHORT nOfsScriptTable= NEXT_UShort( pScriptHeader ); + if( (nTag != nRequestedScript) && (nRequestedScript != 0) ) + continue; + + const FT_Byte* pScriptTable = pGsubBase + nOfsScriptList + nOfsScriptTable; + const USHORT nDefaultLangsysOfs = NEXT_UShort( pScriptTable ); + const USHORT nCntLangSystem = NEXT_UShort( pScriptTable ); + USHORT nLangsysOffset = 0; + for( USHORT nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex ) + { + const ULONG nTag = NEXT_Long( pScriptTable ); // e.g. KOR/ZHS/ZHT/JAN + const USHORT nOffset= NEXT_UShort( pScriptTable ); + if( (nTag != nRequestedLangsys) && (nRequestedLangsys != 0) ) + continue; + nLangsysOffset = nOffset; + break; + } + + if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) ) + { + const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs; + const USHORT nLookupOrder = NEXT_UShort( pLangSys ); + const USHORT nReqFeatureIdx = NEXT_UShort( pLangSys ); + const USHORT nCntFeature = NEXT_UShort( pLangSys ); + aFeatureIndexList.push_back( nReqFeatureIdx ); + for( USHORT i = 0; i < nCntFeature; ++i ) + { + const USHORT nFeatureIndex = NEXT_UShort( pLangSys ); + aFeatureIndexList.push_back( nFeatureIndex ); + } + } + + if( nLangsysOffset != 0 ) + { + const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset; + const USHORT nLookupOrder = NEXT_UShort( pLangSys ); + const USHORT nReqFeatureIdx = NEXT_UShort( pLangSys ); + const USHORT nCntFeature = NEXT_UShort( pLangSys ); + aFeatureIndexList.push_back( nReqFeatureIdx ); + for( USHORT i = 0; i < nCntFeature; ++i ) + { + const USHORT nFeatureIndex = NEXT_UShort( pLangSys ); + aFeatureIndexList.push_back( nFeatureIndex ); + } + } + } + + if( !aFeatureIndexList.size() ) + return true; + + UshortList aLookupIndexList; + UshortList aLookupOffsetList; + + // parse Feature Table + const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable; + const USHORT nCntFeature = NEXT_UShort( pFeatureHeader ); + for( USHORT nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex ) + { + const ULONG nTag = NEXT_Long( pFeatureHeader ); // e.g. locl/vert/trad/smpl/liga/fina/... + const USHORT nOffset= NEXT_UShort( pFeatureHeader ); + + // feature (required && (requested || available))? + if( (aFeatureIndexList[0] != nFeatureIndex) + && (!std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag)) + || (!std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex) ) ) + continue; + + const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset; + const USHORT nCntLookups = NEXT_UShort( pFeatureTable ); + for( USHORT i = 0; i < nCntLookups; ++i ) + { + const USHORT nLookupIndex = NEXT_UShort( pFeatureTable ); + aLookupIndexList.push_back( nLookupIndex ); + } + if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/... + aLookupIndexList.push_back( 0 ); + } + + // parse Lookup List + const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList; + const USHORT nCntLookupTable = NEXT_UShort( pLookupHeader ); + for( USHORT nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx ) + { + const USHORT nOffset = NEXT_UShort( pLookupHeader ); + if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) ) + aLookupOffsetList.push_back( nOffset ); + } + + UshortList::const_iterator it = aLookupOffsetList.begin(); + for(; it != aLookupOffsetList.end(); ++it ) + { + const USHORT nOfsLookupTable = *it; + const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable; + const USHORT eLookupType = NEXT_UShort( pLookupTable ); + const USHORT eLookupFlag = NEXT_UShort( pLookupTable ); + const USHORT nCntLookupSubtable = NEXT_UShort( pLookupTable ); + + // TODO: switch( eLookupType ) + if( eLookupType != 1 ) // TODO: once we go beyond SingleSubst + continue; + + for( USHORT nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx ) + { + const USHORT nOfsSubLookupTable = NEXT_UShort( pLookupTable ); + const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable; + + const USHORT nFmtSubstitution = NEXT_UShort( pSubLookup ); + const USHORT nOfsCoverage = NEXT_UShort( pSubLookup ); + + typedef std::pair<USHORT,USHORT> GlyphSubst; + typedef std::vector<GlyphSubst> SubstVector; + SubstVector aSubstVector; + + const FT_Byte* pCoverage = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage; + const USHORT nFmtCoverage = NEXT_UShort( pCoverage ); + switch( nFmtCoverage ) + { + case 1: // Coverage Format 1 + { + const USHORT nCntGlyph = NEXT_UShort( pCoverage ); + aSubstVector.reserve( nCntGlyph ); + for( USHORT i = 0; i < nCntGlyph; ++i ) + { + const USHORT nGlyphId = NEXT_UShort( pCoverage ); + aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) ); + } + } + break; + + case 2: // Coverage Format 2 + { + const USHORT nCntRange = NEXT_UShort( pCoverage ); + for( int i = nCntRange; --i >= 0; ) + { + const USHORT nGlyph0 = NEXT_UShort( pCoverage ); + const USHORT nGlyph1 = NEXT_UShort( pCoverage ); + const USHORT nCovIdx = NEXT_UShort( pCoverage ); + for( USHORT j = nGlyph0; j <= nGlyph1; ++j ) + aSubstVector.push_back( GlyphSubst( j + nCovIdx, 0 ) ); + } + } + break; + } + + SubstVector::iterator it( aSubstVector.begin() ); + + switch( nFmtSubstitution ) + { + case 1: // Single Substitution Format 1 + { + const USHORT nDeltaGlyphId = NEXT_UShort( pSubLookup ); + for(; it != aSubstVector.end(); ++it ) + (*it).second = (*it).first + nDeltaGlyphId; + } + break; + + case 2: // Single Substitution Format 2 + { + const USHORT nCntGlyph = NEXT_UShort( pSubLookup ); + for( int i = nCntGlyph; (it != aSubstVector.end()) && (--i>=0); ++it ) + { + const USHORT nGlyphId = NEXT_UShort( pSubLookup ); + (*it).second = nGlyphId; + } + } + break; + } + + // now apply the glyph substitutions that have been collected in this subtable + if( aSubstVector.size() > 0 ) + { + GlyphSubstitution* pGSubstitution = new GlyphSubstitution; + pTTFile->pGSubstitution = (void*)pGSubstitution; + for( it = aSubstVector.begin(); it != aSubstVector.end(); ++it ) + (*pGSubstitution)[ (*it).first ] = (*it).second; + } + } + } + + return true; +} + +int UseGSUB( struct _TrueTypeFont* pTTFile, int nGlyph, int wmode ) +{ + GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution; + if( pGlyphSubstitution != 0 ) + { + GlyphSubstitution::const_iterator it( pGlyphSubstitution->find( nGlyph ) ); + if( it != pGlyphSubstitution->end() ) + nGlyph = (*it).second; + } + + return nGlyph; +} diff --git a/psprint/source/fontsubset/gsub.h b/psprint/source/fontsubset/gsub.h new file mode 100644 index 000000000000..97ed37637c54 --- /dev/null +++ b/psprint/source/fontsubset/gsub.h @@ -0,0 +1,70 @@ +/************************************************************************* + * + * $RCSfile: gsub.h,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:36 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _PSP_GSUB_H +#define _PSP_GSUB_H + +int UseGSUB( struct _TrueTypeFont* pTTFile, int nGlyph, int wmode ); + +int ReadGSUB( struct _TrueTypeFont* pTTFile, unsigned char* pGsubBase, + int nRequestedScript, int nRequestedLangsys ); + +#endif /* _PSP_GSUB_H */ diff --git a/psprint/source/fontsubset/list.c b/psprint/source/fontsubset/list.c new file mode 100644 index 000000000000..8bcc69f65b55 --- /dev/null +++ b/psprint/source/fontsubset/list.c @@ -0,0 +1,623 @@ +/************************************************************************* + * + * $RCSfile: list.c,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:36 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Alexander Gelfenbain + * + * + ************************************************************************/ + +/* $Id: list.c,v 1.1.1.1 2001-05-08 11:45:36 pl Exp $ */ + +/*[]---------------------------------------------------[]*/ +/*| |*/ +/*| list.c - bidirectional list class |*/ +/*| |*/ +/*| |*/ +/*| Author: Alexander Gelfenbain |*/ +/*[]---------------------------------------------------[]*/ + +#include <stdlib.h> +#include <assert.h> +#ifdef MALLOC_TRACE +#include <stdio.h> +#include </usr/local/include/malloc.h> +#endif +#include "list.h" + +/*- private data types */ +typedef struct _lnode { + struct _lnode *next; + struct _lnode *prev; + + void *value; + +} lnode; + +struct _list { + lnode *head, *tail, *cptr; + size_t aCount; + void (*eDtor)(void *); +}; + +/*- private methods */ + +static lnode *newNode(void *el) +{ + lnode *ptr = malloc(sizeof(lnode)); + assert(ptr != 0); + + ptr->value = el; + + return ptr; +} + +static lnode *appendPrim(list this, void *el) +{ + lnode *ptr = newNode(el); + lnode **flink, *blink; + + if (this->tail != 0) { + flink = &(this->tail->next); + blink = this->tail; + } else { + flink = &this->head; + blink = 0; + this->cptr = ptr; /*- list was empty - set current to this element */ + } + + *flink = ptr; + this->tail = ptr; + + ptr->prev = blink; + ptr->next = 0; + + this->aCount++; + return ptr; +} + +static lnode *prependPrim(list this, void *el) +{ + lnode *ptr = newNode(el); + lnode *flink, **blink; + + if (this->head != 0) { + blink = &(this->head->prev); + flink = this->head; + } else { + blink = &this->tail; + flink = 0; + this->cptr = ptr; /*- list was empty - set current to this element */ + } + + *blink = ptr; + this->head = ptr; + + ptr->next = flink; + ptr->prev = 0; + + this->aCount++; + return ptr; +} + + +/*- public methods */ +list listNewEmpty(void) /*- default ctor */ +{ + list this = malloc(sizeof(struct _list)); + assert(this != 0); + + this->aCount = 0; + this->eDtor = 0; + this->head = this->tail = this->cptr = 0; + + return this; +} + +list listNewCopy(list l) /*- copy ctor */ +{ + lnode *ptr, *c; + list this; + assert(l != 0); + + this = malloc(sizeof(struct _list)); + assert(this != 0); + + ptr = l->head; + + this->aCount = 0; + this->eDtor = 0; + this->head = this->tail = this->cptr = 0; + + while (ptr) { + c = appendPrim(this, ptr->value); + if (ptr == l->cptr) this->cptr = c; + ptr = ptr->next; + } + + return this; +} + +void listDispose(list this) /*- dtor */ +{ + assert(this != 0); + listClear(this); + free(this); +} + +void listSetElementDtor(list this, void (*f)(void *)) +{ + assert(this != 0); + this->eDtor = f; +} + + +list listCopy(list to, list from) /*- assignment */ +{ + lnode *ptr, *c; + assert(to != 0); + assert(from != 0); + + listClear(to); + ptr = from->head; + + while (ptr) { + c = appendPrim(to, ptr->value); + if (ptr == from->cptr) to->cptr = c; + ptr = ptr->next; + } + + return to; +} + + +/* calling this function on an empty list is a run-time error */ +void *listCurrent(list this) +{ + assert(this != 0); + assert(this->cptr != 0); + return this->cptr->value; +} + +int listCount(list this) +{ + assert(this != 0); + return this->aCount; +} + +int listIsEmpty(list this) +{ + assert(this != 0); + return this->aCount == 0; +} + + +int listAtFirst(list this) +{ + assert(this != 0); + return this->cptr == this->head; +} + +int listAtLast(list this) +{ + assert(this != 0); + return this->cptr == this->tail; +} + +int listPosition(list this) +{ + int res = 0; + lnode *ptr; + assert(this != 0); + + ptr = this->head; + + while (ptr != this->cptr) { + ptr = ptr->next; + res++; + } + + return res; +} + +int listFind(list this, void *el) +{ + lnode *ptr; + assert(this != 0); + + ptr = this->head; + + while (ptr) { + if (ptr->value == el) { + this->cptr = ptr; + return 1; + } + ptr = ptr->next; + } + + return 0; +} + +int listNext(list this) +{ + return listSkipForward(this, 1); +} + +int listPrev(list this) +{ + return listSkipBackward(this, 1); +} + +int listSkipForward(list this, int n) +{ + int m = 0; + assert(this != 0); + + if (this->cptr == 0) return 0; + + while (n != 0) { + if (this->cptr->next == 0) break; + this->cptr = this->cptr->next; + n--; + m++; + } + return m; +} + +int listSkipBackward(list this, int n) +{ + int m = 0; + assert(this != 0); + + if (this->cptr == 0) return 0; + + while (n != 0) { + if (this->cptr->prev == 0) break; + this->cptr = this->cptr->prev; + n--; + m++; + } + return m; +} + +int listToFirst(list this) +{ + assert(this != 0); + + if (this->cptr != this->head) { + this->cptr = this->head; + return 1; + } + return 0; +} + +int listToLast(list this) +{ + assert(this != 0); + + if (this->cptr != this->tail) { + this->cptr = this->tail; + return 1; + } + return 0; +} + +int listPositionAt(list this, int n) /*- returns the actual position number */ +{ + int m = 0; + assert(this != 0); + + this->cptr = this->head; + while (n != 0) { + if (this->cptr->next == 0) break; + this->cptr = this->cptr->next; + n--; + m++; + } + return m; +} + +list listAppend(list this, void *el) +{ + assert(this != 0); + + appendPrim(this, el); + return this; +} + +list listPrepend(list this, void *el) +{ + assert(this != 0); + + prependPrim(this, el); + return this; +} + +list listInsertAfter(list this, void *el) +{ + lnode *ptr; + assert(this != 0); + + if (this->cptr == 0) return listAppend(this, el); + + ptr = newNode(el); + + ptr->prev = this->cptr; + ptr->next = this->cptr->next; + this->cptr->next = ptr; + + if (ptr->next != 0) { + ptr->next->prev = ptr; + } else { + this->tail = ptr; + } + this->aCount++; + return this; +} + +list listInsertBefore(list this, void *el) +{ + lnode *ptr; + assert(this != 0); + + if (this->cptr == 0) return listAppend(this, el); + + ptr = newNode(el); + + ptr->prev = this->cptr->prev; + ptr->next = this->cptr; + this->cptr->prev = ptr; + + if (ptr->prev != 0) { + ptr->prev->next = ptr; + } else { + this->head = ptr; + } + this->aCount++; + return this; +} + +list listRemove(list this) +{ + lnode *ptr = 0; + if (this->cptr == 0) return this; + + if (this->cptr->next != 0) { + ptr = this->cptr->next; + this->cptr->next->prev = this->cptr->prev; + } else { + this->tail = this->cptr->prev; + } + + if (this->cptr->prev != 0) { + if (ptr == 0) ptr = this->cptr->prev; + this->cptr->prev->next = this->cptr->next; + } else { + this->head = this->cptr->next; + } + + if (this->eDtor) this->eDtor(this->cptr->value); /* call the dtor callback */ + + free(this->cptr); + this->aCount--; + this->cptr = ptr; + return this; +} + +list listClear(list this) +{ + lnode *node = this->head, *ptr; + + while (node) { + ptr = node->next; + if (this->eDtor) this->eDtor(node->value); /* call the dtor callback */ + free(node); + this->aCount--; + node = ptr; + } + + this->head = this->tail = this->cptr = 0; + assert(this->aCount == 0); + return this; +} + +void listForAll(list this, void (*f)(void *)) +{ + lnode *ptr = this->head; + while (ptr) { + f(ptr->value); + ptr = ptr->next; + } +} + +void **listToArray(list this) +{ + void **res; + lnode *ptr = this->head; + int i = 0; + + assert(this->aCount != 0); + res = calloc(this->aCount, sizeof(void *)); + assert(res != 0); + + while (ptr) { + res[i++] = ptr->value; + ptr = ptr->next; + } + return res; +} + + +/* #define TEST */ +#ifdef TEST +#include <stdio.h> + +void printlist(list l) +{ + int saved; + assert(l != 0); + saved = listPosition(l); + + printf("[ "); + + if (!listIsEmpty(l)) { + listToFirst(l); + do { + printf("%d ", (int) listCurrent(l)); + } while (listNext(l)); + } + + printf("]\n"); + + listPositionAt(l, saved); +} + +void printstringlist(list l) +{ + int saved; + assert(l != 0); + saved = listPosition(l); + + printf("[ "); + + if (!listIsEmpty(l)) { + listToFirst(l); + do { + printf("'%s' ", (char *) listCurrent(l)); + } while (listNext(l)); + } + + printf("]\n"); + + listPositionAt(l, saved); +} + +void printstat(list l) +{ + printf("count: %d, position: %d, isEmpty: %d, atFirst: %d, atLast: %d.\n", + listCount(l), listPosition(l), listIsEmpty(l), listAtFirst(l), listAtLast(l)); +} + +void allfunc(void *e) +{ + printf("%d ", e); +} + +void edtor(void *ptr) +{ + printf("element dtor: 0x%08x\n", ptr); + free(ptr); +} + +int main() +{ + list l1, l2; + char *ptr; + int i; + +#ifdef MALLOC_TRACE + mal_leaktrace(1); + mal_debug(2); +#endif + + l1 = listNewEmpty(); + printstat(l1); + + listAppend(l1, 1); + printstat(l1); + + listAppend(l1, 2); + printstat(l1); + + listAppend(l1, 3); + printstat(l1); + + printlist(l1); + + listToFirst(l1); + listInsertBefore(l1, -5); + printlist(l1); + + l2 = listNewCopy(l1); + printlist(l2); + + listForAll(l2, allfunc); + printf("\n"); + + listClear(l1); + listSetElementDtor(l1, edtor); + + for(i=0; i<10; i++) { + ptr = malloc(20); + sprintf(ptr, "element # %d", i); + listAppend(l1, ptr); + } + + printstringlist(l1); + + + listDispose(l1); + listDispose(l2); + +#ifdef MALLOC_TRACE + mal_dumpleaktrace(stdout); +#endif + + + return 0; +} +#endif + + diff --git a/psprint/source/fontsubset/list.h b/psprint/source/fontsubset/list.h new file mode 100644 index 000000000000..20f10530f78d --- /dev/null +++ b/psprint/source/fontsubset/list.h @@ -0,0 +1,135 @@ +/************************************************************************* + * + * $RCSfile: list.h,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:36 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Alexander Gelfenbain + * + * + ************************************************************************/ + +/* $Id: list.h,v 1.1.1.1 2001-05-08 11:45:36 pl Exp $ */ + +/*[]---------------------------------------------------[]*/ +/*| |*/ +/*| Implementation of the list data type |*/ +/*| |*/ +/*| |*/ +/*| Author: Alexander Gelfenbain |*/ +/*[]---------------------------------------------------[]*/ + +#ifndef __CLIST_H +#define __CLIST_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + * List of void * pointers + */ + + typedef struct _list *list; + +/*- constructors and a destructor */ + list listNewEmpty(void); + list listNewCopy(list); + void listDispose(list); + void listSetElementDtor(list, void (*f)(void *)); /*- this function will be executed when the element is removed via listRemove() or listClear() */ + +/*- assignment */ + list listCopy(list to, list from); + +/*- queries */ + void * listCurrent(list); + int listCount(list); + int listIsEmpty(list); + int listAtFirst(list); + int listAtLast(list); + int listPosition(list); /* Expensive! */ + +/*- search */ + int listFind(list, void *); /* Returns true/false */ + +/*- positioning functions */ +/*- return the number of elements by which the current position in the list changes */ + int listNext(list); + int listPrev(list); + int listSkipForward(list, int n); + int listSkipBackward(list, int n); + int listToFirst(list); + int listToLast(list); + int listPositionAt(list, int n); /* Expensive! */ + +/*- adding and removing elements */ + list listAppend(list, void *); + list listPrepend(list, void *); + list listInsertAfter(list, void *); + list listInsertBefore(list, void *); + list listRemove(list); /* removes the current element */ + list listClear(list); /* removes all elements */ + +/*- forall */ + void listForAll(list, void (*f)(void *)); + +/*- conversion */ + void **listToArray(list); + +#ifdef __cplusplus +} +#endif + + +#endif /* __CLIST_H */ diff --git a/psprint/source/fontsubset/makefile.mk b/psprint/source/fontsubset/makefile.mk new file mode 100644 index 000000000000..15e389009286 --- /dev/null +++ b/psprint/source/fontsubset/makefile.mk @@ -0,0 +1,93 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: pl $ $Date: 2001-05-08 11:45:36 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=psprint +TARGET=fontsubset + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Files -------------------------------------------------------- + +.IF "$(OS)"=="MACOSX" + +dummy: + @echo "Nothing to build for Mac OS X" + +.ELSE # "$(OS)"=="MACOSX" + +SLOFILES=\ + $(SLO)$/list.obj \ + $(SLO)$/sft.obj \ + $(SLO)$/xlat.obj \ + $(SLO)$/crc32.obj \ + $(SLO)$/ttcr.obj \ + $(SLO)$/gsub.obj + +.ENDIF # "$(OS)"=="MACOSX" + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/psprint/source/fontsubset/sft.c b/psprint/source/fontsubset/sft.c new file mode 100644 index 000000000000..e82dac2aa573 --- /dev/null +++ b/psprint/source/fontsubset/sft.c @@ -0,0 +1,3074 @@ +/************************************************************************* + * + * $RCSfile: sft.c,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Alexander Gelfenbain + * + * + ************************************************************************/ + +/* $Id: sft.c,v 1.1.1.1 2001-05-08 11:45:37 pl Exp $ + * Sun Font Tools + * + * Author: Alexander Gelfenbain + * + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include "sft.h" +#include "gsub.h" +#if ! (defined(NO_TTCR) && defined(NO_TYPE42)) +#include "ttcr.h" +#endif +#ifdef NO_LIST +#include "list.h" /* list.h does not get included in the sft.h */ +#endif +#ifndef NO_MAPPERS /* include MapChar() and MapString() */ +#include "xlat.h" +#endif +#ifndef NO_TYPE3 /* include CreateT3FromTTGlyphs() */ +#include "crc32.h" +#endif + +#ifdef TEST7 +#include <ctype.h> +#endif + +/*- module identification */ + +const char *modname = "SunTypeTools-TT"; +const char *modver = "1.0"; +const char *modextra = "gelf"; + +/*- private functions, constants and data types */ /*FOLD00*/ + +enum PathSegmentType { + PS_NOOP = 0, + PS_MOVETO = 1, + PS_LINETO = 2, + PS_CURVETO = 3, + PS_CLOSEPATH = 4 +}; + +typedef struct { + int type; + int x1, y1; + int x2, y2; + int x3, y3; +} PSPathElement; + +/*- In horisontal writing mode right sidebearing is calculated using this formula + *- rsb = aw - (lsb + xMax - xMin) -*/ +typedef struct { + int16 xMin; + int16 yMin; + int16 xMax; + int16 yMax; + uint16 aw; /*- Advance Width (horisontal writing mode) */ + int16 lsb; /*- Left sidebearing (horisontal writing mode) */ + uint16 ah; /*- advance height (vertical writing mode) */ + int16 tsb; /*- top sidebearing (vertical writing mode) */ +} TTGlyphMetrics; + +#define HFORMAT_LINELEN 64 + +typedef struct { + FILE *o; + char buffer[HFORMAT_LINELEN]; + int bufpos; + int total; +} HexFmt; + +typedef struct { + uint32 nGlyphs; /* number of glyphs in the font + 1 */ + uint32 *offs; /* array of nGlyphs offsets */ +} GlyphOffsets; + +/* private tags */ +static const uint32 TTFontClassTag = 0x74746663; /* 'ttfc' */ + +static const uint32 T_true = 0x74727565; /* 'true' */ +static const uint32 T_ttcf = 0x74746366; /* 'ttcf' */ + +/* standard TrueType table tags and their ordinal numbers */ +static const uint32 T_maxp = 0x6D617870; static const uint32 O_maxp = 0; /* 'maxp' */ +static const uint32 T_glyf = 0x676C7966; static const uint32 O_glyf = 1; /* 'glyf' */ +static const uint32 T_head = 0x68656164; static const uint32 O_head = 2; /* 'head' */ +static const uint32 T_loca = 0x6C6F6361; static const uint32 O_loca = 3; /* 'loca' */ +static const uint32 T_name = 0x6E616D65; static const uint32 O_name = 4; /* 'name' */ +static const uint32 T_hhea = 0x68686561; static const uint32 O_hhea = 5; /* 'hhea' */ +static const uint32 T_hmtx = 0x686D7478; static const uint32 O_hmtx = 6; /* 'hmtx' */ +static const uint32 T_cmap = 0x636D6170; static const uint32 O_cmap = 7; /* 'cmap' */ +static const uint32 T_vhea = 0x76686561; static const uint32 O_vhea = 8; /* 'vhea' */ +static const uint32 T_vmtx = 0x766D7478; static const uint32 O_vmtx = 9; /* 'vmtx' */ +static const uint32 T_OS2 = 0x4F532F32; static const uint32 O_OS2 = 10; /* 'OS/2' */ +static const uint32 T_post = 0x706F7374; static const uint32 O_post = 11; /* 'post' */ +static const uint32 T_kern = 0x6B65726E; static const uint32 O_kern = 12; /* 'kern' */ +static const uint32 T_cvt = 0x63767420; static const uint32 O_cvt = 13; /* 'cvt_' - only used in TT->TT generation */ +static const uint32 T_prep = 0x70726570; static const uint32 O_prep = 14; /* 'prep' - only used in TT->TT generation */ +static const uint32 T_fpgm = 0x6670676D; static const uint32 O_fpgm = 15; /* 'fpgm' - only used in TT->TT generation */ +static const uint32 T_gsub = 0x47535542; static const uint32 O_gsub = 16; /* 'GSUB' */ +#define NUM_TAGS 17 + +#define LAST_URANGE_BIT 69 +const char *ulcodes[LAST_URANGE_BIT+2] = { + /* 0 */ "Basic Latin", + /* 1 */ "Latin-1 Supplement", + /* 2 */ "Latin Extended-A", + /* 3 */ "Latin Extended-B", + /* 4 */ "IPA Extensions", + /* 5 */ "Spacing Modifier Letters", + /* 6 */ "Combining Diacritical Marks", + /* 7 */ "Basic Greek", + /* 8 */ "Greek Symbols And Coptic", + /* 9 */ "Cyrillic", + /* 10 */ "Armenian", + /* 11 */ "Basic Hebrew", + /* 12 */ "Hebrew Extended (A and B blocks combined)", + /* 13 */ "Basic Arabic", + /* 14 */ "Arabic Extended", + /* 15 */ "Devanagari", + /* 16 */ "Bengali", + /* 17 */ "Gurmukhi", + /* 18 */ "Gujarati", + /* 19 */ "Oriya", + /* 20 */ "Tamil", + /* 21 */ "Telugu", + /* 22 */ "Kannada", + /* 23 */ "Malayalam", + /* 24 */ "Thai", + /* 25 */ "Lao", + /* 26 */ "Basic Georgian", + /* 27 */ "Georgian Extended", + /* 28 */ "Hangul Jamo", + /* 29 */ "Latin Extended Additional", + /* 30 */ "Greek Extended", + /* 31 */ "General Punctuation", + /* 32 */ "Superscripts And Subscripts", + /* 33 */ "Currency Symbols", + /* 34 */ "Combining Diacritical Marks For Symbols", + /* 35 */ "Letterlike Symbols", + /* 36 */ "Number Forms", + /* 37 */ "Arrows", + /* 38 */ "Mathematical Operators", + /* 39 */ "Miscellaneous Technical", + /* 40 */ "Control Pictures", + /* 41 */ "Optical Character Recognition", + /* 42 */ "Enclosed Alphanumerics", + /* 43 */ "Box Drawing", + /* 44 */ "Block Elements", + /* 45 */ "Geometric Shapes", + /* 46 */ "Miscellaneous Symbols", + /* 47 */ "Dingbats", + /* 48 */ "CJK Symbols And Punctuation", + /* 49 */ "Hiragana", + /* 50 */ "Katakana", + /* 51 */ "Bopomofo", + /* 52 */ "Hangul Compatibility Jamo", + /* 53 */ "CJK Miscellaneous", + /* 54 */ "Enclosed CJK Letters And Months", + /* 55 */ "CJK Compatibility", + /* 56 */ "Hangul", + /* 57 */ "Reserved for Unicode SubRanges", + /* 58 */ "Reserved for Unicode SubRanges", + /* 59 */ "CJK Unified Ideographs", + /* 60 */ "Private Use Area", + /* 61 */ "CJK Compatibility Ideographs", + /* 62 */ "Alphabetic Presentation Forms", + /* 63 */ "Arabic Presentation Forms-A", + /* 64 */ "Combining Half Marks", + /* 65 */ "CJK Compatibility Forms", + /* 66 */ "Small Form Variants", + /* 67 */ "Arabic Presentation Forms-B", + /* 68 */ "Halfwidth And Fullwidth Forms", + /* 69 */ "Specials", + /*70-127*/ "Reserved for Unicode SubRanges" +}; + + + +/*- inline functions */ /*FOLD01*/ +#ifdef __GNUC__ +#define _inline static __inline__ +#else +#define _inline static +#endif + +_inline void *smalloc(size_t size) +{ + void *res = malloc(size); + assert(res != 0); + return res; +} + +_inline void *scalloc(size_t n, size_t size) +{ + void *res = calloc(n, size); + assert(res != 0); + return res; +} + +_inline uint32 mkTag(byte a, byte b, byte c, byte d) { + return (a << 24) | (b << 16) | (c << 8) | d; +} + +/*- Data access macros for data stored in big-endian or little-endian format */ +_inline int16 GetInt16(const byte *ptr, size_t offset, int bigendian) +{ + int16 t; + assert(ptr != 0); + + if (bigendian) { + t = (ptr+offset)[0] << 8 | (ptr+offset)[1]; + } else { + t = (ptr+offset)[1] << 8 | (ptr+offset)[0]; + } + + return t; +} + +_inline uint16 GetUInt16(const byte *ptr, size_t offset, int bigendian) +{ + uint16 t; + assert(ptr != 0); + + if (bigendian) { + t = (ptr+offset)[0] << 8 | (ptr+offset)[1]; + } else { + t = (ptr+offset)[1] << 8 | (ptr+offset)[0]; + } + + return t; +} + +_inline int32 GetInt32(const byte *ptr, size_t offset, int bigendian) +{ + int32 t; + assert(ptr != 0); + + if (bigendian) { + t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 | + (ptr+offset)[2] << 8 | (ptr+offset)[3]; + } else { + t = (ptr+offset)[3] << 24 | (ptr+offset)[2] << 16 | + (ptr+offset)[1] << 8 | (ptr+offset)[0]; + } + + return t; +} + +_inline uint32 GetUInt32(const byte *ptr, size_t offset, int bigendian) +{ + uint32 t; + assert(ptr != 0); + + + if (bigendian) { + t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 | + (ptr+offset)[2] << 8 | (ptr+offset)[3]; + } else { + t = (ptr+offset)[3] << 24 | (ptr+offset)[2] << 16 | + (ptr+offset)[1] << 8 | (ptr+offset)[0]; + } + + return t; +} + +_inline void PutInt16(int16 val, byte *ptr, size_t offset, int bigendian) +{ + assert(ptr != 0); + + if (bigendian) { + ptr[offset] = (val >> 8) & 0xFF; + ptr[offset+1] = val & 0xFF; + } else { + ptr[offset+1] = (val >> 8) & 0xFF; + ptr[offset] = val & 0xFF; + } + +} + +#if defined(G_BIG_ENDIAN) +#define Int16FromMOTA(a) (a) +#else +static uint16 Int16FromMOTA(uint16 a) { + return (uint16) (((byte)((a) >> 8)) | ((byte)(a) << 8)); +} +#endif + +_inline F16Dot16 fixedMul(F16Dot16 a, F16Dot16 b) +{ + unsigned int a1, b1; + unsigned int a2, b2; + F16Dot16 res; + int sign; + + sign = (a & 0x80000000) ^ (b & 0x80000000); + if (a < 0) a = -a; + if (b < 0) b = -b; + + a1 = a >> 16; + b1 = a & 0xFFFF; + a2 = b >> 16; + b2 = b & 0xFFFF; + + res = a1 * a2; + + /* if (res > 0x7FFF) assert(!"fixedMul: F16Dot16 overflow"); */ + + res <<= 16; + res += a1 * b2 + b1 * a2 + ((b1 * b2) >> 16); + + return sign ? -res : res; +} + + +_inline F16Dot16 fixedDiv(F16Dot16 a, F16Dot16 b) +{ + unsigned int f, r; + F16Dot16 res; + int sign; + + sign = (a & 0x80000000) ^ (b & 0x80000000); + if (a < 0) a = -a; + if (b < 0) b = -b; + + f = a / b; + r = a % b; + + /* if (f > 0x7FFFF) assert(!"fixedDiv: F16Dot16 overflow"); */ + + while (r > 0xFFFF) { + r >>= 1; + b >>= 1; + } + + res = (f << 16) + (r << 16) / b; + + return sign ? -res : res; +} + +/*- returns a * b / c -*/ +/* XXX provide a real implementation that preserves accuracy */ +_inline F16Dot16 fixedMulDiv(F16Dot16 a, F16Dot16 b, F16Dot16 c) +{ + F16Dot16 res; + + res = fixedMul(a, b); + return fixedDiv(res, c); +} + +/*- Translate units from TT to PS (standard 1/1000) -*/ +_inline int XUnits(int unitsPerEm, int n) +{ + return (n * 1000) / unitsPerEm; +} + +_inline const char *UnicodeRangeName(uint16 bit) +{ + if (bit > LAST_URANGE_BIT) bit = LAST_URANGE_BIT+1; + + return ulcodes[bit]; +} + + +#if 0 +/* It would have been nice if it worked, but I found so many fonts that don't + * follow the TrueType spec (sorted table directory) that I have to re-write this + * stuff. + */ + +static byte *getTDEntry(TrueTypeFont *ttf, uint32 tag) /*FOLD01*/ +{ + int l = 0, r = ttf->ntables-1, i; + uint32 t; + + do { + i = (l + r) >> 1; + t = GetUInt32(ttf->ptr + 12, i << 4, 1); + if (tag >= t) l = i + 1; + if (tag <= t) r = i - 1; + } while (l <= r); + + if (l - r == 2) { + return ttf->ptr + 12 + 16 * (l - 1); + } + return 0; +} + +static byte *getTable(TrueTypeFont *ttf, uint32 tag) /*FOLD01*/ +{ + byte *ptr = getTDEntry(ttf, tag); + if (!ptr) return 0; + + return ttf->ptr + GetUInt32(ptr, 8, 1); +} + +static uint32 getTableSize(TrueTypeFont *ttf, uint32 tag) /*FOLD01*/ +{ + byte *ptr = getTDEntry(ttf, tag); + if (!ptr) return 0; + + return GetUInt32(ptr, 12, 1); +} + +#endif + +_inline byte *getTable(TrueTypeFont *ttf, uint32 ord) +{ + return ttf->tables[ord]; +} + +_inline uint32 getTableSize(TrueTypeFont *ttf, uint32 ord) +{ + return ttf->tlens[ord]; +} + +#ifndef NO_TYPE42 +/* Hex Formatter functions */ +static char HexChars[] = "0123456789ABCDEF"; + +static HexFmt *HexFmtNew(FILE *outf) +{ + HexFmt *res = smalloc(sizeof(HexFmt)); + res->bufpos = res->total = 0; + res->o = outf; + return res; +} + +static void HexFmtFlush(HexFmt *_this) +{ + if (_this->bufpos) { + fwrite(_this->buffer, 1, _this->bufpos, _this->o); + _this->bufpos = 0; + } +} + + +_inline void HexFmtOpenString(HexFmt *_this) +{ + fputs("<\n", _this->o); +} + +_inline void HexFmtCloseString(HexFmt *_this) +{ + HexFmtFlush(_this); + fputs("00\n>\n", _this->o); +} + +_inline void HexFmtDispose(HexFmt *_this) +{ + HexFmtFlush(_this); + free(_this); +} + +static void HexFmtBlockWrite(HexFmt *_this, const void *ptr, off_t size) +{ + byte Ch; + off_t i; + + if (_this->total + size > 65534) { + HexFmtFlush(_this); + HexFmtCloseString(_this); + _this->total = 0; + HexFmtOpenString(_this); + } + for (i=0; i<size; i++) { + Ch = ((byte *) ptr)[i]; + _this->buffer[_this->bufpos++] = HexChars[Ch >> 4]; + _this->buffer[_this->bufpos++] = HexChars[Ch & 0xF]; + if (_this->bufpos == HFORMAT_LINELEN) { + HexFmtFlush(_this); + fputc('\n', _this->o); + } + + } + _this->total += size; +} +#endif + + + +/* Outline Extraction functions */ /*FOLD01*/ + +/* fills the aw and lsb entries of the TTGlyphMetrics structure from hmtx table -*/ +static void GetMetrics(TrueTypeFont *ttf, uint32 glyphID, TTGlyphMetrics *metrics) +{ + byte *table = getTable(ttf, O_hmtx); + + metrics->aw = metrics->lsb = metrics->ah = metrics->tsb = 0; + if (!table || !ttf->numberOfHMetrics) return; + + if (glyphID < ttf->numberOfHMetrics) { + metrics->aw = GetUInt16(table, 4 * glyphID, 1); + metrics->lsb = GetInt16(table, 4 * glyphID + 2, 1); + } else { + metrics->aw = GetUInt16(table, 4 * (ttf->numberOfHMetrics - 1), 1); + metrics->lsb = GetInt16(table + ttf->numberOfHMetrics * 4, (glyphID - ttf->numberOfHMetrics) * 2, 1); + } + + table = getTable(ttf, O_vmtx); + if (!table || !ttf->numOfLongVerMetrics) return; + + if (glyphID < ttf->numOfLongVerMetrics) { + metrics->ah = GetUInt16(table, 4 * glyphID, 1); + metrics->tsb = GetInt16(table, 4 * glyphID + 2, 1); + } else { + metrics->ah = GetUInt16(table, 4 * (ttf->numOfLongVerMetrics - 1), 1); + metrics->tsb = GetInt16(table + ttf->numOfLongVerMetrics * 4, (glyphID - ttf->numOfLongVerMetrics) * 2, 1); + } +} + +static int GetTTGlyphOutline(TrueTypeFont *, uint32 , ControlPoint **, TTGlyphMetrics *, list ); + +/* returns the number of control points, allocates the pointArray */ +static int GetSimpleTTOutline(TrueTypeFont *ttf, uint32 glyphID, ControlPoint **pointArray, TTGlyphMetrics *metrics) /*FOLD02*/ +{ + byte *table = getTable(ttf, O_glyf); + byte *ptr, *p, flag, n; + int16 numberOfContours; + uint16 t, instLen, lastPoint=0; + int i, j, z; + ControlPoint* pa; + + *pointArray = 0; + + /* printf("GetSimpleTTOutline(%d)\n", glyphID); */ + + if (glyphID >= ttf->nglyphs) return 0; /*- glyph is not present in the font */ + ptr = table + ttf->goffsets[glyphID]; + if ((numberOfContours = GetInt16(ptr, 0, 1)) <= 0) return 0; /*- glyph is not simple */ + + if (metrics) { /*- GetCompoundTTOutline() calls this function with NULL metrics -*/ + metrics->xMin = GetInt16(ptr, 2, 1); + metrics->yMin = GetInt16(ptr, 4, 1); + metrics->xMax = GetInt16(ptr, 6, 1); + metrics->yMax = GetInt16(ptr, 8, 1); + GetMetrics(ttf, glyphID, metrics); + } + + /* determine the last point and be extra safe about it. But probably this code is not needed */ + + for (i=0; i<numberOfContours; i++) { + if ((t = GetUInt16(ptr, 10+i*2, 1)) > lastPoint) lastPoint = t; + } + + instLen = GetUInt16(ptr, 10 + numberOfContours*2, 1); + p = ptr + 10 + 2 * numberOfContours + 2 + instLen; + pa = calloc(lastPoint+1, sizeof(ControlPoint)); + + i = 0; + while (i <= lastPoint) { + pa[i++].flags = flag = (uint32) *p++; + if (flag & 8) { /*- repeat flag */ + n = *p++; + for (j=0; j<n; j++) { + if (i > lastPoint) { /*- if the font is really broken */ + free(pa); + return 0; + } + pa[i++].flags = flag; + } + } + } + + /*- Process the X coordinate */ + z = 0; + for (i = 0; i <= lastPoint; i++) { + if (pa[i].flags & 0x02) { + if (pa[i].flags & 0x10) { + z += (int) (*p++); + } else { + z -= (int) (*p++); + } + } else if ( !(pa[i].flags & 0x10)) { + z += GetInt16(p, 0, 1); + p += 2; + } + pa[i].x = z; + } + + /*- Process the Y coordinate */ + z = 0; + for (i = 0; i <= lastPoint; i++) { + if (pa[i].flags & 0x04) { + if (pa[i].flags & 0x20) { + z += *p++; + } else { + z -= *p++; + } + } else if ( !(pa[i].flags & 0x20)) { + z += GetInt16(p, 0, 1); + p += 2; + } + pa[i].y = z; + } + + for (i=0; i<numberOfContours; i++) { + pa[GetUInt16(ptr, 10 + i * 2, 1)].flags |= 0x00008000; /*- set the end contour flag */ + } + + *pointArray = pa; + return lastPoint + 1; +} + +static int GetCompoundTTOutline(TrueTypeFont *ttf, uint32 glyphID, ControlPoint **pointArray, TTGlyphMetrics *metrics, list glyphlist) /*FOLD02*/ +{ + uint16 flags, index; + int16 e, f, numberOfContours; + byte *table = getTable(ttf, O_glyf); + byte *ptr; + list myPoints; + ControlPoint *nextComponent, *pa; + int i, np; + F16Dot16 a = 0x10000, b = 0, c = 0, d = 0x10000, m, n, abs1, abs2, abs3; + + *pointArray = 0; + /* printf("GetCompoundTTOutline(%d)\n", glyphID); */ + + if (glyphID >= ttf->nglyphs) { /*- incorrect glyphID */ + return 0; + } + ptr = table + ttf->goffsets[glyphID]; + if ((numberOfContours = GetInt16(ptr, 0, 1)) != -1) { /*- glyph is not compound */ + return 0; + } + + myPoints = listNewEmpty(); + listSetElementDtor(myPoints, free); + + if (metrics) { + metrics->xMin = GetInt16(ptr, 2, 1); + metrics->yMin = GetInt16(ptr, 4, 1); + metrics->xMax = GetInt16(ptr, 6, 1); + metrics->yMax = GetInt16(ptr, 8, 1); + GetMetrics(ttf, glyphID, metrics); + } + + ptr += 10; + + do { + flags = GetUInt16(ptr, 0, 1); + /* printf("flags: 0x%X\n", flags); */ + index = GetUInt16(ptr, 2, 1); + ptr += 4; + + if (listFind(glyphlist, (void *) (int) index)) { +#ifdef DEBUG + fprintf(stderr, "Endless loop found in a compound glyph.\n"); + fprintf(stderr, "%d -> ", index); + listToFirst(glyphlist); + fprintf(stderr," ["); + do { + fprintf(stderr,"%d ", (int) listCurrent(glyphlist)); + } while (listNext(glyphlist)); + fprintf(stderr,"]\n"); + /**/ +#endif + } + + listAppend(glyphlist, (void *) (int) index); + +#ifdef DEBUG2 + fprintf(stderr,"glyphlist: += %d\n", index); +#endif + + if ((np = GetTTGlyphOutline(ttf, index, &nextComponent, 0, glyphlist)) == 0) { + /* XXX that probably indicates a corrupted font */ +#ifdef DEBUG + fprintf(stderr, "An empty compound!\n"); + /* assert(!"An empty compound"); */ +#endif + } + + listToLast(glyphlist); +#ifdef DEBUG2 + listToFirst(glyphlist); + fprintf(stderr,"%d [", listCount(glyphlist)); + if (!listIsEmpty(glyphlist)) { + do { + fprintf(stderr,"%d ", (int) listCurrent(glyphlist)); + } while (listNext(glyphlist)); + } + fprintf(stderr, "]\n"); + fprintf(stderr, "glyphlist: -= %d\n", (int) listCurrent(glyphlist)); + +#endif + listRemove(glyphlist); + + if (flags & USE_MY_METRICS) { + if (metrics) GetMetrics(ttf, index, metrics); + } + + if (flags & ARG_1_AND_2_ARE_WORDS) { + e = GetInt16(ptr, 0, 1); + f = GetInt16(ptr, 2, 1); + /* printf("ARG_1_AND_2_ARE_WORDS: %d %d\n", e & 0xFFFF, f & 0xFFFF); */ + ptr += 4; + } else { + if (flags & ARGS_ARE_XY_VALUES) { /* args are signed */ + e = (int8) *ptr++; + f = (int8) *ptr++; + /* printf("ARGS_ARE_XY_VALUES: %d %d\n", e & 0xFF, f & 0xFF); */ + } else { /* args are unsigned */ + /* printf("!ARGS_ARE_XY_VALUES\n"); */ + e = *ptr++; + f = *ptr++; + } + + } + + a = d = 0x10000; + b = c = 0; + + if (flags & WE_HAVE_A_SCALE) { +#ifdef DEBUG2 + fprintf(stderr, "WE_HAVE_A_SCALE\n"); +#endif + a = GetInt16(ptr, 0, 1) << 2; + d = a; + ptr += 2; + } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { +#ifdef DEBUG2 + fprintf(stderr, "WE_HAVE_AN_X_AND_Y_SCALE\n"); +#endif + a = GetInt16(ptr, 0, 1) << 2; + d = GetInt16(ptr, 2, 1) << 2; + ptr += 4; + } else if (flags & WE_HAVE_A_TWO_BY_TWO) { +#ifdef DEBUG2 + fprintf(stderr, "WE_HAVE_A_TWO_BY_TWO\n"); +#endif + a = GetInt16(ptr, 0, 1) << 2; + b = GetInt16(ptr, 2, 1) << 2; + c = GetInt16(ptr, 4, 1) << 2; + d = GetInt16(ptr, 6, 1) << 2; + ptr += 8; + } + + abs1 = (a < 0) ? -a : a; + abs2 = (b < 0) ? -b : b; + m = (abs1 > abs2) ? abs1 : abs2; + abs3 = abs1 - abs2; + if (abs3 < 0) abs3 = -abs3; + if (abs3 <= 33) m *= 2; + + abs1 = (c < 0) ? -c : c; + abs2 = (d < 0) ? -d : d; + n = (abs1 > abs2) ? abs1 : abs2; + abs3 = abs1 - abs2; + if (abs3 < 0) abs3 = -abs3; + if (abs3 <= 33) n *= 2; + + if (!ARGS_ARE_XY_VALUES) { /* match the points */ + assert(!"ARGS_ARE_XY_VALUES is not implemented!!!\n"); + } + +#ifdef DEBUG2 + fprintf(stderr, "a: %f, b: %f, c: %f, d: %f, e: %f, f: %f, m: %f, n: %f\n", + ((double) a) / 65536, + ((double) b) / 65536, + ((double) c) / 65536, + ((double) d) / 65536, + ((double) e) / 65536, + ((double) f) / 65536, + ((double) m) / 65536, + ((double) n) / 65536); +#endif + + for (i=0; i<np; i++) { + F16Dot16 t; + ControlPoint *cp = malloc(sizeof(ControlPoint)); + cp->flags = nextComponent[i].flags; + t = fixedMulDiv(a, nextComponent[i].x << 16, m) + fixedMulDiv(c, nextComponent[i].y << 16, m) + (e << 16); + cp->x = fixedMul(t, m) >> 16; + t = fixedMulDiv(b, nextComponent[i].x << 16, n) + fixedMulDiv(d, nextComponent[i].y << 16, n) + (f << 16); + cp->y = fixedMul(t, n) >> 16; + +#ifdef DEBUG2 + fprintf(stderr, "( %d %d ) -> ( %d %d )\n", nextComponent[i].x, nextComponent[i].y, cp->x, cp->y); +#endif + + listAppend(myPoints, cp); + } + + free(nextComponent); + + } while (flags & MORE_COMPONENTS); + + + + np = listCount(myPoints); + + pa = calloc(np, sizeof(ControlPoint)); + assert(pa != 0); + listToFirst(myPoints); + for (i=0; i<np; i++) { + memcpy(pa+i, listCurrent(myPoints), sizeof(ControlPoint)); + listNext(myPoints); + } + listDispose(myPoints); + + *pointArray = pa; + return np; +} + +/* NOTE: GetTTGlyphOutline() returns -1 if the glyphID is incorrect, + * but Get{Simple|Compound}GlyphOutline returns 0 in such a case. + * + * NOTE: glyphlist is the stack of glyphs traversed while constructing + * a composite glyph. This is a safequard against endless recursion + * in corrupted fonts. + */ +static int GetTTGlyphOutline(TrueTypeFont *ttf, uint32 glyphID, ControlPoint **pointArray, TTGlyphMetrics *metrics, list glyphlist) +{ + byte *ptr, *table = getTable(ttf, O_glyf); + int16 numberOfContours; + int length; + int res; + *pointArray = 0; + + if (metrics) { + memset(metrics, 0, sizeof(TTGlyphMetrics)); /*- metrics is initialized to all zeroes */ + } + + if (glyphID >= ttf->nglyphs) return -1; /**/ + + ptr = table + ttf->goffsets[glyphID]; + length = ttf->goffsets[glyphID+1] - ttf->goffsets[glyphID]; + + if (length == 0) { /*- empty glyphs still have hmtx and vmtx metrics values */ + if (metrics) GetMetrics(ttf, glyphID, metrics); + return 0; + } + + numberOfContours = GetInt16(ptr, 0, 1); + + if (numberOfContours >= 0) { + res=GetSimpleTTOutline(ttf, glyphID, pointArray, metrics); + } else { + int glyphlistFlag = 0; + if (!glyphlist) { + glyphlistFlag = 1; + glyphlist = listNewEmpty(); + listAppend(glyphlist, (void *) glyphID); + } + res = GetCompoundTTOutline(ttf, glyphID, pointArray, metrics, glyphlist); + if (glyphlistFlag) { + glyphlistFlag = 0; + listDispose(glyphlist); + glyphlist = 0; + } + } + +#ifdef DEBUG3 + { + int i; + FILE *out = fopen("points.dat", "a"); + assert(out != 0); + fprintf(out, "Glyph: %d\nPoints: %d\n", glyphID, res); + for (i=0; i<res; i++) { + fprintf(out, "%c ", ((*pointArray)[i].flags & 0x8000) ? 'X' : '.'); + fprintf(out, "%c ", ((*pointArray)[i].flags & 1) ? '+' : '-'); + fprintf(out, "%d %d\n", (*pointArray)[i].x, (*pointArray)[i].y); + } + fclose(out); + } +#endif + + return res; +} + +#ifndef NO_TYPE3 + +static PSPathElement *newPSPathElement(int t) +{ + PSPathElement *p = malloc(sizeof(PSPathElement)); + assert(p != 0); + + p->type = t; + return p; +} + +/*- returns the number of items in the path -*/ + +static int BSplineToPSPath(ControlPoint *srcA, int srcCount, PSPathElement **path) +{ + list pList = listNewEmpty(); + int i = 0, pCount = 0; + PSPathElement *p; + + int x0, y0, x1, y1, x2, y2, curx, cury; + int lastOff = 0; /*- last point was off-contour */ + int scflag = 1; /*- start contour flag */ + int ecflag = 0; /*- end contour flag */ + int cp = 0; /*- current point */ + + listSetElementDtor(pList, free); + *path = 0; + + /* if (srcCount > 0) for(;;) */ + while (srcCount > 0) { /*- srcCount does not get changed inside the loop. */ + int StartContour, EndContour; + + if (scflag) { + int l = cp; + StartContour = cp; + while (!(srcA[l].flags & 0x8000)) l++; + EndContour = l; + if (StartContour == EndContour) { + if (cp + 1 < srcCount) { + cp++; + continue; + } else { + break; + } + } + p = newPSPathElement(PS_MOVETO); + if (!(srcA[cp].flags & 1)) { + if (!(srcA[EndContour].flags & 1)) { + p->x1 = x0 = (srcA[cp].x + srcA[EndContour].x + 1) / 2; + p->y1 = y0 = (srcA[cp].y + srcA[EndContour].y + 1) / 2; + } else { + p->x1 = x0 = srcA[EndContour].x; + p->y1 = y0 = srcA[EndContour].y; + } + } else { + p->x1 = x0 = srcA[cp].x; + p->y1 = y0 = srcA[cp].y; + cp++; + } + listAppend(pList, p); + lastOff = 0; + scflag = 0; + } + + curx = srcA[cp].x; + cury = srcA[cp].y; + + if (srcA[cp].flags & 1) { + if (lastOff) { + p = newPSPathElement(PS_CURVETO); + p->x1 = x0 + (2 * (x1 - x0) + 1) / 3; + p->y1 = y0 + (2 * (y1 - y0) + 1) / 3; + p->x2 = x1 + (curx - x1 + 1) / 3; + p->y2 = y1 + (cury - y1 + 1) / 3; + p->x3 = curx; + p->y3 = cury; + listAppend(pList, p); + } else { + if (!(x0 == curx && y0 == cury)) { /* eliminate empty lines */ + p = newPSPathElement(PS_LINETO); + p->x1 = curx; + p->y1 = cury; + listAppend(pList, p); + } + } + + x0 = curx; y0 = cury; lastOff = 0; + } else { + if (lastOff) { + x2 = (x1 + curx + 1) / 2; + y2 = (y1 + cury + 1) / 2; + p = newPSPathElement(PS_CURVETO); + p->x1 = x0 + (2 * (x1 - x0) + 1) / 3; + p->y1 = y0 + (2 * (y1 - y0) + 1) / 3; + p->x2 = x1 + (x2 - x1 + 1) / 3; + p->y2 = y1 + (y2 - y1 + 1) / 3; + p->x3 = x2; + p->y3 = y2; + listAppend(pList, p); + x0 = x2; y0 = y2; + x1 = curx; y1 = cury; + } else { + x1 = curx; y1 = cury; + } + lastOff = true; + } + + if (ecflag) { + listAppend(pList, newPSPathElement(PS_CLOSEPATH)); + scflag = 1; + ecflag = 0; + cp = EndContour + 1; + if (cp >= srcCount) break; + continue; + } + + if (cp == EndContour) { + cp = StartContour; + ecflag = true; + } else { + cp++; + } + } + + if ((pCount = listCount(pList)) > 0) { + p = calloc(pCount, sizeof(PSPathElement)); + assert(p != 0); + listToFirst(pList); + for (i=0; i<pCount; i++) { + memcpy(p + i, listCurrent(pList), sizeof(PSPathElement)); + listNext(pList); + } + listDispose(pList); + *path = p; + } + + return pCount; +} + +#endif + +/*- Extracts a string from the name table and allocates memory for it -*/ + +static char *nameExtract(byte *name, int n, int dbFlag) +{ + int i; + char *res; + byte *ptr = name + GetUInt16(name, 4, 1) + GetUInt16(name + 6, 12 * n + 10, 1); + int len = GetUInt16(name+6, 12 * n + 8, 1); + + if (dbFlag) { + res = malloc(1 + len/2); + assert(res != 0); + for (i = 0; i < len/2; i++) res[i] = *(ptr + i * 2 + 1); + res[len/2] = 0; + } else { + res = malloc(1 + len); + assert(res != 0); + memcpy(res, ptr, len); + res[len] = 0; + } + + return res; +} + +static int findname(byte *name, uint16 n, uint16 platformID, uint16 encodingID, uint16 languageID, uint16 nameID) +{ + int l = 0, r = n-1, i; + uint32 t1, t2; + uint32 m1, m2; + + if (n == 0) return -1; + + m1 = (platformID << 16) | encodingID; + m2 = (languageID << 16) | nameID; + + do { + i = (l + r) >> 1; + t1 = GetUInt32(name + 6, i * 12 + 0, 1); + t2 = GetUInt32(name + 6, i * 12 + 4, 1); + + if (! ((m1 < t1) || ((m1 == t1) && (m2 < t2)))) l = i + 1; + if (! ((m1 > t1) || ((m1 == t1) && (m2 > t2)))) r = i - 1; + } while (l <= r); + + if (l - r == 2) { + return l - 1; + } + + return -1; +} + +/* XXX marlett.ttf uses (3, 0, 1033) instead of (3, 1, 1033) and does not have any Apple tables. + * Fix: if (3, 1, 1033) is not found - need to check for (3, 0, 1033) + * + * /d/fonts/ttzh_tw/Big5/Hanyi/ma6b5p uses (1, 0, 19) for English strings, instead of (1, 0, 0) + * and does not have (3, 1, 1033) + * Fix: if (1, 0, 0) and (3, 1, 1033) are not found need to look for (1, 0, *) - that will + * require a change in algorithm + * + * /d/fonts/fdltest/Korean/h2drrm has unsorted names and a an unknown (to me) Mac LanguageID, + * but (1, 0, 1042) strings usable + * Fix: change algorithm, and use (1, 0, *) if both standard Mac and MS strings are not found + */ + +static void GetNames(TrueTypeFont *t) +{ + byte *table = getTable(t, O_name); + uint16 n = GetUInt16(table, 2, 1); + int i, r; + + /* PostScript name: preferred Microsoft */ + if ((r = findname(table, n, 3, 1, 0x0409, 6)) != -1) { + t->psname = nameExtract(table, r, 1); + } else if ((r = findname(table, n, 1, 0, 0, 6)) != -1) { + t->psname = nameExtract(table, r, 0); + } else { + char* pReverse = t->fname + strlen(t->fname); + /* take only last token of filename */ + while(pReverse != t->fname && *pReverse != '/') pReverse--; + if(*pReverse == '/') pReverse++; + t->psname = strdup(pReverse); + assert(t->psname != 0); + for (i=strlen(t->psname) - 1; i > 0; i--) { /*- Remove the suffix -*/ + if (t->psname[i] == '.' ) { + t->psname[i] = 0; + break; + } + } + } + + /* Font family and subfamily names: preferred Apple */ + if ((r = findname(table, n, 1, 0, 0, 1)) != -1) { + t->family = nameExtract(table, r, 0); + } else if ((r = findname(table, n, 3, 1, 0x0409, 1)) != -1) { + t->family = nameExtract(table, r, 1); + } else { + t->family = strdup(t->psname); + assert(t->family != 0); + } + + if ((r = findname(table, n, 1, 0, 0, 2)) != -1) { + t->subfamily = nameExtract(table, r, 0); + } else if ((r = findname(table, n, 3, 1, 0x0409, 2)) != -1) { + t->subfamily = nameExtract(table, r, 1); + } else { + t->subfamily = strdup(""); + assert(t->family != 0); + } + +} + +enum cmapType { + CMAP_NOT_USABLE = -1, + CMAP_MS_Symbol = 10, + CMAP_MS_Unicode = 11, + CMAP_MS_ShiftJIS = 12, + CMAP_MS_Big5 = 13, + CMAP_MS_PRC = 14, + CMAP_MS_Wansung = 15, + CMAP_MS_Johab = 16 +}; + +#define MISSING_GLYPH_INDEX 0 + +/* + * All getGlyph?() functions and freinds are implemented by: + * @author Manpreet Singh + */ +static uint16 getGlyph0(const byte* cmap, uint16 c) { + if (c <= 255) { + return *(cmap + 6 + c); + } else { + return MISSING_GLYPH_INDEX; + } +} + +typedef struct _subHeader2 { + uint16 firstCode; + uint16 entryCount; + uint16 idDelta; + uint16 idRangeOffset; +} subHeader2; + +static uint16 getGlyph2(const byte *cmap, uint16 c) { + uint16 *CMAP2 = (uint16 *) cmap; + byte theHighByte; + byte theLowByte; + subHeader2* subHeader2s; + uint16* subHeader2Keys; + uint16 firstCode; + int k; + int ToReturn; + + theHighByte = (byte)((c >> 8) & 0x00ff); + theLowByte = (byte)(c & 0x00ff); + subHeader2Keys = CMAP2 + 3; + subHeader2s = (subHeader2 *)(subHeader2Keys + 256); + k = Int16FromMOTA(subHeader2Keys[theHighByte]) / 8; + + if(k == 0) { + firstCode = Int16FromMOTA(subHeader2s[k].firstCode); + if(theLowByte >= firstCode && theLowByte < (firstCode + Int16FromMOTA(subHeader2s[k].entryCount))) { + return *((&(subHeader2s[0].idRangeOffset)) + + (Int16FromMOTA(subHeader2s[0].idRangeOffset)/2) /* + offset */ + + theLowByte /* + to_look */ + - Int16FromMOTA(subHeader2s[0].firstCode) + ); + } else { + return MISSING_GLYPH_INDEX; + } + } else if (k > 0) { + firstCode = Int16FromMOTA(subHeader2s[k].firstCode); + if(theLowByte >= firstCode && theLowByte < (firstCode + Int16FromMOTA(subHeader2s[k].entryCount))) { + ToReturn = *((&(subHeader2s[k].idRangeOffset)) + + (Int16FromMOTA(subHeader2s[k].idRangeOffset)/2) + + theLowByte - firstCode); + if(ToReturn == 0) { + return MISSING_GLYPH_INDEX; + } else { + return (uint16)((ToReturn + Int16FromMOTA(subHeader2s[k].idDelta)) % 0xFFFF); + } + } else { + return MISSING_GLYPH_INDEX; + } + } else { + return MISSING_GLYPH_INDEX; + } +} + +static uint16 getGlyph6(const byte *cmap, uint16 c) { + uint16 firstCode; + uint16 *CMAP6 = (uint16 *) cmap; + + firstCode = *(CMAP6 + 3); + if (c < firstCode || c > (firstCode + (*(CMAP6 + 4))/*entryCount*/ - 1)) { + return MISSING_GLYPH_INDEX; + } else { + return *((CMAP6 + 5)/*glyphIdArray*/ + (c - firstCode)); + } +} + +static uint16 GEbinsearch(uint16 *ar, uint16 length, uint16 toSearch) { + signed int low, mid, high, lastfound = 0xffff; + uint16 res; + if(length == (uint16)0 || length == (uint16)0xFFFF) { + return (uint16)0xFFFF; + } + low = 0; + high = length - 1; + while(high >= low) { + mid = (high + low)/2; + res = Int16FromMOTA(*(ar+mid)); + if(res >= toSearch) { + lastfound = mid; + high = --mid; + } else { + low = ++mid; + } + } + return lastfound; +} + + +static uint16 getGlyph4(const byte *cmap, uint16 c) { + uint16 i; + int ToReturn; + uint16 segCount; + uint16 * startCode; + uint16 * endCode; + uint16 * idDelta; + /* uint16 * glyphIdArray; */ + uint16 * idRangeOffset; + uint16 * glyphIndexArray; + uint16 *CMAP4 = (uint16 *) cmap; + /* uint16 GEbinsearch(uint16 *ar, uint16 length, uint16 toSearch); */ + + segCount = Int16FromMOTA(*(CMAP4 + 3))/2; + endCode = CMAP4 + 7; + i = GEbinsearch(endCode, segCount, c); + + if (i == (uint16) 0xFFFF) { + return MISSING_GLYPH_INDEX; + } + startCode = endCode + segCount + 1; + + if(Int16FromMOTA(startCode[i]) > c) { + return MISSING_GLYPH_INDEX; + } + idDelta = startCode + segCount; + idRangeOffset = idDelta + segCount; + glyphIndexArray = idRangeOffset + segCount; + + if(Int16FromMOTA(idRangeOffset[i]) != 0) { + ToReturn = Int16FromMOTA(*(&(idRangeOffset[i]) + (Int16FromMOTA(idRangeOffset[i])/2 + (c - Int16FromMOTA(startCode[i]))))); + } else { + ToReturn = (Int16FromMOTA(idDelta[i]) + c)%65536; + } + return ToReturn; +} + +static void FindCmap(TrueTypeFont *ttf) +{ + byte *table = getTable(ttf, O_cmap); + uint16 ncmaps = GetUInt16(table, 2, 1); + int i; + uint32 ThreeZero = 0; /* MS Symbol */ + uint32 ThreeOne = 0; /* MS Unicode */ + uint32 ThreeTwo = 0; /* MS ShiftJIS */ + uint32 ThreeThree = 0; /* MS Big5 */ + uint32 ThreeFour = 0; /* MS PRC */ + uint32 ThreeFive = 0; /* MS Wansung */ + uint32 ThreeSix = 0; /* MS Johab */ + + for (i = 0; i < ncmaps; i++) { + uint32 offset; + uint16 pID, eID; + + pID = GetUInt16(table, 4 + i * 8, 1); + eID = GetUInt16(table, 6 + i * 8, 1); + offset = GetUInt32(table, 8 + i * 8, 1); + + if (pID == 3) { + switch (eID) { + case 0: ThreeZero = offset; break; + case 1: ThreeOne = offset; break; + case 2: ThreeTwo = offset; break; + case 3: ThreeThree = offset; break; + case 4: ThreeFour = offset; break; + case 5: ThreeFive = offset; break; + case 6: ThreeSix = offset; break; + } + } + } + + if (ThreeOne) { + ttf->cmapType = CMAP_MS_Unicode; + ttf->cmap = table + ThreeOne; + } else if (ThreeTwo) { + ttf->cmapType = CMAP_MS_ShiftJIS; + ttf->cmap = table + ThreeTwo; + } else if (ThreeThree) { + ttf->cmapType = CMAP_MS_Big5; + ttf->cmap = table + ThreeThree; + } else if (ThreeFour) { + ttf->cmapType = CMAP_MS_PRC; + ttf->cmap = table + ThreeFour; + } else if (ThreeFive) { + ttf->cmapType = CMAP_MS_Wansung; + ttf->cmap = table + ThreeFive; + } else if (ThreeSix) { + ttf->cmapType = CMAP_MS_Johab; + ttf->cmap = table + ThreeSix; + } else if (ThreeZero) { + ttf->cmapType = CMAP_MS_Symbol; + ttf->cmap = table + ThreeZero; + } else { + ttf->cmapType = CMAP_NOT_USABLE; + ttf->cmap = 0; + } + + if (ttf->cmapType != CMAP_NOT_USABLE) { + + switch (GetUInt16(ttf->cmap, 0, 1)) { + case 0: ttf->mapper = getGlyph0; break; + case 2: ttf->mapper = getGlyph2; break; + case 4: ttf->mapper = getGlyph4; break; + case 6: ttf->mapper = getGlyph6; break; + default: +#ifdef DEBUG + /*- if the cmap table is really broken */ + printf("%s: %d is not a recognized cmap format.\n", ttf->fname, GetUInt16(ttf->cmap, 0, 1)); +#endif + ttf->cmapType = CMAP_NOT_USABLE; + ttf->cmap = 0; + ttf->mapper = 0; + } + } +} + +static void GetKern(TrueTypeFont *ttf) +{ + byte *table = getTable(ttf, O_kern); + byte *ptr; + int i; + /* + uint16 v1; + uint32 v2; + */ + + if (!table) goto badtable; + + if (GetUInt16(table, 0, 1) == 0) { /* Traditional Microsoft style table with USHORT version and nTables fields */ + ttf->nkern = GetUInt16(table, 2, 1); + ttf->kerntables = calloc(ttf->nkern, sizeof(byte *)); + assert(ttf->kerntables != 0); + memset(ttf->kerntables, 0, ttf->nkern * sizeof(byte *)); + ttf->kerntype = KT_MICROSOFT; + ptr = table + 4; + for (i=0; i < ttf->nkern; i++) { + ttf->kerntables[i] = ptr; + ptr += GetUInt16(ptr, 2, 1); + } + return; + } + + if (GetUInt32(table, 0, 1) == 0x00010000) { /* MacOS style kern tables: fixed32 version and uint32 nTables fields */ + ttf->nkern = GetUInt32(table, 4, 1); + ttf->kerntables = calloc(ttf->nkern, sizeof(byte *)); + assert(ttf->kerntables != 0); + memset(ttf->kerntables, 0, ttf->nkern * sizeof(byte *)); + ttf->kerntype = KT_APPLE_NEW; + ptr = table + 8; + for (i = 0; i < ttf->nkern; i++) { + ttf->kerntables[i] = ptr; + ptr += GetUInt32(ptr, 0, 1); + } + return; + } + + badtable: + ttf->kerntype = KT_NONE; + ttf->kerntables = 0; + + return; +} + +/* KernGlyphsPrim?() functions expect the caller to ensure the validity of their arguments and + * that x and y elements of the kern array are initialized to zeroes + */ +static void KernGlyphsPrim1(TrueTypeFont *ttf, uint16 *glyphs, int nglyphs, int wmode, KernData *kern) +{ + fprintf(stderr, "MacOS kerning tables have not been implemented yet!\n"); +} + +static void KernGlyphsPrim2(TrueTypeFont *ttf, uint16 *glyphs, int nglyphs, int wmode, KernData *kern) +{ + int i, j; + uint32 gpair; + + for (i = 0; i < nglyphs - 1; i++) { + gpair = (glyphs[i] << 16) | glyphs[i+1]; +#ifdef DEBUG2 + /* All fonts with MS kern table that I've seen so far contain just one kern subtable. + * MS kern documentation is very poor and I doubt that font developers will be using + * several subtables. I expect them to be using OpenType tables instead. + * According to MS documention, format 2 subtables are not supported by Windows and OS/2. + */ + if (ttf->nkern > 1) { + fprintf(stderr, "KernGlyphsPrim2: %d kern tables found.\n", ttf->nkern); + } +#endif + for (j = 0; j < ttf->nkern; j++) { + uint16 coverage = GetUInt16(ttf->kerntables[j], 4, 1); + byte *ptr; + int npairs; + uint32 t; + int l, r, k; + + if (! ((coverage & 1) ^ wmode)) continue; + if ((coverage & 0xFFFE) != 0) { +#ifdef DEBUG2 + fprintf(stderr, "KernGlyphsPrim2: coverage flags are not supported: %04X.\n", coverage); +#endif + continue; + } + ptr = ttf->kerntables[j]; + npairs = GetUInt16(ptr, 6, 1); + ptr += 14; + l = 0; + r = npairs; + do { + k = (l + r) >> 1; + t = GetUInt32(ptr, k * 6, 1); + if (gpair >= t) l = k + 1; + if (gpair <= t) r = k - 1; + } while (l <= r); + if (l - r == 2) { + if (!wmode) { + kern[i].x = XUnits(ttf->unitsPerEm, GetInt16(ptr, 4 + (l-1) * 6, 1)); + } else { + kern[i].y = XUnits(ttf->unitsPerEm, GetInt16(ptr, 4 + (l-1) * 6, 1)); + } + /* !wmode ? kern[i].x : kern[i].y = GetInt16(ptr, 4 + (l-1) * 6, 1); */ + } + } + } +} + +/*- Public functions */ /*FOLD00*/ + +int CountTTCFonts(const char* fname) +{ + int nFonts = 0; + byte buffer[12]; + int fd = open(fname, O_RDONLY); + if( fd != -1 ) { + if (read(fd, buffer, 12) == 12) { + if(GetUInt32(buffer, 0, 1) == T_ttcf ) + nFonts = GetUInt32(buffer, 8, 1); + } + close(fd); + } + return nFonts; +} + + +int OpenTTFont(const char *fname, uint32 facenum, TrueTypeFont** ttf) /*FOLD01*/ +{ + TrueTypeFont *t; + int ret, i, fd = -1; + struct stat st; + uint32 version; + byte *table, *offset; + uint32 length, tag; + uint32 tdoffset = 0; /* offset to TableDirectory in a TTC file. For TTF files is 0 */ + + int indexfmt, k; + + *ttf = 0; + + if (!fname || !*fname) return SF_BADFILE; + + t = malloc(sizeof(TrueTypeFont)); + assert(t != 0); + t->tag = 0; + t->fname = 0; + t->fsize = -1; + t->ptr = 0; + t->nglyphs = 0xFFFFFFFF; + t->pGSubstitution = 0; + + t->fname = strdup(fname); + assert(t->fname != 0); + + fd = open(fname, O_RDONLY); + + if (fd == -1) { + ret = SF_BADFILE; + goto cleanup; + } + + if (fstat(fd, &st) == -1) { + ret = SF_FILEIO; + goto cleanup; + } + t->fsize = st.st_size; + + if ((t->ptr = (byte *) mmap(0, t->fsize, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { + ret = SF_MEMORY; + goto cleanup; + } + close(fd); + + version = GetInt32(t->ptr, 0, 1); + + if ((version == 0x00010000) || (version == T_true)) { + tdoffset = 0; + } else if (version == T_ttcf) { /*- TrueType collection */ + if (GetUInt32(t->ptr, 4, 1) != 0x00010000) { + CloseTTFont(t); + return SF_TTFORMAT; + } + if (facenum >= GetUInt32(t->ptr, 8, 1)) { + CloseTTFont(t); + return SF_FONTNO; + } + tdoffset = GetUInt32(t->ptr, 12 + 4 * facenum, 1); + } else { + CloseTTFont(t); + return SF_TTFORMAT; + } + +#ifdef DEBUG2 + fprintf(stderr, "tdoffset: %d\n", tdoffset); +#endif + + /* magic number */ + t->tag = TTFontClassTag; + + t->ntables = GetUInt16(t->ptr + tdoffset, 4, 1); + + t->tables = calloc(NUM_TAGS, sizeof(void *)); + assert(t->tables != 0); + t->tlens = calloc(NUM_TAGS, sizeof(uint32)); + assert(t->tlens != 0); + + memset(t->tables, 0, NUM_TAGS * sizeof(void *)); + memset(t->tlens, 0, NUM_TAGS * sizeof(uint32)); + + + /* parse the tables */ + for (i=0; i<t->ntables; i++) { + tag = GetUInt32(t->ptr + tdoffset + 12, 16 * i, 1); + offset = t->ptr + GetUInt32(t->ptr + tdoffset + 12, 16 * i + 8, 1); + length = GetUInt32(t->ptr + tdoffset + 12, 16 * i + 12, 1); + + if (tag == T_maxp) { t->tables[O_maxp] = offset; t->tlens[O_maxp] = length; continue; } + if (tag == T_glyf) { t->tables[O_glyf] = offset; t->tlens[O_glyf] = length; continue; } + if (tag == T_head) { t->tables[O_head] = offset; t->tlens[O_head] = length; continue; } + if (tag == T_loca) { t->tables[O_loca] = offset; t->tlens[O_loca] = length; continue; } + if (tag == T_name) { t->tables[O_name] = offset; t->tlens[O_name] = length; continue; } + if (tag == T_hhea) { t->tables[O_hhea] = offset; t->tlens[O_hhea] = length; continue; } + if (tag == T_hmtx) { t->tables[O_hmtx] = offset; t->tlens[O_hmtx] = length; continue; } + if (tag == T_cmap) { t->tables[O_cmap] = offset; t->tlens[O_cmap] = length; continue; } + if (tag == T_vhea) { t->tables[O_vhea] = offset; t->tlens[O_vhea] = length; continue; } + if (tag == T_vmtx) { t->tables[O_vmtx] = offset; t->tlens[O_vmtx] = length; continue; } + if (tag == T_OS2 ) { t->tables[O_OS2 ] = offset; t->tlens[O_OS2 ] = length; continue; } + if (tag == T_post) { t->tables[O_post] = offset; t->tlens[O_post] = length; continue; } + if (tag == T_kern) { t->tables[O_kern] = offset; t->tlens[O_kern] = length; continue; } + if (tag == T_cvt ) { t->tables[O_cvt ] = offset; t->tlens[O_cvt ] = length; continue; } + if (tag == T_prep) { t->tables[O_prep] = offset; t->tlens[O_prep] = length; continue; } + if (tag == T_fpgm) { t->tables[O_fpgm] = offset; t->tlens[O_fpgm] = length; continue; } + if (tag == T_gsub) { t->tables[O_gsub] = offset; t->tlens[O_gsub] = length; continue; } + } + + + /* At this point TrueTypeFont is constructed, now need to verify the font format + and read the basic font properties */ + + /* The following tables are absolutely required: + * maxp, head, glyf, loca, name, cmap + */ + + if (!(getTable(t, O_maxp) && getTable(t, O_head) && getTable(t, O_glyf) && getTable(t, O_loca) && getTable(t, O_name) && getTable(t, O_cmap) )) { + CloseTTFont(t); + return SF_TTFORMAT; + } + + table = getTable(t, O_maxp); + t->nglyphs = GetUInt16(table, 4, 1); + + table = getTable(t, O_head); + t->unitsPerEm = GetUInt16(table, 18, 1); + indexfmt = GetInt16(table, 50, 1); + + if (!((indexfmt == 0) || indexfmt == 1)) { + CloseTTFont(t); + return SF_TTFORMAT; + } + + k = (getTableSize(t, O_loca) / (indexfmt ? 4 : 2)) - 1; + if (k < t->nglyphs) t->nglyphs = k; /* Hack for broken Chinese fonts */ + + table = getTable(t, O_loca); + + t->goffsets = (uint32 *) calloc(1+t->nglyphs, sizeof(uint32)); + assert(t->goffsets != 0); + + for (i = 0; i <= t->nglyphs; i++) { + t->goffsets[i] = indexfmt ? GetUInt32(table, i << 2, 1) : GetUInt16(table, i << 1, 1) << 1; + } + + table = getTable(t, O_hhea); + t->numberOfHMetrics = (table != 0) ? GetUInt16(table, 34, 1) : 0; + + table = getTable(t, O_vhea); + t->numOfLongVerMetrics = (table != 0) ? GetUInt16(table, 34, 1) : 0; + + GetNames(t); + FindCmap(t); + GetKern(t); + ReadGSUB(t,t->tables[O_gsub],0,0); + + *ttf = t; + return SF_OK; + + cleanup: + /*- t and t->fname have been allocated! */ + free(t->fname); + free(t); + if (fd != -1) close(fd); + return ret; +} + +void CloseTTFont(TrueTypeFont *ttf) /*FOLD01*/ +{ + if (ttf->tag != TTFontClassTag) return; + + munmap((char *) ttf->ptr, ttf->fsize); + free(ttf->fname); + free(ttf->goffsets); + free(ttf->psname); + free(ttf->family); + free(ttf->subfamily); + free(ttf->tables); + free(ttf->tlens); + free(ttf->kerntables); + free(ttf); + return; +} + +int GetTTGlyphPoints(TrueTypeFont *ttf, uint32 glyphID, ControlPoint **pointArray) +{ + return GetTTGlyphOutline(ttf, glyphID, pointArray, 0, 0); +} + +#ifdef NO_LIST +static +#endif +int GetTTGlyphComponents(TrueTypeFont *ttf, uint32 glyphID, list glyphlist) +{ + byte *ptr, *glyf = getTable(ttf, O_glyf); + int n = 1; + + if (glyphID >= ttf->nglyphs) return 0; + ptr = glyf + ttf->goffsets[glyphID]; + + listAppend(glyphlist, (void *) glyphID); + + if (GetInt16(ptr, 0, 1) == -1) { + uint16 flags, index; + ptr += 10; + do { + flags = GetUInt16(ptr, 0, 1); + index = GetUInt16(ptr, 2, 1); + + ptr += 4; + n += GetTTGlyphComponents(ttf, index, glyphlist); + + if (flags & ARG_1_AND_2_ARE_WORDS) { + ptr += 4; + } else { + ptr += 2; + } + + if (flags & WE_HAVE_A_SCALE) { + ptr += 2; + } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { + ptr += 4; + } else if (flags & WE_HAVE_A_TWO_BY_TWO) { + ptr += 8; + } + } while (flags & MORE_COMPONENTS); + } + + return n; +} + +#ifndef NO_TYPE3 +int CreateT3FromTTGlyphs(TrueTypeFont *ttf, FILE *outf, const char *fname, /*FOLD00*/ + uint16 *glyphArray, byte *encoding, int nGlyphs, + int wmode) +{ + ControlPoint *pa; + PSPathElement *path; + int i, j, r, n; + byte *table = getTable(ttf, O_head); + TTGlyphMetrics metrics; + int UPEm = ttf->unitsPerEm; + + const char *h01 = "%%!PS-AdobeFont-%d.%d-%d.%d\n"; + const char *h02 = "%%%%Creator: %s %s %s\n"; + const char *h03 = "%%%%Title: %s\n"; + const char *h04 = "%%%%CreationDate: %s\n"; + const char *h05 = "%%%%Pages: 0\n"; + const char *h06 = "%%%%EndComments\n"; + const char *h07 = "%%%%BeginResource: font %s\n"; + const char *h08 = "%%%%EndResource\n"; + const char *h09 = "%% Original font name: %s\n"; + + const char *h10 = + "30 dict begin\n" + "/PaintType 0 def\n" + "/FontType 3 def\n" + "/StrokeWidth 0 def\n"; + + const char *h11 = "/FontName /%s def\n"; + + /* + const char *h12 = "%/UniqueID %d def\n"; + */ + const char *h13 = "/FontMatrix [.001 0 0 .001 0 0] def\n"; + const char *h14 = "/FontBBox [%d %d %d %d] def\n"; + + const char *h15= + "/Encoding 256 array def\n" + " 0 1 255 {Encoding exch /.notdef put} for\n"; + + const char *h16 = " Encoding %d /glyph%d put\n"; + const char *h17 = "/XUID [103 0 0 16#%08X %d 16#%08X 16#%08X] def\n"; + + const char *h30 = "/CharProcs %d dict def\n"; + const char *h31 = " CharProcs begin\n"; + const char *h32 = " /.notdef {} def\n"; + const char *h33 = " /glyph%d {\n"; + const char *h34 = " } bind def\n"; + const char *h35 = " end\n"; + + const char *h40 = + "/BuildGlyph {\n" + " exch /CharProcs get exch\n" + " 2 copy known not\n" + " {pop /.notdef} if\n" + " get exec\n" + "} bind def\n" + "/BuildChar {\n" + " 1 index /Encoding get exch get\n" + " 1 index /BuildGlyph get exec\n" + "} bind def\n" + "currentdict end\n"; + + const char *h41 = "/%s exch definefont pop\n"; + + + if (!((nGlyphs > 0) && (nGlyphs <= 256))) return SF_GLYPHNUM; + if (!glyphArray) return SF_BADARG; + if (!fname) fname = ttf->psname; + + fprintf(outf, h01, GetInt16(table, 0, 1), GetUInt16(table, 2, 1), GetInt16(table, 4, 1), GetUInt16(table, 6, 1)); + fprintf(outf, h02, modname, modver, modextra); + fprintf(outf, h03, fname); + fprintf(outf, h04, " "); + fprintf(outf, h05); + fprintf(outf, h06); + fprintf(outf, h07, fname); + fprintf(outf, h09, ttf->psname); + + fprintf(outf, h10); + fprintf(outf, h11, fname); +/* fprintf(outf, h12, 4000000); */ + + /* XUID generation: + * 103 0 0 C1 C2 C3 C4 + * C1 - CRC-32 of the entire source TrueType font + * C2 - number of glyphs in the subset + * C3 - CRC-32 of the glyph array + * C4 - CRC-32 of the encoding array + * + * All CRC-32 numbers are presented as hexadecimal numbers + */ + + fprintf(outf, h17, crc32(ttf->ptr, ttf->fsize), nGlyphs, crc32(glyphArray, nGlyphs * 2), crc32(encoding, nGlyphs)); + fprintf(outf, h13); + fprintf(outf, h14, XUnits(UPEm, GetInt16(table, 36, 1)), XUnits(UPEm, GetInt16(table, 38, 1)), XUnits(UPEm, GetInt16(table, 40, 1)), XUnits(UPEm, GetInt16(table, 42, 1))); + fprintf(outf, h15); + + for (i = 0; i < nGlyphs; i++) { + fprintf(outf, h16, encoding[i], i); + } + + fprintf(outf, h30, nGlyphs+1); + fprintf(outf, h31); + fprintf(outf, h32); + + for (i = 0; i < nGlyphs; i++) { + fprintf(outf, h33, i); + r = GetTTGlyphOutline(ttf, glyphArray[i] < ttf->nglyphs ? glyphArray[i] : 0, &pa, &metrics, 0); + + if (r > 0) { + n = BSplineToPSPath(pa, r, &path); + } else { + n = 0; /* glyph might have zero contours but valid metrics ??? */ + path = 0; + if (r < 0) { /* glyph is not present in the font - pa array was not allocated, so no need to free it */ + continue; + } + } + fprintf(outf, "\t%d %d %d %d %d %d setcachedevice\n", + wmode == 0 ? XUnits(UPEm, metrics.aw) : 0, + wmode == 0 ? 0 : -XUnits(UPEm, metrics.ah), + XUnits(UPEm, metrics.xMin), + XUnits(UPEm, metrics.yMin), + XUnits(UPEm, metrics.xMax), + XUnits(UPEm, metrics.yMax)); + + for (j = 0; j < n; j++) { + switch (path[j].type) { + case PS_MOVETO: + fprintf(outf, "\t%d %d moveto\n", XUnits(UPEm, path[j].x1), XUnits(UPEm, path[j].y1)); + break; + + case PS_LINETO: + fprintf(outf, "\t%d %d lineto\n", XUnits(UPEm, path[j].x1), XUnits(UPEm, path[j].y1)); + break; + + case PS_CURVETO: + fprintf(outf, "\t%d %d %d %d %d %d curveto\n", XUnits(UPEm, path[j].x1), XUnits(UPEm, path[j].y1), XUnits(UPEm, path[j].x2), XUnits(UPEm, path[j].y2), XUnits(UPEm, path[j].x3), XUnits(UPEm, path[j].y3)); + break; + + case PS_CLOSEPATH: + fprintf(outf, "\tclosepath\n"); + break; + } + } + if (n > 0) fprintf(outf, "\tfill\n"); /* if glyph is not a whitespace character */ + + fprintf(outf, h34); + + free(pa); + free(path); + } + fprintf(outf, h35); + + fprintf(outf, h40); + fprintf(outf, h41, fname); + + fprintf(outf, h08); + return SF_OK; +} +#endif + +#ifndef NO_TTCR +int CreateTTFromTTGlyphs(TrueTypeFont *ttf, + const char *fname, + uint16 *glyphArray, + byte *encoding, + int nGlyphs, + int nNameRecs, + NameRecord *nr, + uint32 flags) +{ + TrueTypeCreator *ttcr; + TrueTypeTable *head=0, *hhea=0, *maxp=0, *cvt=0, *prep=0, *glyf=0, *fpgm=0, *cmap=0, *name=0, *post = 0, *os2 = 0; + byte *p; + int i; + int res; + uint32 *gID; + + TrueTypeCreatorNewEmpty(T_true, &ttcr); + + /** name **/ + + if (flags & TTCF_AutoName) { + /* not implemented yet + NameRecord *names; + NameRecord newname; + int n = GetTTNameRecords(ttf, &names); + int n1 = 0, n2 = 0, n3 = 0, n4 = 0, n5 = 0, n6 = 0; + byte *cp1; + byte suffix[32]; + uint32 c1 = crc32(glyphArray, nGlyphs * 2); + uint32 c2 = crc32(encoding, nGlyphs); + int len; + snprintf(suffix, 31, "S%08X%08X-%d", c1, c2, nGlyphs); + + name = TrueTypeTableNew_name(0, 0); + for (i = 0; i < n; i++) { + if (names[i].platformID == 1 && names[i].encodingID == 0 && names[i].languageID == 0 && names[i].nameID == 1) { + + memcpy(newname, names+i, sizeof(NameRecord)); + newname.slen = name[i].slen + strlen(suffix); + */ + const byte ptr[] = {0,'T',0,'r',0,'u',0,'e',0,'T',0,'y',0,'p',0,'e',0,'S',0,'u',0,'b',0,'s',0,'e',0,'t'}; + NameRecord n1 = {1, 0, 0, 6, 14, "(byte *) TrueTypeSubset"}; + NameRecord n2 = {3, 1, 1033, 6, 28, 0}; + n2.sptr = (byte *) ptr; + name = TrueTypeTableNew_name(0, 0); + nameAdd(name, &n1); + nameAdd(name, &n2); + } else { + if (nNameRecs == 0) { + NameRecord *names; + int n = GetTTNameRecords(ttf, &names); + name = TrueTypeTableNew_name(n, names); + DisposeNameRecords(names, n); + } else { + name = TrueTypeTableNew_name(nNameRecs, nr); + } + } + + /** maxp **/ + maxp = TrueTypeTableNew_maxp(getTable(ttf, O_maxp), getTableSize(ttf, O_maxp)); + + /** hhea **/ + p = getTable(ttf, O_hhea); + if (p) { + hhea = TrueTypeTableNew_hhea(GetUInt16(p, 4, 1), GetUInt16(p, 6, 1), GetUInt16(p, 8, 1), GetUInt16(p, 18, 1), GetUInt16(p, 20, 1)); + } else { + hhea = TrueTypeTableNew_hhea(0, 0, 0, 0, 0); + } + + /** head **/ + + p = getTable(ttf, O_head); + assert(p != 0); + head = TrueTypeTableNew_head(GetUInt32(p, 4, 1), + GetUInt16(p, 16, 1), + GetUInt16(p, 18, 1), + p+20, + GetUInt16(p, 44, 1), + GetUInt16(p, 46, 1), + GetInt16(p, 48, 1)); + + + /** glyf **/ + + glyf = TrueTypeTableNew_glyf(); + gID = scalloc(nGlyphs, sizeof(uint32)); + + for (i = 0; i < nGlyphs; i++) { + gID[i] = glyfAdd(glyf, GetTTRawGlyphData(ttf, glyphArray[i]), ttf); + } + + + /** cmap **/ + cmap = TrueTypeTableNew_cmap(); + + for (i=0; i < nGlyphs; i++) { + cmapAdd(cmap, 0x0100, encoding[i], gID[i]); + } + + /** cvt **/ + if ((p = getTable(ttf, O_cvt)) != 0) { + cvt = TrueTypeTableNew(T_cvt, getTableSize(ttf, O_cvt), p); + } + + /** prep **/ + if ((p = getTable(ttf, O_prep)) != 0) { + prep = TrueTypeTableNew(T_prep, getTableSize(ttf, O_prep), p); + } + + /** fpgm **/ + if ((p = getTable(ttf, O_fpgm)) != 0) { + fpgm = TrueTypeTableNew(T_fpgm, getTableSize(ttf, O_fpgm), p); + } + + /** post **/ + if ((p = getTable(ttf, O_post)) != 0) { + post = TrueTypeTableNew_post(0x00030000, + GetUInt32(p, 4, 1), + GetUInt16(p, 8, 1), + GetUInt16(p, 10, 1), + GetUInt16(p, 12, 1)); + } else { + post = TrueTypeTableNew_post(0x00030000, 0, 0, 0, 0); + } + + if (flags & TTCF_IncludeOS2) { + if ((p = getTable(ttf, O_OS2)) != 0) { + os2 = TrueTypeTableNew(T_OS2, getTableSize(ttf, O_OS2), p); + } + } + + AddTable(ttcr, name); AddTable(ttcr, maxp); AddTable(ttcr, hhea); + AddTable(ttcr, head); AddTable(ttcr, glyf); AddTable(ttcr, cmap); + AddTable(ttcr, cvt ); AddTable(ttcr, prep); AddTable(ttcr, fpgm); + AddTable(ttcr, post); AddTable(ttcr, os2); + + if ((res = StreamToFile(ttcr, fname)) != SF_OK) { +#ifdef DEBUG + fprintf(stderr, "StreamToFile: error code: %d.\n", res); +#endif + } + + TrueTypeCreatorDispose(ttcr); + free(gID); + + return res; +} +#endif + + +#ifndef NO_TYPE42 +static GlyphOffsets *GlyphOffsetsNew(byte *sfntP) +{ + GlyphOffsets *res = smalloc(sizeof(GlyphOffsets)); + byte *loca; + uint16 i, numTables = GetUInt16(sfntP, 4, 1); + uint32 locaLen; + int16 indexToLocFormat; + + for (i = 0; i < numTables; i++) { + uint32 tag = GetUInt32(sfntP + 12, 16 * i, 1); + uint32 off = GetUInt32(sfntP + 12, 16 * i + 8, 1); + uint32 len = GetUInt32(sfntP + 12, 16 * i + 12, 1); + + if (tag == T_loca) { + loca = sfntP + off; + locaLen = len; + } else if (tag == T_head) { + indexToLocFormat = GetInt16(sfntP + off, 50, 1); + } + } + + res->nGlyphs = locaLen / ((indexToLocFormat == 1) ? 4 : 2); + assert(res->nGlyphs != 0); + res->offs = scalloc(res->nGlyphs, sizeof(uint32)); + + for (i = 0; i < res->nGlyphs; i++) { + if (indexToLocFormat == 1) { + res->offs[i] = GetUInt32(loca, i * 4, 1); + } else { + res->offs[i] = GetUInt16(loca, i * 2, 1) << 1; + } + } + return res; +} + +static void GlyphOffsetsDispose(GlyphOffsets *_this) +{ + if (_this) { + free(_this->offs); + free(_this); + } +} + +static void DumpSfnts(FILE *outf, byte *sfntP) +{ + HexFmt *h = HexFmtNew(outf); + uint16 i, numTables = GetUInt16(sfntP, 4, 1); + uint32 j, *offs, *len; + GlyphOffsets *go = GlyphOffsetsNew(sfntP); + byte pad[] = {0,0,0,0}; /* zeroes */ + + assert(numTables <= 9); /* Type42 has 9 required tables */ + + offs = scalloc(numTables, sizeof(uint32)); + len = scalloc(numTables, sizeof(uint32)); + + fputs("/sfnts [", outf); + HexFmtOpenString(h); + HexFmtBlockWrite(h, sfntP, 12); /* stream out the Offset Table */ + HexFmtBlockWrite(h, sfntP+12, 16 * numTables); /* stream out the Table Directory */ + + for (i=0; i<numTables; i++) { + uint32 tag = GetUInt32(sfntP + 12, 16 * i, 1); + uint32 off = GetUInt32(sfntP + 12, 16 * i + 8, 1); + uint32 len = GetUInt32(sfntP + 12, 16 * i + 12, 1); + + if (tag != T_glyf) { + HexFmtBlockWrite(h, sfntP + off, len); + } else { + byte *glyf = sfntP + off; + uint32 o, l; + for (j = 0; j < go->nGlyphs - 1; j++) { + o = go->offs[j]; + l = go->offs[j + 1] - o; + HexFmtBlockWrite(h, glyf + o, l); + } + } + HexFmtBlockWrite(h, pad, (4 - (len & 3)) & 3); + } + HexFmtCloseString(h); + fputs("] def\n", outf); + GlyphOffsetsDispose(go); + HexFmtDispose(h); + free(offs); + free(len); +} + +int CreateT42FromTTGlyphs(TrueTypeFont *ttf, + FILE *outf, + const char *psname, + uint16 *glyphArray, + byte *encoding, + int nGlyphs) +{ + TrueTypeCreator *ttcr; + TrueTypeTable *head=0, *hhea=0, *maxp=0, *cvt=0, *prep=0, *glyf=0, *fpgm=0; + byte *p; + int i; + int res; + + uint32 ver, rev; + byte *headP; + + byte *sfntP; + uint32 sfntLen; + int UPEm = ttf->unitsPerEm; + + uint16 *gID; + + if (nGlyphs >= 256) return SF_GLYPHNUM; + + assert(psname != 0); + + TrueTypeCreatorNewEmpty(T_true, &ttcr); + + /* head */ + headP = p = getTable(ttf, O_head); + assert(p != 0); + head = TrueTypeTableNew_head(GetUInt32(p, 4, 1), GetUInt16(p, 16, 1), GetUInt16(p, 18, 1), p+20, GetUInt16(p, 44, 1), GetUInt16(p, 46, 1), GetInt16(p, 48, 1)); + ver = GetUInt32(p, 0, 1); + rev = GetUInt32(p, 4, 1); + + /** hhea **/ + p = getTable(ttf, O_hhea); + if (p) { + hhea = TrueTypeTableNew_hhea(GetUInt16(p, 4, 1), GetUInt16(p, 6, 1), GetUInt16(p, 8, 1), GetUInt16(p, 18, 1), GetUInt16(p, 20, 1)); + } else { + hhea = TrueTypeTableNew_hhea(0, 0, 0, 0, 0); + } + + /** maxp **/ + maxp = TrueTypeTableNew_maxp(getTable(ttf, O_maxp), getTableSize(ttf, O_maxp)); + + /** cvt **/ + if ((p = getTable(ttf, O_cvt)) != 0) { + cvt = TrueTypeTableNew(T_cvt, getTableSize(ttf, O_cvt), p); + } + + /** prep **/ + if ((p = getTable(ttf, O_prep)) != 0) { + prep = TrueTypeTableNew(T_prep, getTableSize(ttf, O_prep), p); + } + + /** fpgm **/ + if ((p = getTable(ttf, O_fpgm)) != 0) { + fpgm = TrueTypeTableNew(T_fpgm, getTableSize(ttf, O_fpgm), p); + } + + /** glyf **/ + glyf = TrueTypeTableNew_glyf(); + gID = scalloc(nGlyphs, sizeof(uint32)); + + for (i = 0; i < nGlyphs; i++) { + gID[i] = glyfAdd(glyf, GetTTRawGlyphData(ttf, glyphArray[i]), ttf); + } + + AddTable(ttcr, head); AddTable(ttcr, hhea); AddTable(ttcr, maxp); AddTable(ttcr, cvt); + AddTable(ttcr, prep); AddTable(ttcr, glyf); AddTable(ttcr, fpgm); + + if ((res = StreamToMemory(ttcr, &sfntP, &sfntLen)) != SF_OK) { + TrueTypeCreatorDispose(ttcr); + free(gID); + return res; + } + + fprintf(outf, "%%!PS-TrueTypeFont-%d.%d-%d.%d\n", ver>>16, ver & 0xFFFF, rev>>16, rev & 0xFFFF); + fprintf(outf, "%%%%Creator: %s %s %s\n", modname, modver, modextra); + fprintf(outf, "%%- Font subset generated from a source font file: '%s'\n", ttf->fname); + fprintf(outf, "%%- Original font name: %s\n", ttf->psname); + fprintf(outf, "%%- Original font family: %s\n", ttf->family); + fprintf(outf, "%%- Original font sub-family: %s\n", ttf->subfamily); + fprintf(outf, "11 dict begin\n"); + fprintf(outf, "/FontName /%s def\n", psname); + fprintf(outf, "/PaintType 0 def\n"); + fprintf(outf, "/FontMatrix [1 0 0 1 0 0] def\n"); + fprintf(outf, "/FontBBox [%d %d %d %d] def\n", XUnits(UPEm, GetInt16(headP, 36, 1)), XUnits(UPEm, GetInt16(headP, 38, 1)), XUnits(UPEm, GetInt16(headP, 40, 1)), XUnits(UPEm, GetInt16(headP, 42, 1))); + fprintf(outf, "/FontType 42 def\n"); + fprintf(outf, "/Encoding 256 array def\n"); + fprintf(outf, " 0 1 255 {Encoding exch /.notdef put} for\n"); + + for (i = 1; i<nGlyphs; i++) { + fprintf(outf, "Encoding %d /glyph%d put\n", encoding[i], gID[i]); + } + fprintf(outf, "/XUID [103 0 1 16#%08X %d 16#%08X 16#%08X] def\n", crc32(ttf->ptr, ttf->fsize), nGlyphs, crc32(glyphArray, nGlyphs * 2), crc32(encoding, nGlyphs)); + + DumpSfnts(outf, sfntP); + + /* dump charstrings */ + fprintf(outf, "/CharStrings %d dict dup begin\n", nGlyphs); + fprintf(outf, "/.notdef 0 def\n"); + for (i = 1; i < glyfCount(glyf); i++) { + fprintf(outf,"/glyph%d %d def\n", i, i); + } + fprintf(outf, "end readonly def\n"); + + fprintf(outf, "FontName currentdict end definefont pop\n"); + TrueTypeCreatorDispose(ttcr); + free(gID); + free(sfntP); + return SF_OK; +} +#endif + + +#ifndef NO_MAPPERS +int MapString(TrueTypeFont *ttf, uint16 *str, int nchars, uint16 *glyphArray, int bvertical) +{ + int i; + uint16 *cp; + + if (ttf->cmapType == CMAP_NOT_USABLE ) return -1; + if (!nchars) return 0; + + if (glyphArray == 0) { + cp = str; + } else { + cp = glyphArray; + } + + switch (ttf->cmapType) { + case CMAP_MS_Symbol: + if( ttf->mapper == getGlyph0 ) { + uint16 aChar; + for( i = 0; i < nchars; i++ ) { + aChar = str[i]; + if( ( aChar & 0xf000 ) == 0xf000 ) + aChar &= 0x00ff; + cp[i] = aChar; + } + } + else if( glyphArray ) + memcpy(glyphArray, str, nchars * 2); + break; + + case CMAP_MS_Unicode: + if (glyphArray != 0) { + memcpy(glyphArray, str, nchars * 2); + } + break; + + case CMAP_MS_ShiftJIS: TranslateString12(str, cp, nchars); break; + case CMAP_MS_Big5: TranslateString13(str, cp, nchars); break; + case CMAP_MS_PRC: TranslateString14(str, cp, nchars); break; + case CMAP_MS_Wansung: TranslateString15(str, cp, nchars); break; + case CMAP_MS_Johab: TranslateString16(str, cp, nchars); break; + } + + for (i = 0; i < nchars; i++) { + cp[i] = ttf->mapper(ttf->cmap, cp[i]); + if (cp[i]!=0 && bvertical!=0) + cp[i] = UseGSUB(ttf,cp[i],bvertical); + } + return nchars; +} + +uint16 MapChar(TrueTypeFont *ttf, uint16 ch, int bvertical) +{ + switch (ttf->cmapType) { + case CMAP_MS_Symbol: + if( ttf->mapper == getGlyph0 && ( ch & 0xf000 ) == 0xf000 ) + ch &= 0x00ff; + return ttf->mapper(ttf->cmap, ch ); + + case CMAP_MS_Unicode: break; + case CMAP_MS_ShiftJIS: ch = TranslateChar12(ch); break; + case CMAP_MS_Big5: ch = TranslateChar13(ch); break; + case CMAP_MS_PRC: ch = TranslateChar14(ch); break; + case CMAP_MS_Wansung: ch = TranslateChar15(ch); break; + case CMAP_MS_Johab: ch = TranslateChar16(ch); break; + default: return 0; + } + ch = ttf->mapper(ttf->cmap, ch); + if (ch!=0 && bvertical!=0) + ch = UseGSUB(ttf,ch,bvertical); + return ch; +} +#endif + +TTSimpleGlyphMetrics *GetTTSimpleGlyphMetrics(TrueTypeFont *ttf, uint16 *glyphArray, int nGlyphs, int mode) +{ + byte *table; + TTSimpleGlyphMetrics *res; + int i; + uint16 glyphID; + int n; + int UPEm = ttf->unitsPerEm; + + if (mode == 0) { + table = getTable(ttf, O_hmtx); + n = ttf->numberOfHMetrics; + } else { + table = getTable(ttf, O_vmtx); + n = ttf->numOfLongVerMetrics; + } + + if (!nGlyphs || !glyphArray) return 0; /* invalid parameters */ + if (!n || !table) return 0; /* the font does not contain the requested metrics */ + + res = calloc(nGlyphs, sizeof(TTSimpleGlyphMetrics)); + assert(res != 0); + + for (i=0; i<nGlyphs; i++) { + glyphID = glyphArray[i]; + + if (glyphID < n) { + res[i].adv = XUnits(UPEm, GetUInt16(table, 4 * glyphID, 1)); + res[i].sb = XUnits(UPEm, GetInt16(table, 4 * glyphID + 2, 1)); + } else { + res[i].adv = XUnits(UPEm, GetUInt16(table, 4 * (n - 1), 1)); + res[i].sb = XUnits(UPEm, GetInt16(table + n * 4, (glyphID - n) * 2, 1)); + } + } + + return res; +} + +#ifndef NO_MAPPERS +TTSimpleGlyphMetrics *GetTTSimpleCharMetrics(TrueTypeFont * ttf, uint16 firstChar, int nChars, int mode) +{ + TTSimpleGlyphMetrics *res = 0; + uint16 *str; + int i, n; + + str = malloc(nChars * 2); + assert(str != 0); + + for (i=0; i<nChars; i++) str[i] = firstChar + i; + if ((n = MapString(ttf, str, nChars, 0, mode)) != -1) { + res = GetTTSimpleGlyphMetrics(ttf, str, n, mode); + } + + free(str); + + return res; +} +#endif + +void GetTTGlobalFontInfo(TrueTypeFont *ttf, TTGlobalFontInfo *info) +{ + byte *table; + int UPEm = ttf->unitsPerEm; + + memset(info, 0, sizeof(TTGlobalFontInfo)); + + info->family = ttf->family; + info->subfamily = ttf->subfamily; + info->psname = ttf->psname; + info->symbolEncoded = ttf->cmapType == CMAP_MS_Symbol ? 1 : 0; + + table = getTable(ttf, O_OS2); + if (table) { + info->weight = GetUInt16(table, 4, 1); + info->width = GetUInt16(table, 6, 1); + + /* There are 3 different versions of OS/2 table: original (68 bytes long), + * Microsoft old (78 bytes long) and Microsoft new (86 bytes long,) + * Apple's documentation recommends looking at the table length. + */ + if (getTableSize(ttf, O_OS2) > 68) { + info->typoAscender = XUnits(UPEm,GetInt16(table, 68, 1)); + info->typoDescender = XUnits(UPEm, GetInt16(table, 70, 1)); + info->typoLineGap = XUnits(UPEm, GetInt16(table, 72, 1)); + info->winAscent = XUnits(UPEm, GetUInt16(table, 74, 1)); + info->winDescent = XUnits(UPEm, GetUInt16(table, 76, 1)); + } + if (ttf->cmapType == CMAP_MS_Unicode) { + info->rangeFlag = 1; + info->ur1 = GetUInt32(table, 42, 1); + info->ur2 = GetUInt32(table, 46, 1); + info->ur3 = GetUInt32(table, 50, 1); + info->ur4 = GetUInt32(table, 54, 1); + } + memcpy(info->panose, table + 32, 10); + } + + + table = getTable(ttf, O_post); + if (table) { + info->pitch = GetUInt32(table, 12, 1); + info->italicAngle = GetInt32(table, 4, 1); + } + + table = getTable(ttf, O_head); /* 'head' tables is always there */ + info->xMin = XUnits(UPEm, GetInt16(table, 36, 1)); + info->yMin = XUnits(UPEm, GetInt16(table, 38, 1)); + info->xMax = XUnits(UPEm, GetInt16(table, 40, 1)); + info->yMax = XUnits(UPEm, GetInt16(table, 42, 1)); + + table = getTable(ttf, O_hhea); + if (table) { + info->ascender = XUnits(UPEm, GetInt16(table, 4, 1)); + info->descender = XUnits(UPEm, GetInt16(table, 6, 1)); + info->linegap = XUnits(UPEm, GetInt16(table, 8, 1)); + } + + table = getTable(ttf, O_vhea); + if (table) { + info->vascent = XUnits(UPEm, GetInt16(table, 4, 1)); + info->vdescent = XUnits(UPEm, GetInt16(table, 6, 1)); + } +} + +void KernGlyphs(TrueTypeFont *ttf, uint16 *glyphs, int nglyphs, int wmode, KernData *kern) +{ + int i; + + if (!nglyphs || !glyphs || !kern) return; + + for (i = 0; i < nglyphs-1; i++) kern[i].x = kern[i].y = 0; + + switch (ttf->kerntype) { + case KT_APPLE_NEW: KernGlyphsPrim1(ttf, glyphs, nglyphs, wmode, kern); return; + case KT_MICROSOFT: KernGlyphsPrim2(ttf, glyphs, nglyphs, wmode, kern); return; + default: return; + } +} + +GlyphData *GetTTRawGlyphData(TrueTypeFont *ttf, uint32 glyphID) +{ + byte *glyf = getTable(ttf, O_glyf); + byte *hmtx = getTable(ttf, O_hmtx); + byte *ptr; + uint32 length; + GlyphData *d; + ControlPoint *cp; + int i, n, m; + + if (glyphID >= ttf->nglyphs) return 0; + + ptr = glyf + ttf->goffsets[glyphID]; + length = ttf->goffsets[glyphID+1] - ttf->goffsets[glyphID]; + + d = malloc(sizeof(GlyphData)); assert(d != 0); + + if (length) { + d->ptr = malloc((length + 1) & ~1); assert(d->ptr != 0); + memcpy(d->ptr, ptr, length); + if (GetInt16(ptr, 0, 1) >= 0) { + d->compflag = 0; + } else { + d->compflag = 1; + } + } else { + d->ptr = 0; + d->compflag = 0; + } + + d->glyphID = glyphID; + d->nbytes = (length + 1) & ~1; + + /* now calculate npoints and ncontours */ + n = GetTTGlyphPoints(ttf, glyphID, &cp); + if (n != -1) { + m = 0; + for (i = 0; i < n; i++) { + if (cp[i].flags & 0x8000) m++; + } + d->npoints = n; + d->ncontours = m; + free(cp); + } else { + d->npoints = 0; + d->ncontours = 0; + } + + /* get adwance width and left sidebearing */ + if (glyphID < ttf->numberOfHMetrics) { + d->aw = GetUInt16(hmtx, 4 * glyphID, 1); + d->lsb = GetInt16(hmtx, 4 * glyphID + 2, 1); + } else { + d->aw = GetUInt16(hmtx, 4 * (ttf->numberOfHMetrics - 1), 1); + d->lsb = GetInt16(hmtx + n * 4, (glyphID - ttf->numberOfHMetrics) * 2, 1); + } + + return d; +} + +int GetTTNameRecords(TrueTypeFont *ttf, NameRecord **nr) +{ + byte *table = getTable(ttf, O_name); + uint16 n = GetUInt16(table, 2, 1); + NameRecord *rec; + uint16 i; + + *nr = 0; + if (n == 0) return 0; + + rec = calloc(n, sizeof(NameRecord)); + + for (i = 0; i < n; i++) { + rec[i].platformID = GetUInt16(table + 6, 12 * i, 1); + rec[i].encodingID = GetUInt16(table + 6, 2 + 12 * i, 1); + rec[i].languageID = GetUInt16(table + 6, 4 + 12 * i, 1); + rec[i].nameID = GetUInt16(table + 6, 6 + 12 * i, 1); + rec[i].slen = GetUInt16(table + 6, 8 + 12 * i, 1); + if (rec[i].slen) { + rec[i].sptr = (byte *) malloc(rec[i].slen); assert(rec[i].sptr != 0); + memcpy(rec[i].sptr, table + GetUInt16(table, 4, 1) + GetUInt16(table + 6, 10 + 12 * i, 1), rec[i].slen); + } else { + rec[i].sptr = 0; + } + } + + *nr = rec; + return n; +} + +void DisposeNameRecords(NameRecord* nr, int n) +{ + int i; + for (i = 0; i < n; i++) { + if (nr[i].sptr) free(nr[i].sptr); + } + free(nr); +} + + + + +#ifdef TEST1 +/* This example creates a subset of a TrueType font with two encoded characters */ +int main(int ac, char **av) +{ + TrueTypeFont *fnt; + int r; + + /* Array of Unicode source characters */ + uint16 chars[2]; + + /* Encoding vector maps character encoding to the ordinal number + * of the glyph in the output file */ + byte encoding[2]; + + /* This array is for glyph IDs that source characters map to */ + uint16 g[2]; + + + if (ac < 2) return 0; + + if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) { + fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]); + return 0; + } + + + /* We want to create the output file that only contains two Unicode characters: + * L'a' and L'A' */ + + chars[0] = L'a'; + chars[1] = L'A'; + + /* Figure out what glyphs do these characters map in our font */ + MapString(fnt, chars, 2, g); + + /* Encode the characters. Value of encoding[i] is the number 0..255 which maps to glyph i of the + * newly generated font */ + encoding[0] = chars[0]; + encoding[1] = chars[1]; + + + /* Generate a subset */ + CreateT3FromTTGlyphs(fnt, stdout, 0, g, encoding, 2, 0); + + /* Now call the dtor for the font */ + CloseTTFont(fnt); + return 0; +} +#endif + +#ifdef TEST2 +/* This example extracts first 224 glyphs from a TT fonts and encodes them starting at 32 */ +int main(int ac, char **av) +{ + TrueTypeFont *fnt; + int i, r; + + /* Array of Unicode source characters */ + uint16 glyphs[224]; + + /* Encoding vector maps character encoding to the ordinal number + * of the glyph in the output file */ + byte encoding[224]; + + + + for (i=0; i<224; i++) { + glyphs[i] = i; + encoding[i] = 32 + i; + } + + if (ac < 2) return 0; + + if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) { + fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]); + return 0; + } + + + /* Encode the characters. Value of encoding[i] is the number 0..255 which maps to glyph i of the + * newly generated font */ + + /* Generate a subset */ + CreateT3FromTTGlyphs(fnt, stdout, 0, glyphs, encoding, 224, 0); + + /* Now call the dtor for the font */ + CloseTTFont(fnt); + return 0; +} +#endif + +#ifdef TEST3 +/* Glyph metrics example */ +int main(int ac, char **av) +{ + TrueTypeFont *fnt; + int i, r; + uint16 glyphs[224]; + TTSimpleGlyphMetrics *m; + + for (i=0; i<224; i++) { + glyphs[i] = i; + } + + if (ac < 2) return 0; + + if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) { + fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]); + return 0; + } + + if ((m = GetTTSimpleGlyphMetrics(fnt, glyphs, 224, 0)) == 0) { + printf("Requested metrics is not available\n"); + } else { + for (i=0; i<224; i++) { + printf("%d. advWid: %5d, LSBear: %5d\n", i, m[i].adv, m[i].sb); + } + } + + /* Now call the dtor for the font */ + free(m); + CloseTTFont(fnt); + return 0; +} +#endif + +#ifdef TEST4 +int main(int ac, char **av) +{ + TrueTypeFont *fnt; + TTGlobalFontInfo info; + int i, r; + + + if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) { + fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]); + return 0; + } + + printf("Font file: %s\n", av[1]); + +#ifdef PRINT_KERN + switch (fnt->kerntype) { + case KT_MICROSOFT: + printf("\tkern: MICROSOFT, ntables: %d.", fnt->nkern); + if (fnt->nkern) { + printf(" ["); + for (i=0; i<fnt->nkern; i++) { + printf("%04X ", GetUInt16(fnt->kerntables[i], 4, 1)); + } + printf("]"); + } + printf("\n"); + break; + + case KT_APPLE_NEW: + printf("\tkern: APPLE_NEW, ntables: %d.", fnt->nkern); + if (fnt->nkern) { + printf(" ["); + for (i=0; i<fnt->nkern; i++) { + printf("%04X ", GetUInt16(fnt->kerntables[i], 4, 1)); + } + printf("]"); + } + printf("\n"); + break; + + case KT_NONE: + printf("\tkern: none.\n"); + break; + + default: + printf("\tkern: unrecoginzed.\n"); + break; + } + printf("\n"); +#endif + + GetTTGlobalFontInfo(fnt, &info); + printf("\tfamily name: `%s`\n", info.family); + printf("\tsubfamily name: `%s`\n", info.subfamily); + printf("\tpostscript name: `%s`\n", info.psname); + printf("\tweight: %d\n", info.weight); + printf("\twidth: %d\n", info.width); + printf("\tpitch: %d\n", info.pitch); + printf("\titalic angle: %d\n", info.italicAngle); + printf("\tbouding box: [%d %d %d %d]\n", info.xMin, info.yMin, info.xMax, info.yMax); + printf("\tascender: %d\n", info.ascender); + printf("\tdescender: %d\n", info.descender); + printf("\tlinegap: %d\n", info.linegap); + printf("\tvascent: %d\n", info.vascent); + printf("\tvdescent: %d\n", info.vdescent); + printf("\ttypoAscender: %d\n", info.typoAscender); + printf("\ttypoDescender: %d\n", info.typoDescender); + printf("\ttypoLineGap: %d\n", info.typoLineGap); + printf("\twinAscent: %d\n", info.winAscent); + printf("\twinDescent: %d\n", info.winDescent); + printf("\tUnicode ranges:\n"); + for (i = 0; i < 32; i++) { + if ((info.ur1 >> i) & 1) { + printf("\t\t\t%s\n", UnicodeRangeName(i)); + } + } + for (i = 0; i < 32; i++) { + if ((info.ur2 >> i) & 1) { + printf("\t\t\t%s\n", UnicodeRangeName(i+32)); + } + } + for (i = 0; i < 32; i++) { + if ((info.ur3 >> i) & 1) { + printf("\t\t\t%s\n", UnicodeRangeName(i+64)); + } + } + for (i = 0; i < 32; i++) { + if ((info.ur4 >> i) & 1) { + printf("\t\t\t%s\n", UnicodeRangeName(i+96)); + } + } + + CloseTTFont(fnt); + return 0; +} +#endif + +#ifdef TEST5 +/* Kerning example */ +int main(int ac, char **av) +{ + TrueTypeFont *fnt; + uint16 g[224]; + KernData d[223]; + int r, i, k = 0; + + g[k++] = 11; + g[k++] = 36; + g[k++] = 11; + g[k++] = 98; + g[k++] = 11; + g[k++] = 144; + g[k++] = 41; + g[k++] = 171; + g[k++] = 51; + g[k++] = 15; + + if (ac < 2) return 0; + + if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) { + fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]); + return 0; + } + + KernGlyphs(fnt, g, k, 0, d); + + for (i = 0; i < k-1; i++) { + printf("%3d %3d: [%3d %3d]\n", g[i], g[i+1], d[i].x, d[i].y); + } + + CloseTTFont(fnt); + return 0; +} +#endif + + + +#ifdef TEST6 +/* This example extracts a single glyph from a font */ +int main(int ac, char **av) +{ + TrueTypeFont *fnt; + int r, i; + + uint16 glyphs[256]; + byte encoding[256]; + + for (i=0; i<256; i++) { + glyphs[i] = 512 + i; + encoding[i] = i; + } + +#if 0 + i=0; + glyphs[i++] = 2001; + glyphs[i++] = 2002; + glyphs[i++] = 2003; + glyphs[i++] = 2004; + glyphs[i++] = 2005; + glyphs[i++] = 2006; + glyphs[i++] = 2007; + glyphs[i++] = 2008; + glyphs[i++] = 2009; + glyphs[i++] = 2010; + glyphs[i++] = 2011; + glyphs[i++] = 2012; + glyphs[i++] = 2013; + glyphs[i++] = 2014; + glyphs[i++] = 2015; + glyphs[i++] = 2016; + glyphs[i++] = 2017; + glyphs[i++] = 2018; + glyphs[i++] = 2019; + glyphs[i++] = 2020; + + + r = 97; + i = 0; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; + encoding[i++] = r++; +#endif + + if (ac < 2) return 0; + + if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) { + fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]); + return 0; + } + + /* Generate a subset */ + CreateT3FromTTGlyphs(fnt, stdout, 0, glyphs, encoding, 256, 0); + + fprintf(stderr, "UnitsPerEm: %d.\n", fnt->unitsPerEm); + + /* Now call the dtor for the font */ + CloseTTFont(fnt); + return 0; +} +#endif + +#ifdef TEST7 +/* NameRecord extraction example */ +int main(int ac, char **av) +{ + TrueTypeFont *fnt; + int r, i, j, n; + NameRecord *nr; + + if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) { + fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]); + return 0; + } + + if ((n = GetTTNameRecords(fnt, &nr)) == 0) { + fprintf(stderr, "No name records in the font.\n"); + return 0; + } + + printf("Number of name records: %d.\n", n); + for (i = 0; i < n; i++) { + printf("%d %d %04X %d [", nr[i].platformID, nr[i].encodingID, nr[i].languageID, nr[i].nameID); + for (j=0; j<nr[i].slen; j++) { + printf("%c", isprint(nr[i].sptr[j]) ? nr[i].sptr[j] : '.'); + } + printf("]\n"); + } + + + DisposeNameRecords(nr, n); + CloseTTFont(fnt); + return 0; +} +#endif + +#ifdef TEST8 +/* TrueType -> TrueType subsetting */ +int main(int ac, char **av) +{ + TrueTypeFont *fnt; + uint16 glyphArray[] = { 0, 98, 99, 22, 24, 25, 26, 27, 28, 29, 30, 31, 1270, 1289, 34}; + byte encoding[] = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46}; + int r; + + if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) { + fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]); + return 0; + } + + CreateTTFromTTGlyphs(fnt, "subfont.ttf", glyphArray, encoding, 15, 0, 0, TTCF_AutoName | TTCF_IncludeOS2); + + CloseTTFont(fnt); + + return 0; +} +#endif + +#ifdef TEST9 +/* TrueType -> Type42 subsetting */ +int main(int ac, char **av) +{ + TrueTypeFont *fnt; + /* + uint16 glyphArray[] = { 0, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34}; + byte encoding[] = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46}; + */ + uint16 glyphArray[] = { 0, 6711, 6724, 11133, 11144, 14360, 26, 27, 28, 29, 30, 31, 1270, 1289, 34}; + byte encoding[] = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46}; + int r; + + if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) { + fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]); + return 0; + } + + CreateT42FromTTGlyphs(fnt, stdout, "testfont", glyphArray, encoding, 15); + + CloseTTFont(fnt); + + return 0; +} +#endif + +#ifdef TEST10 +/* Component glyph test */ +int main(int ac, char **av) +{ + TrueTypeFont *fnt; + int r, i; + list glyphlist = listNewEmpty(); + + if ((r = OpenTTFont(av[1], 0, &fnt)) != SF_OK) { + fprintf(stderr, "Error %d opening font file: `%s`.\n", r, av[1]); + return 0; + } + + for (i = 0; i < fnt->nglyphs; i++) { + r = GetTTGlyphComponents(fnt, i, glyphlist); + if (r > 1) { + printf("%d -> ", i); + listToFirst(glyphlist); + do { + printf("%d ", (int) listCurrent(glyphlist)); + } while (listNext(glyphlist)); + printf("\n"); + } else { + printf("%d: single glyph.\n", i); + } + listClear(glyphlist); + } + + CloseTTFont(fnt); + listDispose(glyphlist); + + return 0; +} +#endif + + diff --git a/psprint/source/fontsubset/sft.h b/psprint/source/fontsubset/sft.h new file mode 100644 index 000000000000..1c94d8bda8a7 --- /dev/null +++ b/psprint/source/fontsubset/sft.h @@ -0,0 +1,649 @@ +/************************************************************************* + * + * $RCSfile: sft.h,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:37 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Alexander Gelfenbain + * + * + ************************************************************************/ + +/* $Id: sft.h,v 1.1.1.1 2001-05-08 11:45:37 pl Exp $ */ + +/** + * + * @file sft.h + * @brief Sun Font Tools + * @author Alexander Gelfenbain + */ + +/* + * If NO_MAPPERS is defined, MapChar() and MapString() and consequently GetTTSimpleCharMetrics() + * don't get compiled in. This is done to avoid including a large chunk of code (TranslateXY() from + * xlat.c in the projects that don't require it. + * + * If NO_TYPE3 is defined CreateT3FromTTGlyphs() does not get compiled in. + * If NO_TYPE42 is defined Type42-related code is excluded + * If NO_TTCR is defined TrueType creation related code is excluded\ + * If NO_LIST is defined list.h and piblic functions that use it don't get compiled + */ + +/* + * Generated fonts contain an XUID entry in the form of: + * + * 103 0 T C1 N C2 C3 + * + * 103 - Sun's Adobe assigned XUID number. Contact person: Alexander Gelfenbain <gelf@eng.sun.com> + * + * T - font type. 0: Type 3, 1: Type 42 + * C1 - CRC-32 of the entire source TrueType font + * N - number of glyphs in the subset + * C2 - CRC-32 of the array of glyph IDs used to generate the subset + * C3 - CRC-32 of the array of encoding numbers used to generate the subset + * + */ + + +#ifndef __SUBFONT_H +#define __SUBFONT_H + +#include <sys/types.h> +#include <unistd.h> +#include <stdio.h> +#ifndef NO_LIST +#include "list.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __sparc +#ifndef G_BIG_ENDIAN +#define G_BIG_ENDIAN +#endif +#endif + +#ifdef __i386 +#ifndef G_LITTLE_ENDIAN +#define G_LITTLE_ENDIAN +#endif +#endif + +#if !defined(G_BIG_ENDIAN) && !defined(G_LITTLE_ENDIAN) +#error "Either G_BIG_ENDIAN or G_LITTLE_ENDIAN should be defined." +#endif + +#if defined(G_BIG_ENDIAN) && defined(G_LITTLE_ENDIAN) +#error "This is bizarre" +#endif + +#if 0 /* These should be defined in the makefile */ +#define DEBUG /* Generate debugging output */ +#define DEBUG2 /* More detailed debugging output */ +#define DEBUG3 /* Dump of TrueType outlines */ +#endif + + + + +/*@{*/ +#define false 0 /**< standard false value */ +#define true 1 /**< standard true value */ +/*@}*/ + +/*- XXX These should be dynamically configured */ /*FOLD00*/ + typedef unsigned char byte; + typedef unsigned char uint8; + typedef signed char int8; + typedef unsigned short int uint16; + typedef short int int16; + + typedef unsigned int uint32; + typedef int int32; + typedef unsigned long long uint64; + typedef long long int64; + +/*@{*/ + typedef int16 F2Dot14; /**< fixed: 2.14 */ + typedef int32 F16Dot16; /**< fixed: 16.16 */ +/*@}*/ + + typedef struct { + uint16 s; + uint16 d; + } uint16pair; + +/** Return value of OpenTTFont() and CreateT3FromTTGlyphs() */ + enum SFErrCodes { + SF_OK, /**< no error */ + SF_BADFILE, /**< file not found */ + SF_FILEIO, /**< file I/O error */ + SF_MEMORY, /**< memory allocation error */ + SF_GLYPHNUM, /**< incorrect number of glyphs */ + SF_BADARG, /**< incorrect arguments */ + SF_TTFORMAT, /**< incorrect TrueType font format */ + SF_TABLEFORMAT, /**< incorrect format of a TrueType table */ + SF_FONTNO /**< incorrect logical font number of a TTC font */ + }; + +/** Value of the weight member of the TTGlobalFontInfo struct */ + enum WeightClass { + FW_THIN = 100, /**< Thin */ + FW_EXTRALIGHT = 200, /**< Extra-light (Ultra-light) */ + FW_LIGHT = 300, /**< Light */ + FW_NORMAL = 400, /**< Normal (Regular) */ + FW_MEDIUM = 500, /**< Medium */ + FW_SEMIBOLD = 600, /**< Semi-bold (Demi-bold) */ + FW_BOLD = 700, /**< Bold */ + FW_EXTRABOLD = 800, /**< Extra-bold (Ultra-bold) */ + FW_BLACK = 900 /**< Black (Heavy) */ + }; + +/** Value of the width member of the TTGlobalFontInfo struct */ + enum WidthClass { + FWIDTH_ULTRA_CONDENSED = 1, /**< 50% of normal */ + FWIDTH_EXTRA_CONDENSED = 2, /**< 62.5% of normal */ + FWIDTH_CONDENSED = 3, /**< 75% of normal */ + FWIDTH_SEMI_CONDENSED = 4, /**< 87.5% of normal */ + FWIDTH_NORMAL = 5, /**< Medium, 100% */ + FWIDTH_SEMI_EXPANDED = 6, /**< 112.5% of normal */ + FWIDTH_EXPANDED = 7, /**< 125% of normal */ + FWIDTH_EXTRA_EXPANDED = 8, /**< 150% of normal */ + FWIDTH_ULTRA_EXPANDED = 9 /**< 200% of normal */ + }; + +/** Type of the 'kern' table, stored in _TrueTypeFont::kerntype */ + enum KernType { + + KT_NONE = 0, /**< no kern table */ + KT_APPLE_NEW = 1, /**< new Apple kern table */ + KT_MICROSOFT = 2 /**< Microsoft table */ + }; + +/* Composite glyph flags definition */ + enum CompositeFlags { + ARG_1_AND_2_ARE_WORDS = 1, + ARGS_ARE_XY_VALUES = 1<<1, + ROUND_XY_TO_GRID = 1<<2, + WE_HAVE_A_SCALE = 1<<3, + MORE_COMPONENTS = 1<<5, + WE_HAVE_AN_X_AND_Y_SCALE = 1<<6, + WE_HAVE_A_TWO_BY_TWO = 1<<7, + WE_HAVE_INSTRUCTIONS = 1<<8, + USE_MY_METRICS = 1<<9, + OVERLAP_COMPOUND = 1<<10 + }; + +#ifndef NO_TTCR +/** Flags for TrueType generation */ + enum TTCreationFlags { + TTCF_AutoName = 1, /**< Automatically generate a compact 'name' table. + If this flag is not set, name table is generated + either from an array of NameRecord structs passed as + arguments or if the array is NULL, 'name' table + of the generated TrueType file will be a copy + of the name table of the original file. + If this flag is set the array of NameRecord structs + is ignored and a very compact 'name' table is automatically + generated. */ + + TTCF_IncludeOS2 = 2 /** If this flag is set OS/2 table from the original font will be + copied to the subset */ + }; +#endif + + + + +/** Structure used by GetTTSimpleGlyphMetrics() and GetTTSimpleCharMetrics() functions */ + typedef struct { + uint16 adv; /**< advance width or height */ + int16 sb; /**< left or top sidebearing */ + } TTSimpleGlyphMetrics; + + + +/** Structure used by the TrueType Creator and GetRawGlyphData() */ + + typedef struct { + uint32 glyphID; /**< glyph ID */ + uint16 nbytes; /**< number of bytes in glyph data */ + byte *ptr; /**< pointer to glyph data */ + uint16 aw; /**< advance width */ + int16 lsb; /**< left sidebearing */ + uint16 compflag; /**< 0- if non-composite, 1- otherwise */ + uint16 npoints; /**< number of points */ + uint16 ncontours; /**< number of contours */ + /* */ + uint32 newID; /**< used internally by the TTCR */ + } GlyphData; + +/** Structure used by the TrueType Creator and CreateTTFromTTGlyphs() */ + typedef struct { + uint16 platformID; /**< Platform ID */ + uint16 encodingID; /**< Platform-specific encoding ID */ + uint16 languageID; /**< Language ID */ + uint16 nameID; /**< Name ID */ + uint16 slen; /**< String length in bytes */ + byte *sptr; /**< Pointer to string data (not zero-terminated!) */ + } NameRecord; + + + +/** Return value of GetTTGlobalFontInfo() */ + + typedef struct { + char *family; /**< family name */ + char *subfamily; /**< subfamily name */ + char *psname; /**< PostScript name */ + int weight; /**< value of WeightClass or 0 if can't be determined */ + int width; /**< value of WidthClass or 0 if can't be determined */ + int pitch; /**< 0: proportianal font, otherwise: monospaced */ + int italicAngle; /**< in counter-clockwise degrees * 65536 */ + int xMin; /**< global bounding box: xMin */ + int yMin; /**< global bounding box: yMin */ + int xMax; /**< global bounding box: xMax */ + int yMax; /**< global bounding box: yMax */ + int ascender; /**< typographic ascent. */ + int descender; /**< typographic descent. */ + int linegap; /**< typographic line gap.\ Negative values are treated as + zero in Win 3.1, System 6 and System 7. */ + int vascent; /**< typographic ascent for vertical writing mode */ + int vdescent; /**< typographic descent for vertical writing mode */ + int typoAscender; /**< OS/2 portable typographic ascender */ + int typoDescender; /**< OS/2 portable typographic descender */ + int typoLineGap; /**< OS/2 portable typographc line gap */ + int winAscent; /**< ascender metric for Windows */ + int winDescent; /**< descender metric for Windows */ + int symbolEncoded; /**< 1: MS symbol encoded 0: not symbol encoded */ + int rangeFlag; /**< if set to 1 Unicode Range flags are applicable */ + uint32 ur1; /**< bits 0 - 31 of Unicode Range flags */ + uint32 ur2; /**< bits 32 - 63 of Unicode Range flags */ + uint32 ur3; /**< bits 64 - 95 of Unicode Range flags */ + uint32 ur4; /**< bits 96 - 127 of Unicode Range flags */ + byte panose[10]; /**< PANOSE classification number */ + } TTGlobalFontInfo; + +/** Structure used by KernGlyphs() */ + typedef struct { + int x; /**< positive: right, negative: left */ + int y; /**< positive: up, negative: down */ + } KernData; + + +/** ControlPoint structure used by GetTTGlyphPoints() */ + typedef struct { + uint32 flags; /**< 00000000 00000000 e0000000 bbbbbbbb */ + /**< b - byte flags from the glyf array */ + /**< e == 0 - regular point */ + /**< e == 1 - end contour */ + int16 x; /**< X coordinate in EmSquare units */ + int16 y; /**< Y coordinate in EmSquare units */ + } ControlPoint; + + typedef struct _TrueTypeFont TrueTypeFont; + +/** + * @defgroup sft Sun Font Tools Exported Functions + */ + + +/** + * Get the number of fonts contained in a TrueType collection + * @param fname - file name + * @return number of fonts or zero, if file is not a TTC file. + * @ingroup sft + */ + int CountTTCFonts(const char* fname); + + +/** + * TrueTypeFont constructor. + * Reads the font file and allocates the memory for the structure. + * @param facenum - logical font number within a TTC file. This value is ignored + * for TrueType fonts + * @return value of SFErrCodes enum + * @ingroup sft + */ + int OpenTTFont(const char *fname, uint32 facenum, TrueTypeFont**); + +/** + * TrueTypeFont destructor. Deallocates the memory. + * @ingroup sft + */ + void CloseTTFont(TrueTypeFont *); + +/** + * Extracts TrueType control points, and stores them in an allocated array pointed to + * by *pointArray. This function returns the number of extracted points. + * + * @param ttf pointer to the TrueTypeFont structure + * @param glyphID Glyph ID + * @param pointArray Return value - address of the pointer to the first element of the array + * of points allocated by the function + * @return Returns the number of points in *pointArray or -1 if glyphID is + * invalid. + * @ingroup sft + * + */ + int GetTTGlyphPoints(TrueTypeFont *ttf, uint32 glyphID, ControlPoint **pointArray); + +/** + * Extracts raw glyph data from the 'glyf' table and returns it in an allocated + * GlyphData structure. + * + * @param ttf pointer to the TrueTypeFont structure + * @param glyphID Glyph ID + * + * @return pointer to an allocated GlyphData structure or NULL if + * glyphID is not present in the font + * @ingroup sft + * + */ + GlyphData *GetTTRawGlyphData(TrueTypeFont *ttf, uint32 glyphID); + +#ifndef NO_LIST +/** + * For a specified glyph adds all component glyphs IDs to the list and + * return their number. If the glyph is a single glyph it has one component + * glyph (which is added to the list) and the function returns 1. + * For a composite glyphs it returns the number of component glyphs + * and adds all of them to the list. + * + * @param ttf pointer to the TrueTypeFont structure + * @param glyphID Glyph ID + * @param glyphlist list of glyphs + * + * @return number of component glyphs + * @ingroup sft + * + */ + int GetTTGlyphComponents(TrueTypeFont *ttf, uint32 glyphID, list glyphlist); +#endif + +/** + * Extracts all Name Records from the font and stores them in an allocated + * array of NameRecord structs + * + * @param ttf pointer to the TrueTypeFont struct + * @param nr pointer to the array of NameRecord structs + * + * @return number of NameRecord structs + * @ingroup sft + */ + + int GetTTNameRecords(TrueTypeFont *ttf, NameRecord **nr); + +/** + * Deallocates previously allocated array of NameRecords. + * + * @param nr array of NameRecord structs + * @param n number of elements in the array + * + * @ingroup sft + */ + void DisposeNameRecords(NameRecord* nr, int n); + + +#ifndef NO_TYPE3 +/** + * Generates a new PostScript Type 3 font and dumps it to <b>outf</b> file. + * This functions subsititues glyph 0 for all glyphIDs that are not found in the font. + * @param ttf pointer to the TrueTypeFont structure + * @param outf the resulting font is written to this stream + * @param fname font name for the new font. If it is NULL the PostScript name of the + * original font will be used + * @param glyphArray pointer to an array of glyphs that are to be extracted from ttf + * @param encoding array of encoding values. encoding[i] specifies the position of the glyph + * glyphArray[i] in the encoding vector of the resulting Type3 font + * @param nGlyphs number of glyph IDs in glyphArray and encoding values in encoding + * @param wmode writing mode for the output file: 0 - horizontal, 1 - vertical + * @return return the value of SFErrCodes enum + * @see SFErrCodes + * @ingroup sft + * + */ + int CreateT3FromTTGlyphs(TrueTypeFont *ttf, FILE *outf, const char *fname, uint16 *glyphArray, byte *encoding, int nGlyphs, int wmode); +#endif + +#ifndef NO_TTCR +/** + * Generates a new TrueType font and dumps it to <b>outf</b> file. + * This functions subsititues glyph 0 for all glyphIDs that are not found in the font. + * @param ttf pointer to the TrueTypeFont structure + * @param fname file name for the output TrueType font file + * @param glyphArray pointer to an array of glyphs that are to be extracted from ttf. The first + * element of this array has to be glyph 0 (default glyph) + * @param encoding array of encoding values. encoding[i] specifies character code for + * the glyphID glyphArray[i]. Character code 0 usually points to a default + * glyph (glyphID 0) + * @param nGlyphs number of glyph IDs in glyphArray and encoding values in encoding + * @param nNameRecs number of NameRecords for the font, if 0 the name table from the + * original font will be used + * @param nr array of NameRecords + * @param flags or'ed TTCreationFlags + * @return return the value of SFErrCodes enum + * @see SFErrCodes + * @ingroup sft + * + */ + int CreateTTFromTTGlyphs(TrueTypeFont *ttf, + const char *fname, + uint16 *glyphArray, + byte *encoding, + int nGlyphs, + int nNameRecs, + NameRecord *nr, + uint32 flags); +#endif + +#ifndef NO_TYPE42 +/** + * Generates a new PostScript Type42 font and dumps it to <b>outf</b> file. + * This functions subsititues glyph 0 for all glyphIDs that are not found in the font. + * @param ttf pointer to the TrueTypeFont structure + * @param outf output stream for a resulting font + * @param psname PostScript name of the resulting font + * @param glyphArray pointer to an array of glyphs that are to be extracted from ttf. The first + * element of this array has to be glyph 0 (default glyph) + * @param encoding array of encoding values. encoding[i] specifies character code for + * the glyphID glyphArray[i]. Character code 0 usually points to a default + * glyph (glyphID 0) + * @param nGlyphs number of glyph IDs in glyphArray and encoding values in encoding + * @return SF_OK - no errors + * SF_GLYPHNUM - too many glyphs (> 255) + * SF_TTFORMAT - corrupted TrueType fonts + * + * @see SFErrCodes + * @ingroup sft + * + */ + int CreateT42FromTTGlyphs(TrueTypeFont *ttf, + FILE *outf, + const char *psname, + uint16 *glyphArray, + byte *encoding, + int nGlyphs); +#endif + + +/** + * Queries glyph metrics. Allocates an array of TTSimpleGlyphMetrics structs and returns it. + * + * @param ttf pointer to the TrueTypeFont structure + * @param glyphArray pointer to an array of glyphs that are to be extracted from ttf + * @param nGlyphs number of glyph IDs in glyphArray and encoding values in encoding + * @param mode writing mode: 0 - horizontal, 1 - vertical + * @ingroup sft + * + */ + TTSimpleGlyphMetrics *GetTTSimpleGlyphMetrics(TrueTypeFont *ttf, uint16 *glyphArray, int nGlyphs, int mode); + +#ifndef NO_MAPPERS +/** + * Queries glyph metrics. Allocates an array of TTSimpleGlyphMetrics structs and returns it. + * This function behaves just like GetTTSimpleGlyphMetrics() but it takes a range of Unicode + * characters instead of an array of glyphs. + * + * @param ttf pointer to the TrueTypeFont structure + * @param firstChar Unicode value of the first character in the range + * @param nChars number of Unicode characters in the range + * @param mode writing mode: 0 - horizontal, 1 - vertical + * + * @see GetTTSimpleGlyphMetrics + * @ingroup sft + * + */ + TTSimpleGlyphMetrics *GetTTSimpleCharMetrics(TrueTypeFont *ttf, uint16 firstChar, int nChars, int mode); + +/** + * Maps a Unicode (UCS-2) string to a glyph array. Returns the number of glyphs in the array, + * which for TrueType fonts is always the same as the number of input characters. + * + * @param ttf pointer to the TrueTypeFont structure + * @param str pointer to a UCS-2 string + * @param nchars number of characters in <b>str</b> + * @param glyphArray pointer to the glyph array where glyph IDs are to be recorded. + * + * @return MapString() returns -1 if the TrueType font has no usable 'cmap' tables. + * Otherwise it returns the number of characters processed: <b>nChars</b> + * + * glyphIDs of TrueType fonts are 2 byte positive numbers. glyphID of 0 denotes a missing + * glyph and traditionally defaults to an empty square. + * glyphArray should be at least sizeof(uint16) * nchars bytes long. If glyphArray is NULL + * MapString() replaces the UCS-2 characters in str with glyphIDs. + * @ingroup sft + */ + int MapString(TrueTypeFont *ttf, uint16 *str, int nchars, uint16 *glyphArray, int bvertical); + +/** + * Maps a Unicode (UCS-2) character to a glyph ID and returns it. Missing glyph has + * a glyphID of 0 so this function can be used to test if a character is encoded in the font. + * + * @param ttf pointer to the TrueTypeFont structure + * @param ch Unicode (UCS-2) character + * @return glyph ID, if the character is missing in the font, the return value is 0. + * @ingroup sft + */ + uint16 MapChar(TrueTypeFont *ttf, uint16 ch, int bvertical); +#endif + +/** + * Returns global font information about the TrueType font. + * @see TTGlobalFontInfo + * + * @param ttf pointer to a TrueTypeFont structure + * @param info pointer to a TTGlobalFontInfo structure + * @ingroup sft + * + */ + void GetTTGlobalFontInfo(TrueTypeFont *ttf, TTGlobalFontInfo *info); + +/** + * Returns kerning information for an array of glyphs. + * Kerning is not cumulative. + * kern[i] contains kerning information for a pair of glyphs at positions i and i+1 + * + * @param ttf pointer to a TrueTypeFont structure + * @param glyphs array of source glyphs + * @param nglyphs number of glyphs in the array + * @param wmode writing mode: 0 - horizontal, 1 - vertical + * @param kern array of KernData structures. It should contain nglyphs-1 elements + * @see KernData + * @ingroup sft + * + */ + void KernGlyphs(TrueTypeFont *ttf, uint16 *glyphs, int nglyphs, int wmode, KernData *kern); + +/** + * Returns nonzero if font is a symbol encoded font + */ + int CheckSymbolEncoding(TrueTypeFont* ttf); + +/*- private definitions */ /*FOLD00*/ + + struct _TrueTypeFont { + uint32 tag; + + char *fname; + off_t fsize; + byte *ptr; + + char *psname; + char *family; + char *subfamily; + + uint32 ntables; + uint32 *goffsets; + int nglyphs; + int unitsPerEm; + int numberOfHMetrics; + int numOfLongVerMetrics; /* if this number is not 0, font has vertical metrics information */ + byte *cmap; + int cmapType; + uint16 (*mapper)(const byte *, uint16); /* character to glyphID translation function */ + void **tables; /* array of pointers to tables */ + uint32 *tlens; /* array of table lengths */ + int kerntype; /* Defined in the KernType enum */ + uint32 nkern; /* number of kern subtables */ + byte **kerntables; /* array of pointers to kern subtables */ + void *pGSubstitution; /* info provided by GSUB for UseGSUB() */ + }; + +#ifdef __cplusplus +} +#endif + +#endif /* __SUBFONT_H */ diff --git a/psprint/source/fontsubset/ttcr.c b/psprint/source/fontsubset/ttcr.c new file mode 100644 index 000000000000..4b09ff43e9a5 --- /dev/null +++ b/psprint/source/fontsubset/ttcr.c @@ -0,0 +1,1666 @@ +/************************************************************************* + * + * $RCSfile: ttcr.c,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Alexander Gelfenbain + * + * + ************************************************************************/ + +/* $Id: ttcr.c,v 1.1.1.1 2001-05-08 11:45:38 pl Exp $ */ + +/* + * TrueTypeCreator method implementation + * + * @author: Alexander Gelfenbain + * + */ + +#include <sys/types.h> +#include <sys/uio.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "ttcr.h" + +/* These must be #defined so that they can be used in initializers */ +#define T_maxp 0x6D617870 +#define T_glyf 0x676C7966 +#define T_head 0x68656164 +#define T_loca 0x6C6F6361 +#define T_name 0x6E616D65 +#define T_hhea 0x68686561 +#define T_hmtx 0x686D7478 +#define T_cmap 0x636D6170 +#define T_vhea 0x76686561 +#define T_vmtx 0x766D7478 +#define T_OS2 0x4F532F32 +#define T_post 0x706F7374 +#define T_kern 0x6B65726E +#define T_cvt 0x63767420 + +typedef struct { + uint32 tag; + uint32 length; + byte *data; +} TableEntry; + +/* + * this is a duplicate code from sft.c but it is left here for performance reasons + */ +#ifdef __GNUC__ +#define _inline static __inline__ +#else +#define _inline static +#endif + +_inline uint32 mkTag(byte a, byte b, byte c, byte d) { + return (a << 24) | (b << 16) | (c << 8) | d; +} + +/*- Data access macros for data stored in big-endian or little-endian format */ +_inline int16 GetInt16(const byte *ptr, size_t offset, int bigendian) +{ + int16 t; + assert(ptr != 0); + + if (bigendian) { + t = (ptr+offset)[0] << 8 | (ptr+offset)[1]; + } else { + t = (ptr+offset)[1] << 8 | (ptr+offset)[0]; + } + + return t; +} + +_inline uint16 GetUInt16(const byte *ptr, size_t offset, int bigendian) +{ + uint16 t; + assert(ptr != 0); + + if (bigendian) { + t = (ptr+offset)[0] << 8 | (ptr+offset)[1]; + } else { + t = (ptr+offset)[1] << 8 | (ptr+offset)[0]; + } + + return t; +} + +_inline int32 GetInt32(const byte *ptr, size_t offset, int bigendian) +{ + int32 t; + assert(ptr != 0); + + if (bigendian) { + t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 | + (ptr+offset)[2] << 8 | (ptr+offset)[3]; + } else { + t = (ptr+offset)[3] << 24 | (ptr+offset)[2] << 16 | + (ptr+offset)[1] << 8 | (ptr+offset)[0]; + } + + return t; +} + +_inline uint32 GetUInt32(const byte *ptr, size_t offset, int bigendian) +{ + uint32 t; + assert(ptr != 0); + + + if (bigendian) { + t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 | + (ptr+offset)[2] << 8 | (ptr+offset)[3]; + } else { + t = (ptr+offset)[3] << 24 | (ptr+offset)[2] << 16 | + (ptr+offset)[1] << 8 | (ptr+offset)[0]; + } + + return t; +} + + +_inline void PutInt16(int16 val, byte *ptr, size_t offset, int bigendian) +{ + assert(ptr != 0); + + if (bigendian) { + ptr[offset] = (val >> 8) & 0xFF; + ptr[offset+1] = val & 0xFF; + } else { + ptr[offset+1] = (val >> 8) & 0xFF; + ptr[offset] = val & 0xFF; + } + +} + +_inline void PutUInt16(uint16 val, byte *ptr, size_t offset, int bigendian) +{ + assert(ptr != 0); + + if (bigendian) { + ptr[offset] = (val >> 8) & 0xFF; + ptr[offset+1] = val & 0xFF; + } else { + ptr[offset+1] = (val >> 8) & 0xFF; + ptr[offset] = val & 0xFF; + } + +} + + +_inline void PutUInt32(uint32 val, byte *ptr, size_t offset, int bigendian) +{ + assert(ptr != 0); + + if (bigendian) { + ptr[offset] = (val >> 24) & 0xFF; + ptr[offset+1] = (val >> 16) & 0xFF; + ptr[offset+2] = (val >> 8) & 0xFF; + ptr[offset+3] = val & 0xFF; + } else { + ptr[offset+3] = (val >> 24) & 0xFF; + ptr[offset+2] = (val >> 16) & 0xFF; + ptr[offset+1] = (val >> 8) & 0xFF; + ptr[offset] = val & 0xFF; + } + +} + + +_inline void PutInt32(int32 val, byte *ptr, size_t offset, int bigendian) +{ + assert(ptr != 0); + + if (bigendian) { + ptr[offset] = (val >> 24) & 0xFF; + ptr[offset+1] = (val >> 16) & 0xFF; + ptr[offset+2] = (val >> 8) & 0xFF; + ptr[offset+3] = val & 0xFF; + } else { + ptr[offset+3] = (val >> 24) & 0xFF; + ptr[offset+2] = (val >> 16) & 0xFF; + ptr[offset+1] = (val >> 8) & 0xFF; + ptr[offset] = val & 0xFF; + } + +} + +static int TableEntryCompareF(const void *l, const void *r) +{ + return ((const TableEntry *) l)->tag - ((const TableEntry *) r)->tag; +} + +static int NameRecordCompareF(const void *l, const void *r) +{ + NameRecord *ll = (NameRecord *) l; + NameRecord *rr = (NameRecord *) r; + + if (ll->platformID != rr->platformID) { + return ll->platformID - rr->platformID; + } else if (ll->encodingID != rr->encodingID) { + return ll->encodingID - rr->encodingID; + } else if (ll->languageID != rr->languageID) { + return ll->languageID - rr->languageID; + } else if (ll->nameID != rr->nameID) { + return ll->nameID - rr->nameID; + } + return 0; +} + + +static uint32 CheckSum(uint32 *ptr, uint32 length) +{ + uint32 sum = 0; + uint32 *endptr = ptr + ((length + 3) & (uint32) ~3) / 4; + + while (ptr < endptr) sum += *ptr++; + + return sum; +} + +_inline void *smalloc(size_t size) +{ + void *res = malloc(size); + assert(res != 0); + return res; +} + +_inline void *scalloc(size_t n, size_t size) +{ + void *res = calloc(n, size); + assert(res != 0); + return res; +} + +/* + * Public functions + */ + +void TrueTypeCreatorNewEmpty(uint32 tag, TrueTypeCreator **_this) +{ + TrueTypeCreator *ptr = smalloc(sizeof(TrueTypeCreator)); + + ptr->tables = listNewEmpty(); + listSetElementDtor(ptr->tables, TrueTypeTableDispose); + + ptr->tag = tag; + + *_this = ptr; +} + +void TrueTypeCreatorDispose(TrueTypeCreator *_this) +{ + listDispose(_this->tables); + free(_this); +} + +int AddTable(TrueTypeCreator *_this, TrueTypeTable *table) +{ + if (table != 0) { + listAppend(_this->tables, table); + } + return SF_OK; +} + +void RemoveTable(TrueTypeCreator *_this, uint32 tag) +{ + int done = 0; + + if (listCount(_this->tables)) { + listToFirst(_this->tables); + do { + if (((TrueTypeTable *) listCurrent(_this->tables))->tag == tag) { + listRemove(_this->tables); + } else { + if (listNext(_this->tables)) { + done = 1; + } + } + } while (!done); + } +} + +static void ProcessTables(TrueTypeCreator *); + +int StreamToMemory(TrueTypeCreator *_this, byte **ptr, uint32 *length) +{ + uint16 numTables, searchRange=1, entrySelector=0, rangeShift; + uint32 s, offset, checkSumAdjustment = 0; + uint32 *p; + byte *ttf; + int i=0, n; + TableEntry *te; + byte *head; /* saved pointer to the head table data for checkSumAdjustment calculation */ + + if ((n = listCount(_this->tables)) == 0) return SF_TTFORMAT; + + ProcessTables(_this); + + /* ProcessTables() adds 'loca' and 'hmtx' */ + + n = listCount(_this->tables); + numTables = (uint16) n; + + + te = scalloc(n, sizeof(TableEntry)); + + listToFirst(_this->tables); + for (i = 0; i < n; i++) { + GetRawData((TrueTypeTable *) listCurrent(_this->tables), &te[i].data, &te[i].length, &te[i].tag); + listNext(_this->tables); + } + + qsort(te, n, sizeof(TableEntry), TableEntryCompareF); + + do { + searchRange *= 2; + entrySelector++; + } while (searchRange <= numTables); + + searchRange *= 8; + entrySelector--; + rangeShift = numTables * 16 - searchRange; + + s = offset = 12 + 16 * n; + + for (i = 0; i < n; i++) { + s += (te[i].length + 3) & (uint32) ~3; + /* if ((te[i].length & 3) != 0) s += (4 - (te[i].length & 3)) & 3; */ + } + + ttf = smalloc(s); + + /* Offset Table */ + PutUInt32(_this->tag, ttf, 0, 1); + PutUInt16(numTables, ttf, 4, 1); + PutUInt16(searchRange, ttf, 6, 1); + PutUInt16(entrySelector, ttf, 8, 1); + PutUInt16(rangeShift, ttf, 10, 1); + + /* Table Directory */ + for (i = 0; i < n; i++) { + PutUInt32(te[i].tag, ttf + 12, 16 * i, 1); + PutUInt32(CheckSum((uint32 *) te[i].data, te[i].length), ttf + 12, 16 * i + 4, 1); + PutUInt32(offset, ttf + 12, 16 * i + 8, 1); + PutUInt32(te[i].length, ttf + 12, 16 * i + 12, 1); + + if (te[i].tag == T_head) { + head = ttf + offset; + } + + memcpy(ttf+offset, te[i].data, (te[i].length + 3) & (uint32) ~3 ); + offset += (te[i].length + 3) & (uint32) ~3; + /* if ((te[i].length & 3) != 0) offset += (4 - (te[i].length & 3)) & 3; */ + } + + free(te); + + p = (uint32 *) ttf; + for (i = 0; i < s / 4; i++) checkSumAdjustment += p[i]; + PutUInt32(0xB1B0AFBA - checkSumAdjustment, head, 8, 1); + + *ptr = ttf; + *length = s; + + return SF_OK; +} + +int StreamToFile(TrueTypeCreator *_this, const char* fname) +{ + byte *ptr; + uint32 length; + int fd, r; + + if (!fname) return SF_BADFILE; + if ((fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) return SF_BADFILE; + + if ((r = StreamToMemory(_this, &ptr, &length)) != SF_OK) return r; + + if (write(fd, ptr, length) != length) { + r = SF_FILEIO; + } else { + r = SF_OK; + } + + close(fd); + free(ptr); + return r; +} + + + +/* + * TrueTypeTable private methods + */ + +#define TABLESIZE_head 54 +#define TABLESIZE_hhea 36 +#define TABLESIZE_maxp 32 + + + +/* Table data points to + * -------------------------------------------- + * generic tdata_generic struct + * 'head' TABLESIZE_head bytes of memory + * 'hhea' TABLESIZE_hhea bytes of memory + * 'loca' tdata_loca struct + * 'maxp' TABLESIZE_maxp bytes of memory + * 'glyf' list of GlyphData structs (defined in sft.h) + * 'name' list of NameRecord structs (defined in sft.h) + * 'post' tdata_post struct + * + */ + + +#define CMAP_SUBTABLE_INIT 10 +#define CMAP_SUBTABLE_INCR 10 +#define CMAP_PAIR_INIT 500 +#define CMAP_PAIR_INCR 500 + +typedef struct { + uint32 id; /* subtable ID (platform/encoding ID) */ + uint32 n; /* number of used translation pairs */ + uint32 m; /* number of allocated translation pairs */ + uint32 *xc; /* character array */ + uint32 *xg; /* glyph array */ +} CmapSubTable; + +typedef struct { + uint32 n; /* number of used CMAP sub-tables */ + uint32 m; /* number of allocated CMAP sub-tables */ + CmapSubTable *s; /* sotred array of sub-tables */ +} table_cmap; + +typedef struct { + uint32 tag; + uint32 nbytes; + byte *ptr; +} tdata_generic; + +typedef struct { + uint32 nbytes; /* number of bytes in loca table */ + byte *ptr; /* pointer to the data */ +} tdata_loca; + +typedef struct { + uint32 format; + uint32 italicAngle; + int16 underlinePosition; + int16 underlineThickness; + uint32 isFixedPitch; + void *ptr; /* format-specific pointer */ +} tdata_post; + + +/* allocate memory for a TT table */ +static byte *ttmalloc(uint32 nbytes) +{ + uint32 n; + byte *res; + + n = (nbytes + 3) & (uint32) ~3; + res = malloc(n); + assert(res != 0); + bzero(res, n); + + return res; +} + +static void FreeGlyphData(void *ptr) +{ + GlyphData *p = (GlyphData *) ptr; + if (p->ptr) free(p->ptr); + free(p); +} + +static void TrueTypeTableDispose_generic(TrueTypeTable *_this) +{ + if (_this) { + if (_this->data) { + tdata_generic *pdata = (tdata_generic *) _this->data; + if (pdata->nbytes) free(pdata->ptr); + free(_this->data); + } + free(_this); + } +} + +static void TrueTypeTableDispose_head(TrueTypeTable *_this) +{ + if (_this) { + if (_this->data) free(_this->data); + free(_this); + } +} + +static void TrueTypeTableDispose_hhea(TrueTypeTable *_this) +{ + if (_this) { + if (_this->data) free(_this->data); + free(_this); + } +} + +static void TrueTypeTableDispose_loca(TrueTypeTable *_this) +{ + if (_this) { + if (_this->data) { + tdata_loca *p = (tdata_loca *) _this->data; + if (p->ptr) free(p->ptr); + free(_this->data); + } + free(_this); + } +} + +static void TrueTypeTableDispose_maxp(TrueTypeTable *_this) +{ + if (_this) { + if (_this->data) free(_this->data); + free(_this); + } +} + +static void TrueTypeTableDispose_glyf(TrueTypeTable *_this) +{ + if (_this) { + if (_this->data) listDispose((list) _this->data); + free(_this); + } +} + +static void TrueTypeTableDispose_cmap(TrueTypeTable *_this) +{ + table_cmap *t; + CmapSubTable *s; + int i; + + if (_this) { + t = (table_cmap *) _this->data; + if (t) { + s = t->s; + if (s) { + for (i = 0; i < t->m; i++) { + if (s[i].xc) free(s[i].xc); + if (s[i].xg) free(s[i].xg); + } + free(s); + } + free(t); + } + free(_this); + } +} + +static void TrueTypeTableDispose_name(TrueTypeTable *_this) +{ + if (_this) { + if (_this->data) listDispose((list) _this->data); + free(_this); + } +} + +static void TrueTypeTableDispose_post(TrueTypeTable *_this) +{ + if (_this) { + tdata_post *p = (tdata_post *) _this->data; + if (p) { + if (p->format == 0x00030000) { + /* do nothing */ + } else { + fprintf(stderr, "Unsupported format of a 'post' table: %08X.\n", p->format); + } + free(p); + } + free(_this); + } +} + +/* destructor vtable */ + +static struct { + uint32 tag; + void (*f)(TrueTypeTable *); +} vtable1[] = +{ + {0, TrueTypeTableDispose_generic}, + {T_head, TrueTypeTableDispose_head}, + {T_hhea, TrueTypeTableDispose_hhea}, + {T_loca, TrueTypeTableDispose_loca}, + {T_maxp, TrueTypeTableDispose_maxp}, + {T_glyf, TrueTypeTableDispose_glyf}, + {T_cmap, TrueTypeTableDispose_cmap}, + {T_name, TrueTypeTableDispose_name}, + {T_post, TrueTypeTableDispose_post} + +}; + +static int GetRawData_generic(TrueTypeTable *_this, byte **ptr, uint32 *len, uint32 *tag) +{ + assert(_this != 0); + assert(_this->data != 0); + + *ptr = ((tdata_generic *) _this->data)->ptr; + *len = ((tdata_generic *) _this->data)->nbytes; + *tag = ((tdata_generic *) _this->data)->tag; + + return TTCR_OK; +} + + +static int GetRawData_head(TrueTypeTable *_this, byte **ptr, uint32 *len, uint32 *tag) +{ + *len = TABLESIZE_head; + *ptr = (byte *) _this->data; + *tag = T_head; + + return TTCR_OK; +} + +static int GetRawData_hhea(TrueTypeTable *_this, byte **ptr, uint32 *len, uint32 *tag) +{ + *len = TABLESIZE_hhea; + *ptr = (byte *) _this->data; + *tag = T_hhea; + + return TTCR_OK; +} + +static int GetRawData_loca(TrueTypeTable *_this, byte **ptr, uint32 *len, uint32 *tag) +{ + tdata_loca *p; + + assert(_this->data != 0); + + p = (tdata_loca *) _this->data; + + if (p->nbytes == 0) return TTCR_ZEROGLYPHS; + + *ptr = p->ptr; + *len = p->nbytes; + *tag = T_loca; + + return TTCR_OK; +} + +static int GetRawData_maxp(TrueTypeTable *_this, byte **ptr, uint32 *len, uint32 *tag) +{ + *len = TABLESIZE_maxp; + *ptr = (byte *) _this->data; + *tag = T_maxp; + + return TTCR_OK; +} + +static int GetRawData_glyf(TrueTypeTable *_this, byte **ptr, uint32 *len, uint32 *tag) +{ + uint32 n, nbytes = 0; + list l = (list) _this->data; + /* uint16 curID = 0; */ /* to check if glyph IDs are sequential and start from zero */ + byte *p; + + *ptr = 0; + *len = 0; + *tag = 0; + + if (listCount(l) == 0) return TTCR_ZEROGLYPHS; + + listToFirst(l); + do { + /* if (((GlyphData *) listCurrent(l))->glyphID != curID++) return TTCR_GLYPHSEQ; */ + nbytes += ((GlyphData *) listCurrent(l))->nbytes; + } while (listNext(l)); + + p = _this->rawdata = ttmalloc(nbytes); + + listToFirst(l); + do { + n = ((GlyphData *) listCurrent(l))->nbytes; + if (n != 0) { + memcpy(p, ((GlyphData *) listCurrent(l))->ptr, n); + p += n; + } + } while (listNext(l)); + + *len = nbytes; + *ptr = _this->rawdata; + *tag = T_glyf; + + return TTCR_OK; +} + +/* cmap packers */ +static byte *PackCmapType0(CmapSubTable *s, uint32 *length) +{ + byte *ptr = smalloc(262); + byte *p = ptr + 6; + int i, j; + uint16 g; + + PutUInt16(0, ptr, 0, 1); + PutUInt16(262, ptr, 2, 1); + PutUInt16(0, ptr, 4, 1); + + for (i = 0; i < 256; i++) { + g = 0; + for (j = 0; j < s->n; j++) { + if (s->xc[j] == i) { + g = (uint16) s->xg[j]; + } + } + p[i] = (byte) g; + } + *length = 262; + return ptr; +} + + +/* XXX it only handles Format 0 encoding tables */ +static byte *PackCmap(CmapSubTable *s, uint32 *length) +{ + return PackCmapType0(s, length); +} + +static int GetRawData_cmap(TrueTypeTable *_this, byte **ptr, uint32 *len, uint32 *tag) +{ + table_cmap *t; + byte **subtables; + uint32 *sizes; /* of subtables */ + int i; + uint32 tlen = 0; + uint32 l; + uint32 cmapsize; + byte *cmap; + uint32 coffset; + + assert(_this != 0); + t = (table_cmap *) _this->data; + assert(t != 0); + assert(t->n != 0); + + subtables = scalloc(t->n, sizeof(byte *)); + sizes = scalloc(t->n, sizeof(uint32)); + + for (i = 0; i < t->n; i++) { + subtables[i] = PackCmap(t->s+i, &l); + sizes[i] = l; + tlen += l; + } + + cmapsize = tlen + 4 + 8 * t->n; + _this->rawdata = cmap = ttmalloc(cmapsize); + + PutUInt16(0, cmap, 0, 1); + PutUInt16(t->n, cmap, 2, 1); + coffset = 4 + t->n * 8; + + for (i = 0; i < t->n; i++) { + PutUInt16(t->s[i].id >> 16, cmap + 4, i * 8, 1); + PutUInt16(t->s[i].id & 0xFF, cmap + 4, 2 + i * 8, 1); + PutUInt32(coffset, cmap + 4, 4 + i * 8, 1); + memcpy(cmap + coffset, subtables[i], sizes[i]); + free(subtables[i]); + coffset += sizes[i]; + } + + free(subtables); + free(sizes); + + *ptr = cmap; + *len = cmapsize; + *tag = T_cmap; + + return TTCR_OK; +} + + +static int GetRawData_name(TrueTypeTable *_this, byte **ptr, uint32 *len, uint32 *tag) +{ + list l; + NameRecord *nr; + int16 i=0, n; /* number of Name Records */ + byte *name; + uint16 nameLen; + int stringLen = 0; + byte *p1, *p2; + + *ptr = 0; + *len = 0; + *tag = 0; + + assert(_this != 0); + l = (list) _this->data; + assert(l != 0); + + if ((n = listCount(l)) == 0) return TTCR_NONAMES; + + nr = scalloc(n, sizeof(NameRecord)); + + listToFirst(l); + + do { + memcpy(nr+i, listCurrent(l), sizeof(NameRecord)); + stringLen += nr[i].slen; + i++; + } while (listNext(l)); + + if (stringLen > 65535) { + free(nr); + return TTCR_NAMETOOLONG; + } + + qsort(nr, n, sizeof(NameRecord), NameRecordCompareF); + + nameLen = stringLen + 12 * n + 6; + name = ttmalloc(nameLen); + + PutUInt16(0, name, 0, 1); + PutUInt16(n, name, 2, 1); + PutUInt16(6 + 12 * n, name, 4, 1); + + p1 = name + 6; + p2 = p1 + 12 * n; + + for (i = 0; i < n; i++) { + PutUInt16(nr[i].platformID, p1, 0, 1); + PutUInt16(nr[i].encodingID, p1, 2, 1); + PutUInt16(nr[i].languageID, p1, 4, 1); + PutUInt16(nr[i].nameID, p1, 6, 1); + PutUInt16(nr[i].slen, p1, 8, 1); + PutUInt16(p2 - (name + 6 + 12 * n), p1, 10, 1); + memcpy(p2, nr[i].sptr, nr[i].slen); + /* {int j; for(j=0; j<nr[i].slen; j++) printf("%c", nr[i].sptr[j]); printf("\n"); }; */ + p2 += nr[i].slen; + p1 += 12; + } + + free(nr); + _this->rawdata = name; + + *ptr = name; + *len = nameLen; + *tag = T_name; + + /*{int j; for(j=0; j<nameLen; j++) printf("%c", name[j]); }; */ + + return TTCR_OK; +} + +static int GetRawData_post(TrueTypeTable *_this, byte **ptr, uint32 *len, uint32 *tag) +{ + tdata_post *p = (tdata_post *) _this->data; + byte *post = 0; + uint32 postLen = 0; + int ret; + + if (_this->rawdata) free(_this->rawdata); + + if (p->format == 0x00030000) { + postLen = 32; + post = ttmalloc(postLen); + PutUInt32(0x00030000, post, 0, 1); + PutUInt32(p->italicAngle, post, 4, 1); + PutUInt16(p->underlinePosition, post, 8, 1); + PutUInt16(p->underlineThickness, post, 10, 1); + PutUInt16(p->isFixedPitch, post, 12, 1); + ret = TTCR_OK; + } else { + fprintf(stderr, "Unrecognized format of a post table: %08X.\n", p->format); + ret = TTCR_POSTFORMAT; + } + + *ptr = _this->rawdata = post; + *len = postLen; + *tag = T_post; + + return ret; +} + + + + + +static struct { + uint32 tag; + int (*f)(TrueTypeTable *, byte **, uint32 *, uint32 *); +} vtable2[] = +{ + {0, GetRawData_generic}, + {T_head, GetRawData_head}, + {T_hhea, GetRawData_hhea}, + {T_loca, GetRawData_loca}, + {T_maxp, GetRawData_maxp}, + {T_glyf, GetRawData_glyf}, + {T_cmap, GetRawData_cmap}, + {T_name, GetRawData_name}, + {T_post, GetRawData_post} + + +}; + +/* + * TrueTypeTable public methods + */ + +/* Note: Type42 fonts only need these tables: + * head, hhea, loca, maxp, cvt, prep, glyf, hmtx, fpgm + * + * Microsoft required tables + * cmap, glyf, head, hhea, hmtx, loca, maxp, name, post, OS/2 + * + * Apple required tables + * cmap, glyf, head, hhea, hmtx, loca, maxp, name, post + * + */ + +TrueTypeTable *TrueTypeTableNew(uint32 tag, + uint32 nbytes, + byte *ptr) +{ + TrueTypeTable *table; + tdata_generic *pdata; + + table = smalloc(sizeof(TrueTypeTable)); + pdata = (tdata_generic *) smalloc(sizeof(tdata_generic)); + pdata->nbytes = nbytes; + pdata->tag = tag; + if (nbytes) { + pdata->ptr = ttmalloc(nbytes); + memcpy(pdata->ptr, ptr, nbytes); + } else { + pdata->ptr = 0; + } + + table->tag = 0; + table->data = pdata; + table->rawdata = 0; + + return table; +} + +TrueTypeTable *TrueTypeTableNew_head(uint32 fontRevision, + uint16 flags, + uint16 unitsPerEm, + byte *created, + uint16 macStyle, + uint16 lowestRecPPEM, + int16 fontDirectionHint) +{ + TrueTypeTable *table; + byte *ptr; + + assert(created != 0); + + table = smalloc(sizeof(TrueTypeTable)); + ptr = ttmalloc(TABLESIZE_head); + + + PutUInt32(0x00010000, ptr, 0, 1); /* version */ + PutUInt32(fontRevision, ptr, 4, 1); + PutUInt32(0x5F0F3CF5, ptr, 12, 1); /* magic number */ + PutUInt16(flags, ptr, 16, 1); + PutUInt16(unitsPerEm, ptr, 18, 1); + memcpy(ptr+20, created, 8); /* Created Long Date */ + bzero(ptr+28, 8); /* Modified Long Date */ + PutUInt16(macStyle, ptr, 44, 1); + PutUInt16(lowestRecPPEM, ptr, 46, 1); + PutUInt16(fontDirectionHint, ptr, 48, 1); + PutUInt16(0, ptr, 52, 1); /* glyph data format: 0 */ + + table->data = (void *) ptr; + table->tag = T_head; + table->rawdata = 0; + + return table; +} + +TrueTypeTable *TrueTypeTableNew_hhea(int16 ascender, + int16 descender, + int16 linegap, + int16 caretSlopeRise, + int16 caretSlopeRun) +{ + TrueTypeTable *table; + byte *ptr; + + table = smalloc(sizeof(TrueTypeTable)); + ptr = ttmalloc(TABLESIZE_hhea); + + PutUInt32(0x00010000, ptr, 0, 1); /* version */ + PutUInt16(ascender, ptr, 4, 1); + PutUInt16(descender, ptr, 6, 1); + PutUInt16(linegap, ptr, 8, 1); + PutUInt16(caretSlopeRise, ptr, 18, 1); + PutUInt16(caretSlopeRun, ptr, 20, 1); + PutUInt16(0, ptr, 22, 1); /* reserved 1 */ + PutUInt16(0, ptr, 24, 1); /* reserved 2 */ + PutUInt16(0, ptr, 26, 1); /* reserved 3 */ + PutUInt16(0, ptr, 28, 1); /* reserved 4 */ + PutUInt16(0, ptr, 30, 1); /* reserved 5 */ + PutUInt16(0, ptr, 32, 1); /* metricDataFormat */ + + table->data = (void *) ptr; + table->tag = T_hhea; + table->rawdata = 0; + + return table; +} + +TrueTypeTable *TrueTypeTableNew_loca(void) +{ + TrueTypeTable *table = smalloc(sizeof(TrueTypeTable)); + table->data = smalloc(sizeof(tdata_loca)); + + ((tdata_loca *)table->data)->nbytes = 0; + ((tdata_loca *)table->data)->ptr = 0; + + table->tag = T_loca; + table->rawdata = 0; + + return table; +} + +TrueTypeTable *TrueTypeTableNew_maxp(byte *maxp, int size) +{ + TrueTypeTable *table = smalloc(sizeof(TrueTypeTable)); + table->data = ttmalloc(TABLESIZE_maxp); + + if (maxp && size == TABLESIZE_maxp) { + memcpy(table->data, maxp, TABLESIZE_maxp); + } + + table->tag = T_maxp; + table->rawdata = 0; + + return table; +} + +TrueTypeTable *TrueTypeTableNew_glyf(void) +{ + TrueTypeTable *table = smalloc(sizeof(TrueTypeTable)); + list l = listNewEmpty(); + + assert(l != 0); + + listSetElementDtor(l, FreeGlyphData); + + table->data = l; + table->rawdata = 0; + table->tag = T_glyf; + + return table; +} + +TrueTypeTable *TrueTypeTableNew_cmap(void) +{ + TrueTypeTable *table = smalloc(sizeof(TrueTypeTable)); + table_cmap *cmap = smalloc(sizeof(table_cmap)); + + cmap->n = 0; + cmap->m = CMAP_SUBTABLE_INIT; + cmap->s = (CmapSubTable *) scalloc(CMAP_SUBTABLE_INIT, sizeof(CmapSubTable)); + memset(cmap->s, 0, sizeof(CmapSubTable) * CMAP_SUBTABLE_INIT); + + table->data = (table_cmap *) cmap; + + table->rawdata = 0; + table->tag = T_cmap; + + return table; +} + +static void DisposeNameRecord(void *ptr) +{ + if (ptr != 0) { + NameRecord *nr = (NameRecord *) ptr; + if (nr->sptr) free(nr->sptr); + free(ptr); + } +} + +static NameRecord* NameRecordNewCopy(NameRecord *nr) +{ + NameRecord *p = smalloc(sizeof(NameRecord)); + + memcpy(p, nr, sizeof(NameRecord)); + + if (p->slen) { + p->sptr = smalloc(p->slen); + memcpy(p->sptr, nr->sptr, p->slen); + } + + return p; +} + +TrueTypeTable *TrueTypeTableNew_name(int n, NameRecord *nr) +{ + TrueTypeTable *table = smalloc(sizeof(TrueTypeTable)); + list l = listNewEmpty(); + + assert(l != 0); + + listSetElementDtor(l, DisposeNameRecord); + + if (n != 0) { + int i; + for (i = 0; i < n; i++) { + listAppend(l, NameRecordNewCopy(nr+i)); + } + } + + table->data = l; + table->rawdata = 0; + table->tag = T_name; + + return table; +} + +TrueTypeTable *TrueTypeTableNew_post(uint32 format, + uint32 italicAngle, + int16 underlinePosition, + int16 underlineThickness, + uint32 isFixedPitch) +{ + TrueTypeTable *table; + tdata_post *post; + + assert(format == 0x00030000); /* Only format 3.0 is supported at this time */ + table = smalloc(sizeof(TrueTypeTable)); + post = smalloc(sizeof(tdata_post)); + + post->format = format; + post->italicAngle = italicAngle; + post->underlinePosition = underlinePosition; + post->underlineThickness = underlineThickness; + post->isFixedPitch = isFixedPitch; + post->ptr = 0; + + table->data = post; + table->rawdata = 0; + table->tag = T_post; + + return table; +} + + + +void TrueTypeTableDispose(TrueTypeTable *_this) +{ + /* XXX do a binary search */ + int i; + + assert(_this != 0); + + if (_this->rawdata) free(_this->rawdata); + + for(i=0; i < sizeof(vtable1)/sizeof(*vtable1); i++) { + if (_this->tag == vtable1[i].tag) { + vtable1[i].f(_this); + return; + } + } + assert(!"Unknown TrueType table.\n"); +} + +int GetRawData(TrueTypeTable *_this, byte **ptr, uint32 *len, uint32 *tag) +{ + /* XXX do a binary search */ + int i; + + assert(_this != 0); + assert(ptr != 0); + assert(len != 0); + assert(tag != 0); + + *ptr = 0; *len = 0; *tag = 0; + + if (_this->rawdata) { + free(_this->rawdata); + _this->rawdata = 0; + } + + for(i=0; i < sizeof(vtable2)/sizeof(*vtable2); i++) { + if (_this->tag == vtable2[i].tag) { + return vtable2[i].f(_this, ptr, len, tag); + } + } + + assert(!"Unknwon TrueType table.\n"); + return TTCR_UNKNOWN; +} + +void cmapAdd(TrueTypeTable *table, uint32 id, uint32 c, uint32 g) +{ + int i, found; + table_cmap *t; + CmapSubTable *s; + + assert(table != 0); + assert(table->tag == T_cmap); + t = (table_cmap *) table->data; assert(t != 0); + s = t->s; assert(s != 0); + + found = 0; + + for (i = 0; i < t->n; i++) { + if (s[i].id == id) { + found = 1; + break; + } + } + + if (!found) { + if (t->n == t->m) { + CmapSubTable *tmp; + tmp = scalloc(t->m + CMAP_SUBTABLE_INCR, sizeof(CmapSubTable)); + memset(tmp, 0, t->m + CMAP_SUBTABLE_INCR * sizeof(CmapSubTable)); + memcpy(tmp, s, sizeof(CmapSubTable) * t->m); + t->m += CMAP_SUBTABLE_INCR; + free(s); + s = tmp; + t->s = s; + } + + for (i = 0; i < t->n; i++) { + if (s[i].id > id) break; + } + + if (i < t->n) { + memmove(s+i+1, s+i, t->n-i); + } + + t->n++; + + s[i].id = id; + s[i].n = 0; + s[i].m = CMAP_PAIR_INIT; + s[i].xc = scalloc(CMAP_PAIR_INIT, sizeof(uint32)); + s[i].xg = scalloc(CMAP_PAIR_INIT, sizeof(uint32)); + } + + if (s[i].n == s[i].m) { + uint32 *tmp1 = scalloc(s[i].m + CMAP_PAIR_INCR, sizeof(uint32)); + uint32 *tmp2 = scalloc(s[i].m + CMAP_PAIR_INCR, sizeof(uint32)); + assert(tmp1 != 0); + assert(tmp2 != 0); + memcpy(tmp1, s[i].xc, sizeof(uint32) * s[i].m); + memcpy(tmp2, s[i].xg, sizeof(uint32) * s[i].m); + s[i].m += CMAP_PAIR_INCR; + free(s[i].xc); + free(s[i].xg); + s[i].xc = tmp1; + s[i].xg = tmp2; + } + + s[i].xc[s[i].n] = c; + s[i].xg[s[i].n] = g; + s[i].n++; +} + +uint32 glyfAdd(TrueTypeTable *table, GlyphData *glyphdata, TrueTypeFont *fnt) +{ + list l; + uint32 currentID; + int ret, n, ncomponents; + list glyphlist; + GlyphData *gd; + + assert(table != 0); + assert(table->tag == T_glyf); + + if (!glyphdata) return -1; + + glyphlist = listNewEmpty(); + + ncomponents = GetTTGlyphComponents(fnt, glyphdata->glyphID, glyphlist); + + l = (list) table->data; + if (listCount(l) > 0) { + listToLast(l); + ret = n = ((GlyphData *) listCurrent(l))->newID + 1; + } else { + ret = n = 0; + } + glyphdata->newID = n++; + listAppend(l, glyphdata); + + if (ncomponents > 1) { + listPositionAt(glyphlist, 1); /* glyphData->glyphID is always the first glyph on the list */ + do { + int found = 0; + currentID = (uint32) listCurrent(glyphlist); + /* XXX expensive! should be rewritten with sorted arrays! */ + listToFirst(l); + do { + if (((GlyphData *) listCurrent(l))->glyphID == currentID) { + found = 1; + break; + } + } while (listNext(l)); + + if (!found) { + gd = GetTTRawGlyphData(fnt, currentID); + gd->newID = n++; + listAppend(l, gd); + } + } while (listNext(glyphlist)); + } + + listDispose(glyphlist); + return ret; +} + +uint32 glyfCount(const TrueTypeTable *table) +{ + assert(table != 0); + assert(table->tag == T_glyf); + return listCount((list) table->data); +} + + +void nameAdd(TrueTypeTable *table, NameRecord *nr) +{ + list l; + + assert(table != 0); + assert(table->tag == T_name); + + l = (list) table->data; + + listAppend(l, NameRecordNewCopy(nr)); +} + +static TrueTypeTable *FindTable(TrueTypeCreator *tt, uint32 tag) +{ + if (listIsEmpty(tt->tables)) return 0; + + listToFirst(tt->tables); + + do { + if (((TrueTypeTable *) listCurrent(tt->tables))->tag == tag) { + return listCurrent(tt->tables); + } + } while (listNext(tt->tables)); + + return 0; +} + +/* This function processes all the tables and synchronizes them before creating + * the output TrueType stream. + * + * *** It adds two TrueType tables to the font: 'loca' and 'hmtx' *** + * + * It does: + * + * - Re-numbers glyph IDs and creates 'glyf', 'loca', and 'hmtx' tables. + * - Calculates xMin, yMin, xMax, and yMax and stores values in 'head' table. + * - Stores indexToLocFormat in 'head' + * - updates 'maxp' table + * - Calculates advanceWidthMax, minLSB, minRSB, xMaxExtent and numberOfHMetrics + * in 'hhea' table + * + */ +static void ProcessTables(TrueTypeCreator *tt) +{ + TrueTypeTable *glyf, *loca, *head, *maxp, *hhea; + list glyphlist; + uint32 nGlyphs, locaLen = 0, glyfLen = 0; + int16 xMin = 0, yMin = 0, xMax = 0, yMax = 0; + int i = 0; + int16 indexToLocFormat; + byte *glyfPtr, *locaPtr, *hmtxPtr, *hheaPtr; + uint32 hmtxSize; + byte *p1, *p2; + uint16 maxPoints = 0, maxContours = 0, maxCompositePoints = 0, maxCompositeContours = 0; + TTSimpleGlyphMetrics *met; + int nlsb = 0; + uint32 *gid; /* array of old glyphIDs */ + + glyf = FindTable(tt, T_glyf); + glyphlist = (list) glyf->data; + nGlyphs = listCount(glyphlist); + assert(nGlyphs != 0); + gid = scalloc(nGlyphs, sizeof(uint32)); + + RemoveTable(tt, T_loca); + RemoveTable(tt, T_hmtx); + + /* XXX Need to make sure that composite glyphs do not break during glyph renumbering */ + + listToFirst(glyphlist); + do { + GlyphData *gd = (GlyphData *) listCurrent(glyphlist); + int16 z; + glyfLen += gd->nbytes; + /* XXX if (gd->nbytes & 1) glyfLen++; */ + + + assert(gd->newID == i); + gid[i++] = gd->glyphID; + /* gd->glyphID = i++; */ + + /* printf("IDs: %d %d.\n", gd->glyphID, gd->newID); */ + + if (gd->nbytes != 0) { + z = GetInt16(gd->ptr, 2, 1); + if (z < xMin) xMin = z; + + z = GetInt16(gd->ptr, 4, 1); + if (z < yMin) yMin = z; + + z = GetInt16(gd->ptr, 6, 1); + if (z > xMax) xMax = z; + + z = GetInt16(gd->ptr, 8, 1); + if (z > yMax) yMax = z; + } + + if (gd->compflag == 0) { /* non-composite glyph */ + if (gd->npoints > maxPoints) maxPoints = gd->npoints; + if (gd->ncontours > maxContours) maxContours = gd->ncontours; + } else { /* composite glyph */ + if (gd->npoints > maxCompositePoints) maxCompositePoints = gd->npoints; + if (gd->ncontours > maxCompositeContours) maxCompositeContours = gd->ncontours; + } + + } while (listNext(glyphlist)); + + indexToLocFormat = (glyfLen / 2 > 0xFFFF) ? 1 : 0; + locaLen = indexToLocFormat ? (nGlyphs + 1) << 2 : (nGlyphs + 1) << 1; + + glyfPtr = ttmalloc(glyfLen); + locaPtr = ttmalloc(locaLen); + met = scalloc(nGlyphs, sizeof(TTSimpleGlyphMetrics)); + i = 0; + + listToFirst(glyphlist); + p1 = glyfPtr; + p2 = locaPtr; + do { + GlyphData *gd = (GlyphData *) listCurrent(glyphlist); + + if (gd->compflag) { /* re-number all components */ + uint16 flags, index; + byte *ptr = gd->ptr + 10; + do { + int j; + flags = GetUInt16(ptr, 0, 1); + index = GetUInt16(ptr, 2, 1); + /* XXX use the sorted array of old to new glyphID mapping and do a binary search */ + for (j = 0; j < nGlyphs; j++) { + if (gid[j] == index) { + break; + } + } + /* printf("X: %d -> %d.\n", index, j); */ + + PutUInt16((uint16) j, ptr, 2, 1); + + ptr += 4; + + if (flags & ARG_1_AND_2_ARE_WORDS) { + ptr += 4; + } else { + ptr += 2; + } + + if (flags & WE_HAVE_A_SCALE) { + ptr += 2; + } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { + ptr += 4; + } else if (flags & WE_HAVE_A_TWO_BY_TWO) { + ptr += 8; + } + } while (flags & MORE_COMPONENTS); + } + + if (gd->nbytes != 0) { + memcpy(p1, gd->ptr, gd->nbytes); + } + if (indexToLocFormat == 1) { + PutUInt32(p1 - glyfPtr, p2, 0, 1); + p2 += 4; + } else { + PutUInt16((p1 - glyfPtr) >> 1, p2, 0, 1); + p2 += 2; + } + p1 += gd->nbytes; + + /* fill the array of metrics */ + met[i].adv = gd->aw; + met[i].sb = gd->lsb; + i++; + } while (listNext(glyphlist)); + + free(gid); + + if (indexToLocFormat == 1) { + PutUInt32(p1 - glyfPtr, p2, 0, 1); + } else { + PutUInt16((p1 - glyfPtr) >> 1, p2, 0, 1); + } + + glyf->rawdata = glyfPtr; + + loca = TrueTypeTableNew_loca(); assert(loca != 0); + ((tdata_loca *) loca->data)->ptr = locaPtr; + ((tdata_loca *) loca->data)->nbytes = locaLen; + + AddTable(tt, loca); + + head = FindTable(tt, T_head); + PutInt16(xMin, head->data, 36, 1); + PutInt16(yMin, head->data, 38, 1); + PutInt16(xMax, head->data, 40, 1); + PutInt16(yMax, head->data, 42, 1); + PutInt16(indexToLocFormat, head->data, 50, 1); + + maxp = FindTable(tt, T_maxp); + + PutUInt16(nGlyphs, maxp->data, 4, 1); + PutUInt16(maxPoints, maxp->data, 6, 1); + PutUInt16(maxContours, maxp->data, 8, 1); + PutUInt16(maxCompositePoints, maxp->data, 10, 1); + PutUInt16(maxCompositeContours, maxp->data, 12, 1); + +#if 0 + /* XXX do not overwrite the existing data. Fix: re-calculate these numbers here */ + PutUInt16(2, maxp->data, 14, 1); /* maxZones is always 2 */ + PutUInt16(0, maxp->data, 16, 1); /* maxTwilightPoints */ + PutUInt16(0, maxp->data, 18, 1); /* maxStorage */ + PutUInt16(0, maxp->data, 20, 1); /* maxFunctionDefs */ + PutUint16(0, maxp->data, 22, 1); /* maxInstructionDefs */ + PutUint16(0, maxp->data, 24, 1); /* maxStackElements */ + PutUint16(0, maxp->data, 26, 1); /* maxSizeOfInstructions */ + PutUint16(0, maxp->data, 28, 1); /* maxComponentElements */ + PutUint16(0, maxp->data, 30, 1); /* maxComponentDepth */ +#endif + + /* + * Generate an htmx table and update hhea table + */ + hhea = FindTable(tt, T_hhea); assert(hhea != 0); + hheaPtr = (byte *) hhea->data; + if (nGlyphs > 2) { + for (i = nGlyphs - 1; i > 0; i--) { + if (met[i].adv != met[i-1].adv) break; + } + nlsb = nGlyphs - 1 - i; + } + hmtxSize = (nGlyphs - nlsb) * 4 + nlsb * 2; + hmtxPtr = ttmalloc(hmtxSize); + p1 = hmtxPtr; + + for (i = 0; i < nGlyphs; i++) { + if (i < nGlyphs - nlsb) { + PutUInt16(met[i].adv, p1, 0, 1); + PutUInt16(met[i].sb, p1, 2, 1); + p1 += 4; + } else { + PutUInt16(met[i].sb, p1, 0, 1); + p1 += 2; + } + } + + AddTable(tt, TrueTypeTableNew(T_hmtx, hmtxSize, hmtxPtr)); + PutUInt16(nGlyphs - nlsb, hheaPtr, 34, 1); + free(hmtxPtr); + free(met); +} + +#ifdef TEST_TTCR +int main(void) +{ + TrueTypeCreator *ttcr; + byte *t1, *t2, *t3, *t4, *t5, *t6, *t7; + + TrueTypeCreatorNewEmpty(mkTag('t','r','u','e'), &ttcr); + + t1 = malloc(1000); memset(t1, 'a', 1000); + t2 = malloc(2000); memset(t2, 'b', 2000); + t3 = malloc(3000); memset(t3, 'c', 3000); + t4 = malloc(4000); memset(t4, 'd', 4000); + t5 = malloc(5000); memset(t5, 'e', 5000); + t6 = malloc(6000); memset(t6, 'f', 6000); + t7 = malloc(7000); memset(t7, 'g', 7000); + + AddTable(ttcr, TrueTypeTableNew(0x6D617870, 1000, t1)); + AddTable(ttcr, TrueTypeTableNew(0x4F532F32, 2000, t2)); + AddTable(ttcr, TrueTypeTableNew(0x636D6170, 3000, t3)); + AddTable(ttcr, TrueTypeTableNew(0x6C6F6361, 4000, t4)); + AddTable(ttcr, TrueTypeTableNew(0x68686561, 5000, t5)); + AddTable(ttcr, TrueTypeTableNew(0x676C7966, 6000, t6)); + AddTable(ttcr, TrueTypeTableNew(0x6B65726E, 7000, t7)); + + free(t1); + free(t2); + free(t3); + free(t4); + free(t5); + free(t6); + free(t7); + + + StreamToFile(ttcr, "ttcrout.ttf"); + + TrueTypeCreatorDispose(ttcr); + return 0; +} +#endif diff --git a/psprint/source/fontsubset/ttcr.h b/psprint/source/fontsubset/ttcr.h new file mode 100644 index 000000000000..414b035cbe19 --- /dev/null +++ b/psprint/source/fontsubset/ttcr.h @@ -0,0 +1,311 @@ +/************************************************************************* + * + * $RCSfile: ttcr.h,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:38 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Alexander Gelfenbain + * + * + ************************************************************************/ + +/* $Id: ttcr.h,v 1.1.1.1 2001-05-08 11:45:38 pl Exp $ */ + +/** + * + * @file ttcr.h + * @brief TrueType font creator + * @author Alexander Gelfenbain + */ + +#ifndef __TTCR_H +#define __TTCR_H + +#include "sft.h" +#include "list.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct _TrueTypeCreator TrueTypeCreator; + +/* TrueType data types */ + typedef struct { + uint16 aw; + int16 lsb; + } longHorMetrics; + +/* A generic base class for all TrueType tables */ + typedef struct { + uint32 tag; /* table tag */ + byte *rawdata; /* raw data allocated by GetRawData_*() */ + void *data; /* table specific data */ + } TrueTypeTable; + +/** Error codes for most functions */ + enum TTCRErrCodes { + TTCR_OK = 0, /**< no error */ + TTCR_ZEROGLYPHS = 1, /**< At least one glyph should be defined */ + TTCR_UNKNOWN = 2, /**< Unknown TrueType table */ + TTCR_GLYPHSEQ = 3, /**< Glyph IDs are not sequential in the glyf table */ + TTCR_NONAMES = 4, /**< 'name' table does not contain any names */ + TTCR_NAMETOOLONG = 5, /**< 'name' table is too long (string data > 64K) */ + TTCR_POSTFORMAT = 6 /**< unsupported format of a 'post' table */ + }; + +/* ============================================================================ + * + * TrueTypeCreator methods + * + * ============================================================================ */ + +/** + * TrueTypeCreator constructor. + * Allocates all internal structures. + */ + void TrueTypeCreatorNewEmpty(uint32 tag, TrueTypeCreator **_this); + +/** + * TrueTypeCreator destructor. It calls destructors for all TrueTypeTables added to it. + */ + void TrueTypeCreatorDispose(TrueTypeCreator *_this); + +/** + * Adds a TrueType table to the TrueType creator. + * SF_TABLEFORMAT value. + * @return value of SFErrCodes type + */ + int AddTable(TrueTypeCreator *_this, TrueTypeTable *table); + +/** + * Removes a TrueType table from the TrueType creator if it is stored there. + * It also calls a TrueTypeTable destructor. + * Note: all generic tables (with tag 0) will be removed if this function is + * called with the second argument of 0. + * @return value of SFErrCodes type + */ + void RemoveTable(TrueTypeCreator *_this, uint32 tag); + + + +/** + * Writes a TrueType font generated by the TrueTypeCreator to a segment of + * memory that this method allocates. When it is not needed anymore the caller + * is supposed to call free() on it. + * @return value of SFErrCodes type + */ + int StreamToMemory(TrueTypeCreator *_this, byte **ptr, uint32 *length); + +/** + * Writes a TrueType font generated by the TrueTypeCreator to a file + * @return value of SFErrCodes type + */ + int StreamToFile(TrueTypeCreator *_this, const char* fname); + + +/* ============================================================================ + * + * TrueTypeTable methods + * + * ============================================================================ */ + +/** + * Destructor for the TrueTypeTable object. + */ + void TrueTypeTableDispose(TrueTypeTable *); + +/** + * This function converts the data of a TrueType table to a raw array of bytes. + * It may allocates the memory for it and returns the size of the raw data in bytes. + * If memory is allocated it does not need to be freed by the caller of this function, + * since the pointer to it is stored in the TrueTypeTable and it is freed by the destructor + * @return TTCRErrCode + * + */ + + int GetRawData(TrueTypeTable *, byte **ptr, uint32 *len, uint32 *tag); + +/** + * + * Creates a new raw TrueType table. The difference between this constructor and + * TrueTypeTableNew_tag constructors is that the latter create structured tables + * while this constructor just copies memory pointed to by ptr to its buffer + * and stores its length. This constructor is suitable for data that is not + * supposed to be processed in any way, just written to the resulting TTF file. + */ + TrueTypeTable *TrueTypeTableNew(uint32 tag, + uint32 nbytes, + byte *ptr); + +/** + * Creates a new 'head' table for a TrueType font. + * Allocates memory for it. Since a lot of values in the 'head' table depend on the + * rest of the tables in the TrueType font this table should be the last one added + * to the font. + */ + TrueTypeTable *TrueTypeTableNew_head(uint32 fontRevision, + uint16 flags, + uint16 unitsPerEm, + byte *created, + uint16 macStyle, + uint16 lowestRecPPEM, + int16 fontDirectionHint); + +/** + * Creates a new 'hhea' table for a TrueType font. + * Allocates memory for it and stores it in the hhea pointer. + */ + TrueTypeTable *TrueTypeTableNew_hhea(int16 ascender, + int16 descender, + int16 linegap, + int16 caretSlopeRise, + int16 caretSlopeRun); + +/** + * Creates a new empty 'loca' table for a TrueType font. + * + * INTERNAL: gets called only from ProcessTables(); + */ + TrueTypeTable *TrueTypeTableNew_loca(void); + +/** + * Creates a new 'maxp' table based on an existing maxp table. + * If maxp is 0, a new empty maxp table is created + * size specifies the size of existing maxp table for + * error-checking purposes + */ + TrueTypeTable *TrueTypeTableNew_maxp(byte *maxp, int size); + +/** + * Creates a new empty 'glyf' table. + */ + TrueTypeTable *TrueTypeTableNew_glyf(void); + +/** + * Creates a new empty 'cmap' table. + */ + TrueTypeTable *TrueTypeTableNew_cmap(void); + +/** + * Creates a new 'name' table. If n != 0 the table gets populated by + * the Name Records stored in the nr array. This function allocates + * memory for its own copy of NameRecords, so nr array has to + * be explicitly deallocated when it is not needed. + */ + TrueTypeTable *TrueTypeTableNew_name(int n, NameRecord *nr); + +/** + * Creates a new 'post' table of one of the supported formats + */ + TrueTypeTable *TrueTypeTableNew_post(uint32 format, + uint32 italicAngle, + int16 underlinePosition, + int16 underlineThickness, + uint32 isFixedPitch); + + +/*------------------------------------------------------------------------------ + * + * Table manipulation functions + * + *------------------------------------------------------------------------------*/ + + +/** + * Add a character/glyph pair to a cmap table + */ + void cmapAdd(TrueTypeTable *, uint32 id, uint32 c, uint32 g); + +/** + * Add a glyph to a glyf table. + * + * @return glyphID of the glyph in the new font + * + * NOTE: This function does not duplicate GlyphData, so memory will be + * deallocated in the table destructor + */ + uint32 glyfAdd(TrueTypeTable *, GlyphData *glyphdata, TrueTypeFont *fnt); + +/** + * Query the number of glyphs currently stored in the 'glyf' table + * + */ + uint32 glyfCount(const TrueTypeTable *); + +/** + * Add a Name Record to a name table. + * NOTE: This function duplicates NameRecord, so the argument + * has to be deallocated by the caller (unlike glyfAdd) + */ + void nameAdd(TrueTypeTable *, NameRecord *nr); + + + +/* + * Private Data Types + */ + + struct _TrueTypeCreator { + uint32 tag; /**< TrueType file tag */ + list tables; /**< List of table tags and pointers */ + }; + + + +#ifdef __cplusplus +} +#endif + +#endif /* __TTCR_H */ diff --git a/psprint/source/fontsubset/u2big5.inc b/psprint/source/fontsubset/u2big5.inc new file mode 100644 index 000000000000..a81b6e3a5c67 --- /dev/null +++ b/psprint/source/fontsubset/u2big5.inc @@ -0,0 +1,1788 @@ +/************************************************************************* + * + * $RCSfile: u2big5.inc,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: pl $ $Date: 2001-05-08 11:45:42 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Alexander Gelfenbain + * + * + ************************************************************************/ + +uint16pair xlat_1_3[13798] = { + {0x0020, 0x0020},{0x0021, 0x0021},{0x0022, 0x0022},{0x0023, 0x0023},{0x0024, 0x0024},{0x0025, 0x0025},{0x0026, 0x0026},{0x0027, 0x0027}, + {0x0028, 0x0028},{0x0029, 0x0029},{0x002A, 0x002A},{0x002B, 0x002B},{0x002C, 0x002C},{0x002D, 0x002D},{0x002E, 0x002E},{0x002F, 0x002F}, + {0x0030, 0x0030},{0x0031, 0x0031},{0x0032, 0x0032},{0x0033, 0x0033},{0x0034, 0x0034},{0x0035, 0x0035},{0x0036, 0x0036},{0x0037, 0x0037}, + {0x0038, 0x0038},{0x0039, 0x0039},{0x003A, 0x003A},{0x003B, 0x003B},{0x003C, 0x003C},{0x003D, 0x003D},{0x003E, 0x003E},{0x003F, 0x003F}, + {0x0040, 0x0040},{0x0041, 0x0041},{0x0042, 0x0042},{0x0043, 0x0043},{0x0044, 0x0044},{0x0045, 0x0045},{0x0046, 0x0046},{0x0047, 0x0047}, + {0x0048, 0x0048},{0x0049, 0x0049},{0x004A, 0x004A},{0x004B, 0x004B},{0x004C, 0x004C},{0x004D, 0x004D},{0x004E, 0x004E},{0x004F, 0x004F}, + {0x0050, 0x0050},{0x0051, 0x0051},{0x0052, 0x0052},{0x0053, 0x0053},{0x0054, 0x0054},{0x0055, 0x0055},{0x0056, 0x0056},{0x0057, 0x0057}, + {0x0058, 0x0058},{0x0059, 0x0059},{0x005A, 0x005A},{0x005B, 0x005B},{0x005C, 0x005C},{0x005D, 0x005D},{0x005E, 0x005E},{0x005F, 0x005F}, + {0x0060, 0x0060},{0x0061, 0x0061},{0x0062, 0x0062},{0x0063, 0x0063},{0x0064, 0x0064},{0x0065, 0x0065},{0x0066, 0x0066},{0x0067, 0x0067}, + {0x0068, 0x0068},{0x0069, 0x0069},{0x006A, 0x006A},{0x006B, 0x006B},{0x006C, 0x006C},{0x006D, 0x006D},{0x006E, 0x006E},{0x006F, 0x006F}, + {0x0070, 0x0070},{0x0071, 0x0071},{0x0072, 0x0072},{0x0073, 0x0073},{0x0074, 0x0074},{0x0075, 0x0075},{0x0076, 0x0076},{0x0077, 0x0077}, + {0x0078, 0x0078},{0x0079, 0x0079},{0x007A, 0x007A},{0x007B, 0x007B},{0x007C, 0x007C},{0x007D, 0x007D},{0x007E, 0x007E},{0x00A2, 0xA246}, + {0x00A3, 0xA247},{0x00A5, 0xA244},{0x00A7, 0xA1B1},{0x00B0, 0xA258},{0x00B1, 0xA1D3},{0x00B7, 0xA150},{0x00D7, 0xA1D1},{0x00F7, 0xA1D2}, + {0x02C7, 0xA3BE},{0x02C9, 0xA3BC},{0x02CA, 0xA3BD},{0x02CB, 0xA3BF},{0x02D9, 0xA3BB},{0x0391, 0xA344},{0x0392, 0xA345},{0x0393, 0xA346}, + {0x0394, 0xA347},{0x0395, 0xA348},{0x0396, 0xA349},{0x0397, 0xA34A},{0x0398, 0xA34B},{0x0399, 0xA34C},{0x039A, 0xA34D},{0x039B, 0xA34E}, + {0x039C, 0xA34F},{0x039D, 0xA350},{0x039E, 0xA351},{0x039F, 0xA352},{0x03A0, 0xA353},{0x03A1, 0xA354},{0x03A3, 0xA355},{0x03A4, 0xA356}, + {0x03A5, 0xA357},{0x03A6, 0xA358},{0x03A7, 0xA359},{0x03A8, 0xA35A},{0x03A9, 0xA35B},{0x03B1, 0xA35C},{0x03B2, 0xA35D},{0x03B3, 0xA35E}, + {0x03B4, 0xA35F},{0x03B5, 0xA360},{0x03B6, 0xA361},{0x03B7, 0xA362},{0x03B8, 0xA363},{0x03B9, 0xA364},{0x03BA, 0xA365},{0x03BB, 0xA366}, + {0x03BC, 0xA367},{0x03BD, 0xA368},{0x03BE, 0xA369},{0x03BF, 0xA36A},{0x03C0, 0xA36B},{0x03C1, 0xA36C},{0x03C3, 0xA36D},{0x03C4, 0xA36E}, + {0x03C5, 0xA36F},{0x03C6, 0xA370},{0x03C7, 0xA371},{0x03C8, 0xA372},{0x03C9, 0xA373},{0x0401, 0xC7B3},{0x0414, 0xC7B1},{0x0415, 0xC7B2}, + {0x0416, 0xC7B4},{0x0417, 0xC7B5},{0x0418, 0xC7B6},{0x0419, 0xC7B7},{0x041A, 0xC7B8},{0x041B, 0xC7B9},{0x041C, 0xC7BA},{0x0423, 0xC7BB}, + {0x0424, 0xC7BC},{0x0425, 0xC7BD},{0x0426, 0xC7BE},{0x0427, 0xC7BF},{0x0428, 0xC7C0},{0x0429, 0xC7C1},{0x042A, 0xC7C2},{0x042B, 0xC7C3}, + {0x042C, 0xC7C4},{0x042D, 0xC7C5},{0x042E, 0xC7C6},{0x042F, 0xC7C7},{0x0430, 0xC7C8},{0x0431, 0xC7C9},{0x0432, 0xC7CA},{0x0433, 0xC7CB}, + {0x0434, 0xC7CC},{0x0435, 0xC7CD},{0x0436, 0xC7CF},{0x0437, 0xC7D0},{0x0438, 0xC7D1},{0x0439, 0xC7D2},{0x043A, 0xC7D3},{0x043B, 0xC7D4}, + {0x043C, 0xC7D5},{0x043D, 0xC7D6},{0x043E, 0xC7D7},{0x043F, 0xC7D8},{0x0440, 0xC7D9},{0x0441, 0xC7DA},{0x0442, 0xC7DB},{0x0443, 0xC7DC}, + {0x0444, 0xC7DD},{0x0445, 0xC7DE},{0x0446, 0xC7DF},{0x0447, 0xC7E0},{0x0448, 0xC7E1},{0x0449, 0xC7E2},{0x044A, 0xC7E3},{0x044B, 0xC7E4}, + {0x044C, 0xC7E5},{0x044D, 0xC7E6},{0x044E, 0xC7E7},{0x044F, 0xC7E8},{0x0451, 0xC7CE},{0x2013, 0xA156},{0x2014, 0xA158},{0x2018, 0xA1A5}, + {0x2019, 0xA1A6},{0x201C, 0xA1A7},{0x201D, 0xA1A8},{0x2022, 0xA145},{0x2025, 0xA14C},{0x2026, 0xA14B},{0x2032, 0xA1AC},{0x2035, 0xA1AB}, + {0x203B, 0xA1B0},{0x203E, 0xA1C2},{0x2103, 0xA24A},{0x2105, 0xA1C1},{0x2109, 0xA24B},{0x2160, 0xA2B9},{0x2161, 0xA2BA},{0x2162, 0xA2BB}, + {0x2163, 0xA2BC},{0x2164, 0xA2BD},{0x2165, 0xA2BE},{0x2166, 0xA2BF},{0x2167, 0xA2C0},{0x2168, 0xA2C1},{0x2169, 0xA2C2},{0x2190, 0xA1F6}, + {0x2191, 0xA1F4},{0x2192, 0xA1F7},{0x2193, 0xA1F5},{0x2196, 0xA1F8},{0x2197, 0xA1F9},{0x2198, 0xA1FB},{0x2199, 0xA1FA},{0x221A, 0xA1D4}, + {0x221E, 0xA1DB},{0x221F, 0xA1E8},{0x2220, 0xA1E7},{0x2223, 0xA1FD},{0x2225, 0xA1FC},{0x2229, 0xA1E4},{0x222A, 0xA1E5},{0x222B, 0xA1EC}, + {0x222E, 0xA1ED},{0x2234, 0xA1EF},{0x2235, 0xA1EE},{0x223C, 0xA1E3},{0x2252, 0xA1DC},{0x2260, 0xA1DA},{0x2261, 0xA1DD},{0x2266, 0xA1D8}, + {0x2267, 0xA1D9},{0x22A5, 0xA1E6},{0x22BF, 0xA1E9},{0x2460, 0xC7E9},{0x2461, 0xC7EA},{0x2462, 0xC7EB},{0x2463, 0xC7EC},{0x2464, 0xC7ED}, + {0x2465, 0xC7EE},{0x2466, 0xC7EF},{0x2467, 0xC7F0},{0x2468, 0xC7F1},{0x2469, 0xC7F2},{0x2474, 0xC7F3},{0x2475, 0xC7F4},{0x2476, 0xC7F5}, + {0x2477, 0xC7F6},{0x2478, 0xC7F7},{0x2479, 0xC7F8},{0x247A, 0xC7F9},{0x247B, 0xC7FA},{0x247C, 0xC7FB},{0x247D, 0xC7FC},{0x2500, 0xA277}, + {0x2502, 0xA278},{0x250C, 0xA27A},{0x2510, 0xA27B},{0x2514, 0xA27C},{0x2518, 0xA27D},{0x251C, 0xA275},{0x2524, 0xA274},{0x252C, 0xA273}, + {0x2534, 0xA272},{0x253C, 0xA271},{0x2550, 0xA2A4},{0x255E, 0xA2A5},{0x2561, 0xA2A7},{0x256A, 0xA2A6},{0x256D, 0xA27E},{0x256E, 0xA2A1}, + {0x256F, 0xA2A3},{0x2570, 0xA2A2},{0x2571, 0xA2AC},{0x2572, 0xA2AD},{0x2573, 0xA2AE},{0x2581, 0xA262},{0x2582, 0xA263},{0x2583, 0xA264}, + {0x2584, 0xA265},{0x2585, 0xA266},{0x2586, 0xA267},{0x2587, 0xA268},{0x2588, 0xA269},{0x2589, 0xA270},{0x258A, 0xA26F},{0x258B, 0xA26E}, + {0x258C, 0xA26D},{0x258D, 0xA26C},{0x258E, 0xA26B},{0x258F, 0xA26A},{0x2594, 0xA276},{0x2595, 0xA279},{0x25A0, 0xA1BD},{0x25A1, 0xA1BC}, + {0x25B2, 0xA1B6},{0x25B3, 0xA1B5},{0x25BC, 0xA1BF},{0x25BD, 0xA1BE},{0x25C6, 0xA1BB},{0x25C7, 0xA1BA},{0x25CB, 0xA1B3},{0x25CE, 0xA1B7}, + {0x25CF, 0xA1B4},{0x25E2, 0xA2A8},{0x25E3, 0xA2A9},{0x25E4, 0xA2AB},{0x25E5, 0xA2AA},{0x2605, 0xA1B9},{0x2606, 0xA1B8},{0x2609, 0xA1F3}, + {0x2640, 0xA1F0},{0x2641, 0xA1F2},{0x2642, 0xA1F1},{0x3000, 0xA140},{0x3001, 0xA142},{0x3002, 0xA143},{0x3003, 0xA1B2},{0x3005, 0xC6A4}, + {0x3008, 0xA171},{0x3009, 0xA172},{0x300A, 0xA16D},{0x300B, 0xA16E},{0x300C, 0xA175},{0x300D, 0xA176},{0x300E, 0xA179},{0x300F, 0xA17A}, + {0x3010, 0xA169},{0x3011, 0xA16A},{0x3012, 0xA245},{0x3014, 0xA165},{0x3015, 0xA166},{0x301D, 0xA1A9},{0x301E, 0xA1AA},{0x3021, 0xA2C3}, + {0x3022, 0xA2C4},{0x3023, 0xA2C5},{0x3024, 0xA2C6},{0x3025, 0xA2C7},{0x3026, 0xA2C8},{0x3027, 0xA2C9},{0x3028, 0xA2CA},{0x3029, 0xA2CB}, + {0x3041, 0xC6A5},{0x3042, 0xC6A6},{0x3043, 0xC6A7},{0x3044, 0xC6A8},{0x3045, 0xC6A9},{0x3046, 0xC6AA},{0x3047, 0xC6AB},{0x3048, 0xC6AC}, + {0x3049, 0xC6AD},{0x304A, 0xC6AE},{0x304B, 0xC6AF},{0x304C, 0xC6B0},{0x304D, 0xC6B1},{0x304E, 0xC6B2},{0x304F, 0xC6B3},{0x3050, 0xC6B4}, + {0x3051, 0xC6B5},{0x3052, 0xC6B6},{0x3053, 0xC6B7},{0x3054, 0xC6B8},{0x3055, 0xC6B9},{0x3056, 0xC6BA},{0x3057, 0xC6BB},{0x3058, 0xC6BC}, + {0x3059, 0xC6BD},{0x305A, 0xC6BE},{0x305B, 0xC6BF},{0x305C, 0xC6C0},{0x305D, 0xC6C1},{0x305E, 0xC6C2},{0x305F, 0xC6C3},{0x3060, 0xC6C4}, + {0x3061, 0xC6C5},{0x3062, 0xC6C6},{0x3063, 0xC6C7},{0x3064, 0xC6C8},{0x3065, 0xC6C9},{0x3066, 0xC6CA},{0x3067, 0xC6CB},{0x3068, 0xC6CC}, + {0x3069, 0xC6CD},{0x306A, 0xC6CE},{0x306B, 0xC6CF},{0x306C, 0xC6D0},{0x306D, 0xC6D1},{0x306E, 0xC6D2},{0x306F, 0xC6D3},{0x3070, 0xC6D4}, + {0x3071, 0xC6D5},{0x3072, 0xC6D6},{0x3073, 0xC6D7},{0x3074, 0xC6D8},{0x3075, 0xC6D9},{0x3076, 0xC6DA},{0x3077, 0xC6DB},{0x3078, 0xC6DC}, + {0x3079, 0xC6DD},{0x307A, 0xC6DE},{0x307B, 0xC6DF},{0x307C, 0xC6E0},{0x307D, 0xC6E1},{0x307E, 0xC6E2},{0x307F, 0xC6E3},{0x3080, 0xC6E4}, + {0x3081, 0xC6E5},{0x3082, 0xC6E6},{0x3083, 0xC6E7},{0x3084, 0xC6E8},{0x3085, 0xC6E9},{0x3086, 0xC6EA},{0x3087, 0xC6EB},{0x3088, 0xC6EC}, + {0x3089, 0xC6ED},{0x308A, 0xC6EE},{0x308B, 0xC6EF},{0x308C, 0xC6F0},{0x308D, 0xC6F1},{0x308E, 0xC6F2},{0x308F, 0xC6F3},{0x3090, 0xC6F4}, + {0x3091, 0xC6F5},{0x3092, 0xC6F6},{0x3093, 0xC6F7},{0x309D, 0xC6A2},{0x309E, 0xC6A3},{0x30A1, 0xC6F8},{0x30A2, 0xC6F9},{0x30A3, 0xC6FA}, + {0x30A4, 0xC6FB},{0x30A5, 0xC6FC},{0x30A6, 0xC6FD},{0x30A7, 0xC6FE},{0x30A8, 0xC740},{0x30A9, 0xC741},{0x30AA, 0xC742},{0x30AB, 0xC743}, + {0x30AC, 0xC744},{0x30AD, 0xC745},{0x30AE, 0xC746},{0x30AF, 0xC747},{0x30B0, 0xC748},{0x30B1, 0xC749},{0x30B2, 0xC74A},{0x30B3, 0xC74B}, + {0x30B4, 0xC74C},{0x30B5, 0xC74D},{0x30B6, 0xC74E},{0x30B7, 0xC74F},{0x30B8, 0xC750},{0x30B9, 0xC751},{0x30BA, 0xC752},{0x30BB, 0xC753}, + {0x30BC, 0xC754},{0x30BD, 0xC755},{0x30BE, 0xC756},{0x30BF, 0xC757},{0x30C0, 0xC758},{0x30C1, 0xC759},{0x30C2, 0xC75A},{0x30C3, 0xC75B}, + {0x30C4, 0xC75C},{0x30C5, 0xC75D},{0x30C6, 0xC75E},{0x30C7, 0xC75F},{0x30C8, 0xC760},{0x30C9, 0xC761},{0x30CA, 0xC762},{0x30CB, 0xC763}, + {0x30CC, 0xC764},{0x30CD, 0xC765},{0x30CE, 0xC766},{0x30CF, 0xC767},{0x30D0, 0xC768},{0x30D1, 0xC769},{0x30D2, 0xC76A},{0x30D3, 0xC76B}, + {0x30D4, 0xC76C},{0x30D5, 0xC76D},{0x30D6, 0xC76E},{0x30D7, 0xC76F},{0x30D8, 0xC770},{0x30D9, 0xC771},{0x30DA, 0xC772},{0x30DB, 0xC773}, + {0x30DC, 0xC774},{0x30DD, 0xC775},{0x30DE, 0xC776},{0x30DF, 0xC777},{0x30E0, 0xC778},{0x30E1, 0xC779},{0x30E2, 0xC77A},{0x30E3, 0xC77B}, + {0x30E4, 0xC77C},{0x30E5, 0xC77D},{0x30E6, 0xC77E},{0x30E7, 0xC7A1},{0x30E8, 0xC7A2},{0x30E9, 0xC7A3},{0x30EA, 0xC7A4},{0x30EB, 0xC7A5}, + {0x30EC, 0xC7A6},{0x30ED, 0xC7A7},{0x30EE, 0xC7A8},{0x30EF, 0xC7A9},{0x30F0, 0xC7AA},{0x30F1, 0xC7AB},{0x30F2, 0xC7AC},{0x30F3, 0xC7AD}, + {0x30F4, 0xC7AE},{0x30F5, 0xC7AF},{0x30F6, 0xC7B0},{0x30FE, 0xC6A1},{0x3105, 0xA374},{0x3106, 0xA375},{0x3107, 0xA376},{0x3108, 0xA377}, + {0x3109, 0xA378},{0x310A, 0xA379},{0x310B, 0xA37A},{0x310C, 0xA37B},{0x310D, 0xA37C},{0x310E, 0xA37D},{0x310F, 0xA37E},{0x3110, 0xA3A1}, + {0x3111, 0xA3A2},{0x3112, 0xA3A3},{0x3113, 0xA3A4},{0x3114, 0xA3A5},{0x3115, 0xA3A6},{0x3116, 0xA3A7},{0x3117, 0xA3A8},{0x3118, 0xA3A9}, + {0x3119, 0xA3AA},{0x311A, 0xA3AB},{0x311B, 0xA3AC},{0x311C, 0xA3AD},{0x311D, 0xA3AE},{0x311E, 0xA3AF},{0x311F, 0xA3B0},{0x3120, 0xA3B1}, + {0x3121, 0xA3B2},{0x3122, 0xA3B3},{0x3123, 0xA3B4},{0x3124, 0xA3B5},{0x3125, 0xA3B6},{0x3126, 0xA3B7},{0x3127, 0xA3B8},{0x3128, 0xA3B9}, + {0x3129, 0xA3BA},{0x32A3, 0xA1C0},{0x338E, 0xA255},{0x338F, 0xA256},{0x339C, 0xA250},{0x339D, 0xA251},{0x339E, 0xA252},{0x33A1, 0xA254}, + {0x33C4, 0xA257},{0x33CE, 0xA253},{0x33D1, 0xA1EB},{0x33D2, 0xA1EA},{0x33D5, 0xA24F},{0x4E00, 0xA440},{0x4E01, 0xA442},{0x4E03, 0xA443}, + {0x4E07, 0xC945},{0x4E08, 0xA456},{0x4E09, 0xA454},{0x4E0A, 0xA457},{0x4E0B, 0xA455},{0x4E0C, 0xC946},{0x4E0D, 0xA4A3},{0x4E0E, 0xC94F}, + {0x4E0F, 0xC94D},{0x4E10, 0xA4A2},{0x4E11, 0xA4A1},{0x4E14, 0xA542},{0x4E15, 0xA541},{0x4E16, 0xA540},{0x4E18, 0xA543},{0x4E19, 0xA4FE}, + {0x4E1E, 0xA5E0},{0x4E1F, 0xA5E1},{0x4E26, 0xA8C3},{0x4E2B, 0xA458},{0x4E2D, 0xA4A4},{0x4E2E, 0xC950},{0x4E30, 0xA4A5},{0x4E31, 0xC963}, + {0x4E32, 0xA6EA},{0x4E33, 0xCBB1},{0x4E38, 0xA459},{0x4E39, 0xA4A6},{0x4E3B, 0xA544},{0x4E3C, 0xC964},{0x4E42, 0xC940},{0x4E43, 0xA444}, + {0x4E45, 0xA45B},{0x4E47, 0xC947},{0x4E48, 0xA45C},{0x4E4B, 0xA4A7},{0x4E4D, 0xA545},{0x4E4E, 0xA547},{0x4E4F, 0xA546},{0x4E52, 0xA5E2}, + {0x4E53, 0xA5E3},{0x4E56, 0xA8C4},{0x4E58, 0xADBC},{0x4E59, 0xA441},{0x4E5C, 0xC941},{0x4E5D, 0xA445},{0x4E5E, 0xA45E},{0x4E5F, 0xA45D}, + {0x4E69, 0xA5E4},{0x4E73, 0xA8C5},{0x4E7E, 0xB0AE},{0x4E7F, 0xD44B},{0x4E82, 0xB6C3},{0x4E83, 0xDCB1},{0x4E84, 0xDCB2},{0x4E86, 0xA446}, + {0x4E88, 0xA4A9},{0x4E8B, 0xA8C6},{0x4E8C, 0xA447},{0x4E8D, 0xC948},{0x4E8E, 0xA45F},{0x4E91, 0xA4AA},{0x4E92, 0xA4AC},{0x4E93, 0xC951}, + {0x4E94, 0xA4AD},{0x4E95, 0xA4AB},{0x4E99, 0xA5E5},{0x4E9B, 0xA8C7},{0x4E9E, 0xA8C8},{0x4E9F, 0xAB45},{0x4EA1, 0xA460},{0x4EA2, 0xA4AE}, + {0x4EA4, 0xA5E6},{0x4EA5, 0xA5E8},{0x4EA6, 0xA5E7},{0x4EA8, 0xA6EB},{0x4EAB, 0xA8C9},{0x4EAC, 0xA8CA},{0x4EAD, 0xAB46},{0x4EAE, 0xAB47}, + {0x4EB3, 0xADBD},{0x4EB6, 0xDCB3},{0x4EB9, 0xF6D6},{0x4EBA, 0xA448},{0x4EC0, 0xA4B0},{0x4EC1, 0xA4AF},{0x4EC2, 0xC952},{0x4EC3, 0xA4B1}, + {0x4EC4, 0xA4B7},{0x4EC6, 0xA4B2},{0x4EC7, 0xA4B3},{0x4EC8, 0xC954},{0x4EC9, 0xC953},{0x4ECA, 0xA4B5},{0x4ECB, 0xA4B6},{0x4ECD, 0xA4B4}, + {0x4ED4, 0xA54A},{0x4ED5, 0xA54B},{0x4ED6, 0xA54C},{0x4ED7, 0xA54D},{0x4ED8, 0xA549},{0x4ED9, 0xA550},{0x4EDA, 0xC96A},{0x4EDC, 0xC966}, + {0x4EDD, 0xC969},{0x4EDE, 0xA551},{0x4EDF, 0xA561},{0x4EE1, 0xC968},{0x4EE3, 0xA54E},{0x4EE4, 0xA54F},{0x4EE5, 0xA548},{0x4EE8, 0xC965}, + {0x4EE9, 0xC967},{0x4EF0, 0xA5F5},{0x4EF1, 0xC9B0},{0x4EF2, 0xA5F2},{0x4EF3, 0xA5F6},{0x4EF4, 0xC9BA},{0x4EF5, 0xC9AE},{0x4EF6, 0xA5F3}, + {0x4EF7, 0xC9B2},{0x4EFB, 0xA5F4},{0x4EFD, 0xA5F7},{0x4EFF, 0xA5E9},{0x4F00, 0xC9B1},{0x4F01, 0xA5F8},{0x4F02, 0xC9B5},{0x4F04, 0xC9B9}, + {0x4F05, 0xC9B6},{0x4F08, 0xC9B3},{0x4F09, 0xA5EA},{0x4F0A, 0xA5EC},{0x4F0B, 0xA5F9},{0x4F0D, 0xA5EE},{0x4F0E, 0xC9AB},{0x4F0F, 0xA5F1}, + {0x4F10, 0xA5EF},{0x4F11, 0xA5F0},{0x4F12, 0xC9BB},{0x4F13, 0xC9B8},{0x4F14, 0xC9AF},{0x4F15, 0xA5ED},{0x4F18, 0xC9AC},{0x4F19, 0xA5EB}, + {0x4F1D, 0xC9B4},{0x4F22, 0xC9B7},{0x4F2C, 0xC9AD},{0x4F2D, 0xCA66},{0x4F2F, 0xA742},{0x4F30, 0xA6F4},{0x4F33, 0xCA67},{0x4F34, 0xA6F1}, + {0x4F36, 0xA744},{0x4F38, 0xA6F9},{0x4F3A, 0xA6F8},{0x4F3B, 0xCA5B},{0x4F3C, 0xA6FC},{0x4F3D, 0xA6F7},{0x4F3E, 0xCA60},{0x4F3F, 0xCA68}, + {0x4F41, 0xCA64},{0x4F43, 0xA6FA},{0x4F46, 0xA6FD},{0x4F47, 0xA6EE},{0x4F48, 0xA747},{0x4F49, 0xCA5D},{0x4F4C, 0xCBBD},{0x4F4D, 0xA6EC}, + {0x4F4E, 0xA743},{0x4F4F, 0xA6ED},{0x4F50, 0xA6F5},{0x4F51, 0xA6F6},{0x4F52, 0xCA62},{0x4F53, 0xCA5E},{0x4F54, 0xA6FB},{0x4F55, 0xA6F3}, + {0x4F56, 0xCA5A},{0x4F57, 0xA6EF},{0x4F58, 0xCA65},{0x4F59, 0xA745},{0x4F5A, 0xA748},{0x4F5B, 0xA6F2},{0x4F5C, 0xA740},{0x4F5D, 0xA746}, + {0x4F5E, 0xA6F0},{0x4F5F, 0xCA63},{0x4F60, 0xA741},{0x4F61, 0xCA69},{0x4F62, 0xCA5C},{0x4F63, 0xA6FE},{0x4F64, 0xCA5F},{0x4F67, 0xCA61}, + {0x4F69, 0xA8D8},{0x4F6A, 0xCBBF},{0x4F6B, 0xCBCB},{0x4F6C, 0xA8D0},{0x4F6E, 0xCBCC},{0x4F6F, 0xA8CB},{0x4F70, 0xA8D5},{0x4F73, 0xA8CE}, + {0x4F74, 0xCBB9},{0x4F75, 0xA8D6},{0x4F76, 0xCBB8},{0x4F77, 0xCBBC},{0x4F78, 0xCBC3},{0x4F79, 0xCBC1},{0x4F7A, 0xA8DE},{0x4F7B, 0xA8D9}, + {0x4F7C, 0xCBB3},{0x4F7D, 0xCBB5},{0x4F7E, 0xA8DB},{0x4F7F, 0xA8CF},{0x4F80, 0xCBB6},{0x4F81, 0xCBC2},{0x4F82, 0xCBC9},{0x4F83, 0xA8D4}, + {0x4F84, 0xCBBB},{0x4F85, 0xCBB4},{0x4F86, 0xA8D3},{0x4F87, 0xCBB7},{0x4F88, 0xA8D7},{0x4F89, 0xCBBA},{0x4F8B, 0xA8D2},{0x4F8D, 0xA8CD}, + {0x4F8F, 0xA8DC},{0x4F90, 0xCBC4},{0x4F91, 0xA8DD},{0x4F92, 0xCBC8},{0x4F94, 0xCBC6},{0x4F95, 0xCBCA},{0x4F96, 0xA8DA},{0x4F97, 0xCBBE}, + {0x4F98, 0xCBB2},{0x4F9A, 0xCBC0},{0x4F9B, 0xA8D1},{0x4F9C, 0xCBC5},{0x4F9D, 0xA8CC},{0x4F9E, 0xCBC7},{0x4FAE, 0xAB56},{0x4FAF, 0xAB4A}, + {0x4FB2, 0xCDE0},{0x4FB3, 0xCDE8},{0x4FB5, 0xAB49},{0x4FB6, 0xAB51},{0x4FB7, 0xAB5D},{0x4FB9, 0xCDEE},{0x4FBA, 0xCDEC},{0x4FBB, 0xCDE7}, + {0x4FBF, 0xAB4B},{0x4FC0, 0xCDED},{0x4FC1, 0xCDE3},{0x4FC2, 0xAB59},{0x4FC3, 0xAB50},{0x4FC4, 0xAB58},{0x4FC5, 0xCDDE},{0x4FC7, 0xCDEA}, + {0x4FC9, 0xCDE1},{0x4FCA, 0xAB54},{0x4FCB, 0xCDE2},{0x4FCD, 0xCDDD},{0x4FCE, 0xAB5B},{0x4FCF, 0xAB4E},{0x4FD0, 0xAB57},{0x4FD1, 0xAB4D}, + {0x4FD3, 0xCDDF},{0x4FD4, 0xCDE4},{0x4FD6, 0xCDEB},{0x4FD7, 0xAB55},{0x4FD8, 0xAB52},{0x4FD9, 0xCDE6},{0x4FDA, 0xAB5A},{0x4FDB, 0xCDE9}, + {0x4FDC, 0xCDE5},{0x4FDD, 0xAB4F},{0x4FDE, 0xAB5C},{0x4FDF, 0xAB53},{0x4FE0, 0xAB4C},{0x4FE1, 0xAB48},{0x4FEC, 0xCDEF},{0x4FEE, 0xADD7}, + {0x4FEF, 0xADC1},{0x4FF1, 0xADD1},{0x4FF3, 0xADD6},{0x4FF4, 0xD0D0},{0x4FF5, 0xD0CF},{0x4FF6, 0xD0D4},{0x4FF7, 0xD0D5},{0x4FF8, 0xADC4}, + {0x4FFA, 0xADCD},{0x4FFE, 0xADDA},{0x5000, 0xADCE},{0x5005, 0xD0C9},{0x5006, 0xADC7},{0x5007, 0xD0CA},{0x5009, 0xADDC},{0x500B, 0xADD3}, + {0x500C, 0xADBE},{0x500D, 0xADBF},{0x500E, 0xD0DD},{0x500F, 0xB0BF},{0x5011, 0xADCC},{0x5012, 0xADCB},{0x5013, 0xD0CB},{0x5014, 0xADCF}, + {0x5015, 0xD45B},{0x5016, 0xADC6},{0x5017, 0xD0D6},{0x5018, 0xADD5},{0x5019, 0xADD4},{0x501A, 0xADCA},{0x501B, 0xD0CE},{0x501C, 0xD0D7}, + {0x501E, 0xD0C8},{0x501F, 0xADC9},{0x5020, 0xD0D8},{0x5021, 0xADD2},{0x5022, 0xD0CC},{0x5023, 0xADC0},{0x5025, 0xADC3},{0x5026, 0xADC2}, + {0x5027, 0xD0D9},{0x5028, 0xADD0},{0x5029, 0xADC5},{0x502A, 0xADD9},{0x502B, 0xADDB},{0x502C, 0xD0D3},{0x502D, 0xADD8},{0x502F, 0xD0DB}, + {0x5030, 0xD0CD},{0x5031, 0xD0DC},{0x5033, 0xD0D1},{0x5035, 0xD0DA},{0x5037, 0xD0D2},{0x503C, 0xADC8},{0x5040, 0xD463},{0x5041, 0xD457}, + {0x5043, 0xB0B3},{0x5045, 0xD45C},{0x5046, 0xD462},{0x5047, 0xB0B2},{0x5048, 0xD455},{0x5049, 0xB0B6},{0x504A, 0xD459},{0x504B, 0xD452}, + {0x504C, 0xB0B4},{0x504D, 0xD456},{0x504E, 0xB0B9},{0x504F, 0xB0BE},{0x5051, 0xD467},{0x5053, 0xD451},{0x5055, 0xB0BA},{0x5057, 0xD466}, + {0x505A, 0xB0B5},{0x505B, 0xD458},{0x505C, 0xB0B1},{0x505D, 0xD453},{0x505E, 0xD44F},{0x505F, 0xD45D},{0x5060, 0xD450},{0x5061, 0xD44E}, + {0x5062, 0xD45A},{0x5063, 0xD460},{0x5064, 0xD461},{0x5065, 0xB0B7},{0x5068, 0xD85B},{0x5069, 0xD45E},{0x506A, 0xD44D},{0x506B, 0xD45F}, + {0x506D, 0xB0C1},{0x506E, 0xD464},{0x506F, 0xB0C0},{0x5070, 0xD44C},{0x5072, 0xD454},{0x5073, 0xD465},{0x5074, 0xB0BC},{0x5075, 0xB0BB}, + {0x5076, 0xB0B8},{0x5077, 0xB0BD},{0x507A, 0xB0AF},{0x507D, 0xB0B0},{0x5080, 0xB3C8},{0x5082, 0xD85E},{0x5083, 0xD857},{0x5085, 0xB3C5}, + {0x5087, 0xD85F},{0x508B, 0xD855},{0x508C, 0xD858},{0x508D, 0xB3C4},{0x508E, 0xD859},{0x5091, 0xB3C7},{0x5092, 0xD85D},{0x5094, 0xD853}, + {0x5095, 0xD852},{0x5096, 0xB3C9},{0x5098, 0xB3CA},{0x5099, 0xB3C6},{0x509A, 0xB3CB},{0x509B, 0xD851},{0x509C, 0xD85C},{0x509D, 0xD85A}, + {0x509E, 0xD854},{0x50A2, 0xB3C3},{0x50A3, 0xD856},{0x50AC, 0xB6CA},{0x50AD, 0xB6C4},{0x50AE, 0xDCB7},{0x50AF, 0xB6CD},{0x50B0, 0xDCBD}, + {0x50B1, 0xDCC0},{0x50B2, 0xB6C6},{0x50B3, 0xB6C7},{0x50B4, 0xDCBA},{0x50B5, 0xB6C5},{0x50B6, 0xDCC3},{0x50B7, 0xB6CB},{0x50B8, 0xDCC4}, + {0x50BA, 0xDCBF},{0x50BB, 0xB6CC},{0x50BD, 0xDCB4},{0x50BE, 0xB6C9},{0x50BF, 0xDCB5},{0x50C1, 0xDCBE},{0x50C2, 0xDCBC},{0x50C4, 0xDCB8}, + {0x50C5, 0xB6C8},{0x50C6, 0xDCB6},{0x50C7, 0xB6CE},{0x50C8, 0xDCBB},{0x50C9, 0xDCC2},{0x50CA, 0xDCB9},{0x50CB, 0xDCC1},{0x50CE, 0xB9B6}, + {0x50CF, 0xB9B3},{0x50D1, 0xB9B4},{0x50D3, 0xE0F9},{0x50D4, 0xE0F1},{0x50D5, 0xB9B2},{0x50D6, 0xB9AF},{0x50D7, 0xE0F2},{0x50DA, 0xB9B1}, + {0x50DB, 0xE0F5},{0x50DD, 0xE0F7},{0x50E0, 0xE0FE},{0x50E3, 0xE0FD},{0x50E4, 0xE0F8},{0x50E5, 0xB9AE},{0x50E6, 0xE0F0},{0x50E7, 0xB9AC}, + {0x50E8, 0xE0F3},{0x50E9, 0xB9B7},{0x50EA, 0xE0F6},{0x50EC, 0xE0FA},{0x50ED, 0xB9B0},{0x50EE, 0xB9AD},{0x50EF, 0xE0FC},{0x50F0, 0xE0FB}, + {0x50F1, 0xB9B5},{0x50F3, 0xE0F4},{0x50F5, 0xBBF8},{0x50F6, 0xE4EC},{0x50F8, 0xE4E9},{0x50F9, 0xBBF9},{0x50FB, 0xBBF7},{0x50FD, 0xE4F0}, + {0x50FE, 0xE4ED},{0x50FF, 0xE4E6},{0x5100, 0xBBF6},{0x5102, 0xBBFA},{0x5103, 0xE4E7},{0x5104, 0xBBF5},{0x5105, 0xBBFD},{0x5106, 0xE4EA}, + {0x5107, 0xE4EB},{0x5108, 0xBBFB},{0x5109, 0xBBFC},{0x510A, 0xE4F1},{0x510B, 0xE4EE},{0x510C, 0xE4EF},{0x5110, 0xBEAA},{0x5111, 0xE8F8}, + {0x5112, 0xBEA7},{0x5113, 0xE8F5},{0x5114, 0xBEA9},{0x5115, 0xBEAB},{0x5117, 0xE8F6},{0x5118, 0xBEA8},{0x511A, 0xE8F7},{0x511C, 0xE8F4}, + {0x511F, 0xC076},{0x5120, 0xECBD},{0x5121, 0xC077},{0x5122, 0xECBB},{0x5124, 0xECBC},{0x5125, 0xECBA},{0x5126, 0xECB9},{0x5129, 0xECBE}, + {0x512A, 0xC075},{0x512D, 0xEFB8},{0x512E, 0xEFB9},{0x5130, 0xE4E8},{0x5131, 0xEFB7},{0x5132, 0xC078},{0x5133, 0xC35F},{0x5134, 0xF1EB}, + {0x5135, 0xF1EC},{0x5137, 0xC4D7},{0x5138, 0xC4D8},{0x5139, 0xF5C1},{0x513A, 0xF5C0},{0x513B, 0xC56C},{0x513C, 0xC56B},{0x513D, 0xF7D0}, + {0x513F, 0xA449},{0x5140, 0xA461},{0x5141, 0xA4B9},{0x5143, 0xA4B8},{0x5144, 0xA553},{0x5145, 0xA552},{0x5146, 0xA5FC},{0x5147, 0xA5FB}, + {0x5148, 0xA5FD},{0x5149, 0xA5FA},{0x514B, 0xA74A},{0x514C, 0xA749},{0x514D, 0xA74B},{0x5152, 0xA8E0},{0x5154, 0xA8DF},{0x5155, 0xA8E1}, + {0x5157, 0xAB5E},{0x5159, 0xA259},{0x515A, 0xD0DE},{0x515B, 0xA25A},{0x515C, 0xB0C2},{0x515D, 0xA25C},{0x515E, 0xA25B},{0x515F, 0xD860}, + {0x5161, 0xA25D},{0x5162, 0xB9B8},{0x5163, 0xA25E},{0x5165, 0xA44A},{0x5167, 0xA4BA},{0x5168, 0xA5FE},{0x5169, 0xA8E2},{0x516B, 0xA44B}, + {0x516C, 0xA4BD},{0x516D, 0xA4BB},{0x516E, 0xA4BC},{0x5171, 0xA640},{0x5175, 0xA74C},{0x5176, 0xA8E4},{0x5177, 0xA8E3},{0x5178, 0xA8E5}, + {0x517C, 0xADDD},{0x5180, 0xBEAC},{0x5187, 0xC94E},{0x5189, 0xA554},{0x518A, 0xA555},{0x518D, 0xA641},{0x518F, 0xCA6A},{0x5191, 0xAB60}, + {0x5192, 0xAB5F},{0x5193, 0xD0E0},{0x5194, 0xD0DF},{0x5195, 0xB0C3},{0x5197, 0xA4BE},{0x5198, 0xC955},{0x519E, 0xCBCD},{0x51A0, 0xAB61}, + {0x51A2, 0xADE0},{0x51A4, 0xADDE},{0x51A5, 0xADDF},{0x51AA, 0xBEAD},{0x51AC, 0xA556},{0x51B0, 0xA642},{0x51B1, 0xC9BC},{0x51B6, 0xA74D}, + {0x51B7, 0xA74E},{0x51B9, 0xCA6B},{0x51BC, 0xCBCE},{0x51BD, 0xA8E6},{0x51BE, 0xCBCF},{0x51C4, 0xD0E2},{0x51C5, 0xD0E3},{0x51C6, 0xADE3}, + {0x51C8, 0xD0E4},{0x51CA, 0xD0E1},{0x51CB, 0xADE4},{0x51CC, 0xADE2},{0x51CD, 0xADE1},{0x51CE, 0xD0E5},{0x51D0, 0xD468},{0x51D4, 0xD861}, + {0x51D7, 0xDCC5},{0x51D8, 0xE140},{0x51DC, 0xBBFE},{0x51DD, 0xBEAE},{0x51DE, 0xE8F9},{0x51E0, 0xA44C},{0x51E1, 0xA45A},{0x51F0, 0xB0C4}, + {0x51F1, 0xB3CD},{0x51F3, 0xB9B9},{0x51F5, 0xC942},{0x51F6, 0xA4BF},{0x51F8, 0xA559},{0x51F9, 0xA557},{0x51FA, 0xA558},{0x51FD, 0xA8E7}, + {0x5200, 0xA44D},{0x5201, 0xA44E},{0x5203, 0xA462},{0x5206, 0xA4C0},{0x5207, 0xA4C1},{0x5208, 0xA4C2},{0x5209, 0xC9BE},{0x520A, 0xA55A}, + {0x520C, 0xC96B},{0x520E, 0xA646},{0x5210, 0xC9BF},{0x5211, 0xA644},{0x5212, 0xA645},{0x5213, 0xC9BD},{0x5216, 0xA647},{0x5217, 0xA643}, + {0x521C, 0xCA6C},{0x521D, 0xAAEC},{0x521E, 0xCA6D},{0x5221, 0xCA6E},{0x5224, 0xA750},{0x5225, 0xA74F},{0x5228, 0xA753},{0x5229, 0xA751}, + {0x522A, 0xA752},{0x522E, 0xA8ED},{0x5230, 0xA8EC},{0x5231, 0xCBD4},{0x5232, 0xCBD1},{0x5233, 0xCBD2},{0x5235, 0xCBD0},{0x5236, 0xA8EE}, + {0x5237, 0xA8EA},{0x5238, 0xA8E9},{0x523A, 0xA8EB},{0x523B, 0xA8E8},{0x5241, 0xA8EF},{0x5243, 0xAB63},{0x5244, 0xCDF0},{0x5246, 0xCBD3}, + {0x5247, 0xAB68},{0x5249, 0xCDF1},{0x524A, 0xAB64},{0x524B, 0xAB67},{0x524C, 0xAB66},{0x524D, 0xAB65},{0x524E, 0xAB62},{0x5252, 0xD0E8}, + {0x5254, 0xADE7},{0x5255, 0xD0EB},{0x5256, 0xADE5},{0x525A, 0xD0E7},{0x525B, 0xADE8},{0x525C, 0xADE6},{0x525D, 0xADE9},{0x525E, 0xD0E9}, + {0x525F, 0xD0EA},{0x5261, 0xD0E6},{0x5262, 0xD0EC},{0x5269, 0xB3D1},{0x526A, 0xB0C5},{0x526B, 0xD469},{0x526C, 0xD46B},{0x526D, 0xD46A}, + {0x526E, 0xD46C},{0x526F, 0xB0C6},{0x5272, 0xB3CE},{0x5274, 0xB3CF},{0x5275, 0xB3D0},{0x5277, 0xB6D0},{0x5278, 0xDCC7},{0x527A, 0xDCC6}, + {0x527B, 0xDCC8},{0x527C, 0xDCC9},{0x527D, 0xB6D1},{0x527F, 0xB6CF},{0x5280, 0xE141},{0x5281, 0xE142},{0x5282, 0xB9BB},{0x5283, 0xB9BA}, + {0x5284, 0xE35A},{0x5287, 0xBC40},{0x5288, 0xBC41},{0x5289, 0xBC42},{0x528A, 0xBC44},{0x528B, 0xE4F2},{0x528C, 0xE4F3},{0x528D, 0xBC43}, + {0x5291, 0xBEAF},{0x5293, 0xBEB0},{0x5296, 0xF1ED},{0x5297, 0xF5C3},{0x5298, 0xF5C2},{0x5299, 0xF7D1},{0x529B, 0xA44F},{0x529F, 0xA55C}, + {0x52A0, 0xA55B},{0x52A3, 0xA648},{0x52A6, 0xC9C0},{0x52A9, 0xA755},{0x52AA, 0xA756},{0x52AB, 0xA754},{0x52AC, 0xA757},{0x52AD, 0xCA6F}, + {0x52AE, 0xCA70},{0x52BB, 0xA8F1},{0x52BC, 0xCBD5},{0x52BE, 0xA8F0},{0x52C0, 0xCDF2},{0x52C1, 0xAB6C},{0x52C2, 0xCDF3},{0x52C3, 0xAB6B}, + {0x52C7, 0xAB69},{0x52C9, 0xAB6A},{0x52CD, 0xD0ED},{0x52D2, 0xB0C7},{0x52D3, 0xD46E},{0x52D5, 0xB0CA},{0x52D6, 0xD46D},{0x52D7, 0xB1E5}, + {0x52D8, 0xB0C9},{0x52D9, 0xB0C8},{0x52DB, 0xB3D4},{0x52DD, 0xB3D3},{0x52DE, 0xB3D2},{0x52DF, 0xB6D2},{0x52E2, 0xB6D5},{0x52E3, 0xB6D6}, + {0x52E4, 0xB6D4},{0x52E6, 0xB6D3},{0x52E9, 0xE143},{0x52EB, 0xE144},{0x52EF, 0xE4F5},{0x52F0, 0xBC45},{0x52F1, 0xE4F4},{0x52F3, 0xBEB1}, + {0x52F4, 0xECBF},{0x52F5, 0xC079},{0x52F7, 0xF1EE},{0x52F8, 0xC455},{0x52FA, 0xA463},{0x52FB, 0xA4C3},{0x52FC, 0xC956},{0x52FE, 0xA4C4}, + {0x52FF, 0xA4C5},{0x5305, 0xA55D},{0x5306, 0xA55E},{0x5308, 0xA649},{0x5309, 0xCA71},{0x530A, 0xCBD6},{0x530B, 0xCBD7},{0x530D, 0xAB6D}, + {0x530E, 0xD0EE},{0x530F, 0xB0CC},{0x5310, 0xB0CB},{0x5311, 0xD863},{0x5312, 0xD862},{0x5315, 0xA450},{0x5316, 0xA4C6},{0x5317, 0xA55F}, + {0x5319, 0xB0CD},{0x531A, 0xC943},{0x531C, 0xC96C},{0x531D, 0xA560},{0x531F, 0xC9C2},{0x5320, 0xA64B},{0x5321, 0xA64A},{0x5322, 0xC9C1}, + {0x5323, 0xA758},{0x532A, 0xADEA},{0x532D, 0xD46F},{0x532F, 0xB6D7},{0x5330, 0xE145},{0x5331, 0xB9BC},{0x5334, 0xE8FA},{0x5337, 0xF3FD}, + {0x5339, 0xA4C7},{0x533C, 0xCBD8},{0x533D, 0xCDF4},{0x533E, 0xB0D0},{0x533F, 0xB0CE},{0x5340, 0xB0CF},{0x5341, 0xA451},{0x5343, 0xA464}, + {0x5344, 0xA2CD},{0x5345, 0xA4CA},{0x5347, 0xA4C9},{0x5348, 0xA4C8},{0x5349, 0xA563},{0x534A, 0xA562},{0x534C, 0xC96D},{0x534D, 0xC9C3}, + {0x5351, 0xA8F5},{0x5352, 0xA8F2},{0x5353, 0xA8F4},{0x5354, 0xA8F3},{0x5357, 0xAB6E},{0x535A, 0xB3D5},{0x535C, 0xA452},{0x535E, 0xA4CB}, + {0x5360, 0xA565},{0x5361, 0xA564},{0x5363, 0xCA72},{0x5366, 0xA8F6},{0x536C, 0xC957},{0x536E, 0xA567},{0x536F, 0xA566},{0x5370, 0xA64C}, + {0x5371, 0xA64D},{0x5372, 0xCA73},{0x5373, 0xA759},{0x5375, 0xA75A},{0x5377, 0xA8F7},{0x5378, 0xA8F8},{0x5379, 0xA8F9},{0x537B, 0xAB6F}, + {0x537C, 0xCDF5},{0x537F, 0xADEB},{0x5382, 0xC944},{0x5384, 0xA4CC},{0x538A, 0xC9C4},{0x538E, 0xCA74},{0x538F, 0xCA75},{0x5392, 0xCBD9}, + {0x5394, 0xCBDA},{0x5396, 0xCDF7},{0x5397, 0xCDF6},{0x5398, 0xCDF9},{0x5399, 0xCDF8},{0x539A, 0xAB70},{0x539C, 0xD470},{0x539D, 0xADED}, + {0x539E, 0xD0EF},{0x539F, 0xADEC},{0x53A4, 0xD864},{0x53A5, 0xB3D6},{0x53A7, 0xD865},{0x53AC, 0xE146},{0x53AD, 0xB9BD},{0x53B2, 0xBC46}, + {0x53B4, 0xF1EF},{0x53B9, 0xC958},{0x53BB, 0xA568},{0x53C3, 0xB0D1},{0x53C8, 0xA453},{0x53C9, 0xA465},{0x53CA, 0xA4CE},{0x53CB, 0xA4CD}, + {0x53CD, 0xA4CF},{0x53D4, 0xA8FB},{0x53D6, 0xA8FA},{0x53D7, 0xA8FC},{0x53DB, 0xAB71},{0x53DF, 0xADEE},{0x53E1, 0xE8FB},{0x53E2, 0xC24F}, + {0x53E3, 0xA466},{0x53E4, 0xA56A},{0x53E5, 0xA579},{0x53E6, 0xA574},{0x53E8, 0xA56F},{0x53E9, 0xA56E},{0x53EA, 0xA575},{0x53EB, 0xA573}, + {0x53EC, 0xA56C},{0x53ED, 0xA57A},{0x53EE, 0xA56D},{0x53EF, 0xA569},{0x53F0, 0xA578},{0x53F1, 0xA577},{0x53F2, 0xA576},{0x53F3, 0xA56B}, + {0x53F5, 0xA572},{0x53F8, 0xA571},{0x53FB, 0xA57B},{0x53FC, 0xA570},{0x5401, 0xA653},{0x5403, 0xA659},{0x5404, 0xA655},{0x5406, 0xA65B}, + {0x5407, 0xC9C5},{0x5408, 0xA658},{0x5409, 0xA64E},{0x540A, 0xA651},{0x540B, 0xA654},{0x540C, 0xA650},{0x540D, 0xA657},{0x540E, 0xA65A}, + {0x540F, 0xA64F},{0x5410, 0xA652},{0x5411, 0xA656},{0x5412, 0xA65C},{0x5418, 0xCA7E},{0x5419, 0xCA7B},{0x541B, 0xA767},{0x541C, 0xCA7C}, + {0x541D, 0xA75B},{0x541E, 0xA75D},{0x541F, 0xA775},{0x5420, 0xA770},{0x5424, 0xCAA5},{0x5425, 0xCA7D},{0x5426, 0xA75F},{0x5427, 0xA761}, + {0x5428, 0xCAA4},{0x5429, 0xA768},{0x542A, 0xCA78},{0x542B, 0xA774},{0x542C, 0xA776},{0x542D, 0xA75C},{0x542E, 0xA76D},{0x5430, 0xCA76}, + {0x5431, 0xA773},{0x5433, 0xA764},{0x5435, 0xA76E},{0x5436, 0xA76F},{0x5437, 0xCA77},{0x5438, 0xA76C},{0x5439, 0xA76A},{0x543B, 0xA76B}, + {0x543C, 0xA771},{0x543D, 0xCAA1},{0x543E, 0xA75E},{0x5440, 0xA772},{0x5441, 0xCAA3},{0x5442, 0xA766},{0x5443, 0xA763},{0x5445, 0xCA7A}, + {0x5446, 0xA762},{0x5447, 0xCAA6},{0x5448, 0xA765},{0x544A, 0xA769},{0x544E, 0xA760},{0x544F, 0xCAA2},{0x5454, 0xCA79},{0x5460, 0xCBEB}, + {0x5461, 0xCBEA},{0x5462, 0xA94F},{0x5463, 0xCBED},{0x5464, 0xCBEF},{0x5465, 0xCBE4},{0x5466, 0xCBE7},{0x5467, 0xCBEE},{0x5468, 0xA950}, + {0x546B, 0xCBE1},{0x546C, 0xCBE5},{0x546F, 0xCBE9},{0x5470, 0xCE49},{0x5471, 0xA94B},{0x5472, 0xCE4D},{0x5473, 0xA8FD},{0x5474, 0xCBE6}, + {0x5475, 0xA8FE},{0x5476, 0xA94C},{0x5477, 0xA945},{0x5478, 0xA941},{0x547A, 0xCBE2},{0x547B, 0xA944},{0x547C, 0xA949},{0x547D, 0xA952}, + {0x547E, 0xCBE3},{0x547F, 0xCBDC},{0x5480, 0xA943},{0x5481, 0xCBDD},{0x5482, 0xCBDF},{0x5484, 0xA946},{0x5486, 0xA948},{0x5487, 0xCBDB}, + {0x5488, 0xCBE0},{0x548B, 0xA951},{0x548C, 0xA94D},{0x548D, 0xCBE8},{0x548E, 0xA953},{0x5490, 0xA94A},{0x5491, 0xCBDE},{0x5492, 0xA947}, + {0x5495, 0xA942},{0x5496, 0xA940},{0x5498, 0xCBEC},{0x549A, 0xA94E},{0x54A0, 0xCE48},{0x54A1, 0xCDFB},{0x54A2, 0xCE4B},{0x54A5, 0xCDFD}, + {0x54A6, 0xAB78},{0x54A7, 0xABA8},{0x54A8, 0xAB74},{0x54A9, 0xABA7},{0x54AA, 0xAB7D},{0x54AB, 0xABA4},{0x54AC, 0xAB72},{0x54AD, 0xCDFC}, + {0x54AE, 0xCE43},{0x54AF, 0xABA3},{0x54B0, 0xCE4F},{0x54B1, 0xABA5},{0x54B3, 0xAB79},{0x54B6, 0xCE45},{0x54B7, 0xCE42},{0x54B8, 0xAB77}, + {0x54BA, 0xCDFA},{0x54BB, 0xABA6},{0x54BC, 0xCE4A},{0x54BD, 0xAB7C},{0x54BE, 0xCE4C},{0x54BF, 0xABA9},{0x54C0, 0xAB73},{0x54C1, 0xAB7E}, + {0x54C2, 0xAB7B},{0x54C3, 0xCE40},{0x54C4, 0xABA1},{0x54C5, 0xCE46},{0x54C6, 0xCE47},{0x54C7, 0xAB7A},{0x54C8, 0xABA2},{0x54C9, 0xAB76}, + {0x54CE, 0xAB75},{0x54CF, 0xCDFE},{0x54D6, 0xCE44},{0x54DE, 0xCE4E},{0x54E0, 0xD144},{0x54E1, 0xADFB},{0x54E2, 0xD0F1},{0x54E4, 0xD0F6}, + {0x54E5, 0xADF4},{0x54E6, 0xAE40},{0x54E7, 0xD0F4},{0x54E8, 0xADEF},{0x54E9, 0xADF9},{0x54EA, 0xADFE},{0x54EB, 0xD0FB},{0x54ED, 0xADFA}, + {0x54EE, 0xADFD},{0x54F1, 0xD0FE},{0x54F2, 0xADF5},{0x54F3, 0xD0F5},{0x54F7, 0xD142},{0x54F8, 0xD143},{0x54FA, 0xADF7},{0x54FB, 0xD141}, + {0x54FC, 0xADF3},{0x54FD, 0xAE43},{0x54FF, 0xD0F8},{0x5501, 0xADF1},{0x5503, 0xD146},{0x5504, 0xD0F9},{0x5505, 0xD0FD},{0x5506, 0xADF6}, + {0x5507, 0xAE42},{0x5508, 0xD0FA},{0x5509, 0xADFC},{0x550A, 0xD140},{0x550B, 0xD147},{0x550C, 0xD4A1},{0x550E, 0xD145},{0x550F, 0xAE44}, + {0x5510, 0xADF0},{0x5511, 0xD0FC},{0x5512, 0xD0F3},{0x5514, 0xADF8},{0x5517, 0xD0F2},{0x551A, 0xD0F7},{0x5526, 0xD0F0},{0x5527, 0xAE41}, + {0x552A, 0xD477},{0x552C, 0xB0E4},{0x552D, 0xD4A7},{0x552E, 0xB0E2},{0x552F, 0xB0DF},{0x5530, 0xD47C},{0x5531, 0xB0DB},{0x5532, 0xD4A2}, + {0x5533, 0xB0E6},{0x5534, 0xD476},{0x5535, 0xD47B},{0x5536, 0xD47A},{0x5537, 0xADF2},{0x5538, 0xB0E1},{0x5539, 0xD4A5},{0x553B, 0xD4A8}, + {0x553C, 0xD473},{0x553E, 0xB3E8},{0x5540, 0xD4A9},{0x5541, 0xB0E7},{0x5543, 0xB0D9},{0x5544, 0xB0D6},{0x5545, 0xD47E},{0x5546, 0xB0D3}, + {0x5548, 0xD4A6},{0x554A, 0xB0DA},{0x554B, 0xD4AA},{0x554D, 0xD474},{0x554E, 0xD4A4},{0x554F, 0xB0DD},{0x5550, 0xD475},{0x5551, 0xD478}, + {0x5552, 0xD47D},{0x5555, 0xB0DE},{0x5556, 0xB0DC},{0x5557, 0xB0E8},{0x555C, 0xB0E3},{0x555E, 0xB0D7},{0x555F, 0xB1D2},{0x5561, 0xB0D8}, + {0x5562, 0xD479},{0x5563, 0xB0E5},{0x5564, 0xB0E0},{0x5565, 0xD4A3},{0x5566, 0xB0D5},{0x556A, 0xB0D4},{0x5575, 0xD471},{0x5576, 0xD472}, + {0x5577, 0xD86A},{0x557B, 0xB3D7},{0x557C, 0xB3DA},{0x557D, 0xD875},{0x557E, 0xB3EE},{0x557F, 0xD878},{0x5580, 0xB3D8},{0x5581, 0xD871}, + {0x5582, 0xB3DE},{0x5583, 0xB3E4},{0x5584, 0xB5BD},{0x5587, 0xB3E2},{0x5588, 0xD86E},{0x5589, 0xB3EF},{0x558A, 0xB3DB},{0x558B, 0xB3E3}, + {0x558C, 0xD876},{0x558D, 0xDCD7},{0x558E, 0xD87B},{0x558F, 0xD86F},{0x5591, 0xD866},{0x5592, 0xD873},{0x5593, 0xD86D},{0x5594, 0xB3E1}, + {0x5595, 0xD879},{0x5598, 0xB3DD},{0x5599, 0xB3F1},{0x559A, 0xB3EA},{0x559C, 0xB3DF},{0x559D, 0xB3DC},{0x559F, 0xB3E7},{0x55A1, 0xD87A}, + {0x55A2, 0xD86C},{0x55A3, 0xD872},{0x55A4, 0xD874},{0x55A5, 0xD868},{0x55A6, 0xD877},{0x55A7, 0xB3D9},{0x55A8, 0xD867},{0x55AA, 0xB3E0}, + {0x55AB, 0xB3F0},{0x55AC, 0xB3EC},{0x55AD, 0xD869},{0x55AE, 0xB3E6},{0x55B1, 0xB3ED},{0x55B2, 0xB3E9},{0x55B3, 0xB3E5},{0x55B5, 0xD870}, + {0x55BB, 0xB3EB},{0x55BF, 0xDCD5},{0x55C0, 0xDCD1},{0x55C2, 0xDCE0},{0x55C3, 0xDCCA},{0x55C4, 0xDCD3},{0x55C5, 0xB6E5},{0x55C6, 0xB6E6}, + {0x55C7, 0xB6DE},{0x55C8, 0xDCDC},{0x55C9, 0xB6E8},{0x55CA, 0xDCCF},{0x55CB, 0xDCCE},{0x55CC, 0xDCCC},{0x55CD, 0xDCDE},{0x55CE, 0xB6DC}, + {0x55CF, 0xDCD8},{0x55D0, 0xDCCD},{0x55D1, 0xB6DF},{0x55D2, 0xDCD6},{0x55D3, 0xB6DA},{0x55D4, 0xDCD2},{0x55D5, 0xDCD9},{0x55D6, 0xDCDB}, + {0x55D9, 0xDCDF},{0x55DA, 0xB6E3},{0x55DB, 0xDCCB},{0x55DC, 0xB6DD},{0x55DD, 0xDCD0},{0x55DF, 0xB6D8},{0x55E1, 0xB6E4},{0x55E2, 0xDCDA}, + {0x55E3, 0xB6E0},{0x55E4, 0xB6E1},{0x55E5, 0xB6E7},{0x55E6, 0xB6DB},{0x55E7, 0xA25F},{0x55E8, 0xB6D9},{0x55E9, 0xDCD4},{0x55EF, 0xB6E2}, + {0x55F2, 0xDCDD},{0x55F6, 0xB9CD},{0x55F7, 0xB9C8},{0x55F9, 0xE155},{0x55FA, 0xE151},{0x55FC, 0xE14B},{0x55FD, 0xB9C2},{0x55FE, 0xB9BE}, + {0x55FF, 0xE154},{0x5600, 0xB9BF},{0x5601, 0xE14E},{0x5602, 0xE150},{0x5604, 0xE153},{0x5606, 0xB9C4},{0x5608, 0xB9CB},{0x5609, 0xB9C5}, + {0x560C, 0xE149},{0x560D, 0xB9C6},{0x560E, 0xB9C7},{0x560F, 0xE14C},{0x5610, 0xB9CC},{0x5612, 0xE14A},{0x5613, 0xE14F},{0x5614, 0xB9C3}, + {0x5615, 0xE148},{0x5616, 0xB9C9},{0x5617, 0xB9C1},{0x561B, 0xB9C0},{0x561C, 0xE14D},{0x561D, 0xE152},{0x561F, 0xB9CA},{0x5627, 0xE147}, + {0x5629, 0xBC4D},{0x562A, 0xE547},{0x562C, 0xE544},{0x562E, 0xBC47},{0x562F, 0xBC53},{0x5630, 0xBC54},{0x5632, 0xBC4A},{0x5633, 0xE542}, + {0x5634, 0xBC4C},{0x5635, 0xE4F9},{0x5636, 0xBC52},{0x5638, 0xE546},{0x5639, 0xBC49},{0x563A, 0xE548},{0x563B, 0xBC48},{0x563D, 0xE543}, + {0x563E, 0xE545},{0x563F, 0xBC4B},{0x5640, 0xE541},{0x5641, 0xE4FA},{0x5642, 0xE4F7},{0x5645, 0xD86B},{0x5646, 0xE4FD},{0x5648, 0xE4F6}, + {0x5649, 0xE4FC},{0x564A, 0xE4FB},{0x564C, 0xE4F8},{0x564E, 0xBC4F},{0x5653, 0xBC4E},{0x5657, 0xBC50},{0x5658, 0xE4FE},{0x5659, 0xBEB2}, + {0x565A, 0xE540},{0x565E, 0xE945},{0x5660, 0xE8FD},{0x5662, 0xBEBE},{0x5663, 0xE942},{0x5664, 0xBEB6},{0x5665, 0xBEBA},{0x5666, 0xE941}, + {0x5668, 0xBEB9},{0x5669, 0xBEB5},{0x566A, 0xBEB8},{0x566B, 0xBEB3},{0x566C, 0xBEBD},{0x566D, 0xE943},{0x566E, 0xE8FE},{0x566F, 0xBEBC}, + {0x5670, 0xE8FC},{0x5671, 0xBEBB},{0x5672, 0xE944},{0x5673, 0xE940},{0x5674, 0xBC51},{0x5676, 0xBEBF},{0x5677, 0xE946},{0x5678, 0xBEB7}, + {0x5679, 0xBEB4},{0x567E, 0xECC6},{0x567F, 0xECC8},{0x5680, 0xC07B},{0x5681, 0xECC9},{0x5682, 0xECC7},{0x5683, 0xECC5},{0x5684, 0xECC4}, + {0x5685, 0xC07D},{0x5686, 0xECC3},{0x5687, 0xC07E},{0x568C, 0xECC1},{0x568D, 0xECC2},{0x568E, 0xC07A},{0x568F, 0xC0A1},{0x5690, 0xC07C}, + {0x5693, 0xECC0},{0x5695, 0xC250},{0x5697, 0xEFBC},{0x5698, 0xEFBA},{0x5699, 0xEFBF},{0x569A, 0xEFBD},{0x569C, 0xEFBB},{0x569D, 0xEFBE}, + {0x56A5, 0xC360},{0x56A6, 0xF1F2},{0x56A7, 0xF1F3},{0x56A8, 0xC456},{0x56AA, 0xF1F4},{0x56AB, 0xF1F0},{0x56AC, 0xF1F5},{0x56AD, 0xF1F1}, + {0x56AE, 0xC251},{0x56B2, 0xF3FE},{0x56B3, 0xF441},{0x56B4, 0xC459},{0x56B5, 0xF440},{0x56B6, 0xC458},{0x56B7, 0xC457},{0x56BC, 0xC45A}, + {0x56BD, 0xF5C5},{0x56BE, 0xF5C6},{0x56C0, 0xC4DA},{0x56C1, 0xC4D9},{0x56C2, 0xC4DB},{0x56C3, 0xF5C4},{0x56C5, 0xF6D8},{0x56C6, 0xF6D7}, + {0x56C8, 0xC56D},{0x56C9, 0xC56F},{0x56CA, 0xC56E},{0x56CB, 0xF6D9},{0x56CC, 0xC5C8},{0x56CD, 0xF8A6},{0x56D1, 0xC5F1},{0x56D3, 0xF8A5}, + {0x56D4, 0xF8EE},{0x56D7, 0xC949},{0x56DA, 0xA57D},{0x56DB, 0xA57C},{0x56DD, 0xA65F},{0x56DE, 0xA65E},{0x56DF, 0xC9C7},{0x56E0, 0xA65D}, + {0x56E1, 0xC9C6},{0x56E4, 0xA779},{0x56E5, 0xCAA9},{0x56E7, 0xCAA8},{0x56EA, 0xA777},{0x56EB, 0xA77A},{0x56EE, 0xCAA7},{0x56F0, 0xA778}, + {0x56F7, 0xCBF0},{0x56F9, 0xCBF1},{0x56FA, 0xA954},{0x56FF, 0xABAA},{0x5701, 0xD148},{0x5702, 0xD149},{0x5703, 0xAE45},{0x5704, 0xAE46}, + {0x5707, 0xD4AC},{0x5708, 0xB0E9},{0x5709, 0xB0EB},{0x570A, 0xD4AB},{0x570B, 0xB0EA},{0x570C, 0xD87C},{0x570D, 0xB3F2},{0x5712, 0xB6E9}, + {0x5713, 0xB6EA},{0x5714, 0xDCE1},{0x5716, 0xB9CF},{0x5718, 0xB9CE},{0x571A, 0xE549},{0x571B, 0xE948},{0x571C, 0xE947},{0x571E, 0xF96B}, + {0x571F, 0xA467},{0x5720, 0xC959},{0x5722, 0xC96E},{0x5723, 0xC96F},{0x5728, 0xA662},{0x5729, 0xA666},{0x572A, 0xC9C9},{0x572C, 0xA664}, + {0x572D, 0xA663},{0x572E, 0xC9C8},{0x572F, 0xA665},{0x5730, 0xA661},{0x5733, 0xA660},{0x5734, 0xC9CA},{0x573B, 0xA7A6},{0x573E, 0xA7A3}, + {0x5740, 0xA77D},{0x5741, 0xCAAA},{0x5745, 0xCAAB},{0x5747, 0xA7A1},{0x5749, 0xCAAD},{0x574A, 0xA77B},{0x574B, 0xCAAE},{0x574C, 0xCAAC}, + {0x574D, 0xA77E},{0x574E, 0xA7A2},{0x574F, 0xA7A5},{0x5750, 0xA7A4},{0x5751, 0xA77C},{0x5752, 0xCAAF},{0x5761, 0xA959},{0x5762, 0xCBFE}, + {0x5764, 0xA95B},{0x5766, 0xA95A},{0x5768, 0xCC40},{0x5769, 0xA958},{0x576A, 0xA957},{0x576B, 0xCBF5},{0x576D, 0xCBF4},{0x576F, 0xCBF2}, + {0x5770, 0xCBF7},{0x5771, 0xCBF6},{0x5772, 0xCBF3},{0x5773, 0xCBFC},{0x5774, 0xCBFD},{0x5775, 0xCBFA},{0x5776, 0xCBF8},{0x5777, 0xA956}, + {0x577B, 0xCBFB},{0x577C, 0xA95C},{0x577D, 0xCC41},{0x5780, 0xCBF9},{0x5782, 0xABAB},{0x5783, 0xA955},{0x578B, 0xABAC},{0x578C, 0xCE54}, + {0x578F, 0xCE5A},{0x5793, 0xABB2},{0x5794, 0xCE58},{0x5795, 0xCE5E},{0x5797, 0xCE55},{0x5798, 0xCE59},{0x5799, 0xCE5B},{0x579A, 0xCE5D}, + {0x579B, 0xCE57},{0x579D, 0xCE56},{0x579E, 0xCE51},{0x579F, 0xCE52},{0x57A0, 0xABAD},{0x57A2, 0xABAF},{0x57A3, 0xABAE},{0x57A4, 0xCE53}, + {0x57A5, 0xCE5C},{0x57AE, 0xABB1},{0x57B5, 0xCE50},{0x57B6, 0xD153},{0x57B8, 0xD152},{0x57B9, 0xD157},{0x57BA, 0xD14E},{0x57BC, 0xD151}, + {0x57BD, 0xD150},{0x57BF, 0xD154},{0x57C1, 0xD158},{0x57C2, 0xAE47},{0x57C3, 0xAE4A},{0x57C6, 0xD14F},{0x57C7, 0xD155},{0x57CB, 0xAE49}, + {0x57CC, 0xD14A},{0x57CE, 0xABB0},{0x57CF, 0xD4BA},{0x57D0, 0xD156},{0x57D2, 0xD14D},{0x57D4, 0xAE48},{0x57D5, 0xD14C},{0x57DC, 0xD4B1}, + {0x57DF, 0xB0EC},{0x57E0, 0xB0F0},{0x57E1, 0xD4C1},{0x57E2, 0xD4AF},{0x57E3, 0xD4BD},{0x57E4, 0xB0F1},{0x57E5, 0xD4BF},{0x57E7, 0xD4C5}, + {0x57E9, 0xD4C9},{0x57EC, 0xD4C0},{0x57ED, 0xD4B4},{0x57EE, 0xD4BC},{0x57F0, 0xD4CA},{0x57F1, 0xD4C8},{0x57F2, 0xD4BE},{0x57F3, 0xD4B9}, + {0x57F4, 0xD4B2},{0x57F5, 0xD8A6},{0x57F6, 0xD4B0},{0x57F7, 0xB0F5},{0x57F8, 0xD4B7},{0x57F9, 0xB0F6},{0x57FA, 0xB0F2},{0x57FB, 0xD4AD}, + {0x57FC, 0xD4C3},{0x57FD, 0xD4B5},{0x5800, 0xD4B3},{0x5801, 0xD4C6},{0x5802, 0xB0F3},{0x5804, 0xD4CC},{0x5805, 0xB0ED},{0x5806, 0xB0EF}, + {0x5807, 0xD4BB},{0x5808, 0xD4B6},{0x5809, 0xAE4B},{0x580A, 0xB0EE},{0x580B, 0xD4B8},{0x580C, 0xD4C7},{0x580D, 0xD4CB},{0x580E, 0xD4C2}, + {0x5810, 0xD4C4},{0x5814, 0xD4AE},{0x5819, 0xD8A1},{0x581B, 0xD8AA},{0x581C, 0xD8A9},{0x581D, 0xB3FA},{0x581E, 0xD8A2},{0x5820, 0xB3FB}, + {0x5821, 0xB3F9},{0x5823, 0xD8A4},{0x5824, 0xB3F6},{0x5825, 0xD8A8},{0x5827, 0xD8A3},{0x5828, 0xD8A5},{0x5829, 0xD87D},{0x582A, 0xB3F4}, + {0x582C, 0xD8B2},{0x582D, 0xD8B1},{0x582E, 0xD8AE},{0x582F, 0xB3F3},{0x5830, 0xB3F7},{0x5831, 0xB3F8},{0x5832, 0xD14B},{0x5833, 0xD8AB}, + {0x5834, 0xB3F5},{0x5835, 0xB0F4},{0x5836, 0xD8AD},{0x5837, 0xD87E},{0x5838, 0xD8B0},{0x5839, 0xD8AF},{0x583B, 0xD8B3},{0x583D, 0xDCEF}, + {0x583F, 0xD8AC},{0x5848, 0xD8A7},{0x5849, 0xDCE7},{0x584A, 0xB6F4},{0x584B, 0xB6F7},{0x584C, 0xB6F2},{0x584D, 0xDCE6},{0x584E, 0xDCEA}, + {0x584F, 0xDCE5},{0x5851, 0xB6EC},{0x5852, 0xB6F6},{0x5853, 0xDCE2},{0x5854, 0xB6F0},{0x5855, 0xDCE9},{0x5857, 0xB6EE},{0x5858, 0xB6ED}, + {0x5859, 0xDCEC},{0x585A, 0xB6EF},{0x585B, 0xDCEE},{0x585D, 0xDCEB},{0x585E, 0xB6EB},{0x5862, 0xB6F5},{0x5863, 0xDCF0},{0x5864, 0xDCE4}, + {0x5865, 0xDCED},{0x5868, 0xDCE3},{0x586B, 0xB6F1},{0x586D, 0xB6F3},{0x586F, 0xDCE8},{0x5871, 0xDCF1},{0x5874, 0xE15D},{0x5875, 0xB9D0}, + {0x5876, 0xE163},{0x5879, 0xB9D5},{0x587A, 0xE15F},{0x587B, 0xE166},{0x587C, 0xE157},{0x587D, 0xB9D7},{0x587E, 0xB9D1},{0x587F, 0xE15C}, + {0x5880, 0xBC55},{0x5881, 0xE15B},{0x5882, 0xE164},{0x5883, 0xB9D2},{0x5885, 0xB9D6},{0x5886, 0xE15A},{0x5887, 0xE160},{0x5888, 0xE165}, + {0x5889, 0xE156},{0x588A, 0xB9D4},{0x588B, 0xE15E},{0x588E, 0xE162},{0x588F, 0xE168},{0x5890, 0xE158},{0x5891, 0xE161},{0x5893, 0xB9D3}, + {0x5894, 0xE167},{0x5898, 0xE159},{0x589C, 0xBC59},{0x589D, 0xE54B},{0x589E, 0xBC57},{0x589F, 0xBC56},{0x58A0, 0xE54D},{0x58A1, 0xE552}, + {0x58A3, 0xE54E},{0x58A5, 0xE551},{0x58A6, 0xBC5C},{0x58A8, 0xBEA5},{0x58A9, 0xBC5B},{0x58AB, 0xE54A},{0x58AC, 0xE550},{0x58AE, 0xBC5A}, + {0x58AF, 0xE54F},{0x58B1, 0xE54C},{0x58B3, 0xBC58},{0x58BA, 0xE94D},{0x58BC, 0xE94F},{0x58BD, 0xE94A},{0x58BE, 0xBEC1},{0x58BF, 0xE94C}, + {0x58C1, 0xBEC0},{0x58C2, 0xE94E},{0x58C5, 0xBEC3},{0x58C6, 0xE950},{0x58C7, 0xBEC2},{0x58C8, 0xE949},{0x58C9, 0xE94B},{0x58CE, 0xC0A5}, + {0x58CF, 0xECCC},{0x58D1, 0xC0A4},{0x58D2, 0xECCD},{0x58D3, 0xC0A3},{0x58D4, 0xECCB},{0x58D5, 0xC0A2},{0x58D6, 0xECCA},{0x58D8, 0xC253}, + {0x58D9, 0xC252},{0x58DA, 0xF1F6},{0x58DB, 0xF1F8},{0x58DD, 0xF1F7},{0x58DE, 0xC361},{0x58DF, 0xC362},{0x58E2, 0xC363},{0x58E3, 0xF442}, + {0x58E4, 0xC45B},{0x58E7, 0xF7D3},{0x58E8, 0xF7D2},{0x58E9, 0xC5F2},{0x58EB, 0xA468},{0x58EC, 0xA4D0},{0x58EF, 0xA7A7},{0x58F4, 0xCE5F}, + {0x58F9, 0xB3FC},{0x58FA, 0xB3FD},{0x58FC, 0xDCF2},{0x58FD, 0xB9D8},{0x58FE, 0xE169},{0x58FF, 0xE553},{0x5903, 0xC95A},{0x5906, 0xCAB0}, + {0x590C, 0xCC42},{0x590D, 0xCE60},{0x590E, 0xD159},{0x590F, 0xAE4C},{0x5912, 0xF1F9},{0x5914, 0xC4DC},{0x5915, 0xA469},{0x5916, 0xA57E}, + {0x5917, 0xC970},{0x5919, 0xA667},{0x591A, 0xA668},{0x591C, 0xA95D},{0x5920, 0xB0F7},{0x5922, 0xB9DA},{0x5924, 0xB9DB},{0x5925, 0xB9D9}, + {0x5927, 0xA46A},{0x5929, 0xA4D1},{0x592A, 0xA4D3},{0x592B, 0xA4D2},{0x592C, 0xC95B},{0x592D, 0xA4D4},{0x592E, 0xA5A1},{0x592F, 0xC971}, + {0x5931, 0xA5A2},{0x5937, 0xA669},{0x5938, 0xA66A},{0x593C, 0xC9CB},{0x593E, 0xA7A8},{0x5940, 0xCAB1},{0x5944, 0xA961},{0x5945, 0xCC43}, + {0x5947, 0xA95F},{0x5948, 0xA960},{0x5949, 0xA95E},{0x594A, 0xD15A},{0x594E, 0xABB6},{0x594F, 0xABB5},{0x5950, 0xABB7},{0x5951, 0xABB4}, + {0x5953, 0xCE61},{0x5954, 0xA962},{0x5955, 0xABB3},{0x5957, 0xAE4D},{0x5958, 0xAE4E},{0x595A, 0xAE4F},{0x595C, 0xD4CD},{0x5960, 0xB3FE}, + {0x5961, 0xD8B4},{0x5962, 0xB0F8},{0x5967, 0xB6F8},{0x5969, 0xB9DD},{0x596A, 0xB9DC},{0x596B, 0xE16A},{0x596D, 0xBC5D},{0x596E, 0xBEC4}, + {0x5970, 0xEFC0},{0x5971, 0xF6DA},{0x5972, 0xF7D4},{0x5973, 0xA46B},{0x5974, 0xA5A3},{0x5976, 0xA5A4},{0x5977, 0xC9D1},{0x5978, 0xA66C}, + {0x5979, 0xA66F},{0x597B, 0xC9CF},{0x597C, 0xC9CD},{0x597D, 0xA66E},{0x597E, 0xC9D0},{0x597F, 0xC9D2},{0x5980, 0xC9CC},{0x5981, 0xA671}, + {0x5982, 0xA670},{0x5983, 0xA66D},{0x5984, 0xA66B},{0x5985, 0xC9CE},{0x598A, 0xA7B3},{0x598D, 0xA7B0},{0x598E, 0xCAB6},{0x598F, 0xCAB9}, + {0x5990, 0xCAB8},{0x5992, 0xA7AA},{0x5993, 0xA7B2},{0x5996, 0xA7AF},{0x5997, 0xCAB5},{0x5998, 0xCAB3},{0x5999, 0xA7AE},{0x599D, 0xA7A9}, + {0x599E, 0xA7AC},{0x59A0, 0xCAB4},{0x59A1, 0xCABB},{0x59A2, 0xCAB7},{0x59A3, 0xA7AD},{0x59A4, 0xA7B1},{0x59A5, 0xA7B4},{0x59A6, 0xCAB2}, + {0x59A7, 0xCABA},{0x59A8, 0xA7AB},{0x59AE, 0xA967},{0x59AF, 0xA96F},{0x59B1, 0xCC4F},{0x59B2, 0xCC48},{0x59B3, 0xA970},{0x59B4, 0xCC53}, + {0x59B5, 0xCC44},{0x59B6, 0xCC4B},{0x59B9, 0xA966},{0x59BA, 0xCC45},{0x59BB, 0xA964},{0x59BC, 0xCC4C},{0x59BD, 0xCC50},{0x59BE, 0xA963}, + {0x59C0, 0xCC51},{0x59C1, 0xCC4A},{0x59C3, 0xCC4D},{0x59C5, 0xA972},{0x59C6, 0xA969},{0x59C7, 0xCC54},{0x59C8, 0xCC52},{0x59CA, 0xA96E}, + {0x59CB, 0xA96C},{0x59CC, 0xCC49},{0x59CD, 0xA96B},{0x59CE, 0xCC47},{0x59CF, 0xCC46},{0x59D0, 0xA96A},{0x59D1, 0xA968},{0x59D2, 0xA971}, + {0x59D3, 0xA96D},{0x59D4, 0xA965},{0x59D6, 0xCC4E},{0x59D8, 0xABB9},{0x59DA, 0xABC0},{0x59DB, 0xCE6F},{0x59DC, 0xABB8},{0x59DD, 0xCE67}, + {0x59DE, 0xCE63},{0x59E0, 0xCE73},{0x59E1, 0xCE62},{0x59E3, 0xABBB},{0x59E4, 0xCE6C},{0x59E5, 0xABBE},{0x59E6, 0xABC1},{0x59E8, 0xABBC}, + {0x59E9, 0xCE70},{0x59EA, 0xABBF},{0x59EC, 0xAE56},{0x59ED, 0xCE76},{0x59EE, 0xCE64},{0x59F1, 0xCE66},{0x59F2, 0xCE6D},{0x59F3, 0xCE71}, + {0x59F4, 0xCE75},{0x59F5, 0xCE72},{0x59F6, 0xCE6B},{0x59F7, 0xCE6E},{0x59FA, 0xCE68},{0x59FB, 0xABC3},{0x59FC, 0xCE6A},{0x59FD, 0xCE69}, + {0x59FE, 0xCE74},{0x59FF, 0xABBA},{0x5A00, 0xCE65},{0x5A01, 0xABC2},{0x5A03, 0xABBD},{0x5A09, 0xAE5C},{0x5A0A, 0xD162},{0x5A0C, 0xAE5B}, + {0x5A0F, 0xD160},{0x5A11, 0xAE50},{0x5A13, 0xAE55},{0x5A15, 0xD15F},{0x5A16, 0xD15C},{0x5A17, 0xD161},{0x5A18, 0xAE51},{0x5A19, 0xD15B}, + {0x5A1B, 0xAE54},{0x5A1C, 0xAE52},{0x5A1E, 0xD163},{0x5A1F, 0xAE53},{0x5A20, 0xAE57},{0x5A23, 0xAE58},{0x5A25, 0xAE5A},{0x5A29, 0xAE59}, + {0x5A2D, 0xD15D},{0x5A2E, 0xD15E},{0x5A33, 0xD164},{0x5A35, 0xD4D4},{0x5A36, 0xB0F9},{0x5A37, 0xD8C2},{0x5A38, 0xD4D3},{0x5A39, 0xD4E6}, + {0x5A3C, 0xB140},{0x5A3E, 0xD4E4},{0x5A40, 0xB0FE},{0x5A41, 0xB0FA},{0x5A42, 0xD4ED},{0x5A43, 0xD4DD},{0x5A44, 0xD4E0},{0x5A46, 0xB143}, + {0x5A47, 0xD4EA},{0x5A48, 0xD4E2},{0x5A49, 0xB0FB},{0x5A4A, 0xB144},{0x5A4C, 0xD4E7},{0x5A4D, 0xD4E5},{0x5A50, 0xD4D6},{0x5A51, 0xD4EB}, + {0x5A52, 0xD4DF},{0x5A53, 0xD4DA},{0x5A55, 0xD4D0},{0x5A56, 0xD4EC},{0x5A57, 0xD4DC},{0x5A58, 0xD4CF},{0x5A5A, 0xB142},{0x5A5B, 0xD4E1}, + {0x5A5C, 0xD4EE},{0x5A5D, 0xD4DE},{0x5A5E, 0xD4D2},{0x5A5F, 0xD4D7},{0x5A60, 0xD4CE},{0x5A62, 0xB141},{0x5A64, 0xD4DB},{0x5A65, 0xD4D8}, + {0x5A66, 0xB0FC},{0x5A67, 0xD4D1},{0x5A69, 0xD4E9},{0x5A6A, 0xB0FD},{0x5A6C, 0xD4D9},{0x5A6D, 0xD4D5},{0x5A70, 0xD4E8},{0x5A77, 0xB440}, + {0x5A78, 0xD8BB},{0x5A7A, 0xD8B8},{0x5A7B, 0xD8C9},{0x5A7C, 0xD8BD},{0x5A7D, 0xD8CA},{0x5A7F, 0xB442},{0x5A83, 0xD8C6},{0x5A84, 0xD8C3}, + {0x5A8A, 0xD8C4},{0x5A8B, 0xD8C7},{0x5A8C, 0xD8CB},{0x5A8E, 0xD4E3},{0x5A8F, 0xD8CD},{0x5A90, 0xDD47},{0x5A92, 0xB443},{0x5A93, 0xD8CE}, + {0x5A94, 0xD8B6},{0x5A95, 0xD8C0},{0x5A97, 0xD8C5},{0x5A9A, 0xB441},{0x5A9B, 0xB444},{0x5A9C, 0xD8CC},{0x5A9D, 0xD8CF},{0x5A9E, 0xD8BA}, + {0x5A9F, 0xD8B7},{0x5AA2, 0xD8B9},{0x5AA5, 0xD8BE},{0x5AA6, 0xD8BC},{0x5AA7, 0xB445},{0x5AA9, 0xD8C8},{0x5AAC, 0xD8BF},{0x5AAE, 0xD8C1}, + {0x5AAF, 0xD8B5},{0x5AB0, 0xDCFA},{0x5AB1, 0xDCF8},{0x5AB2, 0xB742},{0x5AB3, 0xB740},{0x5AB4, 0xDD43},{0x5AB5, 0xDCF9},{0x5AB6, 0xDD44}, + {0x5AB7, 0xDD40},{0x5AB8, 0xDCF7},{0x5AB9, 0xDD46},{0x5ABA, 0xDCF6},{0x5ABB, 0xDCFD},{0x5ABC, 0xB6FE},{0x5ABD, 0xB6FD},{0x5ABE, 0xB6FC}, + {0x5ABF, 0xDCFB},{0x5AC0, 0xDD41},{0x5AC1, 0xB6F9},{0x5AC2, 0xB741},{0x5AC4, 0xDCF4},{0x5AC6, 0xDCFE},{0x5AC7, 0xDCF3},{0x5AC8, 0xDCFC}, + {0x5AC9, 0xB6FA},{0x5ACA, 0xDD42},{0x5ACB, 0xDCF5},{0x5ACC, 0xB6FB},{0x5ACD, 0xDD45},{0x5AD5, 0xE16E},{0x5AD6, 0xB9E2},{0x5AD7, 0xB9E1}, + {0x5AD8, 0xB9E3},{0x5AD9, 0xE17A},{0x5ADA, 0xE170},{0x5ADB, 0xE176},{0x5ADC, 0xE16B},{0x5ADD, 0xE179},{0x5ADE, 0xE178},{0x5ADF, 0xE17C}, + {0x5AE0, 0xE175},{0x5AE1, 0xB9DE},{0x5AE2, 0xE174},{0x5AE3, 0xB9E4},{0x5AE5, 0xE16D},{0x5AE6, 0xB9DF},{0x5AE8, 0xE17B},{0x5AE9, 0xB9E0}, + {0x5AEA, 0xE16F},{0x5AEB, 0xE172},{0x5AEC, 0xE177},{0x5AED, 0xE171},{0x5AEE, 0xE16C},{0x5AF3, 0xE173},{0x5AF4, 0xE555},{0x5AF5, 0xBC61}, + {0x5AF6, 0xE558},{0x5AF7, 0xE557},{0x5AF8, 0xE55A},{0x5AF9, 0xE55C},{0x5AFB, 0xBC5F},{0x5AFD, 0xE556},{0x5AFF, 0xE554},{0x5B01, 0xE55D}, + {0x5B02, 0xE55B},{0x5B03, 0xE559},{0x5B05, 0xE55F},{0x5B07, 0xE55E},{0x5B08, 0xBC63},{0x5B09, 0xBC5E},{0x5B0B, 0xBC60},{0x5B0C, 0xBC62}, + {0x5B0F, 0xE560},{0x5B10, 0xE957},{0x5B13, 0xE956},{0x5B14, 0xE955},{0x5B16, 0xE958},{0x5B17, 0xE951},{0x5B19, 0xE952},{0x5B1A, 0xE95A}, + {0x5B1B, 0xE953},{0x5B1D, 0xBEC5},{0x5B1E, 0xE95C},{0x5B20, 0xE95B},{0x5B21, 0xE954},{0x5B23, 0xECD1},{0x5B24, 0xC0A8},{0x5B25, 0xECCF}, + {0x5B26, 0xECD4},{0x5B27, 0xECD3},{0x5B28, 0xE959},{0x5B2A, 0xC0A7},{0x5B2C, 0xECD2},{0x5B2D, 0xECCE},{0x5B2E, 0xECD6},{0x5B2F, 0xECD5}, + {0x5B30, 0xC0A6},{0x5B32, 0xECD0},{0x5B34, 0xBEC6},{0x5B38, 0xC254},{0x5B3C, 0xEFC1},{0x5B3D, 0xF1FA},{0x5B3E, 0xF1FB},{0x5B3F, 0xF1FC}, + {0x5B40, 0xC45C},{0x5B43, 0xC45D},{0x5B45, 0xF443},{0x5B47, 0xF5C8},{0x5B48, 0xF5C7},{0x5B4B, 0xF6DB},{0x5B4C, 0xF6DC},{0x5B4D, 0xF7D5}, + {0x5B4E, 0xF8A7},{0x5B50, 0xA46C},{0x5B51, 0xA46D},{0x5B53, 0xA46E},{0x5B54, 0xA4D5},{0x5B55, 0xA5A5},{0x5B56, 0xC9D3},{0x5B57, 0xA672}, + {0x5B58, 0xA673},{0x5B5A, 0xA7B7},{0x5B5B, 0xA7B8},{0x5B5C, 0xA7B6},{0x5B5D, 0xA7B5},{0x5B5F, 0xA973},{0x5B62, 0xCC55},{0x5B63, 0xA975}, + {0x5B64, 0xA974},{0x5B65, 0xCC56},{0x5B69, 0xABC4},{0x5B6B, 0xAE5D},{0x5B6C, 0xD165},{0x5B6E, 0xD4F0},{0x5B70, 0xB145},{0x5B71, 0xB447}, + {0x5B72, 0xD4EF},{0x5B73, 0xB446},{0x5B75, 0xB9E5},{0x5B77, 0xE17D},{0x5B78, 0xBEC7},{0x5B7A, 0xC0A9},{0x5B7B, 0xECD7},{0x5B7D, 0xC45E}, + {0x5B7F, 0xC570},{0x5B81, 0xC972},{0x5B83, 0xA5A6},{0x5B84, 0xC973},{0x5B85, 0xA676},{0x5B87, 0xA674},{0x5B88, 0xA675},{0x5B89, 0xA677}, + {0x5B8B, 0xA7BA},{0x5B8C, 0xA7B9},{0x5B8E, 0xCABC},{0x5B8F, 0xA7BB},{0x5B92, 0xCABD},{0x5B93, 0xCC57},{0x5B95, 0xCC58},{0x5B97, 0xA976}, + {0x5B98, 0xA978},{0x5B99, 0xA97A},{0x5B9A, 0xA977},{0x5B9B, 0xA97B},{0x5B9C, 0xA979},{0x5BA2, 0xABC8},{0x5BA3, 0xABC5},{0x5BA4, 0xABC7}, + {0x5BA5, 0xABC9},{0x5BA6, 0xABC6},{0x5BA7, 0xD166},{0x5BA8, 0xCE77},{0x5BAC, 0xD168},{0x5BAD, 0xD167},{0x5BAE, 0xAE63},{0x5BB0, 0xAE5F}, + {0x5BB3, 0xAE60},{0x5BB4, 0xAE62},{0x5BB5, 0xAE64},{0x5BB6, 0xAE61},{0x5BB8, 0xAE66},{0x5BB9, 0xAE65},{0x5BBF, 0xB14A},{0x5BC0, 0xD4F2}, + {0x5BC1, 0xD4F1},{0x5BC2, 0xB149},{0x5BC4, 0xB148},{0x5BC5, 0xB147},{0x5BC6, 0xB14B},{0x5BC7, 0xB146},{0x5BCA, 0xD8D5},{0x5BCB, 0xD8D2}, + {0x5BCC, 0xB449},{0x5BCD, 0xD8D1},{0x5BCE, 0xD8D6},{0x5BD0, 0xB44B},{0x5BD1, 0xD8D4},{0x5BD2, 0xB448},{0x5BD3, 0xB44A},{0x5BD4, 0xD8D3}, + {0x5BD6, 0xDD48},{0x5BD8, 0xDD49},{0x5BD9, 0xDD4A},{0x5BDE, 0xB9E6},{0x5BDF, 0xB9EE},{0x5BE0, 0xE17E},{0x5BE1, 0xB9E8},{0x5BE2, 0xB9EC}, + {0x5BE3, 0xE1A1},{0x5BE4, 0xB9ED},{0x5BE5, 0xB9E9},{0x5BE6, 0xB9EA},{0x5BE7, 0xB9E7},{0x5BE8, 0xB9EB},{0x5BE9, 0xBC66},{0x5BEA, 0xD8D0}, + {0x5BEB, 0xBC67},{0x5BEC, 0xBC65},{0x5BEE, 0xBC64},{0x5BEF, 0xE95D},{0x5BF0, 0xBEC8},{0x5BF1, 0xECD8},{0x5BF2, 0xECD9},{0x5BF5, 0xC364}, + {0x5BF6, 0xC45F},{0x5BF8, 0xA46F},{0x5BFA, 0xA678},{0x5C01, 0xABCA},{0x5C03, 0xD169},{0x5C04, 0xAE67},{0x5C07, 0xB14E},{0x5C08, 0xB14D}, + {0x5C09, 0xB14C},{0x5C0A, 0xB44C},{0x5C0B, 0xB44D},{0x5C0C, 0xD8D7},{0x5C0D, 0xB9EF},{0x5C0E, 0xBEC9},{0x5C0F, 0xA470},{0x5C10, 0xC95C}, + {0x5C11, 0xA4D6},{0x5C12, 0xC974},{0x5C15, 0xC9D4},{0x5C16, 0xA679},{0x5C1A, 0xA97C},{0x5C1F, 0xDD4B},{0x5C22, 0xA471},{0x5C24, 0xA4D7}, + {0x5C25, 0xC9D5},{0x5C28, 0xCABE},{0x5C2A, 0xCABF},{0x5C2C, 0xA7BC},{0x5C30, 0xD8D8},{0x5C31, 0xB44E},{0x5C33, 0xDD4C},{0x5C37, 0xC0AA}, + {0x5C38, 0xA472},{0x5C39, 0xA4A8},{0x5C3A, 0xA4D8},{0x5C3B, 0xC975},{0x5C3C, 0xA5A7},{0x5C3E, 0xA7C0},{0x5C3F, 0xA7BF},{0x5C40, 0xA7BD}, + {0x5C41, 0xA7BE},{0x5C44, 0xCC59},{0x5C45, 0xA97E},{0x5C46, 0xA9A1},{0x5C47, 0xCC5A},{0x5C48, 0xA97D},{0x5C4B, 0xABCE},{0x5C4C, 0xCE78}, + {0x5C4D, 0xABCD},{0x5C4E, 0xABCB},{0x5C4F, 0xABCC},{0x5C50, 0xAE6A},{0x5C51, 0xAE68},{0x5C54, 0xD16B},{0x5C55, 0xAE69},{0x5C56, 0xD16A}, + {0x5C58, 0xAE5E},{0x5C59, 0xD4F3},{0x5C5C, 0xB150},{0x5C5D, 0xB151},{0x5C60, 0xB14F},{0x5C62, 0xB9F0},{0x5C63, 0xE1A2},{0x5C64, 0xBC68}, + {0x5C65, 0xBC69},{0x5C67, 0xE561},{0x5C68, 0xC0AB},{0x5C69, 0xEFC2},{0x5C6A, 0xEFC3},{0x5C6C, 0xC4DD},{0x5C6D, 0xF8A8},{0x5C6E, 0xC94B}, + {0x5C6F, 0xA4D9},{0x5C71, 0xA473},{0x5C73, 0xC977},{0x5C74, 0xC976},{0x5C79, 0xA67A},{0x5C7A, 0xC9D7},{0x5C7B, 0xC9D8},{0x5C7C, 0xC9D6}, + {0x5C7E, 0xC9D9},{0x5C86, 0xCAC7},{0x5C88, 0xCAC2},{0x5C89, 0xCAC4},{0x5C8A, 0xCAC6},{0x5C8B, 0xCAC3},{0x5C8C, 0xA7C4},{0x5C8D, 0xCAC0}, + {0x5C8F, 0xCAC1},{0x5C90, 0xA7C1},{0x5C91, 0xA7C2},{0x5C92, 0xCAC5},{0x5C93, 0xCAC8},{0x5C94, 0xA7C3},{0x5C95, 0xCAC9},{0x5C9D, 0xCC68}, + {0x5C9F, 0xCC62},{0x5CA0, 0xCC5D},{0x5CA1, 0xA9A3},{0x5CA2, 0xCC65},{0x5CA3, 0xCC63},{0x5CA4, 0xCC5C},{0x5CA5, 0xCC69},{0x5CA6, 0xCC6C}, + {0x5CA7, 0xCC67},{0x5CA8, 0xCC60},{0x5CA9, 0xA9A5},{0x5CAA, 0xCC66},{0x5CAB, 0xA9A6},{0x5CAC, 0xCC61},{0x5CAD, 0xCC64},{0x5CAE, 0xCC5B}, + {0x5CAF, 0xCC5F},{0x5CB0, 0xCC6B},{0x5CB1, 0xA9A7},{0x5CB3, 0xA9A8},{0x5CB5, 0xCC5E},{0x5CB6, 0xCC6A},{0x5CB7, 0xA9A2},{0x5CB8, 0xA9A4}, + {0x5CC6, 0xCEAB},{0x5CC7, 0xCEA4},{0x5CC8, 0xCEAA},{0x5CC9, 0xCEA3},{0x5CCA, 0xCEA5},{0x5CCB, 0xCE7D},{0x5CCC, 0xCE7B},{0x5CCE, 0xCEAC}, + {0x5CCF, 0xCEA9},{0x5CD0, 0xCE79},{0x5CD2, 0xABD0},{0x5CD3, 0xCEA7},{0x5CD4, 0xCEA8},{0x5CD6, 0xCEA6},{0x5CD7, 0xCE7C},{0x5CD8, 0xCE7A}, + {0x5CD9, 0xABCF},{0x5CDA, 0xCEA2},{0x5CDB, 0xCE7E},{0x5CDE, 0xCEA1},{0x5CDF, 0xCEAD},{0x5CE8, 0xAE6F},{0x5CEA, 0xAE6E},{0x5CEC, 0xD16C}, + {0x5CED, 0xAE6B},{0x5CEE, 0xD16E},{0x5CF0, 0xAE70},{0x5CF1, 0xD16F},{0x5CF4, 0xAE73},{0x5CF6, 0xAE71},{0x5CF7, 0xD170},{0x5CF8, 0xCEAE}, + {0x5CF9, 0xD172},{0x5CFB, 0xAE6D},{0x5CFD, 0xAE6C},{0x5CFF, 0xD16D},{0x5D00, 0xD171},{0x5D01, 0xAE72},{0x5D06, 0xB153},{0x5D07, 0xB152}, + {0x5D0B, 0xD4F5},{0x5D0C, 0xD4F9},{0x5D0D, 0xD4FB},{0x5D0E, 0xB154},{0x5D0F, 0xD4FE},{0x5D11, 0xB158},{0x5D12, 0xD541},{0x5D14, 0xB15A}, + {0x5D16, 0xB156},{0x5D17, 0xB15E},{0x5D19, 0xB15B},{0x5D1A, 0xD4F7},{0x5D1B, 0xB155},{0x5D1D, 0xD4F6},{0x5D1E, 0xD4F4},{0x5D1F, 0xD543}, + {0x5D20, 0xD4F8},{0x5D22, 0xB157},{0x5D23, 0xD542},{0x5D24, 0xB15C},{0x5D25, 0xD4FD},{0x5D26, 0xD4FC},{0x5D27, 0xB15D},{0x5D28, 0xD4FA}, + {0x5D29, 0xB159},{0x5D2E, 0xD544},{0x5D30, 0xD540},{0x5D31, 0xD8E7},{0x5D32, 0xD8EE},{0x5D33, 0xD8E3},{0x5D34, 0xB451},{0x5D35, 0xD8DF}, + {0x5D36, 0xD8EF},{0x5D37, 0xD8D9},{0x5D38, 0xD8EC},{0x5D39, 0xD8EA},{0x5D3A, 0xD8E4},{0x5D3C, 0xD8ED},{0x5D3D, 0xD8E6},{0x5D3F, 0xD8DE}, + {0x5D40, 0xD8F0},{0x5D41, 0xD8DC},{0x5D42, 0xD8E9},{0x5D43, 0xD8DA},{0x5D45, 0xD8F1},{0x5D47, 0xB452},{0x5D49, 0xD8EB},{0x5D4A, 0xDD4F}, + {0x5D4B, 0xD8DD},{0x5D4C, 0xB44F},{0x5D4E, 0xD8E1},{0x5D50, 0xB450},{0x5D51, 0xD8E0},{0x5D52, 0xD8E5},{0x5D55, 0xD8E2},{0x5D59, 0xD8E8}, + {0x5D5E, 0xDD53},{0x5D62, 0xDD56},{0x5D63, 0xDD4E},{0x5D65, 0xDD50},{0x5D67, 0xDD55},{0x5D68, 0xDD54},{0x5D69, 0xB743},{0x5D6B, 0xD8DB}, + {0x5D6C, 0xDD52},{0x5D6F, 0xB744},{0x5D71, 0xDD4D},{0x5D72, 0xDD51},{0x5D77, 0xE1A9},{0x5D79, 0xE1B0},{0x5D7A, 0xE1A7},{0x5D7C, 0xE1AE}, + {0x5D7D, 0xE1A5},{0x5D7E, 0xE1AD},{0x5D7F, 0xE1B1},{0x5D80, 0xE1A4},{0x5D81, 0xE1A8},{0x5D82, 0xE1A3},{0x5D84, 0xB9F1},{0x5D86, 0xE1A6}, + {0x5D87, 0xB9F2},{0x5D88, 0xE1AC},{0x5D89, 0xE1AB},{0x5D8A, 0xE1AA},{0x5D8D, 0xE1AF},{0x5D92, 0xE565},{0x5D93, 0xE567},{0x5D94, 0xBC6B}, + {0x5D95, 0xE568},{0x5D97, 0xE563},{0x5D99, 0xE562},{0x5D9A, 0xE56C},{0x5D9C, 0xE56A},{0x5D9D, 0xBC6A},{0x5D9E, 0xE56D},{0x5D9F, 0xE564}, + {0x5DA0, 0xE569},{0x5DA1, 0xE56B},{0x5DA2, 0xE566},{0x5DA7, 0xE961},{0x5DA8, 0xE966},{0x5DA9, 0xE960},{0x5DAA, 0xE965},{0x5DAC, 0xE95E}, + {0x5DAD, 0xE968},{0x5DAE, 0xE964},{0x5DAF, 0xE969},{0x5DB0, 0xE963},{0x5DB1, 0xE95F},{0x5DB2, 0xE967},{0x5DB4, 0xE96A},{0x5DB5, 0xE962}, + {0x5DB7, 0xECDA},{0x5DB8, 0xC0AF},{0x5DBA, 0xC0AD},{0x5DBC, 0xC0AC},{0x5DBD, 0xC0AE},{0x5DC0, 0xEFC4},{0x5DC2, 0xF172},{0x5DC3, 0xF1FD}, + {0x5DC6, 0xF444},{0x5DC7, 0xF445},{0x5DC9, 0xC460},{0x5DCB, 0xF5C9},{0x5DCD, 0xC4DE},{0x5DCF, 0xF5CA},{0x5DD1, 0xF6DE},{0x5DD2, 0xC572}, + {0x5DD4, 0xC571},{0x5DD5, 0xF6DD},{0x5DD6, 0xC5C9},{0x5DD8, 0xF7D6},{0x5DDD, 0xA474},{0x5DDE, 0xA67B},{0x5DDF, 0xC9DA},{0x5DE0, 0xCACA}, + {0x5DE1, 0xA8B5},{0x5DE2, 0xB15F},{0x5DE5, 0xA475},{0x5DE6, 0xA5AA},{0x5DE7, 0xA5A9},{0x5DE8, 0xA5A8},{0x5DEB, 0xA7C5},{0x5DEE, 0xAE74}, + {0x5DF0, 0xDD57},{0x5DF1, 0xA476},{0x5DF2, 0xA477},{0x5DF3, 0xA478},{0x5DF4, 0xA4DA},{0x5DF7, 0xABD1},{0x5DF9, 0xCEAF},{0x5DFD, 0xB453}, + {0x5DFE, 0xA479},{0x5DFF, 0xC95D},{0x5E02, 0xA5AB},{0x5E03, 0xA5AC},{0x5E04, 0xC978},{0x5E06, 0xA67C},{0x5E0A, 0xCACB},{0x5E0C, 0xA7C6}, + {0x5E0E, 0xCACC},{0x5E11, 0xA9AE},{0x5E14, 0xCC6E},{0x5E15, 0xA9AC},{0x5E16, 0xA9AB},{0x5E17, 0xCC6D},{0x5E18, 0xA9A9},{0x5E19, 0xCC6F}, + {0x5E1A, 0xA9AA},{0x5E1B, 0xA9AD},{0x5E1D, 0xABD2},{0x5E1F, 0xABD4},{0x5E20, 0xCEB3},{0x5E21, 0xCEB0},{0x5E22, 0xCEB1},{0x5E23, 0xCEB2}, + {0x5E24, 0xCEB4},{0x5E25, 0xABD3},{0x5E28, 0xD174},{0x5E29, 0xD173},{0x5E2B, 0xAE76},{0x5E2D, 0xAE75},{0x5E33, 0xB162},{0x5E34, 0xD546}, + {0x5E36, 0xB161},{0x5E37, 0xB163},{0x5E38, 0xB160},{0x5E3D, 0xB455},{0x5E3E, 0xD545},{0x5E40, 0xB456},{0x5E41, 0xD8F3},{0x5E43, 0xB457}, + {0x5E44, 0xD8F2},{0x5E45, 0xB454},{0x5E4A, 0xDD5A},{0x5E4B, 0xDD5C},{0x5E4C, 0xB745},{0x5E4D, 0xDD5B},{0x5E4E, 0xDD59},{0x5E4F, 0xDD58}, + {0x5E53, 0xE1B4},{0x5E54, 0xB9F7},{0x5E55, 0xB9F5},{0x5E57, 0xB9F6},{0x5E58, 0xE1B2},{0x5E59, 0xE1B3},{0x5E5B, 0xB9F3},{0x5E5C, 0xE571}, + {0x5E5D, 0xE56F},{0x5E5F, 0xBC6D},{0x5E60, 0xE570},{0x5E61, 0xBC6E},{0x5E62, 0xBC6C},{0x5E63, 0xB9F4},{0x5E66, 0xE96D},{0x5E67, 0xE96B}, + {0x5E68, 0xE96C},{0x5E69, 0xE56E},{0x5E6A, 0xECDC},{0x5E6B, 0xC0B0},{0x5E6C, 0xECDB},{0x5E6D, 0xEFC5},{0x5E6E, 0xEFC6},{0x5E6F, 0xE96E}, + {0x5E70, 0xF1FE},{0x5E72, 0xA47A},{0x5E73, 0xA5AD},{0x5E74, 0xA67E},{0x5E75, 0xC9DB},{0x5E76, 0xA67D},{0x5E78, 0xA9AF},{0x5E79, 0xB746}, + {0x5E7B, 0xA4DB},{0x5E7C, 0xA5AE},{0x5E7D, 0xABD5},{0x5E7E, 0xB458},{0x5E80, 0xC979},{0x5E82, 0xC97A},{0x5E84, 0xC9DC},{0x5E87, 0xA7C8}, + {0x5E88, 0xCAD0},{0x5E89, 0xCACE},{0x5E8A, 0xA7C9},{0x5E8B, 0xCACD},{0x5E8C, 0xCACF},{0x5E8D, 0xCAD1},{0x5E8F, 0xA7C7},{0x5E95, 0xA9B3}, + {0x5E96, 0xA9B4},{0x5E97, 0xA9B1},{0x5E9A, 0xA9B0},{0x5E9B, 0xCEB8},{0x5E9C, 0xA9B2},{0x5EA0, 0xABD6},{0x5EA2, 0xCEB7},{0x5EA3, 0xCEB9}, + {0x5EA4, 0xCEB6},{0x5EA5, 0xCEBA},{0x5EA6, 0xABD7},{0x5EA7, 0xAE79},{0x5EA8, 0xD175},{0x5EAA, 0xD177},{0x5EAB, 0xAE77},{0x5EAC, 0xD178}, + {0x5EAD, 0xAE78},{0x5EAE, 0xD176},{0x5EB0, 0xCEB5},{0x5EB1, 0xD547},{0x5EB2, 0xD54A},{0x5EB3, 0xD54B},{0x5EB4, 0xD548},{0x5EB5, 0xB167}, + {0x5EB6, 0xB166},{0x5EB7, 0xB164},{0x5EB8, 0xB165},{0x5EB9, 0xD549},{0x5EBE, 0xB168},{0x5EC1, 0xB45A},{0x5EC2, 0xB45B},{0x5EC4, 0xB45C}, + {0x5EC5, 0xDD5D},{0x5EC6, 0xDD5F},{0x5EC7, 0xDD61},{0x5EC8, 0xB748},{0x5EC9, 0xB747},{0x5ECA, 0xB459},{0x5ECB, 0xDD60},{0x5ECC, 0xDD5E}, + {0x5ECE, 0xE1B8},{0x5ED1, 0xE1B6},{0x5ED2, 0xE1BC},{0x5ED3, 0xB9F8},{0x5ED4, 0xE1BD},{0x5ED5, 0xE1BA},{0x5ED6, 0xB9F9},{0x5ED7, 0xE1B7}, + {0x5ED8, 0xE1B5},{0x5ED9, 0xE1BB},{0x5EDA, 0xBC70},{0x5EDB, 0xE573},{0x5EDC, 0xE1B9},{0x5EDD, 0xBC72},{0x5EDE, 0xE574},{0x5EDF, 0xBC71}, + {0x5EE0, 0xBC74},{0x5EE1, 0xE575},{0x5EE2, 0xBC6F},{0x5EE3, 0xBC73},{0x5EE5, 0xE973},{0x5EE6, 0xE971},{0x5EE7, 0xE970},{0x5EE8, 0xE972}, + {0x5EE9, 0xE96F},{0x5EEC, 0xC366},{0x5EEE, 0xF446},{0x5EEF, 0xF447},{0x5EF1, 0xF5CB},{0x5EF2, 0xF6DF},{0x5EF3, 0xC655},{0x5EF6, 0xA9B5}, + {0x5EF7, 0xA7CA},{0x5EFA, 0xABD8},{0x5EFE, 0xA47B},{0x5EFF, 0xA4DC},{0x5F01, 0xA5AF},{0x5F02, 0xC9DD},{0x5F04, 0xA7CB},{0x5F05, 0xCAD2}, + {0x5F07, 0xCEBB},{0x5F08, 0xABD9},{0x5F0A, 0xB9FA},{0x5F0B, 0xA47C},{0x5F0F, 0xA6A1},{0x5F12, 0xB749},{0x5F13, 0xA47D},{0x5F14, 0xA4DD}, + {0x5F15, 0xA4DE},{0x5F17, 0xA5B1},{0x5F18, 0xA5B0},{0x5F1A, 0xC9DE},{0x5F1B, 0xA6A2},{0x5F1D, 0xCAD3},{0x5F1F, 0xA7CC},{0x5F22, 0xCC71}, + {0x5F23, 0xCC72},{0x5F24, 0xCC73},{0x5F26, 0xA9B6},{0x5F27, 0xA9B7},{0x5F28, 0xCC70},{0x5F29, 0xA9B8},{0x5F2D, 0xABDA},{0x5F2E, 0xCEBC}, + {0x5F30, 0xD17A},{0x5F31, 0xAE7A},{0x5F33, 0xD179},{0x5F35, 0xB169},{0x5F36, 0xD54C},{0x5F37, 0xB16A},{0x5F38, 0xD54D},{0x5F3C, 0xB45D}, + {0x5F40, 0xDD62},{0x5F43, 0xE1BF},{0x5F44, 0xE1BE},{0x5F46, 0xB9FB},{0x5F48, 0xBC75},{0x5F49, 0xE576},{0x5F4A, 0xBECA},{0x5F4B, 0xE974}, + {0x5F4C, 0xC0B1},{0x5F4E, 0xC573},{0x5F4F, 0xF7D8},{0x5F54, 0xCC74},{0x5F56, 0xCEBD},{0x5F57, 0xB16B},{0x5F58, 0xD8F4},{0x5F59, 0xB74A}, + {0x5F5D, 0xC255},{0x5F62, 0xA7CE},{0x5F64, 0xA7CD},{0x5F65, 0xABDB},{0x5F67, 0xD17B},{0x5F69, 0xB16D},{0x5F6A, 0xB343},{0x5F6B, 0xB16E}, + {0x5F6C, 0xB16C},{0x5F6D, 0xB45E},{0x5F6F, 0xE1C0},{0x5F70, 0xB9FC},{0x5F71, 0xBC76},{0x5F73, 0xC94C},{0x5F74, 0xC9DF},{0x5F76, 0xCAD5}, + {0x5F77, 0xA7CF},{0x5F78, 0xCAD4},{0x5F79, 0xA7D0},{0x5F7C, 0xA9BC},{0x5F7D, 0xCC77},{0x5F7E, 0xCC76},{0x5F7F, 0xA9BB},{0x5F80, 0xA9B9}, + {0x5F81, 0xA9BA},{0x5F82, 0xCC75},{0x5F85, 0xABDD},{0x5F86, 0xCEBE},{0x5F87, 0xABE0},{0x5F88, 0xABDC},{0x5F89, 0xABE2},{0x5F8A, 0xABDE}, + {0x5F8B, 0xABDF},{0x5F8C, 0xABE1},{0x5F90, 0xAE7D},{0x5F91, 0xAE7C},{0x5F92, 0xAE7B},{0x5F96, 0xD54F},{0x5F97, 0xB16F},{0x5F98, 0xB172}, + {0x5F99, 0xB170},{0x5F9B, 0xD54E},{0x5F9C, 0xB175},{0x5F9E, 0xB171},{0x5F9F, 0xD550},{0x5FA0, 0xB174},{0x5FA1, 0xB173},{0x5FA5, 0xD8F6}, + {0x5FA6, 0xD8F5},{0x5FA8, 0xB461},{0x5FA9, 0xB45F},{0x5FAA, 0xB460},{0x5FAB, 0xD8F7},{0x5FAC, 0xB74B},{0x5FAD, 0xDD64},{0x5FAE, 0xB74C}, + {0x5FAF, 0xDD63},{0x5FB2, 0xE577},{0x5FB5, 0xBC78},{0x5FB6, 0xE1C1},{0x5FB7, 0xBC77},{0x5FB9, 0xB9FD},{0x5FBB, 0xECDE},{0x5FBC, 0xE975}, + {0x5FBD, 0xC0B2},{0x5FBE, 0xECDD},{0x5FBF, 0xF240},{0x5FC0, 0xF448},{0x5FC1, 0xF449},{0x5FC3, 0xA4DF},{0x5FC5, 0xA5B2},{0x5FC9, 0xC97B}, + {0x5FCC, 0xA7D2},{0x5FCD, 0xA7D4},{0x5FCF, 0xC9E2},{0x5FD0, 0xCAD8},{0x5FD1, 0xCAD7},{0x5FD2, 0xCAD6},{0x5FD4, 0xC9E1},{0x5FD5, 0xC9E0}, + {0x5FD6, 0xA6A4},{0x5FD7, 0xA7D3},{0x5FD8, 0xA7D1},{0x5FD9, 0xA6A3},{0x5FDD, 0xA9BD},{0x5FDE, 0xCC78},{0x5FE0, 0xA9BE},{0x5FE1, 0xCADD}, + {0x5FE3, 0xCADF},{0x5FE4, 0xCADE},{0x5FE5, 0xCC79},{0x5FE8, 0xCADA},{0x5FEA, 0xA7D8},{0x5FEB, 0xA7D6},{0x5FED, 0xCAD9},{0x5FEE, 0xCADB}, + {0x5FEF, 0xCAE1},{0x5FF1, 0xA7D5},{0x5FF3, 0xCADC},{0x5FF4, 0xCAE5},{0x5FF5, 0xA9C0},{0x5FF7, 0xCAE2},{0x5FF8, 0xA7D7},{0x5FFA, 0xCAE0}, + {0x5FFB, 0xCAE3},{0x5FFD, 0xA9BF},{0x5FFF, 0xA9C1},{0x6000, 0xCAE4},{0x6009, 0xCCAF},{0x600A, 0xCCA2},{0x600B, 0xCC7E},{0x600C, 0xCCAE}, + {0x600D, 0xCCA9},{0x600E, 0xABE7},{0x600F, 0xA9C2},{0x6010, 0xCCAA},{0x6011, 0xCCAD},{0x6012, 0xABE3},{0x6013, 0xCCAC},{0x6014, 0xA9C3}, + {0x6015, 0xA9C8},{0x6016, 0xA9C6},{0x6017, 0xCCA3},{0x6019, 0xCC7C},{0x601A, 0xCCA5},{0x601B, 0xA9CD},{0x601C, 0xCCB0},{0x601D, 0xABE4}, + {0x601E, 0xCCA6},{0x6020, 0xABE5},{0x6021, 0xA9C9},{0x6022, 0xCCA8},{0x6024, 0xCECD},{0x6025, 0xABE6},{0x6026, 0xCC7B},{0x6027, 0xA9CA}, + {0x6028, 0xABE8},{0x6029, 0xA9CB},{0x602A, 0xA9C7},{0x602B, 0xA9CC},{0x602C, 0xCCA7},{0x602D, 0xCC7A},{0x602E, 0xCCAB},{0x602F, 0xA9C4}, + {0x6032, 0xCC7D},{0x6033, 0xCCA4},{0x6034, 0xCCA1},{0x6035, 0xA9C5},{0x6037, 0xCEBF},{0x6039, 0xCEC0},{0x6040, 0xCECA},{0x6041, 0xD1A1}, + {0x6042, 0xCECB},{0x6043, 0xABEE},{0x6044, 0xCECE},{0x6045, 0xCEC4},{0x6046, 0xABED},{0x6047, 0xCEC6},{0x6049, 0xCEC7},{0x604C, 0xCEC9}, + {0x604D, 0xABE9},{0x6050, 0xAEA3},{0x6053, 0xCEC5},{0x6054, 0xCEC1},{0x6055, 0xAEA4},{0x6058, 0xCECF},{0x6059, 0xAE7E},{0x605A, 0xD17D}, + {0x605B, 0xCEC8},{0x605D, 0xD17C},{0x605E, 0xCEC3},{0x605F, 0xCECC},{0x6062, 0xABEC},{0x6063, 0xAEA1},{0x6064, 0xABF2},{0x6065, 0xAEA2}, + {0x6066, 0xCED0},{0x6067, 0xD17E},{0x6068, 0xABEB},{0x6069, 0xAEA6},{0x606A, 0xABF1},{0x606B, 0xABF0},{0x606C, 0xABEF},{0x606D, 0xAEA5}, + {0x606E, 0xCED1},{0x606F, 0xAEA7},{0x6070, 0xABEA},{0x6072, 0xCEC2},{0x607F, 0xB176},{0x6080, 0xD1A4},{0x6081, 0xD1A6},{0x6083, 0xD1A8}, + {0x6084, 0xAEA8},{0x6085, 0xAEAE},{0x6086, 0xD553},{0x6087, 0xD1AC},{0x6088, 0xD1A3},{0x6089, 0xB178},{0x608A, 0xD551},{0x608C, 0xAEAD}, + {0x608D, 0xAEAB},{0x608E, 0xD1AE},{0x6090, 0xD552},{0x6092, 0xD1A5},{0x6094, 0xAEAC},{0x6095, 0xD1A9},{0x6096, 0xAEAF},{0x6097, 0xD1AB}, + {0x609A, 0xAEAA},{0x609B, 0xD1AA},{0x609C, 0xD1AD},{0x609D, 0xD1A7},{0x609F, 0xAEA9},{0x60A0, 0xB179},{0x60A2, 0xD1A2},{0x60A3, 0xB177}, + {0x60A8, 0xB17A},{0x60B0, 0xD555},{0x60B1, 0xD55E},{0x60B2, 0xB464},{0x60B4, 0xB17C},{0x60B5, 0xB1A3},{0x60B6, 0xB465},{0x60B7, 0xD560}, + {0x60B8, 0xB1AA},{0x60B9, 0xD8F9},{0x60BA, 0xD556},{0x60BB, 0xB1A2},{0x60BC, 0xB1A5},{0x60BD, 0xB17E},{0x60BE, 0xD554},{0x60BF, 0xD562}, + {0x60C0, 0xD565},{0x60C1, 0xD949},{0x60C3, 0xD563},{0x60C4, 0xD8FD},{0x60C5, 0xB1A1},{0x60C6, 0xB1A8},{0x60C7, 0xB1AC},{0x60C8, 0xD55D}, + {0x60C9, 0xD8F8},{0x60CA, 0xD561},{0x60CB, 0xB17B},{0x60CC, 0xD8FA},{0x60CD, 0xD564},{0x60CE, 0xD8FC},{0x60CF, 0xD559},{0x60D1, 0xB462}, + {0x60D3, 0xD557},{0x60D4, 0xD558},{0x60D5, 0xB1A7},{0x60D8, 0xB1A6},{0x60D9, 0xD55B},{0x60DA, 0xB1AB},{0x60DB, 0xD55F},{0x60DC, 0xB1A4}, + {0x60DD, 0xD55C},{0x60DF, 0xB1A9},{0x60E0, 0xB466},{0x60E1, 0xB463},{0x60E2, 0xD8FB},{0x60E4, 0xD55A},{0x60E6, 0xB17D},{0x60F0, 0xB46B}, + {0x60F1, 0xB46F},{0x60F2, 0xD940},{0x60F3, 0xB751},{0x60F4, 0xB46D},{0x60F5, 0xD944},{0x60F6, 0xB471},{0x60F7, 0xDD65},{0x60F8, 0xD946}, + {0x60F9, 0xB753},{0x60FA, 0xB469},{0x60FB, 0xB46C},{0x60FC, 0xD947},{0x60FE, 0xD948},{0x60FF, 0xD94E},{0x6100, 0xB473},{0x6101, 0xB754}, + {0x6103, 0xD94A},{0x6104, 0xD94F},{0x6105, 0xD943},{0x6106, 0xB75E},{0x6108, 0xB755},{0x6109, 0xB472},{0x610A, 0xD941},{0x610B, 0xD950}, + {0x610D, 0xB75D},{0x610E, 0xB470},{0x610F, 0xB74E},{0x6110, 0xD94D},{0x6112, 0xB474},{0x6113, 0xD945},{0x6114, 0xD8FE},{0x6115, 0xB46A}, + {0x6116, 0xD942},{0x6118, 0xD94B},{0x611A, 0xB74D},{0x611B, 0xB752},{0x611C, 0xB467},{0x611D, 0xD94C},{0x611F, 0xB750},{0x6123, 0xB468}, + {0x6127, 0xB75C},{0x6128, 0xE1C3},{0x6129, 0xDD70},{0x612B, 0xDD68},{0x612C, 0xE1C2},{0x612E, 0xDD6C},{0x612F, 0xDD6E},{0x6132, 0xDD6B}, + {0x6134, 0xB75B},{0x6136, 0xDD6A},{0x6137, 0xB75F},{0x613B, 0xE1D2},{0x613E, 0xB75A},{0x613F, 0xBA40},{0x6140, 0xDD71},{0x6141, 0xE1C4}, + {0x6144, 0xB758},{0x6145, 0xDD69},{0x6146, 0xDD6D},{0x6147, 0xB9FE},{0x6148, 0xB74F},{0x6149, 0xDD66},{0x614A, 0xDD67},{0x614B, 0xBA41}, + {0x614C, 0xB757},{0x614D, 0xB759},{0x614E, 0xB756},{0x614F, 0xDD6F},{0x6152, 0xE1C8},{0x6153, 0xE1C9},{0x6154, 0xE1CE},{0x6155, 0xBC7D}, + {0x6156, 0xE1D5},{0x6158, 0xBA47},{0x615A, 0xBA46},{0x615B, 0xE1D0},{0x615D, 0xBC7C},{0x615E, 0xE1C5},{0x615F, 0xBA45},{0x6161, 0xE1D4}, + {0x6162, 0xBA43},{0x6163, 0xBA44},{0x6165, 0xE1D1},{0x6166, 0xE5AA},{0x6167, 0xBC7A},{0x6168, 0xB46E},{0x616A, 0xE1D3},{0x616B, 0xBCA3}, + {0x616C, 0xE1CB},{0x616E, 0xBC7B},{0x6170, 0xBCA2},{0x6171, 0xE1C6},{0x6172, 0xE1CA},{0x6173, 0xE1C7},{0x6174, 0xE1CD},{0x6175, 0xBA48}, + {0x6176, 0xBC79},{0x6177, 0xBA42},{0x6179, 0xE57A},{0x617A, 0xE1CF},{0x617C, 0xBCA1},{0x617E, 0xBCA4},{0x6180, 0xE1CC},{0x6182, 0xBC7E}, + {0x6183, 0xE579},{0x6189, 0xE57E},{0x618A, 0xBECE},{0x618B, 0xE578},{0x618C, 0xE9A3},{0x618D, 0xE5A9},{0x618E, 0xBCA8},{0x6190, 0xBCA6}, + {0x6191, 0xBECC},{0x6192, 0xE5A6},{0x6193, 0xE5A2},{0x6194, 0xBCAC},{0x6196, 0xE978},{0x619A, 0xBCAA},{0x619B, 0xE5A1},{0x619D, 0xE976}, + {0x619F, 0xE5A5},{0x61A1, 0xE5A8},{0x61A2, 0xE57D},{0x61A4, 0xBCAB},{0x61A7, 0xBCA5},{0x61A8, 0xE977},{0x61A9, 0xBECD},{0x61AA, 0xE5A7}, + {0x61AB, 0xBCA7},{0x61AC, 0xBCA9},{0x61AD, 0xE5A4},{0x61AE, 0xBCAD},{0x61AF, 0xE5A3},{0x61B0, 0xE57C},{0x61B1, 0xE57B},{0x61B2, 0xBECB}, + {0x61B3, 0xE5AB},{0x61B4, 0xE97A},{0x61B5, 0xECE0},{0x61B6, 0xBED0},{0x61B8, 0xE9A2},{0x61BA, 0xE97E},{0x61BC, 0xECE1},{0x61BE, 0xBED1}, + {0x61BF, 0xE9A1},{0x61C1, 0xE97C},{0x61C2, 0xC0B4},{0x61C3, 0xECDF},{0x61C5, 0xE979},{0x61C6, 0xE97B},{0x61C7, 0xC0B5},{0x61C8, 0xBED3}, + {0x61C9, 0xC0B3},{0x61CA, 0xBED2},{0x61CB, 0xC0B7},{0x61CC, 0xE97D},{0x61CD, 0xBECF},{0x61D6, 0xEFCF},{0x61D8, 0xEFC7},{0x61DE, 0xECE7}, + {0x61DF, 0xEFC8},{0x61E0, 0xECE3},{0x61E3, 0xC256},{0x61E4, 0xECE5},{0x61E5, 0xECE4},{0x61E6, 0xC0B6},{0x61E7, 0xECE2},{0x61E8, 0xECE6}, + {0x61E9, 0xEFD0},{0x61EA, 0xEFCC},{0x61EB, 0xEFCE},{0x61ED, 0xEFC9},{0x61EE, 0xEFCA},{0x61F0, 0xEFCD},{0x61F1, 0xEFCB},{0x61F2, 0xC367}, + {0x61F5, 0xC36A},{0x61F6, 0xC369},{0x61F7, 0xC368},{0x61F8, 0xC461},{0x61F9, 0xF44A},{0x61FA, 0xC462},{0x61FB, 0xF241},{0x61FC, 0xC4DF}, + {0x61FD, 0xF5CC},{0x61FE, 0xC4E0},{0x61FF, 0xC574},{0x6200, 0xC5CA},{0x6201, 0xF7D9},{0x6203, 0xF7DA},{0x6204, 0xF7DB},{0x6207, 0xF9BA}, + {0x6208, 0xA4E0},{0x6209, 0xC97C},{0x620A, 0xA5B3},{0x620C, 0xA6A6},{0x620D, 0xA6A7},{0x620E, 0xA6A5},{0x6210, 0xA6A8},{0x6211, 0xA7DA}, + {0x6212, 0xA7D9},{0x6214, 0xCCB1},{0x6215, 0xA9CF},{0x6216, 0xA9CE},{0x6219, 0xD1AF},{0x621A, 0xB1AD},{0x621B, 0xB1AE},{0x621F, 0xB475}, + {0x6220, 0xDD72},{0x6221, 0xB760},{0x6222, 0xB761},{0x6223, 0xDD74},{0x6224, 0xDD76},{0x6225, 0xDD75},{0x6227, 0xE1D7},{0x6229, 0xE1D6}, + {0x622A, 0xBA49},{0x622B, 0xE1D8},{0x622D, 0xE5AC},{0x622E, 0xBCAE},{0x6230, 0xBED4},{0x6232, 0xC0B8},{0x6233, 0xC257},{0x6234, 0xC0B9}, + {0x6236, 0xA4E1},{0x623A, 0xCAE6},{0x623D, 0xCCB2},{0x623E, 0xA9D1},{0x623F, 0xA9D0},{0x6240, 0xA9D2},{0x6241, 0xABF3},{0x6242, 0xCED2}, + {0x6243, 0xCED3},{0x6246, 0xD1B0},{0x6247, 0xAEB0},{0x6248, 0xB1AF},{0x6249, 0xB476},{0x624A, 0xD951},{0x624B, 0xA4E2},{0x624D, 0xA47E}, + {0x624E, 0xA4E3},{0x6250, 0xC97D},{0x6251, 0xA5B7},{0x6252, 0xA5B6},{0x6253, 0xA5B4},{0x6254, 0xA5B5},{0x6258, 0xA6AB},{0x6259, 0xC9E9}, + {0x625A, 0xC9EB},{0x625B, 0xA6AA},{0x625C, 0xC9E3},{0x625E, 0xC9E4},{0x6260, 0xC9EA},{0x6261, 0xC9E6},{0x6262, 0xC9E8},{0x6263, 0xA6A9}, + {0x6264, 0xC9E5},{0x6265, 0xC9EC},{0x6266, 0xC9E7},{0x626D, 0xA7E1},{0x626E, 0xA7EA},{0x626F, 0xA7E8},{0x6270, 0xCAF0},{0x6271, 0xCAED}, + {0x6272, 0xCAF5},{0x6273, 0xA7E6},{0x6274, 0xCAF6},{0x6276, 0xA7DF},{0x6277, 0xCAF3},{0x6279, 0xA7E5},{0x627A, 0xCAEF},{0x627B, 0xCAEE}, + {0x627C, 0xA7E3},{0x627D, 0xCAF4},{0x627E, 0xA7E4},{0x627F, 0xA9D3},{0x6280, 0xA7DE},{0x6281, 0xCAF1},{0x6283, 0xCAE7},{0x6284, 0xA7DB}, + {0x6286, 0xA7EE},{0x6287, 0xCAEC},{0x6288, 0xCAF2},{0x6289, 0xA7E0},{0x628A, 0xA7E2},{0x628C, 0xCAE8},{0x628E, 0xCAE9},{0x628F, 0xCAEA}, + {0x6291, 0xA7ED},{0x6292, 0xA7E7},{0x6293, 0xA7EC},{0x6294, 0xCAEB},{0x6295, 0xA7EB},{0x6296, 0xA7DD},{0x6297, 0xA7DC},{0x6298, 0xA7E9}, + {0x62A8, 0xA9E1},{0x62A9, 0xCCBE},{0x62AA, 0xCCB7},{0x62AB, 0xA9DC},{0x62AC, 0xA9EF},{0x62AD, 0xCCB3},{0x62AE, 0xCCBA},{0x62AF, 0xCCBC}, + {0x62B0, 0xCCBF},{0x62B1, 0xA9EA},{0x62B3, 0xCCBB},{0x62B4, 0xCCB4},{0x62B5, 0xA9E8},{0x62B6, 0xCCB8},{0x62B8, 0xCCC0},{0x62B9, 0xA9D9}, + {0x62BB, 0xCCBD},{0x62BC, 0xA9E3},{0x62BD, 0xA9E2},{0x62BE, 0xCCB6},{0x62BF, 0xA9D7},{0x62C2, 0xA9D8},{0x62C4, 0xA9D6},{0x62C6, 0xA9EE}, + {0x62C7, 0xA9E6},{0x62C8, 0xA9E0},{0x62C9, 0xA9D4},{0x62CA, 0xCCB9},{0x62CB, 0xA9DF},{0x62CC, 0xA9D5},{0x62CD, 0xA9E7},{0x62CE, 0xA9F0}, + {0x62CF, 0xCED4},{0x62D0, 0xA9E4},{0x62D1, 0xCCB5},{0x62D2, 0xA9DA},{0x62D3, 0xA9DD},{0x62D4, 0xA9DE},{0x62D6, 0xA9EC},{0x62D7, 0xA9ED}, + {0x62D8, 0xA9EB},{0x62D9, 0xA9E5},{0x62DA, 0xA9E9},{0x62DB, 0xA9DB},{0x62DC, 0xABF4},{0x62EB, 0xCEDA},{0x62EC, 0xAC41},{0x62ED, 0xABF8}, + {0x62EE, 0xABFA},{0x62EF, 0xAC40},{0x62F0, 0xCEE6},{0x62F1, 0xABFD},{0x62F2, 0xD1B1},{0x62F3, 0xAEB1},{0x62F4, 0xAC43},{0x62F5, 0xCED7}, + {0x62F6, 0xCEDF},{0x62F7, 0xABFE},{0x62F8, 0xCEDE},{0x62F9, 0xCEDB},{0x62FA, 0xCEE3},{0x62FB, 0xCEE5},{0x62FC, 0xABF7},{0x62FD, 0xABFB}, + {0x62FE, 0xAC42},{0x62FF, 0xAEB3},{0x6300, 0xCEE0},{0x6301, 0xABF9},{0x6302, 0xAC45},{0x6303, 0xCED9},{0x6307, 0xABFC},{0x6308, 0xAEB2}, + {0x6309, 0xABF6},{0x630B, 0xCED6},{0x630C, 0xCEDD},{0x630D, 0xCED5},{0x630E, 0xCED8},{0x630F, 0xCEDC},{0x6310, 0xD1B2},{0x6311, 0xAC44}, + {0x6313, 0xCEE1},{0x6314, 0xCEE2},{0x6315, 0xCEE4},{0x6316, 0xABF5},{0x6328, 0xAEC1},{0x6329, 0xD1BE},{0x632A, 0xAEBF},{0x632B, 0xAEC0}, + {0x632C, 0xD1B4},{0x632D, 0xD1C4},{0x632F, 0xAEB6},{0x6332, 0xD566},{0x6333, 0xD1C6},{0x6334, 0xD1C0},{0x6336, 0xD1B7},{0x6338, 0xD1C9}, + {0x6339, 0xD1BA},{0x633A, 0xAEBC},{0x633B, 0xD57D},{0x633C, 0xD1BD},{0x633D, 0xAEBE},{0x633E, 0xAEB5},{0x6340, 0xD1CB},{0x6341, 0xD1BF}, + {0x6342, 0xAEB8},{0x6343, 0xD1B8},{0x6344, 0xD1B5},{0x6345, 0xD1B6},{0x6346, 0xAEB9},{0x6347, 0xD1C5},{0x6348, 0xD1CC},{0x6349, 0xAEBB}, + {0x634A, 0xD1BC},{0x634B, 0xD1BB},{0x634C, 0xAEC3},{0x634D, 0xAEC2},{0x634E, 0xAEB4},{0x634F, 0xAEBA},{0x6350, 0xAEBD},{0x6351, 0xD1C8}, + {0x6354, 0xD1C2},{0x6355, 0xAEB7},{0x6356, 0xD1B3},{0x6357, 0xD1CA},{0x6358, 0xD1C1},{0x6359, 0xD1C3},{0x635A, 0xD1C7},{0x6365, 0xD567}, + {0x6367, 0xB1B7},{0x6368, 0xB1CB},{0x6369, 0xB1CA},{0x636B, 0xB1BF},{0x636D, 0xD579},{0x636E, 0xD575},{0x636F, 0xD572},{0x6370, 0xD5A6}, + {0x6371, 0xB1BA},{0x6372, 0xB1B2},{0x6375, 0xD577},{0x6376, 0xB4A8},{0x6377, 0xB1B6},{0x6378, 0xD5A1},{0x637A, 0xB1CC},{0x637B, 0xB1C9}, + {0x637C, 0xD57B},{0x637D, 0xD56A},{0x6380, 0xB1C8},{0x6381, 0xD5A3},{0x6382, 0xD569},{0x6383, 0xB1BD},{0x6384, 0xB1C1},{0x6385, 0xD5A2}, + {0x6387, 0xD573},{0x6388, 0xB1C2},{0x6389, 0xB1BC},{0x638A, 0xD568},{0x638C, 0xB478},{0x638D, 0xD5A5},{0x638E, 0xD571},{0x638F, 0xB1C7}, + {0x6390, 0xD574},{0x6391, 0xD5A4},{0x6392, 0xB1C6},{0x6394, 0xD952},{0x6396, 0xB1B3},{0x6397, 0xD56F},{0x6398, 0xB1B8},{0x6399, 0xB1C3}, + {0x639B, 0xB1BE},{0x639C, 0xD578},{0x639D, 0xD56E},{0x639E, 0xD56C},{0x639F, 0xD57E},{0x63A0, 0xB1B0},{0x63A1, 0xB1C4},{0x63A2, 0xB1B4}, + {0x63A3, 0xB477},{0x63A4, 0xD57C},{0x63A5, 0xB1B5},{0x63A7, 0xB1B1},{0x63A8, 0xB1C0},{0x63A9, 0xB1BB},{0x63AA, 0xB1B9},{0x63AB, 0xD570}, + {0x63AC, 0xB1C5},{0x63AD, 0xD56D},{0x63AE, 0xD57A},{0x63AF, 0xD576},{0x63B0, 0xD954},{0x63B1, 0xD953},{0x63BD, 0xD56B},{0x63BE, 0xD964}, + {0x63C0, 0xB47A},{0x63C2, 0xD96A},{0x63C3, 0xD959},{0x63C4, 0xD967},{0x63C5, 0xDD77},{0x63C6, 0xB47D},{0x63C7, 0xD96B},{0x63C8, 0xD96E}, + {0x63C9, 0xB47C},{0x63CA, 0xD95C},{0x63CB, 0xD96D},{0x63CC, 0xD96C},{0x63CD, 0xB47E},{0x63CE, 0xD955},{0x63CF, 0xB479},{0x63D0, 0xB4A3}, + {0x63D2, 0xB4A1},{0x63D3, 0xD969},{0x63D5, 0xD95F},{0x63D6, 0xB4A5},{0x63D7, 0xD970},{0x63D8, 0xD968},{0x63D9, 0xD971},{0x63DA, 0xB4AD}, + {0x63DB, 0xB4AB},{0x63DC, 0xD966},{0x63DD, 0xD965},{0x63DF, 0xD963},{0x63E0, 0xD95D},{0x63E1, 0xB4A4},{0x63E3, 0xB4A2},{0x63E4, 0xD1B9}, + {0x63E5, 0xD956},{0x63E7, 0xDDB7},{0x63E8, 0xD957},{0x63E9, 0xB47B},{0x63EA, 0xB4AA},{0x63EB, 0xDD79},{0x63ED, 0xB4A6},{0x63EE, 0xB4A7}, + {0x63EF, 0xD958},{0x63F0, 0xD96F},{0x63F1, 0xDD78},{0x63F2, 0xD960},{0x63F3, 0xD95B},{0x63F4, 0xB4A9},{0x63F5, 0xD961},{0x63F6, 0xD95E}, + {0x63F9, 0xB4AE},{0x6406, 0xB770},{0x6409, 0xDD7C},{0x640A, 0xDDB1},{0x640B, 0xDDB6},{0x640C, 0xDDAA},{0x640D, 0xB76C},{0x640E, 0xDDBB}, + {0x640F, 0xB769},{0x6410, 0xDD7A},{0x6412, 0xDD7B},{0x6413, 0xB762},{0x6414, 0xB76B},{0x6415, 0xDDA4},{0x6416, 0xB76E},{0x6417, 0xB76F}, + {0x6418, 0xDDA5},{0x641A, 0xDDB2},{0x641B, 0xDDB8},{0x641C, 0xB76A},{0x641E, 0xB764},{0x641F, 0xDDA3},{0x6420, 0xDD7D},{0x6421, 0xDDBA}, + {0x6422, 0xDDA8},{0x6423, 0xDDA9},{0x6424, 0xDD7E},{0x6425, 0xDDB4},{0x6426, 0xDDAB},{0x6427, 0xDDB5},{0x6428, 0xDDAD},{0x642A, 0xB765}, + {0x642B, 0xE1D9},{0x642C, 0xB768},{0x642D, 0xB766},{0x642E, 0xDDB9},{0x642F, 0xDDB0},{0x6430, 0xDDAC},{0x6433, 0xDDA1},{0x6434, 0xBA53}, + {0x6435, 0xDDAF},{0x6436, 0xB76D},{0x6437, 0xDDA7},{0x6439, 0xDDA6},{0x643D, 0xB767},{0x643E, 0xB763},{0x643F, 0xE1EE},{0x6440, 0xDDB3}, + {0x6441, 0xDDAE},{0x6443, 0xDDA2},{0x644B, 0xE1E9},{0x644D, 0xE1DA},{0x644E, 0xE1E5},{0x6450, 0xE1EC},{0x6451, 0xBA51},{0x6452, 0xB4AC}, + {0x6453, 0xE1EA},{0x6454, 0xBA4C},{0x6458, 0xBA4B},{0x6459, 0xE1F1},{0x645B, 0xE1DB},{0x645C, 0xE1E8},{0x645D, 0xE1DC},{0x645E, 0xE1E7}, + {0x645F, 0xBA4F},{0x6460, 0xE1EB},{0x6461, 0xD962},{0x6465, 0xE1F2},{0x6466, 0xE1E3},{0x6467, 0xBA52},{0x6468, 0xE5BA},{0x6469, 0xBCAF}, + {0x646B, 0xE1F0},{0x646C, 0xE1EF},{0x646D, 0xBA54},{0x646E, 0xE5AD},{0x646F, 0xBCB0},{0x6470, 0xE5AE},{0x6472, 0xE1DF},{0x6473, 0xE1E0}, + {0x6474, 0xE1DD},{0x6475, 0xE1E2},{0x6476, 0xE1DE},{0x6477, 0xE1F3},{0x6478, 0xBA4E},{0x6479, 0xBCB1},{0x647A, 0xBA50},{0x647B, 0xBA55}, + {0x647D, 0xE1E1},{0x647F, 0xE1ED},{0x6482, 0xE1E6},{0x6485, 0xE5B1},{0x6487, 0xBA4A},{0x6488, 0xBCB4},{0x6489, 0xE9AA},{0x648A, 0xE5B6}, + {0x648B, 0xE5B5},{0x648C, 0xE5B7},{0x648F, 0xE5B4},{0x6490, 0xBCB5},{0x6492, 0xBCBB},{0x6493, 0xBCB8},{0x6495, 0xBCB9},{0x6496, 0xE5AF}, + {0x6497, 0xE5B2},{0x6498, 0xE5BC},{0x6499, 0xBCC1},{0x649A, 0xBCBF},{0x649C, 0xE5B3},{0x649D, 0xD95A},{0x649E, 0xBCB2},{0x649F, 0xE5B9}, + {0x64A0, 0xE5B0},{0x64A2, 0xBCC2},{0x64A3, 0xE5B8},{0x64A4, 0xBA4D},{0x64A5, 0xBCB7},{0x64A6, 0xE1E4},{0x64A9, 0xBCBA},{0x64AB, 0xBCBE}, + {0x64AC, 0xBCC0},{0x64AD, 0xBCBD},{0x64AE, 0xBCBC},{0x64B0, 0xBCB6},{0x64B1, 0xE5BB},{0x64B2, 0xBCB3},{0x64B3, 0xBCC3},{0x64BB, 0xBED8}, + {0x64BC, 0xBED9},{0x64BD, 0xE9A9},{0x64BE, 0xBEE2},{0x64BF, 0xBEDF},{0x64C1, 0xBED6},{0x64C2, 0xBEDD},{0x64C3, 0xE9AB},{0x64C4, 0xBEDB}, + {0x64C5, 0xBED5},{0x64C7, 0xBEDC},{0x64C9, 0xE9A8},{0x64CA, 0xC0BB},{0x64CB, 0xBED7},{0x64CD, 0xBEDE},{0x64CE, 0xC0BA},{0x64CF, 0xE9A7}, + {0x64D0, 0xE9A6},{0x64D2, 0xBEE0},{0x64D4, 0xBEE1},{0x64D6, 0xE9A5},{0x64D7, 0xE9A4},{0x64D8, 0xC0BC},{0x64D9, 0xE9AE},{0x64DA, 0xBEDA}, + {0x64DB, 0xE9AC},{0x64E0, 0xC0BD},{0x64E2, 0xC0C2},{0x64E3, 0xECEA},{0x64E4, 0xECEC},{0x64E6, 0xC0BF},{0x64E8, 0xECED},{0x64E9, 0xECE9}, + {0x64EB, 0xECEB},{0x64EC, 0xC0C0},{0x64ED, 0xC0C3},{0x64EF, 0xECE8},{0x64F0, 0xC0BE},{0x64F1, 0xC0C1},{0x64F2, 0xC259},{0x64F3, 0xE9AD}, + {0x64F4, 0xC258},{0x64F7, 0xC25E},{0x64F8, 0xEFD4},{0x64FA, 0xC25C},{0x64FB, 0xC25D},{0x64FC, 0xEFD7},{0x64FD, 0xEFD3},{0x64FE, 0xC25A}, + {0x64FF, 0xEFD1},{0x6500, 0xC36B},{0x6501, 0xEFD5},{0x6503, 0xEFD6},{0x6504, 0xEFD2},{0x6506, 0xC25B},{0x6507, 0xF242},{0x6509, 0xF245}, + {0x650C, 0xF246},{0x650D, 0xF244},{0x650E, 0xF247},{0x650F, 0xC36C},{0x6510, 0xF243},{0x6513, 0xF44E},{0x6514, 0xC464},{0x6515, 0xF44D}, + {0x6516, 0xF44C},{0x6517, 0xF44B},{0x6518, 0xC463},{0x6519, 0xC465},{0x651B, 0xF5CD},{0x651C, 0xC4E2},{0x651D, 0xC4E1},{0x6520, 0xF6E1}, + {0x6521, 0xF6E0},{0x6522, 0xF6E3},{0x6523, 0xC5CB},{0x6524, 0xC575},{0x6525, 0xF7DD},{0x6526, 0xF6E2},{0x6529, 0xF7DC},{0x652A, 0xC5CD}, + {0x652B, 0xC5CC},{0x652C, 0xC5F3},{0x652D, 0xF8A9},{0x652E, 0xF8EF},{0x652F, 0xA4E4},{0x6532, 0xD972},{0x6533, 0xE9AF},{0x6536, 0xA6AC}, + {0x6537, 0xCAF7},{0x6538, 0xA7F1},{0x6539, 0xA7EF},{0x653B, 0xA7F0},{0x653D, 0xCCC1},{0x653E, 0xA9F1},{0x653F, 0xAC46},{0x6541, 0xCEE7}, + {0x6543, 0xCEE8},{0x6545, 0xAC47},{0x6546, 0xD1CE},{0x6548, 0xAEC4},{0x6549, 0xAEC5},{0x654A, 0xD1CD},{0x654F, 0xB1D3},{0x6551, 0xB1CF}, + {0x6553, 0xD5A7},{0x6554, 0xB1D6},{0x6555, 0xB1D5},{0x6556, 0xB1CE},{0x6557, 0xB1D1},{0x6558, 0xB1D4},{0x6559, 0xB1D0},{0x655C, 0xD976}, + {0x655D, 0xB1CD},{0x655E, 0xB4AF},{0x6562, 0xB4B1},{0x6563, 0xB4B2},{0x6564, 0xD975},{0x6565, 0xD978},{0x6566, 0xB4B0},{0x6567, 0xD973}, + {0x6568, 0xD977},{0x656A, 0xD974},{0x656C, 0xB771},{0x656F, 0xDDBC},{0x6572, 0xBA56},{0x6573, 0xE1F4},{0x6574, 0xBEE3},{0x6575, 0xBCC4}, + {0x6576, 0xE5BD},{0x6577, 0xBCC5},{0x6578, 0xBCC6},{0x6579, 0xE5BF},{0x657A, 0xE5BE},{0x657B, 0xE5C0},{0x657C, 0xE9B1},{0x657F, 0xE9B0}, + {0x6580, 0xECEF},{0x6581, 0xECEE},{0x6582, 0xC0C4},{0x6583, 0xC0C5},{0x6584, 0xF248},{0x6587, 0xA4E5},{0x658C, 0xD979},{0x6590, 0xB4B4}, + {0x6591, 0xB4B3},{0x6592, 0xDDBD},{0x6594, 0xEFD8},{0x6595, 0xC4E3},{0x6596, 0xF7DE},{0x6597, 0xA4E6},{0x6599, 0xAEC6},{0x659B, 0xB1D8}, + {0x659C, 0xB1D7},{0x659D, 0xD97A},{0x659E, 0xD97B},{0x659F, 0xB772},{0x65A0, 0xE1F5},{0x65A1, 0xBA57},{0x65A2, 0xE9B2},{0x65A4, 0xA4E7}, + {0x65A5, 0xA5B8},{0x65A7, 0xA9F2},{0x65A8, 0xCCC2},{0x65AA, 0xCEE9},{0x65AB, 0xAC48},{0x65AC, 0xB1D9},{0x65AE, 0xD97C},{0x65AF, 0xB4B5}, + {0x65B0, 0xB773},{0x65B2, 0xE5C1},{0x65B3, 0xE5C2},{0x65B6, 0xECF0},{0x65B7, 0xC25F},{0x65B8, 0xF8F0},{0x65B9, 0xA4E8},{0x65BB, 0xCCC3}, + {0x65BC, 0xA9F3},{0x65BD, 0xAC49},{0x65BF, 0xCEEA},{0x65C1, 0xAEC7},{0x65C2, 0xD1D2},{0x65C3, 0xD1D0},{0x65C4, 0xD1D1},{0x65C5, 0xAEC8}, + {0x65C6, 0xD1CF},{0x65CB, 0xB1DB},{0x65CC, 0xB1DC},{0x65CD, 0xD5A8},{0x65CE, 0xB1DD},{0x65CF, 0xB1DA},{0x65D0, 0xD97D},{0x65D2, 0xD97E}, + {0x65D3, 0xDDBE},{0x65D6, 0xBA59},{0x65D7, 0xBA58},{0x65DA, 0xECF1},{0x65DB, 0xEFD9},{0x65DD, 0xF24A},{0x65DE, 0xF249},{0x65DF, 0xF44F}, + {0x65E1, 0xC95E},{0x65E2, 0xAC4A},{0x65E5, 0xA4E9},{0x65E6, 0xA5B9},{0x65E8, 0xA6AE},{0x65E9, 0xA6AD},{0x65EC, 0xA6AF},{0x65ED, 0xA6B0}, + {0x65EE, 0xC9EE},{0x65EF, 0xC9ED},{0x65F0, 0xCAF8},{0x65F1, 0xA7F2},{0x65F2, 0xCAFB},{0x65F3, 0xCAFA},{0x65F4, 0xCAF9},{0x65F5, 0xCAFC}, + {0x65FA, 0xA9F4},{0x65FB, 0xCCC9},{0x65FC, 0xCCC5},{0x65FD, 0xCCCE},{0x6600, 0xA9FB},{0x6602, 0xA9F9},{0x6603, 0xCCCA},{0x6604, 0xCCC6}, + {0x6605, 0xCCCD},{0x6606, 0xA9F8},{0x6607, 0xAA40},{0x6608, 0xCCC8},{0x6609, 0xCCC4},{0x660A, 0xA9FE},{0x660B, 0xCCCB},{0x660C, 0xA9F7}, + {0x660D, 0xCCCC},{0x660E, 0xA9FA},{0x660F, 0xA9FC},{0x6610, 0xCCD0},{0x6611, 0xCCCF},{0x6612, 0xCCC7},{0x6613, 0xA9F6},{0x6614, 0xA9F5}, + {0x6615, 0xA9FD},{0x661C, 0xCEEF},{0x661D, 0xCEF5},{0x661F, 0xAC50},{0x6620, 0xAC4D},{0x6621, 0xCEEC},{0x6622, 0xCEF1},{0x6624, 0xAC53}, + {0x6625, 0xAC4B},{0x6626, 0xCEF0},{0x6627, 0xAC4E},{0x6628, 0xAC51},{0x662B, 0xCEF3},{0x662D, 0xAC4C},{0x662E, 0xCEF8},{0x662F, 0xAC4F}, + {0x6631, 0xAC52},{0x6632, 0xCEED},{0x6633, 0xCEF2},{0x6634, 0xCEF6},{0x6635, 0xCEEE},{0x6636, 0xCEEB},{0x6639, 0xCEF7},{0x663A, 0xCEF4}, + {0x6641, 0xAED0},{0x6642, 0xAEC9},{0x6643, 0xAECC},{0x6645, 0xAECF},{0x6647, 0xD1D5},{0x6649, 0xAECA},{0x664A, 0xD1D3},{0x664C, 0xAECE}, + {0x664F, 0xAECB},{0x6651, 0xD1D6},{0x6652, 0xAECD},{0x6659, 0xD5AC},{0x665A, 0xB1DF},{0x665B, 0xD5AB},{0x665C, 0xD5AD},{0x665D, 0xB1DE}, + {0x665E, 0xB1E3},{0x665F, 0xD1D4},{0x6661, 0xD5AA},{0x6662, 0xD5AE},{0x6664, 0xB1E0},{0x6665, 0xD5A9},{0x6666, 0xB1E2},{0x6668, 0xB1E1}, + {0x666A, 0xD9A7},{0x666C, 0xD9A2},{0x666E, 0xB4B6},{0x666F, 0xB4BA},{0x6670, 0xB4B7},{0x6671, 0xD9A5},{0x6672, 0xD9A8},{0x6674, 0xB4B8}, + {0x6676, 0xB4B9},{0x6677, 0xB4BE},{0x6678, 0xDDC7},{0x6679, 0xD9A6},{0x667A, 0xB4BC},{0x667B, 0xD9A3},{0x667C, 0xD9A1},{0x667E, 0xB4BD}, + {0x6680, 0xD9A4},{0x6684, 0xB779},{0x6686, 0xDDBF},{0x6687, 0xB776},{0x6688, 0xB777},{0x6689, 0xB775},{0x668A, 0xDDC4},{0x668B, 0xDDC3}, + {0x668C, 0xDDC0},{0x668D, 0xB77B},{0x6690, 0xDDC2},{0x6691, 0xB4BB},{0x6694, 0xDDC6},{0x6695, 0xDDC1},{0x6696, 0xB778},{0x6697, 0xB774}, + {0x6698, 0xB77A},{0x6699, 0xDDC5},{0x669D, 0xBA5C},{0x669F, 0xE1F8},{0x66A0, 0xE1F7},{0x66A1, 0xE1F6},{0x66A2, 0xBA5A},{0x66A8, 0xBA5B}, + {0x66A9, 0xE5C5},{0x66AA, 0xE5C8},{0x66AB, 0xBCC8},{0x66AE, 0xBCC7},{0x66AF, 0xE5C9},{0x66B0, 0xE5C4},{0x66B1, 0xBCCA},{0x66B2, 0xE5C6}, + {0x66B4, 0xBCC9},{0x66B5, 0xE5C3},{0x66B7, 0xE5C7},{0x66B8, 0xBEE9},{0x66B9, 0xBEE6},{0x66BA, 0xE9BB},{0x66BB, 0xE9BA},{0x66BD, 0xE9B9}, + {0x66BE, 0xE9B4},{0x66C0, 0xE9B5},{0x66C4, 0xBEE7},{0x66C6, 0xBEE4},{0x66C7, 0xBEE8},{0x66C8, 0xE9B3},{0x66C9, 0xBEE5},{0x66CA, 0xE9B6}, + {0x66CB, 0xE9B7},{0x66CC, 0xE9BC},{0x66CF, 0xE9B8},{0x66D2, 0xECF2},{0x66D6, 0xC0C7},{0x66D8, 0xEFDC},{0x66D9, 0xC0C6},{0x66DA, 0xEFDA}, + {0x66DB, 0xEFDB},{0x66DC, 0xC260},{0x66DD, 0xC36E},{0x66DE, 0xF24B},{0x66E0, 0xC36D},{0x66E3, 0xF451},{0x66E4, 0xF452},{0x66E6, 0xC466}, + {0x66E8, 0xF450},{0x66E9, 0xC4E4},{0x66EB, 0xF7DF},{0x66EC, 0xC5CE},{0x66ED, 0xF8AA},{0x66EE, 0xF8AB},{0x66F0, 0xA4EA},{0x66F2, 0xA6B1}, + {0x66F3, 0xA6B2},{0x66F4, 0xA7F3},{0x66F6, 0xCCD1},{0x66F7, 0xAC54},{0x66F8, 0xAED1},{0x66F9, 0xB1E4},{0x66FC, 0xB0D2},{0x66FE, 0xB4BF}, + {0x66FF, 0xB4C0},{0x6700, 0xB3CC},{0x6701, 0xD9A9},{0x6703, 0xB77C},{0x6704, 0xE1FA},{0x6705, 0xE1F9},{0x6708, 0xA4EB},{0x6709, 0xA6B3}, + {0x670A, 0xCCD2},{0x670B, 0xAA42},{0x670D, 0xAA41},{0x670F, 0xCEF9},{0x6710, 0xCEFA},{0x6712, 0xD1D7},{0x6713, 0xD1D8},{0x6714, 0xAED2}, + {0x6715, 0xAED3},{0x6717, 0xAED4},{0x6718, 0xD5AF},{0x671B, 0xB1E6},{0x671D, 0xB4C2},{0x671F, 0xB4C1},{0x6720, 0xDDC8},{0x6721, 0xDF7A}, + {0x6722, 0xE1FB},{0x6723, 0xE9BD},{0x6726, 0xC261},{0x6727, 0xC467},{0x6728, 0xA4EC},{0x672A, 0xA5BC},{0x672B, 0xA5BD},{0x672C, 0xA5BB}, + {0x672D, 0xA5BE},{0x672E, 0xA5BA},{0x6731, 0xA6B6},{0x6733, 0xC9F6},{0x6734, 0xA6B5},{0x6735, 0xA6B7},{0x6738, 0xC9F1},{0x6739, 0xC9F0}, + {0x673A, 0xC9F3},{0x673B, 0xC9F2},{0x673C, 0xC9F5},{0x673D, 0xA6B4},{0x673E, 0xC9EF},{0x673F, 0xC9F4},{0x6745, 0xCAFD},{0x6746, 0xA7FD}, + {0x6747, 0xCAFE},{0x6748, 0xCB43},{0x6749, 0xA7FC},{0x674B, 0xCB47},{0x674C, 0xCB42},{0x674D, 0xCB45},{0x674E, 0xA7F5},{0x674F, 0xA7F6}, + {0x6750, 0xA7F7},{0x6751, 0xA7F8},{0x6753, 0xA840},{0x6755, 0xCB41},{0x6756, 0xA7FA},{0x6757, 0xA841},{0x6759, 0xCB40},{0x675A, 0xCB46}, + {0x675C, 0xA7F9},{0x675D, 0xCB44},{0x675E, 0xA7FB},{0x675F, 0xA7F4},{0x6760, 0xA7FE},{0x676A, 0xAA57},{0x676C, 0xCCD4},{0x676D, 0xAA43}, + {0x676F, 0xAA4D},{0x6770, 0xAA4E},{0x6771, 0xAA46},{0x6772, 0xAA58},{0x6773, 0xAA48},{0x6774, 0xCCDC},{0x6775, 0xAA53},{0x6776, 0xCCD7}, + {0x6777, 0xAA49},{0x6778, 0xCCE6},{0x6779, 0xCCE7},{0x677A, 0xCCDF},{0x677B, 0xCCD8},{0x677C, 0xAA56},{0x677D, 0xCCE4},{0x677E, 0xAA51}, + {0x677F, 0xAA4F},{0x6781, 0xCCE5},{0x6783, 0xCCE3},{0x6784, 0xCCDB},{0x6785, 0xCCD3},{0x6786, 0xCCDA},{0x6787, 0xAA4A},{0x6789, 0xAA50}, + {0x678B, 0xAA44},{0x678C, 0xCCDE},{0x678D, 0xCCDD},{0x678E, 0xCCD5},{0x6790, 0xAA52},{0x6791, 0xCCE1},{0x6792, 0xCCD6},{0x6793, 0xAA55}, + {0x6794, 0xCCE8},{0x6795, 0xAA45},{0x6797, 0xAA4C},{0x6798, 0xCCD9},{0x6799, 0xCCE2},{0x679A, 0xAA54},{0x679C, 0xAA47},{0x679D, 0xAA4B}, + {0x679F, 0xCCE0},{0x67AE, 0xCF5B},{0x67AF, 0xAC5C},{0x67B0, 0xAC69},{0x67B2, 0xCF56},{0x67B3, 0xCF4C},{0x67B4, 0xAC62},{0x67B5, 0xCF4A}, + {0x67B6, 0xAC5B},{0x67B7, 0xCF45},{0x67B8, 0xAC65},{0x67B9, 0xCF52},{0x67BA, 0xCEFE},{0x67BB, 0xCF41},{0x67C0, 0xCF44},{0x67C1, 0xCEFB}, + {0x67C2, 0xCF51},{0x67C3, 0xCF61},{0x67C4, 0xAC60},{0x67C5, 0xCF46},{0x67C6, 0xCF58},{0x67C8, 0xCEFD},{0x67C9, 0xCF5F},{0x67CA, 0xCF60}, + {0x67CB, 0xCF63},{0x67CC, 0xCF5A},{0x67CD, 0xCF4B},{0x67CE, 0xCF53},{0x67CF, 0xAC66},{0x67D0, 0xAC59},{0x67D1, 0xAC61},{0x67D2, 0xAC6D}, + {0x67D3, 0xAC56},{0x67D4, 0xAC58},{0x67D8, 0xCF43},{0x67D9, 0xAC6A},{0x67DA, 0xAC63},{0x67DB, 0xCF5D},{0x67DC, 0xCF40},{0x67DD, 0xAC6C}, + {0x67DE, 0xAC67},{0x67DF, 0xCF49},{0x67E2, 0xAC6B},{0x67E3, 0xCF50},{0x67E4, 0xCF48},{0x67E5, 0xAC64},{0x67E6, 0xCF5C},{0x67E7, 0xCF54}, + {0x67E9, 0xAC5E},{0x67EA, 0xCF62},{0x67EB, 0xCF47},{0x67EC, 0xAC5A},{0x67ED, 0xCF59},{0x67EE, 0xCF4F},{0x67EF, 0xAC5F},{0x67F0, 0xCF55}, + {0x67F1, 0xAC57},{0x67F2, 0xCEFC},{0x67F3, 0xAC68},{0x67F4, 0xAEE3},{0x67F5, 0xAC5D},{0x67F6, 0xCF4E},{0x67F7, 0xCF4D},{0x67F8, 0xCF42}, + {0x67FA, 0xCF5E},{0x67FC, 0xCF57},{0x67FF, 0xAC55},{0x6812, 0xD1EC},{0x6813, 0xAEEA},{0x6814, 0xD1ED},{0x6816, 0xD1E1},{0x6817, 0xAEDF}, + {0x6818, 0xAEEB},{0x681A, 0xD1DA},{0x681C, 0xD1E3},{0x681D, 0xD1EB},{0x681F, 0xD1D9},{0x6820, 0xD1F4},{0x6821, 0xAED5},{0x6825, 0xD1F3}, + {0x6826, 0xD1EE},{0x6828, 0xD1EF},{0x6829, 0xAEDD},{0x682A, 0xAEE8},{0x682B, 0xD1E5},{0x682D, 0xD1E6},{0x682E, 0xD1F0},{0x682F, 0xD1E7}, + {0x6831, 0xD1E2},{0x6832, 0xD1DC},{0x6833, 0xD1DD},{0x6834, 0xD1EA},{0x6835, 0xD1E4},{0x6838, 0xAED6},{0x6839, 0xAEDA},{0x683A, 0xD1F2}, + {0x683B, 0xD1DE},{0x683C, 0xAEE6},{0x683D, 0xAEE2},{0x6840, 0xAEE5},{0x6841, 0xAEEC},{0x6842, 0xAEDB},{0x6843, 0xAEE7},{0x6844, 0xD1E9}, + {0x6845, 0xAEE9},{0x6846, 0xAED8},{0x6848, 0xAED7},{0x6849, 0xD1DB},{0x684B, 0xD1DF},{0x684C, 0xAEE0},{0x684D, 0xD1F1},{0x684E, 0xD1E8}, + {0x684F, 0xD1E0},{0x6850, 0xAEE4},{0x6851, 0xAEE1},{0x6853, 0xAED9},{0x6854, 0xAEDC},{0x686B, 0xD5C4},{0x686D, 0xD5B4},{0x686E, 0xD5B5}, + {0x686F, 0xD5B9},{0x6871, 0xD5C8},{0x6872, 0xD5C5},{0x6874, 0xD5BE},{0x6875, 0xD5BD},{0x6876, 0xB1ED},{0x6877, 0xD5C1},{0x6878, 0xD5D0}, + {0x6879, 0xD5B0},{0x687B, 0xD5D1},{0x687C, 0xD5C3},{0x687D, 0xD5D5},{0x687E, 0xD5C9},{0x687F, 0xB1EC},{0x6880, 0xD5C7},{0x6881, 0xB1E7}, + {0x6882, 0xB1FC},{0x6883, 0xB1F2},{0x6885, 0xB1F6},{0x6886, 0xB1F5},{0x6887, 0xD5B1},{0x6889, 0xD5CE},{0x688A, 0xD5D4},{0x688B, 0xD5CC}, + {0x688C, 0xD5D3},{0x688F, 0xD5C0},{0x6890, 0xD5B2},{0x6891, 0xD5D2},{0x6892, 0xD5C2},{0x6893, 0xB1EA},{0x6894, 0xB1F7},{0x6896, 0xD5CB}, + {0x6897, 0xB1F0},{0x689B, 0xD5CA},{0x689C, 0xD5B3},{0x689D, 0xB1F8},{0x689F, 0xB1FA},{0x68A0, 0xD5CD},{0x68A1, 0xB1FB},{0x68A2, 0xB1E9}, + {0x68A3, 0xD5BA},{0x68A4, 0xD5CF},{0x68A7, 0xB1EF},{0x68A8, 0xB1F9},{0x68A9, 0xD5BC},{0x68AA, 0xD5C6},{0x68AB, 0xD5B7},{0x68AC, 0xD5BB}, + {0x68AD, 0xB1F4},{0x68AE, 0xD5B6},{0x68AF, 0xB1E8},{0x68B0, 0xB1F1},{0x68B1, 0xB1EE},{0x68B2, 0xD5BF},{0x68B3, 0xAEDE},{0x68B4, 0xD9C0}, + {0x68B5, 0xB1EB},{0x68C4, 0xB1F3},{0x68C6, 0xD9C3},{0x68C7, 0xD9D9},{0x68C8, 0xD9CE},{0x68C9, 0xB4D6},{0x68CB, 0xB4D1},{0x68CC, 0xD9BD}, + {0x68CD, 0xB4D2},{0x68CE, 0xD9CD},{0x68D0, 0xD9C6},{0x68D1, 0xD9D3},{0x68D2, 0xB4CE},{0x68D3, 0xD9AB},{0x68D4, 0xD9D5},{0x68D5, 0xB4C4}, + {0x68D6, 0xD9B3},{0x68D7, 0xB4C7},{0x68D8, 0xB4C6},{0x68DA, 0xB4D7},{0x68DC, 0xD9AD},{0x68DD, 0xD9CF},{0x68DE, 0xD9D0},{0x68DF, 0xB4C9}, + {0x68E0, 0xB4C5},{0x68E1, 0xD9BB},{0x68E3, 0xB4D0},{0x68E4, 0xD9B6},{0x68E6, 0xD9D1},{0x68E7, 0xB4CC},{0x68E8, 0xD9C9},{0x68E9, 0xD9D6}, + {0x68EA, 0xD9B0},{0x68EB, 0xD9B5},{0x68EC, 0xD9AF},{0x68EE, 0xB4CB},{0x68EF, 0xD9C2},{0x68F0, 0xDDDE},{0x68F1, 0xD9B1},{0x68F2, 0xB4CF}, + {0x68F3, 0xD9BA},{0x68F4, 0xD9D2},{0x68F5, 0xB4CA},{0x68F6, 0xD9B7},{0x68F7, 0xD9B4},{0x68F8, 0xD9C5},{0x68F9, 0xB4CD},{0x68FA, 0xB4C3}, + {0x68FB, 0xB4D9},{0x68FC, 0xD9C8},{0x68FD, 0xD9C7},{0x6904, 0xD9AC},{0x6905, 0xB4C8},{0x6906, 0xD9D4},{0x6907, 0xD9BC},{0x6908, 0xD9BE}, + {0x690A, 0xD9CB},{0x690B, 0xD9CA},{0x690C, 0xD9AA},{0x690D, 0xB4D3},{0x690E, 0xB4D5},{0x690F, 0xD9B2},{0x6910, 0xD9B9},{0x6911, 0xD9C1}, + {0x6912, 0xB4D4},{0x6913, 0xD9B8},{0x6914, 0xD9C4},{0x6915, 0xD9D7},{0x6917, 0xD9CC},{0x6925, 0xD9D8},{0x692A, 0xD9AE},{0x692F, 0xDDF2}, + {0x6930, 0xB7A6},{0x6932, 0xDDF0},{0x6933, 0xDDDB},{0x6934, 0xDDE0},{0x6935, 0xDDD9},{0x6937, 0xDDEC},{0x6938, 0xDDCB},{0x6939, 0xDDD2}, + {0x693B, 0xDDEA},{0x693C, 0xDDF4},{0x693D, 0xDDDC},{0x693F, 0xDDCF},{0x6940, 0xDDE2},{0x6941, 0xDDE7},{0x6942, 0xDDD3},{0x6944, 0xDDE4}, + {0x6945, 0xDDD0},{0x6948, 0xDDD7},{0x6949, 0xDDD8},{0x694A, 0xB7A8},{0x694B, 0xDDEB},{0x694C, 0xDDE9},{0x694E, 0xDDCC},{0x694F, 0xDDEE}, + {0x6951, 0xDDEF},{0x6952, 0xDDF1},{0x6953, 0xB7AC},{0x6954, 0xB7A4},{0x6956, 0xD5B8},{0x6957, 0xDDD4},{0x6958, 0xDDE6},{0x6959, 0xDDD5}, + {0x695A, 0xB7A1},{0x695B, 0xB7B1},{0x695C, 0xDDED},{0x695D, 0xB7AF},{0x695E, 0xB7AB},{0x695F, 0xDDCA},{0x6960, 0xB7A3},{0x6962, 0xDDCD}, + {0x6963, 0xB7B0},{0x6965, 0xDDDD},{0x6966, 0xDDC9},{0x6968, 0xB7A9},{0x6969, 0xDDE1},{0x696A, 0xDDD1},{0x696B, 0xB7AA},{0x696C, 0xDDDA}, + {0x696D, 0xB77E},{0x696E, 0xB4D8},{0x696F, 0xDDE3},{0x6970, 0xD9BF},{0x6971, 0xDDCE},{0x6974, 0xDDE8},{0x6975, 0xB7A5},{0x6976, 0xDDE5}, + {0x6977, 0xB7A2},{0x6978, 0xDDDF},{0x6979, 0xB7AD},{0x697A, 0xDDD6},{0x697B, 0xDDF3},{0x6982, 0xB7A7},{0x6983, 0xDEC6},{0x6986, 0xB7AE}, + {0x698D, 0xE24A},{0x698E, 0xE248},{0x6990, 0xE25E},{0x6991, 0xE246},{0x6993, 0xE258},{0x6994, 0xB77D},{0x6995, 0xBA5F},{0x6996, 0xE242}, + {0x6997, 0xE25D},{0x6999, 0xE247},{0x699A, 0xE255},{0x699B, 0xBA64},{0x699C, 0xBA5D},{0x699E, 0xE25B},{0x69A0, 0xE240},{0x69A1, 0xE25A}, + {0x69A3, 0xBA6F},{0x69A4, 0xE251},{0x69A5, 0xE261},{0x69A6, 0xBA6D},{0x69A7, 0xE249},{0x69A8, 0xBA5E},{0x69A9, 0xE24B},{0x69AA, 0xE259}, + {0x69AB, 0xBA67},{0x69AC, 0xE244},{0x69AD, 0xBA6B},{0x69AE, 0xBA61},{0x69AF, 0xE24D},{0x69B0, 0xE243},{0x69B1, 0xE1FC},{0x69B3, 0xE257}, + {0x69B4, 0xBA68},{0x69B5, 0xE260},{0x69B6, 0xE1FD},{0x69B7, 0xBA65},{0x69B9, 0xE253},{0x69BB, 0xBA66},{0x69BC, 0xE245},{0x69BD, 0xE250}, + {0x69BE, 0xE24C},{0x69BF, 0xE24E},{0x69C1, 0xBA60},{0x69C2, 0xE25F},{0x69C3, 0xBA6E},{0x69C4, 0xE24F},{0x69C6, 0xE262},{0x69C9, 0xE1FE}, + {0x69CA, 0xE254},{0x69CB, 0xBA63},{0x69CC, 0xBA6C},{0x69CD, 0xBA6A},{0x69CE, 0xE241},{0x69CF, 0xE256},{0x69D0, 0xBA69},{0x69D3, 0xBA62}, + {0x69D4, 0xE252},{0x69D9, 0xE25C},{0x69E2, 0xE5D5},{0x69E4, 0xE5D1},{0x69E5, 0xE5CD},{0x69E6, 0xE5E1},{0x69E7, 0xE5DE},{0x69E8, 0xBCCD}, + {0x69EB, 0xE5E5},{0x69EC, 0xE5D4},{0x69ED, 0xBCD8},{0x69EE, 0xE5DB},{0x69F1, 0xE5D0},{0x69F2, 0xE5DA},{0x69F3, 0xBCD5},{0x69F4, 0xE5EE}, + {0x69F6, 0xE5EB},{0x69F7, 0xE5DD},{0x69F8, 0xE5CE},{0x69FB, 0xE5E2},{0x69FC, 0xE5E4},{0x69FD, 0xBCD1},{0x69FE, 0xE5D8},{0x69FF, 0xE5D3}, + {0x6A00, 0xE5CA},{0x6A01, 0xBCCE},{0x6A02, 0xBCD6},{0x6A04, 0xE5E7},{0x6A05, 0xBCD7},{0x6A06, 0xE5CB},{0x6A07, 0xE5ED},{0x6A08, 0xE5E0}, + {0x6A09, 0xE5E6},{0x6A0A, 0xBCD4},{0x6A0D, 0xE5E3},{0x6A0F, 0xE5EA},{0x6A11, 0xBCD9},{0x6A13, 0xBCD3},{0x6A14, 0xE5DC},{0x6A15, 0xE5CF}, + {0x6A16, 0xE5EF},{0x6A17, 0xE5CC},{0x6A18, 0xE5E8},{0x6A19, 0xBCD0},{0x6A1B, 0xE5D6},{0x6A1D, 0xE5D7},{0x6A1E, 0xBCCF},{0x6A1F, 0xBCCC}, + {0x6A20, 0xE5D2},{0x6A21, 0xBCD2},{0x6A23, 0xBCCB},{0x6A25, 0xE5E9},{0x6A26, 0xE5EC},{0x6A27, 0xE5D9},{0x6A28, 0xE9CA},{0x6A32, 0xE9C2}, + {0x6A34, 0xE9BE},{0x6A35, 0xBEF6},{0x6A38, 0xBEEB},{0x6A39, 0xBEF0},{0x6A3A, 0xBEEC},{0x6A3B, 0xE9CC},{0x6A3C, 0xE9D7},{0x6A3D, 0xBEEA}, + {0x6A3E, 0xE9C4},{0x6A3F, 0xE9CD},{0x6A40, 0xE5DF},{0x6A41, 0xE9CE},{0x6A44, 0xBEF1},{0x6A46, 0xE9DD},{0x6A47, 0xBEF5},{0x6A48, 0xBEF8}, + {0x6A49, 0xE9C0},{0x6A4B, 0xBEF4},{0x6A4D, 0xE9DB},{0x6A4E, 0xE9DC},{0x6A4F, 0xE9D2},{0x6A50, 0xE9D1},{0x6A51, 0xE9C9},{0x6A54, 0xE9D3}, + {0x6A55, 0xE9DA},{0x6A56, 0xE9D9},{0x6A58, 0xBEEF},{0x6A59, 0xBEED},{0x6A5A, 0xE9CB},{0x6A5B, 0xE9C8},{0x6A5D, 0xE9C5},{0x6A5E, 0xE9D8}, + {0x6A5F, 0xBEF7},{0x6A60, 0xE9D6},{0x6A61, 0xBEF3},{0x6A62, 0xBEF2},{0x6A64, 0xE9D0},{0x6A66, 0xE9BF},{0x6A67, 0xE9C1},{0x6A68, 0xE9C3}, + {0x6A69, 0xE9D5},{0x6A6A, 0xE9CF},{0x6A6B, 0xBEEE},{0x6A6D, 0xE9C6},{0x6A6F, 0xE9D4},{0x6A76, 0xE9C7},{0x6A7E, 0xC0CF},{0x6A7F, 0xED45}, + {0x6A80, 0xC0C8},{0x6A81, 0xECF5},{0x6A83, 0xED41},{0x6A84, 0xC0CA},{0x6A85, 0xED48},{0x6A87, 0xECFC},{0x6A89, 0xECF7},{0x6A8C, 0xED49}, + {0x6A8D, 0xECF3},{0x6A8E, 0xECFE},{0x6A90, 0xC0D1},{0x6A91, 0xED44},{0x6A92, 0xED4A},{0x6A93, 0xECFD},{0x6A94, 0xC0C9},{0x6A95, 0xED40}, + {0x6A96, 0xECF4},{0x6A97, 0xC0D0},{0x6A9A, 0xED47},{0x6A9B, 0xECF9},{0x6A9C, 0xC0CC},{0x6A9E, 0xECFB},{0x6A9F, 0xECF8},{0x6AA0, 0xC0D2}, + {0x6AA1, 0xECFA},{0x6AA2, 0xC0CB},{0x6AA3, 0xC0CE},{0x6AA4, 0xED43},{0x6AA5, 0xECF6},{0x6AA6, 0xED46},{0x6AA8, 0xED42},{0x6AAC, 0xC263}, + {0x6AAD, 0xEFE7},{0x6AAE, 0xC268},{0x6AAF, 0xC269},{0x6AB3, 0xC262},{0x6AB4, 0xEFE6},{0x6AB6, 0xEFE3},{0x6AB7, 0xEFE4},{0x6AB8, 0xC266}, + {0x6AB9, 0xEFDE},{0x6ABA, 0xEFE2},{0x6ABB, 0xC265},{0x6ABD, 0xEFDF},{0x6AC2, 0xC267},{0x6AC3, 0xC264},{0x6AC5, 0xEFDD},{0x6AC6, 0xEFE1}, + {0x6AC7, 0xEFE5},{0x6ACB, 0xF251},{0x6ACC, 0xF24E},{0x6ACD, 0xF257},{0x6ACF, 0xF256},{0x6AD0, 0xF254},{0x6AD1, 0xF24F},{0x6AD3, 0xC372}, + {0x6AD9, 0xF250},{0x6ADA, 0xC371},{0x6ADB, 0xC0CD},{0x6ADC, 0xF253},{0x6ADD, 0xC370},{0x6ADE, 0xF258},{0x6ADF, 0xF252},{0x6AE0, 0xF24D}, + {0x6AE1, 0xEFE0},{0x6AE5, 0xC36F},{0x6AE7, 0xF24C},{0x6AE8, 0xF456},{0x6AEA, 0xF455},{0x6AEB, 0xF255},{0x6AEC, 0xC468},{0x6AEE, 0xF459}, + {0x6AEF, 0xF45A},{0x6AF0, 0xF454},{0x6AF1, 0xF458},{0x6AF3, 0xF453},{0x6AF8, 0xF5D1},{0x6AF9, 0xF457},{0x6AFA, 0xC4E7},{0x6AFB, 0xC4E5}, + {0x6AFC, 0xF5CF},{0x6B00, 0xF5D2},{0x6B02, 0xF5CE},{0x6B03, 0xF5D0},{0x6B04, 0xC4E6},{0x6B08, 0xF6E5},{0x6B09, 0xF6E6},{0x6B0A, 0xC576}, + {0x6B0B, 0xF6E4},{0x6B0F, 0xF7E2},{0x6B10, 0xC5CF},{0x6B11, 0xF7E0},{0x6B12, 0xF7E1},{0x6B13, 0xF8AC},{0x6B16, 0xC656},{0x6B17, 0xF8F3}, + {0x6B18, 0xF8F1},{0x6B19, 0xF8F2},{0x6B1A, 0xF8F4},{0x6B1E, 0xF9BB},{0x6B20, 0xA4ED},{0x6B21, 0xA6B8},{0x6B23, 0xAA59},{0x6B25, 0xCCE9}, + {0x6B28, 0xCF64},{0x6B2C, 0xD1F5},{0x6B2D, 0xD1F7},{0x6B2F, 0xD1F6},{0x6B31, 0xD1F8},{0x6B32, 0xB1FD},{0x6B33, 0xD5D7},{0x6B34, 0xD1F9}, + {0x6B36, 0xD5D6},{0x6B37, 0xD5D8},{0x6B38, 0xD5D9},{0x6B39, 0xD9DA},{0x6B3A, 0xB4DB},{0x6B3B, 0xD9DB},{0x6B3C, 0xD9DD},{0x6B3D, 0xB4DC}, + {0x6B3E, 0xB4DA},{0x6B3F, 0xD9DC},{0x6B41, 0xDDFA},{0x6B42, 0xDDF8},{0x6B43, 0xDDF7},{0x6B45, 0xDDF6},{0x6B46, 0xDDF5},{0x6B47, 0xB7B2}, + {0x6B48, 0xDDF9},{0x6B49, 0xBA70},{0x6B4A, 0xE263},{0x6B4B, 0xE265},{0x6B4C, 0xBA71},{0x6B4D, 0xE264},{0x6B4E, 0xBCDB},{0x6B50, 0xBCDA}, + {0x6B51, 0xE5F0},{0x6B54, 0xE9DF},{0x6B55, 0xE9DE},{0x6B56, 0xE9E0},{0x6B59, 0xBEF9},{0x6B5B, 0xED4B},{0x6B5C, 0xC0D3},{0x6B5E, 0xEFE8}, + {0x6B5F, 0xC26A},{0x6B60, 0xF259},{0x6B61, 0xC577},{0x6B62, 0xA4EE},{0x6B63, 0xA5BF},{0x6B64, 0xA6B9},{0x6B65, 0xA842},{0x6B66, 0xAA5A}, + {0x6B67, 0xAA5B},{0x6B6A, 0xAC6E},{0x6B6D, 0xD1FA},{0x6B72, 0xB7B3},{0x6B76, 0xE6D1},{0x6B77, 0xBEFA},{0x6B78, 0xC26B},{0x6B79, 0xA4EF}, + {0x6B7B, 0xA6BA},{0x6B7E, 0xCCEB},{0x6B7F, 0xAA5C},{0x6B80, 0xCCEA},{0x6B82, 0xCF65},{0x6B83, 0xAC6F},{0x6B84, 0xCF66},{0x6B86, 0xAC70}, + {0x6B88, 0xD1FC},{0x6B89, 0xAEEE},{0x6B8A, 0xAEED},{0x6B8C, 0xD5DE},{0x6B8D, 0xD5DC},{0x6B8E, 0xD5DD},{0x6B8F, 0xD5DB},{0x6B91, 0xD5DA}, + {0x6B94, 0xD9DE},{0x6B95, 0xD9E1},{0x6B96, 0xB4DE},{0x6B97, 0xD9DF},{0x6B98, 0xB4DD},{0x6B99, 0xD9E0},{0x6B9B, 0xDDFB},{0x6B9E, 0xE266}, + {0x6B9F, 0xE267},{0x6BA0, 0xE268},{0x6BA2, 0xE5F3},{0x6BA3, 0xE5F2},{0x6BA4, 0xBCDC},{0x6BA5, 0xE5F1},{0x6BA6, 0xE5F4},{0x6BA7, 0xE9E1}, + {0x6BAA, 0xE9E2},{0x6BAB, 0xE9E3},{0x6BAD, 0xED4C},{0x6BAE, 0xC0D4},{0x6BAF, 0xC26C},{0x6BB0, 0xF25A},{0x6BB2, 0xC4E8},{0x6BB3, 0xC95F}, + {0x6BB5, 0xAC71},{0x6BB6, 0xCF67},{0x6BB7, 0xAEEF},{0x6BBA, 0xB1FE},{0x6BBC, 0xB4DF},{0x6BBD, 0xD9E2},{0x6BBF, 0xB7B5},{0x6BC0, 0xB7B4}, + {0x6BC3, 0xE269},{0x6BC4, 0xE26A},{0x6BC5, 0xBCDD},{0x6BC6, 0xBCDE},{0x6BC7, 0xE9E5},{0x6BC8, 0xE9E4},{0x6BC9, 0xEFE9},{0x6BCA, 0xF7E3}, + {0x6BCB, 0xA4F0},{0x6BCC, 0xC960},{0x6BCD, 0xA5C0},{0x6BCF, 0xA843},{0x6BD0, 0xCB48},{0x6BD2, 0xAC72},{0x6BD3, 0xB7B6},{0x6BD4, 0xA4F1}, + {0x6BD6, 0xCF68},{0x6BD7, 0xAC73},{0x6BD8, 0xCF69},{0x6BDA, 0xC0D5},{0x6BDB, 0xA4F2},{0x6BDE, 0xCCEC},{0x6BE0, 0xCF6A},{0x6BE2, 0xD242}, + {0x6BE3, 0xD241},{0x6BE4, 0xD1FE},{0x6BE6, 0xD1FD},{0x6BE7, 0xD243},{0x6BE8, 0xD240},{0x6BEB, 0xB240},{0x6BEC, 0xB241},{0x6BEF, 0xB4E0}, + {0x6BF0, 0xD9E3},{0x6BF2, 0xD9E4},{0x6BF3, 0xD9E5},{0x6BF7, 0xDE41},{0x6BF8, 0xDE42},{0x6BF9, 0xDE40},{0x6BFB, 0xDDFD},{0x6BFC, 0xDDFE}, + {0x6BFD, 0xB7B7},{0x6BFE, 0xE26B},{0x6BFF, 0xE5F7},{0x6C00, 0xE5F6},{0x6C01, 0xE5F5},{0x6C02, 0xE5F8},{0x6C03, 0xE9E7},{0x6C04, 0xE9E6}, + {0x6C05, 0xBEFB},{0x6C06, 0xE9E8},{0x6C08, 0xC0D6},{0x6C09, 0xED4D},{0x6C0B, 0xEFEA},{0x6C0C, 0xF25B},{0x6C0D, 0xF6E7},{0x6C0F, 0xA4F3}, + {0x6C10, 0xA5C2},{0x6C11, 0xA5C1},{0x6C13, 0xAA5D},{0x6C14, 0xC961},{0x6C15, 0xC97E},{0x6C16, 0xA6BB},{0x6C18, 0xC9F7},{0x6C19, 0xCB49}, + {0x6C1A, 0xCB4A},{0x6C1B, 0xAA5E},{0x6C1D, 0xCCED},{0x6C1F, 0xAC74},{0x6C20, 0xCF6B},{0x6C21, 0xCF6C},{0x6C23, 0xAEF0},{0x6C24, 0xAEF4}, + {0x6C25, 0xD244},{0x6C26, 0xAEF3},{0x6C27, 0xAEF1},{0x6C28, 0xAEF2},{0x6C2A, 0xD5DF},{0x6C2B, 0xB242},{0x6C2C, 0xB4E3},{0x6C2E, 0xB4E1}, + {0x6C2F, 0xB4E2},{0x6C30, 0xD9E6},{0x6C33, 0xBA72},{0x6C34, 0xA4F4},{0x6C36, 0xC9A1},{0x6C38, 0xA5C3},{0x6C3B, 0xC9A4},{0x6C3E, 0xA5C6}, + {0x6C3F, 0xC9A3},{0x6C40, 0xA5C5},{0x6C41, 0xA5C4},{0x6C42, 0xA844},{0x6C43, 0xC9A2},{0x6C46, 0xC9F8},{0x6C4A, 0xC9FC},{0x6C4B, 0xC9FE}, + {0x6C4C, 0xCA40},{0x6C4D, 0xA6C5},{0x6C4E, 0xA6C6},{0x6C4F, 0xC9FB},{0x6C50, 0xA6C1},{0x6C52, 0xC9F9},{0x6C54, 0xC9FD},{0x6C55, 0xA6C2}, + {0x6C57, 0xA6BD},{0x6C59, 0xA6BE},{0x6C5B, 0xA6C4},{0x6C5C, 0xC9FA},{0x6C5D, 0xA6BC},{0x6C5E, 0xA845},{0x6C5F, 0xA6BF},{0x6C60, 0xA6C0}, + {0x6C61, 0xA6C3},{0x6C65, 0xCB5B},{0x6C66, 0xCB59},{0x6C67, 0xCB4C},{0x6C68, 0xA851},{0x6C69, 0xCB53},{0x6C6A, 0xA84C},{0x6C6B, 0xCB4D}, + {0x6C6D, 0xCB55},{0x6C6F, 0xCB52},{0x6C70, 0xA84F},{0x6C71, 0xCB51},{0x6C72, 0xA856},{0x6C73, 0xCB5A},{0x6C74, 0xA858},{0x6C76, 0xA85A}, + {0x6C78, 0xCB4B},{0x6C7A, 0xA84D},{0x6C7B, 0xCB5C},{0x6C7D, 0xA854},{0x6C7E, 0xA857},{0x6C80, 0xCD45},{0x6C81, 0xA847},{0x6C82, 0xA85E}, + {0x6C83, 0xA855},{0x6C84, 0xCB4E},{0x6C85, 0xA84A},{0x6C86, 0xA859},{0x6C87, 0xCB56},{0x6C88, 0xA848},{0x6C89, 0xA849},{0x6C8A, 0xCD43}, + {0x6C8B, 0xCB4F},{0x6C8C, 0xA850},{0x6C8D, 0xA85B},{0x6C8E, 0xCB5D},{0x6C8F, 0xCB50},{0x6C90, 0xA84E},{0x6C92, 0xA853},{0x6C93, 0xCCEE}, + {0x6C94, 0xA85C},{0x6C95, 0xCB57},{0x6C96, 0xA852},{0x6C98, 0xA85D},{0x6C99, 0xA846},{0x6C9A, 0xCB54},{0x6C9B, 0xA84B},{0x6C9C, 0xCB58}, + {0x6C9D, 0xCD44},{0x6CAB, 0xAA6A},{0x6CAC, 0xAA7A},{0x6CAD, 0xCCF5},{0x6CAE, 0xAA71},{0x6CB0, 0xCD4B},{0x6CB1, 0xAA62},{0x6CB3, 0xAA65}, + {0x6CB4, 0xCD42},{0x6CB6, 0xCCF3},{0x6CB7, 0xCCF7},{0x6CB8, 0xAA6D},{0x6CB9, 0xAA6F},{0x6CBA, 0xCCFA},{0x6CBB, 0xAA76},{0x6CBC, 0xAA68}, + {0x6CBD, 0xAA66},{0x6CBE, 0xAA67},{0x6CBF, 0xAA75},{0x6CC0, 0xCD47},{0x6CC1, 0xAA70},{0x6CC2, 0xCCF9},{0x6CC3, 0xCCFB},{0x6CC4, 0xAA6E}, + {0x6CC5, 0xAA73},{0x6CC6, 0xCCFC},{0x6CC7, 0xCD4A},{0x6CC9, 0xAC75},{0x6CCA, 0xAA79},{0x6CCC, 0xAA63},{0x6CCD, 0xCD49},{0x6CCF, 0xCD4D}, + {0x6CD0, 0xCCF8},{0x6CD1, 0xCD4F},{0x6CD2, 0xCD40},{0x6CD3, 0xAA6C},{0x6CD4, 0xCCF4},{0x6CD5, 0xAA6B},{0x6CD6, 0xAA7D},{0x6CD7, 0xAA72}, + {0x6CD9, 0xCCF2},{0x6CDA, 0xCF75},{0x6CDB, 0xAA78},{0x6CDC, 0xAA7C},{0x6CDD, 0xCD41},{0x6CDE, 0xCD46},{0x6CE0, 0xAA7E},{0x6CE1, 0xAA77}, + {0x6CE2, 0xAA69},{0x6CE3, 0xAA5F},{0x6CE5, 0xAA64},{0x6CE7, 0xCCF6},{0x6CE8, 0xAA60},{0x6CE9, 0xCD4E},{0x6CEB, 0xCCF0},{0x6CEC, 0xCCEF}, + {0x6CED, 0xCCFD},{0x6CEE, 0xCCF1},{0x6CEF, 0xAA7B},{0x6CF0, 0xAEF5},{0x6CF1, 0xAA74},{0x6CF2, 0xCCFE},{0x6CF3, 0xAA61},{0x6CF5, 0xACA6}, + {0x6CF9, 0xCD4C},{0x6D00, 0xCF7C},{0x6D01, 0xCFA1},{0x6D03, 0xCFA4},{0x6D04, 0xCF77},{0x6D07, 0xCFA7},{0x6D08, 0xCFAA},{0x6D09, 0xCFAC}, + {0x6D0A, 0xCF74},{0x6D0B, 0xAC76},{0x6D0C, 0xAC7B},{0x6D0D, 0xD249},{0x6D0E, 0xACAD},{0x6D0F, 0xCFA5},{0x6D10, 0xCFAD},{0x6D11, 0xCF7B}, + {0x6D12, 0xCF73},{0x6D16, 0xD264},{0x6D17, 0xAC7E},{0x6D18, 0xCFA2},{0x6D19, 0xCF78},{0x6D1A, 0xCF7A},{0x6D1B, 0xACA5},{0x6D1D, 0xCF7D}, + {0x6D1E, 0xAC7D},{0x6D1F, 0xCF70},{0x6D20, 0xCFA8},{0x6D22, 0xCFAB},{0x6D25, 0xAC7A},{0x6D27, 0xACA8},{0x6D28, 0xCF6D},{0x6D29, 0xACAA}, + {0x6D2A, 0xAC78},{0x6D2B, 0xACAE},{0x6D2C, 0xCFA9},{0x6D2D, 0xCF6F},{0x6D2E, 0xACAB},{0x6D2F, 0xD25E},{0x6D30, 0xCD48},{0x6D31, 0xAC7C}, + {0x6D32, 0xAC77},{0x6D33, 0xCF76},{0x6D34, 0xCF6E},{0x6D35, 0xACAC},{0x6D36, 0xACA4},{0x6D37, 0xCFA3},{0x6D38, 0xACA9},{0x6D39, 0xACA7}, + {0x6D3A, 0xCF79},{0x6D3B, 0xACA1},{0x6D3C, 0xCF71},{0x6D3D, 0xACA2},{0x6D3E, 0xACA3},{0x6D3F, 0xCF72},{0x6D40, 0xCFA6},{0x6D41, 0xAC79}, + {0x6D42, 0xCF7E},{0x6D58, 0xD24C},{0x6D59, 0xAEFD},{0x6D5A, 0xAF43},{0x6D5E, 0xD255},{0x6D5F, 0xD25B},{0x6D60, 0xD257},{0x6D61, 0xD24A}, + {0x6D62, 0xD24D},{0x6D63, 0xD246},{0x6D64, 0xD247},{0x6D65, 0xAF4A},{0x6D66, 0xAEFA},{0x6D67, 0xD256},{0x6D68, 0xD25F},{0x6D69, 0xAF45}, + {0x6D6A, 0xAEF6},{0x6D6C, 0xAF40},{0x6D6D, 0xD24E},{0x6D6E, 0xAF42},{0x6D6F, 0xD24F},{0x6D70, 0xD259},{0x6D74, 0xAF44},{0x6D75, 0xD268}, + {0x6D76, 0xD248},{0x6D77, 0xAEFC},{0x6D78, 0xAEFB},{0x6D79, 0xAF48},{0x6D7A, 0xD245},{0x6D7B, 0xD266},{0x6D7C, 0xD25A},{0x6D7D, 0xD267}, + {0x6D7E, 0xD261},{0x6D7F, 0xD253},{0x6D80, 0xD262},{0x6D82, 0xD25C},{0x6D83, 0xD265},{0x6D84, 0xD263},{0x6D85, 0xAF49},{0x6D86, 0xD254}, + {0x6D87, 0xAEF9},{0x6D88, 0xAEF8},{0x6D89, 0xAF41},{0x6D8A, 0xAF47},{0x6D8B, 0xD260},{0x6D8C, 0xAF46},{0x6D8D, 0xD251},{0x6D8E, 0xB243}, + {0x6D90, 0xD269},{0x6D91, 0xD250},{0x6D92, 0xD24B},{0x6D93, 0xAEFE},{0x6D94, 0xAF4B},{0x6D95, 0xAEF7},{0x6D97, 0xD258},{0x6D98, 0xD25D}, + {0x6DAA, 0xB265},{0x6DAB, 0xD5E1},{0x6DAC, 0xD5E5},{0x6DAE, 0xB252},{0x6DAF, 0xB250},{0x6DB2, 0xB247},{0x6DB3, 0xD5E3},{0x6DB4, 0xD5E2}, + {0x6DB5, 0xB25B},{0x6DB7, 0xD5E8},{0x6DB8, 0xB255},{0x6DBA, 0xD5FA},{0x6DBB, 0xD647},{0x6DBC, 0xB244},{0x6DBD, 0xD5F7},{0x6DBE, 0xD5F0}, + {0x6DBF, 0xB267},{0x6DC0, 0xD5E0},{0x6DC2, 0xD5FC},{0x6DC4, 0xB264},{0x6DC5, 0xB258},{0x6DC6, 0xB263},{0x6DC7, 0xB24E},{0x6DC8, 0xD5EC}, + {0x6DC9, 0xD5FE},{0x6DCA, 0xD5F6},{0x6DCB, 0xB24F},{0x6DCC, 0xB249},{0x6DCD, 0xD645},{0x6DCF, 0xD5FD},{0x6DD0, 0xD640},{0x6DD1, 0xB251}, + {0x6DD2, 0xB259},{0x6DD3, 0xD642},{0x6DD4, 0xD5EA},{0x6DD5, 0xD5FB},{0x6DD6, 0xD5EF},{0x6DD7, 0xD644},{0x6DD8, 0xB25E},{0x6DD9, 0xB246}, + {0x6DDA, 0xB25C},{0x6DDB, 0xD5F4},{0x6DDC, 0xD5F2},{0x6DDD, 0xD5F3},{0x6DDE, 0xB253},{0x6DDF, 0xD5EE},{0x6DE0, 0xD5ED},{0x6DE1, 0xB248}, + {0x6DE2, 0xD5E7},{0x6DE3, 0xD646},{0x6DE4, 0xB24A},{0x6DE5, 0xD5F1},{0x6DE6, 0xB268},{0x6DE8, 0xB262},{0x6DE9, 0xD5E6},{0x6DEA, 0xB25F}, + {0x6DEB, 0xB25D},{0x6DEC, 0xB266},{0x6DED, 0xD5F8},{0x6DEE, 0xB261},{0x6DEF, 0xD252},{0x6DF0, 0xD5F9},{0x6DF1, 0xB260},{0x6DF2, 0xD641}, + {0x6DF3, 0xB245},{0x6DF4, 0xD5F5},{0x6DF5, 0xB257},{0x6DF6, 0xD5E9},{0x6DF7, 0xB256},{0x6DF9, 0xB254},{0x6DFA, 0xB24C},{0x6DFB, 0xB24B}, + {0x6DFC, 0xD9E7},{0x6DFD, 0xD643},{0x6E00, 0xD5EB},{0x6E03, 0xD9FC},{0x6E05, 0xB24D},{0x6E19, 0xB541},{0x6E1A, 0xB25A},{0x6E1B, 0xB4EE}, + {0x6E1C, 0xD9F6},{0x6E1D, 0xB4FC},{0x6E1F, 0xD9EA},{0x6E20, 0xB4EB},{0x6E21, 0xB4E7},{0x6E22, 0xDA49},{0x6E23, 0xB4ED},{0x6E24, 0xB4F1}, + {0x6E25, 0xB4EC},{0x6E26, 0xB4F5},{0x6E27, 0xDA4D},{0x6E28, 0xDA44},{0x6E2B, 0xD9F1},{0x6E2C, 0xB4FA},{0x6E2D, 0xB4F4},{0x6E2E, 0xD9FD}, + {0x6E2F, 0xB4E4},{0x6E30, 0xDA4A},{0x6E31, 0xDA43},{0x6E32, 0xB4E8},{0x6E33, 0xD9F7},{0x6E34, 0xB4F7},{0x6E35, 0xDA55},{0x6E36, 0xDA56}, + {0x6E38, 0xB4E5},{0x6E39, 0xDA48},{0x6E3A, 0xB4F9},{0x6E3B, 0xD9FB},{0x6E3C, 0xD9ED},{0x6E3D, 0xD9EE},{0x6E3E, 0xB4FD},{0x6E3F, 0xD9F2}, + {0x6E40, 0xD9F9},{0x6E41, 0xD9F3},{0x6E43, 0xB4FB},{0x6E44, 0xB544},{0x6E45, 0xD9EF},{0x6E46, 0xD9E8},{0x6E47, 0xD9E9},{0x6E49, 0xD9EB}, + {0x6E4A, 0xB4EA},{0x6E4B, 0xD9F8},{0x6E4D, 0xB4F8},{0x6E4E, 0xB542},{0x6E51, 0xD9FA},{0x6E52, 0xDA53},{0x6E53, 0xDA4B},{0x6E54, 0xB4E6}, + {0x6E55, 0xDA51},{0x6E56, 0xB4F2},{0x6E58, 0xB4F0},{0x6E5A, 0xDA57},{0x6E5B, 0xB4EF},{0x6E5C, 0xDA41},{0x6E5D, 0xD9F4},{0x6E5E, 0xD9FE}, + {0x6E5F, 0xB547},{0x6E60, 0xDA45},{0x6E61, 0xDA42},{0x6E62, 0xD9F0},{0x6E63, 0xB543},{0x6E64, 0xDA4F},{0x6E65, 0xDA4C},{0x6E66, 0xDA54}, + {0x6E67, 0xB4E9},{0x6E68, 0xDA40},{0x6E69, 0xB546},{0x6E6B, 0xDA47},{0x6E6E, 0xB4F3},{0x6E6F, 0xB4F6},{0x6E71, 0xDA46},{0x6E72, 0xB545}, + {0x6E73, 0xD9F5},{0x6E74, 0xD5E4},{0x6E77, 0xDA50},{0x6E78, 0xDA4E},{0x6E79, 0xDA52},{0x6E88, 0xD9EC},{0x6E89, 0xB540},{0x6E8D, 0xDE61}, + {0x6E8E, 0xDE60},{0x6E8F, 0xDE46},{0x6E90, 0xB7BD},{0x6E92, 0xDE5F},{0x6E93, 0xDE49},{0x6E94, 0xDE4A},{0x6E96, 0xB7C7},{0x6E97, 0xDE68}, + {0x6E98, 0xB7C2},{0x6E99, 0xDE5E},{0x6E9B, 0xDE43},{0x6E9C, 0xB7C8},{0x6E9D, 0xB7BE},{0x6E9E, 0xDE52},{0x6E9F, 0xDE48},{0x6EA0, 0xDE4B}, + {0x6EA1, 0xDE63},{0x6EA2, 0xB7B8},{0x6EA3, 0xDE6A},{0x6EA4, 0xDE62},{0x6EA5, 0xB7C1},{0x6EA6, 0xDE57},{0x6EA7, 0xB7CC},{0x6EAA, 0xB7CB}, + {0x6EAB, 0xB7C5},{0x6EAE, 0xDE69},{0x6EAF, 0xB7B9},{0x6EB0, 0xDE55},{0x6EB1, 0xDE4C},{0x6EB2, 0xDE59},{0x6EB3, 0xDE65},{0x6EB4, 0xB7CD}, + {0x6EB6, 0xB7BB},{0x6EB7, 0xDE54},{0x6EB9, 0xDE4D},{0x6EBA, 0xB7C4},{0x6EBC, 0xB7C3},{0x6EBD, 0xDE50},{0x6EBE, 0xDE5A},{0x6EBF, 0xDE64}, + {0x6EC0, 0xDE47},{0x6EC1, 0xDE51},{0x6EC2, 0xB7BC},{0x6EC3, 0xDE5B},{0x6EC4, 0xB7C9},{0x6EC5, 0xB7C0},{0x6EC6, 0xDE4E},{0x6EC7, 0xB7BF}, + {0x6EC8, 0xDE45},{0x6EC9, 0xDE53},{0x6ECA, 0xDE67},{0x6ECB, 0xB4FE},{0x6ECC, 0xBAB0},{0x6ECD, 0xDE56},{0x6ECE, 0xE26C},{0x6ECF, 0xDE58}, + {0x6ED0, 0xDE66},{0x6ED1, 0xB7C6},{0x6ED2, 0xDE4F},{0x6ED3, 0xB7BA},{0x6ED4, 0xB7CA},{0x6ED5, 0xBCF0},{0x6ED6, 0xDE44},{0x6ED8, 0xDE5D}, + {0x6EDC, 0xDE5C},{0x6EEB, 0xE2AA},{0x6EEC, 0xBAAD},{0x6EED, 0xE27D},{0x6EEE, 0xE2A4},{0x6EEF, 0xBAA2},{0x6EF1, 0xE26E},{0x6EF2, 0xBAAF}, + {0x6EF4, 0xBA77},{0x6EF5, 0xE26D},{0x6EF6, 0xE2B0},{0x6EF7, 0xBAB1},{0x6EF8, 0xE271},{0x6EF9, 0xE2A3},{0x6EFB, 0xE273},{0x6EFC, 0xE2B3}, + {0x6EFD, 0xE2AF},{0x6EFE, 0xBA75},{0x6EFF, 0xBAA1},{0x6F00, 0xE653},{0x6F01, 0xBAAE},{0x6F02, 0xBA7D},{0x6F03, 0xE26F},{0x6F05, 0xE2AE}, + {0x6F06, 0xBAA3},{0x6F07, 0xE2AB},{0x6F08, 0xE2B8},{0x6F09, 0xE275},{0x6F0A, 0xE27E},{0x6F0D, 0xE2B6},{0x6F0E, 0xE2AC},{0x6F0F, 0xBA7C}, + {0x6F12, 0xE27C},{0x6F13, 0xBA76},{0x6F14, 0xBA74},{0x6F15, 0xBAA8},{0x6F18, 0xE27A},{0x6F19, 0xE277},{0x6F1A, 0xE278},{0x6F1C, 0xE2B2}, + {0x6F1E, 0xE2B7},{0x6F1F, 0xE2B5},{0x6F20, 0xBA7A},{0x6F21, 0xE2B9},{0x6F22, 0xBA7E},{0x6F23, 0xBAA7},{0x6F25, 0xE270},{0x6F26, 0xE5FA}, + {0x6F27, 0xE279},{0x6F29, 0xBA78},{0x6F2A, 0xBAAC},{0x6F2B, 0xBAA9},{0x6F2C, 0xBA7B},{0x6F2D, 0xE2A5},{0x6F2E, 0xE274},{0x6F2F, 0xBAAA}, + {0x6F30, 0xE2A7},{0x6F31, 0xBAA4},{0x6F32, 0xBAA6},{0x6F33, 0xBA73},{0x6F35, 0xE2A9},{0x6F36, 0xE2A1},{0x6F37, 0xE272},{0x6F38, 0xBAA5}, + {0x6F39, 0xE2B1},{0x6F3A, 0xE2B4},{0x6F3B, 0xE27B},{0x6F3C, 0xE2A8},{0x6F3E, 0xBA79},{0x6F3F, 0xBCDF},{0x6F40, 0xE2A6},{0x6F41, 0xE5F9}, + {0x6F43, 0xE2AD},{0x6F4E, 0xE276},{0x6F4F, 0xE644},{0x6F50, 0xE64E},{0x6F51, 0xBCE2},{0x6F52, 0xE64D},{0x6F53, 0xE659},{0x6F54, 0xBCE4}, + {0x6F55, 0xE64B},{0x6F57, 0xE64F},{0x6F58, 0xBCEF},{0x6F5A, 0xE646},{0x6F5B, 0xBCE7},{0x6F5D, 0xE652},{0x6F5E, 0xE9F0},{0x6F5F, 0xBCF3}, + {0x6F60, 0xBCF2},{0x6F61, 0xE654},{0x6F62, 0xE643},{0x6F63, 0xE65E},{0x6F64, 0xBCED},{0x6F66, 0xBCE3},{0x6F67, 0xE657},{0x6F69, 0xE65B}, + {0x6F6A, 0xE660},{0x6F6B, 0xE655},{0x6F6C, 0xE649},{0x6F6D, 0xBCE6},{0x6F6E, 0xBCE9},{0x6F6F, 0xBCF1},{0x6F70, 0xBCEC},{0x6F72, 0xE64C}, + {0x6F73, 0xE2A2},{0x6F76, 0xE648},{0x6F77, 0xE65F},{0x6F78, 0xBCE8},{0x6F7A, 0xBCEB},{0x6F7B, 0xE661},{0x6F7C, 0xBCE0},{0x6F7D, 0xE656}, + {0x6F7E, 0xE5FB},{0x6F7F, 0xE65C},{0x6F80, 0xC0DF},{0x6F82, 0xE64A},{0x6F84, 0xBCE1},{0x6F85, 0xE645},{0x6F86, 0xBCE5},{0x6F87, 0xE5FC}, + {0x6F88, 0xBAAB},{0x6F89, 0xE641},{0x6F8B, 0xE65A},{0x6F8C, 0xE642},{0x6F8D, 0xE640},{0x6F8E, 0xBCEA},{0x6F90, 0xE658},{0x6F92, 0xE5FE}, + {0x6F93, 0xE651},{0x6F94, 0xE650},{0x6F95, 0xE65D},{0x6F96, 0xE647},{0x6F97, 0xBCEE},{0x6F9E, 0xE9F3},{0x6FA0, 0xBF49},{0x6FA1, 0xBEFE}, + {0x6FA2, 0xEA40},{0x6FA3, 0xE9EB},{0x6FA4, 0xBF41},{0x6FA5, 0xE9F7},{0x6FA6, 0xBF48},{0x6FA7, 0xBF43},{0x6FA8, 0xE9F5},{0x6FA9, 0xED4F}, + {0x6FAA, 0xE9FB},{0x6FAB, 0xEA42},{0x6FAC, 0xE9FA},{0x6FAD, 0xE9E9},{0x6FAE, 0xE9F8},{0x6FAF, 0xEA44},{0x6FB0, 0xEA46},{0x6FB1, 0xBEFD}, + {0x6FB2, 0xEA45},{0x6FB3, 0xBF44},{0x6FB4, 0xBF4A},{0x6FB6, 0xBF47},{0x6FB8, 0xE9FE},{0x6FB9, 0xBF46},{0x6FBA, 0xE9F9},{0x6FBC, 0xE9ED}, + {0x6FBD, 0xE9F2},{0x6FBF, 0xE9FD},{0x6FC0, 0xBF45},{0x6FC1, 0xBF42},{0x6FC2, 0xBEFC},{0x6FC3, 0xBF40},{0x6FC4, 0xE9F1},{0x6FC6, 0xE5FD}, + {0x6FC7, 0xE9EC},{0x6FC8, 0xE9EF},{0x6FC9, 0xEA41},{0x6FCA, 0xE9F4},{0x6FCB, 0xE9EA},{0x6FCC, 0xED4E},{0x6FCD, 0xEA43},{0x6FCE, 0xE9EE}, + {0x6FCF, 0xE9FC},{0x6FD4, 0xED51},{0x6FD5, 0xC0E3},{0x6FD8, 0xC0D7},{0x6FDB, 0xC0DB},{0x6FDC, 0xED53},{0x6FDD, 0xED59},{0x6FDE, 0xED57}, + {0x6FDF, 0xC0D9},{0x6FE0, 0xC0DA},{0x6FE1, 0xC0E1},{0x6FE2, 0xED5A},{0x6FE3, 0xED52},{0x6FE4, 0xC0DC},{0x6FE6, 0xED56},{0x6FE7, 0xED55}, + {0x6FE8, 0xED5B},{0x6FE9, 0xC0E2},{0x6FEB, 0xC0DD},{0x6FEC, 0xC0E0},{0x6FED, 0xED54},{0x6FEE, 0xC0E4},{0x6FEF, 0xC0DE},{0x6FF0, 0xC0E5}, + {0x6FF1, 0xC0D8},{0x6FF2, 0xED58},{0x6FF4, 0xED50},{0x6FF7, 0xEFF7},{0x6FFA, 0xC271},{0x6FFB, 0xEFF4},{0x6FFC, 0xEFF6},{0x6FFE, 0xC26F}, + {0x6FFF, 0xEFF2},{0x7000, 0xEFF3},{0x7001, 0xEFEE},{0x7004, 0xE9F6},{0x7005, 0xEFEF},{0x7006, 0xC270},{0x7007, 0xEFEB},{0x7009, 0xC26D}, + {0x700A, 0xEFF8},{0x700B, 0xC26E},{0x700C, 0xEFEC},{0x700D, 0xEFED},{0x700E, 0xEFF1},{0x700F, 0xC273},{0x7011, 0xC272},{0x7014, 0xEFF0}, + {0x7015, 0xC378},{0x7016, 0xF25F},{0x7017, 0xF265},{0x7018, 0xC379},{0x7019, 0xF25C},{0x701A, 0xC376},{0x701B, 0xC373},{0x701C, 0xF267}, + {0x701D, 0xC377},{0x701F, 0xC374},{0x7020, 0xF25E},{0x7021, 0xF261},{0x7022, 0xF262},{0x7023, 0xF263},{0x7024, 0xF266},{0x7026, 0xEFF5}, + {0x7027, 0xF25D},{0x7028, 0xC375},{0x7029, 0xF264},{0x702A, 0xF268},{0x702B, 0xF260},{0x702F, 0xF45D},{0x7030, 0xC46A},{0x7031, 0xF460}, + {0x7032, 0xC46B},{0x7033, 0xF468},{0x7034, 0xF45F},{0x7035, 0xF45C},{0x7037, 0xF45E},{0x7038, 0xF462},{0x7039, 0xF465},{0x703A, 0xF464}, + {0x703B, 0xF467},{0x703C, 0xF45B},{0x703E, 0xC469},{0x703F, 0xF463},{0x7040, 0xF466},{0x7041, 0xF469},{0x7042, 0xF461},{0x7043, 0xF5D3}, + {0x7044, 0xF5D4},{0x7045, 0xF5D8},{0x7046, 0xF5D9},{0x7048, 0xF5D6},{0x7049, 0xF5D7},{0x704A, 0xF5D5},{0x704C, 0xC4E9},{0x7051, 0xC578}, + {0x7052, 0xF6EB},{0x7055, 0xF6E8},{0x7056, 0xF6E9},{0x7057, 0xF6EA},{0x7058, 0xC579},{0x705A, 0xF7E5},{0x705B, 0xF7E4},{0x705D, 0xF8AF}, + {0x705E, 0xC5F4},{0x705F, 0xF8AD},{0x7060, 0xF8B0},{0x7061, 0xF8AE},{0x7062, 0xF8F5},{0x7063, 0xC657},{0x7064, 0xC665},{0x7065, 0xF9A3}, + {0x7066, 0xF96C},{0x7068, 0xF9A2},{0x7069, 0xF9D0},{0x706A, 0xF9D1},{0x706B, 0xA4F5},{0x7070, 0xA6C7},{0x7071, 0xCA41},{0x7074, 0xCB5E}, + {0x7076, 0xA85F},{0x7078, 0xA862},{0x707A, 0xCB5F},{0x707C, 0xA860},{0x707D, 0xA861},{0x7082, 0xCD58},{0x7083, 0xCD5A},{0x7084, 0xCD55}, + {0x7085, 0xCD52},{0x7086, 0xCD54},{0x708A, 0xAAA4},{0x708E, 0xAAA2},{0x7091, 0xCD56},{0x7092, 0xAAA3},{0x7093, 0xCD53},{0x7094, 0xCD50}, + {0x7095, 0xAAA1},{0x7096, 0xCD57},{0x7098, 0xCD51},{0x7099, 0xAAA5},{0x709A, 0xCD59},{0x709F, 0xCFAF},{0x70A1, 0xCFB3},{0x70A4, 0xACB7}, + {0x70A9, 0xCFB6},{0x70AB, 0xACAF},{0x70AC, 0xACB2},{0x70AD, 0xACB4},{0x70AE, 0xACB6},{0x70AF, 0xACB3},{0x70B0, 0xCFB2},{0x70B1, 0xCFB1}, + {0x70B3, 0xACB1},{0x70B4, 0xCFB4},{0x70B5, 0xCFB5},{0x70B7, 0xCFAE},{0x70B8, 0xACB5},{0x70BA, 0xACB0},{0x70BE, 0xCFB0},{0x70C5, 0xD277}, + {0x70C6, 0xD278},{0x70C7, 0xD279},{0x70C8, 0xAF50},{0x70CA, 0xAF4C},{0x70CB, 0xD26E},{0x70CD, 0xD276},{0x70CE, 0xD27B},{0x70CF, 0xAF51}, + {0x70D1, 0xD26C},{0x70D2, 0xD272},{0x70D3, 0xD26B},{0x70D4, 0xD275},{0x70D7, 0xD271},{0x70D8, 0xAF4D},{0x70D9, 0xAF4F},{0x70DA, 0xD27A}, + {0x70DC, 0xD26A},{0x70DD, 0xD26D},{0x70DE, 0xD273},{0x70E0, 0xD274},{0x70E1, 0xD27C},{0x70E2, 0xD270},{0x70E4, 0xAF4E},{0x70EF, 0xB26D}, + {0x70F0, 0xD64E},{0x70F3, 0xD650},{0x70F4, 0xD64C},{0x70F6, 0xD658},{0x70F7, 0xD64A},{0x70F8, 0xD657},{0x70F9, 0xB269},{0x70FA, 0xD648}, + {0x70FB, 0xDA5B},{0x70FC, 0xD652},{0x70FD, 0xB26C},{0x70FF, 0xD653},{0x7100, 0xD656},{0x7102, 0xD65A},{0x7104, 0xD64F},{0x7106, 0xD654}, + {0x7109, 0xB26A},{0x710A, 0xB26B},{0x710B, 0xD659},{0x710C, 0xD64D},{0x710D, 0xD649},{0x710E, 0xD65B},{0x7110, 0xD651},{0x7113, 0xD655}, + {0x7117, 0xD64B},{0x7119, 0xB548},{0x711A, 0xB549},{0x711B, 0xDA65},{0x711C, 0xB54F},{0x711E, 0xDA59},{0x711F, 0xDA62},{0x7120, 0xDA58}, + {0x7121, 0xB54C},{0x7122, 0xDA60},{0x7123, 0xDA5E},{0x7125, 0xDA5F},{0x7126, 0xB54A},{0x7128, 0xDA63},{0x712E, 0xDA5C},{0x712F, 0xDA5A}, + {0x7130, 0xB54B},{0x7131, 0xDA5D},{0x7132, 0xDA61},{0x7136, 0xB54D},{0x713A, 0xDA64},{0x7141, 0xDE70},{0x7142, 0xDE77},{0x7143, 0xDE79}, + {0x7144, 0xDEA1},{0x7146, 0xB7DA},{0x7147, 0xDE6B},{0x7149, 0xB7D2},{0x714B, 0xDE7A},{0x714C, 0xB7D7},{0x714D, 0xDEA2},{0x714E, 0xB7CE}, + {0x7150, 0xDE7D},{0x7152, 0xDE6D},{0x7153, 0xDE7E},{0x7154, 0xDE6C},{0x7156, 0xB7DC},{0x7158, 0xDE78},{0x7159, 0xB7CF},{0x715A, 0xDEA3}, + {0x715C, 0xB7D4},{0x715D, 0xDE71},{0x715E, 0xB7D9},{0x715F, 0xDE7C},{0x7160, 0xDE6F},{0x7161, 0xDE76},{0x7162, 0xDE72},{0x7163, 0xDE6E}, + {0x7164, 0xB7D1},{0x7165, 0xB7D8},{0x7166, 0xB7D6},{0x7167, 0xB7D3},{0x7168, 0xB7DB},{0x7169, 0xB7D0},{0x716A, 0xDE75},{0x716C, 0xB7D5}, + {0x716E, 0xB54E},{0x7170, 0xDE7B},{0x7172, 0xDE73},{0x7178, 0xDE74},{0x717B, 0xE2C1},{0x717D, 0xBAB4},{0x7180, 0xE2BD},{0x7181, 0xE2C3}, + {0x7182, 0xE2BF},{0x7184, 0xBAB6},{0x7185, 0xE2BE},{0x7186, 0xE2C2},{0x7187, 0xE2BA},{0x7189, 0xE2BC},{0x718A, 0xBAB5},{0x718F, 0xE2C0}, + {0x7190, 0xE2BB},{0x7192, 0xBAB7},{0x7194, 0xBAB2},{0x7197, 0xE2C4},{0x7199, 0xBAB3},{0x719A, 0xE667},{0x719B, 0xE664},{0x719C, 0xE670}, + {0x719D, 0xE66A},{0x719E, 0xE66C},{0x719F, 0xBCF4},{0x71A0, 0xE666},{0x71A1, 0xE66E},{0x71A4, 0xE66D},{0x71A5, 0xE66B},{0x71A7, 0xE671}, + {0x71A8, 0xBCF7},{0x71A9, 0xE668},{0x71AA, 0xE66F},{0x71AC, 0xBCF5},{0x71AF, 0xE663},{0x71B0, 0xE665},{0x71B1, 0xBCF6},{0x71B2, 0xE662}, + {0x71B3, 0xE672},{0x71B5, 0xE669},{0x71B8, 0xEA4A},{0x71B9, 0xBF51},{0x71BC, 0xEA55},{0x71BD, 0xEA53},{0x71BE, 0xBF4B},{0x71BF, 0xEA49}, + {0x71C0, 0xEA4C},{0x71C1, 0xEA4D},{0x71C2, 0xEA48},{0x71C3, 0xBF55},{0x71C4, 0xBF56},{0x71C5, 0xEA47},{0x71C6, 0xEA56},{0x71C7, 0xEA51}, + {0x71C8, 0xBF4F},{0x71C9, 0xBF4C},{0x71CA, 0xEA50},{0x71CB, 0xEA4E},{0x71CE, 0xBF52},{0x71CF, 0xEA52},{0x71D0, 0xBF4D},{0x71D2, 0xBF4E}, + {0x71D4, 0xEA4F},{0x71D5, 0xBF50},{0x71D6, 0xEA4B},{0x71D8, 0xEA54},{0x71D9, 0xBF53},{0x71DA, 0xEA57},{0x71DB, 0xEA58},{0x71DC, 0xBF54}, + {0x71DF, 0xC0E7},{0x71E0, 0xC0EE},{0x71E1, 0xED5C},{0x71E2, 0xED62},{0x71E4, 0xED60},{0x71E5, 0xC0EA},{0x71E6, 0xC0E9},{0x71E7, 0xC0E6}, + {0x71E8, 0xED5E},{0x71EC, 0xC0EC},{0x71ED, 0xC0EB},{0x71EE, 0xC0E8},{0x71F0, 0xED61},{0x71F1, 0xED5D},{0x71F2, 0xED5F},{0x71F4, 0xC0ED}, + {0x71F8, 0xC277},{0x71F9, 0xEFFB},{0x71FB, 0xC274},{0x71FC, 0xC275},{0x71FD, 0xEFFD},{0x71FE, 0xC276},{0x71FF, 0xEFFA},{0x7201, 0xEFF9}, + {0x7202, 0xF26C},{0x7203, 0xEFFC},{0x7205, 0xF26D},{0x7206, 0xC37A},{0x7207, 0xF26B},{0x720A, 0xF26A},{0x720C, 0xF269},{0x720D, 0xC37B}, + {0x7210, 0xC46C},{0x7213, 0xF46A},{0x7214, 0xF46B},{0x7219, 0xF5DC},{0x721A, 0xF5DB},{0x721B, 0xC4EA},{0x721D, 0xF5DA},{0x721E, 0xF6EC}, + {0x721F, 0xF6ED},{0x7222, 0xF7E6},{0x7223, 0xF8B1},{0x7226, 0xF8F6},{0x7227, 0xF9BC},{0x7228, 0xC679},{0x7229, 0xF9C6},{0x722A, 0xA4F6}, + {0x722C, 0xAAA6},{0x722D, 0xAAA7},{0x7230, 0xACB8},{0x7235, 0xC0EF},{0x7236, 0xA4F7},{0x7238, 0xAAA8},{0x7239, 0xAF52},{0x723A, 0xB7DD}, + {0x723B, 0xA4F8},{0x723D, 0xB26E},{0x723E, 0xBAB8},{0x723F, 0xC962},{0x7241, 0xCFB7},{0x7242, 0xD27D},{0x7244, 0xE2C5},{0x7246, 0xC0F0}, + {0x7247, 0xA4F9},{0x7248, 0xAAA9},{0x7249, 0xCFB8},{0x724A, 0xCFB9},{0x724B, 0xDA66},{0x724C, 0xB550},{0x724F, 0xDEA4},{0x7252, 0xB7DE}, + {0x7253, 0xE2C6},{0x7256, 0xBCF8},{0x7258, 0xC37C},{0x7259, 0xA4FA},{0x725A, 0xDA67},{0x725B, 0xA4FB},{0x725D, 0xA6C9},{0x725E, 0xCA42}, + {0x725F, 0xA6C8},{0x7260, 0xA865},{0x7261, 0xA864},{0x7262, 0xA863},{0x7263, 0xCB60},{0x7267, 0xAAAA},{0x7269, 0xAAAB},{0x726A, 0xCD5B}, + {0x726C, 0xCFBA},{0x726E, 0xCFBD},{0x726F, 0xACBA},{0x7270, 0xCFBB},{0x7272, 0xACB9},{0x7273, 0xCFBC},{0x7274, 0xACBB},{0x7276, 0xD2A2}, + {0x7277, 0xD2A1},{0x7278, 0xD27E},{0x7279, 0xAF53},{0x727B, 0xD65D},{0x727C, 0xD65E},{0x727D, 0xB26F},{0x727E, 0xD65C},{0x727F, 0xD65F}, + {0x7280, 0xB552},{0x7281, 0xB270},{0x7284, 0xB551},{0x7285, 0xDA6B},{0x7286, 0xDA6A},{0x7288, 0xDA68},{0x7289, 0xDA69},{0x728B, 0xDA6C}, + {0x728C, 0xDEA6},{0x728D, 0xDEA5},{0x728E, 0xDEA9},{0x7290, 0xDEA8},{0x7291, 0xDEA7},{0x7292, 0xBAB9},{0x7293, 0xE2C9},{0x7295, 0xE2C8}, + {0x7296, 0xBABA},{0x7297, 0xE2C7},{0x7298, 0xE673},{0x729A, 0xE674},{0x729B, 0xBCF9},{0x729D, 0xEA59},{0x729E, 0xEA5A},{0x72A1, 0xF272}, + {0x72A2, 0xC37D},{0x72A3, 0xF271},{0x72A4, 0xF270},{0x72A5, 0xF26E},{0x72A6, 0xF26F},{0x72A7, 0xC4EB},{0x72A8, 0xF46C},{0x72A9, 0xF6EE}, + {0x72AA, 0xF8F7},{0x72AC, 0xA4FC},{0x72AE, 0xC9A5},{0x72AF, 0xA5C7},{0x72B0, 0xC9A6},{0x72B4, 0xCA43},{0x72B5, 0xCA44},{0x72BA, 0xCB66}, + {0x72BD, 0xCB62},{0x72BF, 0xCB61},{0x72C0, 0xAAAC},{0x72C1, 0xCB65},{0x72C2, 0xA867},{0x72C3, 0xCB63},{0x72C4, 0xA866},{0x72C5, 0xCB67}, + {0x72C6, 0xCB64},{0x72C9, 0xCD5F},{0x72CA, 0xCFBE},{0x72CB, 0xCD5D},{0x72CC, 0xCD64},{0x72CE, 0xAAAD},{0x72D0, 0xAAB0},{0x72D1, 0xCD65}, + {0x72D2, 0xCD61},{0x72D4, 0xCD62},{0x72D6, 0xCD5C},{0x72D7, 0xAAAF},{0x72D8, 0xCD5E},{0x72D9, 0xAAAE},{0x72DA, 0xCD63},{0x72DC, 0xCD60}, + {0x72DF, 0xCFC2},{0x72E0, 0xACBD},{0x72E1, 0xACBE},{0x72E3, 0xCFC5},{0x72E4, 0xCFBF},{0x72E6, 0xCFC4},{0x72E8, 0xCFC0},{0x72E9, 0xACBC}, + {0x72EA, 0xCFC3},{0x72EB, 0xCFC1},{0x72F3, 0xD2A8},{0x72F4, 0xD2A5},{0x72F6, 0xD2A7},{0x72F7, 0xAF58},{0x72F8, 0xAF57},{0x72F9, 0xAF55}, + {0x72FA, 0xD2A4},{0x72FB, 0xD2A9},{0x72FC, 0xAF54},{0x72FD, 0xAF56},{0x72FE, 0xD2A6},{0x72FF, 0xD667},{0x7300, 0xD2A3},{0x7301, 0xD2AA}, + {0x7307, 0xD662},{0x7308, 0xD666},{0x730A, 0xD665},{0x730B, 0xDA6E},{0x730C, 0xDA79},{0x730F, 0xD668},{0x7311, 0xD663},{0x7312, 0xDA6D}, + {0x7313, 0xB274},{0x7316, 0xB273},{0x7317, 0xD661},{0x7318, 0xD664},{0x7319, 0xB275},{0x731B, 0xB272},{0x731C, 0xB271},{0x731D, 0xD660}, + {0x731E, 0xD669},{0x7322, 0xDA70},{0x7323, 0xDA77},{0x7325, 0xB554},{0x7326, 0xDA76},{0x7327, 0xDA73},{0x7329, 0xB556},{0x732D, 0xDA75}, + {0x7330, 0xDA6F},{0x7331, 0xDA71},{0x7332, 0xDA74},{0x7333, 0xDA72},{0x7334, 0xB555},{0x7335, 0xDA78},{0x7336, 0xB553},{0x7337, 0xB7DF}, + {0x733A, 0xDEAD},{0x733B, 0xDEAC},{0x733C, 0xDEAA},{0x733E, 0xB7E2},{0x733F, 0xB7E1},{0x7340, 0xDEAE},{0x7342, 0xDEAB},{0x7343, 0xE2CA}, + {0x7344, 0xBABB},{0x7345, 0xB7E0},{0x7349, 0xDEB0},{0x734A, 0xDEAF},{0x734C, 0xE2CD},{0x734D, 0xE2CB},{0x734E, 0xBCFA},{0x7350, 0xBABC}, + {0x7351, 0xE2CC},{0x7352, 0xE676},{0x7357, 0xBCFB},{0x7358, 0xE675},{0x7359, 0xE67E},{0x735A, 0xE67D},{0x735B, 0xE67B},{0x735D, 0xE67A}, + {0x735E, 0xE677},{0x735F, 0xE678},{0x7360, 0xE679},{0x7361, 0xE67C},{0x7362, 0xE6A1},{0x7365, 0xEA5F},{0x7366, 0xEA5C},{0x7367, 0xEA5D}, + {0x7368, 0xBF57},{0x7369, 0xEA5B},{0x736A, 0xEA61},{0x736B, 0xEA60},{0x736C, 0xEA5E},{0x736E, 0xED64},{0x736F, 0xED65},{0x7370, 0xC0F1}, + {0x7372, 0xC0F2},{0x7373, 0xED63},{0x7375, 0xC279},{0x7376, 0xEFFE},{0x7377, 0xC278},{0x7378, 0xC37E},{0x737A, 0xC3A1},{0x737B, 0xC46D}, + {0x737C, 0xF46E},{0x737D, 0xF46D},{0x737E, 0xF5DD},{0x737F, 0xF6EF},{0x7380, 0xC57A},{0x7381, 0xF7E8},{0x7382, 0xF7E7},{0x7383, 0xF7E9}, + {0x7384, 0xA5C8},{0x7385, 0xCFC6},{0x7386, 0xAF59},{0x7387, 0xB276},{0x7388, 0xD66A},{0x7389, 0xA5C9},{0x738A, 0xC9A7},{0x738B, 0xA4FD}, + {0x738E, 0xCA45},{0x7392, 0xCB6C},{0x7393, 0xCB6A},{0x7394, 0xCB6B},{0x7395, 0xCB68},{0x7396, 0xA868},{0x7397, 0xCB69},{0x739D, 0xCD6D}, + {0x739F, 0xAAB3},{0x73A0, 0xCD6B},{0x73A1, 0xCD67},{0x73A2, 0xCD6A},{0x73A4, 0xCD66},{0x73A5, 0xAAB5},{0x73A6, 0xCD69},{0x73A8, 0xAAB2}, + {0x73A9, 0xAAB1},{0x73AB, 0xAAB4},{0x73AC, 0xCD6C},{0x73AD, 0xCD68},{0x73B2, 0xACC2},{0x73B3, 0xACC5},{0x73B4, 0xCFCE},{0x73B5, 0xCFCD}, + {0x73B6, 0xCFCC},{0x73B7, 0xACBF},{0x73B8, 0xCFD5},{0x73B9, 0xCFCB},{0x73BB, 0xACC1},{0x73BC, 0xD2AF},{0x73BE, 0xCFD2},{0x73BF, 0xCFD0}, + {0x73C0, 0xACC4},{0x73C2, 0xCFC8},{0x73C3, 0xCFD3},{0x73C5, 0xCFCA},{0x73C6, 0xCFD4},{0x73C7, 0xCFD1},{0x73C8, 0xCFC9},{0x73CA, 0xACC0}, + {0x73CB, 0xCFD6},{0x73CC, 0xCFC7},{0x73CD, 0xACC3},{0x73D2, 0xD2B4},{0x73D3, 0xD2AB},{0x73D4, 0xD2B6},{0x73D6, 0xD2AE},{0x73D7, 0xD2B9}, + {0x73D8, 0xD2BA},{0x73D9, 0xD2AC},{0x73DA, 0xD2B8},{0x73DB, 0xD2B5},{0x73DC, 0xD2B3},{0x73DD, 0xD2B7},{0x73DE, 0xAF5F},{0x73E0, 0xAF5D}, + {0x73E3, 0xD2B1},{0x73E5, 0xD2AD},{0x73E7, 0xD2B0},{0x73E8, 0xD2BB},{0x73E9, 0xD2B2},{0x73EA, 0xAF5E},{0x73EB, 0xCFCF},{0x73ED, 0xAF5A}, + {0x73EE, 0xAF5C},{0x73F4, 0xD678},{0x73F5, 0xD66D},{0x73F6, 0xD66B},{0x73F8, 0xD66C},{0x73FA, 0xD673},{0x73FC, 0xD674},{0x73FD, 0xD670}, + {0x73FE, 0xB27B},{0x73FF, 0xD675},{0x7400, 0xD672},{0x7401, 0xD66F},{0x7403, 0xB279},{0x7404, 0xD66E},{0x7405, 0xB277},{0x7406, 0xB27A}, + {0x7407, 0xD671},{0x7408, 0xD679},{0x7409, 0xAF5B},{0x740A, 0xB278},{0x740B, 0xD677},{0x740C, 0xD676},{0x740D, 0xB27C},{0x7416, 0xDA7E}, + {0x741A, 0xDAA1},{0x741B, 0xB560},{0x741D, 0xDAA7},{0x7420, 0xDAA9},{0x7421, 0xDAA2},{0x7422, 0xB55A},{0x7423, 0xDAA6},{0x7424, 0xDAA5}, + {0x7425, 0xB55B},{0x7426, 0xB561},{0x7428, 0xB562},{0x7429, 0xDAA8},{0x742A, 0xB558},{0x742B, 0xDA7D},{0x742C, 0xDA7B},{0x742D, 0xDAA3}, + {0x742E, 0xDA7A},{0x742F, 0xB55F},{0x7430, 0xDA7C},{0x7431, 0xDAA4},{0x7432, 0xDAAA},{0x7433, 0xB559},{0x7434, 0xB55E},{0x7435, 0xB55C}, + {0x7436, 0xB55D},{0x743A, 0xB557},{0x743F, 0xB7E9},{0x7440, 0xDEB7},{0x7441, 0xB7E8},{0x7442, 0xDEBB},{0x7444, 0xDEB1},{0x7446, 0xDEBC}, + {0x744A, 0xDEB2},{0x744B, 0xDEB3},{0x744D, 0xDEBD},{0x744E, 0xDEBA},{0x744F, 0xDEB8},{0x7450, 0xDEB9},{0x7451, 0xDEB5},{0x7452, 0xDEB4}, + {0x7454, 0xDEBE},{0x7455, 0xB7E5},{0x7457, 0xDEB6},{0x7459, 0xB7EA},{0x745A, 0xB7E4},{0x745B, 0xB7EB},{0x745C, 0xB7EC},{0x745E, 0xB7E7}, + {0x745F, 0xB7E6},{0x7462, 0xE2CE},{0x7463, 0xBABE},{0x7464, 0xBABD},{0x7467, 0xE2D3},{0x7469, 0xBCFC},{0x746A, 0xBABF},{0x746D, 0xBAC1}, + {0x746E, 0xE2D4},{0x746F, 0xB7E3},{0x7470, 0xBAC0},{0x7471, 0xE2D0},{0x7472, 0xE2D2},{0x7473, 0xE2CF},{0x7475, 0xE2D1},{0x7479, 0xE6AB}, + {0x747C, 0xE6AA},{0x747D, 0xE6A7},{0x747E, 0xBD40},{0x747F, 0xEA62},{0x7480, 0xBD41},{0x7481, 0xE6A6},{0x7483, 0xBCFE},{0x7485, 0xE6A8}, + {0x7486, 0xE6A5},{0x7487, 0xE6A2},{0x7488, 0xE6A9},{0x7489, 0xE6A3},{0x748A, 0xE6A4},{0x748B, 0xBCFD},{0x7490, 0xED69},{0x7492, 0xEA66}, + {0x7494, 0xEA65},{0x7495, 0xEA67},{0x7497, 0xED66},{0x7498, 0xBF5A},{0x749A, 0xEA63},{0x749C, 0xBF58},{0x749E, 0xBF5C},{0x749F, 0xBF5B}, + {0x74A0, 0xEA64},{0x74A1, 0xEA68},{0x74A3, 0xBF59},{0x74A5, 0xED6D},{0x74A6, 0xC0F5},{0x74A7, 0xC27A},{0x74A8, 0xC0F6},{0x74A9, 0xC0F3}, + {0x74AA, 0xED6A},{0x74AB, 0xED68},{0x74AD, 0xED6B},{0x74AF, 0xED6E},{0x74B0, 0xC0F4},{0x74B1, 0xED6C},{0x74B2, 0xED67},{0x74B5, 0xF042}, + {0x74B6, 0xF045},{0x74B7, 0xF275},{0x74B8, 0xF040},{0x74BA, 0xF46F},{0x74BB, 0xF046},{0x74BD, 0xC3A2},{0x74BE, 0xF044},{0x74BF, 0xC27B}, + {0x74C0, 0xF041},{0x74C1, 0xF043},{0x74C2, 0xF047},{0x74C3, 0xF276},{0x74C5, 0xF274},{0x74CA, 0xC3A3},{0x74CB, 0xF273},{0x74CF, 0xC46E}, + {0x74D4, 0xC4ED},{0x74D5, 0xF6F1},{0x74D6, 0xC4EC},{0x74D7, 0xF6F3},{0x74D8, 0xF6F0},{0x74D9, 0xF6F2},{0x74DA, 0xC5D0},{0x74DB, 0xF8B2}, + {0x74DC, 0xA5CA},{0x74DD, 0xCD6E},{0x74DE, 0xD2BC},{0x74DF, 0xD2BD},{0x74E0, 0xB27D},{0x74E1, 0xDEBF},{0x74E2, 0xBF5D},{0x74E3, 0xC3A4}, + {0x74E4, 0xC57B},{0x74E5, 0xF8B3},{0x74E6, 0xA5CB},{0x74E8, 0xCD6F},{0x74E9, 0xA260},{0x74EC, 0xCFD7},{0x74EE, 0xCFD8},{0x74F4, 0xD2BE}, + {0x74F5, 0xD2BF},{0x74F6, 0xB27E},{0x74F7, 0xB2A1},{0x74FB, 0xDAAB},{0x74FD, 0xDEC2},{0x74FE, 0xDEC1},{0x74FF, 0xDEC0},{0x7500, 0xE2D5}, + {0x7502, 0xE2D6},{0x7503, 0xE2D7},{0x7504, 0xBAC2},{0x7507, 0xE6AD},{0x7508, 0xE6AC},{0x750B, 0xEA69},{0x750C, 0xBF5E},{0x750D, 0xBF5F}, + {0x750F, 0xED72},{0x7510, 0xED6F},{0x7511, 0xED70},{0x7512, 0xED71},{0x7513, 0xF049},{0x7514, 0xF048},{0x7515, 0xC27C},{0x7516, 0xF277}, + {0x7517, 0xF5DE},{0x7518, 0xA5CC},{0x751A, 0xACC6},{0x751C, 0xB2A2},{0x751D, 0xDEC3},{0x751F, 0xA5CD},{0x7521, 0xD2C0},{0x7522, 0xB2A3}, + {0x7525, 0xB563},{0x7526, 0xB564},{0x7528, 0xA5CE},{0x7529, 0xA5CF},{0x752A, 0xCA46},{0x752B, 0xA86A},{0x752C, 0xA869},{0x752D, 0xACC7}, + {0x752E, 0xCFD9},{0x752F, 0xDAAC},{0x7530, 0xA5D0},{0x7531, 0xA5D1},{0x7532, 0xA5D2},{0x7533, 0xA5D3},{0x7537, 0xA86B},{0x7538, 0xA86C}, + {0x7539, 0xCB6E},{0x753A, 0xCB6D},{0x753D, 0xAAB6},{0x753E, 0xCD72},{0x753F, 0xCD70},{0x7540, 0xCD71},{0x7547, 0xCFDA},{0x7548, 0xCFDB}, + {0x754B, 0xACCB},{0x754C, 0xACC9},{0x754E, 0xACCA},{0x754F, 0xACC8},{0x7554, 0xAF60},{0x7559, 0xAF64},{0x755A, 0xAF63},{0x755B, 0xD2C1}, + {0x755C, 0xAF62},{0x755D, 0xAF61},{0x755F, 0xD2C2},{0x7562, 0xB2A6},{0x7563, 0xD67B},{0x7564, 0xD67A},{0x7565, 0xB2A4},{0x7566, 0xB2A5}, + {0x756A, 0xB566},{0x756B, 0xB565},{0x756C, 0xDAAE},{0x756F, 0xDAAD},{0x7570, 0xB2A7},{0x7576, 0xB7ED},{0x7577, 0xDEC5},{0x7578, 0xB7EE}, + {0x7579, 0xDEC4},{0x757D, 0xE2D8},{0x757E, 0xE6AE},{0x757F, 0xBD42},{0x7580, 0xEA6A},{0x7584, 0xED73},{0x7586, 0xC3A6},{0x7587, 0xC3A5}, + {0x758A, 0xC57C},{0x758B, 0xA5D4},{0x758C, 0xCD73},{0x758F, 0xB2A8},{0x7590, 0xE2D9},{0x7591, 0xBAC3},{0x7594, 0xCB6F},{0x7595, 0xCB70}, + {0x7598, 0xCD74},{0x7599, 0xAAB8},{0x759A, 0xAAB9},{0x759D, 0xAAB7},{0x75A2, 0xACCF},{0x75A3, 0xACD0},{0x75A4, 0xACCD},{0x75A5, 0xACCE}, + {0x75A7, 0xCFDC},{0x75AA, 0xCFDD},{0x75AB, 0xACCC},{0x75B0, 0xD2C3},{0x75B2, 0xAF68},{0x75B3, 0xAF69},{0x75B5, 0xB2AB},{0x75B6, 0xD2C9}, + {0x75B8, 0xAF6E},{0x75B9, 0xAF6C},{0x75BA, 0xD2CA},{0x75BB, 0xD2C5},{0x75BC, 0xAF6B},{0x75BD, 0xAF6A},{0x75BE, 0xAF65},{0x75BF, 0xD2C8}, + {0x75C0, 0xD2C7},{0x75C1, 0xD2C4},{0x75C2, 0xAF6D},{0x75C4, 0xD2C6},{0x75C5, 0xAF66},{0x75C7, 0xAF67},{0x75CA, 0xB2AC},{0x75CB, 0xD6A1}, + {0x75CC, 0xD6A2},{0x75CD, 0xB2AD},{0x75CE, 0xD67C},{0x75CF, 0xD67E},{0x75D0, 0xD6A4},{0x75D1, 0xD6A3},{0x75D2, 0xD67D},{0x75D4, 0xB2A9}, + {0x75D5, 0xB2AA},{0x75D7, 0xDAB6},{0x75D8, 0xB56B},{0x75D9, 0xB56A},{0x75DA, 0xDAB0},{0x75DB, 0xB568},{0x75DD, 0xDAB3},{0x75DE, 0xB56C}, + {0x75DF, 0xDAB4},{0x75E0, 0xB56D},{0x75E1, 0xDAB1},{0x75E2, 0xB567},{0x75E3, 0xB569},{0x75E4, 0xDAB5},{0x75E6, 0xDAB2},{0x75E7, 0xDAAF}, + {0x75ED, 0xDED2},{0x75EF, 0xDEC7},{0x75F0, 0xB7F0},{0x75F1, 0xB7F3},{0x75F2, 0xB7F2},{0x75F3, 0xB7F7},{0x75F4, 0xB7F6},{0x75F5, 0xDED3}, + {0x75F6, 0xDED1},{0x75F7, 0xDECA},{0x75F8, 0xDECE},{0x75F9, 0xDECD},{0x75FA, 0xB7F4},{0x75FB, 0xDED0},{0x75FC, 0xDECC},{0x75FD, 0xDED4}, + {0x75FE, 0xDECB},{0x75FF, 0xB7F5},{0x7600, 0xB7EF},{0x7601, 0xB7F1},{0x7603, 0xDEC9},{0x7608, 0xE2DB},{0x7609, 0xBAC7},{0x760A, 0xE2DF}, + {0x760B, 0xBAC6},{0x760C, 0xE2DC},{0x760D, 0xBAC5},{0x760F, 0xDEC8},{0x7610, 0xDECF},{0x7611, 0xE2DE},{0x7613, 0xBAC8},{0x7614, 0xE2E0}, + {0x7615, 0xE2DD},{0x7616, 0xE2DA},{0x7619, 0xE6B1},{0x761A, 0xE6B5},{0x761B, 0xE6B7},{0x761C, 0xE6B3},{0x761D, 0xE6B2},{0x761E, 0xE6B0}, + {0x761F, 0xBD45},{0x7620, 0xBD43},{0x7621, 0xBD48},{0x7622, 0xBD49},{0x7623, 0xE6B4},{0x7624, 0xBD46},{0x7625, 0xE6AF},{0x7626, 0xBD47}, + {0x7627, 0xBAC4},{0x7628, 0xE6B6},{0x7629, 0xBD44},{0x762D, 0xEA6C},{0x762F, 0xEA6B},{0x7630, 0xEA73},{0x7631, 0xEA6D},{0x7632, 0xEA72}, + {0x7633, 0xEA6F},{0x7634, 0xBF60},{0x7635, 0xEA71},{0x7638, 0xBF61},{0x763A, 0xBF62},{0x763C, 0xEA70},{0x763D, 0xEA6E},{0x7642, 0xC0F8}, + {0x7643, 0xED74},{0x7646, 0xC0F7},{0x7647, 0xED77},{0x7648, 0xED75},{0x7649, 0xED76},{0x764C, 0xC0F9},{0x7650, 0xF04D},{0x7652, 0xC2A1}, + {0x7653, 0xF04E},{0x7656, 0xC27D},{0x7657, 0xF04F},{0x7658, 0xC27E},{0x7659, 0xF04C},{0x765A, 0xF050},{0x765C, 0xF04A},{0x765F, 0xC3A7}, + {0x7660, 0xF278},{0x7661, 0xC3A8},{0x7662, 0xC46F},{0x7664, 0xF04B},{0x7665, 0xC470},{0x7669, 0xC4EE},{0x766A, 0xF5DF},{0x766C, 0xC57E}, + {0x766D, 0xF6F4},{0x766E, 0xC57D},{0x7670, 0xF7EA},{0x7671, 0xC5F5},{0x7672, 0xC5F6},{0x7675, 0xF9CC},{0x7678, 0xACD1},{0x7679, 0xCFDE}, + {0x767B, 0xB56E},{0x767C, 0xB56F},{0x767D, 0xA5D5},{0x767E, 0xA6CA},{0x767F, 0xCA47},{0x7681, 0xCB71},{0x7682, 0xA86D},{0x7684, 0xAABA}, + {0x7686, 0xACD2},{0x7687, 0xACD3},{0x7688, 0xACD4},{0x7689, 0xD6A6},{0x768A, 0xD2CB},{0x768B, 0xAF6F},{0x768E, 0xB2AE},{0x768F, 0xD6A5}, + {0x7692, 0xDAB8},{0x7693, 0xB571},{0x7695, 0xDAB7},{0x7696, 0xB570},{0x7699, 0xDED5},{0x769A, 0xBD4A},{0x769B, 0xE6BB},{0x769C, 0xE6B8}, + {0x769D, 0xE6B9},{0x769E, 0xE6BA},{0x76A4, 0xED78},{0x76A6, 0xF051},{0x76AA, 0xF471},{0x76AB, 0xF470},{0x76AD, 0xF6F5},{0x76AE, 0xA5D6}, + {0x76AF, 0xCD75},{0x76B0, 0xAF70},{0x76B4, 0xB572},{0x76B5, 0xDED6},{0x76B8, 0xE2E1},{0x76BA, 0xBD4B},{0x76BB, 0xEA74},{0x76BD, 0xF052}, + {0x76BE, 0xF472},{0x76BF, 0xA5D7},{0x76C2, 0xAABB},{0x76C3, 0xACD7},{0x76C4, 0xCFDF},{0x76C5, 0xACD8},{0x76C6, 0xACD6},{0x76C8, 0xACD5}, + {0x76C9, 0xD2CC},{0x76CA, 0xAF71},{0x76CD, 0xAF72},{0x76CE, 0xAF73},{0x76D2, 0xB2B0},{0x76D3, 0xD6A7},{0x76D4, 0xB2AF},{0x76DA, 0xDAB9}, + {0x76DB, 0xB2B1},{0x76DC, 0xB573},{0x76DD, 0xDED7},{0x76DE, 0xB7F8},{0x76DF, 0xB7F9},{0x76E1, 0xBAC9},{0x76E3, 0xBACA},{0x76E4, 0xBD4C}, + {0x76E5, 0xBF64},{0x76E6, 0xEA75},{0x76E7, 0xBF63},{0x76E9, 0xED79},{0x76EA, 0xC0FA},{0x76EC, 0xF053},{0x76ED, 0xF473},{0x76EE, 0xA5D8}, + {0x76EF, 0xA86E},{0x76F0, 0xCD78},{0x76F1, 0xCD77},{0x76F2, 0xAABC},{0x76F3, 0xCD76},{0x76F4, 0xAABD},{0x76F5, 0xCD79},{0x76F7, 0xCFE5}, + {0x76F8, 0xACDB},{0x76F9, 0xACDA},{0x76FA, 0xCFE7},{0x76FB, 0xCFE6},{0x76FC, 0xACDF},{0x76FE, 0xACDE},{0x7701, 0xACD9},{0x7703, 0xCFE1}, + {0x7704, 0xCFE2},{0x7705, 0xCFE3},{0x7707, 0xACE0},{0x7708, 0xCFE0},{0x7709, 0xACDC},{0x770A, 0xCFE4},{0x770B, 0xACDD},{0x7710, 0xD2CF}, + {0x7711, 0xD2D3},{0x7712, 0xD2D1},{0x7713, 0xD2D0},{0x7715, 0xD2D4},{0x7719, 0xD2D5},{0x771A, 0xD2D6},{0x771B, 0xD2CE},{0x771D, 0xD2CD}, + {0x771F, 0xAF75},{0x7720, 0xAF76},{0x7722, 0xD2D7},{0x7723, 0xD2D2},{0x7725, 0xD6B0},{0x7727, 0xD2D8},{0x7728, 0xAF77},{0x7729, 0xAF74}, + {0x772D, 0xD6AA},{0x772F, 0xD6A9},{0x7731, 0xD6AB},{0x7732, 0xD6AC},{0x7733, 0xD6AE},{0x7734, 0xD6AD},{0x7735, 0xD6B2},{0x7736, 0xB2B5}, + {0x7737, 0xB2B2},{0x7738, 0xB2B6},{0x7739, 0xD6A8},{0x773A, 0xB2B7},{0x773B, 0xD6B1},{0x773C, 0xB2B4},{0x773D, 0xD6AF},{0x773E, 0xB2B3}, + {0x7744, 0xDABC},{0x7745, 0xDABE},{0x7746, 0xDABA},{0x7747, 0xDABB},{0x774A, 0xDABF},{0x774B, 0xDAC1},{0x774C, 0xDAC2},{0x774D, 0xDABD}, + {0x774E, 0xDAC0},{0x774F, 0xB574},{0x7752, 0xDEDB},{0x7754, 0xDEE0},{0x7755, 0xDED8},{0x7756, 0xDEDC},{0x7759, 0xDEE1},{0x775A, 0xDEDD}, + {0x775B, 0xB7FA},{0x775C, 0xB843},{0x775E, 0xB7FD},{0x775F, 0xDED9},{0x7760, 0xDEDA},{0x7761, 0xBACE},{0x7762, 0xB846},{0x7763, 0xB7FE}, + {0x7765, 0xB844},{0x7766, 0xB7FC},{0x7767, 0xDEDF},{0x7768, 0xB845},{0x7769, 0xDEDE},{0x776A, 0xB841},{0x776B, 0xB7FB},{0x776C, 0xB842}, + {0x776D, 0xDEE2},{0x776E, 0xE2E6},{0x776F, 0xE2E8},{0x7779, 0xB840},{0x777C, 0xE2E3},{0x777D, 0xBACC},{0x777E, 0xE2E9},{0x777F, 0xBACD}, + {0x7780, 0xE2E7},{0x7781, 0xE2E2},{0x7782, 0xE2E5},{0x7783, 0xE2EA},{0x7784, 0xBACB},{0x7785, 0xE2E4},{0x7787, 0xBD4E},{0x7788, 0xE6BF}, + {0x7789, 0xE6BE},{0x778B, 0xBD51},{0x778C, 0xBD4F},{0x778D, 0xE6BC},{0x778E, 0xBD4D},{0x778F, 0xE6BD},{0x7791, 0xBD50},{0x7795, 0xEA7D}, + {0x7797, 0xEAA1},{0x7799, 0xEA7E},{0x779A, 0xEA76},{0x779B, 0xEA7A},{0x779C, 0xEA79},{0x779D, 0xEA77},{0x779E, 0xBF66},{0x779F, 0xBF67}, + {0x77A0, 0xBF65},{0x77A1, 0xEA78},{0x77A2, 0xEA7B},{0x77A3, 0xEA7C},{0x77A5, 0xBF68},{0x77A7, 0xC140},{0x77A8, 0xEDA3},{0x77AA, 0xC0FC}, + {0x77AB, 0xED7B},{0x77AC, 0xC0FE},{0x77AD, 0xC141},{0x77B0, 0xC0FD},{0x77B1, 0xEDA2},{0x77B2, 0xED7C},{0x77B3, 0xC0FB},{0x77B4, 0xEDA1}, + {0x77B5, 0xED7A},{0x77B6, 0xED7E},{0x77B7, 0xED7D},{0x77BA, 0xF055},{0x77BB, 0xC2A4},{0x77BC, 0xC2A5},{0x77BD, 0xC2A2},{0x77BF, 0xC2A3}, + {0x77C2, 0xF054},{0x77C4, 0xF27B},{0x77C7, 0xC3A9},{0x77C9, 0xF279},{0x77CA, 0xF27A},{0x77CC, 0xF474},{0x77CD, 0xF477},{0x77CE, 0xF475}, + {0x77CF, 0xF476},{0x77D0, 0xF5E0},{0x77D3, 0xC4EF},{0x77D4, 0xF7EB},{0x77D5, 0xF8B4},{0x77D7, 0xC5F7},{0x77D8, 0xF8F8},{0x77D9, 0xF8F9}, + {0x77DA, 0xC666},{0x77DB, 0xA5D9},{0x77DC, 0xACE1},{0x77DE, 0xDAC3},{0x77E0, 0xDEE3},{0x77E2, 0xA5DA},{0x77E3, 0xA86F},{0x77E5, 0xAABE}, + {0x77E7, 0xCFE8},{0x77E8, 0xCFE9},{0x77E9, 0xAF78},{0x77EC, 0xDAC4},{0x77ED, 0xB575},{0x77EE, 0xB847},{0x77EF, 0xC142},{0x77F0, 0xEDA4}, + {0x77F1, 0xF27C},{0x77F2, 0xF478},{0x77F3, 0xA5DB},{0x77F7, 0xCDA1},{0x77F8, 0xCD7A},{0x77F9, 0xCD7C},{0x77FA, 0xCD7E},{0x77FB, 0xCD7D}, + {0x77FC, 0xCD7B},{0x77FD, 0xAABF},{0x7802, 0xACE2},{0x7803, 0xCFF2},{0x7805, 0xCFED},{0x7806, 0xCFEA},{0x7809, 0xCFF1},{0x780C, 0xACE4}, + {0x780D, 0xACE5},{0x780E, 0xCFF0},{0x780F, 0xCFEF},{0x7810, 0xCFEE},{0x7811, 0xCFEB},{0x7812, 0xCFEC},{0x7813, 0xCFF3},{0x7814, 0xACE3}, + {0x781D, 0xAF7C},{0x781F, 0xAFA4},{0x7820, 0xAFA3},{0x7821, 0xD2E1},{0x7822, 0xD2DB},{0x7823, 0xD2D9},{0x7825, 0xAFA1},{0x7826, 0xD6B9}, + {0x7827, 0xAF7A},{0x7828, 0xD2DE},{0x7829, 0xD2E2},{0x782A, 0xD2E4},{0x782B, 0xD2E0},{0x782C, 0xD2DA},{0x782D, 0xAFA2},{0x782E, 0xD2DF}, + {0x782F, 0xD2DD},{0x7830, 0xAF79},{0x7831, 0xD2E5},{0x7832, 0xAFA5},{0x7833, 0xD2E3},{0x7834, 0xAF7D},{0x7835, 0xD2DC},{0x7837, 0xAF7E}, + {0x7838, 0xAF7B},{0x7843, 0xB2B9},{0x7845, 0xD6BA},{0x7848, 0xD6B3},{0x7849, 0xD6B5},{0x784A, 0xD6B7},{0x784C, 0xD6B8},{0x784D, 0xD6B6}, + {0x784E, 0xB2BA},{0x7850, 0xD6BB},{0x7852, 0xD6B4},{0x785C, 0xDAC8},{0x785D, 0xB576},{0x785E, 0xDAD0},{0x7860, 0xDAC5},{0x7862, 0xDAD1}, + {0x7864, 0xDAC6},{0x7865, 0xDAC7},{0x7868, 0xDACF},{0x7869, 0xDACE},{0x786A, 0xDACB},{0x786B, 0xB2B8},{0x786C, 0xB577},{0x786D, 0xDAC9}, + {0x786E, 0xDACC},{0x786F, 0xB578},{0x7870, 0xDACD},{0x7871, 0xDACA},{0x7879, 0xDEEE},{0x787B, 0xDEF2},{0x787C, 0xB84E},{0x787E, 0xE2F0}, + {0x787F, 0xB851},{0x7880, 0xDEF0},{0x7883, 0xDEED},{0x7884, 0xDEE8},{0x7885, 0xDEEA},{0x7886, 0xDEEB},{0x7887, 0xDEE4},{0x7889, 0xB84D}, |