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