home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / server / dix / dixfonts.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-23  |  33.3 KB  |  1,413 lines

  1. /************************************************************************
  2. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
  3. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  4.  
  5.                         All Rights Reserved
  6.  
  7. Permission to use, copy, modify, and distribute this software and its
  8. documentation for any purpose and without fee is hereby granted,
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in
  11. supporting documentation, and that the names of Digital or MIT not be
  12. used in advertising or publicity pertaining to distribution of the
  13. software without specific, written prior permission.
  14.  
  15. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  16. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  17. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  18. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  19. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  20. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21. SOFTWARE.
  22.  
  23. ************************************************************************/
  24.  
  25. /* $XConsortium: dixfonts.c,v 1.32 91/08/23 13:57:34 keith 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 "osstruct.h"
  39. #include "closestr.h"
  40.  
  41. #ifdef DEBUG
  42. #include    <stdio.h>
  43. #endif
  44.  
  45. #define QUERYCHARINFO(pci, pr)  *(pr) = (pci)->metrics
  46.  
  47. static Mask FontFormat = 
  48. #if IMAGE_BYTE_ORDER == LSBFirst
  49.     BitmapFormatByteOrderLSB |
  50. #else
  51.     BitmapFormatByteOrderMSB |
  52. #endif
  53.  
  54. #if BITMAP_BIT_ORDER == LSBFirst
  55.     BitmapFormatBitOrderLSB |
  56. #else
  57.     BitmapFormatBitOrderMSB |
  58. #endif
  59.  
  60.     BitmapFormatImageRectMin |
  61.  
  62. #if GLYPHPADBYTES == 1
  63.     BitmapFormatScanlinePad8 |
  64. #endif
  65.  
  66. #if GLYPHPADBYTES == 2
  67.     BitmapFormatScanlinePad16 |
  68. #endif
  69.  
  70. #if GLYPHPADBYTES == 4
  71.     BitmapFormatScanlinePad32 |
  72. #endif
  73.  
  74. #if GLYPHPADBYTES == 8
  75.     BitmapFormatScanlinePad64 |
  76. #endif
  77.  
  78.     BitmapFormatScanlineUnit8;
  79.  
  80. static int  FinishListFontsWithInfo();
  81.  
  82. extern pointer fosNaturalParams;
  83. extern FontPtr defaultFont;
  84.  
  85. extern void (*ReplySwapVector[256]) ();
  86.  
  87. static FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0;
  88. static int  num_fpes = 0;
  89. static FPEFunctions *fpe_functions = (FPEFunctions *) 0;
  90. static int  num_fpe_types = 0;
  91.  
  92. static unsigned char *font_path_string;
  93.  
  94. static int  num_slept_fpes = 0;
  95. static int  size_slept_fpes = 0;
  96. static FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0;
  97. static FontPatternCachePtr patternCache;
  98.  
  99. int
  100. FontToXError(err)
  101.     int         err;
  102. {
  103.     switch (err) {
  104.     case Successful:
  105.     return Success;
  106.     case AllocError:
  107.     return BadAlloc;
  108.     case BadFontName:
  109.     case BadFontPath:
  110.     return BadName;
  111.     case BadFontFormat:    /* is there something better? */
  112.     case BadCharRange:
  113.     return BadValue;
  114.     default:
  115.     return err;
  116.     }
  117. }
  118.  
  119.  
  120. /*
  121.  * adding RT_FONT prevents conflict with default cursor font
  122.  */
  123. Bool
  124. SetDefaultFont(defaultfontname)
  125.     char       *defaultfontname;
  126. {
  127.     int         err;
  128.     FontPtr     pf;
  129.     XID         fid;
  130.  
  131.     fid = FakeClientID(0);
  132.     err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync,
  133.            (unsigned) strlen(defaultfontname), defaultfontname);
  134.     if (err != Success)
  135.     return FALSE;
  136.     pf = (FontPtr) LookupIDByType(fid, RT_FONT);
  137.     if (pf == (FontPtr) NULL)
  138.     return FALSE;
  139.     defaultFont = pf;
  140.     return TRUE;
  141. }
  142.  
  143. /*
  144.  * note that the font wakeup queue is not refcounted.  this is because
  145.  * an fpe needs to be added when its inited, and removed when its finally
  146.  * freed, in order to handle any data that isn't requested, like FS events.
  147.  *
  148.  * since the only thing that should call these routines is the renderer's
  149.  * init_fpe() and free_fpe(), there shouldn't be any problem in using
  150.  * freed data.
  151.  */
  152. void
  153. QueueFontWakeup(fpe)
  154.     FontPathElementPtr fpe;
  155. {
  156.     int         i;
  157.     FontPathElementPtr *new;
  158.  
  159.     for (i = 0; i < num_slept_fpes; i++) {
  160.     if (slept_fpes[i] == fpe) {
  161.  
  162. #ifdef DEBUG
  163.         fprintf(stderr, "re-queueing fpe wakeup\n");
  164. #endif
  165.  
  166.         return;
  167.     }
  168.     }
  169.     if (num_slept_fpes == size_slept_fpes) {
  170.     new = (FontPathElementPtr *)
  171.         xrealloc(slept_fpes,
  172.              sizeof(FontPathElementPtr) * (size_slept_fpes + 4));
  173.     if (!new)
  174.         return;
  175.     slept_fpes = new;
  176.     size_slept_fpes += 4;
  177.     }
  178.     slept_fpes[num_slept_fpes] = fpe;
  179.     num_slept_fpes++;
  180. }
  181.  
  182. void
  183. RemoveFontWakeup(fpe)
  184.     FontPathElementPtr fpe;
  185. {
  186.     int         i,
  187.                 j;
  188.  
  189.     for (i = 0; i < num_slept_fpes; i++) {
  190.     if (slept_fpes[i] == fpe) {
  191.         for (j = i; j < num_slept_fpes; j++) {
  192.         slept_fpes[j] = slept_fpes[j + 1];
  193.         }
  194.         num_slept_fpes--;
  195.         return;
  196.     }
  197.     }
  198. }
  199.  
  200. /* ARGSUSED */
  201. int
  202. FontWakeup(data, count, LastSelectMask)
  203.     pointer     data;
  204.     int         count;
  205.     long       *LastSelectMask;
  206. {
  207.     int         i;
  208.     FontPathElementPtr fpe;
  209.  
  210.     if (count < 0)
  211.     return Success;        /* ignore -1 return from select XXX */
  212.     /* wake up any fpe's that may be waiting for information */
  213.     for (i = 0; i < num_slept_fpes; i++) {
  214.     fpe = slept_fpes[i];
  215.     (void) (*fpe_functions[fpe->type].wakeup_fpe) (fpe, LastSelectMask);
  216.     }
  217.  
  218.     return Success;
  219. }
  220.  
  221. static Bool
  222. doOpenFont(client, c)
  223.     ClientPtr   client;
  224.     OFclosurePtr c;
  225. {
  226.     FontPtr     pfont = NullFont;
  227.     FontPathElementPtr fpe;
  228.     ScreenPtr   pScr;
  229.     int         err = Successful;
  230.     int         i;
  231.     char       *alias,
  232.                *newname;
  233.     int         newlen;
  234.  
  235.     if (client->clientGone)
  236.     {
  237.     if (c->current_fpe < c->num_fpes)
  238.     {
  239.         fpe = c->fpe_list[c->current_fpe];
  240.         (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
  241.     }
  242.     err = Successful;
  243.     goto bail;
  244.     }
  245.     while (c->current_fpe < c->num_fpes) {
  246.     fpe = c->fpe_list[c->current_fpe];
  247.     err = (*fpe_functions[fpe->type].open_font)
  248.         ((pointer) client, fpe, c->flags,
  249.          c->fontname, c->fnamelen, FontFormat,
  250.          BitmapFormatMaskByte |
  251.          BitmapFormatMaskBit |
  252.          BitmapFormatMaskImageRectangle |
  253.          BitmapFormatMaskScanLinePad |
  254.          BitmapFormatMaskScanLineUnit,
  255.          c->fontid, &pfont, &alias);
  256.  
  257.     if (err == FontNameAlias && alias) {
  258.         newlen = strlen(alias);
  259.         newname = (char *) xrealloc(c->fontname, newlen);
  260.         if (!newname) {
  261.         err = AllocError;
  262.         break;
  263.         }
  264.         bcopy(alias, newname, newlen);
  265.         c->fontname = newname;
  266.         c->fnamelen = newlen;
  267.         c->current_fpe = 0;
  268.         continue;
  269.     }
  270.     if (err == BadFontName) {
  271.         c->current_fpe++;
  272.         continue;
  273.     }
  274.     if (err == Suspended) {
  275.         if (!c->slept) {
  276.         c->slept = TRUE;
  277.         ClientSleep(client, doOpenFont, (pointer) c);
  278.         }
  279.         return TRUE;
  280.     }
  281.     break;
  282.     }
  283.  
  284.     if (err != Successful)
  285.     goto bail;
  286.     if (!pfont) {
  287.     err = BadFontName;
  288.     goto bail;
  289.     }
  290.     pfont->fpe = fpe;
  291.     pfont->refcnt++;
  292.     if (pfont->refcnt == 1) {
  293.     UseFPE(pfont->fpe);
  294.     for (i = 0; i < screenInfo.numScreens; i++) {
  295.         pScr = screenInfo.screens[i];
  296.         if (pScr->RealizeFont)
  297.         {
  298.         if (!(*pScr->RealizeFont) (pScr, pfont))
  299.         {
  300.             CloseFont (pfont, (Font) 0);
  301.             err = AllocError;
  302.             goto bail;
  303.         }
  304.         }
  305.     }
  306.     }
  307.     if (!AddResource(c->fontid, RT_FONT, (pointer) pfont)) {
  308.     err = AllocError;
  309.     goto bail;
  310.     }
  311.     if (patternCache && pfont->info.cachable)
  312.     CacheFontPattern(patternCache, c->origFontName, c->origFontNameLen,
  313.              pfont);
  314. bail:
  315.     if (err != Successful && c->client != serverClient) {
  316.     SendErrorToClient(c->client, X_OpenFont, 0,
  317.               c->fontid, FontToXError(err));
  318.     }
  319.     if (c->slept)
  320.     ClientWakeup(c->client);
  321.     for (i = 0; i < c->num_fpes; i++) {
  322.     FreeFPE(c->fpe_list[i], FALSE);
  323.     }
  324.     xfree(c->fpe_list);
  325.     xfree(c->fontname);
  326.     xfree(c);
  327.     return TRUE;
  328. }
  329.  
  330. int
  331. OpenFont(client, fid, flags, lenfname, pfontname)
  332.     ClientPtr   client;
  333.     XID         fid;
  334.     Mask        flags;
  335.     unsigned    lenfname;
  336.     char       *pfontname;
  337. {
  338.     OFclosurePtr c;
  339.     int         i;
  340.     FontPtr     cached;
  341.  
  342.     if (patternCache)
  343.     {
  344.     cached = FindCachedFontPattern(patternCache, pfontname, lenfname);
  345.     if (cached)
  346.     {
  347.         if (!AddResource(fid, RT_FONT, (pointer) cached))
  348.         return BadAlloc;
  349.         cached->refcnt++;
  350.         return Success;
  351.     }
  352.     }
  353.     c = (OFclosurePtr) xalloc(sizeof(OFclosureRec));
  354.     if (!c)
  355.     return BadAlloc;
  356.     c->fontname = (char *) xalloc(lenfname);
  357.     c->origFontName = pfontname;
  358.     c->origFontNameLen = lenfname;
  359.     if (!c->fontname) {
  360.     xfree(c);
  361.     return BadAlloc;
  362.     }
  363.     /*
  364.      * copy the current FPE list, so that if it gets changed by another client
  365.      * while we're blocking, the request still appears atomic
  366.      */
  367.     c->fpe_list = (FontPathElementPtr *)
  368.     xalloc(sizeof(FontPathElementPtr) * num_fpes);
  369.     if (!c->fpe_list) {
  370.     xfree(c->fontname);
  371.     xfree(c);
  372.     return BadAlloc;
  373.     }
  374.     bcopy(pfontname, c->fontname, lenfname);
  375.     for (i = 0; i < num_fpes; i++) {
  376.     c->fpe_list[i] = font_path_elements[i];
  377.     UseFPE(c->fpe_list[i]);
  378.     }
  379.     c->client = client;
  380.     c->fontid = fid;
  381.     c->current_fpe = 0;
  382.     c->num_fpes = num_fpes;
  383.     c->fnamelen = lenfname;
  384.     c->slept = FALSE;
  385.     c->flags = flags;
  386.  
  387.     (void) doOpenFont(client, c);
  388.     return Success;
  389. }
  390.  
  391. /*
  392.  * Decrement font's ref count, and free storage if ref count equals zero
  393.  */
  394. /*ARGSUSED*/
  395. int
  396. CloseFont(pfont, fid)
  397.     FontPtr     pfont;
  398.     Font        fid;
  399. {
  400.     int         nscr;
  401.     ScreenPtr   pscr;
  402.     FontPathElementPtr fpe;
  403.  
  404.     if (pfont == NullFont)
  405.     return (Success);
  406.     if (--pfont->refcnt == 0) {
  407.     if (patternCache && pfont->info.cachable)
  408.         RemoveCachedFontPattern (patternCache, pfont);
  409.     /*
  410.      * since the last reference is gone, ask each screen to free any
  411.      * storage it may have allocated locally for it.
  412.      */
  413.     for (nscr = 0; nscr < screenInfo.numScreens; nscr++) {
  414.         pscr = screenInfo.screens[nscr];
  415.         if (pscr->UnrealizeFont)
  416.         (*pscr->UnrealizeFont) (pscr, pfont);
  417.     }
  418.     if (pfont == defaultFont)
  419.         defaultFont = NULL;
  420.     fpe = pfont->fpe;
  421.     (*fpe_functions[fpe->type].close_font) (fpe, pfont);
  422.     FreeFPE(fpe, FALSE);
  423.     }
  424.     return (Success);
  425. }
  426.  
  427.  
  428. /***====================================================================***/
  429.  
  430.  /*
  431.   * \ Sets up pReply as the correct QueryFontReply for pFont with the first
  432.   * nProtoCCIStructs char infos. \
  433.   */
  434.  
  435. /* 5/23/89 (ef) -- XXX! Does this already exist somewhere? */
  436. static xCharInfo xciNoSuchChar = {0, 0, 0, 0, 0, 0};
  437.  
  438. void
  439. QueryFont(pFont, pReply, nProtoCCIStructs)
  440.     FontPtr     pFont;
  441.     xQueryFontReply *pReply;    /* caller must allocate this storage */
  442.     int         nProtoCCIStructs;
  443. {
  444.     FontPropPtr pFP;
  445.     int         r,
  446.                 c,
  447.                 i;
  448.     xFontProp  *prFP;
  449.     xCharInfo  *prCI;
  450.     xCharInfo  *charInfos[256];
  451.     char        chars[512];
  452.     int         nrows,
  453.                 ncols;
  454.     int         ninfos;
  455.     int         count;
  456.  
  457.     /* pr->length set in dispatch */
  458.     pReply->minCharOrByte2 = pFont->info.firstCol;
  459.     pReply->defaultChar = pFont->info.defaultCh;
  460.     pReply->maxCharOrByte2 = pFont->info.lastCol;
  461.     pReply->drawDirection = pFont->info.drawDirection;
  462.     pReply->allCharsExist = pFont->info.allExist;
  463.     pReply->minByte1 = pFont->info.firstRow;
  464.     pReply->maxByte1 = pFont->info.lastRow;
  465.     pReply->fontAscent = pFont->info.fontAscent;
  466.     pReply->fontDescent = pFont->info.fontDescent;
  467.  
  468.     pReply->minBounds = pFont->info.ink_minbounds;
  469.     pReply->maxBounds = pFont->info.ink_maxbounds;
  470.  
  471.     pReply->nFontProps = pFont->info.nprops;
  472.     pReply->nCharInfos = nProtoCCIStructs;
  473.  
  474.     for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) (&pReply[1]);
  475.         i < pFont->info.nprops;
  476.         i++, pFP++, prFP++) {
  477.     prFP->name = pFP->name;
  478.     prFP->value = pFP->value;
  479.     }
  480.  
  481.     ninfos = 0;
  482.     ncols = pFont->info.lastCol - pFont->info.firstCol + 1;
  483.     prCI = (xCharInfo *) (prFP);
  484.     for (r = pFont->info.firstRow;
  485.         ninfos < nProtoCCIStructs && r <= pFont->info.lastRow;
  486.         r++) {
  487.     i = 0;
  488.     for (c = pFont->info.firstCol; c <= pFont->info.lastCol; c++) {
  489.         chars[i++] = r;
  490.         chars[i++] = c;
  491.     }
  492.     (*pFont->get_metrics) (pFont, ncols, chars, TwoD16Bit,
  493.                    &count, charInfos);
  494.     i = 0;
  495.     for (i = 0; i < count && ninfos < nProtoCCIStructs; i++) {
  496.         if (charInfos[i])
  497.         *prCI = *charInfos[i];
  498.         else
  499.         *prCI = xciNoSuchChar;
  500.         prCI++;
  501.         ninfos++;
  502.     }
  503.     }
  504.     return;
  505. }
  506.  
  507. static Bool
  508. doListFonts(client, c)
  509.     ClientPtr   client;
  510.     LFclosurePtr c;
  511. {
  512.     int         err;
  513.     FontPathElementPtr fpe;
  514.     xListFontsReply reply;
  515.     FontNamesPtr names;
  516.     int         stringLens,
  517.                 i,
  518.                 nnames;
  519.     char       *bufptr,
  520.                *bufferStart;
  521.     int         count;
  522.  
  523.     if (client->clientGone)
  524.     {
  525.     if (c->current_fpe < c->num_fpes)
  526.     {
  527.         fpe = c->fpe_list[c->current_fpe];
  528.         (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
  529.     }
  530.     err = Successful;
  531.     goto bail;
  532.     }
  533.     /* try each fpe in turn, returning if one wants to be blocked */
  534.  
  535.     while (c->current_fpe < c->num_fpes && c->names->nnames <= c->max_names)
  536.     {
  537.  
  538.     fpe = c->fpe_list[c->current_fpe];
  539.  
  540.     err = (*fpe_functions[fpe->type].list_fonts)
  541.         (c->client, fpe, c->pattern, c->patlen,
  542.          c->max_names - c->names->nnames, c->names);
  543.  
  544.     if (err == Suspended) {
  545.         if (!c->slept) {
  546.         c->slept = TRUE;
  547.         ClientSleep(client, doListFonts, c);
  548.         }
  549.         return TRUE;
  550.     }
  551.     if (err != Successful)
  552.         break;
  553.     c->current_fpe++;
  554.     }
  555.     if (err != Successful) {
  556.     SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err));
  557.     goto bail;
  558.     }
  559.     names = c->names;
  560.     nnames = names->nnames;
  561.     client = c->client;
  562.     stringLens = 0;
  563.     for (i = 0; i < nnames; i++)
  564.     stringLens += names->length[i];
  565.  
  566.     reply.type = X_Reply;
  567.     reply.length = (stringLens + nnames + 3) >> 2;
  568.     reply.nFonts = nnames;
  569.     reply.sequenceNumber = client->sequence;
  570.  
  571.     bufptr = bufferStart = (char *) ALLOCATE_LOCAL(reply.length << 2);
  572.  
  573.     if (!bufptr && reply.length) {
  574.     SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc);
  575.     goto bail;
  576.     }
  577.     /*
  578.      * since WriteToClient long word aligns things, copy to temp buffer and
  579.      * write all at once
  580.      */
  581.     for (i = 0; i < nnames; i++) {
  582.     *bufptr++ = names->length[i];
  583.     bcopy(names->names[i], bufptr, names->length[i]);
  584.     bufptr += names->length[i];
  585.     }
  586.     client->pSwapReplyFunc = ReplySwapVector[X_ListFonts];
  587.     WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply);
  588.     (void) WriteToClient(client, stringLens + nnames, bufferStart);
  589.     DEALLOCATE_LOCAL(bufferStart);
  590. bail:
  591.     if (c->slept)
  592.     ClientWakeup(client);
  593.     for (i = 0; i < c->num_fpes; i++)
  594.     FreeFPE(c->fpe_list[i], FALSE);
  595.     xfree(c->fpe_list);
  596.     FreeFontNames (c->names);
  597.     xfree(c->pattern);
  598.     xfree(c);
  599.     return TRUE;
  600. }
  601.  
  602. static      LFclosurePtr
  603. MakeListFontsClosure(client, pattern, length, max_names)
  604.     ClientPtr   client;
  605.     unsigned char *pattern;
  606.     unsigned int length;
  607.     unsigned int max_names;
  608. {
  609.     LFclosurePtr c;
  610.     int         i;
  611.     FontNamesPtr all_names;
  612.  
  613.     c = (LFclosurePtr) xalloc(sizeof(LFclosureRec));
  614.     if (!c)
  615.     return 0;
  616.     c->pattern = (char *) xalloc(length);
  617.     if (!c->pattern) {
  618.     xfree(c);
  619.     return 0;
  620.     }
  621.     c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100);
  622.     if (!c->names) {
  623.     xfree(c->pattern);
  624.     xfree(c);
  625.     return 0;
  626.     }
  627.     c->fpe_list = (FontPathElementPtr *)
  628.     xalloc(sizeof(FontPathElementPtr) * num_fpes);
  629.     if (!c->fpe_list)
  630.     {
  631.     FreeFontNames(c->names);
  632.     xfree(c->pattern);
  633.     xfree(c);
  634.     return 0;
  635.     }
  636.     bcopy(pattern, c->pattern, length);
  637.     for (i = 0; i < num_fpes; i++) {
  638.     c->fpe_list[i] = font_path_elements[i];
  639.     UseFPE(c->fpe_list[i]);
  640.     }
  641.     c->patlen = length;
  642.     c->client = client;
  643.     c->max_names = max_names;
  644.     c->current_fpe = 0;
  645.     c->num_fpes = num_fpes;
  646.     c->slept = FALSE;
  647.     return c;
  648. }
  649.  
  650. int
  651. ListFonts(client, pattern, length, max_names)
  652.     ClientPtr   client;
  653.     unsigned char *pattern;
  654.     unsigned int length;
  655.     unsigned int max_names;
  656. {
  657.     LFclosurePtr c;
  658.  
  659.     c = MakeListFontsClosure(client, pattern, length, max_names);
  660.     if (!c)
  661.     return BadAlloc;
  662.  
  663.     (void) doListFonts(client, c);
  664.     return Success;
  665. }
  666.  
  667. doListFontsWithInfo(client, c)
  668.     ClientPtr   client;
  669.     LFWIclosurePtr c;
  670. {
  671.     FontPathElementPtr fpe;
  672.     int         err = Successful;
  673.     char       *name;
  674.     int         namelen;
  675.     int         numFonts;
  676.     FontInfoRec fontInfo,
  677.                *pFontInfo;
  678.     xListFontsWithInfoReply *reply;
  679.     int         length;
  680.     xFontProp  *pFP;
  681.     int         i;
  682.     xListFontsWithInfoReply finalReply;
  683.  
  684.     if (client->clientGone)
  685.     {
  686.     if (c->current.current_fpe < c->num_fpes)
  687.      {
  688.         fpe = c->fpe_list[c->current.current_fpe];
  689.         (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
  690.     }
  691.     err = Successful;
  692.     goto bail;
  693.     }
  694.     client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo];
  695.     while (c->current.current_fpe < c->num_fpes)
  696.     {
  697.     fpe = c->fpe_list[c->current.current_fpe];
  698.     err = Successful;
  699.     if (!c->current.list_started)
  700.      {
  701.         err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
  702.         (client, fpe, c->current.pattern, c->current.patlen,
  703.          c->current.max_names, &c->current.private);
  704.         if (err == Suspended)
  705.          {
  706.         if (!c->slept)
  707.          {
  708.             ClientSleep(client, doListFontsWithInfo, c);
  709.             c->slept = TRUE;
  710.         }
  711.         return TRUE;
  712.         }
  713.         if (err == Successful)
  714.         c->current.list_started = TRUE;
  715.     }
  716.     if (err == Successful)
  717.      {
  718.         name = 0;
  719.         pFontInfo = &fontInfo;
  720.         err = (*fpe_functions[fpe->type].list_next_font_with_info)
  721.         (client, fpe, &name, &namelen, &pFontInfo,
  722.          &numFonts, c->current.private);
  723.         if (err == Suspended)
  724.          {
  725.         if (!c->slept)
  726.          {
  727.             ClientSleep(client, doListFontsWithInfo, c);
  728.             c->slept = TRUE;
  729.         }
  730.         return TRUE;
  731.         }
  732.     }
  733.     /*
  734.      * When we get an alias back, save our state and reset back to the
  735.      * start of the FPE looking for the specified name.  As soon as a real
  736.      * font is found for the alias, pop back to the old state
  737.      */
  738.     if (err == FontNameAlias)
  739.      {
  740.         if (!c->haveSaved)
  741.         c->saved = c->current;
  742.         c->current.pattern = name;
  743.         c->current.patlen = namelen;
  744.         c->current.max_names = 1;
  745.         c->current.current_fpe = 0;
  746.         c->current.private = 0;
  747.         c->current.list_started = FALSE;
  748.         c->haveSaved = TRUE;
  749.         c->savedNumFonts = numFonts;
  750.         c->savedName = (char *) pFontInfo;
  751.     }
  752.     /*
  753.      * At the end of this FPE, step to the next.  If we've finished
  754.      * processing an alias, pop state back. If we've sent enough font
  755.      * names, quit.
  756.      */
  757.     else if (err == BadFontName)
  758.      {
  759.         c->current.list_started = FALSE;
  760.         c->current.current_fpe++;
  761.         err = Successful;
  762.         if (c->haveSaved)
  763.          {
  764.         if (c->current.max_names == 0 ||
  765.             c->current.current_fpe == c->num_fpes)
  766.          {
  767.             c->haveSaved = FALSE;
  768.             c->saved.max_names -= (1 - c->current.max_names);
  769.             c->current = c->saved;
  770.         }
  771.         }
  772.         if (c->current.max_names == 0)
  773.         break;
  774.     }
  775.      else if (err == Successful)
  776.      {
  777.         length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp);
  778.         reply = c->reply;
  779.         if (c->length < length)
  780.          {
  781.         reply = (xListFontsWithInfoReply *) xrealloc(c->reply, length);
  782.         if (!reply)
  783.          {
  784.             err = AllocError;
  785.             break;
  786.         }
  787.         c->reply = reply;
  788.         c->length = length;
  789.         }
  790.         if (c->haveSaved)
  791.          {
  792.         numFonts = c->savedNumFonts;
  793.         name = c->savedName;
  794.         namelen = strlen(name);
  795.         }
  796.         reply->type = X_Reply;
  797.         reply->length = (sizeof *reply - sizeof(xGenericReply) +
  798.                  pFontInfo->nprops * sizeof(xFontProp) +
  799.                  namelen + 3) >> 2;
  800.         reply->sequenceNumber = client->sequence;
  801.         reply->nameLength = namelen;
  802.         reply->minBounds = pFontInfo->ink_minbounds;
  803.         reply->maxBounds = pFontInfo->ink_maxbounds;
  804.         reply->minCharOrByte2 = pFontInfo->firstCol;
  805.         reply->maxCharOrByte2 = pFontInfo->lastCol;
  806.         reply->defaultChar = pFontInfo->defaultCh;
  807.         reply->nFontProps = pFontInfo->nprops;
  808.         reply->drawDirection = pFontInfo->drawDirection;
  809.         reply->minByte1 = pFontInfo->firstRow;
  810.         reply->maxByte1 = pFontInfo->lastRow;
  811.         reply->allCharsExist = pFontInfo->allExist;
  812.         reply->fontAscent = pFontInfo->fontAscent;
  813.         reply->fontDescent = pFontInfo->fontDescent;
  814.         reply->nReplies = numFonts;
  815.         pFP = (xFontProp *) (reply + 1);
  816.         for (i = 0; i < pFontInfo->nprops; i++)
  817.          {
  818.         pFP->name = pFontInfo->props[i].name;
  819.         pFP->value = pFontInfo->props[i].value;
  820.         pFP++;
  821.         }
  822.         WriteSwappedDataToClient(client, length, reply);
  823.         (void) WriteToClient(client, namelen, name);
  824.         if (pFontInfo == &fontInfo)
  825.          {
  826.         xfree(fontInfo.props);
  827.         xfree(fontInfo.isStringProp);
  828.         }
  829.         --c->current.max_names;
  830.         if (c->current.max_names < 0)
  831.         break;
  832.     }
  833.     }
  834.     length = sizeof(xListFontsWithInfoReply);
  835.     bzero((char *) &finalReply, sizeof(xListFontsWithInfoReply));
  836.     finalReply.type = X_Reply;
  837.     finalReply.sequenceNumber = client->sequence;
  838.     finalReply.length = (sizeof(xListFontsWithInfoReply)
  839.              - sizeof(xGenericReply)) >> 2;
  840.     WriteSwappedDataToClient(client, length, &finalReply);
  841. bail:
  842.     if (c->slept)
  843.     ClientWakeup(client);
  844.     for (i = 0; i < c->num_fpes; i++)
  845.     FreeFPE(c->fpe_list[i], FALSE);
  846.     xfree(c->fpe_list);
  847.     xfree(c->current.pattern);
  848.     xfree(c);
  849.     return TRUE;
  850. }
  851.  
  852. int
  853. StartListFontsWithInfo(client, length, pattern, max_names)
  854.     ClientPtr   client;
  855.     int         length;
  856.     char       *pattern;
  857.     int         max_names;
  858. {
  859.     int            err;
  860.     int            i;
  861.     LFWIclosurePtr  c;
  862.  
  863.     if (!(c = (LFWIclosurePtr) xalloc(sizeof *c)))
  864.     goto badAlloc;
  865.     if (!(c->current.pattern = (char *) xalloc(length)))
  866.     {
  867.     xfree(c);
  868.     goto badAlloc;
  869.     }
  870.     c->fpe_list = (FontPathElementPtr *)
  871.     xalloc(sizeof(FontPathElementPtr) * num_fpes);
  872.     if (!c->fpe_list)
  873.     {
  874.     xfree(c->current.pattern);
  875.     xfree(c);
  876.     goto badAlloc;
  877.     }
  878.     bcopy(pattern, c->current.pattern, length);
  879.     for (i = 0; i < num_fpes; i++)
  880.     {
  881.     c->fpe_list[i] = font_path_elements[i];
  882.     UseFPE(c->fpe_list[i]);
  883.     }
  884.     c->client = client;
  885.     c->num_fpes = num_fpes;
  886.     c->reply = 0;
  887.     c->length = 0;
  888.     c->current.patlen = length;
  889.     c->current.current_fpe = 0;
  890.     c->current.max_names = max_names;
  891.     c->current.list_started = FALSE;
  892.     c->current.private = 0;
  893.     c->savedNumFonts = 0;
  894.     c->haveSaved = FALSE;
  895.     c->slept = FALSE;
  896.     doListFontsWithInfo(client, c);
  897.     return Success;
  898. badAlloc:
  899.     return BadAlloc;
  900. }
  901.  
  902. /* does the necessary magic to figure out the fpe type */
  903. static int
  904. DetermineFPEType(pathname)
  905.     char       *pathname;
  906. {
  907.     int         i;
  908.  
  909.     for (i = 0; i < num_fpe_types; i++) {
  910.     if ((*fpe_functions[i].name_check) (pathname))
  911.         return i;
  912.     }
  913.     return -1;
  914. }
  915.  
  916.  
  917. static void
  918. FreeFontPath(list, n, force)
  919.     FontPathElementPtr    *list;
  920.     Bool        force;
  921.     int         n;
  922. {
  923.     int         i;
  924.  
  925.     for (i = 0; i < n; i++) {
  926.     FreeFPE(list[i], force);
  927.     }
  928.     xfree((char *) list);
  929. }
  930.  
  931. static      FontPathElementPtr
  932. find_existing_fpe(list, num, name, len)
  933.     FontPathElementPtr *list;
  934.     int         num;
  935.     char       *name;
  936.     int         len;
  937. {
  938.     FontPathElementPtr fpe;
  939.     int         i;
  940.  
  941.     for (i = 0; i < num; i++) {
  942.     fpe = list[i];
  943.     if (fpe->name_length == len && bcmp(name, fpe->name, len) == 0)
  944.         return fpe;
  945.     }
  946.     return (FontPathElementPtr) 0;
  947. }
  948.  
  949.  
  950. static int
  951. SetFontPathElements(npaths, paths, bad)
  952.     int         npaths;
  953.     unsigned char *paths;
  954.     int        *bad;
  955. {
  956.     int         i,
  957.                 err;
  958.     int         valid_paths = 0;
  959.     int         badpath = 0;
  960.     Bool        builtinflag = FALSE;
  961.     unsigned int len;
  962.     unsigned char *cp = paths;
  963.     FontPathElementPtr fpe,
  964.                *fplist;
  965.  
  966.     fplist = (FontPathElementPtr *)
  967.     xalloc(sizeof(FontPathElementPtr) * npaths);
  968.     if (!fplist) {
  969.     *bad = 0;
  970.     return BadAlloc;
  971.     }
  972.     for (i = 0; i < npaths; i++) {
  973.     len = (unsigned int) (*cp++);
  974.  
  975.     if (len) {
  976.         /* if its already in our active list, just reset it */
  977.         /*
  978.          * note that this can miss FPE's in limbo -- may be worth catching
  979.          * them, though it'd muck up refcounting
  980.          */
  981.         fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len);
  982.         if (fpe) {
  983.         err = (*fpe_functions[fpe->type].reset_fpe) (fpe);
  984.         if (err == Successful) {
  985.             UseFPE(fpe);/* since it'll be decref'd later when freed
  986.                  * from the old list */
  987.             fplist[valid_paths++] = fpe;
  988.             cp += len;
  989.             continue;
  990.         }
  991.         /* if error or can't do it, act like its a new one */
  992.         }
  993.         fpe = (FontPathElementPtr) xalloc(sizeof(FontPathElementRec));
  994.         if (!fpe) {
  995.         err = BadAlloc;
  996.         goto bail;
  997.         }
  998.         fpe->name = (char *) xalloc(len + 1);
  999.         if (!fpe->name) {
  1000.         xfree(fpe);
  1001.         err = BadAlloc;
  1002.         goto bail;
  1003.         }
  1004.         fpe->refcount = 1;
  1005.  
  1006.         strncpy(fpe->name, (char *) cp, (int) len);
  1007.         cp += len;
  1008.         fpe->name[len] = '\0';
  1009.         fpe->name_length = len;
  1010.         fpe->type = DetermineFPEType(fpe->name);
  1011.         if (fpe->type == -1) {
  1012.         xfree(fpe->name);
  1013.         xfree(fpe);
  1014.         err = BadValue;
  1015.         goto bail;
  1016.         }
  1017.         err = (*fpe_functions[fpe->type].init_fpe) (fpe, FontFormat);
  1018.         if (err != Successful) {
  1019.         xfree(fpe->name);
  1020.         xfree(fpe);
  1021.         err = BadValue;
  1022.         goto bail;
  1023.         }
  1024.         fplist[valid_paths++] = fpe;
  1025.     }
  1026.     }
  1027.  
  1028.     FreeFontPath(font_path_elements, num_fpes, FALSE);
  1029.     font_path_elements = fplist;
  1030.     if (patternCache)
  1031.     EmptyFontPatternCache(patternCache);
  1032.     num_fpes = valid_paths;
  1033.  
  1034.     return Success;
  1035. bail:
  1036.     *bad = i;
  1037.     while (--i >= 0)
  1038.     FreeFPE(fplist[i], FALSE);
  1039.     xfree(fplist);
  1040.     return err;
  1041. }
  1042.  
  1043. /* XXX -- do we need to pass error down to each renderer? */
  1044. int
  1045. SetFontPath(client, npaths, paths, error)
  1046.     ClientPtr   client;
  1047.     int         npaths;
  1048.     unsigned char *paths;
  1049.     int        *error;
  1050. {
  1051.     int         len,
  1052.                 err = Success;
  1053.  
  1054.     if (npaths == 0) {
  1055.     if (SetDefaultFontPath(defaultFontPath) != Success)
  1056.         return BadName;
  1057.     } else {
  1058.     err = SetFontPathElements(npaths, paths, error);
  1059.     }
  1060.     return err;
  1061. }
  1062.  
  1063. SetDefaultFontPath(path)
  1064.     char       *path;
  1065. {
  1066.     unsigned char *cp,
  1067.                *pp,
  1068.                *nump,
  1069.                *newpath;
  1070.     int         num = 1,
  1071.                 len,
  1072.                 err,
  1073.                 size = 0,
  1074.                 bad;
  1075.  
  1076.     /* get enough for string, plus values -- use up commas */
  1077.     len = strlen(path) + 1;
  1078.     nump = cp = newpath = (unsigned char *) ALLOCATE_LOCAL(len);
  1079.     if (!newpath)
  1080.     return BadAlloc;
  1081.     pp = (unsigned char *) path;
  1082.     cp++;
  1083.     while (*pp) {
  1084.     if (*pp == ',') {
  1085.         *nump = (unsigned char) size;
  1086.         nump = cp++;
  1087.         pp++;
  1088.         num++;
  1089.         size = 0;
  1090.     } else {
  1091.         *cp++ = *pp++;
  1092.         size++;
  1093.     }
  1094.     }
  1095.     *nump = (unsigned char) size;
  1096.  
  1097.     err = SetFontPathElements(num, newpath, &bad);
  1098.  
  1099.     DEALLOCATE_LOCAL(newpath);
  1100.  
  1101.     return err;
  1102. }
  1103.  
  1104. unsigned char *
  1105. GetFontPath(count, length)
  1106.     int            *count;
  1107.     int            *length;
  1108. {
  1109.     int            i;
  1110.     unsigned char       *c;
  1111.     int            len;
  1112.     FontPathElementPtr    fpe;
  1113.  
  1114.     len = 0;
  1115.     for (i = 0; i < num_fpes; i++) {
  1116.     fpe = font_path_elements[i];
  1117.     len += fpe->name_length + 1;
  1118.     }
  1119.     font_path_string = (unsigned char *) xrealloc(font_path_string, len);
  1120.     if (!font_path_string)
  1121.     return NULL;
  1122.  
  1123.     c = font_path_string;
  1124.     *length = 0;
  1125.     for (i = 0; i < num_fpes; i++) {
  1126.     fpe = font_path_elements[i];
  1127.     *c = fpe->name_length;
  1128.     *length += *c++;
  1129.     bcopy(fpe->name, c, fpe->name_length);
  1130.     c += fpe->name_length;
  1131.     }
  1132.     *count = num_fpes;
  1133.     return font_path_string;
  1134. }
  1135.  
  1136. LoadGlyphs(client, pfont, nchars, item_size, data)
  1137.     ClientPtr   client;
  1138.     FontPtr     pfont;
  1139.     unsigned    nchars;
  1140.     int         item_size;
  1141.     unsigned char *data;
  1142. {
  1143.  
  1144. #ifdef NOTDEF
  1145. /* under construction */
  1146.     /* either returns Success, ClientBlocked, or some nasty error */
  1147.     return (*fpe_functions[pfont->type].load_glyphs)
  1148.     (client, pfont, nchars, item_size, data);
  1149. #endif
  1150. }
  1151.  
  1152. /* XXX -- these two funcs may want to be broken into macros */
  1153. void
  1154. UseFPE(fpe)
  1155.     FontPathElementPtr fpe;
  1156. {
  1157.     fpe->refcount++;
  1158. }
  1159.  
  1160. void
  1161. FreeFPE (fpe, force)
  1162.     FontPathElementPtr    fpe;
  1163.     Bool        force;
  1164. {
  1165.     fpe->refcount--;
  1166.     if (force || fpe->refcount == 0) {
  1167.     (*fpe_functions[fpe->type].free_fpe) (fpe);
  1168.     xfree(fpe->name);
  1169.     xfree(fpe);
  1170.     }
  1171. }
  1172.  
  1173. DeleteClientFontStuff(client)
  1174.     ClientPtr    client;
  1175. {
  1176.     int            i;
  1177.     FontPathElementPtr    fpe;
  1178.  
  1179.     for (i = 0; i < num_fpes; i++)
  1180.     {
  1181.     fpe = font_path_elements[i];
  1182.     if (fpe_functions[fpe->type].client_died)
  1183.         (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
  1184.     }
  1185. }
  1186.  
  1187. InitFonts ()
  1188. {
  1189.     patternCache = MakeFontPatternCache();
  1190.     FontFileRegisterFpeFunctions();
  1191.     fs_register_fpe_functions();
  1192. }
  1193.  
  1194. GetDefaultPointSize ()
  1195. {
  1196.     return 120;
  1197. }
  1198.  
  1199. struct resolution {
  1200.     CARD16 x_resolution B16;
  1201.     CARD16 y_resolution B16;
  1202.     CARD16 point_size B16;
  1203. };
  1204.  
  1205. struct resolution *
  1206. GetClientResolutions (num)
  1207.     int        *num;
  1208. {
  1209.     static struct resolution res;
  1210.     int         mm,
  1211.                 pix;
  1212.     ScreenPtr   pScreen;
  1213.  
  1214.     pScreen = screenInfo.screens[0];
  1215.     res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth;
  1216.     /*
  1217.      * XXX - we'll want this as long as bitmap instances are prevalent so that
  1218.      * we can match them from scalable fonts
  1219.      */
  1220.     if (res.x_resolution < 88)
  1221.     res.x_resolution = 75;
  1222.     else
  1223.     res.x_resolution = 100;
  1224.     res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight;
  1225.     if (res.y_resolution < 88)
  1226.     res.y_resolution = 75;
  1227.     else
  1228.     res.y_resolution = 100;
  1229.     res.point_size = 120;
  1230.     *num = 1;
  1231.     return &res;
  1232. }
  1233.  
  1234. /*
  1235.  * returns the type index of the new fpe
  1236.  *
  1237.  * should be called (only once!) by each type of fpe when initialized
  1238.  */
  1239.  
  1240. int
  1241. RegisterFPEFunctions(name_func, init_func, free_func, reset_func,
  1242.        open_func, close_func, list_func, start_lfwi_func, next_lfwi_func,
  1243.              wakeup_func, client_died)
  1244.     Bool        (*name_func) ();
  1245.     int         (*init_func) ();
  1246.     int         (*free_func) ();
  1247.     int         (*reset_func) ();
  1248.     int         (*open_func) ();
  1249.     int         (*close_func) ();
  1250.     int         (*list_func) ();
  1251.     int         (*start_lfwi_func) ();
  1252.     int         (*next_lfwi_func) ();
  1253.     int         (*wakeup_func) ();
  1254.     int        (*client_died) ();
  1255. {
  1256.     FPEFunctions *new;
  1257.  
  1258.     /* grow the list */
  1259.     new = (FPEFunctions *) xrealloc(fpe_functions,
  1260.                  (num_fpe_types + 1) * sizeof(FPEFunctions));
  1261.     if (!new)
  1262.     return -1;
  1263.     fpe_functions = new;
  1264.  
  1265.     fpe_functions[num_fpe_types].name_check = name_func;
  1266.     fpe_functions[num_fpe_types].open_font = open_func;
  1267.     fpe_functions[num_fpe_types].close_font = close_func;
  1268.     fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func;
  1269.     fpe_functions[num_fpe_types].list_fonts = list_func;
  1270.     fpe_functions[num_fpe_types].start_list_fonts_with_info =
  1271.     start_lfwi_func;
  1272.     fpe_functions[num_fpe_types].list_next_font_with_info =
  1273.     next_lfwi_func;
  1274.     fpe_functions[num_fpe_types].init_fpe = init_func;
  1275.     fpe_functions[num_fpe_types].free_fpe = free_func;
  1276.     fpe_functions[num_fpe_types].reset_fpe = reset_func;
  1277.     fpe_functions[num_fpe_types].client_died = client_died;
  1278.  
  1279.     return num_fpe_types++;
  1280. }
  1281.  
  1282. FreeFonts()
  1283. {
  1284.     if (patternCache) {
  1285.     FreeFontPatternCache(patternCache);
  1286.     patternCache = 0;
  1287.     }
  1288.     FreeFontPath(font_path_elements, num_fpes, TRUE);
  1289.     font_path_elements = 0;
  1290.     num_fpes = 0;
  1291.     xfree(fpe_functions);
  1292.     num_fpe_types = 0;
  1293.     fpe_functions = (FPEFunctions *) 0;
  1294. }
  1295.  
  1296. /* convenience functions for FS interface */
  1297.  
  1298. FontPtr
  1299. find_old_font(id)
  1300.     XID         id;
  1301. {
  1302.     return (FontPtr) LookupIDByType(id, RT_NONE);
  1303. }
  1304.  
  1305. Font
  1306. GetNewFontClientID()
  1307. {
  1308.     return FakeClientID(0);
  1309. }
  1310.  
  1311. int
  1312. StoreFontClientFont(pfont, id)
  1313.     FontPtr     pfont;
  1314.     Font        id;
  1315. {
  1316.     return AddResource(id, RT_NONE, (pointer) pfont);
  1317. }
  1318.  
  1319. DeleteFontClientID(id)
  1320.     Font        id;
  1321. {
  1322.     FreeResource(id, RT_NONE);
  1323. }
  1324.  
  1325.  
  1326. static int  fs_handlers_installed = 0;
  1327. static unsigned int last_server_gen;
  1328.  
  1329. init_fs_handlers(fpe, block_handler)
  1330.     FontPathElementPtr fpe;
  1331.     int         (*block_handler) ();
  1332. {
  1333.     /* if server has reset, make sure the b&w handlers are reinstalled */
  1334.     if (last_server_gen < serverGeneration) {
  1335.     last_server_gen = serverGeneration;
  1336.     fs_handlers_installed = 0;
  1337.     }
  1338.     if (fs_handlers_installed == 0) {
  1339.  
  1340. #ifdef DEBUG
  1341.     fprintf(stderr, "adding FS b & w handlers\n");
  1342. #endif
  1343.  
  1344.     if (!RegisterBlockAndWakeupHandlers(block_handler,
  1345.                         FontWakeup, (pointer) 0))
  1346.         return AllocError;
  1347.     fs_handlers_installed++;
  1348.     }
  1349.     QueueFontWakeup(fpe);
  1350.     return Successful;
  1351. }
  1352.  
  1353. remove_fs_handlers(fpe, block_handler, all)
  1354.     FontPathElementPtr fpe;
  1355.     int         (*block_handler) ();
  1356.     Bool        all;
  1357. {
  1358.     if (all) {
  1359.     /* remove the handlers if no one else is using them */
  1360.     if (--fs_handlers_installed == 0) {
  1361.  
  1362. #ifdef DEBUG
  1363.         fprintf(stderr, "removing FS b & w handlers\n");
  1364. #endif
  1365.  
  1366.         RemoveBlockAndWakeupHandlers(block_handler, FontWakeup,
  1367.                      (pointer) 0);
  1368.     }
  1369.     }
  1370.     RemoveFontWakeup(fpe);
  1371. }
  1372.  
  1373. #ifdef DEBUG
  1374. #define GLWIDTHBYTESPADDED(bits,nbytes) \
  1375.     ((nbytes) == 1 ? (((bits)+7)>>3)        /* pad to 1 byte */ \
  1376.     :(nbytes) == 2 ? ((((bits)+15)>>3)&~1)  /* pad to 2 bytes */ \
  1377.     :(nbytes) == 4 ? ((((bits)+31)>>3)&~3)  /* pad to 4 bytes */ \
  1378.     :(nbytes) == 8 ? ((((bits)+63)>>3)&~7)  /* pad to 8 bytes */ \
  1379.     : 0)
  1380.  
  1381. #define GLYPH_SIZE(ch, nbytes)          \
  1382.     GLWIDTHBYTESPADDED((ch)->metrics.rightSideBearing - \
  1383.             (ch)->metrics.leftSideBearing, (nbytes))
  1384. dump_char_ascii(cip)
  1385.     CharInfoPtr cip;
  1386. {
  1387.     int         r,
  1388.                 l;
  1389.     int         bpr;
  1390.     int         byte;
  1391.     static unsigned maskTab[] = {
  1392.     (1 << 7), (1 << 6), (1 << 5), (1 << 4),
  1393.     (1 << 3), (1 << 2), (1 << 1), (1 << 0),
  1394.     };
  1395.  
  1396.     bpr = GLYPH_SIZE(cip, 4);
  1397.     for (r = 0; r < (cip->metrics.ascent + cip->metrics.descent); r++) {
  1398.     pointer     row = (pointer) cip->bits + r * bpr;
  1399.  
  1400.     byte = 0;
  1401.     for (l = 0; l <= (cip->metrics.rightSideBearing -
  1402.               cip->metrics.leftSideBearing); l++) {
  1403.         if (maskTab[l & 7] & row[l >> 3])
  1404.         putchar('X');
  1405.         else
  1406.         putchar('.');
  1407.     }
  1408.     putchar('\n');
  1409.     }
  1410. }
  1411.  
  1412. #endif
  1413.