#ifndef __IBMC__
# ifndef __WATCOMC__
# error "This source requires IBM VisualAge C++ or Watcom C/C++"
# endif
#endif
#undef USE_UCONV
#define INCL_WINSHELLDATA
#define INCL_DOSMISC
#define INCL_DOSNLS
#define INCL_DOSPROCESS
#define INCL_GRE_DCS
#define INCL_GRE_DEVSUPPORT
#define INCL_DDIMISC
#define INCL_IFI
#include <os2.h>
#include <pmddi.h>
#ifdef USE_UCONV
#include <uconv.h>
#endif
#include <string.h>
#include <stdlib.h>
#define _syscall _System
#include "32pmifi.h"
#include "freetype.h"
#include "ftxkern.h"
#include "ftxwidth.h"
#include "ftifi.h"
#define NETSCAPE_FIX
#define FAKE_TNR
LONG _System ConvertFontFile(PSZ pszSrc, PSZ pszDestDir, PSZ pszNewName);
HFF _System LoadFontFile(PSZ pszFileName);
LONG _System UnloadFontFile(HFF hff);
LONG _System QueryFaces(HFF hff, PIFIMETRICS pifiMetrics, ULONG cMetricLen,
ULONG cFountCount, ULONG cStart);
HFC _System OpenFontContext(HFF hff, ULONG ulFont);
LONG _System SetFontContext(HFC hfc, PCONTEXTINFO pci);
LONG _System CloseFontContext(HFC hfc);
LONG _System QueryFaceAttr(HFC hfc, ULONG iQuery, PBYTE pBuffer,
ULONG cb, PGLYPH pagi, GLYPH giStart);
LONG _System QueryCharAttr(HFC hfc, PCHARATTR pCharAttr,
PBITMAPMETRICS pbmm);
LONG _System QueryFullFaces(HFF hff, PVOID pBuff, PULONG buflen,
PULONG cFontCount, ULONG cStart);
FDDISPATCH fdisp = {
LoadFontFile,
QueryFaces,
UnloadFontFile,
OpenFontContext,
SetFontContext,
CloseFontContext,
QueryFaceAttr,
QueryCharAttr,
NULL,
ConvertFontFile,
QueryFullFaces
};
#pragma export (fdhdr, "FONT_DRIVER_DISPATCH_TABLE", 1)
FDHEADER fdhdr =
{
sizeof(FDHEADER),
"OS/2 FONT DRIVER",
"TrueType (Using FreeType Engine)",
IFI_VERSION20,
0,
&fdisp
};
#ifdef DEBUG
HFILE LogHandle = NULLHANDLE;
ULONG Written = 0;
char log[2048] = "";
char buf[2048] = "";
char* itoa10( int i, char* buffer ) {
char* ptr = buffer;
char* rptr = buffer;
char digit;
if (i == 0) {
buffer[0] = '0';
buffer[1] = 0;
return buffer;
}
if (i < 0) {
*ptr = '-';
ptr++; rptr++;
i = -i;
}
while (i != 0) {
*ptr = (char) (i % 10 + '0');
ptr++;
i /= 10;
}
*ptr = 0; ptr--;
while (ptr > rptr) {
digit = *ptr;
*ptr = *rptr;
*rptr = digit;
ptr--;
rptr++;
}
return buffer;
}
# define COPY(s) strcpy(log, s)
# define CAT(s) strcat(log, s)
# define CATI(v) strcat(log, itoa10( (int)v, buf ))
# define WRITE DosWrite(LogHandle, log, strlen(log), &Written)
# define ERET1(label) { COPY("Error at "); \
CATI(__LINE__); \
CAT("\r\n"); \
WRITE; \
goto label; \
}
# define ERRRET(e) { COPY("Error at "); \
CATI(__LINE__); \
CAT("\r\n"); \
WRITE; \
return(e); \
}
#else
# define COPY(s)
# define CAT(s)
# define CATI(v)
# define WRITE
# define ERET1(label) goto label;
# define ERRRET(e) return(e);
#endif
TT_Engine engine;
typedef struct _TListElement TListElement, *PListElement;
struct _TListElement
{
PListElement next;
PListElement prev;
long key;
void* data;
};
typedef struct _TList TList, *PList;
struct _TList
{
PListElement head;
PListElement tail;
int count;
};
static PListElement free_elements = 0;
#if 0
typedef struct _TGlyph_Image TGlyph_Image, *PGlyph_Image;
struct _TGlyph_Image
{
PListElement element;
TT_Glyph_Metrics metrics;
TT_Outline outline;
};
#endif
typedef struct _TFontFace TFontFace, *PFontFace;
struct _TFontFace
{
TT_Face face;
TT_Glyph glyph;
TT_CharMap charMap;
TT_Kerning directory;
USHORT *widths;
USHORT *kernIndices;
LONG em_size;
ULONG flags;
#if 0
TList sizes;
#endif
LONG charMode;
};
typedef struct _TFontFile TFontFile, *PFontFile;
struct _TFontFile
{
PListElement element;
HFF hff;
CHAR filename[260];
LONG ref_count;
ULONG flags;
ULONG numFaces;
TFontFace *faces;
};
#define FC_FLAG_FIXED_WIDTH 1
#define FC_FLAG_DBCS_FACE 2
#define FL_FLAG_FAKE_ROMAN 8
#define FL_FLAG_LIVE_FACE 16
#define FL_FLAG_CONTEXT_OPEN 32
#define FL_FLAG_ALREADY_USED 64
#define FL_FLAG_DBCS_FILE 128
int max_open_files = 10;
ULONG ulProcessCount = 0;
static TList liveFiles = { NULL, NULL, 0 };
static TList idleFiles = { NULL, NULL, 0 };
typedef struct _TFontSize TFontSize, *PFontSize;
struct _TFontSize
{
PListElement element;
HFC hfc;
TT_Instance instance;
BOOL transformed;
BOOL vertical;
TT_Matrix matrix;
PFontFile file;
ULONG faceIndex;
};
#define MAX_CONTEXTS 5
static TFontSize contexts[MAX_CONTEXTS];
static ULONG ScriptTag = -1;
static ULONG LangSysTag = -1;
static ULONG iLangId = TT_MS_LANGID_ENGLISH_UNITED_STATES;
static ULONG uLastGlyph = 255;
static PSZ pGlyphlistName = "SYMBOL";
static BOOL isGBK = TRUE;
static ULONG ulCp[2] = {1};
static UCHAR DBCSLead[12];
#define is_HALFCHAR(_x) ((_x) < 0x0400)
LONG interfaceSEId(TT_Face face, BOOL UDCflag, LONG encoding);
static char* LookupName(TT_Face face, int index );
static ULONG GetCharmap(TT_Face face);
static int GetOutlineLen(TT_Outline *ol);
static int GetOutline(TT_Outline *ol, PBYTE pb);
BOOL IsDBCSChar(UCHAR c)
{
ULONG i;
for (i = 0; DBCSLead[i] && DBCSLead[i+1]; i += 2)
if ((c >= DBCSLead[i]) && (c <= DBCSLead[i+1]))
return TRUE;
return FALSE;
}
TT_Error TT_Alloc( long Size, void** P );
TT_Error TT_Free( void** P );
TT_Error TTMemory_Init(void);
static TT_Error error;
#define ALLOC( p, size ) TT_Alloc( (size), (void**)&(p) )
#define FREE( p ) TT_Free( (void**)&(p) )
static PListElement New_Element( void )
{
PListElement e = free_elements;
if (e)
free_elements = e->next;
else
{
if ( ALLOC( e, sizeof(TListElement) ) )
return NULL;
}
e->next = e->prev = e->data = NULL;
e->key = 0;
return e;
}
static void Done_Element( PListElement element )
{
element->next = free_elements;
free_elements = element;
}
static int List_Insert( PList list, PListElement element )
{
if (!list || !element)
return -1;
element->next = list->head;
if (list->head)
list->head->prev = element;
element->prev = NULL;
list->head = element;
if (!list->tail)
list->tail = element;
list->count++;
return 0;
}
static int List_Remove( PList list, PListElement element )
{
if (!element)
return -1;
if (element->prev)
element->prev->next = element->next;
else
list->head = element->next;
if (element->next)
element->next->prev = element->prev;
else
list->tail = element->prev;
element->next = element->prev = NULL;
list->count --;
return 0;
}
static PListElement List_Find( PList list, long key )
{
static PListElement cur;
for ( cur=list->head; cur; cur = cur->next )
if ( cur->key == key )
return cur;
return NULL;
}
static int Sleep_FontFile( PFontFile cur_file )
{
int i;
if (!(cur_file->flags & FL_FLAG_LIVE_FACE))
ERRRET(-1);
if (cur_file->flags & FL_FLAG_CONTEXT_OPEN) {
if (List_Remove( &liveFiles, cur_file->element ))
ERRRET(-1);
if (List_Insert( &liveFiles, cur_file->element ))
ERRRET(-1);
cur_file = (PFontFile)(liveFiles.tail->data);
}
if (List_Remove( &liveFiles, cur_file->element ))
ERRRET(-1);
if (List_Insert( &idleFiles, cur_file->element ))
ERRRET(-1);
for (i = 0; i < cur_file->numFaces; i++) {
TT_Done_Glyph( cur_file->faces[i].glyph );
TT_Close_Face( cur_file->faces[i].face );
}
cur_file->flags &= ~FL_FLAG_LIVE_FACE;
return 0;
}
static int Wake_FontFile( PFontFile cur_file )
{
static TT_Face face;
static TT_Glyph glyph;
static TT_CharMap cmap;
static TT_Face_Properties props;
static PFontFace cur_face;
ULONG encoding, i;
if (cur_file->flags & FL_FLAG_LIVE_FACE)
ERRRET(-1);
error = TT_Open_Face(engine, cur_file->filename, &face);
if (error)
{
COPY( "Error while opening " ); CAT( cur_file->filename );
CAT( ", error code = " ); CATI( error ); CAT( "\r\n" ); WRITE;
return -1;
}
error = TT_New_Glyph( face, &glyph );
if (error)
{
COPY( "Error while creating container for " ); CAT( cur_file->filename );
CAT( ", error code = " ); CATI( error ); CAT( "\r\n" ); WRITE;
goto Fail_Face;
}
encoding = GetCharmap(face);
error = TT_Get_CharMap(face, encoding & 0xFFFF, &cmap);
if (error)
{
COPY( "Error: No char map in " ); CAT( cur_file->filename );
CAT( "\r\n" ); WRITE;
goto Fail_Glyph;
}
TT_Get_Face_Properties(face, &props);
if (List_Remove( &idleFiles, cur_file->element ))
ERET1( Fail_Glyph );
if (List_Insert( &liveFiles, cur_file->element ))
ERET1( Fail_Glyph );
cur_file->numFaces = props.num_Faces;
if (cur_file->faces == NULL) {
if (ALLOC(cur_face, sizeof(TFontFace) * cur_file->numFaces))
ERET1( Fail_Glyph );
cur_file->faces = cur_face;
}
else
cur_face = cur_file->faces;
cur_face->face = face;
cur_face->glyph = glyph;
cur_face->charMap = cmap;
cur_file->flags |= FL_FLAG_LIVE_FACE;
if (!(cur_file->flags & FL_FLAG_ALREADY_USED)) {
cur_face->charMode = encoding >> 16;
cur_face->em_size = props.header->Units_Per_EM;
TT_Get_Face_Properties(cur_face->face, &props);
if (props.num_Glyphs > 1024) {
cur_file->flags |= FL_FLAG_DBCS_FILE;
cur_face->flags |= FC_FLAG_DBCS_FACE;
}
cur_face->widths = NULL;
cur_face->kernIndices = NULL;
}
error = TT_Get_Kerning_Directory(face, &(cur_face->directory));
if (error)
cur_face->directory.nTables = 0;
TT_Flush_Face(face);
for (i = 1; i < cur_file->numFaces; i++) {
error = TT_Open_Collection(engine, cur_file->filename,
i, &face);
if (error)
return -1;
error = TT_New_Glyph( face, &glyph );
if (error)
ERET1(Fail_Face);
encoding = GetCharmap(face);
error = TT_Get_CharMap(face, encoding & 0xFFFF, &cmap);
if (error)
ERET1(Fail_Glyph);
cur_face = &(cur_file->faces[i]);
cur_face->face = face;
cur_face->glyph = glyph;
cur_face->charMap = cmap;
if (!(cur_file->flags & FL_FLAG_ALREADY_USED)) {
cur_face->em_size = props.header->Units_Per_EM;
cur_face->charMode = encoding >> 16;
if (cur_file->flags & FL_FLAG_DBCS_FILE)
cur_face->flags |= FC_FLAG_DBCS_FACE;
cur_face->widths = NULL;
cur_face->kernIndices = NULL;
}
error = TT_Get_Kerning_Directory(face, &(cur_face->directory));
if (error)
cur_face->directory.nTables = 0;
}
cur_file->flags |= FL_FLAG_ALREADY_USED;
error = TT_Flush_Face(face);
if (error) {
COPY("Error flushing face\r\n"); WRITE;
}
return 0;
Fail_Glyph:
TT_Done_Glyph( glyph );
Fail_Face:
TT_Close_Face(face);
return -1;
}
static void Done_FontFile( PFontFile *file )
{
static PListElement element;
static PListElement next;
ULONG i;
#if 0
element = (*face)->sizes.head;
while (element)
{
next = element->next;
FREE( element->data );
Done_Element( element );
element = next;
}
#endif
if ((*file)->flags & FL_FLAG_LIVE_FACE)
{
for (i = 0; i < (*file)->numFaces; i++) {
TT_Done_Glyph( (*file)->faces[i].glyph );
TT_Close_Face( (*file)->faces[i].face );
if ((*file)->faces[i].widths)
FREE((*file)->faces[i].widths);
if ((*file)->faces[i].kernIndices)
FREE((*file)->faces[i].kernIndices);
}
}
FREE( (*file)->faces );
FREE( *file );
}
static PFontFile New_FontFile( char* file_name )
{
static PListElement element;
static PFontFile cur_file;
static TT_CharMap cmap;
for ( element = liveFiles.head; element; element = element->next )
{
cur_file = (PFontFile)element->data;
if (strcmp( cur_file->filename, file_name ) == 0)
goto Exit_Same;
}
for ( element = idleFiles.head; element; element = element->next )
{
cur_file = (PFontFile)element->data;
if (strcmp( cur_file->filename, file_name ) == 0)
goto Exit_Same;
}
element = New_Element();
if (!element)
ERRRET(NULL);
if ( ALLOC( cur_file, sizeof(TFontFile) ) )
ERET1( Fail_Element );
element->data = cur_file;
element->key = (long)cur_file;
cur_file->element = element;
cur_file->ref_count = 1;
cur_file->hff = (HFF)cur_file;
strcpy( cur_file->filename, file_name);
cur_file->flags = 0;
cur_file->faces = NULL;
#if 0
cur_face->sizes.head = NULL;
cur_face->sizes.tail = NULL;
cur_face->sizes.count= 0;
#endif
if (List_Insert( &idleFiles, element ))
ERET1( Fail_File );
if ( liveFiles.count >= max_open_files)
{
COPY( "rolling...\n" ); WRITE;
if (Sleep_FontFile( (PFontFile)(liveFiles.tail->data) ))
ERET1( Fail_File );
}
if ( Wake_FontFile( cur_file ) )
{
COPY( "could not open/wake " ); CAT( file_name ); CAT( "\r\n" ); WRITE;
if (List_Remove( &idleFiles, element ))
ERET1( Fail_File );
ERET1( Fail_File );
}
return cur_file;
Fail_File:
FREE( cur_file );
Fail_Element:
Done_Element( element );
return NULL;
Exit_Same:
cur_file->ref_count++;
COPY( " -> (duplicate) hff = " ); CATI( cur_file->hff );
CAT( "\r\n" ); WRITE;
return cur_file;
}
PFontFile getFontFile( HFF hff )
{
static PListElement element;
element = List_Find( &liveFiles, (long)hff );
if (element)
{
if ( liveFiles.head != element )
{
if ( List_Remove( &liveFiles, element ) )
ERRRET( NULL );
if ( List_Insert( &liveFiles, element ) )
ERRRET( NULL );
}
return (PFontFile)(element->data);
}
element = List_Find( &idleFiles, (long)hff );
if (element)
{
if ( liveFiles.count >= max_open_files )
if (Sleep_FontFile( (PFontFile)(liveFiles.tail->data) ))
ERRRET( NULL );
if ( Wake_FontFile( (PFontFile)(element->data) ) )
ERRRET( NULL );
COPY ( "hff " ); CATI( hff ); CAT( " awoken\n" ); WRITE;
return (PFontFile)(element->data);
}
COPY( "Could not find hff " ); CATI( hff ); CAT( " in lists\n" ); WRITE;
#ifdef DEBUG
COPY( "Live files : " ); CATI( liveFiles.count ); CAT( "\r\n" ); WRITE;
for (element = liveFiles.head; element; element = element->next)
{
COPY( ((PFontFile)(element->data))->filename ); CAT("\r\n");WRITE;
}
COPY( "Idle files : " ); CATI( idleFiles.count ); CAT( "\r\n" ); WRITE;
for (element = idleFiles.head; element; element = element->next)
{
COPY( ((PFontFile)(element->data))->filename ); CAT("\r\n");WRITE;
}
#endif
return NULL;
}
static PFontSize getFontSize( HFC hfc )
{
int i;
for ( i = 0; i < MAX_CONTEXTS; i++ )
if ( contexts[i].hfc == hfc ) {
return &contexts[i];
}
return NULL;
}
#ifdef USE_UCONV
#define MAX_UCONV_CACHE 10
#define UCONV_TYPE_UGL 1
#define UCONV_TYPE_BIG5 2
#define UCONV_TYPE_SJIS 4
typedef struct _UCACHEENTRY {
UconvObject object;
PID pid;
ULONG type;
} UCACHEENTRY, *PUCACHEENTRY;
static UCACHEENTRY UconvCache[MAX_UCONV_CACHE];
static int slotsUsed = 0;
int getUconvObject(UniChar *name, UconvObject *ConvObj, ULONG UconvType) {
PPIB ppib;
PTIB ptib;
PID curPid;
int i;
if (DosGetInfoBlocks(&ptib, &ppib))
return -1;
curPid = ppib->pib_ulpid;
if (slotsUsed == 0) {
if (UniCreateUconvObject(name, ConvObj) != ULS_SUCCESS)
return -1;
UconvCache[0].object = *ConvObj;
UconvCache[0].pid = curPid;
UconvCache[0].type = UconvType;
for (i = 1; i < MAX_UCONV_CACHE; i++) {
UconvCache[i].object = NULL;
UconvCache[i].pid = 0;
}
slotsUsed = 1;
return 0;
}
i = 0;
while ((UconvCache[i].pid != curPid || UconvCache[i].type != UconvType)
&& i < slotsUsed)
i++;
if (i < slotsUsed) {
*ConvObj = UconvCache[i].object;
return 0;
}
if (slotsUsed == MAX_UCONV_CACHE) {
UniFreeUconvObject(UconvCache[0].object);
for (i = 1; i < MAX_UCONV_CACHE; i++) {
UconvCache[i - 1].object = UconvCache[i].object;
UconvCache[i - 1].pid = UconvCache[i].pid;
UconvCache[i - 1].type = UconvCache[i].type;
}
}
if (UniCreateUconvObject(name, ConvObj) != ULS_SUCCESS)
return -1;
if (slotsUsed < MAX_UCONV_CACHE)
slotsUsed++;
UconvCache[slotsUsed - 1].object = *ConvObj;
UconvCache[slotsUsed - 1].pid = curPid;
UconvCache[slotsUsed - 1].type = UconvType;
return 0;
}
void CleanUCONVCache(void) {
PPIB ppib;
PTIB ptib;
PID curPid;
int i = 0, j;
if (DosGetInfoBlocks(&ptib, &ppib))
return;
curPid = ppib->pib_ulpid;
while (i < slotsUsed) {
if (UconvCache[i].pid == curPid) {
UniFreeUconvObject(UconvCache[i].object);
for (j = i + 1; j < slotsUsed; j++) {
UconvCache[j - 1].object = UconvCache[j].object;
UconvCache[j - 1].pid = UconvCache[j].pid;
UconvCache[j - 1].type = UconvCache[j].type;
}
slotsUsed--;
}
i++;
}
}
#endif
static int PM2TT( TT_CharMap charMap,
ULONG mode,
int index)
{
#ifdef USE_UCONV
static UconvObject UGLObj = NULL;
static BOOL UconvSet = FALSE;
char char_data[2], *pin_char_str;
size_t in_bytes_left, uni_chars_left, num_subs;
UniChar *pout_uni_str, uni_buffer[4];
int rc;
static UniChar uglName[10] = L"OS2UGL";
static UniChar uglNameBig5[10] = L"IBM-950";
static UniChar uglNameSJIS[10] = L"IBM-943";
switch (mode) {
case TRANSLATE_UGL:
if (UconvSet == FALSE) {
switch (iLangId) {
case TT_MS_LANGID_GREEK_GREECE:
strncpy((char*)uglName, (char*)L"OS2UGLG", 16);
break;
case TT_MS_LANGID_HEBREW_ISRAEL:
strncpy((char*)uglName, (char*)L"OS2UGLH", 16);
break;
case TT_MS_LANGID_ARABIC_SAUDI_ARABIA:
strncpy((char*)uglName, (char*)L"OS2UGLA", 16);
break;
}
UconvSet = TRUE;
}
if (getUconvObject(uglName, &UGLObj, UCONV_TYPE_UGL) != 0)
return 0;
if (index > MAX_GLYPH)
return 0;
char_data[0] = index;
char_data[1] = index >> 8;
pout_uni_str = uni_buffer;
pin_char_str = char_data;
in_bytes_left = 2;
uni_chars_left = 1;
rc = UniUconvToUcs(UGLObj, (void**)&pin_char_str, &in_bytes_left,
&pout_uni_str, &uni_chars_left,
&num_subs);
if (rc != ULS_SUCCESS)
return 0;
else
return TT_Char_Index(charMap, ((unsigned short*)uni_buffer)[0]);
case TRANSLATE_SYMBOL:
case TRANSLATE_UNICODE:
case TRANSLATE_BIG5:
case TRANSLATE_SJIS:
return TT_Char_Index(charMap, index);
case TRANSLATE_UNI_BIG5:
case TRANSLATE_UNI_SJIS:
switch (mode) {
case TRANSLATE_UNI_BIG5:
if (getUconvObject(uglNameBig5, &UGLObj, UCONV_TYPE_BIG5) != 0)
return 0;
break;
case TRANSLATE_UNI_SJIS:
if (getUconvObject(uglNameSJIS, &UGLObj, UCONV_TYPE_SJIS) != 0)
return 0;
break;
}
if (index & 0xFF00) {
char_data[0] = (index & 0xFF00) >> 8;
char_data[1] = index & 0x00FF;
}
else {
char_data[0] = index;
char_data[1] = 0;
}
pout_uni_str = uni_buffer;
pin_char_str = char_data;
in_bytes_left = 2;
uni_chars_left = 2;
rc = UniUconvToUcs(UGLObj, (void**)&pin_char_str, &in_bytes_left,
&pout_uni_str, &uni_chars_left,
&num_subs);
if (rc != ULS_SUCCESS)
return 0;
else
return TT_Char_Index(charMap, ((unsigned short*)uni_buffer)[0]);
default:
return 0;
}
#else
switch (mode)
{
case TRANSLATE_UGL:
if (iLangId == TT_MS_LANGID_GREEK_GREECE)
if ((index >= GREEK_START) && (index < GREEK_START + GREEK_GLYPHS))
return TT_Char_Index(charMap, SubUGLGreek[index - GREEK_START]);
if (index <= MAX_GLYPH)
return TT_Char_Index(charMap, UGL2Uni[index]);
else
ERRRET(0);
case TRANSLATE_SYMBOL :
case TRANSLATE_UNICODE:
case TRANSLATE_BIG5:
case TRANSLATE_SJIS:
return TT_Char_Index(charMap, index);
default:
return 0;
}
#endif
}
#define toupper( c ) ( ((c) >= 'a') && ((c) <= 'z') ? (c) - 'a' + 'A' : (c) )
static
int mystricmp(const char *s1, const char *s2) {
int i = 0;
int match = 0;
int len = strlen(s1);
if (len != strlen(s2))
return 1;
while (i < len) {
if (toupper(s1[i]) != toupper(s2[i])) {
match = 1;
break;
}
i++;
}
return match;
}
static
char *mystrrchr(char *s, char c) {
int i = 0;
int lastfound = -1;
int len = strlen(s);
while (i <= len) {
if (IsDBCSChar(s[i])) {
i += 2;
continue;
}
if (s[i] == c)
lastfound = i;
i++;
}
if (lastfound == -1)
return NULL;
else
return s + lastfound;
}
LONG _System ConvertFontFile( PSZ source,
PSZ dest_dir,
PSZ new_name )
{
PSZ source_name;
COPY("ConvertFontFile: Src = "); CAT(source);
if (dest_dir) {
CAT(", DestDir = "); CAT(dest_dir);
}
CAT("\r\n"); WRITE;
if (dest_dir && new_name)
{
source_name = mystrrchr( source, '\\' );
if (!source_name)
ERRRET(-1);
source_name++;
strcpy( new_name, source_name );
if (strncmp(source, dest_dir, strlen(dest_dir)) == 0)
return OK;
if ( DosCopy( source, dest_dir, DCPY_EXISTING) )
ERRRET(-1);
COPY(" -> Name: "); CAT(new_name); CAT("\r\n"); WRITE;
}
else
{
COPY("Delete file "); CAT(source); CAT("\r\n"); WRITE;
DosDelete(source);
}
return OK;
}
HFF _System LoadFontFile( PSZ file_name )
{
PSZ extension;
PFontFile cur_file;
PListElement element;
COPY( "LoadFontFile " ); CAT( file_name ); CAT( "\r\n" ); WRITE;
extension = mystrrchr( file_name, '.' );
if ( extension == NULL ||
(mystricmp(extension, ".TTF") &&
mystricmp(extension, ".TTC")) )
return ((HFF)-1);
cur_file = New_FontFile( file_name );
if (cur_file)
return cur_file->hff;
else
return (HFF)-1;
}
LONG _System UnloadFontFile( HFF hff )
{
PListElement element;
COPY("UnloadFontFile: hff = "); CATI((int) hff); CAT("\r\n"); WRITE;
for (element = liveFiles.head; element; element = element->next)
{
if (element->key == (long)hff)
{
PFontFile file = (PFontFile)element->data;
if (--file->ref_count > 0)
return 0;
List_Remove( &liveFiles, element );
Done_Element( element );
Done_FontFile( &file );
return 0;
}
}
for (element = idleFiles.head; element; element = element->next)
{
if (element->key == (long)hff)
{
PFontFile file = (PFontFile)element->data;
if (--file->ref_count > 0)
return 0;
List_Remove( &idleFiles, element );
Done_Element( element );
Done_FontFile( &file );
return 0;
}
}
return -1;
}
LONG _System QueryFaces( HFF hff,
PIFIMETRICS pifiMetrics,
ULONG cMetricLen,
ULONG cFontCount,
ULONG cStart)
{
static TT_Face_Properties properties;
static IFIMETRICS ifi;
PFontFace pface;
TT_Header *phead;
TT_Horizontal_Header *phhea;
TT_OS2 *pOS2;
TT_Postscript *ppost;
PIFIMETRICS pifi2;
PFontFile file;
LONG index, faceIndex, ifiCount = 0;
char *name;
COPY( "QueryFaces: hff = " ); CATI( hff );
CAT( ", cFontCount = " ); CATI( cFontCount );
CAT( ", cStart = " ); CATI( cStart );
CAT( ", cMetricLen = " ); CATI( cMetricLen );
CAT( "\r\n");
WRITE;
file = getFontFile(hff);
if (!file)
ERRRET(-1)
if (cMetricLen == 0) {
# ifdef FAKE_TNR
pface = &(file->faces[0]);
name = LookupName(pface->face, TT_NAME_ID_FONT_FAMILY);
if (!strcmp(name, "Times New Roman")) {
file->flags |= FL_FLAG_FAKE_ROMAN;
return 2;
}
# endif
if (file->flags & FL_FLAG_DBCS_FILE)
return file->numFaces * 2;
else
return file->numFaces;
}
for (faceIndex = 0; faceIndex < file->numFaces; faceIndex++) {
pface = &(file->faces[faceIndex]);
TT_Get_Face_Properties( pface->face, &properties );
pOS2 = properties.os2;
phead = properties.header;
phhea = properties.horizontal;
ppost = properties.postscript;
name = LookupName(pface->face, TT_NAME_ID_FONT_FAMILY);
if (name == NULL)
ERET1(Fail);
strncpy(ifi.szFamilyname, name, FACESIZE);
ifi.szFamilyname[FACESIZE - 1] = '\0';
name = LookupName(pface->face, TT_NAME_ID_FULL_NAME);
if (name == NULL) {
ERET1(Fail);
}
strncpy(ifi.szFacename, name, FACESIZE);
ifi.szFacename[FACESIZE - 1] = '\0';
if ((pface->charMode == TRANSLATE_UGL) && (properties.num_Glyphs > 1024))
{
LONG specEnc;
BOOL UDCflag = FALSE;
specEnc = interfaceSEId(pface->face, UDCflag, PSEID_UNICODE);
switch (specEnc) {
case PSEID_SHIFTJIS:
strcpy( ifi.szGlyphlistName, "PMJPN" );
pface->charMode = TRANSLATE_UNI_SJIS;
break;
case PSEID_BIG5:
strcpy( ifi.szGlyphlistName, "PMCHT" );
pface->charMode = TRANSLATE_UNI_BIG5;
break;
default:
strcpy( ifi.szGlyphlistName, "UNICODE" );
pface->charMode = TRANSLATE_UNICODE;
}
#if 0
strcpy( ifi.szGlyphlistName, "PMJPN" );
pface->charMode = TRANSLATE_UNI_SJIS;
#endif
}
else
if (pface->charMode == TRANSLATE_SYMBOL)
strcpy(ifi.szGlyphlistName, "SYMBOL");
else
if (pface->charMode == TRANSLATE_BIG5)
strcpy(ifi.szGlyphlistName, "PMCHT");
else
if (pface->charMode == TRANSLATE_SJIS)
strcpy(ifi.szGlyphlistName, "PMJPN");
else
strcpy(ifi.szGlyphlistName, "PM383");
ifi.idRegistry = 0;
ifi.lCapEmHeight = phead->Units_Per_EM;
ifi.lXHeight = phead->yMax /2;
ifi.lMaxAscender = pOS2->usWinAscent;
if ((LONG)pOS2->usWinDescent >= 0)
ifi.lMaxDescender = pOS2->usWinDescent;
else
ifi.lMaxDescender = -pOS2->usWinDescent;
ifi.lLowerCaseAscent = phhea->Ascender;
ifi.lLowerCaseDescent = -phhea->Descender;
ifi.lInternalLeading = ifi.lMaxAscender + ifi.lMaxDescender
- ifi.lCapEmHeight;
ifi.lExternalLeading = 0;
ifi.lAveCharWidth = pOS2->xAvgCharWidth;
ifi.lMaxCharInc = phhea->advance_Width_Max;
ifi.lEmInc = phead->Units_Per_EM;
ifi.lMaxBaselineExt = ifi.lMaxAscender + ifi.lMaxDescender;
ifi.fxCharSlope = -ppost->italicAngle;
ifi.fxInlineDir = 0;
ifi.fxCharRot = 0;
ifi.usWeightClass = pOS2->usWeightClass;
ifi.usWidthClass = pOS2->usWidthClass;
ifi.lEmSquareSizeX = phead->Units_Per_EM;
ifi.lEmSquareSizeY = phead->Units_Per_EM;
ifi.giFirstChar = 0;
ifi.giLastChar = 503;
ifi.giDefaultChar = 0;
ifi.giBreakChar = 32;
ifi.usNominalPointSize = 120;
ifi.usMinimumPointSize = 10;
ifi.usMaximumPointSize = 10000;
ifi.fsType = pOS2->fsType & IFIMETRICS_LICENSED;
ifi.fsDefn = IFIMETRICS_OUTLINE;
ifi.fsSelection = 0;
ifi.fsCapabilities = 0;
ifi.lSubscriptXSize = pOS2->ySubscriptXSize;
ifi.lSubscriptYSize = pOS2->ySubscriptYSize;
ifi.lSubscriptXOffset = pOS2->ySubscriptXOffset;
ifi.lSubscriptYOffset = pOS2->ySubscriptYOffset;
ifi.lSuperscriptXSize = pOS2->ySuperscriptXSize;
ifi.lSuperscriptYSize = pOS2->ySuperscriptYSize;
ifi.lSuperscriptXOffset = pOS2->ySuperscriptXOffset;
ifi.lSuperscriptYOffset = pOS2->ySuperscriptYOffset;
ifi.lUnderscoreSize = ppost->underlineThickness;
if (ifi.lUnderscoreSize == 150)
ifi.lUnderscoreSize = 100;
ifi.lUnderscorePosition = -ppost->underlinePosition;
ifi.lStrikeoutSize = pOS2->yStrikeoutSize;
ifi.lStrikeoutPosition = pOS2->yStrikeoutPosition;
#if 1
if (pface->directory.nTables != 0 &&
pface->directory.tables[0].format == 0) {
ifi.cKerningPairs = (pface->directory.tables[0].length - 8) / 6;
ifi.fsType |= IFIMETRICS_KERNING;
}
else
#endif
ifi.cKerningPairs = 0;
ifi.ulFontClass = 0x10D;
if (ifi.usWeightClass >= 100)
ifi.usWeightClass /= 100;
if (ifi.usWeightClass == 4)
ifi.usWeightClass = 5;
if (pOS2->panose[3] == 9) {
ifi.fsType |= IFIMETRICS_FIXED;
pface->flags |= FC_FLAG_FIXED_WIDTH;
}
switch (pface->charMode) {
case TRANSLATE_UNICODE:
ifi.giLastChar = pOS2->usLastCharIndex;
ifi.fsType |= IFIMETRICS_MBCS | IFIMETRICS_DBCS;
break;
case TRANSLATE_SYMBOL:
ifi.giLastChar = 255;
break;
case TRANSLATE_BIG5:
case TRANSLATE_UNI_BIG5:
ifi.giLastChar = 383;
ifi.fsType |= IFIMETRICS_MBCS | IFIMETRICS_DBCS;
break;
case TRANSLATE_SJIS:
case TRANSLATE_UNI_SJIS:
ifi.giLastChar = 890;
ifi.fsType |= IFIMETRICS_MBCS | IFIMETRICS_DBCS;
break;
}
if (pOS2->fsSelection & 0x01) {
ifi.fsSelection |= 0x01;
}
if (pOS2->fsSelection & 0x02) {
ifi.fsSelection |= IFIMETRICS_UNDERSCORE;
}
if (pOS2->fsSelection & 0x04) {
ifi.fsSelection |= IFIMETRICS_OVERSTRUCK;
}
index = faceIndex * ((file->flags & FL_FLAG_DBCS_FILE) ? 2 : 1);
if ((index >= cStart) && (index < (cStart + cFontCount))) {
memcpy((((PBYTE) pifiMetrics) + ifiCount), &ifi,
sizeof(IFIMETRICS) > cMetricLen ? cMetricLen : sizeof(IFIMETRICS));
ifiCount += cMetricLen;
}
if ((file->flags & FL_FLAG_DBCS_FILE) && (index + 1 >= cStart) &&
(index + 1 < (cStart + cFontCount))) {
pifi2 = (PIFIMETRICS) (((PBYTE) pifiMetrics) + ifiCount);
memcpy(pifi2, &ifi,
sizeof(IFIMETRICS) > cMetricLen ? cMetricLen : sizeof(IFIMETRICS));
strcpy(pifi2->szFamilyname + 1, ifi.szFamilyname);
pifi2->szFamilyname[0] = '@';
strcpy(pifi2->szFacename + 1, ifi.szFacename);
pifi2->szFacename[0] = '@';
ifiCount += cMetricLen;
}
# ifdef FAKE_TNR
if ((file->flags & FL_FLAG_FAKE_ROMAN) && (index + 1 >= cStart) &&
(index + 1 < (cStart + cFontCount))) {
pifi2 = (PIFIMETRICS) (((PBYTE) pifiMetrics) + ifiCount);
memcpy(pifi2, &ifi,
sizeof(IFIMETRICS) > cMetricLen ? cMetricLen : sizeof(IFIMETRICS));
strcpy(pifi2->szFamilyname, "Roman");
switch (strlen(ifi.szFacename)) {
case 15:
strcpy(pifi2->szFacename, "Tms Rmn");
break;
case 20:
strcpy(pifi2->szFacename, "Tms Rmn Bold");
break;
case 22:
strcpy(pifi2->szFacename, "Tms Rmn Italic");
break;
case 27:
strcpy(pifi2->szFacename, "Tms Rmn Bold Italic");
break;
}
ifiCount += cMetricLen;
}
# endif
}
Exit:
TT_Flush_Face(pface->face);
return cFontCount;
Fail:
TT_Flush_Face(pface->face);
return -1;
}
HFC _System OpenFontContext( HFF hff,
ULONG ulFont)
{
int i = 0;
static TT_Instance instance;
static PFontFile file;
ULONG faceIndex;
COPY("OpenFontContext: hff = "); CATI((int) hff); CAT("\r\n");
COPY(" ulFont = "); CATI((int) ulFont); CAT("\r\n");
WRITE;
file = getFontFile(hff);
if (!file)
ERRRET((HFC)-1)
faceIndex = file->flags & FL_FLAG_DBCS_FILE ? ulFont / 2 : ulFont;
# ifdef FAKE_TNR
if (file->flags & FL_FLAG_FAKE_ROMAN)
faceIndex = 0;
# endif
if (faceIndex > file->numFaces)
ERRRET((HFC)-1)
error = TT_New_Instance( file->faces[faceIndex].face, &instance);
if (error)
ERET1( Fail );
error = TT_Set_Instance_Resolutions(instance, 72, 72);
if (error)
ERRRET((HFC)-1)
i = 0;
while ((contexts[i].hfc != 0) && (i < MAX_CONTEXTS))
i++;
if (i == MAX_CONTEXTS)
ERET1( Fail );
contexts[i].hfc = (HFC)(i + 0x100);
contexts[i].instance = instance;
contexts[i].transformed = FALSE;
contexts[i].file = file;
contexts[i].faceIndex = faceIndex;
if ((file->flags & FL_FLAG_DBCS_FILE) && (ulFont & 1))
contexts[i].vertical = TRUE;
else
contexts[i].vertical = FALSE;
file->flags |= FL_FLAG_CONTEXT_OPEN;
COPY("-> hfc "); CATI((int) contexts[i].hfc); CAT("\r\n"); WRITE;
TT_Flush_Face(file->faces[faceIndex].face);
return contexts[i].hfc;
Fail:
TT_Flush_Face(file->faces[faceIndex].face);
return (HFC)-1;
}
LONG _System SetFontContext( HFC hfc,
PCONTEXTINFO pci )
{
LONG ptsize, temp, emsize;
PFontSize size;
COPY("SetFontContext: hfc = "); CATI((int) hfc);
CAT(", sizlPPM.cx = "); CATI((int) pci->sizlPPM.cx);
CAT(", sizlPPM.cy = "); CATI((int) pci->sizlPPM.cy);
CAT("\r\n pfxSpot.x = "); CATI((int) pci->pfxSpot.x);
CAT(", pfxSpot.y = "); CATI((int) pci->pfxSpot.y);
CAT("\r\n eM11 = "); CATI((int) pci->matXform.eM11);
CAT(", eM12 = "); CATI((int) pci->matXform.eM12);
CAT(", eM21 = "); CATI((int) pci->matXform.eM21);
CAT(", eM22 = "); CATI((int) pci->matXform.eM22);
CAT("\r\n");
WRITE;
size = getFontSize(hfc);
if (!size)
ERRRET(-1)
emsize = size->file->faces[size->faceIndex].em_size;
size->transformed =
( pci->matXform.eM11 != pci->matXform.eM22 ||
(pci->matXform.eM12 | pci->matXform.eM21) != 0 ||
pci->matXform.eM11 <= 0 );
if ( size->transformed )
{
if ((pci->matXform.eM11 > 0 && pci->matXform.eM22 > 0) &&
(pci->matXform.eM12 | pci->matXform.eM21) == 0) {
LONG ptsizex, ptsizey;
size->transformed = FALSE;
ptsizex = (emsize * pci->matXform.eM11) >> 10;
ptsizey = (emsize * pci->matXform.eM22) >> 10;
error = TT_Set_Instance_CharSizes(size->instance, ptsizex, ptsizey);
if (error)
ERRRET(-1)
return 0;
}
size->matrix.xx = pci->matXform.eM11 * 64;
size->matrix.xy = pci->matXform.eM21 * 64;
size->matrix.yx = pci->matXform.eM12 * 64;
size->matrix.yy = pci->matXform.eM22 * 64;
error = TT_Set_Instance_CharSize(size->instance, emsize);
if (error)
ERRRET(-1)
return 0;
}
ptsize = (emsize * (pci->matXform.eM11 + pci->matXform.eM21)) >> 10;
if (ptsize <= 0)
ptsize = 1;
error = TT_Set_Instance_CharSize(size->instance, ptsize);
if (error)
ERRRET(-1)
return 0;
}
LONG _System CloseFontContext( HFC hfc)
{
PFontSize size;
COPY("CloseFontContext: hfc = "); CATI((int)hfc); CAT("\r\n"); WRITE;
size = getFontSize(hfc);
if (!size)
ERRRET(-1)
size->hfc = 0;
size->file->flags &= ~FL_FLAG_CONTEXT_OPEN;
if (size->file->flags & FL_FLAG_LIVE_FACE) {
COPY("Closing instance: "); CATI((int)(size->instance.z)); CAT("\r\n"); WRITE;
error = TT_Done_Instance(size->instance);
if (error)
ERRRET(-1)
}
COPY("CloseFontContext successful\r\n"); WRITE;
return 0;
}
#define MAX_KERN_INDEX 504
GLYPH ReverseTranslate(PFontFace face, USHORT index) {
ULONG i;
GLYPH newidx = 0;
for (i = 0; i < MAX_KERN_INDEX; i++) {
newidx = PM2TT(face->charMap,
face->charMode,
i);
if (newidx == index)
break;
}
if (i < MAX_KERN_INDEX)
return i;
else
return 0;
}
LONG _System QueryFaceAttr( HFC hfc,
ULONG iQuery,
PBYTE pBuffer,
ULONG cb,
PGLYPH pagi,
GLYPH giStart )
{
int count, i = 0;
PFontSize size;
PFontFace face;
static TT_Face_Properties properties;
TT_OS2 *pOS2;
ABC_TRIPLETS* pt;
COPY("QueryFaceAttr: hfc = "); CATI((int) hfc); CAT("\r\n"); WRITE;
size = getFontSize(hfc);
if (!size)
ERRRET(-1)
face = &(size->file->faces[size->faceIndex]);
if (iQuery == FD_QUERY_KERNINGPAIRS)
{
TT_Kern_0 kerntab;
ULONG used = 0;
FD_KERNINGPAIRS *kpair;
USHORT *kernIndices, idx;
count = cb / sizeof(FD_KERNINGPAIRS);
COPY("QUERY_KERNINGPAIRS, "); CATI((int) count);
CAT("\r\n"); WRITE;
#if 1
if (face->directory.tables == NULL)
return 0;
if (face->directory.tables[0].format != 0)
ERRRET(-1);
error = TT_Load_Kerning_Table(face->face, 0);
if (error)
ERET1( Fail );
kerntab = face->directory.tables[0].t.kern0;
kpair = (PVOID)pBuffer;
if (face->kernIndices == NULL) {
TT_Get_Face_Properties( face->face, &properties );
error = ALLOC(face->kernIndices,
properties.num_Glyphs * sizeof (USHORT));
if (error)
ERET1( Fail );
memset(face->kernIndices, 0xFF,
properties.num_Glyphs * sizeof (USHORT));
}
kernIndices = face->kernIndices;
while ((i < kerntab.nPairs) && (i < count))
{
idx = kerntab.pairs[i].left;
if (kernIndices[idx] == (USHORT)-1)
kernIndices[idx] = ReverseTranslate(face, idx);
kpair->giFirst = kernIndices[idx];
idx = kerntab.pairs[i].right;
if (kernIndices[idx] == (USHORT)-1)
kernIndices[idx] = ReverseTranslate(face, idx);
kpair->giSecond = kernIndices[idx];
kpair->eKerningAmount = kerntab.pairs[i].value;
kpair++;
i++;
}
COPY("Returned kerning pairs: "); CATI(i); CAT("\r\n"); WRITE;
return i;
#else
return 0;
#endif
}
if (iQuery == FD_QUERY_ABC_WIDTHS)
{
count = cb / sizeof(ABC_TRIPLETS);
COPY("QUERY_ABC_WIDTHS, "); CATI((int) count);
CAT(" items, giStart = "); CATI((int) giStart);
if (pBuffer == NULL)
CAT(" NULL buffer");
CAT("\r\n"); WRITE;
TT_Get_Face_Properties( face->face, &properties );
pt = (ABC_TRIPLETS*)pBuffer;
for (i = giStart; i < giStart + count; i++, pt++)
{
int index;
unsigned short wid;
static unsigned short adv_widths [2];
static unsigned short adv_heights[2];
static unsigned short widths[2], heights[2];
static short lefts [2], tops [2];
index = PM2TT( face->charMap,
face->charMode,
i );
if (size->vertical && properties.vertical && 0)
error = TT_Get_Face_Metrics( face->face, index, index,
lefts, adv_widths, tops, adv_heights );
else
error = TT_Get_Face_Metrics( face->face, index, index,
lefts, adv_widths, NULL, NULL );
if (error)
goto Broken_Glyph;
if (face->flags & FC_FLAG_FIXED_WIDTH) {
wid = adv_widths[0] - lefts[0];
}
else {
if (face->flags & FC_FLAG_DBCS_FACE) {
if (face->widths == NULL) {
error = ALLOC(face->widths,
properties.num_Glyphs * sizeof (USHORT));
if (error)
goto Broken_Glyph;
memset(face->widths, 0xFF,
properties.num_Glyphs * sizeof (USHORT));
}
if (face->widths[index] == 0xFFFF) {
error = TT_Get_Face_Widths( face->face, index, index,
widths, heights );
if (error)
goto Broken_Glyph;
wid = face->widths[index] = widths[0];
}
else
wid = face->widths[index];
}
else {
error = TT_Get_Face_Widths( face->face, index, index,
widths, heights );
if (error)
goto Broken_Glyph;
wid = widths[0];
}
}
if (size->vertical && !is_HALFCHAR(i))
{
if (properties.vertical && 0)
{
pt->lA = tops[0];
pt->ulB = heights[0];
pt->lC = adv_heights[0] - pt->lA - pt->ulB;
}
else
{
pt->lA = pt->lC = 0;
pt->ulB = properties.os2->usWinAscent +
properties.os2->usWinDescent;
}
}
else
{
pt->lA = lefts[0];
pt->ulB = wid;
pt->lC = adv_widths[0] - pt->lA - pt->ulB;
}
#ifdef NETSCAPE_FIX
if (face->charMode != TRANSLATE_SYMBOL &&
!size->vertical) {
if (face->flags & FC_FLAG_FIXED_WIDTH) {
pt->ulB = pt->ulB + pt->lA + pt->lC;
pt->lA = 0;
pt->lC = 0;
} else if (i == 32) {
pt->ulB = adv_widths[0] - 2 * lefts[0];
pt->lC = lefts[0];
}
}
#endif
continue;
Broken_Glyph:
pt->lA = pt->lC = 0;
if (size->vertical && !is_HALFCHAR(i))
pt->ulB = properties.os2->usWinAscent +
properties.os2->usWinDescent;
else
pt->ulB = properties.horizontal->xMax_Extent;
}
}
TT_Flush_Face(face->face);
return count;
Fail:
TT_Flush_Face(face->face);
return -1;
}
LONG _System QueryCharAttr( HFC hfc,
PCHARATTR pCharAttr,
PBITMAPMETRICS pbmm )
{
static TT_Raster_Map bitmap;
static TT_Outline outline;
static TT_BBox bbox;
PFontSize size;
PFontFace face;
LONG temp;
PBYTE pb;
int i, j;
ULONG cb;
size = getFontSize(hfc);
if (!size)
ERRRET(-1)
face = &(size->file->faces[size->faceIndex]);
error = TT_Load_Glyph( size->instance,
face->glyph,
PM2TT( face->charMap,
face->charMode,
pCharAttr->gi),
TTLOAD_DEFAULT);
if (error)
{
if (i == 0)
ERET1( Fail )
else
{
error = TT_Load_Glyph( size->instance,
face->glyph,
0,
TTLOAD_DEFAULT);
if (error) {
COPY("Error code is "); CATI(error); CAT("\r\n"); WRITE;
ERET1( Fail );
}
}
}
TT_Flush_Face( face->face );
error = TT_Get_Glyph_Outline( face->glyph, &outline );
if (error)
ERRRET(-1);
if (size->vertical && !is_HALFCHAR(pCharAttr->gi)) {
TT_Matrix vertMatrix;
vertMatrix.xx = 0x00000;
vertMatrix.xy = -0x10000;
vertMatrix.yx = 0x10000;
vertMatrix.yy = 0x00000;
TT_Get_Outline_BBox( &outline, &bbox );
TT_Transform_Outline(&outline, &vertMatrix);
TT_Translate_Outline(&outline, bbox.yMax, 0);
TT_Translate_Outline(&outline, 0, bbox.yMin);
}
if (size->transformed)
TT_Transform_Outline( &outline, &size->matrix );
if ( pCharAttr->iQuery & FD_QUERY_OUTLINE )
{
if (pCharAttr->cbLen == 0)
return GetOutlineLen( &outline );
return GetOutline( &outline, pCharAttr->pBuffer );
}
TT_Get_Outline_BBox( &outline, &bbox );
if (size->transformed) {
bbox.xMax = bbox.xMin = 0;
for (i = 0; i < outline.n_points; i++) {
if (bbox.xMin > outline.points[i].x)
bbox.xMin = outline.points[i].x;
if (bbox.xMax < outline.points[i].x)
bbox.xMax = outline.points[i].x;
}
}
bbox.xMin &= -64;
bbox.yMin &= -64;
bbox.xMax = (bbox.xMax+63) & -64;
bbox.yMax = (bbox.yMax+63) & -64;
if (pCharAttr->iQuery & FD_QUERY_BITMAPMETRICS)
{
pbmm->sizlExtent.cx = (bbox.xMax - bbox.xMin) >> 6;
pbmm->sizlExtent.cy = (bbox.yMax - bbox.yMin) >> 6;
pbmm->cyAscent = 0;
pbmm->pfxOrigin.x = bbox.xMin << 10;
pbmm->pfxOrigin.y = bbox.yMax << 10;
if (!(pCharAttr->iQuery & FD_QUERY_CHARIMAGE))
return sizeof(*pbmm);
}
if (pCharAttr->iQuery & FD_QUERY_CHARIMAGE)
{
bitmap.width = (bbox.xMax - bbox.xMin) >> 6;
bitmap.rows = (bbox.yMax - bbox.yMin) >> 6;
bitmap.cols = ((bitmap.width + 31) / 8) & -4;
bitmap.flow = TT_Flow_Down;
bitmap.bitmap = pCharAttr->pBuffer;
bitmap.size = bitmap.rows * bitmap.cols;
if (pCharAttr->cbLen == 0)
return bitmap.size;
if (bitmap.size > pCharAttr->cbLen)
ERRRET(-1)
memset(bitmap.bitmap, 0, pCharAttr->cbLen);
error = TT_Get_Glyph_Bitmap( face->glyph,
&bitmap,
-bbox.xMin,
-bbox.yMin );
if (error)
ERRRET(-1);
return bitmap.size;
}
ERRRET(-1)
Fail:
TT_Flush_Face(face->face);
return -1;
}
LONG _System QueryFullFaces( HFF hff,
PVOID pBuff,
PULONG buflen,
PULONG cFontCount,
ULONG cStart )
{
COPY("!QueryFullFaces: hff = "); CATI((int) hff); CAT("\r\n"); WRITE;
ERRRET(-1)
}
static void LimitsInit(void) {
char cBuffer[25];
if (PrfQueryProfileString(HINI_USERPROFILE, "FreeType/2", "OPENFACES",
NULL, cBuffer, sizeof(cBuffer)) > 0) {
max_open_files = atoi(cBuffer);
if (max_open_files < 8)
max_open_files = 8;
}
else
max_open_files = 12;
}
void my_itoa(int num, char *cp) {
char temp[10];
int i = 0;
do {
temp[i++] = (num % 10) + '0';
num /= 10;
} while (num);
while (i--) {
*cp++ = temp[i];
}
*cp = '\0';
}
VOID GetUdcInfo(VOID) {
ULONG ulUdc, ulUdcInfo, i;
PVOID gPtr;
HINI hini;
CHAR szCpStr[10] = "CP";
DosQueryCp(sizeof(ulCp), (ULONG*)&ulCp, &i);
my_itoa((INT) ulCp, szCpStr + 2);
}
static ULONG LangInit(void) {
COUNTRYCODE cc = {0, 0};
COUNTRYINFO ci;
ULONG cilen;
isGBK = FALSE;
GetUdcInfo();
if (DosQueryCtryInfo(sizeof(ci), &cc, &ci, &cilen))
return -1;
DosQueryDBCSEnv(sizeof(DBCSLead), &cc, DBCSLead);
uLastGlyph = 383;
switch (ci.country) {
case 81:
iLangId = TT_MS_LANGID_JAPANESE_JAPAN;
ScriptTag = *(ULONG *) "kana";
LangSysTag = *(ULONG *) "JAN ";
pGlyphlistName = "PMJPN";
uLastGlyph = 890;
break;
case 88:
iLangId = TT_MS_LANGID_CHINESE_TAIWAN;
ScriptTag = *(ULONG *) "kana";
LangSysTag = *(ULONG *) "CHT ";
pGlyphlistName = "PMCHT";
break;
case 86:
if (ci.codepage == 1386 || ulCp[0] == 1386 || ulCp[1] == 1386) {
isGBK = TRUE;
}
iLangId = TT_MS_LANGID_CHINESE_PRC;
ScriptTag = *(ULONG *) "kana";
LangSysTag = *(ULONG *) "CHS ";
pGlyphlistName = "PMPRC";
break;
case 82:
iLangId = TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA;
ScriptTag = *(ULONG *) "hang";
LangSysTag = *(ULONG *) "KOR ";
pGlyphlistName = "PMKOR";
uLastGlyph = 949;
break;
case 30:
iLangId = TT_MS_LANGID_GREEK_GREECE;
default:
ScriptTag = *(ULONG *) "";
LangSysTag = *(ULONG *) "";
break;
}
return 0;
}
ULONG FirstInit(void) {
LONG lReqCount;
ULONG ulCurMaxFH;
# ifdef DEBUG
ULONG Action;
DosOpen("C:\\FTIFI.LOG", &LogHandle, &Action, 0, FILE_NORMAL,
OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS,
OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_WRITE_THROUGH |
OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_WRITEONLY,
NULL);
COPY("FreeType/2 loaded.\r\n");
WRITE;
# endif
lReqCount = 5;
DosSetRelMaxFH(&lReqCount, &ulCurMaxFH);
error = TT_Init_FreeType(&engine);
if (error)
return 0;
error = TT_Init_Kerning_Extension(engine);
COPY("FreeType Init called\r\n");
WRITE;
if (LangInit())
return 0;
COPY("NLS initialized.\r\n");
WRITE;
LimitsInit();
COPY("Open faces limit set to "); CATI(max_open_files); CAT("\r\n");
WRITE;
if (error)
return 0;
COPY("Initialization successful.\r\n");
WRITE;
return 1;
}
ULONG FinalTerm(void) {
PListElement cur;
PListElement tmp;
cur = free_elements;
while (cur != NULL) {
tmp = cur;
cur = cur->next;
FREE(tmp);
}
TT_Done_FreeType(engine);
# ifdef DEBUG
COPY("FreeType/2 terminated.\r\n");
WRITE;
DosClose(LogHandle);
# endif
return 1;
}
ULONG _System _DLL_InitTerm(ULONG hModule, ULONG ulFlag) {
switch (ulFlag) {
case 0:
if (++ulProcessCount == 1)
return FirstInit();
else
return 1;
case 1: {
int i;
# ifdef USE_UCONV
CleanUCONVCache();
# endif
if(--ulProcessCount == 0)
return FinalTerm();
else
return 1;
}
}
return 0;
}
LONG interfaceSEId(TT_Face face, BOOL UDCflag, LONG encoding) {
ULONG range1 = 0;
ULONG bits, mask;
TT_OS2 *pOS2;
static TT_Face_Properties props;
TT_Get_Face_Properties(face, &props);
pOS2 = props.os2;
if (encoding == PSEID_UNICODE) {
if (!UDCflag && props.num_Glyphs < 1024) {
encoding = PSEID_PM383;
} else if (pOS2->version >= 1) {
range1 = pOS2->ulCodePageRange1;
bits = 0;
if (range1 & OS2_CP1_ANSI_OEM_JAPANESE_JIS)
bits++;
if (range1 & OS2_CP1_ANSI_OEM_CHINESE_SIMPLIFIED)
bits++;
if (range1 & OS2_CP1_ANSI_OEM_CHINESE_TRADITIONAL)
bits++;
if (range1 & OS2_CP1_ANSI_OEM_KOREAN_WANSUNG)
bits++;
if (range1 & OS2_CP1_ANSI_OEM_KOREAN_JOHAB)
bits++;
if (bits == 1) {
switch (range1) {
case OS2_CP1_ANSI_OEM_JAPANESE_JIS:
encoding = PSEID_SHIFTJIS;
break;
case OS2_CP1_ANSI_OEM_CHINESE_SIMPLIFIED:
encoding = PSEID_PRC;
break;
case OS2_CP1_ANSI_OEM_CHINESE_TRADITIONAL:
encoding = PSEID_BIG5;
break;
case OS2_CP1_ANSI_OEM_KOREAN_WANSUNG:
encoding = PSEID_WANSUNG;
break;
case OS2_CP1_ANSI_OEM_KOREAN_JOHAB:
encoding = PSEID_JOHAB;
break;
default:
break;
}
}
} else {
switch (iLangId) {
case TT_MS_LANGID_JAPANESE_JAPAN:
encoding = PSEID_SHIFTJIS;
break;
case TT_MS_LANGID_CHINESE_PRC:
case TT_MS_LANGID_CHINESE_SINGAPORE:
encoding = PSEID_PRC;
break;
case TT_MS_LANGID_CHINESE_TAIWAN:
case TT_MS_LANGID_CHINESE_HONG_KONG:
encoding = PSEID_BIG5;
break;
case TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA:
encoding = PSEID_WANSUNG;
break;
case TT_MS_LANGID_KOREAN_JOHAB_KOREA:
encoding = PSEID_JOHAB;
break;
}
}
}
return encoding;
}
static char* LookupName(TT_Face face, int index )
{
static char name_buffer[FACESIZE + 2];
int name_len = 0;
int i, j, n;
USHORT platform, encoding, language, id;
char* string;
USHORT string_len;
int found;
n = TT_Get_Name_Count( face );
if ( n < 0 )
return NULL;
for ( i = 0; i < n; i++ )
{
TT_Get_Name_ID( face, i, &platform, &encoding, &language, &id );
TT_Get_Name_String( face, i, &string, &string_len );
if ( id == index )
{
found = 0;
if ( platform == TT_PLATFORM_MICROSOFT )
for ( j = 5; j >= 0; j-- )
if ( encoding == j )
switch (language)
{
case TT_MS_LANGID_CHINESE_TAIWAN:
if (encoding == PSEID_PRC)
found = 1;
break;
case TT_MS_LANGID_JAPANESE_JAPAN:
if (encoding == PSEID_SHIFTJIS)
found = 1;
break;
case TT_MS_LANGID_ENGLISH_UNITED_STATES :
case TT_MS_LANGID_ENGLISH_UNITED_KINGDOM :
case TT_MS_LANGID_ENGLISH_AUSTRALIA :
case TT_MS_LANGID_ENGLISH_CANADA :
case TT_MS_LANGID_ENGLISH_NEW_ZEALAND :
case TT_MS_LANGID_ENGLISH_IRELAND :
case TT_MS_LANGID_ENGLISH_SOUTH_AFRICA :
found = 1;
break;
}
if ( !found && platform == 0 && language == 0 )
found = 1;
if (found)
{
if (language == TT_MS_LANGID_CHINESE_TAIWAN ||
language == TT_MS_LANGID_JAPANESE_JAPAN) {
int i,j;
if (string_len > FACESIZE - 1)
string_len = FACESIZE - 1;
for (i=0, j=0; i<string_len; i++)
if (string[i] != '\0')
name_buffer[j++] = string[i];
name_buffer[j] = '\0';
return name_buffer;
}
else {
if ( string_len > FACESIZE * 2)
string_len = FACESIZE * 2;
name_len = 0;
for ( i = 1; i < string_len; i += 2 )
name_buffer[name_len++] = string[i];
name_buffer[name_len] = '\0';
return name_buffer;
}
}
}
}
return NULL;
}
static ULONG GetCharmap(TT_Face face)
{
int n;
USHORT platform, encoding;
int i, best, bestVal, val;
n = TT_Get_CharMap_Count(face);
if (n < 0)
ERRRET(-1)
bestVal = 16;
best = -1;
for (i = 0; i < n; i++)
{
TT_Get_CharMap_ID( face, i, &platform, &encoding );
if ( platform == TT_PLATFORM_MICROSOFT && encoding == TT_MS_ID_UNICODE_CS)
return i;
val = -1;
if (platform == TT_PLATFORM_APPLE_UNICODE)
val = 2;
else if (platform == TT_PLATFORM_MICROSOFT
&& encoding == TT_MS_ID_BIG_5)
val = 3;
else if (platform == TT_PLATFORM_MICROSOFT
&& encoding == TT_MS_ID_SJIS)
val = 4;
else if (platform == TT_PLATFORM_MACINTOSH
&& encoding == TT_MAC_ID_ROMAN)
val = 5;
else if (platform == TT_PLATFORM_MICROSOFT
&& encoding == TT_MS_ID_SYMBOL_CS)
val = 6;
if (val > 0 && val <= bestVal)
{
bestVal = val;
best = i;
}
}
if (i < 0)
return 0;
if (bestVal == 3)
best |= ( TRANSLATE_BIG5 << 16 );
if (bestVal == 4)
best |= ( TRANSLATE_SJIS << 16 );
if (bestVal == 5)
best |= ( TRANSLATE_SYMBOL << 16 );
return best;
}
static int GetOutlineLen(TT_Outline *ol)
{
int index;
BOOL on_curve;
int i, start = 0;
int first, last;
ULONG cb = 0;
for ( i = 0; i < ol->n_contours; i++ ) {
cb += sizeof(POLYGONHEADER);
first = start;
last = ol->contours[i];
on_curve = (ol->flags[first] & 1);
index = first;
while ( index < last ) {
index++;
if ( on_curve ) {
on_curve = ( ol->flags[index] & 1 );
if ( on_curve ) {
cb += sizeof(PRIMLINE);
}
}
else {
on_curve = ( ol->flags[index] & 1 );
if ( on_curve ) {
cb += sizeof(PRIMSPLINE);
}
else {
cb += sizeof(PRIMSPLINE);
}
}
}
if ( ol->flags[first] & 1 )
{
if ( on_curve )
cb += sizeof(PRIMLINE);
else
cb += sizeof(PRIMSPLINE);
}
else
if (!on_curve)
cb += sizeof(PRIMSPLINE);
start = ol->contours[i] + 1;
}
return cb;
}
static ULONG cb = 0, polycb;
static LONG lastX, lastY;
static PBYTE pb;
static POINTFX Q, R;
static POLYGONHEADER hdr = {0, FD_POLYGON_TYPE};
static PRIMLINE line = {FD_PRIM_LINE};
static PRIMSPLINE spline = {FD_PRIM_SPLINE};
static void Line_From(LONG x, LONG y) {
line.pte.x = x << 10;
line.pte.y = y << 10;
memcpy(&(pb[cb]), &line, sizeof(line));
cb += sizeof(PRIMLINE);
polycb += sizeof(PRIMLINE);
}
static void Bezier_From( LONG x0, LONG y0, LONG x2, LONG y2, LONG x1, LONG y1 ) {
spline.pte[0].x = x0 << 10;
spline.pte[0].y = y0 << 10;
Q.x = (x0 + 2 * x1) / 3;
Q.y = (y0 + 2 * y1) / 3;
R.x = (x2 + 2 * x1) / 3;
R.y = (y2 + 2 * y1) / 3;
spline.pte[1].x = Q.x << 10;
spline.pte[1].y = Q.y << 10;
spline.pte[2].x = R.x << 10;
spline.pte[2].y = R.y << 10;
memcpy(&(pb[cb]), &spline, sizeof(spline));
cb += sizeof(PRIMSPLINE);
polycb += sizeof(PRIMSPLINE);
}
static int GetOutline(TT_Outline *ol, PBYTE pbuf) {
LONG x, y;
LONG cx, cy;
LONG mx, my;
LONG x_first, y_first;
LONG x_last, y_last;
int index;
BOOL on_curve;
int i, start = 0;
int first, last;
ULONG polystart;
pb = pbuf;
cb = 0;
for ( i = 0; i < ol->n_contours; i++ ) {
polystart = cb;
polycb = sizeof(POLYGONHEADER);
cb += sizeof(POLYGONHEADER);
first = start;
last = ol->contours[i];
x_first = ol->points[first].x;
y_first = ol->points[first].y;
x_last = ol->points[last].x;
y_last = ol->points[last].y;
lastX = cx = x_first;
lastY = cy = y_first;
on_curve = (ol->flags[first] & 1);
index = first;
if ( !on_curve ) {
if ( ol->flags[last] & 1 ) {
lastX = x_last;
lastY = y_last;
}
else {
lastX = (lastX + x_last)/2;
lastY = (lastY + y_last)/2;
x_last = lastX;
y_last = lastY;
}
}
while ( index < last ) {
index++;
x = ( ol->points[index].x );
y = ( ol->points[index].y );
if ( on_curve ) {
on_curve = ( ol->flags[index] & 1 );
if ( on_curve ) {
Line_From( lastX, lastY );
lastX = x;
lastY = y;
}
else {
cx = x;
cy = y;
}
}
else {
on_curve = ( ol->flags[index] & 1 );
if ( on_curve ) {
Bezier_From(lastX, lastY, x, y, cx, cy );
lastX = x;
lastY = y;
}
else {
mx = (cx + x) / 2;
my = (cy + y)/2;
Bezier_From( lastX, lastY, mx, my, cx, cy );
lastX = mx;
lastY = my;
cx = x;
cy = y;
}
}
}
if ( ol->flags[first] & 1 ) {
if ( on_curve )
Line_From( lastX, lastY);
else
Bezier_From( lastX, lastY, x_first, y_first, cx, cy );
}
else
if (!on_curve)
Bezier_From( lastX, lastY, x_last, y_last, cx, cy );
start = ol->contours[i] + 1;
hdr.cb = polycb;
memcpy(&(pb[polystart]), &hdr, sizeof(hdr));
}
return cb;
}