summaryrefslogtreecommitdiff
path: root/src/FreeType/ftfuncs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/FreeType/ftfuncs.c')
-rw-r--r--src/FreeType/ftfuncs.c1770
1 files changed, 1770 insertions, 0 deletions
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]);
+}