]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/dix/dixfonts.c
Support RDP5 logon packets.
[rdpsrv] / Xserver / programs / Xserver / dix / dixfonts.c
1 /************************************************************************
2 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
3
4                         All Rights Reserved
5
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that the name of Digital not be
11 used in advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.
13
14 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21
22 ************************************************************************/
23
24 /* $XConsortium: dixfonts.c /main/58 1996/09/28 17:11:55 rws $ */
25 /* $XFree86: xc/programs/Xserver/dix/dixfonts.c,v 3.6 1996/12/23 06:29:40 dawes Exp $ */
26
27 #define NEED_REPLIES
28 #include "X.h"
29 #include "Xmd.h"
30 #include "Xproto.h"
31 #include "scrnintstr.h"
32 #include "resource.h"
33 #include "dixstruct.h"
34 #include "cursorstr.h"
35 #include "misc.h"
36 #include "opaque.h"
37 #include "dixfontstr.h"
38 #include "closestr.h"
39
40 #ifdef DEBUG
41 #include        <stdio.h>
42 #endif
43
44 #define QUERYCHARINFO(pci, pr)  *(pr) = (pci)->metrics
45
46 static Mask FontFormat = 
47 #if IMAGE_BYTE_ORDER == LSBFirst
48     BitmapFormatByteOrderLSB |
49 #else
50     BitmapFormatByteOrderMSB |
51 #endif
52
53 #if BITMAP_BIT_ORDER == LSBFirst
54     BitmapFormatBitOrderLSB |
55 #else
56     BitmapFormatBitOrderMSB |
57 #endif
58
59     BitmapFormatImageRectMin |
60
61 #if GLYPHPADBYTES == 1
62     BitmapFormatScanlinePad8 |
63 #endif
64
65 #if GLYPHPADBYTES == 2
66     BitmapFormatScanlinePad16 |
67 #endif
68
69 #if GLYPHPADBYTES == 4
70     BitmapFormatScanlinePad32 |
71 #endif
72
73 #if GLYPHPADBYTES == 8
74     BitmapFormatScanlinePad64 |
75 #endif
76
77     BitmapFormatScanlineUnit8;
78
79 extern pointer fosNaturalParams;
80 extern FontPtr defaultFont;
81
82 static FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0;
83 static int  num_fpes = 0;
84 static FPEFunctions *fpe_functions = (FPEFunctions *) 0;
85 static int  num_fpe_types = 0;
86
87 static unsigned char *font_path_string;
88
89 static int  num_slept_fpes = 0;
90 static int  size_slept_fpes = 0;
91 static FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0;
92 static FontPatternCachePtr patternCache;
93
94 int
95 FontToXError(err)
96     int         err;
97 {
98     switch (err) {
99     case Successful:
100         return Success;
101     case AllocError:
102         return BadAlloc;
103     case BadFontName:
104     case BadFontPath:
105         return BadName;
106     case BadFontFormat: /* is there something better? */
107     case BadCharRange:
108         return BadValue;
109     default:
110         return err;
111     }
112 }
113
114
115 /*
116  * adding RT_FONT prevents conflict with default cursor font
117  */
118 Bool
119 SetDefaultFont(defaultfontname)
120     char       *defaultfontname;
121 {
122     int         err;
123     FontPtr     pf;
124     XID         fid;
125
126     fid = FakeClientID(0);
127     err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync,
128                    (unsigned) strlen(defaultfontname), defaultfontname);
129     if (err != Success)
130         return FALSE;
131     pf = (FontPtr) LookupIDByType(fid, RT_FONT);
132     if (pf == (FontPtr) NULL)
133         return FALSE;
134     defaultFont = pf;
135     return TRUE;
136 }
137
138 /*
139  * note that the font wakeup queue is not refcounted.  this is because
140  * an fpe needs to be added when it's inited, and removed when it's finally
141  * freed, in order to handle any data that isn't requested, like FS events.
142  *
143  * since the only thing that should call these routines is the renderer's
144  * init_fpe() and free_fpe(), there shouldn't be any problem in using
145  * freed data.
146  */
147 void
148 QueueFontWakeup(fpe)
149     FontPathElementPtr fpe;
150 {
151     int         i;
152     FontPathElementPtr *new;
153
154     for (i = 0; i < num_slept_fpes; i++) {
155         if (slept_fpes[i] == fpe) {
156
157 #ifdef DEBUG
158             fprintf(stderr, "re-queueing fpe wakeup\n");
159 #endif
160
161             return;
162         }
163     }
164     if (num_slept_fpes == size_slept_fpes) {
165         new = (FontPathElementPtr *)
166             xrealloc(slept_fpes,
167                      sizeof(FontPathElementPtr) * (size_slept_fpes + 4));
168         if (!new)
169             return;
170         slept_fpes = new;
171         size_slept_fpes += 4;
172     }
173     slept_fpes[num_slept_fpes] = fpe;
174     num_slept_fpes++;
175 }
176
177 void
178 RemoveFontWakeup(fpe)
179     FontPathElementPtr fpe;
180 {
181     int         i,
182                 j;
183
184     for (i = 0; i < num_slept_fpes; i++) {
185         if (slept_fpes[i] == fpe) {
186             for (j = i; j < num_slept_fpes; j++) {
187                 slept_fpes[j] = slept_fpes[j + 1];
188             }
189             num_slept_fpes--;
190             return;
191         }
192     }
193 }
194
195 /* ARGSUSED */
196 void
197 FontWakeup(data, count, LastSelectMask)
198     pointer     data;
199     int         count;
200     pointer     LastSelectMask;
201 {
202     int         i;
203     FontPathElementPtr fpe;
204
205     if (count < 0)
206         return;
207     /* wake up any fpe's that may be waiting for information */
208     for (i = 0; i < num_slept_fpes; i++) {
209         fpe = slept_fpes[i];
210         (void) (*fpe_functions[fpe->type].wakeup_fpe) (fpe, LastSelectMask);
211     }
212 }
213
214 /* XXX -- these two funcs may want to be broken into macros */
215 static void
216 #if NeedFunctionPrototypes
217 UseFPE(FontPathElementPtr fpe)
218 #else
219 UseFPE(fpe)
220     FontPathElementPtr fpe;
221 #endif
222 {
223     fpe->refcount++;
224 }
225
226 static void
227 #if NeedFunctionPrototypes
228 FreeFPE (FontPathElementPtr fpe)
229 #else
230 FreeFPE (fpe)
231     FontPathElementPtr  fpe;
232 #endif
233 {
234     fpe->refcount--;
235     if (fpe->refcount == 0) {
236         (*fpe_functions[fpe->type].free_fpe) (fpe);
237         xfree(fpe->name);
238         xfree(fpe);
239     }
240 }
241
242 static Bool
243 #if NeedFunctionPrototypes
244 doOpenFont(ClientPtr client, OFclosurePtr c)
245 #else
246 doOpenFont(client, c)
247     ClientPtr   client;
248     OFclosurePtr c;
249 #endif
250 {
251     FontPtr     pfont = NullFont;
252     FontPathElementPtr fpe;
253     ScreenPtr   pScr;
254     int         err = Successful;
255     int         i;
256     char       *alias,
257                *newname;
258     int         newlen;
259     int         aliascount = 20;
260
261     if (client->clientGone)
262     {
263         if (c->current_fpe < c->num_fpes)
264         {
265             fpe = c->fpe_list[c->current_fpe];
266             (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
267         }
268         err = Successful;
269         goto bail;
270     }
271     while (c->current_fpe < c->num_fpes) {
272         fpe = c->fpe_list[c->current_fpe];
273         err = (*fpe_functions[fpe->type].open_font)
274             ((pointer) client, fpe, c->flags,
275              c->fontname, c->fnamelen, FontFormat,
276              BitmapFormatMaskByte |
277              BitmapFormatMaskBit |
278              BitmapFormatMaskImageRectangle |
279              BitmapFormatMaskScanLinePad |
280              BitmapFormatMaskScanLineUnit,
281              c->fontid, &pfont, &alias,
282              c->non_cachable_font && c->non_cachable_font->fpe == fpe ?
283                  c->non_cachable_font :
284                  (FontPtr)0);
285
286         if (err == FontNameAlias && alias) {
287             newlen = strlen(alias);
288             newname = (char *) xrealloc(c->fontname, newlen);
289             if (!newname) {
290                 err = AllocError;
291                 break;
292             }
293             memmove(newname, alias, newlen);
294             c->fontname = newname;
295             c->fnamelen = newlen;
296             c->current_fpe = 0;
297             if (--aliascount <= 0)
298                 break;
299             continue;
300         }
301         if (err == BadFontName) {
302             c->current_fpe++;
303             continue;
304         }
305         if (err == Suspended) {
306             if (!c->slept) {
307                 c->slept = TRUE;
308                 ClientSleep(client, (ClientSleepProcPtr)doOpenFont, (pointer) c);
309             }
310             return TRUE;
311         }
312         break;
313     }
314
315     if (err != Successful)
316         goto bail;
317     if (!pfont) {
318         err = BadFontName;
319         goto bail;
320     }
321     if (!pfont->fpe)
322         pfont->fpe = fpe;
323     pfont->refcnt++;
324     if (pfont->refcnt == 1) {
325         UseFPE(pfont->fpe);
326         for (i = 0; i < screenInfo.numScreens; i++) {
327             pScr = screenInfo.screens[i];
328             if (pScr->RealizeFont)
329             {
330                 if (!(*pScr->RealizeFont) (pScr, pfont))
331                 {
332                     CloseFont (pfont, (Font) 0);
333                     err = AllocError;
334                     goto bail;
335                 }
336             }
337         }
338     }
339     if (!AddResource(c->fontid, RT_FONT, (pointer) pfont)) {
340         err = AllocError;
341         goto bail;
342     }
343     if (patternCache && pfont != c->non_cachable_font)
344         CacheFontPattern(patternCache, c->origFontName, c->origFontNameLen,
345                          pfont);
346 bail:
347     if (err != Successful && c->client != serverClient) {
348         SendErrorToClient(c->client, X_OpenFont, 0,
349                           c->fontid, FontToXError(err));
350     }
351     if (c->slept)
352         ClientWakeup(c->client);
353     for (i = 0; i < c->num_fpes; i++) {
354         FreeFPE(c->fpe_list[i]);
355     }
356     xfree(c->fpe_list);
357     xfree(c->fontname);
358     xfree(c);
359     return TRUE;
360 }
361
362 int
363 OpenFont(client, fid, flags, lenfname, pfontname)
364     ClientPtr   client;
365     XID         fid;
366     Mask        flags;
367     unsigned    lenfname;
368     char       *pfontname;
369 {
370     OFclosurePtr c;
371     int         i;
372     FontPtr     cached = (FontPtr)0;
373
374 #ifdef FONTDEBUG
375     char *f;
376     f = (char *)xalloc(lenfname + 1);
377     memmove(f, pfontname, lenfname);
378     f[lenfname] = '\0';
379     ErrorF("OpenFont: fontname is \"%s\"\n", f);
380     xfree(f);
381 #endif
382     if (!lenfname)
383         return BadName;
384     if (patternCache)
385     {
386
387     /*
388     ** Check name cache.  If we find a cached version of this font that
389     ** is cachable, immediately satisfy the request with it.  If we find
390     ** a cached version of this font that is non-cachable, we do not
391     ** satisfy the request with it.  Instead, we pass the FontPtr to the
392     ** FPE's open_font code (the fontfile FPE in turn passes the
393     ** information to the rasterizer; the fserve FPE ignores it).
394     **
395     ** Presumably, the font is marked non-cachable because the FPE has
396     ** put some licensing restrictions on it.  If the FPE, using
397     ** whatever logic it relies on, determines that it is willing to
398     ** share this existing font with the client, then it has the option
399     ** to return the FontPtr we passed it as the newly-opened font.
400     ** This allows the FPE to exercise its licensing logic without
401     ** having to create another instance of a font that already exists.
402     */
403
404         cached = FindCachedFontPattern(patternCache, pfontname, lenfname);
405         if (cached && cached->info.cachable)
406         {
407             if (!AddResource(fid, RT_FONT, (pointer) cached))
408                 return BadAlloc;
409             cached->refcnt++;
410             return Success;
411         }
412     }
413     c = (OFclosurePtr) xalloc(sizeof(OFclosureRec));
414     if (!c)
415         return BadAlloc;
416     c->fontname = (char *) xalloc(lenfname);
417     c->origFontName = pfontname;
418     c->origFontNameLen = lenfname;
419     if (!c->fontname) {
420         xfree(c);
421         return BadAlloc;
422     }
423     /*
424      * copy the current FPE list, so that if it gets changed by another client
425      * while we're blocking, the request still appears atomic
426      */
427     c->fpe_list = (FontPathElementPtr *)
428         xalloc(sizeof(FontPathElementPtr) * num_fpes);
429     if (!c->fpe_list) {
430         xfree(c->fontname);
431         xfree(c);
432         return BadAlloc;
433     }
434     memmove(c->fontname, pfontname, lenfname);
435     for (i = 0; i < num_fpes; i++) {
436         c->fpe_list[i] = font_path_elements[i];
437         UseFPE(c->fpe_list[i]);
438     }
439     c->client = client;
440     c->fontid = fid;
441     c->current_fpe = 0;
442     c->num_fpes = num_fpes;
443     c->fnamelen = lenfname;
444     c->slept = FALSE;
445     c->flags = flags;
446     c->non_cachable_font = cached;
447
448     (void) doOpenFont(client, c);
449     return Success;
450 }
451
452 /*
453  * Decrement font's ref count, and free storage if ref count equals zero
454  */
455 /*ARGSUSED*/
456 int
457 CloseFont(value, fid)
458     pointer     value;  /* must conform to DeleteType */
459     XID         fid;
460 {
461     int         nscr;
462     ScreenPtr   pscr;
463     FontPathElementPtr fpe;
464     FontPtr     pfont = (FontPtr)value;
465
466     if (pfont == NullFont)
467         return (Success);
468     if (--pfont->refcnt == 0) {
469         if (patternCache && pfont->info.cachable)
470             RemoveCachedFontPattern (patternCache, pfont);
471         /*
472          * since the last reference is gone, ask each screen to free any
473          * storage it may have allocated locally for it.
474          */
475         for (nscr = 0; nscr < screenInfo.numScreens; nscr++) {
476             pscr = screenInfo.screens[nscr];
477             if (pscr->UnrealizeFont)
478                 (*pscr->UnrealizeFont) (pscr, pfont);
479         }
480         if (pfont == defaultFont)
481             defaultFont = NULL;
482 #ifdef LBX
483         LbxFreeFontTag(pfont);
484 #endif
485         fpe = pfont->fpe;
486         (*fpe_functions[fpe->type].close_font) (fpe, pfont);
487         FreeFPE(fpe);
488     }
489     return (Success);
490 }
491
492
493 /***====================================================================***/
494
495  /*
496   * \ Sets up pReply as the correct QueryFontReply for pFont with the first
497   * nProtoCCIStructs char infos. \
498   */
499
500 void
501 QueryFont(pFont, pReply, nProtoCCIStructs)
502     FontPtr          pFont;
503     xQueryFontReply *pReply;    /* caller must allocate this storage */
504     int              nProtoCCIStructs;
505 {
506     FontPropPtr      pFP;
507     int              r,
508                      c,
509                      i;
510     xFontProp       *prFP;
511     xCharInfo       *prCI;
512     xCharInfo       *charInfos[256];
513     unsigned char    chars[512];
514     int              ninfos;
515     unsigned long    ncols;
516     unsigned long    count;
517
518     /* pr->length set in dispatch */
519     pReply->minCharOrByte2 = pFont->info.firstCol;
520     pReply->defaultChar = pFont->info.defaultCh;
521     pReply->maxCharOrByte2 = pFont->info.lastCol;
522     pReply->drawDirection = pFont->info.drawDirection;
523     pReply->allCharsExist = pFont->info.allExist;
524     pReply->minByte1 = pFont->info.firstRow;
525     pReply->maxByte1 = pFont->info.lastRow;
526     pReply->fontAscent = pFont->info.fontAscent;
527     pReply->fontDescent = pFont->info.fontDescent;
528
529     pReply->minBounds = pFont->info.ink_minbounds;
530     pReply->maxBounds = pFont->info.ink_maxbounds;
531
532     pReply->nFontProps = pFont->info.nprops;
533     pReply->nCharInfos = nProtoCCIStructs;
534
535     for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) (&pReply[1]);
536             i < pFont->info.nprops;
537             i++, pFP++, prFP++) {
538         prFP->name = pFP->name;
539         prFP->value = pFP->value;
540     }
541
542     ninfos = 0;
543     ncols = (unsigned long) (pFont->info.lastCol - pFont->info.firstCol + 1);
544     prCI = (xCharInfo *) (prFP);
545     for (r = pFont->info.firstRow;
546             ninfos < nProtoCCIStructs && r <= (int)pFont->info.lastRow;
547             r++) {
548         i = 0;
549         for (c = pFont->info.firstCol; c <= (int)pFont->info.lastCol; c++) {
550             chars[i++] = r;
551             chars[i++] = c;
552         }
553         (*pFont->get_metrics) (pFont, ncols, chars, TwoD16Bit,
554                                &count, charInfos);
555         i = 0;
556         for (i = 0; i < (int) count && ninfos < nProtoCCIStructs; i++) {
557             *prCI = *charInfos[i];
558             prCI++;
559             ninfos++;
560         }
561     }
562     return;
563 }
564
565 static Bool
566 #if NeedFunctionPrototypes
567 doListFontsAndAliases(ClientPtr client, LFclosurePtr c)
568 #else
569 doListFontsAndAliases(client, c)
570     ClientPtr   client;
571     LFclosurePtr c;
572 #endif
573 {
574     FontPathElementPtr fpe;
575     int         err = Successful;
576     FontNamesPtr names = NULL;
577     char       *name, *resolved=NULL;
578     int         namelen, resolvedlen;
579     int         nnames;
580     int         stringLens;
581     int         i;
582     xListFontsReply reply;
583     char        *bufptr;
584     char        *bufferStart;
585     int         aliascount;
586
587     if (client->clientGone)
588     {
589         if (c->current.current_fpe < c->num_fpes)
590         {
591             fpe = c->fpe_list[c->current.current_fpe];
592             (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
593         }
594         err = Successful;
595         goto bail;
596     }
597
598     if (!c->current.patlen)
599         goto finish;
600
601     while (c->current.current_fpe < c->num_fpes) {
602         fpe = c->fpe_list[c->current.current_fpe];
603         err = Successful;
604
605         if (!fpe_functions[fpe->type].start_list_fonts_and_aliases)
606         {
607             /* This FPE doesn't support/require list_fonts_and_aliases */
608
609             err = (*fpe_functions[fpe->type].list_fonts)
610                 ((pointer) c->client, fpe, c->current.pattern,
611                  c->current.patlen, c->current.max_names - c->names->nnames,
612                  c->names);
613
614             if (err == Suspended) {
615                 if (!c->slept) {
616                     c->slept = TRUE;
617                     ClientSleep(client,
618                         (ClientSleepProcPtr)doListFontsAndAliases,
619                         (pointer) c);
620                 }
621                 return TRUE;
622             }
623
624             err = BadFontName;
625         }
626         else
627         {
628             /* Start of list_fonts_and_aliases functionality.  Modeled
629                after list_fonts_with_info in that it resolves aliases,
630                except that the information collected from FPEs is just
631                names, not font info.  Each list_next_font_or_alias()
632                returns either a name into name/namelen or an alias into
633                name/namelen and its target name into resolved/resolvedlen.
634                The code at this level then resolves the alias by polling
635                the FPEs.  */
636
637             if (!c->current.list_started) {
638                 err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases)
639                     ((pointer) c->client, fpe, c->current.pattern,
640                      c->current.patlen, c->current.max_names - c->names->nnames,
641                      &c->current.private);
642                 if (err == Suspended) {
643                     if (!c->slept) {
644                         ClientSleep(client,
645                                     (ClientSleepProcPtr)doListFontsAndAliases,
646                                     (pointer) c);
647                         c->slept = TRUE;
648                     }
649                     return TRUE;
650                 }
651                 if (err == Successful)
652                     c->current.list_started = TRUE;
653             }
654             if (err == Successful) {
655                 char    *tmpname;
656                 name = 0;
657                 err = (*fpe_functions[fpe->type].list_next_font_or_alias)
658                     ((pointer) c->client, fpe, &name, &namelen, &tmpname,
659                      &resolvedlen, c->current.private);
660                 if (err == Suspended) {
661                     if (!c->slept) {
662                         ClientSleep(client,
663                                     (ClientSleepProcPtr)doListFontsAndAliases,
664                                     (pointer) c);
665                         c->slept = TRUE;
666                     }
667                     return TRUE;
668                 }
669                 if (err == FontNameAlias) {
670                     if (resolved) xfree(resolved);
671                     resolved = (char *) xalloc(resolvedlen + 1);
672                     if (resolved)
673                         memmove(resolved, tmpname, resolvedlen + 1);
674                 }
675             }
676
677             if (err == Successful)
678             {
679                 if (c->haveSaved)
680                 {
681                     if (c->savedName)
682                         (void)AddFontNamesName(c->names, c->savedName,
683                                                c->savedNameLen);
684                 }
685                 else
686                     (void)AddFontNamesName(c->names, name, namelen);
687             }
688
689             /*
690              * When we get an alias back, save our state and reset back to
691              * the start of the FPE looking for the specified name.  As
692              * soon as a real font is found for the alias, pop back to the
693              * old state
694              */
695             else if (err == FontNameAlias) {
696                 char    tmp_pattern[256];
697                 /*
698                  * when an alias recurses, we need to give
699                  * the last FPE a chance to clean up; so we call
700                  * it again, and assume that the error returned
701                  * is BadFontName, indicating the alias resolution
702                  * is complete.
703                  */
704                 memmove(tmp_pattern, resolved, resolvedlen);
705                 if (c->haveSaved)
706                 {
707                     char    *tmpname;
708                     int     tmpnamelen;
709
710                     tmpname = 0;
711                     (void) (*fpe_functions[fpe->type].list_next_font_or_alias)
712                         ((pointer) c->client, fpe, &tmpname, &tmpnamelen,
713                          &tmpname, &tmpnamelen, c->current.private);
714                     if (--aliascount <= 0)
715                     {
716                         err = BadFontName;
717                         goto ContBadFontName;
718                     }
719                 }
720                 else
721                 {
722                     c->saved = c->current;
723                     c->haveSaved = TRUE;
724                     if (c->savedName)
725                         xfree(c->savedName);
726                     c->savedName = (char *)xalloc(namelen + 1);
727                     if (c->savedName)
728                         memmove(c->savedName, name, namelen + 1);
729                     c->savedNameLen = namelen;
730                     aliascount = 20;
731                 }
732                 memmove(c->current.pattern, tmp_pattern, resolvedlen);
733                 c->current.patlen = resolvedlen;
734                 c->current.max_names = c->names->nnames + 1;
735                 c->current.current_fpe = -1;
736                 c->current.private = 0;
737                 err = BadFontName;
738             }
739         }
740         /*
741          * At the end of this FPE, step to the next.  If we've finished
742          * processing an alias, pop state back. If we've collected enough
743          * font names, quit.
744          */
745         if (err == BadFontName) {
746           ContBadFontName: ;
747             c->current.list_started = FALSE;
748             c->current.current_fpe++;
749             err = Successful;
750             if (c->haveSaved)
751             {
752                 if (c->names->nnames == c->current.max_names ||
753                         c->current.current_fpe == c->num_fpes) {
754                     c->haveSaved = FALSE;
755                     c->current = c->saved;
756                     /* Give the saved namelist a chance to clean itself up */
757                     continue;
758                 }
759             }
760             if (c->names->nnames == c->current.max_names)
761                 break;
762         }
763     }
764
765     /*
766      * send the reply
767      */
768     if (err != Successful) {
769         SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err));
770         goto bail;
771     }
772
773 finish:
774
775     names = c->names;
776     nnames = names->nnames;
777     client = c->client;
778     stringLens = 0;
779     for (i = 0; i < nnames; i++)
780         stringLens += (names->length[i] <= 255) ? names->length[i] : 0;
781
782     reply.type = X_Reply;
783     reply.length = (stringLens + nnames + 3) >> 2;
784     reply.nFonts = nnames;
785     reply.sequenceNumber = client->sequence;
786
787     bufptr = bufferStart = (char *) ALLOCATE_LOCAL(reply.length << 2);
788
789     if (!bufptr && reply.length) {
790         SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc);
791         goto bail;
792     }
793     /*
794      * since WriteToClient long word aligns things, copy to temp buffer and
795      * write all at once
796      */
797     for (i = 0; i < nnames; i++) {
798         if (names->length[i] > 255)
799             reply.nFonts--;
800         else
801         {
802             *bufptr++ = names->length[i];
803             memmove( bufptr, names->names[i], names->length[i]);
804             bufptr += names->length[i];
805         }
806     }
807     nnames = reply.nFonts;
808     reply.length = (stringLens + nnames + 3) >> 2;
809     client->pSwapReplyFunc = ReplySwapVector[X_ListFonts];
810     WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply);
811     (void) WriteToClient(client, stringLens + nnames, bufferStart);
812     DEALLOCATE_LOCAL(bufferStart);
813
814 bail:
815     if (c->slept)
816         ClientWakeup(client);
817     for (i = 0; i < c->num_fpes; i++)
818         FreeFPE(c->fpe_list[i]);
819     xfree(c->fpe_list);
820     if (c->savedName) xfree(c->savedName);
821     FreeFontNames(names);
822     xfree(c);
823     if (resolved) xfree(resolved);
824     return TRUE;
825 }
826
827 int
828 ListFonts(client, pattern, length, max_names)
829     ClientPtr   client;
830     unsigned char *pattern;
831     unsigned int length;
832     unsigned int max_names;
833 {
834     int         i;
835     LFclosurePtr c;
836
837     if (!(c = (LFclosurePtr) xalloc(sizeof *c)))
838         return BadAlloc;
839     c->fpe_list = (FontPathElementPtr *)
840         xalloc(sizeof(FontPathElementPtr) * num_fpes);
841     if (!c->fpe_list) {
842         xfree(c);
843         return BadAlloc;
844     }
845     c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100);
846     if (!c->names)
847     {
848         xfree(c->fpe_list);
849         xfree(c);
850         return BadAlloc;
851     }
852     memmove( c->current.pattern, pattern, length);
853     for (i = 0; i < num_fpes; i++) {
854         c->fpe_list[i] = font_path_elements[i];
855         UseFPE(c->fpe_list[i]);
856     }
857     c->client = client;
858     c->num_fpes = num_fpes;
859     c->current.patlen = length;
860     c->current.current_fpe = 0;
861     c->current.max_names = max_names;
862     c->current.list_started = FALSE;
863     c->current.private = 0;
864     c->haveSaved = FALSE;
865     c->slept = FALSE;
866     c->savedName = 0;
867     doListFontsAndAliases(client, c);
868     return Success;
869 }
870
871 int
872 doListFontsWithInfo(client, c)
873     ClientPtr   client;
874     LFWIclosurePtr c;
875 {
876     FontPathElementPtr fpe;
877     int         err = Successful;
878     char       *name;
879     int         namelen;
880     int         numFonts;
881     FontInfoRec fontInfo,
882                *pFontInfo;
883     xListFontsWithInfoReply *reply;
884     int         length;
885     xFontProp  *pFP;
886     int         i;
887     int         aliascount;
888     xListFontsWithInfoReply finalReply;
889
890     if (client->clientGone)
891     {
892         if (c->current.current_fpe < c->num_fpes)
893         {
894             fpe = c->fpe_list[c->current.current_fpe];
895             (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
896         }
897         err = Successful;
898         goto bail;
899     }
900     client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo];
901     if (!c->current.patlen)
902         goto finish;
903     while (c->current.current_fpe < c->num_fpes)
904     {
905         fpe = c->fpe_list[c->current.current_fpe];
906         err = Successful;
907         if (!c->current.list_started)
908         {
909             err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
910                 (client, fpe, c->current.pattern, c->current.patlen,
911                  c->current.max_names, &c->current.private);
912             if (err == Suspended)
913             {
914                 if (!c->slept)
915                 {
916                     ClientSleep(client, (ClientSleepProcPtr)doListFontsWithInfo, c);
917                     c->slept = TRUE;
918                 }
919                 return TRUE;
920             }
921             if (err == Successful)
922                 c->current.list_started = TRUE;
923         }
924         if (err == Successful)
925         {
926             name = 0;
927             pFontInfo = &fontInfo;
928             err = (*fpe_functions[fpe->type].list_next_font_with_info)
929                 (client, fpe, &name, &namelen, &pFontInfo,
930                  &numFonts, c->current.private);
931             if (err == Suspended)
932             {
933                 if (!c->slept)
934                 {
935                     ClientSleep(client,
936                              (ClientSleepProcPtr)doListFontsWithInfo,
937                              c);
938                     c->slept = TRUE;
939                 }
940                 return TRUE;
941             }
942         }
943         /*
944          * When we get an alias back, save our state and reset back to the
945          * start of the FPE looking for the specified name.  As soon as a real
946          * font is found for the alias, pop back to the old state
947          */
948         if (err == FontNameAlias)
949         {
950             /*
951              * when an alias recurses, we need to give
952              * the last FPE a chance to clean up; so we call
953              * it again, and assume that the error returned
954              * is BadFontName, indicating the alias resolution
955              * is complete.
956              */
957             if (c->haveSaved)
958             {
959                 char    *tmpname;
960                 int     tmpnamelen;
961                 FontInfoPtr tmpFontInfo;
962
963                 tmpname = 0;
964                 tmpFontInfo = &fontInfo;
965                 (void) (*fpe_functions[fpe->type].list_next_font_with_info)
966                     (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo,
967                      &numFonts, c->current.private);
968                 if (--aliascount <= 0)
969                 {
970                     err = BadFontName;
971                     goto ContBadFontName;
972                 }
973             }
974             else
975             {
976                 c->saved = c->current;
977                 c->haveSaved = TRUE;
978                 c->savedNumFonts = numFonts;
979                 c->savedName = (char *) pFontInfo;
980                 aliascount = 20;
981             }
982             memmove(c->current.pattern, name, namelen);
983             c->current.patlen = namelen;
984             c->current.max_names = 1;
985             c->current.current_fpe = 0;
986             c->current.private = 0;
987             c->current.list_started = FALSE;
988         }
989         /*
990          * At the end of this FPE, step to the next.  If we've finished
991          * processing an alias, pop state back.  If we've sent enough font
992          * names, quit.  Always wait for BadFontName to let the FPE
993          * have a chance to clean up.
994          */
995         else if (err == BadFontName)
996         {
997           ContBadFontName: ;
998             c->current.list_started = FALSE;
999             c->current.current_fpe++;
1000             err = Successful;
1001             if (c->haveSaved)
1002             {
1003                 if (c->current.max_names == 0 ||
1004                         c->current.current_fpe == c->num_fpes)
1005                 {
1006                     c->haveSaved = FALSE;
1007                     c->saved.max_names -= (1 - c->current.max_names);
1008                     c->current = c->saved;
1009                 }
1010             }
1011             else if (c->current.max_names == 0)
1012                 break;
1013         }
1014         else if (err == Successful)
1015         {
1016             length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp);
1017             reply = c->reply;
1018             if (c->length < length)
1019             {
1020                 reply = (xListFontsWithInfoReply *) xrealloc(c->reply, length);
1021                 if (!reply)
1022                 {
1023                     err = AllocError;
1024                     break;
1025                 }
1026                 c->reply = reply;
1027                 c->length = length;
1028             }
1029             if (c->haveSaved)
1030             {
1031                 numFonts = c->savedNumFonts;
1032                 name = c->savedName;
1033                 namelen = strlen(name);
1034             }
1035             reply->type = X_Reply;
1036             reply->length = (sizeof *reply - sizeof(xGenericReply) +
1037                              pFontInfo->nprops * sizeof(xFontProp) +
1038                              namelen + 3) >> 2;
1039             reply->sequenceNumber = client->sequence;
1040             reply->nameLength = namelen;
1041             reply->minBounds = pFontInfo->ink_minbounds;
1042             reply->maxBounds = pFontInfo->ink_maxbounds;
1043             reply->minCharOrByte2 = pFontInfo->firstCol;
1044             reply->maxCharOrByte2 = pFontInfo->lastCol;
1045             reply->defaultChar = pFontInfo->defaultCh;
1046             reply->nFontProps = pFontInfo->nprops;
1047             reply->drawDirection = pFontInfo->drawDirection;
1048             reply->minByte1 = pFontInfo->firstRow;
1049             reply->maxByte1 = pFontInfo->lastRow;
1050             reply->allCharsExist = pFontInfo->allExist;
1051             reply->fontAscent = pFontInfo->fontAscent;
1052             reply->fontDescent = pFontInfo->fontDescent;
1053             reply->nReplies = numFonts;
1054             pFP = (xFontProp *) (reply + 1);
1055             for (i = 0; i < pFontInfo->nprops; i++)
1056             {
1057                 pFP->name = pFontInfo->props[i].name;
1058                 pFP->value = pFontInfo->props[i].value;
1059                 pFP++;
1060             }
1061             WriteSwappedDataToClient(client, length, reply);
1062             (void) WriteToClient(client, namelen, name);
1063             if (pFontInfo == &fontInfo)
1064             {
1065                 xfree(fontInfo.props);
1066                 xfree(fontInfo.isStringProp);
1067             }
1068             --c->current.max_names;
1069         }
1070     }
1071 finish:
1072     length = sizeof(xListFontsWithInfoReply);
1073     bzero((char *) &finalReply, sizeof(xListFontsWithInfoReply));
1074     finalReply.type = X_Reply;
1075     finalReply.sequenceNumber = client->sequence;
1076     finalReply.length = (sizeof(xListFontsWithInfoReply)
1077                      - sizeof(xGenericReply)) >> 2;
1078     WriteSwappedDataToClient(client, length, &finalReply);
1079 bail:
1080     if (c->slept)
1081         ClientWakeup(client);
1082     for (i = 0; i < c->num_fpes; i++)
1083         FreeFPE(c->fpe_list[i]);
1084     xfree(c->reply);
1085     xfree(c->fpe_list);
1086     xfree(c);
1087     return TRUE;
1088 }
1089
1090 int
1091 StartListFontsWithInfo(client, length, pattern, max_names)
1092     ClientPtr   client;
1093     int         length;
1094     unsigned char       *pattern;
1095     int         max_names;
1096 {
1097     int             i;
1098     LFWIclosurePtr  c;
1099
1100     if (!(c = (LFWIclosurePtr) xalloc(sizeof *c)))
1101         goto badAlloc;
1102     c->fpe_list = (FontPathElementPtr *)
1103         xalloc(sizeof(FontPathElementPtr) * num_fpes);
1104     if (!c->fpe_list)
1105     {
1106         xfree(c);
1107         goto badAlloc;
1108     }
1109     memmove(c->current.pattern, pattern, length);
1110     for (i = 0; i < num_fpes; i++)
1111     {
1112         c->fpe_list[i] = font_path_elements[i];
1113         UseFPE(c->fpe_list[i]);
1114     }
1115     c->client = client;
1116     c->num_fpes = num_fpes;
1117     c->reply = 0;
1118     c->length = 0;
1119     c->current.patlen = length;
1120     c->current.current_fpe = 0;
1121     c->current.max_names = max_names;
1122     c->current.list_started = FALSE;
1123     c->current.private = 0;
1124     c->savedNumFonts = 0;
1125     c->haveSaved = FALSE;
1126     c->slept = FALSE;
1127     doListFontsWithInfo(client, c);
1128     return Success;
1129 badAlloc:
1130     return BadAlloc;
1131 }
1132
1133 #define TextEltHeader 2
1134 #define FontShiftSize 5
1135 static XID clearGC[] = { CT_NONE };
1136 #define clearGCmask (GCClipMask)
1137
1138 int
1139 doPolyText(client, c)
1140     ClientPtr   client;
1141     register PTclosurePtr c;
1142 {
1143     register FontPtr pFont = c->pGC->font, oldpFont;
1144     Font        fid, oldfid;
1145     int err = Success, lgerr;   /* err is in X error, not font error, space */
1146     enum { NEVER_SLEPT, START_SLEEP, SLEEPING } client_state;
1147     FontPathElementPtr fpe;
1148     GC *origGC;
1149
1150     if (client->clientGone)
1151     {
1152         fpe = c->pGC->font->fpe;
1153         (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1154
1155         if (c->slept)
1156         {
1157             /* Client has died, but we cannot bail out right now.  We
1158                need to clean up after the work we did when going to
1159                sleep.  Setting the drawable pointer to 0 makes this
1160                happen without any attempts to render or perform other
1161                unnecessary activities.  */
1162             c->pDraw = (DrawablePtr)0;
1163         }
1164         else
1165         {
1166             err = Success;
1167             goto bail;
1168         }
1169     }
1170
1171     /* Make sure our drawable hasn't disappeared while we slept. */
1172     if (c->slept &&
1173         c->pDraw &&
1174         c->pDraw != (DrawablePtr)SecurityLookupIDByClass(client, c->did,
1175                                         RC_DRAWABLE, SecurityWriteAccess))
1176     {
1177         /* Our drawable has disappeared.  Treat like client died... ask
1178            the FPE code to clean up after client and avoid further
1179            rendering while we clean up after ourself.  */
1180         fpe = c->pGC->font->fpe;
1181         (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1182         c->pDraw = (DrawablePtr)0;
1183     }
1184
1185     client_state = c->slept ? SLEEPING : NEVER_SLEPT;
1186
1187     while (c->endReq - c->pElt > TextEltHeader)
1188     {
1189         if (*c->pElt == FontChange)
1190         {
1191             if (c->endReq - c->pElt < FontShiftSize)
1192             {
1193                  err = BadLength;
1194                  goto bail;
1195             }
1196
1197             oldpFont = pFont;
1198             oldfid = fid;
1199
1200             fid =  ((Font)*(c->pElt+4))         /* big-endian */
1201                  | ((Font)*(c->pElt+3)) << 8
1202                  | ((Font)*(c->pElt+2)) << 16
1203                  | ((Font)*(c->pElt+1)) << 24;
1204             pFont = (FontPtr)SecurityLookupIDByType(client, fid, RT_FONT,
1205                                                     SecurityReadAccess);
1206             if (!pFont)
1207             {
1208                 client->errorValue = fid;
1209                 err = BadFont;
1210                 /* restore pFont and fid for step 4 (described below) */
1211                 pFont = oldpFont;
1212                 fid = oldfid;
1213
1214                 /* If we're in START_SLEEP mode, the following step
1215                    shortens the request...  in the unlikely event that
1216                    the fid somehow becomes valid before we come through
1217                    again to actually execute the polytext, which would
1218                    then mess up our refcounting scheme badly.  */
1219                 c->err = err;
1220                 c->endReq = c->pElt;
1221
1222                 goto bail;
1223             }
1224
1225             /* Step 3 (described below) on our new font */
1226             if (client_state == START_SLEEP)
1227                 pFont->refcnt++;
1228             else
1229             {
1230                 if (pFont != c->pGC->font && c->pDraw)
1231                 {
1232                     ChangeGC( c->pGC, GCFont, &fid);
1233                     ValidateGC(c->pDraw, c->pGC);
1234                     if (c->reqType == X_PolyText8)
1235                         c->polyText = (PolyTextPtr) c->pGC->ops->PolyText8;
1236                     else
1237                         c->polyText = (PolyTextPtr) c->pGC->ops->PolyText16;
1238                 }
1239
1240                 /* Undo the refcnt++ we performed when going to sleep */
1241                 if (client_state == SLEEPING)
1242                     (void)CloseFont(c->pGC->font, (Font)0);
1243             }
1244             c->pElt += FontShiftSize;
1245         }
1246         else    /* print a string */
1247         {
1248             unsigned char *pNextElt;
1249             pNextElt = c->pElt + TextEltHeader + (*c->pElt)*c->itemSize;
1250             if ( pNextElt > c->endReq)
1251             {
1252                 err = BadLength;
1253                 goto bail;
1254             }
1255             if (client_state == START_SLEEP)
1256             {
1257                 c->pElt = pNextElt;
1258                 continue;
1259             }
1260             if (c->pDraw)
1261             {
1262                 lgerr = LoadGlyphs(client, c->pGC->font, *c->pElt, c->itemSize,
1263                                    c->pElt + TextEltHeader);
1264             }
1265             else lgerr = Successful;
1266
1267             if (lgerr == Suspended)
1268             {
1269                 if (!c->slept) {
1270                     int len;
1271                     GC *pGC;
1272                     PTclosurePtr new_closure;
1273
1274     /*  We're putting the client to sleep.  We need to do a few things
1275         to ensure successful and atomic-appearing execution of the
1276         remainder of the request.  First, copy the remainder of the
1277         request into a safe malloc'd area.  Second, create a scratch GC
1278         to use for the remainder of the request.  Third, mark all fonts
1279         referenced in the remainder of the request to prevent their
1280         deallocation.  Fourth, make the original GC look like the
1281         request has completed...  set its font to the final font value
1282         from this request.  These GC manipulations are for the unlikely
1283         (but possible) event that some other client is using the GC.
1284         Steps 3 and 4 are performed by running this procedure through
1285         the remainder of the request in a special no-render mode
1286         indicated by client_state = START_SLEEP.  */
1287
1288                     /* Step 1 */
1289                     /* Allocate a malloc'd closure structure to replace
1290                        the local one we were passed */
1291                     new_closure = (PTclosurePtr) xalloc(sizeof(PTclosureRec));
1292                     if (!new_closure)
1293                     {
1294                         err = BadAlloc;
1295                         goto bail;
1296                     }
1297                     *new_closure = *c;
1298                     c = new_closure;
1299
1300                     len = c->endReq - c->pElt;
1301                     c->data = (unsigned char *)xalloc(len);
1302                     if (!c->data)
1303                     {
1304                         xfree(c);
1305                         err = BadAlloc;
1306                         goto bail;
1307                     }
1308                     memmove(c->data, c->pElt, len);
1309                     c->pElt = c->data;
1310                     c->endReq = c->pElt + len;
1311
1312                     /* Step 2 */
1313
1314                     pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
1315                     if (!pGC)
1316                     {
1317                         xfree(c->data);
1318                         xfree(c);
1319                         err = BadAlloc;
1320                         goto bail;
1321                     }
1322                     if ((err = CopyGC(c->pGC, pGC, GCFunction |
1323                                       GCPlaneMask | GCForeground |
1324                                       GCBackground | GCFillStyle |
1325                                       GCTile | GCStipple |
1326                                       GCTileStipXOrigin |
1327                                       GCTileStipYOrigin | GCFont |
1328                                       GCSubwindowMode | GCClipXOrigin |
1329                                       GCClipYOrigin | GCClipMask)) !=
1330                                       Success)
1331                     {
1332                         FreeScratchGC(pGC);
1333                         xfree(c->data);
1334                         xfree(c);
1335                         err = BadAlloc;
1336                         goto bail;
1337                     }
1338                     origGC = c->pGC;
1339                     c->pGC = pGC;
1340                     ValidateGC(c->pDraw, c->pGC);
1341                     
1342                     c->slept = TRUE;
1343                     ClientSleep(client,
1344                              (ClientSleepProcPtr)doPolyText,
1345                              (pointer) c);
1346
1347                     /* Set up to perform steps 3 and 4 */
1348                     client_state = START_SLEEP;
1349                     continue;   /* on to steps 3 and 4 */
1350                 }
1351                 return TRUE;
1352             }
1353             else if (lgerr != Successful)
1354             {
1355                 err = FontToXError(lgerr);
1356                 goto bail;
1357             }
1358             if (c->pDraw)
1359             {
1360                 c->xorg += *((INT8 *)(c->pElt + 1));    /* must be signed */
1361                 c->xorg = (* c->polyText)(c->pDraw, c->pGC, c->xorg, c->yorg,
1362                     *c->pElt, c->pElt + TextEltHeader);
1363             }
1364             c->pElt = pNextElt;
1365         }
1366     }
1367
1368 bail:
1369
1370     if (client_state == START_SLEEP)
1371     {
1372         /* Step 4 */
1373         if (pFont != origGC->font)
1374         {
1375             ChangeGC(origGC, GCFont, &fid);
1376             ValidateGC(c->pDraw, origGC);
1377         }
1378
1379         /* restore pElt pointer for execution of remainder of the request */
1380         c->pElt = c->data;
1381         return TRUE;
1382     }
1383
1384     if (c->err != Success) err = c->err;
1385     if (err != Success && c->client != serverClient) {
1386         SendErrorToClient(c->client, c->reqType, 0, 0, err);
1387     }
1388     if (c->slept)
1389     {
1390         ClientWakeup(c->client);
1391         ChangeGC(c->pGC, clearGCmask, clearGC);
1392
1393         /* Unreference the font from the scratch GC */
1394         CloseFont(c->pGC->font, (Font)0);
1395         c->pGC->font = NullFont;
1396
1397         FreeScratchGC(c->pGC);
1398         xfree(c->data);
1399         xfree(c);
1400     }
1401     return TRUE;
1402 }
1403
1404 int
1405 PolyText(client, pDraw, pGC, pElt, endReq, xorg, yorg, reqType, did)
1406     ClientPtr client;
1407     DrawablePtr pDraw;
1408     GC *pGC;
1409     unsigned char *pElt;
1410     unsigned char *endReq;
1411     int xorg;
1412     int yorg;
1413     int reqType;
1414     XID did;
1415 {
1416     PTclosureRec local_closure;
1417
1418     local_closure.pElt = pElt;
1419     local_closure.endReq = endReq;
1420     local_closure.client = client;
1421     local_closure.pDraw = pDraw;
1422     local_closure.xorg = xorg;
1423     local_closure.yorg = yorg;
1424     if ((local_closure.reqType = reqType) == X_PolyText8)
1425     {
1426         local_closure.polyText = (PolyTextPtr) pGC->ops->PolyText8;
1427         local_closure.itemSize = 1;
1428     }
1429     else
1430     {
1431         local_closure.polyText =  (PolyTextPtr) pGC->ops->PolyText16;
1432         local_closure.itemSize = 2;
1433     }
1434     local_closure.pGC = pGC;
1435     local_closure.did = did;
1436     local_closure.err = Success;
1437     local_closure.slept = FALSE;
1438
1439     (void) doPolyText(client, &local_closure);
1440     return Success;
1441 }
1442
1443
1444 #undef TextEltHeader
1445 #undef FontShiftSize
1446
1447 int
1448 doImageText(client, c)
1449     ClientPtr   client;
1450     register ITclosurePtr c;
1451 {
1452     int err = Success, lgerr;   /* err is in X error, not font error, space */
1453     FontPathElementPtr fpe;
1454
1455     if (client->clientGone)
1456     {
1457         fpe = c->pGC->font->fpe;
1458         (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1459         err = Success;
1460         goto bail;
1461     }
1462
1463     /* Make sure our drawable hasn't disappeared while we slept. */
1464     if (c->slept &&
1465         c->pDraw &&
1466         c->pDraw != (DrawablePtr)SecurityLookupIDByClass(client, c->did,
1467                                         RC_DRAWABLE, SecurityWriteAccess))
1468     {
1469         /* Our drawable has disappeared.  Treat like client died... ask
1470            the FPE code to clean up after client. */
1471         fpe = c->pGC->font->fpe;
1472         (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1473         err = Success;
1474         goto bail;
1475     }
1476
1477     lgerr = LoadGlyphs(client, c->pGC->font, c->nChars, c->itemSize, c->data);
1478     if (lgerr == Suspended)
1479     {
1480         if (!c->slept) {
1481             GC *pGC;
1482             unsigned char *data;
1483             ITclosurePtr new_closure;
1484
1485             /* We're putting the client to sleep.  We need to
1486                save some state.  Similar problem to that handled
1487                in doPolyText, but much simpler because the
1488                request structure is much simpler. */
1489
1490             new_closure = (ITclosurePtr) xalloc(sizeof(ITclosureRec));
1491             if (!new_closure)
1492             {
1493                 err = BadAlloc;
1494                 goto bail;
1495             }
1496             *new_closure = *c;
1497             c = new_closure;
1498
1499             data = (unsigned char *)xalloc(c->nChars * c->itemSize);
1500             if (!data)
1501             {
1502                 xfree(c);
1503                 err = BadAlloc;
1504                 goto bail;
1505             }
1506             memmove(data, c->data, c->nChars * c->itemSize);
1507             c->data = data;
1508
1509             pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
1510             if (!pGC)
1511             {
1512                 xfree(c->data);
1513                 xfree(c);
1514                 err = BadAlloc;
1515                 goto bail;
1516             }
1517             if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask |
1518                               GCForeground | GCBackground | GCFillStyle |
1519                               GCTile | GCStipple | GCTileStipXOrigin |
1520                               GCTileStipYOrigin | GCFont |
1521                               GCSubwindowMode | GCClipXOrigin |
1522                               GCClipYOrigin | GCClipMask)) != Success)
1523             {
1524                 FreeScratchGC(pGC);
1525                 xfree(c->data);
1526                 xfree(c);
1527                 err = BadAlloc;
1528                 goto bail;
1529             }
1530             c->pGC = pGC;
1531             ValidateGC(c->pDraw, c->pGC);
1532
1533             c->slept = TRUE;
1534             ClientSleep(client, (ClientSleepProcPtr)doImageText, (pointer) c);
1535         }
1536         return TRUE;
1537     }
1538     else if (lgerr != Successful)
1539     {
1540         err = FontToXError(lgerr);
1541         goto bail;
1542     }
1543     if (c->pDraw)
1544     {
1545         (* c->imageText)(c->pDraw, c->pGC, c->xorg, c->yorg,
1546             c->nChars, c->data);
1547     }
1548
1549 bail:
1550
1551     if (err != Success && c->client != serverClient) {
1552         SendErrorToClient(c->client, c->reqType, 0, 0, err);
1553     }
1554     if (c->slept)
1555     {
1556         ClientWakeup(c->client);
1557         ChangeGC(c->pGC, clearGCmask, clearGC);
1558
1559         /* Unreference the font from the scratch GC */
1560         CloseFont(c->pGC->font, (Font)0);
1561         c->pGC->font = NullFont;
1562
1563         FreeScratchGC(c->pGC);
1564         xfree(c->data);
1565         xfree(c);
1566     }
1567     return TRUE;
1568 }
1569
1570 int
1571 ImageText(client, pDraw, pGC, nChars, data, xorg, yorg, reqType, did)
1572     ClientPtr client;
1573     DrawablePtr pDraw;
1574     GC *pGC;
1575     int nChars;
1576     unsigned char *data;
1577     int xorg;
1578     int yorg;
1579     int reqType;
1580     XID did;
1581 {
1582     ITclosureRec local_closure;
1583
1584     local_closure.client = client;
1585     local_closure.pDraw = pDraw;
1586     local_closure.pGC = pGC;
1587     local_closure.nChars = nChars;
1588     local_closure.data = data;
1589     local_closure.xorg = xorg;
1590     local_closure.yorg = yorg;
1591     if ((local_closure.reqType = reqType) == X_ImageText8)
1592     {
1593         local_closure.imageText = (ImageTextPtr) pGC->ops->ImageText8;
1594         local_closure.itemSize = 1;
1595     }
1596     else
1597     {
1598         local_closure.imageText = (ImageTextPtr) pGC->ops->ImageText16;
1599         local_closure.itemSize = 2;
1600     }
1601     local_closure.did = did;
1602     local_closure.slept = FALSE;
1603
1604     (void) doImageText(client, &local_closure);
1605     return Success;
1606 }
1607
1608
1609 /* does the necessary magic to figure out the fpe type */
1610 static int
1611 #if NeedFunctionPrototypes
1612 DetermineFPEType(char *pathname)
1613 #else
1614 DetermineFPEType(pathname)
1615     char       *pathname;
1616 #endif
1617 {
1618     int         i;
1619
1620     for (i = 0; i < num_fpe_types; i++) {
1621         if ((*fpe_functions[i].name_check) (pathname))
1622             return i;
1623     }
1624     return -1;
1625 }
1626
1627
1628 static void
1629 #if NeedFunctionPrototypes
1630 FreeFontPath(FontPathElementPtr *list, int n, Bool force)
1631 #else
1632 FreeFontPath(list, n, force)
1633     FontPathElementPtr  *list;
1634     Bool                force;
1635     int         n;
1636 #endif
1637 {
1638     int         i;
1639
1640     for (i = 0; i < n; i++) {
1641         if (force) {
1642             /* Sanity check that all refcounts will be 0 by the time
1643                we get to the end of the list. */
1644             int found = 1;      /* the first reference is us */
1645             int j;
1646             for (j = i+1; j < n; j++) {
1647                 if (list[j] == list[i])
1648                     found++;
1649             }
1650             if (list[i]->refcount != found) {
1651                 ErrorF("FreeFontPath: FPE \"%.*s\" refcount is %d, should be %d; fixing.\n",
1652                        list[i]->name_length, list[i]->name,
1653                        list[i]->refcount, found);
1654                 list[i]->refcount = found; /* ensure it will get freed */
1655             }
1656         }
1657         FreeFPE(list[i]);
1658     }
1659     xfree((char *) list);
1660 }
1661
1662 static FontPathElementPtr
1663 #if NeedFunctionPrototypes
1664 find_existing_fpe(FontPathElementPtr *list, int num, unsigned char *name, int len)
1665 #else
1666 find_existing_fpe(list, num, name, len)
1667     FontPathElementPtr *list;
1668     int         num;
1669     unsigned char *name;
1670     int         len;
1671 #endif
1672 {
1673     FontPathElementPtr fpe;
1674     int         i;
1675
1676     for (i = 0; i < num; i++) {
1677         fpe = list[i];
1678         if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0)
1679             return fpe;
1680     }
1681     return (FontPathElementPtr) 0;
1682 }
1683
1684
1685 static int
1686 #if NeedFunctionPrototypes
1687 SetFontPathElements(int npaths, unsigned char *paths, int *bad)
1688 #else
1689 SetFontPathElements(npaths, paths, bad)
1690     int         npaths;
1691     unsigned char *paths;
1692     int        *bad;
1693 #endif
1694 {
1695     int         i,
1696                 err;
1697     int         valid_paths = 0;
1698     unsigned int len;
1699     unsigned char *cp = paths;
1700     FontPathElementPtr fpe,
1701                *fplist;
1702
1703     fplist = (FontPathElementPtr *)
1704         xalloc(sizeof(FontPathElementPtr) * npaths);
1705     if (!fplist) {
1706         *bad = 0;
1707         return BadAlloc;
1708     }
1709     for (i = 0; i < num_fpe_types; i++) {
1710         if (fpe_functions[i].set_path_hook)
1711             (*fpe_functions[i].set_path_hook) ();
1712     }
1713     for (i = 0; i < npaths; i++) {
1714         len = (unsigned int) (*cp++);
1715
1716         if (len) {
1717             /* if it's already in our active list, just reset it */
1718             /*
1719              * note that this can miss FPE's in limbo -- may be worth catching
1720              * them, though it'd muck up refcounting
1721              */
1722             fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len);
1723             if (fpe) {
1724                 err = (*fpe_functions[fpe->type].reset_fpe) (fpe);
1725                 if (err == Successful) {
1726                     UseFPE(fpe);/* since it'll be decref'd later when freed
1727                                  * from the old list */
1728                     fplist[valid_paths++] = fpe;
1729                     cp += len;
1730                     continue;
1731                 }
1732                 /* if error or can't do it, act like it's a new one */
1733             }
1734             fpe = (FontPathElementPtr) xalloc(sizeof(FontPathElementRec));
1735             if (!fpe) {
1736                 err = BadAlloc;
1737                 goto bail;
1738             }
1739             fpe->name = (char *) xalloc(len + 1);
1740             if (!fpe->name) {
1741                 xfree(fpe);
1742                 err = BadAlloc;
1743                 goto bail;
1744             }
1745             fpe->refcount = 1;
1746
1747             strncpy(fpe->name, (char *) cp, (int) len);
1748             cp += len;
1749             fpe->name[len] = '\0';
1750             fpe->name_length = len;
1751             fpe->type = DetermineFPEType(fpe->name);
1752             if (fpe->type == -1) {
1753                 xfree(fpe->name);
1754                 xfree(fpe);
1755                 err = BadValue;
1756                 goto bail;
1757             }
1758             err = (*fpe_functions[fpe->type].init_fpe) (fpe);
1759             if (err != Successful) {
1760                 xfree(fpe->name);
1761                 xfree(fpe);
1762                 err = Successful;
1763             }
1764             else {
1765               fplist[valid_paths++] = fpe;
1766             }
1767         } else {
1768             err = BadValue;
1769             goto bail;
1770         }
1771     }
1772
1773     FreeFontPath(font_path_elements, num_fpes, FALSE);
1774     font_path_elements = fplist;
1775     if (patternCache)
1776         EmptyFontPatternCache(patternCache);
1777     num_fpes = valid_paths;
1778
1779     return Success;
1780 bail:
1781     *bad = i;
1782     while (--i >= 0)
1783         FreeFPE(fplist[i]);
1784     xfree(fplist);
1785     return err;
1786 }
1787
1788 /* XXX -- do we need to pass error down to each renderer? */
1789 int
1790 SetFontPath(client, npaths, paths, error)
1791     ClientPtr   client;
1792     int         npaths;
1793     unsigned char *paths;
1794     int        *error;
1795 {
1796     int   err = Success;
1797
1798     if (npaths == 0) {
1799         if (SetDefaultFontPath(defaultFontPath) != Success)
1800             return BadName;
1801     } else {
1802         err = SetFontPathElements(npaths, paths, error);
1803     }
1804     return err;
1805 }
1806
1807 /*** TJR - dirty hack - this variable is used in lib/font/fontfile/dirfile.c */
1808 int settingDefaultFontPath = 0;
1809
1810 int
1811 SetDefaultFontPath(path)
1812     char       *path;
1813 {
1814     unsigned char *cp,
1815                *pp,
1816                *nump,
1817                *newpath;
1818     int         num = 1,
1819                 len,
1820                 err,
1821                 size = 0,
1822                 bad;
1823
1824     /* get enough for string, plus values -- use up commas */
1825     len = strlen(path) + 1;
1826     nump = cp = newpath = (unsigned char *) ALLOCATE_LOCAL(len);
1827     if (!newpath)
1828         return BadAlloc;
1829     pp = (unsigned char *) path;
1830     cp++;
1831     while (*pp) {
1832         if (*pp == ',') {
1833             *nump = (unsigned char) size;
1834             nump = cp++;
1835             pp++;
1836             num++;
1837             size = 0;
1838         } else {
1839             *cp++ = *pp++;
1840             size++;
1841         }
1842     }
1843     *nump = (unsigned char) size;
1844
1845     settingDefaultFontPath = 1;
1846
1847     err = SetFontPathElements(num, newpath, &bad);
1848
1849     settingDefaultFontPath = 0;
1850
1851     DEALLOCATE_LOCAL(newpath);
1852
1853     return err;
1854 }
1855
1856 unsigned char *
1857 GetFontPath(count, length)
1858     int                 *count;
1859     int                 *length;
1860 {
1861     int                 i;
1862     unsigned char       *c;
1863     int                 len;
1864     FontPathElementPtr  fpe;
1865
1866     len = 0;
1867     for (i = 0; i < num_fpes; i++) {
1868         fpe = font_path_elements[i];
1869         len += fpe->name_length + 1;
1870     }
1871     font_path_string = (unsigned char *) xrealloc(font_path_string, len);
1872     if (!font_path_string)
1873         return NULL;
1874
1875     c = font_path_string;
1876     *length = 0;
1877     for (i = 0; i < num_fpes; i++) {
1878         fpe = font_path_elements[i];
1879         *c = fpe->name_length;
1880         *length += *c++;
1881         memmove(c, fpe->name, fpe->name_length);
1882         c += fpe->name_length;
1883     }
1884     *count = num_fpes;
1885     return font_path_string;
1886 }
1887
1888 int
1889 LoadGlyphs(client, pfont, nchars, item_size, data)
1890     ClientPtr   client;
1891     FontPtr     pfont;
1892     unsigned    nchars;
1893     int         item_size;
1894     unsigned char *data;
1895 {
1896     if (fpe_functions[pfont->fpe->type].load_glyphs)
1897         return (*fpe_functions[pfont->fpe->type].load_glyphs)
1898             (client, pfont, 0, nchars, item_size, data);
1899     else
1900         return Successful;
1901 }
1902
1903 void
1904 DeleteClientFontStuff(client)
1905     ClientPtr   client;
1906 {
1907     int                 i;
1908     FontPathElementPtr  fpe;
1909
1910     for (i = 0; i < num_fpes; i++)
1911     {
1912         fpe = font_path_elements[i];
1913         if (fpe_functions[fpe->type].client_died)
1914             (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1915     }
1916 }
1917
1918 void
1919 InitFonts ()
1920 {
1921     patternCache = MakeFontPatternCache();
1922
1923     if (screenInfo.numScreens > screenInfo.numVideoScreens) {
1924         PrinterFontRegisterFpeFunctions();
1925         FontFileCheckRegisterFpeFunctions();
1926         check_fs_register_fpe_functions();
1927     } else {
1928         FontFileRegisterFpeFunctions();
1929         fs_register_fpe_functions();
1930     }
1931 }
1932
1933 int
1934 GetDefaultPointSize ()
1935 {
1936     return 120;
1937 }
1938
1939
1940 FontResolutionPtr
1941 GetClientResolutions (num)
1942     int        *num;
1943 {
1944     if (requestingClient && requestingClient->fontResFunc != NULL &&
1945         !requestingClient->clientGone)
1946     {
1947         return (*requestingClient->fontResFunc)(requestingClient, num);
1948     }
1949     else {
1950         static struct _FontResolution res;
1951         ScreenPtr   pScreen;
1952
1953         pScreen = screenInfo.screens[0];
1954         res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth;
1955         /*
1956          * XXX - we'll want this as long as bitmap instances are prevalent 
1957          so that we can match them from scalable fonts
1958          */
1959         if (res.x_resolution < 88)
1960             res.x_resolution = 75;
1961         else
1962             res.x_resolution = 100;
1963         res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight;
1964         if (res.y_resolution < 88)
1965             res.y_resolution = 75;
1966         else
1967             res.y_resolution = 100;
1968         res.point_size = 120;
1969         *num = 1;
1970         return &res;
1971     }
1972 }
1973
1974 /*
1975  * returns the type index of the new fpe
1976  *
1977  * should be called (only once!) by each type of fpe when initialized
1978  */
1979
1980 int
1981 #if NeedFunctionPrototypes
1982 RegisterFPEFunctions(
1983     int         (*name_func) (
1984                   char* /* name */
1985                   ),
1986     int         (*init_func) (
1987                   FontPathElementPtr /* fpe */
1988                   ),
1989     int         (*free_func) (
1990                   FontPathElementPtr /* fpe */
1991                   ),
1992     int         (*reset_func) (
1993                   FontPathElementPtr /* fpe */
1994                   ),
1995     int         (*open_func) (
1996                   pointer /* client */,
1997                   FontPathElementPtr /* fpe */,
1998                   int /* flags */,
1999                   char* /* name */,
2000                   int /* namelen */,
2001                   fsBitmapFormat /* format */,
2002                   fsBitmapFormatMask /* fmask */,
2003                   unsigned long /* id (type XID or FSID) */,
2004                   FontPtr* /* pFont */,
2005                   char** /* aliasName */,
2006                   FontPtr /* non_cachable_font */
2007                   ),
2008     int         (*close_func) (
2009                   FontPathElementPtr /* fpe */,
2010                   FontPtr /* pFont */
2011                   ),
2012     int         (*list_func) (
2013                   pointer /* client */,
2014                   FontPathElementPtr /* fpe */,
2015                   char* /* pat */,
2016                   int /* len */,
2017                   int /* max */,
2018                   FontNamesPtr /* names */
2019                   ),
2020     int         (*start_lfwi_func) (
2021                   pointer /* client */,
2022                   FontPathElementPtr /* fpe */,
2023                   char* /* pat */,
2024                   int /* patlen */,
2025                   int /* maxnames */,
2026                   pointer* /* privatep */
2027                   ),
2028     int         (*next_lfwi_func) (
2029                   pointer /* client */,
2030                   FontPathElementPtr /* fpe */,
2031                   char** /* name */,
2032                   int* /* namelen */,
2033                   FontInfoPtr* /* info */,
2034                   int* /* numFonts */,
2035                   pointer /* private */
2036                   ),
2037     int         (*wakeup_func) (
2038                   FontPathElementPtr /* fpe */,
2039                   unsigned long* /* LastSelectMask */
2040                   ),
2041     int         (*client_died) (
2042                   pointer /* client */,
2043                   FontPathElementPtr /* fpe */
2044                   ),
2045     int         (*load_glyphs) (
2046                   pointer /* client */,
2047                   FontPtr /* pfont */,
2048                   Bool /* range_flag */,
2049                   unsigned int /* nchars */,
2050                   int /* item_size */,
2051                   unsigned char* /* data */
2052                   ),
2053     int         (*start_list_alias_func) (
2054                   pointer /* client */,
2055                   FontPathElementPtr /* fpe */,
2056                   char* /* pat */,
2057                   int /* len */,
2058                   int /* max */,
2059                   pointer* /* privatep */
2060                   ),
2061     int         (*next_list_alias_func) (
2062                   pointer /* client */,
2063                   FontPathElementPtr /* fpe */,
2064                   char** /* namep */,
2065                   int* /* namelenp */,
2066                   char** /* resolvedp */,
2067                   int* /* resolvedlenp */,
2068                   pointer /* private */
2069                   ),
2070     void        (*set_path_func) (
2071                   void
2072                   )
2073 )
2074 #else
2075 RegisterFPEFunctions(name_func, init_func, free_func, reset_func,
2076            open_func, close_func, list_func, start_lfwi_func, next_lfwi_func,
2077                      wakeup_func, client_died, load_glyphs,
2078                      start_list_alias_func, next_list_alias_func,
2079                      set_path_func)
2080     Bool        (*name_func) ();
2081     int         (*init_func) ();
2082     int         (*free_func) ();
2083     int         (*reset_func) ();
2084     int         (*open_func) ();
2085     int         (*close_func) ();
2086     int         (*list_func) ();
2087     int         (*start_lfwi_func) ();
2088     int         (*next_lfwi_func) ();
2089     int         (*wakeup_func) ();
2090     int         (*client_died) ();
2091     int         (*load_glyphs) ();
2092     int         (*start_list_alias_func) ();
2093     int         (*next_list_alias_func) ();
2094     void        (*set_path_func) ();
2095 #endif
2096 {
2097     FPEFunctions *new;
2098
2099     /* grow the list */
2100     new = (FPEFunctions *) xrealloc(fpe_functions,
2101                                  (num_fpe_types + 1) * sizeof(FPEFunctions));
2102     if (!new)
2103         return -1;
2104     fpe_functions = new;
2105
2106     fpe_functions[num_fpe_types].name_check = name_func;
2107     fpe_functions[num_fpe_types].open_font = open_func;
2108     fpe_functions[num_fpe_types].close_font = close_func;
2109     fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func;
2110     fpe_functions[num_fpe_types].list_fonts = list_func;
2111     fpe_functions[num_fpe_types].start_list_fonts_with_info =
2112         start_lfwi_func;
2113     fpe_functions[num_fpe_types].list_next_font_with_info =
2114         next_lfwi_func;
2115     fpe_functions[num_fpe_types].init_fpe = init_func;
2116     fpe_functions[num_fpe_types].free_fpe = free_func;
2117     fpe_functions[num_fpe_types].reset_fpe = reset_func;
2118     fpe_functions[num_fpe_types].client_died = client_died;
2119     fpe_functions[num_fpe_types].load_glyphs = load_glyphs;
2120     fpe_functions[num_fpe_types].start_list_fonts_and_aliases =
2121         start_list_alias_func;
2122     fpe_functions[num_fpe_types].list_next_font_or_alias =
2123         next_list_alias_func;
2124     fpe_functions[num_fpe_types].set_path_hook = set_path_func;
2125
2126     return num_fpe_types++;
2127 }
2128
2129 void
2130 FreeFonts()
2131 {
2132     if (patternCache) {
2133         FreeFontPatternCache(patternCache);
2134         patternCache = 0;
2135     }
2136     FreeFontPath(font_path_elements, num_fpes, TRUE);
2137     font_path_elements = 0;
2138     num_fpes = 0;
2139     xfree(fpe_functions);
2140     num_fpe_types = 0;
2141     fpe_functions = (FPEFunctions *) 0;
2142 }
2143
2144 /* convenience functions for FS interface */
2145
2146 FontPtr
2147 find_old_font(id)
2148     XID         id;
2149 {
2150     return (FontPtr) SecurityLookupIDByType(NullClient, id, RT_NONE,
2151                                             SecurityUnknownAccess);
2152 }
2153
2154 Font
2155 GetNewFontClientID()
2156 {
2157     return FakeClientID(0);
2158 }
2159
2160 int
2161 StoreFontClientFont(pfont, id)
2162     FontPtr     pfont;
2163     Font        id;
2164 {
2165     return AddResource(id, RT_NONE, (pointer) pfont);
2166 }
2167
2168 void
2169 DeleteFontClientID(id)
2170     Font        id;
2171 {
2172     FreeResource(id, RT_NONE);
2173 }
2174
2175 int
2176 client_auth_generation(client)
2177     ClientPtr client;
2178 {
2179     return 0;
2180 }
2181
2182 static int  fs_handlers_installed = 0;
2183 static unsigned int last_server_gen;
2184
2185 int
2186 init_fs_handlers(fpe, block_handler)
2187     FontPathElementPtr fpe;
2188     BlockHandlerProcPtr block_handler;
2189 {
2190     /* if server has reset, make sure the b&w handlers are reinstalled */
2191     if (last_server_gen < serverGeneration) {
2192         last_server_gen = serverGeneration;
2193         fs_handlers_installed = 0;
2194     }
2195     if (fs_handlers_installed == 0) {
2196
2197 #ifdef DEBUG
2198         fprintf(stderr, "adding FS b & w handlers\n");
2199 #endif
2200
2201         if (!RegisterBlockAndWakeupHandlers(block_handler,
2202                                             FontWakeup, (pointer) 0))
2203             return AllocError;
2204         fs_handlers_installed++;
2205     }
2206     QueueFontWakeup(fpe);
2207     return Successful;
2208 }
2209
2210 void
2211 remove_fs_handlers(fpe, block_handler, all)
2212     FontPathElementPtr fpe;
2213     BlockHandlerProcPtr block_handler;
2214     Bool        all;
2215 {
2216     if (all) {
2217         /* remove the handlers if no one else is using them */
2218         if (--fs_handlers_installed == 0) {
2219
2220 #ifdef DEBUG
2221             fprintf(stderr, "removing FS b & w handlers\n");
2222 #endif
2223
2224             RemoveBlockAndWakeupHandlers(block_handler, FontWakeup,
2225                                          (pointer) 0);
2226         }
2227     }
2228     RemoveFontWakeup(fpe);
2229 }
2230
2231 #ifdef DEBUG
2232 #define GLWIDTHBYTESPADDED(bits,nbytes) \
2233         ((nbytes) == 1 ? (((bits)+7)>>3)        /* pad to 1 byte */ \
2234         :(nbytes) == 2 ? ((((bits)+15)>>3)&~1)  /* pad to 2 bytes */ \
2235         :(nbytes) == 4 ? ((((bits)+31)>>3)&~3)  /* pad to 4 bytes */ \
2236         :(nbytes) == 8 ? ((((bits)+63)>>3)&~7)  /* pad to 8 bytes */ \
2237         : 0)
2238
2239 #define GLYPH_SIZE(ch, nbytes)          \
2240         GLWIDTHBYTESPADDED((ch)->metrics.rightSideBearing - \
2241                         (ch)->metrics.leftSideBearing, (nbytes))
2242 dump_char_ascii(cip)
2243     CharInfoPtr cip;
2244 {
2245     int         r,
2246                 l;
2247     int         bpr;
2248     int         byte;
2249     static unsigned maskTab[] = {
2250         (1 << 7), (1 << 6), (1 << 5), (1 << 4),
2251         (1 << 3), (1 << 2), (1 << 1), (1 << 0),
2252     };
2253
2254     bpr = GLYPH_SIZE(cip, 4);
2255     for (r = 0; r < (cip->metrics.ascent + cip->metrics.descent); r++) {
2256         pointer     row = (pointer) cip->bits + r * bpr;
2257
2258         byte = 0;
2259         for (l = 0; l <= (cip->metrics.rightSideBearing -
2260                           cip->metrics.leftSideBearing); l++) {
2261             if (maskTab[l & 7] & row[l >> 3])
2262                 putchar('X');
2263             else
2264                 putchar('.');
2265         }
2266         putchar('\n');
2267     }
2268 }
2269
2270 #endif