1/*
2 * Copyright 1990 Network Computing Devices
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Network Computing Devices not be used
9 * in advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission.  Network Computing Devices
11 * makes no representations about the suitability of this software for any
12 * purpose.  It is provided "as is" without express or implied warranty.
13 *
14 * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
16 * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
17 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
18 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
19 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
20 * OR PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Author:  	Dave Lemke, Network Computing Devices, Inc
23 */
24/*
25 * FS data conversion
26 */
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include        <X11/X.h>
32#include 	<X11/Xtrans/Xtrans.h>
33#include	<X11/Xpoll.h>
34#include	<X11/fonts/FS.h>
35#include	<X11/fonts/FSproto.h>
36#include	<X11/fonts/fontmisc.h>
37#include	<X11/fonts/fontstruct.h>
38#include	"fservestr.h"
39#include	<X11/fonts/fontutil.h>
40#include	"fslibos.h"
41
42extern char _fs_glyph_undefined;
43extern char _fs_glyph_requested;
44
45/*
46 * converts data from font server form to X server form
47 */
48
49void
50_fs_convert_char_info(fsXCharInfo *src, xCharInfo *dst)
51{
52    dst->ascent = src->ascent;
53    dst->descent = src->descent;
54    dst->leftSideBearing = src->left;
55    dst->rightSideBearing = src->right;
56    dst->characterWidth = src->width;
57    dst->attributes = src->attributes;
58}
59
60void
61_fs_init_fontinfo(FSFpePtr conn, FontInfoPtr pfi)
62{
63    if (conn->fsMajorVersion == 1) {
64	unsigned short n;
65	n = pfi->firstCol;
66	pfi->firstCol = pfi->firstRow;
67	pfi->firstRow = n;
68	n = pfi->lastCol;
69	pfi->lastCol = pfi->lastRow;
70	pfi->lastRow = n;
71	pfi->defaultCh = ((pfi->defaultCh >> 8) & 0xff)
72	                   + ((pfi->defaultCh & 0xff) << 8);
73    }
74
75    if (FontCouldBeTerminal (pfi))
76    {
77	pfi->terminalFont = TRUE;
78	pfi->minbounds.ascent = pfi->fontAscent;
79	pfi->minbounds.descent = pfi->fontDescent;
80	pfi->minbounds.leftSideBearing = 0;
81	pfi->minbounds.rightSideBearing = pfi->minbounds.characterWidth;
82	pfi->maxbounds = pfi->minbounds;
83    }
84
85    FontComputeInfoAccelerators (pfi);
86}
87
88int
89_fs_convert_props(fsPropInfo *pi, fsPropOffset *po, pointer pd,
90		  FontInfoPtr pfi)
91{
92    FontPropPtr dprop;
93    int         i,
94                nprops;
95    char       *is_str;
96    fsPropOffset local_off;
97    char *off_adr;
98    char *pdc = pd;
99
100/* stolen from server/include/resource.h */
101#define BAD_RESOURCE 0xe0000000
102
103    nprops = pfi->nprops = pi->num_offsets;
104
105    if (nprops < 0
106	|| nprops > SIZE_MAX/(sizeof(FontPropRec) + sizeof(char)))
107	return -1;
108
109    dprop = malloc(sizeof(FontPropRec) * nprops + sizeof (char) * nprops);
110    if (!dprop)
111	return -1;
112
113    is_str = (char *) (dprop + nprops);
114    pfi->props = dprop;
115    pfi->isStringProp = is_str;
116
117    off_adr = (char *)po;
118    for (i = 0; i < nprops; i++, dprop++, is_str++)
119    {
120	memcpy(&local_off, off_adr, SIZEOF(fsPropOffset));
121	if ((local_off.name.position >= pi->data_len) ||
122		(local_off.name.length >
123		 (pi->data_len - local_off.name.position)))
124	    goto bail;
125	dprop->name = MakeAtom(&pdc[local_off.name.position],
126			       local_off.name.length, 1);
127	if (local_off.type != PropTypeString) {
128	    *is_str = FALSE;
129	    dprop->value = local_off.value.position;
130	} else {
131	    *is_str = TRUE;
132	    if ((local_off.value.position >= pi->data_len) ||
133		(local_off.value.length >
134		 (pi->data_len - local_off.value.position)))
135		goto bail;
136	    dprop->value = (INT32) MakeAtom(&pdc[local_off.value.position],
137					    local_off.value.length, 1);
138	    if (dprop->value == BAD_RESOURCE)
139	    {
140	      bail:
141		free (pfi->props);
142		pfi->nprops = 0;
143		pfi->props = 0;
144		pfi->isStringProp = 0;
145		return -1;
146	    }
147	}
148	off_adr += SIZEOF(fsPropOffset);
149    }
150
151    return nprops;
152}
153
154void
155_fs_free_props (FontInfoPtr pfi)
156{
157    if (pfi->props)
158    {
159	free (pfi->props);
160	pfi->nprops = 0;
161	pfi->props = 0;
162    }
163}
164
165int
166_fs_convert_lfwi_reply(FSFpePtr conn, FontInfoPtr pfi,
167		       fsListFontsWithXInfoReply *fsrep,
168		       fsPropInfo *pi, fsPropOffset *po, pointer pd)
169{
170    fsUnpack_XFontInfoHeader(fsrep, pfi);
171    _fs_init_fontinfo(conn, pfi);
172
173    if (_fs_convert_props(pi, po, pd, pfi) == -1)
174	return AllocError;
175
176    return Successful;
177}
178
179
180#define ENCODING_UNDEFINED(enc) \
181	((enc)->bits == &_fs_glyph_undefined ? \
182	 TRUE : \
183	 (access_done = access_done && (enc)->bits != &_fs_glyph_requested, \
184	  FALSE))
185
186#define GLYPH_UNDEFINED(loc) ENCODING_UNDEFINED(encoding + (loc))
187
188/*
189 * figures out what glyphs to request
190 *
191 * Includes logic to attempt to reduce number of round trips to the font
192 * server:  when a glyph is requested, fs_build_range() requests a
193 * 16-glyph range of glyphs that contains the requested glyph.  This is
194 * predicated on the belief that using a glyph increases the chances
195 * that nearby glyphs will be used: a good assumption for phonetic
196 * alphabets, but a questionable one for ideographic/pictographic ones.
197 */
198/* ARGSUSED */
199int
200fs_build_range(FontPtr pfont, Bool range_flag, unsigned int count,
201	       int item_size, unsigned char *data, int *nranges,
202	       fsRange **ranges)
203{
204    FSFontDataPtr fsd = (FSFontDataPtr) (pfont->fpePrivate);
205    FSFontPtr fsfont = (FSFontPtr) (pfont->fontPrivate);
206    register CharInfoPtr encoding = fsfont->encoding;
207    FontInfoPtr pfi = &(pfont->info);
208    fsRange	range;
209    int		access_done = TRUE;
210    int		err;
211    register unsigned long firstrow, lastrow, firstcol, lastcol;
212    register unsigned long row;
213    register unsigned long col;
214    register unsigned long loc;
215
216    if (!fsd->glyphs_to_get)
217	return AccessDone;
218
219    firstrow = pfi->firstRow;
220    lastrow = pfi->lastRow;
221    firstcol = pfi->firstCol;
222    lastcol = pfi->lastCol;
223
224    /* Make sure we have default char */
225    if (fsfont->pDefault && ENCODING_UNDEFINED(fsfont->pDefault))
226    {
227	loc = fsfont->pDefault - encoding;
228	row = loc / (lastcol - firstcol + 1) + firstrow;
229	col = loc % (lastcol - firstcol + 1) + firstcol;
230
231	range.min_char_low = range.max_char_low = col;
232	range.min_char_high = range.max_char_high = row;
233
234	if ((err = add_range(&range, nranges, ranges, FALSE)) !=
235	    Successful) return err;
236	encoding[loc].bits = &_fs_glyph_requested;
237	access_done = FALSE;
238    }
239
240    if (!range_flag && item_size == 1)
241    {
242	if (firstrow != 0) return AccessDone;
243	while (count--)
244	{
245	    col = *data++;
246	    if (col >= firstcol && col <= lastcol &&
247		GLYPH_UNDEFINED(col - firstcol))
248	    {
249		int col1, col2;
250		col1 = col & 0xf0;
251		col2 = col1 + 15;
252		if (col1 < firstcol) col1 = firstcol;
253		if (col2 > lastcol) col2 = lastcol;
254		/* Collect a 16-glyph neighborhood containing the requested
255		   glyph... should in most cases reduce the number of round
256		   trips to the font server. */
257		for (col = col1; col <= col2; col++)
258		{
259		    if (!GLYPH_UNDEFINED(col - firstcol)) continue;
260		    range.min_char_low = range.max_char_low = col;
261		    range.min_char_high = range.max_char_high = 0;
262		    if ((err = add_range(&range, nranges, ranges, FALSE)) !=
263		        Successful) return err;
264		    encoding[col - firstcol].bits = &_fs_glyph_requested;
265		    access_done = FALSE;
266		}
267	    }
268	}
269    }
270    else
271    {
272	fsRange fullrange[1];
273
274	if (range_flag && count == 0)
275	{
276	    count = 2;
277	    data = (unsigned char *)fullrange;
278	    fullrange[0].min_char_high = firstrow;
279	    fullrange[0].min_char_low = firstcol;
280	    fullrange[0].max_char_high = lastrow;
281	    fullrange[0].max_char_low = lastcol;
282	}
283
284	while (count--)
285	{
286	    int row1, col1, row2, col2;
287	    row1 = row2 = *data++;
288	    col1 = col2 = *data++;
289	    if (range_flag)
290	    {
291		if (count)
292		{
293		    row2 = *data++;
294		    col2 = *data++;
295		    count--;
296		}
297		else
298		{
299		    row2 = lastrow;
300		    col2 = lastcol;
301		}
302		if (row1 < firstrow) row1 = firstrow;
303		if (row2 > lastrow) row2 = lastrow;
304		if (col1 < firstcol) col1 = firstcol;
305		if (col2 > lastcol) col2 = lastcol;
306	    }
307	    else
308	    {
309		if (row1 < firstrow || row1 > lastrow ||
310		    col1 < firstcol || col1 > lastcol)
311		    continue;
312	    }
313	    for (row = row1; row <= row2; row++)
314	    {
315	    expand_glyph_range: ;
316		loc = (row - firstrow) * (lastcol + 1 - firstcol) +
317		      (col1 - firstcol);
318		for (col = col1; col <= col2; col++, loc++)
319		{
320		    if (GLYPH_UNDEFINED(loc))
321		    {
322			if (row1 == row2 &&
323			    (((col1 & 0xf) && col1 > firstcol) ||
324			     (col2 & 0xf) != 0xf) && (col2 < lastcol))
325			{
326			    /* If we're loading from a single row, expand
327			       range of glyphs loaded to a multiple of
328			       a 16-glyph range -- attempt to reduce number
329			       of round trips to the font server. */
330			    col1 &= 0xf0;
331			    col2 = (col2 & 0xf0) + 15;
332			    if (col1 < firstcol) col1 = firstcol;
333			    if (col2 > lastcol) col2 = lastcol;
334			    goto expand_glyph_range;
335			}
336			range.min_char_low = range.max_char_low = col;
337			range.min_char_high = range.max_char_high = row;
338			if ((err = add_range(&range, nranges, ranges, FALSE)) !=
339			    Successful) return err;
340			encoding[loc].bits = &_fs_glyph_requested;
341			access_done = FALSE;
342		    }
343		}
344	    }
345	}
346    }
347
348    return access_done ?
349	   AccessDone :
350	   Successful;
351}
352
353#undef GLYPH_UNDEFINED
354#undef ENCODING_UNDEFINED
355
356
357/* _fs_clean_aborted_loadglyphs(): Undoes the changes to the encoding array
358   performed by fs_build_range(); for use if the associated LoadGlyphs
359   requests needs to be cancelled. */
360
361void
362_fs_clean_aborted_loadglyphs(FontPtr pfont, int num_expected_ranges,
363			     fsRange *expected_ranges)
364{
365    register FSFontPtr fsfont;
366    register int i;
367
368    fsfont = (FSFontPtr) pfont->fontPrivate;
369    if (fsfont->encoding)
370    {
371	fsRange full_range[1];
372	if (!num_expected_ranges)
373	{
374	    full_range[0].min_char_low = pfont->info.firstCol;
375	    full_range[0].min_char_high = pfont->info.firstRow;
376	    full_range[0].max_char_low = pfont->info.lastCol;
377	    full_range[0].max_char_high = pfont->info.lastRow;
378	    num_expected_ranges = 1;
379	    expected_ranges = full_range;
380	}
381
382	for (i = 0; i < num_expected_ranges; i++)
383	{
384	    int row, col;
385	    for (row = expected_ranges[i].min_char_high;
386		 row <= expected_ranges[i].max_char_high;
387		 row++)
388	    {
389		register CharInfoPtr encoding = fsfont->encoding +
390		    ((row - pfont->info.firstRow) *
391		     (pfont->info.lastCol -
392		      pfont->info.firstCol + 1) +
393		     expected_ranges[i].min_char_low -
394		     pfont->info.firstCol);
395		for (col = expected_ranges[i].min_char_low;
396		     col <= expected_ranges[i].max_char_low;
397		     encoding++, col++)
398		{
399		    if (encoding->bits == &_fs_glyph_requested)
400			encoding->bits = &_fs_glyph_undefined;
401		}
402	    }
403	}
404    }
405}
406
407static int
408_fs_get_glyphs(FontPtr pFont, unsigned long count, unsigned char *chars,
409	       FontEncoding charEncoding,
410	       unsigned long *glyphCount, /* RETURN */
411	       CharInfoPtr *glyphs) 	  /* RETURN  */
412{
413    FSFontPtr   fsdata;
414    unsigned int firstCol;
415    register unsigned int numCols;
416    unsigned int firstRow;
417    unsigned int numRows;
418    CharInfoPtr *glyphsBase;
419    register unsigned int c;
420    register CharInfoPtr pci;
421    unsigned int r;
422    CharInfoPtr encoding;
423    CharInfoPtr pDefault;
424    FSFontDataPtr fsd = (FSFontDataPtr) pFont->fpePrivate;
425    int         err = Successful;
426
427    fsdata = (FSFontPtr) pFont->fontPrivate;
428    encoding = fsdata->encoding;
429    pDefault = fsdata->pDefault;
430    firstCol = pFont->info.firstCol;
431    numCols = pFont->info.lastCol - firstCol + 1;
432    glyphsBase = glyphs;
433
434    /* In this age of glyph caching, any glyphs gotten through this
435       procedure should already be loaded.  If they are not, we are
436       dealing with someone (perhaps a ddx driver optimizing a font)
437       that doesn't understand the finer points of glyph caching.  The
438       CHECK_ENCODING macro checks for this condition...  if found, it
439       calls fs_load_all_glyphs(), which corrects it.  Since the caller
440       of this code will not know how to handle a return value of
441       Suspended, the fs_load_all_glyphs() procedure will block and
442       freeze the server until the load operation is done.  Moral: the
443       glyphCachingMode flag really must indicate the capabilities of
444       the ddx drivers.  */
445
446#define CHECK_ENCODING(cnum) \
447    ( pci = encoding + (cnum), \
448      fsd->glyphs_to_get ? \
449      ( pci->bits == &_fs_glyph_undefined || pci->bits == &_fs_glyph_requested ? \
450	((err = fs_load_all_glyphs(pFont)), pci) : \
451	pci ) : \
452      pci )
453
454    switch (charEncoding) {
455
456    case Linear8Bit:
457    case TwoD8Bit:
458	if (pFont->info.firstRow > 0)
459	    break;
460	if (pFont->info.allExist && pDefault) {
461	    while (err == Successful && count--) {
462		c = (*chars++) - firstCol;
463		if (c < numCols)
464		    *glyphs++ = CHECK_ENCODING(c);
465		else
466		    *glyphs++ = pDefault;
467	    }
468	} else {
469	    while (err == Successful && count--) {
470		c = (*chars++) - firstCol;
471		if (c < numCols && CHECK_ENCODING(c)->bits)
472		    *glyphs++ = pci;
473		else if (pDefault)
474		    *glyphs++ = pDefault;
475	    }
476	}
477	break;
478    case Linear16Bit:
479	if (pFont->info.allExist && pDefault) {
480	    while (err == Successful && count--) {
481		c = *chars++ << 8;
482		c = (c | *chars++) - firstCol;
483		if (c < numCols)
484		    *glyphs++ = CHECK_ENCODING(c);
485		else
486		    *glyphs++ = pDefault;
487	    }
488	} else {
489	    while (err == Successful && count--) {
490		c = *chars++ << 8;
491		c = (c | *chars++) - firstCol;
492		if (c < numCols && CHECK_ENCODING(c)->bits)
493		    *glyphs++ = pci;
494		else if (pDefault)
495		    *glyphs++ = pDefault;
496	    }
497	}
498	break;
499
500    case TwoD16Bit:
501	firstRow = pFont->info.firstRow;
502	numRows = pFont->info.lastRow - firstRow + 1;
503	while (err == Successful && count--) {
504	    r = (*chars++) - firstRow;
505	    c = (*chars++) - firstCol;
506	    if (r < numRows && c < numCols &&
507		    CHECK_ENCODING(r * numCols + c)->bits)
508		*glyphs++ = pci;
509	    else if (pDefault)
510		*glyphs++ = pDefault;
511	}
512	break;
513    }
514    *glyphCount = glyphs - glyphsBase;
515    return err;
516}
517
518
519static int
520_fs_get_metrics(FontPtr pFont, unsigned long count, unsigned char *chars,
521		FontEncoding charEncoding,
522		unsigned long *glyphCount, /* RETURN */
523		xCharInfo **glyphs) 	   /* RETURN */
524{
525    FSFontPtr   fsdata;
526    unsigned int firstCol;
527    register unsigned int numCols;
528    unsigned int firstRow;
529    unsigned int numRows;
530    xCharInfo **glyphsBase;
531    register unsigned int c;
532    unsigned int r;
533    CharInfoPtr encoding;
534    CharInfoPtr pDefault;
535
536    fsdata = (FSFontPtr) pFont->fontPrivate;
537    encoding = fsdata->inkMetrics;
538    pDefault = fsdata->pDefault;
539    /* convert default bitmap metric to default ink metric */
540    if (pDefault)
541	pDefault = encoding + (pDefault - fsdata->encoding);
542    firstCol = pFont->info.firstCol;
543    numCols = pFont->info.lastCol - firstCol + 1;
544    glyphsBase = glyphs;
545
546
547    /* XXX - this should be much smarter */
548    /* make sure the glyphs are there */
549    switch (charEncoding) {
550
551    case Linear8Bit:
552    case TwoD8Bit:
553	if (pFont->info.firstRow > 0)
554	    break;
555	if (pFont->info.allExist && pDefault) {
556	    while (count--) {
557		c = (*chars++) - firstCol;
558		if (c < numCols)
559		    *glyphs++ = (xCharInfo *)&encoding[c];
560		else
561		    *glyphs++ = (xCharInfo *)pDefault;
562	    }
563	} else {
564	    while (count--) {
565		c = (*chars++) - firstCol;
566		if (c < numCols)
567		    *glyphs++ = (xCharInfo *)(encoding + c);
568		else if (pDefault)
569		    *glyphs++ = (xCharInfo *)pDefault;
570	    }
571	}
572	break;
573    case Linear16Bit:
574	if (pFont->info.allExist && pDefault) {
575	    while (count--) {
576		c = *chars++ << 8;
577		c = (c | *chars++) - firstCol;
578		if (c < numCols)
579		    *glyphs++ = (xCharInfo *)(encoding + c);
580		else
581		    *glyphs++ = (xCharInfo *)pDefault;
582	    }
583	} else {
584	    while (count--) {
585		c = *chars++ << 8;
586		c = (c | *chars++) - firstCol;
587		if (c < numCols)
588		    *glyphs++ = (xCharInfo *)(encoding + c);
589		else if (pDefault)
590		    *glyphs++ = (xCharInfo *)pDefault;
591	    }
592	}
593	break;
594
595    case TwoD16Bit:
596	firstRow = pFont->info.firstRow;
597	numRows = pFont->info.lastRow - firstRow + 1;
598	while (count--) {
599	    r = (*chars++) - firstRow;
600	    c = (*chars++) - firstCol;
601	    if (r < numRows && c < numCols)
602		*glyphs++ = (xCharInfo *)(encoding + (r * numCols + c));
603	    else if (pDefault)
604		*glyphs++ = (xCharInfo *)pDefault;
605	}
606	break;
607    }
608    *glyphCount = glyphs - glyphsBase;
609    return Successful;
610}
611
612
613static void
614_fs_unload_font(FontPtr pfont)
615{
616    FSFontPtr	    fsdata = (FSFontPtr) pfont->fontPrivate;
617    FSFontDataPtr   fsd = (FSFontDataPtr) pfont->fpePrivate;
618    CharInfoPtr	    encoding = fsdata->encoding;
619    FSGlyphPtr	    glyphs;
620
621    /*
622     * fsdata points at FSFontRec, FSFontDataRec and name
623     */
624    if (encoding)
625	free(encoding);
626
627    while ((glyphs = fsdata->glyphs))
628    {
629	fsdata->glyphs = glyphs->next;
630	free (glyphs);
631    }
632
633    /* XXX we may get called after the resource DB has been cleaned out */
634    if (find_old_font(fsd->fontid))
635	DeleteFontClientID (fsd->fontid);
636
637    _fs_free_props (&pfont->info);
638
639    free(fsdata);
640
641    DestroyFontRec(pfont);
642}
643
644FontPtr
645fs_create_font (FontPathElementPtr  fpe,
646		const char	    *name,
647		int		    namelen,
648		fsBitmapFormat	    format,
649		fsBitmapFormatMask  fmask)
650{
651    FontPtr	    pfont;
652    FSFontPtr	    fsfont;
653    FSFontDataPtr   fsd;
654    int		    bit, byte, scan, glyph;
655
656    pfont = CreateFontRec ();
657    if (!pfont)
658	return 0;
659    fsfont = malloc (sizeof (FSFontRec) + sizeof (FSFontDataRec) + namelen + 1);
660    if (!fsfont)
661    {
662	DestroyFontRec (pfont);
663	return 0;
664    }
665    fsd = (FSFontDataPtr) (fsfont + 1);
666    bzero((char *) fsfont, sizeof(FSFontRec));
667    bzero((char *) fsd, sizeof(FSFontDataRec));
668
669    pfont->fpe = fpe;
670    pfont->fontPrivate = (pointer) fsfont;
671    pfont->fpePrivate = (pointer) fsd;
672
673    /* These font components will be needed in packGlyphs */
674    CheckFSFormat(format, BitmapFormatMaskBit |
675		  BitmapFormatMaskByte |
676		  BitmapFormatMaskScanLineUnit |
677		  BitmapFormatMaskScanLinePad,
678		  &bit,
679		  &byte,
680		  &scan,
681		  &glyph,
682		  NULL);
683    pfont->format = format;
684    pfont->bit = bit;
685    pfont->byte = byte;
686    pfont->scan = scan;
687    pfont->glyph = glyph;
688
689    pfont->info.nprops = 0;
690    pfont->info.props = 0;
691    pfont->info.isStringProp = 0;
692
693    /* set font function pointers */
694    pfont->get_glyphs = _fs_get_glyphs;
695    pfont->get_metrics = _fs_get_metrics;
696    pfont->unload_font = _fs_unload_font;
697    pfont->unload_glyphs = NULL;
698
699    /* set the FPE private information */
700    fsd->format = format;
701    fsd->fmask = fmask;
702    fsd->name = (char *) (fsd + 1);
703    memcpy (fsd->name, name, namelen);
704    fsd->name[namelen] = '\0';
705    fsd->fontid = GetNewFontClientID ();
706
707    /* save the ID */
708    if (!StoreFontClientFont(pfont, fsd->fontid))
709    {
710	free (fsfont);
711	DestroyFontRec (pfont);
712	return 0;
713    }
714
715    return pfont;
716}
717
718pointer
719fs_alloc_glyphs (FontPtr pFont, int size)
720{
721    FSGlyphPtr	glyphs;
722    FSFontPtr	fsfont = (FSFontPtr) pFont->fontPrivate;
723
724    if (size < (INT_MAX - sizeof (FSGlyphRec)))
725	glyphs = malloc (sizeof (FSGlyphRec) + size);
726    else
727	glyphs = NULL;
728    if (glyphs == NULL)
729	return NULL;
730    glyphs->next = fsfont->glyphs;
731    fsfont->glyphs = glyphs;
732    return (pointer) (glyphs + 1);
733}
734