2 * Kimikage NScripter Plugins Project
\r
4 * This software is distributed under a BSD-style license.
\r
5 * See license.txt for more information.
\r
8 #include "CharacterMap.h"
\r
10 // This code is based on a sample code of
\r
11 // KB
\81F241020 (http://support.microsoft.com/kb/241020/)
\r
15 CharacterMap::CharacterMap( void )
\r
17 hdc = CreateCompatibleDC( NULL );
\r
22 CharacterMap::~CharacterMap( void )
\r
31 bool CharacterMap::selectFont( const LOGFONTA *font )
\r
34 HFONT hFont = CreateFontIndirectA( font );
\r
35 SelectObject( hdc, hFont );
\r
37 if ( !fetchUnicodeCMapTable() )
\r
42 characterCount = getCharacterCount( cmapTable );
\r
46 void CharacterMap::clearFont( void )
\r
48 if ( NULL != hFont )
\r
50 DeleteObject( hFont );
\r
54 delete [] cmapTable;
\r
60 void CharacterMap::swapArrays( CMap4 *format4 )
\r
62 const USHORT *startCount = getStartCountArray( format4 );
\r
63 const USHORT *idDelta = getIdDeltaArray( format4 );
\r
64 const USHORT *idRangeOffset = getIdRangeOffsetArray( format4 );
\r
65 const USHORT *endCount = getEndCountArray( format4 );
\r
66 const USHORT *endOfBuffer = reinterpret_cast<const USHORT *>(
\r
67 reinterpret_cast<LPBYTE>( format4 ) + format4->length );
\r
69 const DWORD segCount = format4->segCountX2 / 2;
\r
70 for( DWORD i = 0; i < segCount; ++i )
\r
72 swap( static_cast<USHORT>( endCount[i] ) );
\r
73 swap( static_cast<USHORT>( startCount[i] ) );
\r
74 swap( static_cast<USHORT>( idDelta[i] ) );
\r
75 swap( static_cast<USHORT>( idRangeOffset[i] ) );
\r
78 USHORT *glyphId = const_cast<USHORT *>( &idRangeOffset[segCount] );
\r
79 while( glyphId < endOfBuffer )
\r
86 bool CharacterMap::getEncoding( CMapEncoding *encoding, int index ) const
\r
88 DWORD result = GetFontData( hdc, cmapName,
\r
89 cmapHeaderSize + encodingSize * index,
\r
90 encoding, sizeof( CMapEncoding ) );
\r
91 if ( result != sizeof( CMapEncoding ) ) return false;
\r
93 swap( encoding->PlatformId );
\r
94 swap( encoding->EncodingId );
\r
95 swap( encoding->Offset );
\r
100 bool CharacterMap::getFormat4Header( CMap4 *header, DWORD offset ) const
\r
102 DWORD written = GetFontData( hdc, cmapName, offset, header, format4HeaderSize );
\r
103 if ( written != format4HeaderSize ) return false;
\r
105 USHORT *fields = reinterpret_cast<USHORT *>( header );
\r
106 for( int i = 0; i < 7; ++i )
\r
114 bool CharacterMap::getFormat4Subtable( CMap4 *subtable, DWORD offset ) const
\r
116 if ( !getFormat4Header( subtable, offset ) ) return false;
\r
118 const DWORD length = subtable->length - format4HeaderSize;
\r
119 DWORD written = GetFontData( hdc, cmapName, offset + format4HeaderSize,
\r
120 subtable->Arrays, length );
\r
122 if ( written != length ) return false;
\r
124 swapArrays( subtable );
\r
130 unsigned int CharacterMap::getCharacterCount( const CMap4 *format4 )
\r
132 if ( format4 == NULL ) return 0;
\r
134 const USHORT *endCount = getEndCountArray( format4 );
\r
135 const USHORT *startCount = getStartCountArray( format4 );
\r
136 const USHORT *idRangeOffset = getIdRangeOffsetArray( format4 );
\r
137 const USHORT segCount = format4->segCountX2 / 2;
\r
139 unsigned int numberOfGlyphs = 0;
\r
141 // by adding up the coverage of each segment
\r
142 for ( USHORT i = 0; i < segCount; ++i )
\r
144 if ( idRangeOffset[i] == 0 )
\r
146 // if per the TT spec, the idRangeOffset element is zero,
\r
147 // all of the characters in this segment exist.
\r
148 numberOfGlyphs += endCount[i] - startCount[i] + 1;
\r
152 const USHORT *glyphId = &(idRangeOffset[i]) + idRangeOffset[i] / 2;
\r
154 for (USHORT ch = startCount[i]; ch <= endCount[i]; ++ch )
\r
156 USHORT idResult = glyphId[ch - startCount[i]];
\r
157 if (idResult != 0) numberOfGlyphs++;
\r
160 return numberOfGlyphs;
\r
163 bool CharacterMap::fetchUnicodeCMapTable( void )
\r
165 USHORT numberOfEncodings;
\r
166 // Get the number of subtables in the CMAP table from the CMAP header
\r
167 // The # of subtables is the second USHORT in the CMAP table, per the TT Spec.
\r
168 DWORD written = GetFontData( hdc, cmapName, sizeof( USHORT ), &numberOfEncodings, sizeof( USHORT ) );
\r
169 if ( written != sizeof( USHORT ) )
\r
171 // Something is wrong, we probably got GDI_ERROR back
\r
172 // Probably this means that the Device Context does not have
\r
173 // a TrueType font selected into it.
\r
176 swap( numberOfEncodings );
\r
178 CMapEncoding encoding = {}; // The current encoding
\r
180 // Get the encodings and look for a Unicode Encoding
\r
181 DWORD iUnicode = numberOfEncodings;
\r
182 for ( DWORD i = 0; i < numberOfEncodings; ++i )
\r
184 if ( !getEncoding( &encoding, i ) ) return false;
\r
186 if (encoding.PlatformId == 3 &&
\r
187 (encoding.EncodingId == 1 || encoding.EncodingId == 0) )
\r
189 iUnicode = i; // Set the index to the Unicode encoding
\r
193 // index out of range means failure to find a Unicode mapping
\r
194 if ( iUnicode >= numberOfEncodings )
\r
196 // No Unicode encoding found.
\r
200 CMap4 format4; // Unicode subtable format
\r
201 // Get the header entries(first 7 USHORTs) for the Unicode encoding.
\r
202 if ( !getFormat4Header( &format4, encoding.Offset ) )
\r
207 if ( format4.format != 4 )
\r
209 // Windows7
\82Ì"
\82l
\82r
\96¾
\92©"
\93\99\82Íformat4.format
\82ª12
\r
213 delete [] cmapTable;
\r
214 cmapTable = reinterpret_cast<CMap4 *>( new unsigned char[format4.length] );
\r
215 if ( cmapTable == NULL ) return false;
\r
217 if ( !getFormat4Subtable( cmapTable, encoding.Offset )) return false;
\r
222 bool CharacterMap::findFormat4Segment(
\r
223 CMap4 *table, // a valid Format4 subtable buffer
\r
224 USHORT ch, // Unicode character to search for
\r
225 USHORT &index // out: index of segment containing ch
\r
228 if ( NULL == table ) return FALSE;
\r
230 const USHORT segCount = table->segCountX2 / 2;
\r
231 const USHORT *startCount = getStartCountArray( table );
\r
232 const USHORT *endCount = getEndCountArray( table );
\r
234 // Find segment that could contain the Unicode character code
\r
235 for( USHORT i = 0; i < segCount; ++i )
\r
237 if ( endCount[i] >= ch )
\r
239 // character code not within the range of the segment
\r
240 if ( startCount[i] > ch ) return false;
\r
241 // this segment contains the character code
\r
246 // We looked in them all, ch not there
\r
251 unsigned int CharacterMap::getGlyphIndex( unsigned int character )
\r
253 When the TrueType font contains a glyph for ch, the
\r
254 function returns the glyph index for that character.
\r
256 If an error occurs, or there is no glyph for ch, the
\r
257 function will return the missing glyph index of zero.
\r
260 if ( NULL == cmapTable ) return 0;
\r
263 // Find the cmap segment that has the character code.
\r
264 if ( !findFormat4Segment( cmapTable, static_cast<USHORT>( character ), i ) )
\r
266 return 0; //
\8c©
\82Â
\82©
\82ç
\82È
\82©
\82Á
\82½
\r
269 // Get pointers to the cmap data
\r
271 const USHORT *idRangeOffset = getIdRangeOffsetArray( cmapTable );
\r
272 const USHORT *idDelta = getIdDeltaArray( cmapTable );
\r
273 const USHORT *startCount = getStartCountArray( cmapTable );
\r
275 if ( idRangeOffset[i] == 0 ) // Per TT spec, if the RangeOffset is zero,
\r
277 // calculate the glyph index directly
\r
278 return static_cast<unsigned int>( (idDelta[i] + character) & 0xFFFF );
\r
281 const USHORT *glyphId = &idRangeOffset[i] + idRangeOffset[i] / 2;
\r
282 // otherwise, use the glyph id array to get the index
\r
283 USHORT idResult = glyphId[character - startCount[i]]; // indexing equation from TT spec
\r
285 if ( !idResult ) return 0; // return the missing glyph
\r
286 // Per TT spec, nonzero means there is a glyph
\r
287 return (idDelta[i] + idResult) & 0xFFFF;
\r
292 From the TrueType Spec revision 1.66
\r
294 USHORT Table Version #
\r
295 USHORT Number of encoding tables
\r
297 const size_t CharacterMap::cmapHeaderSize = sizeof( USHORT ) * 2;
\r
299 /* ENCODING entry Data aka CMAPENCODING
\r
300 From the TrueType Spec revision 1.66
\r
303 USHORT Platform Specific Encoding Id
\r
304 ULONG Byte Offset from beginning of table
\r
306 const size_t CharacterMap::encodingSize = sizeof( USHORT ) * 2 + sizeof( ULONG );
\r
308 const size_t CharacterMap::format4HeaderSize = sizeof( USHORT ) * 7;
\r
310 // DWORD packed four letter table name for each GetFontData()
\r
311 // function call when working with the CMAP TrueType table
\r
312 const DWORD CharacterMap::cmapName = makeTableName( 'c','m','a','p' );
\r