diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:48:50 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:48:50 +0000 |
commit | 3795e9702b3b3a6fe0594d09cdd110adeb5e42f9 (patch) | |
tree | caec4aaf13f12f0a31c15cb24ad2127eff834dd2 /src/FreeType | |
parent | 153e8da44452905ae04a0e20ad0d85f40399b4ca (diff) |
Initial revision
Diffstat (limited to 'src/FreeType')
-rw-r--r-- | src/FreeType/ft.h | 89 | ||||
-rw-r--r-- | src/FreeType/ftenc.c | 212 | ||||
-rw-r--r-- | src/FreeType/ftfuncs.c | 1770 | ||||
-rw-r--r-- | src/FreeType/ftfuncs.h | 122 | ||||
-rw-r--r-- | src/FreeType/ftsystem.c | 329 | ||||
-rw-r--r-- | src/FreeType/fttools.c | 188 |
6 files changed, 2710 insertions, 0 deletions
diff --git a/src/FreeType/ft.h b/src/FreeType/ft.h new file mode 100644 index 0000000..d4cacc2 --- /dev/null +++ b/src/FreeType/ft.h @@ -0,0 +1,89 @@ +/* +Copyright (c) 1997 by Mark Leisher +Copyright (c) 1998-2002 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* $XFree86: xc/lib/font/FreeType/ft.h,v 1.19 2002/10/01 00:02:09 alanh Exp $ */ + +#ifndef _FT_H_ +#define _FT_H_ + +#include <X11/Xfuncproto.h> + +#undef DEBUG_TRUETYPE + +#ifdef DEBUG_TRUETYPE +#define MUMBLE(s) (ErrorF((s))) +#define MUMBLE1(s,x) (ErrorF((s),(x))) +#else +#define MUMBLE(s) +#define MUMBLE1(s,x) +#endif + +#undef MAX +#define MAX(h,i) ((h) > (i) ? (h) : (i)) +#define ADJUSTMAX(m,v) if((v)>(m)) (m)=(v) +#undef MIN +#define MIN(l,o) ((l) < (o) ? (l) : (o)) +#define ADJUSTMIN(m,v) if ((v)<(m)) (m)=(v) + +/* When comparing floating point values, we want to ignore small errors. */ +#define NEGLIGIBLE ((double)0.001) +/* Are x and y significantly different? */ +#define DIFFER(x,y) (fabs((x)-(y))>=NEGLIGIBLE*fabs(x)) +/* Is x significantly different from 0 w.r.t. y? */ +#define DIFFER0(x,y) (fabs(x)>=NEGLIGIBLE*fabs(y)) + +/* Two to the sixteenth power, as a double. */ +#define TWO_SIXTEENTH ((double)(1<<16)) +#define TWO_SIXTH ((double)(1<<6)) + +/* Data structures used across files */ + +typedef struct _FTMapping +{ + int named; + FT_CharMap cmap; + int base; + struct _FontMap *mapping; /* allow inclusion without fontenc.h */ +} FTMappingRec, *FTMappingPtr; + +/* Prototypes */ + +/* ftfuncs.c */ + +void FreeTypeRegisterFontFileFunctions(void); + +/* ftenc.c */ + +int FTPickMapping(char*, int, char*, FT_Face, FTMappingPtr); +unsigned FTRemap(FT_Face face, FTMappingPtr, unsigned code); + +/* fttools.c */ + +int FTu2a(int, char*, char*, int, int); +int FTtoXReturnCode(int); +int FTGetEnglishName(FT_Face, int, char *, int); +int FTcheckForTTCName(char*, char**, int*); + +extern void ErrorF(const char*, ...); + +#endif /* _FT_H_ */ diff --git a/src/FreeType/ftenc.c b/src/FreeType/ftenc.c new file mode 100644 index 0000000..7243f3f --- /dev/null +++ b/src/FreeType/ftenc.c @@ -0,0 +1,212 @@ +/* +Copyright (c) 1998-2002 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +/* $XFree86: xc/lib/font/FreeType/ftenc.c,v 1.21 2002/10/01 00:02:10 alanh Exp $ */ + +#ifndef FONTMODULE +#include <string.h> +#else +#include "Xmd.h" +#include "Xdefs.h" +#include "xf86_ansic.h" +#endif + +#include "fontmisc.h" +#include "fontenc.h" +#include "freetype/freetype.h" +#include "freetype/ttnameid.h" +#include "freetype/tttables.h" +#include "freetype/t1tables.h" +#include "freetype/ftxf86.h" +#include "ft.h" + +static int find_cmap(int, int, int, FT_Face, FT_CharMap *); + +static int +FTEncFontSpecific(char *encoding) +{ + char *p = encoding; + + while(*p != '-') { + if(*p == '\0') + return 0; + p++; + } + p++; + return (strcasecmp(p, "fontspecific") == 0); +} + +int +FTPickMapping(char *xlfd, int length, char *filename, FT_Face face, + FTMappingPtr tm) +{ + FontEncPtr encoding; + FontMapPtr mapping; + FT_CharMap cmap; + int ftrc; + + char *encoding_name = 0; + + if(xlfd) + encoding_name = FontEncFromXLFD(xlfd, length); + if(!encoding_name) + encoding_name = "iso8859-1"; + + if(FTEncFontSpecific(encoding_name)) { + ftrc = FT_Select_Charmap(face, ft_encoding_adobe_custom); + if(ftrc != 0) { + ErrorF("FreeType: couldn't select custom Type 1 encoding\n"); + return -1; + } else { + tm->named = 0; + tm->cmap = face->charmap; + tm->base = 0; + tm->mapping = NULL; + return 0; + } + } + + encoding = FontEncFind(encoding_name, filename); + if(encoding == NULL) { + ErrorF("FreeType: couldn't find encoding %s\n", encoding_name); + encoding = FontEncFind("iso8859-1", filename); + } + if(encoding == NULL) { + ErrorF("FreeType: couldn't find encoding iso8859-1.\n"); + return -1; + } + + if(FT_Has_PS_Glyph_Names(face)) { + for(mapping = encoding->mappings; mapping; mapping = mapping->next) { + if(mapping->type == FONT_ENCODING_POSTSCRIPT) { + tm->named = 1; + tm->base = 0; + tm->mapping = mapping; + return 0; + } + } + } + + for(mapping = encoding->mappings; mapping; mapping = mapping->next) { + if(find_cmap(mapping->type, mapping->pid, mapping->eid, face, + &cmap)) { + tm->named = 0; + tm->cmap = cmap; + if(strcasecmp(encoding_name, "microsoft-symbol") == 0) { + /* deal with undocumented lossage */ + TT_OS2 *os2; + os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); + if(os2) + tm->base = os2->usFirstCharIndex - 0x20; + else + tm->base = 0; + } else + tm->base = 0; + tm->mapping = mapping; + return 0; + } + } + + return -1; +} + +static int +find_cmap(int type, int pid, int eid, FT_Face face, FT_CharMap *cmap_return) +{ + int i, n; + FT_CharMap cmap = NULL; + + n = face->num_charmaps; + + switch(type) { + case FONT_ENCODING_TRUETYPE: /* specific cmap */ + for(i=0; i<n; i++) { + cmap = face->charmaps[i]; + if(cmap->platform_id == pid && cmap->encoding_id == eid) { + *cmap_return = cmap; + return 1; + } + } + break; + case FONT_ENCODING_UNICODE: /* any Unicode cmap */ + /* prefer Microsoft Unicode */ + for(i=0; i<n; i++) { + cmap = face->charmaps[i]; + if(cmap->platform_id == TT_PLATFORM_MICROSOFT && + cmap->encoding_id == TT_MS_ID_UNICODE_CS) { + *cmap_return = cmap; + return 1; + } + } + break; + /* Try Apple Unicode */ + for(i=0; i<n; i++) { + cmap = face->charmaps[i]; + if(cmap->platform_id == TT_PLATFORM_APPLE_UNICODE) { + *cmap_return = cmap; + return 1; + } + } + /* ISO Unicode? */ + for(i=0; i<n; i++) { + cmap = face->charmaps[i]; + if(cmap->platform_id == TT_PLATFORM_ISO) { + *cmap_return = cmap; + return 1; + } + } + break; + default: + return 0; + } + return 0; +} + +unsigned +FTRemap(FT_Face face, FTMappingPtr tm, unsigned code) +{ + unsigned index; + char *name; + unsigned glyph_index; + + if(tm->mapping) { + if(tm->named) { + name = FontEncName(code, tm->mapping); + if(!name) + return 0; + glyph_index = FT_Get_Name_Index(face, name); + return glyph_index; + } else { + index = FontEncRecode(code, tm->mapping) + tm->base; + FT_Set_Charmap(face, tm->cmap); + glyph_index = FT_Get_Char_Index(face, index); + return glyph_index; + } + } else { + if(code < 0x100) { + index = code; + FT_Set_Charmap(face, tm->cmap); + glyph_index = FT_Get_Char_Index(face, index); + return glyph_index; + } else + return 0; + } +} diff --git a/src/FreeType/ftfuncs.c b/src/FreeType/ftfuncs.c new file mode 100644 index 0000000..fa58006 --- /dev/null +++ b/src/FreeType/ftfuncs.c @@ -0,0 +1,1770 @@ +/* +Copyright (c) 1997 by Mark Leisher +Copyright (c) 1998-2002 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* $XFree86: xc/lib/font/FreeType/ftfuncs.c,v 1.27 2003/02/13 03:01:45 dawes Exp $ */ + +#include "fontmisc.h" + +#ifndef FONTMODULE +#include <string.h> +#include <math.h> +#else +#include "Xmd.h" +#include "Xdefs.h" +#include "xf86_ansic.h" +#endif + +#include "fntfilst.h" +#include "fontutil.h" +#include "FSproto.h" +#include "freetype/freetype.h" +#include "freetype/ftsizes.h" +#include "freetype/ttnameid.h" +#include "freetype/tttables.h" +#include "freetype/t1tables.h" +#include "freetype/ftxf86.h" + +#include "fontenc.h" +#include "ft.h" +#include "ftfuncs.h" + +/* The propery names for all the XLFD properties. */ + +static char *xlfd_props[] = { + "FOUNDRY", + "FAMILY_NAME", + "WEIGHT_NAME", + "SLANT", + "SETWIDTH_NAME", + "ADD_STYLE_NAME", + "PIXEL_SIZE", + "POINT_SIZE", + "RESOLUTION_X", + "RESOLUTION_Y", + "SPACING", + "AVERAGE_WIDTH", + "CHARSET_REGISTRY", + "CHARSET_ENCODING", +}; + + +static int ftypeInitP = 0; /* is the engine initialised? */ +static FT_Library ftypeLibrary; + +static FTFacePtr faceTable[NUMFACEBUCKETS]; + +static unsigned +hash(char *string) +{ + int i; + unsigned u = 0; + for(i = 0; string[i] != '\0'; i++) + u = (u<<2) + (unsigned char)string[i]; + return u; +} + +static int +ifloor(int x, int y) +{ + if(x >= 0) + return x/y; + else + return x/y - 1; +} + +static int +iceil(int x, int y) +{ + return ifloor(x + y - 1, y); +} + +static int +FreeTypeOpenFace(FTFacePtr *facep, char *fileName) +{ + FT_Error ftrc; + int bucket; + FTFacePtr face, otherFace; + char *realFileName; + int faceNumber; + + if (!ftypeInitP) { + ftrc = FT_Init_FreeType(&ftypeLibrary); + if (ftrc != 0) { + ErrorF("FreeType: error initializing ftypeEngine: %d\n", ftrc); + return AllocError; + } + ftypeInitP = 1; + } + + /* Try to find a matching face in the hashtable */ + bucket = hash(fileName)%NUMFACEBUCKETS; + otherFace = faceTable[bucket]; + while(otherFace) { + if(strcmp(otherFace->filename, fileName) == 0) + break; + otherFace = otherFace->next; + } + if(otherFace) { + MUMBLE1("Returning cached face: %s\n", otherFace->filename); + *facep = otherFace; + return Successful; + } + + /* No cached match; need to make a new one */ + face = (FTFacePtr)xalloc(sizeof(FTFaceRec)); + if(face == NULL) { + return AllocError; + } + + face->filename = (char*)xalloc(strlen(fileName)+1); + if(face->filename == NULL) { + xfree(face); + return AllocError; + } + strcpy(face->filename, fileName); + + face->instances = NULL; + face->active_instance = NULL; + + if(FTcheckForTTCName(fileName, &realFileName, &faceNumber)) { + ftrc = FT_New_Face(ftypeLibrary, realFileName, faceNumber, &face->face); + xfree(realFileName); + } else + ftrc = FT_New_Face(ftypeLibrary, fileName, 0, &face->face); + if(ftrc != 0) { + ErrorF("FreeType: couldn't open face %s: %d\n", fileName, ftrc); + xfree(face->filename); + xfree(face); + return BadFontPath; + } + + /* Insert face in hashtable and return it */ + face->next = faceTable[bucket]; + faceTable[bucket] = face; + *facep = face; + return Successful; +} + +static void +FreeTypeFreeFace(FTFacePtr face) +{ + int bucket; + FTFacePtr otherFace; + + if(!face->instances) { + bucket = hash(face->filename) % NUMFACEBUCKETS; + if(faceTable[bucket] == face) + faceTable[bucket] = face->next; + else { + otherFace = faceTable[bucket]; + while(otherFace) { + if(otherFace->next == face) + break; + otherFace = otherFace->next; + } + if(otherFace && otherFace->next) + otherFace->next = otherFace->next->next; + else + ErrorF("FreeType: freeing unknown face\n"); + } + MUMBLE1("Closing face: %s\n", face->filename); + FT_Done_Face(face->face); + xfree(face->filename); + xfree(face); + } +} + +static int +TransEqual(FTNormalisedTransformationPtr t1, FTNormalisedTransformationPtr t2) +{ + if(t1->scale != t2->scale) + return 0; + else if(t1->xres != t2->xres || t1->yres != t2->yres) + return 0; + else if(t1->nonIdentity != t2->nonIdentity) + return 0; + else if(t1->nonIdentity && t2->nonIdentity) { + return + t1->matrix.xx == t2->matrix.xx && + t1->matrix.yx == t2->matrix.yx && + t1->matrix.yy == t2->matrix.yy && + t1->matrix.xy == t2->matrix.xy; + } else + return 1; +} + +static int +BitmapFormatEqual(FontBitmapFormatPtr f1, FontBitmapFormatPtr f2) +{ + return + f1->bit == f2->bit && + f1->byte == f2->byte && + f1->glyph == f2->glyph; +} + +static int +FTInstanceMatch(FTInstancePtr instance, + char *fileName, FTNormalisedTransformationPtr trans, + int charcell, FontBitmapFormatPtr bmfmt) +{ + if(strcmp(instance->face->filename, fileName) != 0) { + return 0; + } else if(!TransEqual(&instance->transformation, trans)) { + return 0; + } else if((charcell && instance->monospaced != FT_CHARCELL) || + (!charcell && instance->monospaced == FT_CHARCELL)) { + return 0; + } else if(!BitmapFormatEqual(&instance->bmfmt, bmfmt)) { + return 0; + } else { + return 1; + } +} + +static int +FreeTypeActivateInstance(FTInstancePtr instance) +{ + FT_Error ftrc; + if(instance->face->active_instance == instance) + return Successful; + + ftrc = FT_Activate_Size(instance->size); + if(ftrc != 0) { + instance->face->active_instance = NULL; + ErrorF("FreeType: couldn't activate instance: %d\n", ftrc); + return FTtoXReturnCode(ftrc); + } + FT_Set_Transform(instance->face->face, + instance->transformation.nonIdentity ? + &instance->transformation.matrix : 0, + 0); + + instance->face->active_instance = instance; + return Successful; +} + +static int +FreeTypeOpenInstance(FTInstancePtr *instance_return, + char *fileName, FTNormalisedTransformationPtr trans, + int charcell, FontBitmapFormatPtr bmfmt) +{ + FT_Error ftrc; + int xrc; + FTInstancePtr instance, otherInstance; + FTFacePtr face; + + xrc = FreeTypeOpenFace(&face, fileName); + if(xrc != Successful) { + return xrc; + } + + /* Search for a matching instance */ + for(otherInstance = face->instances; + otherInstance; + otherInstance = otherInstance->next) { + if(FTInstanceMatch(otherInstance, fileName, trans, charcell, bmfmt)) + break; + } + if(otherInstance) { + MUMBLE("Returning cached instance\n"); + otherInstance->refcount++; + *instance_return = otherInstance; + return Successful; + } + + /* None matching found */ + instance = (FTInstancePtr)xalloc(sizeof(FTInstanceRec)); + if(instance == NULL) { + return AllocError; + } + + instance->refcount = 1; + instance->face = face; + + instance->monospaced = charcell?FT_CHARCELL:0; + instance->charcellMetrics = 0; + instance->width = 0; + + instance->transformation = *trans; + instance->bmfmt = *bmfmt; + instance->nglyphs = instance->face->face->num_glyphs; + instance->glyphs = NULL; + instance->available = NULL; + + ftrc = FT_New_Size(instance->face->face, &instance->size); + if(ftrc != 0) { + ErrorF("FreeType: couldn't create size object: %d\n", ftrc); + FreeTypeFreeFace(instance->face); + xfree(instance); + return FTtoXReturnCode(ftrc); + } + FreeTypeActivateInstance(instance); + ftrc = FT_Set_Char_Size(instance->face->face, + (int)(trans->scale*(1<<6)+0.5), + (int)(trans->scale*(1<<6)+0.5), + trans->xres, trans->yres); + if(ftrc != 0) { + FT_Done_Size(instance->size); + FreeTypeFreeFace(instance->face); + xfree(instance); + return FTtoXReturnCode(ftrc); + } + + /* maintain a linked list of instances */ + instance->next = instance->face->instances; + instance->face->instances = instance; + + *instance_return = instance; + return Successful; +} + +static void +FreeTypeFreeInstance(FTInstancePtr instance) +{ + FTInstancePtr otherInstance; + + if(instance->face->active_instance == instance) + instance->face->active_instance = NULL; + instance->refcount--; + if(instance->refcount <= 0) { + int i,j; + + if(instance->face->instances == instance) + instance->face->instances = instance->next; + else { + for(otherInstance = instance->face->instances; + otherInstance; + otherInstance = otherInstance->next) + if(otherInstance->next == instance) { + otherInstance->next = instance->next; + break; + } + } + + FT_Done_Size(instance->size); + FreeTypeFreeFace(instance->face); + + if(instance->charcellMetrics) { + xfree(instance->charcellMetrics); + } + if(instance->glyphs) { + for(i = 0; i < iceil(instance->nglyphs, FONTSEGMENTSIZE); i++) { + if(instance->glyphs[i]) { + for(j = 0; j < FONTSEGMENTSIZE; j++) { + if(instance->available[i][j] == + FT_AVAILABLE_RASTERISED) + xfree(instance->glyphs[i][j].bits); + } + xfree(instance->glyphs[i]); + } + } + xfree(instance->glyphs); + } + if(instance->available) { + for(i = 0; i < iceil(instance->nglyphs, FONTSEGMENTSIZE); i++) { + if(instance->available[i]) + xfree(instance->available[i]); + } + xfree(instance->available); + } + xfree(instance); + } +} + +static int +FreeTypeInstanceFindGlyph(unsigned idx, FTInstancePtr instance, + CharInfoPtr **glyphs, int ***available, + int *found, int *segmentP, int *offsetP) +{ + int segment, offset; + + if(idx > instance->nglyphs) { + *found = 0; + return Successful; + } + + if(*available == NULL) { + *available = + (int**)xalloc(sizeof(int*) * iceil(instance->nglyphs, + FONTSEGMENTSIZE)); + if(*available == NULL) + return AllocError; + memset((char*)(*available), 0, + sizeof(int*) * iceil(instance->nglyphs, FONTSEGMENTSIZE)); + } + + segment = ifloor(idx, FONTSEGMENTSIZE); + offset = idx - segment * FONTSEGMENTSIZE; + + if((*available)[segment] == NULL) { + (*available)[segment] = (int*)xalloc(sizeof(int) * FONTSEGMENTSIZE); + if((*available)[segment] == NULL) + return AllocError; + memset((char*)(*available)[segment], 0, sizeof(int) * FONTSEGMENTSIZE); + } + + if(*glyphs == NULL) { + *glyphs = (CharInfoPtr*)xalloc(sizeof(CharInfoPtr)* + iceil(instance->nglyphs, + FONTSEGMENTSIZE)); + if(*glyphs == NULL) + return AllocError; + memset((char*)(*glyphs), 0, + sizeof(CharInfoPtr)*iceil(instance->nglyphs, FONTSEGMENTSIZE)); + } + + if((*glyphs)[segment] == NULL) { + (*glyphs)[segment]= + (CharInfoPtr)xalloc(sizeof(CharInfoRec) * FONTSEGMENTSIZE); + if((*glyphs)[segment] == NULL) + return AllocError; + } + + *found = 1; + *segmentP = segment; + *offsetP = offset; + return Successful; +} + +static int +FreeTypeInstanceGetGlyph(unsigned idx, CharInfoPtr *g, FTInstancePtr instance) +{ + int found, segment, offset; + FT_Error ftrc; + int xrc; + int ***available; + CharInfoPtr **glyphs; + + available = &instance->available; + glyphs = &instance->glyphs; + + xrc = FreeTypeInstanceFindGlyph(idx, instance, glyphs, available, + &found, &segment, &offset); + if(xrc != Successful) + return xrc; + + if(!found || (*available)[segment][offset] == FT_AVAILABLE_NO) { + *g = 0; + return Successful; + } else if((*available)[segment][offset] == FT_AVAILABLE_RASTERISED) { + *g = &(*glyphs)[segment][offset]; + return Successful; + } + + /* Tough: need to rasterise a new glyph. */ + FreeTypeActivateInstance(instance); + ftrc = FT_Load_Glyph(instance->face->face, idx, + FT_LOAD_RENDER | FT_LOAD_MONOCHROME); + if(ftrc != 0) + return FTtoXReturnCode(ftrc); + + if(instance->monospaced == FT_CHARCELL && + (*available)[segment][offset] == 0) + memcpy((char*)&(*glyphs)[segment][offset].metrics, + (char*)instance->charcellMetrics, + sizeof(xCharInfo)); + + xrc = FreeTypeRasteriseGlyph(&(*glyphs)[segment][offset], + instance, instance->monospaced == FT_CHARCELL); + if(xrc != Successful) + return xrc; + else + (*available)[segment][offset] = FT_AVAILABLE_RASTERISED; + + /* Update the width to match the width of the font */ + if(instance->monospaced) { + if((*available)[segment][offset] >= FT_AVAILABLE_RASTERISED) + (*glyphs)[segment][offset].metrics.characterWidth = instance->width; + } + + /* return the glyph */ + if((*available)[segment][offset] >= FT_AVAILABLE_RASTERISED) + *g = &(*glyphs)[segment][offset]; + else + *g = 0; + return Successful; +} + +static int +FreeTypeInstanceGetGlyphMetrics(unsigned idx, + xCharInfo **metrics, FTInstancePtr instance) +{ + CharInfoPtr g; + int xrc; + int found, segment, offset; + + xrc = FreeTypeInstanceFindGlyph(idx, instance, + &instance->glyphs, &instance->available, + &found, &segment, &offset); + if(xrc != Successful) + return xrc; + + if(!found) { + *metrics = 0; + return Successful; + } + + if(instance->available[segment][offset] == 0) { + if(instance->monospaced < FT_CHARCELL) { + xrc = FreeTypeInstanceGetGlyph(idx, &g, instance); + if(xrc != Successful) + return xrc; + } else { + memcpy((char*)&instance->glyphs[segment][offset].metrics, + (char*)instance->charcellMetrics, + sizeof(xCharInfo)); + instance->available[segment][offset] = FT_AVAILABLE_YES; + } + } + + if(instance->available[segment][offset] >= FT_AVAILABLE_YES) { + *metrics = &instance->glyphs[segment][offset].metrics; + } else + *metrics = 0; + + return Successful; +} + +int +FreeTypeRasteriseGlyph(CharInfoPtr tgp, FTInstancePtr instance, + int hasMetrics) +{ +#define TRANSFORM_X(x_value) \ + ((int)floor((((double)(x_value)*(double)instance->transformation.matrix.xx)/\ + (TWO_SIXTEENTH*TWO_SIXTH))+0.5)) + +#define TRANSFORM_Y(y_value) \ + ((int)floor((((double)(y_value)*(double)instance->transformation.matrix.yy)/\ + (TWO_SIXTEENTH*TWO_SIXTH))+0.5)) + +#define TRANSFORM_X_RAW(value) \ + ((int)floor((double)(value)/instance->transformation.scale/TWO_SIXTH/(smetrics.x_ppem/72.0)*1000.0+0.5)) + + FTFacePtr face; + FT_Bitmap *bitmap; + char *raster = NULL; + FT_Size_Metrics smetrics; + FT_Glyph_Metrics *metrics; + int wd, ht, bpr; /* width, height, bytes per row */ + int dx, dy; + int leftSideBearing, rightSideBearing, characterWidth, rawCharacterWidth, + ascent, descent; + int i = 0, j; + + face = instance->face; + smetrics = instance->size->metrics; + + FreeTypeActivateInstance(instance); + + metrics = &face->face->glyph->metrics; + bitmap = &face->face->glyph->bitmap; + + if(hasMetrics) { + wd = tgp->metrics.rightSideBearing - tgp->metrics.leftSideBearing; + ht = tgp->metrics.ascent + tgp->metrics.descent; + dx = -tgp->metrics.leftSideBearing + + TRANSFORM_X(metrics->horiBearingX); + dy = tgp->metrics.ascent - TRANSFORM_Y(metrics->horiBearingY); + } else { + wd = bitmap->width; + ht = bitmap->rows; + dx = 0; + dy = 0; + /* The X convention is to consider a character with an empty + * bounding box as undefined. This convention is broken. */ + if(wd <= 0) wd = 1; + if(ht <= 0) ht = 1; + } + + /* Make sure rounding doesn't cause a crash in memcpy below */ + if(wd < bitmap->width) + wd = bitmap->width; + if(ht < bitmap->rows) + ht = bitmap->rows; + + bpr = (((wd + (instance->bmfmt.glyph<<3) - 1) >> 3) & + -instance->bmfmt.glyph); + if(tgp) { + raster = (char*)xalloc(ht * bpr); + if(raster == NULL) + return AllocError; + memset(raster, 0, ht * bpr); + } + + if(dx == 0 && dy == 0 && bpr == bitmap->pitch) { + memcpy(raster, bitmap->buffer, bitmap->rows * bitmap->pitch); + } else if(dx == 0) { + for(i = MAX(0, -dy); i < bitmap->rows && i + dy < ht; i++) + memcpy(raster + (i + dy) * bpr, + bitmap->buffer + i * bitmap->pitch, + bitmap->pitch); + } else { + for(i = MAX(0, -dy); i < bitmap->rows && i + dy < ht; i++) { + for(j = MAX(0, -dx); j < bitmap->width && j + dx < wd; j++) { + int set; + set = (bitmap->buffer[i * bitmap->pitch + j / 8] & + 1 << (7 - j % 8)); + if(set) + raster[(i + dy) * bpr + (j + dx) / 8] |= + 1 << (7 - (j + dx) % 8); + } + } + } + + tgp->bits = raster; + + if(instance->bmfmt.bit == LSBFirst) { + BitOrderInvert((unsigned char*)(tgp->bits), ht*bpr); + } + + if(instance->bmfmt.byte != instance->bmfmt.bit) { + switch(instance->bmfmt.scan) { + case 1: + break; + case 2: + TwoByteSwap((unsigned char*)(tgp->bits), ht*bpr); + break; + case 4: + FourByteSwap((unsigned char*)(tgp->bits), ht*bpr); + break; + default: + ; + } + } + + + if(!hasMetrics) { + leftSideBearing = TRANSFORM_X(metrics->horiBearingX); + rightSideBearing = wd + TRANSFORM_X(metrics->horiBearingX); + + characterWidth = TRANSFORM_X(metrics->horiAdvance); + rawCharacterWidth = TRANSFORM_X_RAW(metrics->horiAdvance); + + ascent = TRANSFORM_Y(metrics->horiBearingY); + descent = ht - TRANSFORM_Y(metrics->horiBearingY); + + if(tgp) { + /* Set the glyph metrics. */ + tgp->metrics.attributes = (unsigned short)((short)rawCharacterWidth); + tgp->metrics.leftSideBearing = leftSideBearing; + tgp->metrics.rightSideBearing = rightSideBearing; + tgp->metrics.characterWidth = characterWidth; + tgp->metrics.ascent = ascent; + tgp->metrics.descent = descent; + } + } + return Successful; +#undef TRANSFORM_X +#undef TRANSFORM_Y +#undef TRANSFORM_X_RAW +} + +static void +FreeTypeFreeFont(FTFontPtr font) +{ + FreeTypeFreeInstance(font->instance); + if(font->ranges) + xfree(font->ranges); + xfree(font); +} + +/* Free a font. If freeProps is 0, don't free the properties. */ + +static void +FreeTypeFreeXFont(FontPtr pFont, int freeProps) +{ + FTFontPtr tf; + + if(pFont) { + if((tf = (FTFontPtr)pFont->fontPrivate)) { + FreeTypeFreeFont(tf); + } + if(freeProps && pFont->info.nprops>0) { + xfree(pFont->info.isStringProp); + xfree(pFont->info.props); + } + DestroyFontRec(pFont); + } +} + + +/* Unload a font */ + +static void +FreeTypeUnloadXFont(FontPtr pFont) +{ + MUMBLE("Unloading\n"); + FreeTypeFreeXFont(pFont, 1); +} + +/* Add the font properties, including the Font name, the XLFD + properties, some strings from the font, and various typographical + data. We only provide data readily available in the tables in the + font for now, altough FIGURE_WIDTH would be a good idea as it is + used by Xaw. */ + +static int +FreeTypeAddProperties(FTFontPtr font, FontScalablePtr vals, FontInfoPtr info, + char *fontname, + int rawAverageWidth) +{ + int i, j, maxprops; + char *sp, *ep, val[MAXFONTNAMELEN], *vp; + FTFacePtr face; + FTInstancePtr instance; + FT_Size_Metrics smetrics; + FTNormalisedTransformationPtr trans; + int upm; + TT_OS2 *os2; + TT_Postscript *post; + PS_FontInfoRec t1info_rec, *t1info; + int xlfdProps = 0; + int ftrc; + + instance = font->instance; + face = instance->face; + smetrics = instance->size->metrics; + trans = &instance->transformation; + upm = face->face->units_per_EM; + + os2 = FT_Get_Sfnt_Table(face->face, ft_sfnt_os2); + post = FT_Get_Sfnt_Table(face->face, ft_sfnt_post); + ftrc = FT_Get_PS_Font_Info(face->face, &t1info_rec); + if(ftrc == 0) + t1info = &t1info_rec; + else + t1info = NULL; + + if(t1info) { + os2 = NULL; + post = NULL; + } + + info->nprops = 0; /* in case we abort */ + + strcpy(val, fontname); + if(FontParseXLFDName(val, vals, FONT_XLFD_REPLACE_VALUE)) { + xlfdProps = 1; + } else { + MUMBLE("Couldn't parse XLFD\n"); + xlfdProps = 0; + } + + maxprops= + 1 + /* NAME */ + (xlfdProps ? 14 : 0) + /* from XLFD */ + 8 + + (os2 ? 6 : 0) + + (post || t1info? 3 : 0) + + 2; /* type */ + + info->props = (FontPropPtr)xalloc(maxprops * sizeof(FontPropRec)); + if(info->props == NULL) + return AllocError; + + info->isStringProp = (char*)xalloc(maxprops); + if(info->isStringProp == NULL) { + xfree(info->props); + return AllocError; + } + + memset((char *)info->isStringProp, 0, maxprops); + + i = 0; + + info->props[i].name = MakeAtom("FONT", 4, TRUE); + info->props[i].value = MakeAtom(val, strlen(val), TRUE); + info->isStringProp[i] = 1; + i++; + + if(*val && *(sp = val + 1)) { + for (j = 0, sp = val + 1; j < 14; j++) { + if (j == 13) + /* Handle the case of the final field containing a subset + specification. */ + for (ep = sp; *ep && *ep != '['; ep++); + else + for (ep = sp; *ep && *ep != '-'; ep++); + + info->props[i].name = + MakeAtom(xlfd_props[j], strlen(xlfd_props[j]), TRUE); + + switch(j) { + case 6: /* pixel size */ + info->props[i].value = + (int)(fabs(vals->pixel_matrix[3]) + 0.5); + i++; + break; + case 7: /* point size */ + info->props[i].value = + (int)(fabs(vals->point_matrix[3])*10.0 + 0.5); + i++; + break; + case 8: /* resolution x */ + info->props[i].value = vals->x; + i++; + break; + case 9: /* resolution y */ + info->props[i].value = vals->y; + i++; + break; + case 11: /* average width */ + info->props[i].value = vals->width; + i++; + break; + default: /* a string */ + info->props[i].value = MakeAtom(sp, ep - sp, TRUE); + info->isStringProp[i] = 1; + i++; + } + sp = ++ep; + } + } + + info->props[i].name = MakeAtom("RAW_AVERAGE_WIDTH", 17, TRUE); + info->props[i].value = rawAverageWidth; + i++; + + info->props[i].name = MakeAtom("FONT_ASCENT", 11, TRUE); + info->props[i].value = info->fontAscent; + i++; + + info->props[i].name = MakeAtom("RAW_ASCENT", 15, TRUE); + info->props[i].value = + ((double)face->face->ascender/(double)upm*1000.0); + i++; + + info->props[i].name = MakeAtom("FONT_DESCENT", 12, TRUE); + info->props[i].value = info->fontDescent; + i++; + + info->props[i].name = MakeAtom("RAW_DESCENT", 16, TRUE); + info->props[i].value = + -((double)face->face->descender/(double)upm*1000.0); + i++; + + j = FTGetEnglishName(face->face, TT_NAME_ID_COPYRIGHT, + val, MAXFONTNAMELEN); + vp = val; + if (j < 0) { + if(t1info && t1info->notice) { + vp = t1info->notice; + j = strlen(vp); + } + } + if(j > 0) { + info->props[i].name = MakeAtom("COPYRIGHT", 9, TRUE); + info->props[i].value = MakeAtom(vp, j, TRUE); + info->isStringProp[i] = 1; + i++; + } + + j = FTGetEnglishName(face->face, TT_NAME_ID_FULL_NAME, + val, MAXFONTNAMELEN); + vp = val; + if (j < 0) { + if(t1info && t1info->full_name) { + vp = t1info->full_name; + j = strlen(vp); + } + } + if(j > 0) { + info->props[i].name = MakeAtom("FACE_NAME", 9, TRUE); + info->props[i].value = MakeAtom(vp, j, TRUE); + info->isStringProp[i] = 1; + i++; + } + + j = FTGetEnglishName(face->face, TT_NAME_ID_PS_NAME, + val, MAXFONTNAMELEN); + vp = val; + if (j < 0) { + if(t1info && t1info->full_name) { + vp = t1info->full_name; + j = strlen(vp); + } + } + if(j > 0) { + info->props[i].name = MakeAtom("_ADOBE_POSTSCRIPT_FONTNAME", 26, TRUE); + info->props[i].value = MakeAtom(vp, j, TRUE); + info->isStringProp[i] = 1; + i++; + } + + /* These macros handle the case of a diagonal matrix. They convert + FUnits into pixels. */ +#define TRANSFORM_FUNITS_X(xval) \ + ((int) \ + floor((((double)(xval)/(double)upm) * \ + ((double)trans->matrix.xx/TWO_SIXTEENTH)*(double)smetrics.x_ppem)+\ + 0.5)) + +#define TRANSFORM_FUNITS_Y(yval) \ + ((int) \ + floor((((double)(yval)/(double)upm) * \ + ((double)trans->matrix.yy/TWO_SIXTEENTH) * (double)smetrics.y_ppem)+\ + 0.5)) + + /* In what follows, we assume the matrix is diagonal. In the rare + case when it is not, the values will be somewhat wrong. */ + + if(os2) { + info->props[i].name = MakeAtom("SUBSCRIPT_SIZE",14,TRUE); + info->props[i].value = + TRANSFORM_FUNITS_Y(os2->ySubscriptYSize); + i++; + info->props[i].name = MakeAtom("SUBSCRIPT_X",11,TRUE); + info->props[i].value = + TRANSFORM_FUNITS_X(os2->ySubscriptXOffset); + i++; + info->props[i].name = MakeAtom("SUBSCRIPT_Y",11,TRUE); + info->props[i].value = + TRANSFORM_FUNITS_Y(os2->ySubscriptYOffset); + i++; + info->props[i].name = MakeAtom("SUPERSCRIPT_SIZE",16,TRUE); + info->props[i].value = + TRANSFORM_FUNITS_Y(os2->ySuperscriptYSize); + i++; + info->props[i].name = MakeAtom("SUPERSCRIPT_X",13,TRUE); + info->props[i].value = + TRANSFORM_FUNITS_X(os2->ySuperscriptXOffset); + i++; + info->props[i].name = MakeAtom("SUPERSCRIPT_Y",13,TRUE); + info->props[i].value = + TRANSFORM_FUNITS_Y(os2->ySuperscriptYOffset); + i++; + } + + if(post || t1info) { + int underlinePosition, underlineThickness; + + if(post) { + underlinePosition = TRANSFORM_FUNITS_Y(post->underlinePosition); + underlineThickness = TRANSFORM_FUNITS_Y(post->underlineThickness); + } else { + underlinePosition = + TRANSFORM_FUNITS_Y(t1info->underline_position); + underlineThickness = + TRANSFORM_FUNITS_Y(t1info->underline_thickness); + } + if(underlineThickness <= 0) + underlineThickness = 1; + + info->props[i].name = MakeAtom("UNDERLINE_THICKNESS",19,TRUE); + info->props[i].value = underlineThickness; + i++; + + info->props[i].name = MakeAtom("UNDERLINE_POSITION",18,TRUE); + info->props[i].value = underlinePosition; + i++; + + /* The italic angle is often unreliable for Type 1 fonts */ + if(post && trans->matrix.xx == trans->matrix.yy) { + info->props[i].name = MakeAtom("ITALIC_ANGLE",12,TRUE); + info->props[i].value = + /* Convert from TT_Fixed to + 64th of a degree counterclockwise from 3 o'clock */ + 90*64+(post->italicAngle >> 10); + i++; + } +#undef TRANSFORM_FUNITS_X +#undef TRANSFORM_FUNITS_Y + } + + info->props[i].name = MakeAtom("FONT_TYPE", 9, TRUE); + vp = (char *)FT_Get_X11_Font_Format(face->face); + info->props[i].value = MakeAtom(vp, strlen(vp), TRUE); + info->isStringProp[i] = 1; + i++; + + info->props[i].name = MakeAtom("RASTERIZER_NAME", 15, TRUE); + info->props[i].value = MakeAtom("FreeType", 10, TRUE); + info->isStringProp[i] = 1; + i++; + + info->nprops = i; + return Successful; +} + +static int +FreeTypeFontGetGlyph(unsigned code, CharInfoPtr *g, FTFontPtr font) +{ + unsigned idx; + int i; + + /* As a special case, we pass 0 even when it is not in the ranges; + this will allow for the default glyph, which should exist in any + TrueType font. */ + + if(code > 0 && font->nranges) { + for(i = 0; i < font->nranges; i++) + if((code >= + font->ranges[i].min_char_low+ + (font->ranges[i].min_char_high<<8)) && + (code <= + font->ranges[i].max_char_low + + (font->ranges[i].max_char_high<<8))) + break; + if(i == font->nranges) { + *g = 0; + return Successful; + } + } + + idx = FTRemap(font->instance->face->face, &font->mapping, code); + + /* Only pass the default glyph if there is no first index */ + if(idx == 0 && + (code != 0 || + (font->mapping.mapping && + (font->mapping.mapping->encoding->first != 0 || + font->mapping.mapping->encoding->first_col != 0)))) { + *g = 0; + return Successful; + } else { + return FreeTypeInstanceGetGlyph(idx, g, font->instance); + } +} + +static int +FreeTypeFontGetGlyphMetrics(unsigned code, xCharInfo **metrics, FTFontPtr font) +{ + unsigned idx; + int i; + + /* As a special case, we pass 0 even when it is not in the ranges; + this will allow for the default glyph, which should exist in any + TrueType font. */ + + if(code>0 && font->nranges) { + for(i = 0; i < font->nranges; i++) + if((code >= + font->ranges[i].min_char_low+ + (font->ranges[i].min_char_high<<8)) && + (code <= + font->ranges[i].max_char_low+(font->ranges[i].max_char_high<<8))) + break; + if(i == font->nranges) { + *metrics = 0; + return Successful; + } + } + + idx = FTRemap(font->instance->face->face, &font->mapping, code); + + if(idx == 0 && + (code != 0 || + (font->mapping.mapping && + (font->mapping.mapping->encoding->first != 0 || + font->mapping.mapping->encoding->first_col != 0)))) { + *metrics = 0; + return Successful; + } else { + return FreeTypeInstanceGetGlyphMetrics(idx, metrics, font->instance); + } +} + +static int +FreeTypeFontGetDefaultGlyph(CharInfoPtr *g, FTFontPtr font) +{ + /* Disable default glyph generation if there is a first index */ + if(font->mapping.mapping && + (font->mapping.mapping->encoding->first || + font->mapping.mapping->encoding->first_col)) { + *g = 0; + return Successful; + } + + /* Using FreeTypeInstanceGetGlyph(0,...) would cause inconsistencies + between metrics and glyphs in the unlikely case that 0 is not + mapped to 0. */ + return FreeTypeFontGetGlyph(0, g, font); +} + +static int +FreeTypeLoadFont(FTFontPtr *font_return, char *fileName, + FontScalablePtr vals, FontEntryPtr entry, + FontBitmapFormatPtr bmfmt) +{ + int xrc; + FTFontPtr font; + FTNormalisedTransformationRec trans; + int charcell; + + font = (FTFontPtr)xalloc(sizeof(FTFontRec)); + if(font == NULL) + return AllocError; + + /* Compute the transformation matrix. We use floating-point + arithmetic for simplicity */ + + trans.xres = vals->x; + trans.yres = vals->y; + + /* This value cannot be 0. */ + trans.scale = MAX(hypot(vals->point_matrix[0], vals->point_matrix[2]), + hypot(vals->point_matrix[1], vals->point_matrix[3])); + trans.nonIdentity = 0; + + /* Try to round stuff. We want approximate zeros to be exact zeros, + and if the elements on the diagonal are approximately equal, we + want them equal. We do this to avoid breaking hinting. */ + if(DIFFER(vals->point_matrix[0], vals->point_matrix[3])) { + trans.nonIdentity = 1; + trans.matrix.xx = + (int)((vals->point_matrix[0]*(double)TWO_SIXTEENTH)/trans.scale); + trans.matrix.yy = + (int)((vals->point_matrix[3]*(double)TWO_SIXTEENTH)/trans.scale); + } else { + trans.matrix.xx = trans.matrix.yy = + ((vals->point_matrix[0] + vals->point_matrix[3])/2* + (double)TWO_SIXTEENTH)/trans.scale; + } + + if(DIFFER0(vals->point_matrix[1], trans.scale)) { + trans.matrix.yx = + (int)((vals->point_matrix[1]*(double)TWO_SIXTEENTH)/trans.scale); + trans.nonIdentity = 1; + } else + trans.matrix.yx = 0; + + if(DIFFER0(vals->point_matrix[2], trans.scale)) { + trans.matrix.xy = + (int)((vals->point_matrix[2]*(double)TWO_SIXTEENTH)/trans.scale); + trans.nonIdentity = 1; + } else + trans.matrix.xy=0; + + /* Check for charcell in XLFD */ + charcell = 0; + if(entry->name.ndashes == 14) { + char *p; + int dashes = 0; + for(p = entry->name.name; + p <= entry->name.name + entry->name.length - 2; + p++) { + if(*p == '-') { + dashes++; + if(dashes == 11) { + if(p[1]=='c' && p[2]=='-') + charcell=1; + break; + } + } + } + } + + xrc = FreeTypeOpenInstance(&font->instance, + fileName, &trans, charcell, bmfmt); + if(xrc != Successful) + return xrc; + + if(entry->name.ndashes == 14) { + if(FTPickMapping(entry->name.name, entry->name.length, fileName, + font->instance->face->face, &font->mapping)) + return BadFontFormat; + } else { + if(FTPickMapping(0, 0, fileName, + font->instance->face->face, &font->mapping)) + return BadFontFormat; + } + + + font->nranges = vals->nranges; + font->ranges = 0; + if(font->nranges) { + font->ranges = (fsRange*)xalloc(vals->nranges*sizeof(fsRange)); + if(font->ranges == NULL) { + FreeTypeFreeFont(font); + return AllocError; + } + memcpy((char*)font->ranges, (char*)vals->ranges, + vals->nranges*sizeof(fsRange)); + } + *font_return = font; + + return Successful; +} + +/* Given a BBox in FUnits, return a transformed BBox in pixels */ +static void +transformBBox(FTNormalisedTransformationPtr transformation, + int upm, int x_ppem, int y_ppem, + int x1, int y1, int x2, int y2, + int *tx1p, int *ty1p, int *tx2p, int *ty2p) +{ + double + xx1, yy1, xx2, yy2, + tx11, ty11, tx12, ty12, tx21, ty21, tx22, ty22, + tx1, ty1, tx2, ty2; + + /* Convert arguments to EM units */ + + xx1 = ((double)x1/(double)upm); + yy1 = ((double)y1/(double)upm); + xx2 = ((double)x2/(double)upm); + yy2 = ((double)y2/(double)upm); + + /* Apply transformation matrix */ + + if(!transformation->nonIdentity) { + tx1 = xx1; + ty1 = yy1; + tx2 = xx2; + ty2 = yy2; + } else { + /* Not an identity matrix, need to compute images of all corners */ + tx11 = + (transformation->matrix.xx/TWO_SIXTEENTH)*xx1 + + (transformation->matrix.xy/TWO_SIXTEENTH)*yy1; + ty11 = + (transformation->matrix.yx/TWO_SIXTEENTH)*xx1 + + (transformation->matrix.yy/TWO_SIXTEENTH)*yy1; + tx12 = + (transformation->matrix.xx/TWO_SIXTEENTH)*xx1 + + (transformation->matrix.xy/TWO_SIXTEENTH)*yy2; + ty12 = + (transformation->matrix.yx/TWO_SIXTEENTH)*xx1 + + (transformation->matrix.yy/TWO_SIXTEENTH)*yy2; + tx21 = + (transformation->matrix.xx/TWO_SIXTEENTH)*xx2 + + (transformation->matrix.xy/TWO_SIXTEENTH)*yy1; + ty21 = + (transformation->matrix.yx/TWO_SIXTEENTH)*xx2 + + (transformation->matrix.yy/TWO_SIXTEENTH)*yy1; + tx22 = + (transformation->matrix.xx/TWO_SIXTEENTH)*xx2 + + (transformation->matrix.xy/TWO_SIXTEENTH)*yy2; + ty22 = + (transformation->matrix.yx/TWO_SIXTEENTH)*xx2 + + (transformation->matrix.yy/TWO_SIXTEENTH)*yy2; + + /* Compute the corners of the new bounding box */ + + tx1 = MIN(MIN(tx11,tx12),MIN(tx21,tx22)); + ty1 = MIN(MIN(ty11,ty12),MIN(ty21,ty22)); + tx2 = MAX(MAX(tx11,tx12),MAX(tx21,tx22)); + ty2 = MAX(MAX(ty11,ty12),MAX(ty21,ty22)); + } + + + /* Convert to device space */ + *tx1p = (int)floor(tx1*(double)x_ppem); + *ty1p = (int)floor(ty1*(double)y_ppem); + *tx2p = (int)ceil(tx2*(double)x_ppem); + *ty2p = (int)ceil(ty2*(double)y_ppem); + + /* Ensure the resulting bounding box is not empty */ + if(*tx1p == *tx2p) + (*tx2p)++; + if(*ty1p == *ty2p) + (*ty2p)++; +} + +static int +is_fixed_width(FT_Face face) +{ + PS_FontInfoRec t1info_rec; + int ftrc; + + if(FT_IS_FIXED_WIDTH(face)) { + return 1; + } + + ftrc = FT_Get_PS_Font_Info(face, &t1info_rec); + if(ftrc == 0 && t1info_rec.is_fixed_pitch) { + return 1; + } + + return 0; +} + +/* Do all the real work for OpenFont or FontInfo */ +/* xf->info is only accessed through info, and xf might be null */ + +static int +FreeTypeLoadXFont(char *fileName, + FontScalablePtr vals, FontPtr xf, FontInfoPtr info, + FontBitmapFormatPtr bmfmt, FontEntryPtr entry) +{ +#define TRANSFORM_FUNITS_X(xval) \ + ((int) \ + floor((((double)(xval)/(double)upm) * \ + ((double)instance->transformation.matrix.xx/TWO_SIXTEENTH)*(double)smetrics.x_ppem)+0.5)) +#define TRANSFORM_FUNITS_X_DOWN(xval) \ + ((int) \ + floor((((double)(xval)/(double)upm) * \ + ((double)instance->transformation.matrix.xx/TWO_SIXTEENTH)*(double)smetrics.x_ppem))) +#define TRANSFORM_FUNITS_X_UP(xval) \ + ((int) \ + ceil((((double)(xval)/(double)upm) * \ + ((double)instance->transformation.matrix.xx/TWO_SIXTEENTH)*(double)smetrics.x_ppem))) +#define TRANSFORM_FUNITS_Y(yval) \ + ((int) \ + floor((((double)(yval)/(double)upm) * \ + ((double)instance->transformation.matrix.yy/TWO_SIXTEENTH)*(double)smetrics.x_ppem)+0.5)) +#define TRANSFORM_FUNITS_Y_DOWN(yval) \ + ((int) \ + floor((((double)(yval)/(double)upm) * \ + ((double)instance->transformation.matrix.yy/TWO_SIXTEENTH) * (double)smetrics.y_ppem))) +#define TRANSFORM_FUNITS_Y_UP(yval) \ + ((int) \ + ceil((((double)(yval)/(double)upm) * \ + ((double)instance->transformation.matrix.yy/TWO_SIXTEENTH) * (double)smetrics.y_ppem))) +#define TRANSFORM_FUNITS_RAW(value) \ + ((long) \ + floor(((double)(value)/(double)upm) * 1000.0 + 0.5)) +#define TRANSFORM_FUNITS_RAW_DOWN(value) \ + ((long) \ + floor(((double)(value)/(double)upm) * 1000.0)) +#define TRANSFORM_FUNITS_RAW_UP(value) \ + ((long) \ + ceil(((double)(value)/(double)upm) * 1000.0)) + + + FTFontPtr font; + FTInstancePtr instance; + FT_Size_Metrics smetrics; + FTFacePtr face; + int xrc, i; + int charcell, constantWidth; + long rawWidth, rawAverageWidth, aw, code, lastCode, firstCode; + int upm, minLsb, maxRsb, ascent, descent, width, averageWidth; + + + xrc = FreeTypeLoadFont(&font, fileName, vals, entry, bmfmt); + if(xrc != Successful) + return xrc; + + instance = font->instance; + face = instance->face; + smetrics = instance->size->metrics; + + upm = face->face->units_per_EM; + charcell = (instance->monospaced == FT_CHARCELL); + constantWidth = charcell || is_fixed_width(face->face); + if(constantWidth && instance->monospaced == 0) + instance->monospaced = FT_MONOSPACED; + + /* There's no way to get the average width right without rasterising + all of the glyphs. We make a serious attempt at getting it right + for monospaced fonts, and try to provide a reasonable + approximation for others. */ + + if(constantWidth) + aw = face->face->max_advance_width; + else + aw = face->face->max_advance_width / 2; + + if(constantWidth) + averageWidth = 10*TRANSFORM_FUNITS_X(aw); + else + averageWidth = TRANSFORM_FUNITS_X(aw*10L); + rawAverageWidth = TRANSFORM_FUNITS_RAW(aw*10L); + + vals->width = averageWidth; + + if(info) { + info->fontAscent = + TRANSFORM_FUNITS_Y(face->face->ascender); + info->fontDescent = + -TRANSFORM_FUNITS_Y(face->face->descender); + firstCode = 0; + lastCode = 0xFFFFL; + if(font->nranges) { + lastCode = 0; + /* The ranges information does not have an effect on firstCode, + as we pass the default glyph at position 0. */ + for(i=0; i<font->nranges; i++) { + code = font->ranges[i].max_char_low + + (font->ranges[i].max_char_high<<8); + if(lastCode < code) + lastCode = code; + } + } + + if(!font->mapping.mapping || + font->mapping.mapping->encoding->row_size == 0) { + /* linear indexing */ + lastCode=MIN(lastCode, + font->mapping.mapping ? + font->mapping.mapping->encoding->size-1 : + 0xFF); + if(font->mapping.mapping && font->mapping.mapping->encoding->first) + firstCode = font->mapping.mapping->encoding->first; + info->firstRow = firstCode/0x100; + info->lastRow = lastCode/0x100; + info->firstCol = + (info->firstRow || info->lastRow) ? 0 : (firstCode & 0xFF); + info->lastCol = info->lastRow ? 0xFF : (lastCode & 0xFF); + } else { + /* matrix indexing */ + info->firstRow = font->mapping.mapping->encoding->first; + info->lastRow = MIN(font->mapping.mapping->encoding->size-1, + lastCode/0x100); + info->firstCol = font->mapping.mapping->encoding->first_col; + info->lastCol = MIN(font->mapping.mapping->encoding->row_size-1, + lastCode<0x100?lastCode:0xFF); + } + + /* firstCode and lastCode are not valid in case of a matrix + encoding */ + + transformBBox(&instance->transformation, upm, + smetrics.x_ppem, smetrics.y_ppem, + charcell? 0 : + face->face->bbox.xMin, + face->face->bbox.yMin, + charcell ? + face->face->max_advance_width : + face->face->bbox.xMax, + face->face->bbox.yMax, + &minLsb, &descent, &maxRsb, &ascent); + descent = -descent; + + width = TRANSFORM_FUNITS_X(face->face->max_advance_width); + rawWidth = + TRANSFORM_FUNITS_RAW(face->face->max_advance_width); + instance->width = width; + + info->constantWidth=constantWidth; + info->constantMetrics=charcell; + + info->minbounds.leftSideBearing = minLsb; + info->minbounds.rightSideBearing = charcell?maxRsb:minLsb; + info->minbounds.characterWidth = constantWidth?width:-width; + info->minbounds.ascent = charcell?ascent:-descent; + info->minbounds.descent = charcell?descent:-ascent; + info->minbounds.attributes = + (unsigned short)(short)(constantWidth?rawWidth:-rawWidth); + + info->maxbounds.leftSideBearing = charcell?minLsb:maxRsb; + info->maxbounds.rightSideBearing = maxRsb; + info->maxbounds.characterWidth = width; + info->maxbounds.ascent = ascent; + info->maxbounds.descent = descent; + info->maxbounds.attributes = (unsigned short)(short)rawWidth; + + if(charcell && instance->charcellMetrics == 0) { + instance->charcellMetrics = (xCharInfo*)xalloc(sizeof(xCharInfo)); + if(instance->charcellMetrics == 0) { + FreeTypeFreeFont(font); + return AllocError; + } + memcpy((char*)instance->charcellMetrics, + (char*)&info->maxbounds, sizeof(xCharInfo)); + } + + /* Glyph metrics are accurate */ + info->inkMetrics=1; + + memcpy((char *)&info->ink_maxbounds, + (char *)&info->maxbounds, sizeof(xCharInfo)); + memcpy((char *)&info->ink_minbounds, + (char *)&info->minbounds, sizeof(xCharInfo)); + + /* XXX - hack */ + info->defaultCh=0; + } + + if(xf) + xf->fontPrivate = (void*)font; + + if(info) { + xrc = FreeTypeAddProperties(font, vals, info, entry->name.name, + rawAverageWidth); + if (xrc != Successful) { + FreeTypeFreeFont(font); + return xrc; + } + } + + return Successful; +#undef TRANSFORM_FUNITS_X +#undef TRANSFORM_FUNITS_X_DOWN +#undef TRANSFORM_FUNITS_X_UP +#undef TRANSFORM_FUNITS_Y +#undef TRANSFORM_FUNITS_Y_DOWN +#undef TRANSFORM_FUNITS_Y_UP +#undef TRANSFORM_FUNITS_RAW +#undef TRANSFORM_FUNITS_RAW_DOWN +#undef TRANSFORM_FUNITS_RAW_UP +} + +/* Routines used by X11 to get info and glyphs from the font. */ + +static int +FreeTypeGetMetrics(FontPtr pFont, unsigned long count, unsigned char *chars, + FontEncoding charEncoding, unsigned long *metricCount, + xCharInfo **metrics) +{ + unsigned int code = 0; + FTFontPtr tf; + xCharInfo **mp, *m; + + + /* The compiler is supposed to initialise all the fields to 0 */ + static xCharInfo noSuchChar; + + /* MUMBLE1("Get metrics for %ld characters\n", count);*/ + + tf = (FTFontPtr)pFont->fontPrivate; + mp = metrics; + + while (count-- > 0) { + switch (charEncoding) { + case Linear8Bit: + case TwoD8Bit: + code = *chars++; + break; + case Linear16Bit: + case TwoD16Bit: + code = (*chars++ << 8); + code |= *chars++; + break; + } + + if(FreeTypeFontGetGlyphMetrics(code, &m, tf) == Successful && m!=0) { + *mp++ = m; + } else + *mp++ = &noSuchChar; + } + + *metricCount = mp - metrics; + return Successful; +} + +static int +FreeTypeGetGlyphs(FontPtr pFont, unsigned long count, unsigned char *chars, + FontEncoding charEncoding, unsigned long *glyphCount, + CharInfoPtr *glyphs) +{ + unsigned int code = 0; + FTFontPtr tf; + CharInfoPtr *gp; + CharInfoPtr g; + + tf = (FTFontPtr)pFont->fontPrivate; + gp = glyphs; + + while (count-- > 0) { + switch (charEncoding) { + case Linear8Bit: case TwoD8Bit: + code = *chars++; + break; + case Linear16Bit: case TwoD16Bit: + code = *chars++ << 8; + code |= *chars++; + break; + } + + if(FreeTypeFontGetGlyph(code, &g, tf) == Successful && g!=0) { + *gp++ = g; + } else + if(FreeTypeFontGetDefaultGlyph(&g, tf) == Successful && g!=0) + *gp++ = g; + } + + *glyphCount = gp - glyphs; + return Successful; +} + +static int +FreeTypeSetUpFont(FontPathElementPtr fpe, FontPtr xf, FontInfoPtr info, + fsBitmapFormat format, fsBitmapFormatMask fmask, + FontBitmapFormatPtr bmfmt) +{ + int xrc; + int image; + + /* Get the default bitmap format information for this X installation. + Also update it for the client if running in the font server. */ + FontDefaultFormat(&bmfmt->bit, &bmfmt->byte, &bmfmt->glyph, &bmfmt->scan); + if ((xrc = CheckFSFormat(format, fmask, &bmfmt->bit, &bmfmt->byte, + &bmfmt->scan, &bmfmt->glyph, + &image)) != Successful) { + MUMBLE1("Aborting after checking FS format: %d\n", xrc); + return xrc; + } + + if(xf) { + xf->refcnt = 0; + xf->bit = bmfmt->bit; + xf->byte = bmfmt->byte; + xf->glyph = bmfmt->glyph; + xf->scan = bmfmt->scan; + xf->format = format; + xf->get_glyphs = FreeTypeGetGlyphs; + xf->get_metrics = FreeTypeGetMetrics; + xf->unload_font = FreeTypeUnloadXFont; + xf->unload_glyphs = 0; + xf->fpe = fpe; + xf->svrPrivate = 0; + xf->fontPrivate = 0; /* we'll set it later */ + xf->fpePrivate = 0; + } + + info->defaultCh = 0; + info->noOverlap = 0; /* not updated */ + info->terminalFont = 0; /* not updated */ + info->constantMetrics = 0; /* we'll set it later */ + info->constantWidth = 0; /* we'll set it later */ + info->inkInside = 1; + info->inkMetrics = 1; + info->allExist=0; /* not updated */ + info->drawDirection = LeftToRight; /* we'll set it later */ + info->cachable = 1; /* we don't do licensing */ + info->anamorphic = 0; /* can hinting lead to anamorphic scaling? */ + info->maxOverlap = 0; /* we'll set it later. */ + info->pad = 0; /* ??? */ + return Successful; +} + +/* Functions exported by the backend */ + +static int +FreeTypeOpenScalable(FontPathElementPtr fpe, FontPtr *ppFont, int flags, + FontEntryPtr entry, char *fileName, FontScalablePtr vals, + fsBitmapFormat format, fsBitmapFormatMask fmask, + FontPtr non_cachable_font) +{ + int xrc; + FontPtr xf; + FontBitmapFormatRec bmfmt; + + MUMBLE1("Open Scalable %s, XLFD=",fileName); +#ifdef DEBUG_TRUETYPE + fwrite(entry->name.name, entry->name.length, 1, stdout); +#endif + MUMBLE("\n"); + + /* Reject ridiculously small values. Singular matrices are okay. */ + if(MAX(hypot(vals->pixel_matrix[0], vals->pixel_matrix[1]), + hypot(vals->pixel_matrix[2], vals->pixel_matrix[3])) + <1.0) + return BadFontName; + + /* Create an X11 server-side font. */ + xf = CreateFontRec(); + if (xf == NULL) + return AllocError; + + xrc = FreeTypeSetUpFont(fpe, xf, &xf->info, format, fmask, &bmfmt); + if(xrc != Successful) { + DestroyFontRec(xf); + return xrc; + } + /* Load the font and fill its info structure. */ + xrc = FreeTypeLoadXFont(fileName, vals, xf, &xf->info, &bmfmt, entry); + if(xrc != Successful) { + /* Free everything up at this level and return the error code. */ + MUMBLE1("Error during load: %d\n",xrc); + DestroyFontRec(xf); + return xrc; + } + + /* Set the font and return. */ + *ppFont = xf; + + return xrc; +} + +/* Routine to get requested font info. */ + +static int +FreeTypeGetInfoScalable(FontPathElementPtr fpe, FontInfoPtr info, + FontEntryPtr entry, FontNamePtr fontName, + char *fileName, FontScalablePtr vals) +{ + int xrc; + FontBitmapFormatRec bmfmt; + + MUMBLE("Get info, XLFD= "); +#ifdef DEBUG_TRUETYPE + fwrite(entry->name.name, entry->name.length, 1, stdout); +#endif + MUMBLE("\n"); + + if(MAX(hypot(vals->pixel_matrix[0], vals->pixel_matrix[1]), + hypot(vals->pixel_matrix[2], vals->pixel_matrix[3])) < 1.0) + return BadFontName; + + xrc = FreeTypeSetUpFont(fpe, 0, info, 0, 0, &bmfmt); + if(xrc != Successful) { + return xrc; + } + + bmfmt.glyph <<= 3; + + xrc = FreeTypeLoadXFont(fileName, vals, 0, info, &bmfmt, entry); + if(xrc != Successful) { + MUMBLE1("Error during load: %d\n", xrc); + return xrc; + } + + return Successful; +} + +/* Renderer registration. */ + +/* Set the capabilities of this renderer. */ +#define CAPABILITIES (CAP_CHARSUBSETTING | CAP_MATRIX) + +/* Set it up so file names with either upper or lower case can be + loaded. We don't support compressed fonts. */ +static FontRendererRec renderers[] = { + {".ttf", 4, 0, FreeTypeOpenScalable, 0, + FreeTypeGetInfoScalable, 0, CAPABILITIES}, + {".TTF", 4, 0, FreeTypeOpenScalable, 0, + FreeTypeGetInfoScalable, 0, CAPABILITIES}, + {".ttc", 4, 0, FreeTypeOpenScalable, 0, + FreeTypeGetInfoScalable, 0, CAPABILITIES}, + {".TTC", 4, 0, FreeTypeOpenScalable, 0, + FreeTypeGetInfoScalable, 0, CAPABILITIES}, + {".otf", 4, 0, FreeTypeOpenScalable, 0, + FreeTypeGetInfoScalable, 0, CAPABILITIES}, + {".OTF", 4, 0, FreeTypeOpenScalable, 0, + FreeTypeGetInfoScalable, 0, CAPABILITIES}, + {".otc", 4, 0, FreeTypeOpenScalable, 0, + FreeTypeGetInfoScalable, 0, CAPABILITIES}, + {".OTC", 4, 0, FreeTypeOpenScalable, 0, + FreeTypeGetInfoScalable, 0, CAPABILITIES}, + {".pfa", 4, 0, FreeTypeOpenScalable, 0, + FreeTypeGetInfoScalable, 0, CAPABILITIES}, + {".PFA", 4, 0, FreeTypeOpenScalable, 0, + FreeTypeGetInfoScalable, 0, CAPABILITIES}, + {".pfb", 4, 0, FreeTypeOpenScalable, 0, + FreeTypeGetInfoScalable, 0, CAPABILITIES}, + {".PFB", 4, 0, FreeTypeOpenScalable, 0, + FreeTypeGetInfoScalable, 0, CAPABILITIES}, +}; +static int num_renderers = sizeof(renderers) / sizeof(renderers[0]); + +void +FreeTypeRegisterFontFileFunctions(void) +{ + int i; + + for (i = 0; i < num_renderers; i++) + FontFileRegisterRenderer(&renderers[i]); +} diff --git a/src/FreeType/ftfuncs.h b/src/FreeType/ftfuncs.h new file mode 100644 index 0000000..6d57abe --- /dev/null +++ b/src/FreeType/ftfuncs.h @@ -0,0 +1,122 @@ +/* +Copyright (c) 1998-2002 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +/* $XFree86: xc/lib/font/FreeType/ftfuncs.h,v 1.12 2002/10/01 00:02:10 alanh Exp $ */ + +/* Number of buckets in the hashtable holding faces */ +#define NUMFACEBUCKETS 32 + +/* Glyphs are held in segments of this size */ +#define FONTSEGMENTSIZE 16 + +/* A structure that holds bitmap order and padding info. */ + +typedef struct { + int bit; /* bit order */ + int byte; /* byte order */ + int glyph; /* glyph pad size */ + int scan; /* machine word size */ +} FontBitmapFormatRec, *FontBitmapFormatPtr; + +struct FTSize_s; + +/* At the lowest level, there is face; FTFaces are in one-to-one + correspondence with TrueType faces. Multiple instance may share + the same face. */ + +typedef struct _FTFace { + char *filename; + FT_Face face; + struct _FTInstance *instances; + struct _FTInstance *active_instance; + struct _FTFace *next; /* link to next face in bucket */ +} FTFaceRec, *FTFacePtr; + +/* A transformation matrix with resolution information */ +typedef struct _FTNormalisedTransformation { + double scale; + int nonIdentity; /* if 0, matrix is the identity */ + FT_Matrix matrix; + int xres, yres; +} FTNormalisedTransformationRec, *FTNormalisedTransformationPtr; + +#define FT_MONOSPACED 1 +#define FT_CHARCELL 2 + +#define FT_AVAILABLE_UNKNOWN 0 +#define FT_AVAILABLE_NO 1 +#define FT_AVAILABLE_YES 2 +#define FT_AVAILABLE_RASTERISED 3 + +/* An instance builds on a face by specifying the transformation + matrix. Multiple fonts may share the same instance. */ + +/* This structure caches bitmap data */ +typedef struct _FTInstance { + FTFacePtr face; /* the associated face */ + FT_Size size; + FTNormalisedTransformationRec transformation; + int monospaced; + int width; /* the width of all glyphs if monospaced */ + xCharInfo *charcellMetrics; /* the metrics if charcell is 1 */ + FontBitmapFormatRec bmfmt; + unsigned nglyphs; + CharInfoPtr *glyphs; /* glyphs and available are used in parallel */ + int **available; + int refcount; + struct _FTInstance *next; /* link to next instance */ +} FTInstanceRec, *FTInstancePtr; + +/* A font is an instance with coding information; fonts are in + one-to-one correspondence with X fonts */ +typedef struct _FTFont{ + FTInstancePtr instance; + FTMappingRec mapping; + int nranges; + fsRange *ranges; +} FTFontRec, *FTFontPtr; + +/* Prototypes for some local functions */ + +static int FreeTypeOpenFace(FTFacePtr *facep, char *fileName); +static void FreeTypeFreeFace(FTFacePtr face); +static int + FreeTypeOpenInstance(FTInstancePtr *instancep, + char *fileName, FTNormalisedTransformationPtr trans, + int charcell, FontBitmapFormatPtr bmfmt); +static void FreeTypeFreeInstance(FTInstancePtr instance); +static int + FreeTypeInstanceGetGlyph(unsigned idx, CharInfoPtr *g, FTInstancePtr instance); +static int +FreeTypeRasteriseGlyph(CharInfoPtr tgp, FTInstancePtr instance, int hasMetrics); +static void FreeTypeFreeFont(FTFontPtr font); +static void FreeTypeFreeXFont(FontPtr pFont, int freeProps); +static void FreeTypeUnloadXFont(FontPtr pFont); +static int +FreeTypeAddProperties(FTFontPtr font, FontScalablePtr vals, FontInfoPtr info, + char *fontname, + int rawAverageWidth); +static int FreeTypeFontGetGlyph(unsigned code, CharInfoPtr *g, FTFontPtr font); +static int FreeTypeFontGetDefaultGlyph(CharInfoPtr *g, FTFontPtr font); +static int +FreeTypeLoadFont(FTFontPtr *fontp, char *fileName, + FontScalablePtr vals, FontEntryPtr entry, + FontBitmapFormatPtr bmfmt); diff --git a/src/FreeType/ftsystem.c b/src/FreeType/ftsystem.c new file mode 100644 index 0000000..300ff5a --- /dev/null +++ b/src/FreeType/ftsystem.c @@ -0,0 +1,329 @@ +/***************************************************************************/ +/* */ +/* ftsystem.c */ +/* */ +/* ANSI-specific FreeType low-level system interface (body). */ +/* */ +/* Copyright 1996-2001, 2002 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* Modified for XFree86. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + +/* Modified for XFree86 */ +/* $XFree86: xc/lib/font/FreeType/ftsystem.c,v 1.3 2002/10/01 00:02:10 alanh Exp $ */ + + /*************************************************************************/ + /* */ + /* This file contains the default interface used by FreeType to access */ + /* low-level, i.e. memory management, i/o access as well as thread */ + /* synchronisation. It can be replaced by user-specific routines if */ + /* necessary. */ + /* */ + /*************************************************************************/ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H +#include FT_INTERNAL_DEBUG_H +#include FT_SYSTEM_H +#include FT_ERRORS_H +#include FT_TYPES_H + +#ifndef FONTMODULE +#include <stdio.h> +#include <stdlib.h> +#else +#include "Xmd.h" +#define _XTYPEDEF_BOOL +#include "Xdefs.h" +#define DONT_DEFINE_WRAPPERS +#include "xf86_ansic.h" +#undef DONT_DEFINE_WRAPPERS +#define malloc(x) xf86malloc(x) +#define realloc(x, y) xf86realloc(x, y) +#define free(x) xf86free(x) +#define FILE XF86FILE +#define fopen(x, y) xf86fopen(x, y) +#define fclose(x) xf86fclose(x) +#define fseek(x, y, z) xf86fseek(x, y, z) +#define ftell(x) xf86ftell(x) +#define SEEK_SET XF86_SEEK_SET +#define SEEK_END XF86_SEEK_END +#define fread(x, y, z, t) xf86fread(x, y, z, t) +#endif + + + /*************************************************************************/ + /* */ + /* MEMORY MANAGEMENT INTERFACE */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* It is not necessary to do any error checking for the */ + /* allocation-related functions. This will be done by the higher level */ + /* routines like FT_Alloc() or FT_Realloc(). */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ft_alloc */ + /* */ + /* <Description> */ + /* The memory allocation function. */ + /* */ + /* <Input> */ + /* memory :: A pointer to the memory object. */ + /* */ + /* size :: The requested size in bytes. */ + /* */ + /* <Return> */ + /* The address of newly allocated block. */ + /* */ + FT_CALLBACK_DEF( void* ) + ft_alloc( FT_Memory memory, + long size ) + { + FT_UNUSED( memory ); + + return malloc( size ); + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ft_realloc */ + /* */ + /* <Description> */ + /* The memory reallocation function. */ + /* */ + /* <Input> */ + /* memory :: A pointer to the memory object. */ + /* */ + /* cur_size :: The current size of the allocated memory block. */ + /* */ + /* new_size :: The newly requested size in bytes. */ + /* */ + /* block :: The current address of the block in memory. */ + /* */ + /* <Return> */ + /* The address of the reallocated memory block. */ + /* */ + FT_CALLBACK_DEF( void* ) + ft_realloc( FT_Memory memory, + long cur_size, + long new_size, + void* block ) + { + FT_UNUSED( memory ); + FT_UNUSED( cur_size ); + + return realloc( block, new_size ); + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ft_free */ + /* */ + /* <Description> */ + /* The memory release function. */ + /* */ + /* <Input> */ + /* memory :: A pointer to the memory object. */ + /* */ + /* block :: The address of block in memory to be freed. */ + /* */ + FT_CALLBACK_DEF( void ) + ft_free( FT_Memory memory, + void* block ) + { + FT_UNUSED( memory ); + + free( block ); + } + + + /*************************************************************************/ + /* */ + /* RESOURCE MANAGEMENT INTERFACE */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_io + + /* We use the macro STREAM_FILE for convenience to extract the */ + /* system-specific stream handle from a given FreeType stream object */ +#define STREAM_FILE( stream ) ( (FILE*)stream->descriptor.pointer ) + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ft_ansi_stream_close */ + /* */ + /* <Description> */ + /* The function to close a stream. */ + /* */ + /* <Input> */ + /* stream :: A pointer to the stream object. */ + /* */ + FT_CALLBACK_DEF( void ) + ft_ansi_stream_close( FT_Stream stream ) + { + fclose( STREAM_FILE( stream ) ); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = 0; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ft_ansi_stream_io */ + /* */ + /* <Description> */ + /* The function to open a stream. */ + /* */ + /* <Input> */ + /* stream :: A pointer to the stream object. */ + /* */ + /* offset :: The position in the data stream to start reading. */ + /* */ + /* buffer :: The address of buffer to store the read data. */ + /* */ + /* count :: The number of bytes to read from the stream. */ + /* */ + /* <Return> */ + /* The number of bytes actually read. */ + /* */ + FT_CALLBACK_DEF( unsigned long ) + ft_ansi_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FILE* file; + + + file = STREAM_FILE( stream ); + + fseek( file, offset, SEEK_SET ); + + return (unsigned long)fread( buffer, 1, count, file ); + } + + + /* documentation is in ftobjs.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ) + { + FILE* file; + + + if ( !stream ) + return FT_Err_Invalid_Stream_Handle; + + file = fopen( filepathname, "rb" ); + if ( !file ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " could not open `%s'\n", filepathname )); + + return FT_Err_Cannot_Open_Resource; + } + + fseek( file, 0, SEEK_END ); + stream->size = ftell( file ); + fseek( file, 0, SEEK_SET ); + + stream->descriptor.pointer = file; + stream->pathname.pointer = (char*)filepathname; + stream->pos = 0; + + stream->read = ft_ansi_stream_io; + stream->close = ft_ansi_stream_close; + + FT_TRACE1(( "FT_Stream_Open:" )); + FT_TRACE1(( " opened `%s' (%d bytes) successfully\n", + filepathname, stream->size )); + + return FT_Err_Ok; + } + + +#ifdef FT_DEBUG_MEMORY + + extern FT_Int + ft_mem_debug_init( FT_Memory memory ); + + extern void + ft_mem_debug_done( FT_Memory memory ); + +#endif + + + /* documentation is in ftobjs.h */ + + FT_EXPORT_DEF( FT_Memory ) + FT_New_Memory( void ) + { + FT_Memory memory; + + + memory = (FT_Memory)malloc( sizeof ( *memory ) ); + if ( memory ) + { + memory->user = 0; + memory->alloc = ft_alloc; + memory->realloc = ft_realloc; + memory->free = ft_free; +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_init( memory ); +#endif + } + + return memory; + } + + + /* documentation is in ftobjs.h */ + + FT_EXPORT_DEF( void ) + FT_Done_Memory( FT_Memory memory ) + { +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_done( memory ); +#endif +#undef free + memory->free( memory, memory ); + } + + +/* END */ diff --git a/src/FreeType/fttools.c b/src/FreeType/fttools.c new file mode 100644 index 0000000..f6510af --- /dev/null +++ b/src/FreeType/fttools.c @@ -0,0 +1,188 @@ +/* + Copyright (c) 1997 by Mark Leisher + Copyright (c) 1998-2002 by Juliusz Chroboczek + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* $XFree86: xc/lib/font/FreeType/fttools.c,v 1.4 2003/02/25 21:36:54 dawes Exp $ */ + +#include "fontmisc.h" +#ifndef FONTMODULE +#include <ctype.h> +#include <string.h> +#else +#include "Xmd.h" +#include "Xdefs.h" +#include "xf86_ansic.h" +#endif + +#include "font.h" +#include "freetype/freetype.h" +#include "freetype/ftsnames.h" +#include "freetype/ttnameid.h" +#include "ft.h" + +#ifndef LSBFirst +#define LSBFirst 0 +#define MSBFirst 1 +#endif + +#define LOBYTE(s,byte) ((byte)==LSBFirst?*(char*)(s):*((char*)(s)+1)) +#define HIBYTE(s,byte) ((byte)==LSBFirst?*((char*)(s)+1):*(char*)(s)) + +int FTtoXReturnCode(int rc) +{ + if(rc == 0x40) + return AllocError; + else return BadFontFormat; +} + +/* Convert slen bytes from UCS-2 to ISO 8859-1. Byte specifies the + endianness of the string, max the maximum number of bytes written into + to. */ +int +FTu2a(int slen, char *from, char *to, int byte, int max) +{ + int i, n; + + n = 0; + for (i = 0; i < slen; i += 2) { + if(n >= max) + break; + if(HIBYTE(from+i, byte)!=0) + *to++='?'; + else + *to++ = LOBYTE(from+i,byte); + n++; + } + *to = 0; + return n; +} + +static int +FTGetName(FT_Face face, int nid, int pid, int eid, FT_SfntName *name_return) +{ + FT_SfntName name; + int n, i; + + n = FT_Get_Sfnt_Name_Count(face); + if(n <= 0) + return 0; + + for(i = 0; i < n; i++) { + if(FT_Get_Sfnt_Name(face, i, &name)) + continue; + if(name.name_id == nid && + name.platform_id == pid && + (eid < 0 || name.encoding_id == eid)) { + switch(name.platform_id) { + case TT_PLATFORM_APPLE_UNICODE: + case TT_PLATFORM_MACINTOSH: + if(name.language_id != TT_MAC_LANGID_ENGLISH) + continue; + break; + case TT_PLATFORM_MICROSOFT: + if(name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES && + name.language_id != TT_MS_LANGID_ENGLISH_UNITED_KINGDOM) + break; + continue; + break; + default: + break; + } + *name_return = name; + return 1; + } + } + return 0; +} + +int +FTGetEnglishName(FT_Face face, int nid, char *name_return, int name_len) +{ + FT_SfntName name; + int len; + + if(FTGetName(face, nid, + TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, &name) || + FTGetName(face, nid, + TT_PLATFORM_APPLE_UNICODE, -1, &name)) + return FTu2a(name.string_len, name.string, name_return, + MSBFirst, name_len); + + /* Pretend that Apple Roman is ISO 8859-1. */ + if(FTGetName(face, nid, TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, &name)) { + len = name.string_len; + if(len > name_len) + len = name_len; + memcpy(name_return, name.string, name_len); + return len; + } + + /* Must be some font that can only be named in Polish or something. */ + return -1; +} + +int +FTcheckForTTCName(char *fileName, char **realFileName, int *faceNumber) +{ + int length; + int fn; + int i, j; + char *start, *realName; + + length = strlen(fileName); + if(length < 4) + return 0; + + if(strcasecmp(fileName + (length-4), ".ttc") != 0 && + strcasecmp(fileName + (length-4), ".otc") != 0) + return 0; + + realName = xalloc(length + 1); + if(realName == NULL) + return 0; + + strcpy(realName, fileName); + *realFileName=realName; + start = strchr(realName, ':'); + if(start) { + fn=0; + i=1; + while(isdigit(start[i])) { + fn *= 10; + fn += start[i]-'0'; + i++; + } + if(start[i]==':') { + *faceNumber = fn; + i++; + j = 0; + while(start[i]) { + start[j++] = start[i++]; + } + start[j] = '\0'; + return 1; + } + } + + *faceNumber = 0; + return 1; +} |