home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: SysTools
/
SysTools.zip
/
ft-beta.zip
/
freetype
/
lib
/
ttcmap.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-10-06
|
12KB
|
484 lines
/*******************************************************************
*
* ttcmap.c 1.0
*
* TrueType Character Mappings
*
* Copyright 1996, 1997 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 "tterror.h"
#include "ttfile.h"
#include "ttmemory.h"
#include "ttload.h"
#include "ttcmap.h"
/*******************************************************************
*
* Function : CharMap_Load
*
* Description : Load one 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.
*
******************************************************************/
TT_Error CharMap_Load( PCMapTable cmap, TT_Stream input )
{
DEFINE_LOAD_LOCALS(input);
int num_SH, num_Seg, i;
unsigned short 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( cmap2->subHeaderKeys, 256 ) ||
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 */
l = cmap->length -
sizeof ( UShort ) * (256 + 3) - num_SH * 8;
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 */
l /= 2;
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( 8 ) )
goto Fail;
cmap4 = &cmap->c.cmap4;
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();
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_UShort();
for ( i = 0; i < num_Seg; i++ )
segments[i].idRangeOffset = GET_UShort();
FORGET_Frame();
l = ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xffff;
/* load ids */
if ( ALLOC( cmap4->glyphIdArray, l ) ||
ACCESS_Frame( l ) )
goto Fail;
for ( i = 0; i < l / 2; i++ )
cmap4->glyphIdArray[i] = GET_UShort();
FORGET_Frame();
break;
case 6:
cmap6 = &cmap->c.cmap6;
if ( ACCESS_Frame( 4 ) )
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 one given charmap table
*
* Input : cmap pointer to cmap table
*
* Output : error code
*
******************************************************************/
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 : Perform charcode->glyph index translation
*
* Input : cmap pointer to cmap table
*
* Output : glyph index, -1 in case of failure
*
* Notes :
*
******************************************************************/
Int code_to_index0( UShort charCode, PCMap0 cmap0 );
Int code_to_index2( UShort charCode, PCMap2 cmap2 );
Int code_to_index4( UShort charCode, PCMap4 cmap4 );
Int code_to_index6( UShort charCode, PCMap6 cmap6 );
Int 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 -1;
}
}
/*******************************************************************
*
* Function : code_to_index0
*
* Description : Convert 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.
*
******************************************************************/
Int code_to_index0( UShort charCode,
PCMap0 cmap0 )
{
if ( charCode <= 0xFF )
return cmap0->glyphIdArray[charCode];
else
return 0;
}
/*******************************************************************
*
* Function : code_to_index2
*
* Description : Convert 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.
*
******************************************************************/
Int code_to_index2( UShort charCode,
PCMap2 cmap2 )
{
UShort index1;
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;
return ( cmap2->glyphIdArray[sh2.idRangeOffset / 2 + (charCode & 0xFF) -
sh2.firstCode] + sh2.idDelta ) & 0xFFFF;
}
}
/*******************************************************************
*
* Function : code_to_index4
*
* Description : Convert 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.
*
******************************************************************/
Int code_to_index4( UShort charCode,
PCMap4 cmap4 )
{
UShort index1, segCount;
Int 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 ( cmap4->glyphIdArray[index1] == 0 )
return 0;
else
return ( cmap4->glyphIdArray[index1] + seg4.idDelta ) & 0xFFFF;
}
}
/*******************************************************************
*
* Function : code_to_index6
*
* Description : Convert 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')
*
******************************************************************/
Int 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];
}