summaryrefslogtreecommitdiff
path: root/src/FreeType
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:50 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:50 +0000
commit3795e9702b3b3a6fe0594d09cdd110adeb5e42f9 (patch)
treecaec4aaf13f12f0a31c15cb24ad2127eff834dd2 /src/FreeType
parent153e8da44452905ae04a0e20ad0d85f40399b4ca (diff)
Initial revision
Diffstat (limited to 'src/FreeType')
-rw-r--r--src/FreeType/ft.h89
-rw-r--r--src/FreeType/ftenc.c212
-rw-r--r--src/FreeType/ftfuncs.c1770
-rw-r--r--src/FreeType/ftfuncs.h122
-rw-r--r--src/FreeType/ftsystem.c329
-rw-r--r--src/FreeType/fttools.c188
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;
+}