FreeType 1.31.1
This commit is contained in:
503
lib/ttcmap.c
Normal file
503
lib/ttcmap.c
Normal file
@@ -0,0 +1,503 @@
|
||||
/*******************************************************************
|
||||
*
|
||||
* ttcmap.c 1.0
|
||||
*
|
||||
* TrueType Character Mappings
|
||||
*
|
||||
* Copyright 1996-1999 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used
|
||||
* modified and distributed under the terms of the FreeType project
|
||||
* license, LICENSE.TXT. By continuing to use, modify, or distribute
|
||||
* this file you indicate that you have read the license and
|
||||
* understand and accept it fully.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
#include "ttobjs.h"
|
||||
#include "ttdebug.h"
|
||||
#include "ttfile.h"
|
||||
#include "ttmemory.h"
|
||||
#include "ttload.h"
|
||||
#include "ttcmap.h"
|
||||
|
||||
/* required by the tracing mode */
|
||||
#undef TT_COMPONENT
|
||||
#define TT_COMPONENT trace_cmap
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
* Function : CharMap_Load
|
||||
*
|
||||
* Description : Loads a given charmap into memory.
|
||||
*
|
||||
* Input : cmap pointer to cmap table
|
||||
*
|
||||
* Output : Error code.
|
||||
*
|
||||
* Notes : - Assumes the the stream is already used (opened).
|
||||
*
|
||||
* - In case of error, releases all partially allocated
|
||||
* tables.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
LOCAL_FUNC
|
||||
TT_Error CharMap_Load( PCMapTable cmap,
|
||||
TT_Stream input )
|
||||
{
|
||||
DEFINE_LOAD_LOCALS( input );
|
||||
|
||||
UShort num_SH, num_Seg, i;
|
||||
|
||||
UShort u, l;
|
||||
|
||||
PCMap0 cmap0;
|
||||
PCMap2 cmap2;
|
||||
PCMap4 cmap4;
|
||||
PCMap6 cmap6;
|
||||
|
||||
PCMap2SubHeader cmap2sub;
|
||||
PCMap4Segment segments;
|
||||
|
||||
|
||||
if ( cmap->loaded )
|
||||
return TT_Err_Ok;
|
||||
|
||||
if ( FILE_Seek( cmap->offset ) )
|
||||
return error;
|
||||
|
||||
switch ( cmap->format )
|
||||
{
|
||||
case 0:
|
||||
cmap0 = &cmap->c.cmap0;
|
||||
|
||||
if ( ALLOC( cmap0->glyphIdArray, 256L ) ||
|
||||
FILE_Read( (void*)cmap0->glyphIdArray, 256L ) )
|
||||
goto Fail;
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
num_SH = 0;
|
||||
cmap2 = &cmap->c.cmap2;
|
||||
|
||||
/* allocate subheader keys */
|
||||
|
||||
if ( ALLOC_ARRAY( cmap2->subHeaderKeys, 256, UShort ) ||
|
||||
ACCESS_Frame( 512L ) )
|
||||
goto Fail;
|
||||
|
||||
for ( i = 0; i < 256; i++ )
|
||||
{
|
||||
u = GET_UShort() / 8;
|
||||
cmap2->subHeaderKeys[i] = u;
|
||||
|
||||
if ( num_SH < u )
|
||||
num_SH = u;
|
||||
}
|
||||
|
||||
FORGET_Frame();
|
||||
|
||||
/* load subheaders */
|
||||
|
||||
cmap2->numGlyphId = l =
|
||||
( ( cmap->length - 2L * (256 + 3) - num_SH * 8L ) & 0xffff) / 2;
|
||||
|
||||
if ( ALLOC_ARRAY( cmap2->subHeaders,
|
||||
num_SH + 1,
|
||||
TCMap2SubHeader ) ||
|
||||
ACCESS_Frame( ( num_SH + 1 ) * 8L ) )
|
||||
goto Fail;
|
||||
|
||||
cmap2sub = cmap2->subHeaders;
|
||||
|
||||
for ( i = 0; i <= num_SH; i++ )
|
||||
{
|
||||
cmap2sub->firstCode = GET_UShort();
|
||||
cmap2sub->entryCount = GET_UShort();
|
||||
cmap2sub->idDelta = GET_Short();
|
||||
/* we apply the location offset immediately */
|
||||
cmap2sub->idRangeOffset = GET_UShort() - ( num_SH - i ) * 8 - 2;
|
||||
|
||||
cmap2sub++;
|
||||
}
|
||||
|
||||
FORGET_Frame();
|
||||
|
||||
/* load glyph ids */
|
||||
|
||||
if ( ALLOC_ARRAY( cmap2->glyphIdArray, l, UShort ) ||
|
||||
ACCESS_Frame( l * 2L ) )
|
||||
goto Fail;
|
||||
|
||||
for ( i = 0; i < l; i++ )
|
||||
cmap2->glyphIdArray[i] = GET_UShort();
|
||||
|
||||
FORGET_Frame();
|
||||
break;
|
||||
|
||||
case 4:
|
||||
cmap4 = &cmap->c.cmap4;
|
||||
|
||||
/* load header */
|
||||
|
||||
if ( ACCESS_Frame( 8L ) )
|
||||
goto Fail;
|
||||
|
||||
cmap4->segCountX2 = GET_UShort();
|
||||
cmap4->searchRange = GET_UShort();
|
||||
cmap4->entrySelector = GET_UShort();
|
||||
cmap4->rangeShift = GET_UShort();
|
||||
|
||||
num_Seg = cmap4->segCountX2 / 2;
|
||||
|
||||
FORGET_Frame();
|
||||
|
||||
/* load segments */
|
||||
|
||||
if ( ALLOC_ARRAY( cmap4->segments,
|
||||
num_Seg,
|
||||
TCMap4Segment ) ||
|
||||
ACCESS_Frame( (num_Seg * 4 + 1) * 2L ) )
|
||||
goto Fail;
|
||||
|
||||
segments = cmap4->segments;
|
||||
|
||||
for ( i = 0; i < num_Seg; i++ )
|
||||
segments[i].endCount = GET_UShort();
|
||||
|
||||
(void)GET_UShort();
|
||||
|
||||
for ( i = 0; i < num_Seg; i++ )
|
||||
segments[i].startCount = GET_UShort();
|
||||
|
||||
for ( i = 0; i < num_Seg; i++ )
|
||||
segments[i].idDelta = GET_Short();
|
||||
|
||||
for ( i = 0; i < num_Seg; i++ )
|
||||
segments[i].idRangeOffset = GET_UShort();
|
||||
|
||||
FORGET_Frame();
|
||||
|
||||
cmap4->numGlyphId = l =
|
||||
( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xffff ) / 2;
|
||||
|
||||
/* load ids */
|
||||
|
||||
if ( ALLOC_ARRAY( cmap4->glyphIdArray, l , UShort ) ||
|
||||
ACCESS_Frame( l * 2L ) )
|
||||
goto Fail;
|
||||
|
||||
for ( i = 0; i < l; i++ )
|
||||
cmap4->glyphIdArray[i] = GET_UShort();
|
||||
|
||||
FORGET_Frame();
|
||||
break;
|
||||
|
||||
case 6:
|
||||
cmap6 = &cmap->c.cmap6;
|
||||
|
||||
if ( ACCESS_Frame( 4L ) )
|
||||
goto Fail;
|
||||
|
||||
cmap6->firstCode = GET_UShort();
|
||||
cmap6->entryCount = GET_UShort();
|
||||
|
||||
FORGET_Frame();
|
||||
|
||||
l = cmap6->entryCount;
|
||||
|
||||
if ( ALLOC_ARRAY( cmap6->glyphIdArray,
|
||||
cmap6->entryCount,
|
||||
Short ) ||
|
||||
ACCESS_Frame( l * 2L ) )
|
||||
goto Fail;
|
||||
|
||||
for ( i = 0; i < l; i++ )
|
||||
cmap6->glyphIdArray[i] = GET_UShort();
|
||||
|
||||
FORGET_Frame();
|
||||
break;
|
||||
|
||||
default: /* corrupt character mapping table */
|
||||
return TT_Err_Invalid_CharMap_Format;
|
||||
|
||||
}
|
||||
return TT_Err_Ok;
|
||||
|
||||
Fail:
|
||||
CharMap_Free( cmap );
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
* Function : CharMap_Free
|
||||
*
|
||||
* Description : Releases a given charmap table.
|
||||
*
|
||||
* Input : cmap pointer to cmap table
|
||||
*
|
||||
* Output : Error code.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
LOCAL_FUNC
|
||||
TT_Error CharMap_Free( PCMapTable cmap )
|
||||
{
|
||||
if ( !cmap )
|
||||
return TT_Err_Ok;
|
||||
|
||||
switch ( cmap->format )
|
||||
{
|
||||
case 0:
|
||||
FREE( cmap->c.cmap0.glyphIdArray );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
FREE( cmap->c.cmap2.subHeaderKeys );
|
||||
FREE( cmap->c.cmap2.subHeaders );
|
||||
FREE( cmap->c.cmap2.glyphIdArray );
|
||||
break;
|
||||
|
||||
case 4:
|
||||
FREE( cmap->c.cmap4.segments );
|
||||
FREE( cmap->c.cmap4.glyphIdArray );
|
||||
cmap->c.cmap4.segCountX2 = 0;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
FREE( cmap->c.cmap6.glyphIdArray );
|
||||
cmap->c.cmap6.entryCount = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* invalid table format, do nothing */
|
||||
;
|
||||
}
|
||||
|
||||
cmap->loaded = FALSE;
|
||||
return TT_Err_Ok;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
* Function : CharMap_Index
|
||||
*
|
||||
* Description : Performs charcode->glyph index translation.
|
||||
*
|
||||
* Input : cmap pointer to cmap table
|
||||
*
|
||||
* Output : Glyph index, 0 in case of failure.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
static UShort code_to_index0( UShort charCode, PCMap0 cmap0 );
|
||||
static UShort code_to_index2( UShort charCode, PCMap2 cmap2 );
|
||||
static UShort code_to_index4( UShort charCode, PCMap4 cmap4 );
|
||||
static UShort code_to_index6( UShort charCode, PCMap6 cmap6 );
|
||||
|
||||
|
||||
LOCAL_FUNC
|
||||
UShort CharMap_Index( PCMapTable cmap,
|
||||
UShort charcode )
|
||||
{
|
||||
switch ( cmap->format )
|
||||
{
|
||||
case 0:
|
||||
return code_to_index0( charcode, &cmap->c.cmap0 );
|
||||
case 2:
|
||||
return code_to_index2( charcode, &cmap->c.cmap2 );
|
||||
case 4:
|
||||
return code_to_index4( charcode, &cmap->c.cmap4 );
|
||||
case 6:
|
||||
return code_to_index6( charcode, &cmap->c.cmap6 );
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
* Function : code_to_index0
|
||||
*
|
||||
* Description : Converts the character code into a glyph index.
|
||||
* Uses format 0.
|
||||
* charCode will be masked to get a value in the range
|
||||
* 0x00-0xFF.
|
||||
*
|
||||
* Input : charCode the wanted character code
|
||||
* cmap0 a pointer to a cmap table in format 0
|
||||
*
|
||||
* Output : Glyph index into the glyphs array.
|
||||
* 0 if the glyph does not exist.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
static UShort code_to_index0( UShort charCode,
|
||||
PCMap0 cmap0 )
|
||||
{
|
||||
if ( charCode <= 0xFF )
|
||||
return cmap0->glyphIdArray[charCode];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
* Function : code_to_index2
|
||||
*
|
||||
* Description : Converts the character code into a glyph index.
|
||||
* Uses format 2.
|
||||
*
|
||||
* Input : charCode the wanted character code
|
||||
* cmap2 a pointer to a cmap table in format 2
|
||||
*
|
||||
* Output : Glyph index into the glyphs array.
|
||||
* 0 if the glyph does not exist.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
static UShort code_to_index2( UShort charCode,
|
||||
PCMap2 cmap2 )
|
||||
{
|
||||
UShort index1, idx, offset;
|
||||
TCMap2SubHeader sh2;
|
||||
|
||||
|
||||
index1 = cmap2->subHeaderKeys[charCode <= 0xFF ?
|
||||
charCode : (charCode >> 8)];
|
||||
|
||||
if ( index1 == 0 )
|
||||
{
|
||||
if ( charCode <= 0xFF )
|
||||
return cmap2->glyphIdArray[charCode]; /* 8bit character code */
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else /* 16bit character code */
|
||||
{
|
||||
if ( charCode <= 0xFF )
|
||||
return 0;
|
||||
|
||||
sh2 = cmap2->subHeaders[index1];
|
||||
|
||||
if ( (charCode & 0xFF) < sh2.firstCode )
|
||||
return 0;
|
||||
|
||||
if ( (charCode & 0xFF) >= (sh2.firstCode + sh2.entryCount) )
|
||||
return 0;
|
||||
|
||||
offset = sh2.idRangeOffset / 2 + (charCode & 0xFF) - sh2.firstCode;
|
||||
if ( offset < cmap2->numGlyphId )
|
||||
idx = cmap2->glyphIdArray[offset];
|
||||
else
|
||||
return 0;
|
||||
|
||||
if ( idx )
|
||||
return (idx + sh2.idDelta) & 0xFFFF;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
* Function : code_to_index4
|
||||
*
|
||||
* Description : Converts the character code into a glyph index.
|
||||
* Uses format 4.
|
||||
*
|
||||
* Input : charCode the wanted character code
|
||||
* cmap4 a pointer to a cmap table in format 4
|
||||
*
|
||||
* Output : Glyph index into the glyphs array.
|
||||
* 0 if the glyph does not exist.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
static UShort code_to_index4( UShort charCode,
|
||||
PCMap4 cmap4 )
|
||||
{
|
||||
UShort index1, segCount;
|
||||
UShort i;
|
||||
TCMap4Segment seg4;
|
||||
|
||||
|
||||
segCount = cmap4->segCountX2 / 2;
|
||||
|
||||
for ( i = 0; i < segCount; i++ )
|
||||
if ( charCode <= cmap4->segments[i].endCount )
|
||||
break;
|
||||
|
||||
/* Safety check - even though the last endCount should be 0xFFFF */
|
||||
if ( i >= segCount )
|
||||
return 0;
|
||||
|
||||
seg4 = cmap4->segments[i];
|
||||
|
||||
if ( charCode < seg4.startCount )
|
||||
return 0;
|
||||
|
||||
if ( seg4.idRangeOffset == 0 )
|
||||
return ( charCode + seg4.idDelta ) & 0xFFFF;
|
||||
else
|
||||
{
|
||||
index1 = seg4.idRangeOffset / 2 + (charCode - seg4.startCount) -
|
||||
(segCount - i);
|
||||
|
||||
if ( index1 < cmap4->numGlyphId )
|
||||
{
|
||||
if ( cmap4->glyphIdArray[index1] == 0 )
|
||||
return 0;
|
||||
else
|
||||
return ( cmap4->glyphIdArray[index1] + seg4.idDelta ) & 0xFFFF;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
* Function : code_to_index6
|
||||
*
|
||||
* Description : Converts the character code into a glyph index.
|
||||
* Uses format 6.
|
||||
*
|
||||
* Input : charCode the wanted character code
|
||||
* cmap6 a pointer to a cmap table in format 6
|
||||
*
|
||||
* Output : Glyph index into the glyphs array.
|
||||
* 0 if the glyph does not exist (`missing character glyph').
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
static UShort code_to_index6( UShort charCode,
|
||||
PCMap6 cmap6 )
|
||||
{
|
||||
UShort firstCode;
|
||||
|
||||
|
||||
firstCode = cmap6->firstCode;
|
||||
|
||||
if ( charCode < firstCode )
|
||||
return 0;
|
||||
|
||||
if ( charCode >= (firstCode + cmap6->entryCount) )
|
||||
return 0;
|
||||
|
||||
return cmap6->glyphIdArray[charCode - firstCode];
|
||||
}
|
||||
|
||||
|
||||
/* END */
|
||||
Reference in New Issue
Block a user