diff options
Diffstat (limited to 'src/fc/fserve.c')
-rw-r--r-- | src/fc/fserve.c | 2815 |
1 files changed, 2815 insertions, 0 deletions
diff --git a/src/fc/fserve.c b/src/fc/fserve.c new file mode 100644 index 0000000..95ce811 --- /dev/null +++ b/src/fc/fserve.c @@ -0,0 +1,2815 @@ +/* $Xorg: fserve.c,v 1.4 2001/02/09 02:04:02 xorgcvs Exp $ */ +/* + +Copyright 1990, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/* + * Copyright 1990 Network Computing Devices + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the names of Network Computing Devices, or Digital + * not be used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * + * NETWORK COMPUTING DEVICES, AND DIGITAL AND DISCLAIM ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES, + * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + * THIS SOFTWARE. + * + * Author: Dave Lemke, Network Computing Devices, Inc + */ +/* + * font server specific font access + */ + +#ifdef WIN32 +#define _WILLWINSOCK_ +#endif +#include <X11/X.h> +#include <X11/Xos.h> +#include "X11/Xpoll.h" +#include "FS.h" +#include "FSproto.h" +#include "fontmisc.h" +#include "fontstruct.h" +#include "fservestr.h" +#include <errno.h> +#ifdef X_NOT_STDC_ENV +extern int errno; +#define Time_t long +extern Time_t time (); +#else +#include <time.h> +#define Time_t time_t +#endif + +#ifdef NCD +#include <ncd/nvram.h> +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +#define NONZEROMETRICS(pci) ((pci)->leftSideBearing || \ + (pci)->rightSideBearing || \ + (pci)->ascent || \ + (pci)->descent || \ + (pci)->characterWidth) + + +extern FontPtr find_old_font(); + +extern int _fs_build_range(); + +static int fs_read_glyphs(); +static int fs_read_list(); +static int fs_read_list_info(); + +static int fs_font_type; +extern fd_set _fs_fd_mask; + +static void fs_block_handler(); +static int fs_wakeup(); + +static FSFpePtr awaiting_reconnect; + +void _fs_connection_died(); +static int _fs_restart_connection(); +static void _fs_try_reconnect(); +static int fs_send_query_info(); +static int fs_send_query_extents(); +static int fs_send_query_bitmaps(); +static int fs_send_close_font(); +static void fs_client_died(); +static void _fs_client_access(); +static void _fs_client_resolution(); + +char _fs_glyph_undefined; +char _fs_glyph_requested; +char _fs_glyph_zero_length; + +/* + * Font server access + * + * the basic idea for the non-blocking access is to have the function + * called multiple times until the actual data is returned, instead + * of ClientBlocked. + * + * the first call to the function will cause the request to be sent to + * the font server, and a block record to be stored in the fpe's list + * of outstanding requests. the FS block handler also sticks the + * proper set of fd's into the select mask. when data is ready to be + * read in, the FS wakup handler will be hit. this will read the + * data off the wire into the proper block record, and then signal the + * client that caused the block so that it can restart. it will then + * call the access function again, which will realize that the data has + * arrived and return it. + */ + + +/* XXX this should probably be a macro once its fully debugged */ +/* ARGSUSED */ +static void +_fs_add_req_log(conn, opcode) + FSFpePtr conn; + int opcode; +{ + +#ifdef DEBUG + conn->reqbuffer[conn->reqindex++] = opcode; + if (conn->reqindex == REQUEST_LOG_SIZE) + conn->reqindex = 0; +#endif + + conn->current_seq++; +} + +static Bool +fs_name_check(name) + char *name; +{ + /* Just make sure there is a protocol/ prefix */ + + return (name && *name != '/' && strchr(name, '/')); +} + +static void +_fs_client_resolution(conn) + FSFpePtr conn; +{ + fsSetResolutionReq srreq; + int num_res; + FontResolutionPtr res; + + res = GetClientResolutions(&num_res); + + if (num_res) { + srreq.reqType = FS_SetResolution; + srreq.num_resolutions = num_res; + srreq.length = (SIZEOF(fsSetResolutionReq) + + (num_res * SIZEOF(fsResolution)) + 3) >> 2; + + _fs_add_req_log(conn, FS_SetResolution); + if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != -1) + (void)_fs_write_pad(conn, (char *) res, + (num_res * SIZEOF(fsResolution))); + } +} + +/* + * sends the stuff that's meaningful to a newly opened or reset FS + */ +static int +fs_send_init_packets(conn) + FSFpePtr conn; +{ + fsSetResolutionReq srreq; + fsSetCataloguesReq screq; + fsListCataloguesReq lcreq; + fsListCataloguesReply lcreply; + int num_cats, + clen, + len; + char *client_cat = (char *) 0, + *cp, + *sp, + *end; + int num_res; + FontResolutionPtr res; + int err = Successful; + +#define CATALOGUE_SEP '+' + + res = GetClientResolutions(&num_res); + if (num_res) { + srreq.reqType = FS_SetResolution; + srreq.num_resolutions = num_res; + srreq.length = (SIZEOF(fsSetResolutionReq) + + (num_res * SIZEOF(fsResolution)) + 3) >> 2; + + _fs_add_req_log(conn, FS_SetResolution); + if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) == -1) + { + err = BadFontPath; + goto fail; + } + if (_fs_write_pad(conn, (char *) res, (num_res * SIZEOF(fsResolution))) == -1) + { + err = BadFontPath; + goto fail; + } + } + sp = strrchr(conn->servername, '/'); + + /* don't get tricked by a non-existant catalogue list */ + if (sp == strchr(conn->servername, '/')) { + /* + * try original name -- this might be an alternate with no catalogues + */ + sp = strrchr(conn->requestedname, '/'); + if (sp == strchr(conn->requestedname, '/')) + sp = (char *) 0; + } + if (sp) { /* turn cats into counted list */ + sp++; + /* allocate more than enough room */ + cp = client_cat = (char *) xalloc(strlen(conn->servername)); + if (!cp) { + err = BadAlloc; + goto fail; + } + num_cats = 0; + while (*sp) { + end = strchr(sp, CATALOGUE_SEP); + if (!end) + end = sp + strlen(sp); + *cp++ = len = end - sp; + num_cats++; + memmove(cp, sp, len); + sp += len; + if (*sp == CATALOGUE_SEP) + sp++; + cp += len; + } + clen = cp - client_cat; + /* our list checked out, so send it */ + screq.reqType = FS_SetCatalogues; + screq.num_catalogues = num_cats; + screq.length = (SIZEOF(fsSetCataloguesReq) + clen + 3) >> 2; + + _fs_add_req_log(conn, FS_SetCatalogues); + if (_fs_write(conn, (char *) &screq, SIZEOF(fsSetCataloguesReq)) == -1) + { + err = BadFontPath; + goto fail; + } + if (_fs_write_pad(conn, (char *) client_cat, clen) == -1) + { + err = BadFontPath; + goto fail; + } + + /* + * now sync up with the font server, to see if an error was generated + * by a bogus catalogue + */ + lcreq.reqType = FS_ListCatalogues; + lcreq.length = (SIZEOF(fsListCataloguesReq)) >> 2; + lcreq.maxNames = 0; + lcreq.nbytes = 0; + _fs_add_req_log(conn, FS_SetCatalogues); + if (_fs_write(conn, (char *) &lcreq, SIZEOF(fsListCataloguesReq)) == -1) + { + err = BadFontPath; + goto fail; + } + + /* + * next bit will either by the ListCats reply, or an error followed by + * the reply + */ + if (_fs_read(conn, (char *) &lcreply, SIZEOF(fsGenericReply)) == -1) { + err = BadFontPath; + goto fail; + } + if (lcreply.type == FS_Error && + ((fsError *) & lcreply)->major_opcode == FS_SetCatalogues) { + _fs_eat_rest_of_error(conn, (fsError *) & lcreply); + /* get ListCats response */ + (void) _fs_read(conn, (char *) &lcreply, + SIZEOF(fsListCataloguesReply)); + err = BadFontPath; + goto fail; + } + /* must be reply, swallow the rest of it */ + _fs_eat_rest_of_error(conn, (fsError *) & lcreply); + } +fail: + xfree(client_cat); + return err; +} + +/* + * close font server and remove any state associated with + * this connection - this includes any client records. + */ + +static void +fs_close_conn(conn) + FSFpePtr conn; +{ + FSClientPtr client, nclient; + + /* XXX - hack. The right fix is to remember that the font server + has gone away when we first discovered it. */ + if (conn->trans_conn) + (void) _FontTransClose (conn->trans_conn); + + if (conn->fs_fd != -1) + FD_CLR(conn->fs_fd, &_fs_fd_mask); + + for (client = conn->clients; client; client = nclient) + { + nclient = client->next; + xfree (client); + } + conn->clients = NULL; +} + +/* + * the wakeup handlers have to be set when the FPE is open, and not + * removed until it is freed, in order to handle unexpected data, like + * events + */ +/* ARGSUSED */ +static int +fs_init_fpe(fpe) + FontPathElementPtr fpe; +{ + FSFpePtr conn; + char *name; + int err; + + /* open font server */ + /* create FS specific fpe info */ + errno = 0; + + name = fpe->name; + + /* hack for old style names */ + if (*name == ':') + name++; /* skip ':' */ + + conn = _fs_open_server(name); + if (conn) { + conn->requestedname = fpe->name; /* stash this for later init use */ + fpe->private = (pointer) conn; + err = fs_send_init_packets(conn); + if (err != Successful) { + fs_close_conn(conn); + xfree(conn->servername); + xfree(conn->alts); + xfree(conn); + return err; + } + if (init_fs_handlers(fpe, fs_block_handler) != Successful) + return AllocError; + FD_SET(conn->fs_fd, &_fs_fd_mask); + conn->attemptReconnect = TRUE; + +#ifdef NCD + if (configData.ExtendedFontDiags) + printf("Connected to font server \"%s\"\n", name); +#endif + + return err; + } + +#ifdef DEBUG + fprintf(stderr, "failed to connect to FS \"%s\"\n", name); +#endif + +#ifdef NCD + if (configData.ExtendedFontDiags) + printf("Failed to connect to font server \"%s\"\n", name); +#endif + + return (errno == ENOMEM) ? AllocError : BadFontPath; +} + +static int +fs_reset_fpe(fpe) + FontPathElementPtr fpe; +{ + (void) fs_send_init_packets((FSFpePtr) fpe->private); + return Successful; +} + +/* + * this shouldn't be called till all refs to the FPE are gone + */ + +static int +fs_free_fpe(fpe) + FontPathElementPtr fpe; +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSFpePtr recon, + *prev; + prev = &awaiting_reconnect; + while (*prev) { + recon = *prev; + if (conn == recon) { + *prev = recon->next_reconnect; + break; + } + prev = &recon->next_reconnect; + } + + fs_close_conn(conn); + + remove_fs_handlers(fpe, fs_block_handler, + !XFD_ANYSET(&_fs_fd_mask) && !awaiting_reconnect); + + xfree(conn->alts); + xfree(conn->servername); + xfree(conn); + fpe->private = (pointer) 0; + +#ifdef NCD + if (configData.ExtendedFontDiags) + printf("Disconnected from font server \"%s\"\n", fpe->name); +#endif + + return Successful; +} + +static FSBlockDataPtr +fs_new_block_rec(fpe, client, type) + FontPathElementPtr fpe; + pointer client; + int type; +{ + FSBlockDataPtr blockrec, + br; + FSFpePtr fsfpe = (FSFpePtr) fpe->private; + int size; + + blockrec = (FSBlockDataPtr) xalloc(sizeof(FSBlockDataRec)); + if (!blockrec) + return (FSBlockDataPtr) 0; + switch (type) { + case FS_OPEN_FONT: + size = sizeof(FSBlockedFontRec); + break; + case FS_LOAD_GLYPHS: + size = sizeof(FSBlockedGlyphRec); + break; + case FS_LIST_FONTS: + size = sizeof(FSBlockedListRec); + break; + case FS_LIST_WITH_INFO: + size = sizeof(FSBlockedListInfoRec); + break; + default: + break; + } + blockrec->data = (pointer) xalloc(size); + if (!blockrec->data) { + xfree(blockrec); + return (FSBlockDataPtr) 0; + } + blockrec->client = client; + blockrec->sequence_number = fsfpe->current_seq; + blockrec->type = type; + blockrec->depending = 0; + blockrec->next = (FSBlockDataPtr) 0; + + /* stick it on the end of the list (since its expected last) */ + br = (FSBlockDataPtr) fsfpe->blocked_requests; + if (!br) { + fsfpe->blocked_requests = (pointer) blockrec; + } else { + while (br->next) + br = br->next; + br->next = blockrec; + } + + return blockrec; +} + +static void +_fs_remove_block_rec(conn, blockrec) + FSFpePtr conn; + FSBlockDataPtr blockrec; +{ + FSBlockDataPtr br, + last; + + last = (FSBlockDataPtr) 0; + br = (FSBlockDataPtr) conn->blocked_requests; + while (br) { + if (br == blockrec) { + if (last) + last->next = br->next; + else + conn->blocked_requests = (pointer) br->next; + if (br->type == FS_LOAD_GLYPHS) + { + FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)br->data; + if (bglyph->num_expected_ranges) + xfree(bglyph->expected_ranges); + } + xfree(br->data); + xfree(br); + return; + } + last = br; + br = br->next; + } +} + +static void +signal_clients_depending(clients_depending) +FSClientsDependingPtr *clients_depending; +{ + FSClientsDependingPtr p = *clients_depending, p2; + *clients_depending = (FSClientsDependingPtr)0; + + while (p != (FSClientsDependingPtr)0) + { + p2 = p; + ClientSignal(p->client); + p = p->next; + xfree(p2); + } +} + +static int +add_clients_depending(clients_depending, client) +FSClientsDependingPtr *clients_depending; +pointer client; +{ + while (*clients_depending != (FSClientsDependingPtr)0) + { + if ((*clients_depending)->client == client) return Suspended; + clients_depending = &(*clients_depending)->next; + } + *clients_depending = (FSClientsDependingPtr)xalloc( + sizeof(FSClientsDependingRec)); + if (!*clients_depending) + return BadAlloc; + + (*clients_depending)->client = client; + (*clients_depending)->next = 0; + return Suspended; +} + +static void +clean_aborted_blockrec(blockrec) + FSBlockDataPtr blockrec; +{ + + switch(blockrec->type) + { + case FS_LOAD_GLYPHS: + { + FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data; + FontPtr pfont = bglyph->pfont; + int num_expected_ranges = bglyph->num_expected_ranges; + fsRange *expected_ranges = bglyph->expected_ranges; + _fs_clean_aborted_loadglyphs(pfont, + num_expected_ranges, + expected_ranges); + signal_clients_depending(&bglyph->clients_depending); + break; + } + case FS_OPEN_FONT: + { + FSBlockedFontPtr bfont = (FSBlockedFontPtr)blockrec->data; + signal_clients_depending(&bfont->clients_depending); + break; + } + default: + break; + } +} + +static void +fs_abort_blockrec(conn, blockrec) + FSFpePtr conn; + FSBlockDataPtr blockrec; +{ + clean_aborted_blockrec(blockrec); + _fs_remove_block_rec(conn, blockrec); +} + + +static void +fs_free_font(bfont) + FSBlockedFontPtr bfont; +{ + FontPtr pfont; + FSFontDataRec *fsd; + + pfont = bfont->pfont; + fsd = (FSFontDataRec *) pfont->fpePrivate; + + /* xfree better be able to handle NULL */ + (*pfont->unload_font)(pfont); + DeleteFontClientID(fsd->fontid); + xfree(fsd->name); + xfree(pfont->info.isStringProp); + xfree(pfont->info.props); + + xfree(pfont); + xfree(fsd); + + bfont->pfont = (FontPtr) 0; +} + +static void +_fs_cleanup_font(bfont) + FSBlockedFontPtr bfont; +{ + FSFontDataRec *fsd; + + if (bfont->pfont) + { + fsd = (FSFontDataRec *) bfont->pfont->fpePrivate; + + /* make sure the FS knows we choked on it */ + fs_send_close_font(fsd->fpe, bfont->fontid); + + fs_free_font(bfont); + } + bfont->errcode = AllocError; +} + + +static int +fs_read_open_font(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsOpenBitmapFontReply rep; + FSBlockDataPtr blockOrig; + FSBlockedFontPtr origBfont; + + /* pull out the OpenFont reply */ + memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply)); + + if (rep.type == FS_Error) { + _fs_eat_rest_of_error(conn, (fsError *) & rep); + return BadFontName; + } else { /* get rest of reply */ + if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply), + SIZEOF(fsOpenBitmapFontReply) - SIZEOF(fsGenericReply)) == -1) { + /* If we're not reopening a font, we'll allocate the + structures again after connection is reestablished. */ + if (!(bfont->flags & FontReopen)) fs_free_font(bfont); + return StillWorking; + } + } + + /* If we're not reopening a font and FS detected a duplicate font + open request, replace our reference to the new font with a + reference to an existing font (possibly one not finished + opening). If this is a reopen, keep the new font reference... + it's got the metrics and extents we read when the font was opened + before. This also gives us the freedom to easily close the font + if we we decide (in fs_read_query_info()) that we don't like what + we got. */ + + if (rep.otherid && !(bfont->flags & FontReopen)) { + (void) fs_send_close_font(fpe, bfont->fontid); + + /* Find old font if we're completely done getting it from server. */ + fs_free_font(bfont); + bfont->pfont = find_old_font(rep.otherid); + bfont->fontid = rep.otherid; + bfont->state = FS_DONE_REPLY; + /* + * look for a blocked request to open the same font + */ + for (blockOrig = (FSBlockDataPtr) conn->blocked_requests; + blockOrig; + blockOrig = blockOrig->next) { + if (blockOrig != blockrec && blockOrig->type == FS_OPEN_FONT) { + origBfont = (FSBlockedFontPtr) blockOrig->data; + if (origBfont->fontid == rep.otherid) { + blockrec->depending = blockOrig->depending; + blockOrig->depending = blockrec; + bfont->state = FS_DEPENDING; + bfont->pfont = origBfont->pfont; + break; + } + } + } + if (bfont->pfont == NULL) + { + /* XXX - something nasty happened */ + return BadFontName; + } + return AccessDone; + } + + bfont->pfont->info.cachable = rep.cachable != 0; + bfont->state = FS_INFO_REPLY; + /* ask for the next stage */ + (void) fs_send_query_info(fpe, blockrec); + return StillWorking; +} + + +static int +fs_read_query_info(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsQueryXInfoReply rep; + fsPropInfo pi; + fsPropOffset *po; + pointer pd; + unsigned long prop_len; + FSBlockedFontRec newbfont, *oldbfont; + FontRec newpfont, *oldpfont; + int err; + + /* If this is a reopen, accumulate the query info into a dummy + font and compare to our original data. */ + if (bfont->flags & FontReopen) + { + newbfont = *(oldbfont = bfont); + bfont = &newbfont; + newpfont = *(oldpfont = oldbfont->pfont); + newpfont.info.isStringProp = NULL; + newpfont.info.props = NULL; + newbfont.pfont = &newpfont; + err = StillWorking; + } + + /* pull out the QueryXInfo reply */ + memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply)); + if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply), + SIZEOF(fsQueryXInfoReply) - SIZEOF(fsGenericReply)) == -1) { + if (bfont->flags & FontReopen) goto bail; + fs_free_font(bfont); + return StillWorking; + } + /* move the data over */ + fsUnpack_XFontInfoHeader(&rep, &bfont->pfont->info); + _fs_init_fontinfo(conn, &bfont->pfont->info); + + if (bfont->pfont->info.terminalFont) + { + bfont->format = + (bfont->format & ~ (BitmapFormatImageRectMask)) | + BitmapFormatImageRectMax; + } + + if (_fs_read(conn, (char *) &pi, SIZEOF(fsPropInfo)) == -1) { + if (bfont->flags & FontReopen) goto bail; + fs_free_font(bfont); + return StillWorking; + } + prop_len = pi.num_offsets * SIZEOF(fsPropOffset); + po = (fsPropOffset *) xalloc(prop_len); + pd = (pointer) xalloc(pi.data_len); + if (!po || !pd) { + xfree(pd); + xfree(po); + /* clear the wire */ + (void) _fs_drain_bytes(conn, prop_len + pi.data_len); + /* clean up the font */ + if (bfont->flags & FontReopen) { err = AllocError ; goto bail; } + (void) _fs_cleanup_font(bfont); + return AllocError; + } + if (_fs_read_pad(conn, (char *) po, prop_len) == -1 || + _fs_read_pad(conn, (char *) pd, pi.data_len) == -1) { + xfree(pd); + xfree(po); + if (bfont->flags & FontReopen) goto bail; + fs_free_font(bfont); + return StillWorking; + } + if (_fs_convert_props(&pi, po, pd, &bfont->pfont->info) == -1) + { + xfree(po); + xfree(pd); + if (bfont->flags & FontReopen) { err = AllocError ; goto bail; } + (void) _fs_cleanup_font(bfont); + return AllocError; + } + xfree(po); + xfree(pd); + + if (bfont->flags & FontReopen) + { + int i; + + err = BadFontName; + + /* We're reopening a font that we lost because of a downed + connection. In the interest of avoiding corruption from + opening a different font than the old one (we already have + its metrics, extents, and probably some of its glyphs), + verify that the metrics and properties all match. */ + + if (newpfont.info.firstCol != oldpfont->info.firstCol || + newpfont.info.lastCol != oldpfont->info.lastCol || + newpfont.info.firstRow != oldpfont->info.firstRow || + newpfont.info.lastRow != oldpfont->info.lastRow || + newpfont.info.defaultCh != oldpfont->info.defaultCh || + newpfont.info.noOverlap != oldpfont->info.noOverlap || + newpfont.info.terminalFont != oldpfont->info.terminalFont || + newpfont.info.constantMetrics != oldpfont->info.constantMetrics || + newpfont.info.constantWidth != oldpfont->info.constantWidth || + newpfont.info.inkInside != oldpfont->info.inkInside || + newpfont.info.inkMetrics != oldpfont->info.inkMetrics || + newpfont.info.allExist != oldpfont->info.allExist || + newpfont.info.drawDirection != oldpfont->info.drawDirection || + newpfont.info.cachable != oldpfont->info.cachable || + newpfont.info.anamorphic != oldpfont->info.anamorphic || + newpfont.info.maxOverlap != oldpfont->info.maxOverlap || + newpfont.info.fontAscent != oldpfont->info.fontAscent || + newpfont.info.fontDescent != oldpfont->info.fontDescent || + newpfont.info.nprops != oldpfont->info.nprops) + goto bail; + +#define MATCH(xci1, xci2) \ + (((xci1).leftSideBearing == (xci2).leftSideBearing) && \ + ((xci1).rightSideBearing == (xci2).rightSideBearing) && \ + ((xci1).characterWidth == (xci2).characterWidth) && \ + ((xci1).ascent == (xci2).ascent) && \ + ((xci1).descent == (xci2).descent) && \ + ((xci1).attributes == (xci2).attributes)) + + if (!MATCH(newpfont.info.maxbounds, oldpfont->info.maxbounds) || + !MATCH(newpfont.info.minbounds, oldpfont->info.minbounds) || + !MATCH(newpfont.info.ink_maxbounds, oldpfont->info.ink_maxbounds) || + !MATCH(newpfont.info.ink_minbounds, oldpfont->info.ink_minbounds)) + goto bail; + +#undef MATCH + + for (i = 0; i < newpfont.info.nprops; i++) + if (newpfont.info.isStringProp[i] != + oldpfont->info.isStringProp[i] || + newpfont.info.props[i].name != + oldpfont->info.props[i].name || + newpfont.info.props[i].value != + oldpfont->info.props[i].value) + goto bail; + + err = Successful; + bail: + if (err != Successful && err != StillWorking) + { + /* Failure. Close the font. */ + fs_send_close_font(((FSFontDataPtr)oldpfont->fpePrivate)->fpe, + bfont->fontid); + ((FSFontDataPtr)oldpfont->fpePrivate)->generation = -1; + } + xfree(newpfont.info.isStringProp); + xfree(newpfont.info.props); + + if (err == Successful) oldbfont->state = FS_DONE_REPLY; + return err; + } + + if (glyphCachingMode == CACHING_OFF || + glyphCachingMode == CACHE_16_BIT_GLYPHS && !bfont->pfont->info.lastRow) + bfont->flags |= FontLoadAll; + + bfont->state = FS_EXTENT_REPLY; + + fs_send_query_extents(fpe, blockrec); + return StillWorking; +} + +static int +fs_read_extent_info(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + FSFontDataPtr fsd = (FSFontDataPtr) bfont->pfont->fpePrivate; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsQueryXExtents16Reply rep; + int i; + int numInfos; + Bool haveInk = FALSE; /* need separate ink metrics? */ + CharInfoPtr ci, + pCI; + FSFontPtr fsfont = (FSFontPtr) bfont->pfont->fontPrivate; + fsXCharInfo *fsci; + fsXCharInfo fscilocal; + pointer fscip; + + /* read the QueryXExtents reply */ + memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply)); + if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply), + SIZEOF(fsQueryXExtents16Reply) - SIZEOF(fsGenericReply)) == -1) { + fs_free_font(bfont); + return StillWorking; + } + /* move the data over */ + /* need separate inkMetrics for fixed font server protocol version */ + numInfos = rep.num_extents; + if (bfont->pfont->info.terminalFont && conn->fsMajorVersion > 1) + { + numInfos *= 2; + haveInk = TRUE; + } + ci = pCI = (CharInfoPtr) xalloc(sizeof(CharInfoRec) * numInfos); +/* XXX this could be done with an ALLOCATE_LOCAL */ + fsci = (fsXCharInfo *) xalloc(SIZEOF(fsXCharInfo) * rep.num_extents); + if (!pCI || !fsci) { + xfree(pCI); + xfree(fsci); + /* clear the unusable data */ + _fs_drain_bytes(conn, SIZEOF(fsXCharInfo) * rep.num_extents); + _fs_cleanup_font(bfont); + return AllocError; + } + fsfont->encoding = pCI; + if (haveInk) + fsfont->inkMetrics = pCI + rep.num_extents; + else + fsfont->inkMetrics = pCI; + + if (_fs_read_pad(conn, (char *) fsci, + SIZEOF(fsXCharInfo) * rep.num_extents) == -1) { + fs_free_font(bfont); + xfree(fsci); + return StillWorking; + } + fsd->glyphs_to_get = 0; + fscip = (pointer) fsci; + ci = fsfont->inkMetrics; + for (i = 0; i < rep.num_extents; i++) { + memcpy(&fscilocal, fscip, SIZEOF(fsXCharInfo)); /* align it */ + _fs_convert_char_info(&fscilocal, &ci->metrics); + fscip += SIZEOF(fsXCharInfo); + /* Initialize the bits field for later glyph-caching use */ + if (NONZEROMETRICS(&ci->metrics)) + { + if (!haveInk && + (ci->metrics.leftSideBearing == ci->metrics.rightSideBearing || + ci->metrics.ascent == -ci->metrics.descent)) + pCI[i].bits = &_fs_glyph_zero_length; + else + { + pCI[i].bits = &_fs_glyph_undefined; + fsd->glyphs_to_get++; + } + } + else + pCI[i].bits = (char *)0; + ci++; + } + + xfree(fsci); + + /* build bitmap metrics, ImageRectMax style */ + if (haveInk) + { + FontInfoRec *fi = &bfont->pfont->info; + CharInfoPtr ii; + + ci = fsfont->encoding; + ii = fsfont->inkMetrics; + for (i = 0; i < rep.num_extents; i++, ci++, ii++) + { + if (NONZEROMETRICS(&ii->metrics)) + { + ci->metrics.leftSideBearing = FONT_MIN_LEFT(fi); + ci->metrics.rightSideBearing = FONT_MAX_RIGHT(fi); + ci->metrics.ascent = FONT_MAX_ASCENT(fi); + ci->metrics.descent = FONT_MAX_DESCENT(fi); + ci->metrics.characterWidth = FONT_MAX_WIDTH(fi); + ci->metrics.attributes = ii->metrics.attributes; + } + else + { + ci->metrics = ii->metrics; + } + } + } + { + unsigned int r, c, numCols, firstCol; + + firstCol = bfont->pfont->info.firstCol; + numCols = bfont->pfont->info.lastCol - firstCol + 1; + c = bfont->pfont->info.defaultCh; + fsfont->pDefault = 0; + if (bfont->pfont->info.lastRow) + { + r = c >> 8; + r -= bfont->pfont->info.firstRow; + c &= 0xff; + c -= firstCol; + if (r < bfont->pfont->info.lastRow-bfont->pfont->info.firstRow+1 && + c < numCols) + fsfont->pDefault = &pCI[r * numCols + c]; + } + else + { + c -= firstCol; + if (c < numCols) + fsfont->pDefault = &pCI[c]; + } + } + bfont->state = FS_GLYPHS_REPLY; + + if (bfont->flags & FontLoadBitmaps) { + fs_send_query_bitmaps(fpe, blockrec); + return StillWorking; + } + return Successful; +} + +/* + * XXX should probably continue to read here if we can, but must be sure + * it's our packet waiting, rather than another interspersed + */ +static int +fs_do_open_font(fpe, blockrec, readheader) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; + Bool readheader; +{ + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + FSFpePtr conn = (FSFpePtr) fpe->private; + int err; + + switch (bfont->state) { + case FS_OPEN_REPLY: + if (readheader) { + /* get the next header */ + if (_fs_read(conn, (char *) &blockrec->header, + SIZEOF(fsGenericReply)) == -1) { + fs_free_font(bfont); + err = StillWorking; + break; + } + } + bfont->errcode = fs_read_open_font(fpe, blockrec); + if (bfont->errcode != StillWorking) { /* already loaded, or error */ + /* if font's already loaded, massage error code */ + switch (bfont->state) { + case FS_DONE_REPLY: + bfont->errcode = Successful; + break; + case FS_DEPENDING: + bfont->errcode = StillWorking; + break; + } + err = bfont->errcode; + break; + } + /* if more data to read or Sync, fall thru, else return */ + if (!(bfont->flags & FontOpenSync)) { + err = bfont->errcode; + break; + } else { + if (_fs_read(conn, (char *) &blockrec->header, + SIZEOF(fsGenericReply)) == -1) { + fs_free_font(bfont); + err = StillWorking; + break; + } + } + /* fall through */ + case FS_INFO_REPLY: + bfont->errcode = fs_read_query_info(fpe, blockrec); + if (bfont->errcode != StillWorking) { + err = bfont->errcode; + break; + } + if (!(bfont->flags & FontOpenSync)) { + err = bfont->errcode; + break; + /* if more data to read, fall thru, else return */ + } else { + if (_fs_read(conn, (char *) &blockrec->header, + SIZEOF(fsGenericReply))) { + fs_free_font(bfont); + err = StillWorking; + break; + } + } + /* fall through */ + case FS_EXTENT_REPLY: + bfont->errcode = fs_read_extent_info(fpe, blockrec); + if (bfont->errcode != StillWorking) { + err = bfont->errcode; + break; + } + if (!(bfont->flags & FontOpenSync)) { + err = bfont->errcode; + break; + } else if (bfont->flags & FontLoadBitmaps) { + if (_fs_read(conn, (char *) &blockrec->header, + SIZEOF(fsGenericReply))) { + fs_free_font(bfont); + err = StillWorking; + break; + } + } + /* fall through */ + case FS_GLYPHS_REPLY: + if (bfont->flags & FontLoadBitmaps) { + bfont->errcode = fs_read_glyphs(fpe, blockrec); + } + err = bfont->errcode; + break; + case FS_DEPENDING: /* can't happen */ + err = bfont->errcode; + default: + err = bfont->errcode; + break; + } + if (err != StillWorking) { + bfont->state = FS_DONE_REPLY; /* for _fs_load_glyphs() */ + while (blockrec = blockrec->depending) { + bfont = (FSBlockedFontPtr) blockrec->data; + bfont->errcode = err; + bfont->state = FS_DONE_REPLY; /* for _fs_load_glyphs() */ + } + } + return err; +} + +/* ARGSUSED */ +static void +fs_block_handler(data, wt, LastSelectMask) + pointer data; + struct timeval **wt; + fd_set* LastSelectMask; +{ + static struct timeval recon_timeout; + Time_t now, + soonest; + FSFpePtr recon; + + XFD_ORSET(LastSelectMask, LastSelectMask, &_fs_fd_mask); + if (recon = awaiting_reconnect) { + now = time((Time_t *) 0); + soonest = recon->time_to_try; + while (recon = recon->next_reconnect) { + if (recon->time_to_try < soonest) + soonest = recon->time_to_try; + } + if (soonest < now) + soonest = now; + soonest = soonest - now; + recon_timeout.tv_sec = soonest; + recon_timeout.tv_usec = 0; + if (*wt == (struct timeval *) 0) { + *wt = &recon_timeout; + } else if ((*wt)->tv_sec > soonest) { + **wt = recon_timeout; + } + } +} + +static void +fs_handle_unexpected(conn, rep) + FSFpePtr conn; + fsGenericReply *rep; +{ + if (rep->type == FS_Event && rep->data1 == KeepAlive) { + fsNoopReq req; + + /* ping it back */ + req.reqType = FS_Noop; + req.length = SIZEOF(fsNoopReq) >> 2; + _fs_add_req_log(conn, FS_Noop); + _fs_write(conn, (char *) &req, SIZEOF(fsNoopReq)); + } + /* this should suck up unexpected replies and events */ + _fs_eat_rest_of_error(conn, (fsError *) rep); +} + +static int +fs_wakeup(fpe, LastSelectMask) + FontPathElementPtr fpe; + fd_set* LastSelectMask; +{ + FSBlockDataPtr blockrec, + br; + FSFpePtr conn = (FSFpePtr) fpe->private; + int err; + fsGenericReply rep; + + /* see if there's any data to be read */ + + /* + * Don't continue if the fd is -1 (which will be true when the + * font server terminates + */ + if (conn->fs_fd == -1) + return FALSE; + + if (FD_ISSET(conn->fs_fd, LastSelectMask)) { + +#ifdef NOTDEF /* bogus - doesn't deal with EOF very well, + * now does it ... */ + /* + * make sure it isn't spurious - mouse events seem to trigger extra + * problems + */ + if (_fs_data_ready(conn) <= 0) { + return FALSE; + } +#endif + + /* get the header */ + if (_fs_read(conn, (char *) &rep, SIZEOF(fsGenericReply)) == -1) + return FALSE; + + /* find the matching block record */ + + for (br = (FSBlockDataPtr) conn->blocked_requests; br; br = br->next) { + if ((CARD16)(br->sequence_number & 0xffff) == + (CARD16)(rep.sequenceNumber - 1)) + break; + } + if (!br) { + fs_handle_unexpected(conn, &rep); + return FALSE; + } + blockrec = br; + + memcpy(&blockrec->header, &rep, SIZEOF(fsGenericReply)); + + /* go read it, and if we're done, wake up the appropriate client */ + switch (blockrec->type) { + case FS_OPEN_FONT: + err = fs_do_open_font(fpe, blockrec, FALSE); + break; + case FS_LOAD_GLYPHS: + err = fs_read_glyphs(fpe, blockrec); + break; + case FS_LIST_FONTS: + err = fs_read_list(fpe, blockrec); + break; + case FS_LIST_WITH_INFO: + err = fs_read_list_info(fpe, blockrec); + break; + default: + break; + } + + if (err != StillWorking) { + while (blockrec) { + ClientSignal(blockrec->client); + blockrec = blockrec->depending; + } + } + /* + * Xx we could loop here and eat any additional replies, but it should + * feel more responsive for other clients if we come back later + */ + } else if (awaiting_reconnect) { + _fs_try_reconnect(); + } + return FALSE; +} + +/* + * Reconnection code + */ + +void +_fs_connection_died(conn) + FSFpePtr conn; +{ + if (!conn->attemptReconnect) + return; + conn->attemptReconnect = FALSE; + fs_close_conn(conn); + conn->time_to_try = time((Time_t *) 0) + FS_RECONNECT_WAIT; + conn->reconnect_delay = FS_RECONNECT_WAIT; + conn->fs_fd = -1; + conn->trans_conn = NULL; + conn->next_reconnect = awaiting_reconnect; + awaiting_reconnect = conn; +} + +static int +_fs_restart_connection(conn) + FSFpePtr conn; +{ + FSBlockDataPtr block; + + conn->current_seq = 0; + FD_SET(conn->fs_fd, &_fs_fd_mask); + if (!fs_send_init_packets(conn)) + return FALSE; + while (block = (FSBlockDataPtr) conn->blocked_requests) { + ClientSignal(block->client); + fs_abort_blockrec(conn, block); + } + return TRUE; +} + +static void +_fs_try_reconnect() +{ + FSFpePtr conn, + *prev; + Time_t now; + + prev = &awaiting_reconnect; + now = time((Time_t *) 0); + while (conn = *prev) { + if (now - conn->time_to_try > 0) { + if (_fs_reopen_server(conn) && _fs_restart_connection(conn)) { + conn->attemptReconnect = TRUE; + *prev = conn->next_reconnect; + if (prev == &awaiting_reconnect) continue; + } else { + if (conn->reconnect_delay < FS_MAX_RECONNECT_WAIT) + conn->reconnect_delay *= 2; + now = time((Time_t *) 0); + conn->time_to_try = now + conn->reconnect_delay; + } + } + prev = &conn->next_reconnect; + } +} + +/* + * sends the actual request out + */ +/* ARGSUSED */ +static int +fs_send_open_font(client, fpe, flags, name, namelen, format, fmask, id, ppfont) + pointer client; + FontPathElementPtr fpe; + Mask flags; + char *name; + int namelen; + fsBitmapFormat format; + fsBitmapFormatMask fmask; + XID id; + FontPtr *ppfont; +{ + FontPtr newfont; + FSBlockDataPtr blockrec = NULL; + FSBlockedFontPtr blockedfont; + FSFontDataPtr fsd; + FSFontPtr fsfont; + FSFpePtr conn; + fsOpenBitmapFontReq openreq; + int err = Suspended; + XID newid; + unsigned char buf[1024]; + char *fontname; + + if (flags & FontReopen) + { + Atom nameatom, fn = None; + int i; + + newfont = *ppfont; + fsd = (FSFontDataPtr)newfont->fpePrivate; + fsfont = (FSFontPtr)newfont->fontPrivate; + fpe = newfont->fpe; + format = fsd->format; + fmask = fsd->fmask; + newid = fsd->fontid; + /* This is an attempt to reopen a font. Did the font have a + NAME property? */ + if ((nameatom = MakeAtom("FONT", 4, 0)) != None) + { + for (i = 0; i < newfont->info.nprops; i++) + if (newfont->info.props[i].name == nameatom && + newfont->info.isStringProp[i]) + { + fn = newfont->info.props[i].value; + break; + } + } + if (fn == None || !(name = NameForAtom(fn))) + { + name = fsd->name; + namelen = fsd->namelen; + } + else + namelen = strlen(name); + } + + conn = (FSFpePtr) fpe->private; + if (namelen > sizeof (buf) - 1) + return BadFontName; + _fs_client_access (conn, client, (flags & FontOpenSync) != 0); + _fs_client_resolution(conn); + + + if (!(flags & FontReopen)) + { + + newid = GetNewFontClientID(); + + /* make the font */ + newfont = (FontPtr) xalloc(sizeof(FontRec)); + + /* and the FS data */ + fsd = (FSFontDataPtr) xalloc(sizeof(FSFontDataRec)); + + fsfont = (FSFontPtr) xalloc(sizeof(FSFontRec)); + + fontname = (char *)xalloc(namelen); + + if (!newfont || !fsd || !fsfont || !fontname) { +lowmem: + if (!(flags & FontReopen)) + { + xfree((char *) newfont); + xfree((char *) fsd); + xfree((char *) fsfont); + xfree((char *) fontname); + } + if (blockrec) fs_abort_blockrec(conn, blockrec); + return AllocError; + } + bzero((char *) newfont, sizeof(FontRec)); + bzero((char *) fsfont, sizeof(FSFontRec)); + bzero((char *) fsd, sizeof(FSFontDataRec)); + } + + /* make a new block record, and add it to the end of the list */ + blockrec = fs_new_block_rec(fpe, client, FS_OPEN_FONT); + if (!blockrec) { + goto lowmem; + } + + if (!(flags & FontReopen)) + { + int bit, byte, scan, glyph; + + newfont->refcnt = 0; + newfont->maxPrivate = -1; + newfont->devPrivates = (pointer *) 0; + newfont->format = format; + + /* These font components will be needed in packGlyphs */ + CheckFSFormat(format, BitmapFormatMaskBit | + BitmapFormatMaskByte | + BitmapFormatMaskScanLineUnit | + BitmapFormatMaskScanLinePad, + &bit, + &byte, + &scan, + &glyph, + NULL); + newfont->bit = bit; + newfont->byte = byte; + newfont->scan = scan; + newfont->glyph = glyph; + + newfont->fpe = fpe; + newfont->fpePrivate = (pointer) fsd; + newfont->fontPrivate = (pointer) fsfont; + _fs_init_font(newfont); + + fsd->fpe = fpe; + fsd->name = fontname; + fsd->namelen = namelen; + memcpy(fontname, name, namelen); + fsd->format = format; + fsd->fmask = fmask; + } + fsd->fontid = newid; + fsd->generation = conn->generation; + + blockedfont = (FSBlockedFontPtr) blockrec->data; + blockedfont->fontid = newid; + blockedfont->pfont = newfont; + blockedfont->state = FS_OPEN_REPLY; + blockedfont->flags = flags; + blockedfont->format = format; + blockedfont->clients_depending = (FSClientsDependingPtr)0; + + /* save the ID */ + if (!StoreFontClientFont(blockedfont->pfont, blockedfont->fontid)) { + goto lowmem; + } + /* do an FS_OpenFont, FS_QueryXInfo and FS_QueryXExtents */ + buf[0] = (unsigned char) namelen; + memcpy(&buf[1], name, namelen); + namelen++; + openreq.reqType = FS_OpenBitmapFont; + openreq.fid = newid; + openreq.format_hint = format; + openreq.format_mask = fmask; + openreq.length = (SIZEOF(fsOpenBitmapFontReq) + namelen + 3) >> 2; + + _fs_add_req_log(conn, FS_OpenBitmapFont); + _fs_write(conn, (char *) &openreq, SIZEOF(fsOpenBitmapFontReq)); + _fs_write_pad(conn, (char *) buf, namelen); + +#ifdef NCD + if (configData.ExtendedFontDiags) { + memcpy(buf, name, MIN(256, namelen)); + buf[MIN(256, namelen)] = '\0'; + printf("Requesting font \"%s\" from font server \"%s\"\n", + buf, fpe->name); + } +#endif + + if (flags & FontOpenSync) { + err = fs_do_open_font(fpe, blockrec, TRUE); + if (blockedfont->errcode == Successful) { + *ppfont = blockedfont->pfont; + } else { + _fs_cleanup_font(blockedfont); + } + _fs_remove_block_rec(conn, blockrec); + } + return err; +} + +static int +fs_send_query_info(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedFontPtr bfont; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsQueryXInfoReq inforeq; + + bfont = (FSBlockedFontPtr) blockrec->data; + + inforeq.reqType = FS_QueryXInfo; + inforeq.id = bfont->fontid; + inforeq.length = SIZEOF(fsQueryXInfoReq) >> 2; + + blockrec->sequence_number = conn->current_seq; + _fs_add_req_log(conn, FS_QueryXInfo); + _fs_write(conn, (char *) &inforeq, SIZEOF(fsQueryXInfoReq)); + + return Successful; +} + +static int +fs_send_query_extents(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedFontPtr bfont; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsQueryXExtents16Req extreq; + + bfont = (FSBlockedFontPtr) blockrec->data; + + extreq.reqType = FS_QueryXExtents16; + extreq.range = fsTrue; + extreq.fid = bfont->fontid; + extreq.num_ranges = 0; + extreq.length = SIZEOF(fsQueryXExtents16Req) >> 2; + + blockrec->sequence_number = conn->current_seq; + _fs_add_req_log(conn, FS_QueryXExtents16); + _fs_write(conn, (char *) &extreq, SIZEOF(fsQueryXExtents16Req)); + + return Successful; +} + +static int +fs_send_query_bitmaps(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedFontPtr bfont; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsQueryXBitmaps16Req bitreq; + + + bfont = (FSBlockedFontPtr) blockrec->data; + + /* send the request */ + bitreq.reqType = FS_QueryXBitmaps16; + bitreq.fid = bfont->fontid; + bitreq.format = bfont->format; + bitreq.range = TRUE; + bitreq.length = SIZEOF(fsQueryXBitmaps16Req) >> 2; + bitreq.num_ranges = 0; + + blockrec->sequence_number = conn->current_seq; + _fs_add_req_log(conn, FS_QueryXBitmaps16); + _fs_write(conn, (char *) &bitreq, SIZEOF(fsQueryXBitmaps16Req)); + + return Successful; +} + +/* ARGSUSED */ +static int +fs_open_font(client, fpe, flags, name, namelen, format, fmask, id, ppfont, + alias, non_cachable_font) + pointer client; + FontPathElementPtr fpe; + Mask flags; + char *name; + fsBitmapFormat format; + fsBitmapFormatMask fmask; + int namelen; + XID id; + FontPtr *ppfont; + char **alias; + FontPtr non_cachable_font; /* Not used in this FPE */ +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockDataPtr blockrec; + FSBlockedFontPtr blockedfont; + int err; + + /* libfont interface expects ImageRectMin glyphs */ + format = format & ~BitmapFormatImageRectMask | BitmapFormatImageRectMin; + + *alias = (char *) 0; + /* XX if we find the blockrec for the font */ + blockrec = (FSBlockDataPtr) conn->blocked_requests; + while (blockrec != (FSBlockDataPtr) 0) { + if (blockrec->type == FS_OPEN_FONT && + blockrec->client == client) { + blockedfont = (FSBlockedFontPtr) blockrec->data; + err = blockedfont->errcode; + if (err == Successful) { + *ppfont = blockedfont->pfont; + } else { + _fs_cleanup_font(blockedfont); + } + /* cleanup */ + _fs_remove_block_rec(conn, blockrec); + return err; + } + blockrec = blockrec->next; + } + return fs_send_open_font(client, fpe, flags, name, namelen, format, fmask, + id, ppfont); +} + +/* ARGSUSED */ +static int +fs_send_close_font(fpe, id) + FontPathElementPtr fpe; + Font id; +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + fsCloseReq req; + + /* tell the font server to close the font */ + req.reqType = FS_CloseFont; + req.length = SIZEOF(fsCloseReq) >> 2; + req.id = id; + _fs_add_req_log(conn, FS_CloseFont); + _fs_write(conn, (char *) &req, SIZEOF(fsCloseReq)); + + return Successful; +} + +/* ARGSUSED */ +static int +fs_close_font(fpe, pfont) + FontPathElementPtr fpe; + FontPtr pfont; +{ + FSFontDataPtr fsd = (FSFontDataPtr) pfont->fpePrivate; + FSFpePtr conn = (FSFpePtr) fpe->private; + + /* XXX we may get called after the resource DB has been cleaned out */ + if (find_old_font(fsd->fontid)) + DeleteFontClientID(fsd->fontid); + if (conn->generation == fsd->generation) + fs_send_close_font(fpe, fsd->fontid); + (*pfont->unload_font) (pfont); + + + xfree(fsd->name); + xfree(fsd); + xfree(pfont->info.isStringProp); + xfree(pfont->info.props); + xfree(pfont->devPrivates); + xfree(pfont); + + + return Successful; +} + +static int +fs_read_glyphs(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr) blockrec->data; + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + FSFpePtr conn = (FSFpePtr) fpe->private; + FontPtr pfont = bglyph->pfont; /* works for either blocked font + or glyph rec... pfont is at + the very beginning of both + blockrec->data structures */ + FSFontDataPtr fsd = (FSFontDataPtr) (pfont->fpePrivate); + FSFontPtr fsdata = (FSFontPtr) pfont->fontPrivate; + FontInfoPtr pfi = &pfont->info; + fsQueryXBitmaps16Reply rep; + fsOffset32 *ppbits; + fsOffset32 local_off; + char *off_adr; + pointer pbitmaps; + char *bits; + int glyph_size, + offset_size, + i, + err; + int nranges = 0; + fsRange *ranges, *nextrange; + unsigned long minchar, maxchar; + + /* get reply header */ + memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply)); + if (rep.type == FS_Error) { +/* XXX -- translate FS error */ + _fs_eat_rest_of_error(conn, (fsError *) & rep); + err = AllocError; + goto bail; + } + if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply), + SIZEOF(fsQueryXBitmaps16Reply) - SIZEOF(fsGenericReply)) == -1) { + if (blockrec->type == FS_OPEN_FONT) + fs_free_font(bfont); + return StillWorking; + } + /* allocate space for glyphs */ + offset_size = SIZEOF(fsOffset32) * (rep.num_chars); + glyph_size = (rep.length << 2) - SIZEOF(fsQueryXBitmaps16Reply) + - offset_size; + ppbits = (fsOffset32 *) xalloc(offset_size); + pbitmaps = (pointer) xalloc(glyph_size); + if (glyph_size && !pbitmaps || !ppbits) + { + xfree(pbitmaps); + xfree(ppbits); + + /* clear wire */ + (void) _fs_drain_bytes_pad(conn, offset_size); + (void) _fs_drain_bytes_pad(conn, glyph_size); + + if (blockrec->type == FS_OPEN_FONT) + _fs_cleanup_font(bfont); + err = AllocError; + goto bail; + } + + /* read offsets */ + if (_fs_read_pad(conn, (char *) ppbits, offset_size) == -1) { + if (blockrec->type == FS_OPEN_FONT) + fs_free_font(bfont); + return StillWorking; + } + + /* read glyphs */ + if (_fs_read_pad(conn, (char *) pbitmaps, glyph_size) == -1) { + if (blockrec->type == FS_OPEN_FONT) + fs_free_font(bfont); + return StillWorking; + } + + if (blockrec->type == FS_LOAD_GLYPHS) + { + nranges = bglyph->num_expected_ranges; + nextrange = ranges = bglyph->expected_ranges; + } + + /* place the incoming glyphs */ + if (nranges) + { + /* We're operating under the assumption that the ranges + requested in the LoadGlyphs call were all legal for this + font, and that individual ranges do not cover multiple + rows... fs_build_range() is designed to ensure this. */ + minchar = (nextrange->min_char_high - pfi->firstRow) * + (pfi->lastCol - pfi->firstCol + 1) + + nextrange->min_char_low - pfi->firstCol; + maxchar = (nextrange->max_char_high - pfi->firstRow) * + (pfi->lastCol - pfi->firstCol + 1) + + nextrange->max_char_low - pfi->firstCol; + nextrange++; + } + else + { + minchar = 0; + maxchar = rep.num_chars; + } + + off_adr = (char *)ppbits; + for (i = 0; i < rep.num_chars; i++) + { + memcpy(&local_off, off_adr, SIZEOF(fsOffset32)); /* align it */ + if (blockrec->type == FS_OPEN_FONT || + fsdata->encoding[minchar].bits == &_fs_glyph_requested) + { + if (local_off.length) + { + bits = (char *)xalloc(local_off.length); + if (bits == NULL) + { + xfree(ppbits); + xfree(pbitmaps); + err = AllocError; + goto bail; + } + memcpy(bits, pbitmaps + local_off.position, + local_off.length); + } + else if (NONZEROMETRICS(&fsdata->encoding[minchar].metrics)) + bits = &_fs_glyph_zero_length; + else + bits = 0; + if (fsdata->encoding[minchar].bits == &_fs_glyph_requested) + fsd->glyphs_to_get--; + fsdata->encoding[minchar].bits = bits; + } + if (minchar++ == maxchar) + { + if (!--nranges) break; + minchar = (nextrange->min_char_high - pfi->firstRow) * + (pfi->lastCol - pfi->firstCol + 1) + + nextrange->min_char_low - pfi->firstCol; + maxchar = (nextrange->max_char_high - pfi->firstRow) * + (pfi->lastCol - pfi->firstCol + 1) + + nextrange->max_char_low - pfi->firstCol; + nextrange++; + } + off_adr += SIZEOF(fsOffset32); + } + + xfree(ppbits); + xfree(pbitmaps); + + if (blockrec->type == FS_OPEN_FONT) + { + fsd->glyphs_to_get = 0; + bfont->state = FS_DONE_REPLY; + } + err = Successful; + +bail: + if (blockrec->type == FS_LOAD_GLYPHS) + { + bglyph->done = TRUE; + bglyph->errcode = err; + } + + return err; +} + + + +static int +fs_send_load_glyphs(client, pfont, nranges, ranges) + pointer client; + FontPtr pfont; + int nranges; + fsRange *ranges; +{ + FSBlockedGlyphPtr blockedglyph; + fsQueryXBitmaps16Req req; + FSFontDataPtr fsd = (FSFontDataPtr) (pfont->fpePrivate); + FontPathElementPtr fpe = fsd->fpe; + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockDataPtr blockrec; + + /* make a new block record, and add it to the end of the list */ + blockrec = fs_new_block_rec(fpe, client, FS_LOAD_GLYPHS); + if (!blockrec) + return AllocError; + blockedglyph = (FSBlockedGlyphPtr) blockrec->data; + blockedglyph->pfont = pfont; + blockedglyph->num_expected_ranges = nranges; + /* Assumption: it's our job to free ranges */ + blockedglyph->expected_ranges = ranges; + blockedglyph->done = FALSE; + blockedglyph->clients_depending = (FSClientsDependingPtr)0; + + blockrec->sequence_number = conn->current_seq; + + /* send the request */ + req.reqType = FS_QueryXBitmaps16; + req.fid = ((FSFontDataPtr) pfont->fpePrivate)->fontid; + req.format = pfont->format; + if (pfont->info.terminalFont) + req.format = req.format & ~(BitmapFormatImageRectMask) | + BitmapFormatImageRectMax; + req.range = TRUE; + /* each range takes up 4 bytes */ + req.length = (SIZEOF(fsQueryXBitmaps16Req) >> 2) + nranges; + req.num_ranges = nranges * 2; /* protocol wants count of fsChar2bs */ + _fs_add_req_log(conn, FS_QueryXBitmaps16); + _fs_write(conn, (char *) &req, SIZEOF(fsQueryXBitmaps16Req)); + + /* Send ranges to the server... pack into a char array by hand + to avoid structure-packing portability problems and to + handle swapping for version1 protocol */ + if (nranges) + { +#define RANGE_BUFFER_SIZE 64 +#define RANGE_BUFFER_SIZE_MASK 63 + int i; + char range_buffer[RANGE_BUFFER_SIZE * 4]; + char *range_buffer_p; + + range_buffer_p = range_buffer; + for (i = 0; i < nranges;) + { + if (conn->fsMajorVersion > 1) + { + *range_buffer_p++ = ranges[i].min_char_high; + *range_buffer_p++ = ranges[i].min_char_low; + *range_buffer_p++ = ranges[i].max_char_high; + *range_buffer_p++ = ranges[i].max_char_low; + } + else + { + *range_buffer_p++ = ranges[i].min_char_low; + *range_buffer_p++ = ranges[i].min_char_high; + *range_buffer_p++ = ranges[i].max_char_low; + *range_buffer_p++ = ranges[i].max_char_high; + } + + if (!(++i & RANGE_BUFFER_SIZE_MASK)) + { + _fs_write(conn, range_buffer, RANGE_BUFFER_SIZE * 4); + range_buffer_p = range_buffer; + } + } + if (i &= RANGE_BUFFER_SIZE_MASK) + _fs_write(conn, range_buffer, i * 4); + } + + return Suspended; +} + + +int +fs_load_all_glyphs(pfont) + FontPtr pfont; +{ + extern pointer serverClient; /* This could be any number that + doesn't conflict with existing + client values. */ + int err; + FSFpePtr conn = (FSFpePtr) pfont->fpe->private; + + /* + * The purpose of this procedure is to load all glyphs in the event + * that we're dealing with someone who doesn't understand the finer + * points of glyph caching... it is called from _fs_get_glyphs() if + * the latter is called to get glyphs that have not yet been loaded. + * We assume that the caller will not know how to handle a return + * value of Suspended (usually the case for a GetGlyphs() caller), + * so this procedure hangs around, freezing the server, for the + * request to complete. This is an unpleasant kluge called to + * perform an unpleasant job that, we hope, will never be required. + */ + + while ((err = _fs_load_glyphs(serverClient, pfont, TRUE, 0, 0, NULL)) == + Suspended) + { + fd_set TempSelectMask; + + FD_ZERO (&TempSelectMask); + + if (_fs_wait_for_readable(conn) == -1) + { + /* We lost our connection. Don't wait to reestablish it; + just give up. */ + _fs_connection_died(conn); + + /* Get rid of blockrec */ + fs_client_died(serverClient, pfont->fpe); + + return BadCharRange; /* As good an error as any other */ + } + FD_SET(conn->fs_fd, &TempSelectMask); + fs_wakeup(pfont->fpe, &TempSelectMask); + } + + return err; +} + + +int +_fs_load_glyphs(client, pfont, range_flag, nchars, item_size, data) + pointer client; + FontPtr pfont; + Bool range_flag; + unsigned int nchars; + int item_size; + unsigned char *data; +{ + + int nranges = 0; + fsRange *ranges = NULL; + int res; + FSBlockDataPtr blockrec; + FSBlockedGlyphPtr blockedglyph; + FSFpePtr conn = (FSFpePtr) pfont->fpe->private; + FSClientsDependingPtr *clients_depending = NULL; + + /* see if the result is already there */ + + blockrec = (FSBlockDataPtr) conn->blocked_requests; + while (blockrec) { + if (blockrec->type == FS_LOAD_GLYPHS) + { + blockedglyph = (FSBlockedGlyphPtr) blockrec->data; + if (blockedglyph->pfont == pfont) + { + if (blockrec->client == client) + { + if (blockedglyph->done) + { + int errcode = blockedglyph->errcode; + signal_clients_depending(&blockedglyph-> + clients_depending); + _fs_remove_block_rec(conn, blockrec); + return errcode; + } + else return Suspended; + } + /* We've found an existing LoadGlyphs blockrec for this + font but for another client. Rather than build a + blockrec for it now (which entails some complex + maintenance), we'll add it to a queue of clients to + be signalled when the existing LoadGlyphs is + completed. */ + clients_depending = &blockedglyph->clients_depending; + break; + } + } + else if (blockrec->type == FS_OPEN_FONT) + { + FSBlockedFontPtr bfont; + bfont = (FSBlockedFontPtr) blockrec->data; + if (bfont->pfont == pfont) + { + if (blockrec->client == client) + { + if (bfont->state == FS_DONE_REPLY) + { + int errcode = bfont->errcode; + signal_clients_depending(&bfont->clients_depending); + _fs_remove_block_rec(conn, blockrec); + if (errcode == Successful) break; + else return errcode; + } + else return Suspended; + } + /* We've found an existing OpenFont blockrec for this + font but for another client. Rather than build a + blockrec for it now (which entails some complex + maintenance), we'll add it to a queue of clients to + be signalled when the existing OpenFont is + completed. */ + if (bfont->state != FS_DONE_REPLY) + { + clients_depending = &bfont->clients_depending; + break; + } + } + } + + blockrec = blockrec->next; + } + + /* + * see if the desired glyphs already exist, and return Successful if they + * do, otherwise build up character range/character string + */ + res = fs_build_range(pfont, range_flag, nchars, item_size, data, + &nranges, &ranges); + + switch (res) + { + case AccessDone: + return Successful; + + case Successful: + break; + + default: + return res; + } + + /* + * If clients_depending is not null, this request must wait for + * some prior request(s) to complete. + */ + if (clients_depending) + { + /* Since we're not ready to send the load_glyphs request yet, + clean up the damage (if any) caused by the fs_build_range() + call. */ + if (nranges) + { + _fs_clean_aborted_loadglyphs(pfont, nranges, ranges); + xfree(ranges); + } + return add_clients_depending(clients_depending, client); + } + + /* + * If fsd->generation != conn->generation, the font has been closed + * due to a lost connection. We will reopen it, which will result + * in one of three things happening: + * 1) The open will succeed and obtain the same font. Life + * is wonderful. + * 2) The open will fail. There is code above to recognize this + * and flunk the LoadGlyphs request. The client might not be + * thrilled. + * 3) Worst case: the open will succeed but the font we open will + * be different. The fs_read_query_info() procedure attempts + * to detect this by comparing the existing metrics and + * properties against those of the reopened font... if they + * don't match, we flunk the reopen, which eventually results + * in flunking the LoadGlyphs request. We could go a step + * further and compare the extents, but this should be + * sufficient. + */ + if (((FSFontDataPtr)pfont->fpePrivate)->generation != conn->generation) + { + /* Since we're not ready to send the load_glyphs request yet, + clean up the damage caused by the fs_build_range() call. */ + _fs_clean_aborted_loadglyphs(pfont, nranges, ranges); + xfree(ranges); + + /* Now try to reopen the font. */ + return fs_send_open_font(client, (FontPathElementPtr)0, + (Mask)FontReopen, (char *)0, 0, + (fsBitmapFormat)0, (fsBitmapFormatMask)0, + (XID)0, &pfont); + } + + return fs_send_load_glyphs(client, pfont, nranges, ranges); +} + + + +static int +fs_read_list(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedListPtr blist = (FSBlockedListPtr) blockrec->data; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsListFontsReply rep; + char *data, + *dp; + int length, + i; + + blist->done = TRUE; + + /* read reply header */ + memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply)); + if (rep.type == FS_Error) { +/* XXX -- translate FS error */ + _fs_eat_rest_of_error(conn, (fsError *) & rep); + return AllocError; + } + if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply), + SIZEOF(fsListFontsReply) - SIZEOF(fsGenericReply)) == -1) { + /* nothing to free (i think) */ + return StillWorking; + } + length = (rep.length << 2) - SIZEOF(fsListFontsReply); + data = (char *) xalloc(length); + if (!data) { + _fs_drain_bytes_pad(conn, length); + return AllocError; + } + /* read the list */ + if (_fs_read_pad(conn, data, length) == -1) { + /* nothing to free (i think) */ + return StillWorking; + } + /* copy data into FontPathRecord */ + dp = data; + for (i = 0; i < rep.nFonts; i++) { + length = *(unsigned char *)dp++; + if (AddFontNamesName(blist->names, dp, length) != Successful) { + blist->errcode = AllocError; + break; + } + dp += length; + } + + xfree(data); + return Successful; +} + +static int +fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames) + pointer client; + FontPathElementPtr fpe; + char *pattern; + int patlen; + int maxnames; + FontNamesPtr newnames; +{ + FSBlockDataPtr blockrec; + FSBlockedListPtr blockedlist; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsListFontsReq req; + + _fs_client_access (conn, client, FALSE); + _fs_client_resolution(conn); + + /* make a new block record, and add it to the end of the list */ + blockrec = fs_new_block_rec(fpe, client, FS_LIST_FONTS); + if (!blockrec) + return AllocError; + blockedlist = (FSBlockedListPtr) blockrec->data; + blockedlist->patlen = patlen; + blockedlist->errcode = Successful; + blockedlist->names = newnames; + blockedlist->done = FALSE; + + /* send the request */ + req.reqType = FS_ListFonts; + req.maxNames = maxnames; + req.nbytes = patlen; + req.length = (SIZEOF(fsListFontsReq) + patlen + 3) >> 2; + _fs_add_req_log(conn, FS_ListFonts); + _fs_write(conn, (char *) &req, SIZEOF(fsListFontsReq)); + _fs_write_pad(conn, (char *) pattern, patlen); + +#ifdef NCD + if (configData.ExtendedFontDiags) { + char buf[256]; + + memcpy(buf, pattern, MIN(256, patlen)); + buf[MIN(256, patlen)] = '\0'; + printf("Listing fonts on pattern \"%s\" from font server \"%s\"\n", + buf, fpe->name); + } +#endif + + return Suspended; +} + +static int +fs_list_fonts(client, fpe, pattern, patlen, maxnames, newnames) + pointer client; + FontPathElementPtr fpe; + char *pattern; + int patlen; + int maxnames; + FontNamesPtr newnames; +{ + FSBlockDataPtr blockrec; + FSBlockedListPtr blockedlist; + FSFpePtr conn = (FSFpePtr) fpe->private; + int err; + + /* see if the result is already there */ + blockrec = (FSBlockDataPtr) conn->blocked_requests; + while (blockrec) { + if (blockrec->type == FS_LIST_FONTS && blockrec->client == client) { + blockedlist = (FSBlockedListPtr) blockrec->data; + if (blockedlist->patlen == patlen && blockedlist->done) { + err = blockedlist->errcode; + _fs_remove_block_rec(conn, blockrec); + return err; + } + } + blockrec = blockrec->next; + } + + /* didn't find waiting record, so send a new one */ + return fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames); +} + +static int padlength[4] = {0, 3, 2, 1}; + +static int +fs_read_list_info(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedListInfoPtr binfo = (FSBlockedListInfoPtr) blockrec->data; + fsListFontsWithXInfoReply rep; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsPropInfo pi; + fsPropOffset *po; + char *name; + pointer pd; + int err; + + /* clean up anything from the last trip */ + if (binfo->name) + { + xfree(binfo->name); + binfo->name = NULL; + } + if (binfo->pfi) { + xfree(binfo->pfi->isStringProp); + xfree(binfo->pfi->props); + xfree(binfo->pfi); + binfo->pfi = NULL; + } + /* get reply header */ + memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply)); + if (rep.type == FS_Error) { +/* XXX -- translate FS error */ + _fs_eat_rest_of_error(conn, (fsError *) & rep); + binfo->errcode = AllocError; + return AllocError; + } + if (conn->fsMajorVersion > 1) + if (rep.nameLength == 0) + goto done; + /* old protocol sent a full-length reply even for the last one */ + if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply), + SIZEOF(fsListFontsWithXInfoReply) - SIZEOF(fsGenericReply)) == -1) { + goto done; + } + if (rep.nameLength == 0) + goto done; + + /* read the data */ + name = (char *) xalloc(rep.nameLength); + binfo->pfi = (FontInfoPtr) xalloc(sizeof(FontInfoRec)); + if (!name || !binfo->pfi) { + xfree(name); + xfree(binfo->pfi); + binfo->pfi = NULL; + _fs_drain_bytes(conn, + rep.length - (SIZEOF(fsListFontsWithXInfoReply) - + SIZEOF(fsGenericReply))); + binfo->errcode = AllocError; + return AllocError; + } + if (conn->fsMajorVersion == 1) + if (_fs_read_pad(conn, name, rep.nameLength) == -1) + goto done; + if (_fs_read_pad(conn, (char *) &pi, SIZEOF(fsPropInfo)) == -1) + goto done; + + po = (fsPropOffset *) xalloc(SIZEOF(fsPropOffset) * pi.num_offsets); + pd = (pointer) xalloc(pi.data_len); + if (!po || !pd) { + xfree(name); + xfree(po); + xfree(pd); + xfree (binfo->pfi); + binfo->pfi = NULL; + binfo->errcode = AllocError; + return AllocError; + } + err = _fs_read_pad(conn, (char *) po, + (pi.num_offsets * SIZEOF(fsPropOffset))); + if (err != -1) + { + if (conn->fsMajorVersion > 1) + err = _fs_read(conn, (char *) pd, pi.data_len); + else + err = _fs_read_pad(conn, (char *) pd, pi.data_len); + } + if (err != -1 && conn->fsMajorVersion != 1) + { + err = _fs_read(conn, name, rep.nameLength); + if (err != -1) + err = _fs_drain_bytes(conn, padlength[(pi.data_len+rep.nameLength)&3]); + } + + if (err == -1) { + xfree(name); + xfree(po); + xfree(pd); + xfree (binfo->pfi); + binfo->pfi = NULL; + goto done; + } + + if (_fs_convert_lfwi_reply(conn, binfo->pfi, &rep, &pi, po, pd) != Successful) + { + xfree(name); + xfree(po); + xfree(pd); + xfree (binfo->pfi); + binfo->pfi = NULL; + goto done; + } + xfree(po); + xfree(pd); + binfo->name = name; + binfo->namelen = rep.nameLength; + binfo->remaining = rep.nReplies; + + binfo->status = FS_LFWI_REPLY; + binfo->errcode = Suspended; + /* disable this font server until we've processed this response */ + FD_CLR(conn->fs_fd, &_fs_fd_mask); + + return Successful; + +done: + binfo->status = FS_LFWI_FINISHED; + binfo->errcode = BadFontName; + binfo->name = (char *) 0; + return Successful; +} + +/* ARGSUSED */ +static int +fs_start_list_with_info(client, fpe, pattern, len, maxnames, pdata) + pointer client; + FontPathElementPtr fpe; + char *pattern; + int len; + int maxnames; + pointer *pdata; +{ + FSBlockDataPtr blockrec; + FSBlockedListInfoPtr blockedinfo; + fsListFontsWithXInfoReq req; + FSFpePtr conn = (FSFpePtr) fpe->private; + + _fs_client_access (conn, client, FALSE); + _fs_client_resolution(conn); + + /* make a new block record, and add it to the end of the list */ + blockrec = fs_new_block_rec(fpe, client, FS_LIST_WITH_INFO); + if (!blockrec) + return AllocError; + blockedinfo = (FSBlockedListInfoPtr) blockrec->data; + bzero((char *) blockedinfo, sizeof(FSBlockedListInfoRec)); + blockedinfo->status = FS_LFWI_WAITING; + blockedinfo->errcode = Suspended; + + /* send the request */ + req.reqType = FS_ListFontsWithXInfo; + req.maxNames = maxnames; + req.nbytes = len; + req.length = (SIZEOF(fsListFontsWithXInfoReq) + len + 3) >> 2; + _fs_add_req_log(conn, FS_ListFontsWithXInfo); + (void) _fs_write(conn, (char *) &req, SIZEOF(fsListFontsWithXInfoReq)); + (void) _fs_write_pad(conn, pattern, len); + +#ifdef NCD + if (configData.ExtendedFontDiags) { + char buf[256]; + + memcpy(buf, pattern, MIN(256, len)); + buf[MIN(256, len)] = '\0'; + printf("Listing fonts with info on pattern \"%s\" from font server \"%s\"\n", + buf, fpe->name); + } +#endif + + return Successful; +} + +/* ARGSUSED */ +static int +fs_next_list_with_info(client, fpe, namep, namelenp, pFontInfo, numFonts, + private) + pointer client; + FontPathElementPtr fpe; + char **namep; + int *namelenp; + FontInfoPtr *pFontInfo; + int *numFonts; + pointer private; +{ + FSBlockDataPtr blockrec; + FSBlockedListInfoPtr blockedinfo; + FSFpePtr conn = (FSFpePtr) fpe->private; + + /* see if the result is already there */ + blockrec = (FSBlockDataPtr) conn->blocked_requests; + while (blockrec) { + if (blockrec->type == FS_LIST_WITH_INFO && + blockrec->client == client) { + blockedinfo = (FSBlockedListInfoPtr) blockrec->data; + break; + } + blockrec = blockrec->next; + } + + if (!blockrec) + { + /* The only good reason for not finding a blockrec would be if + disconnect/reconnect to the font server wiped it out and the + code that called us didn't do the right thing to create + another one. Under those circumstances, we need to return an + error to prevent that code from attempting to interpret the + information we don't return. */ + return BadFontName; + } + + if (blockedinfo->status == FS_LFWI_WAITING) + return Suspended; + + *namep = blockedinfo->name; + *namelenp = blockedinfo->namelen; + *pFontInfo = blockedinfo->pfi; + *numFonts = blockedinfo->remaining; + FD_SET(conn->fs_fd, &_fs_fd_mask); + if (blockedinfo->status == FS_LFWI_FINISHED) { + int err = blockedinfo->errcode; + + _fs_remove_block_rec(conn, blockrec); + return err; + } + if (blockedinfo->status == FS_LFWI_REPLY) { + blockedinfo->status = FS_LFWI_WAITING; + return Successful; + } else { + return blockedinfo->errcode; + } +} + +/* + * Called when client exits + */ + +static void +fs_client_died(client, fpe) + pointer client; + FontPathElementPtr fpe; +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockDataPtr blockrec, + depending; + FSClientPtr *prev, cur; + fsFreeACReq freeac; + + for (prev = &conn->clients; cur = *prev; prev = &cur->next) + { + if (cur->client == client) { + freeac.reqType = FS_FreeAC; + freeac.id = cur->acid; + freeac.length = sizeof (fsFreeACReq) >> 2; + _fs_add_req_log(conn, FS_FreeAC); + _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq)); + *prev = cur->next; + xfree (cur); + break; + } + } + /* see if the result is already there */ + blockrec = (FSBlockDataPtr) conn->blocked_requests; + while (blockrec) { + if (blockrec->client == client) + break; + blockrec = blockrec->next; + } + if (!blockrec) + return; + if (blockrec->type == FS_LIST_WITH_INFO) + { + FSBlockedListInfoPtr binfo; + binfo = (FSBlockedListInfoPtr) blockrec->data; + if (binfo->status == FS_LFWI_REPLY) + FD_SET(conn->fs_fd, &_fs_fd_mask); + if (binfo->name) + { + xfree(binfo->name); + binfo->name = NULL; + } + if (binfo->pfi) + { + xfree(binfo->pfi->isStringProp); + xfree(binfo->pfi->props); + xfree(binfo->pfi); + binfo->pfi = NULL; + } + } + /* replace the client pointers in this block rec with the chained one */ + if (depending = blockrec->depending) { + blockrec->client = depending->client; + blockrec->depending = depending->depending; + blockrec = depending; + } + fs_abort_blockrec(conn, blockrec); +} + +static void +_fs_client_access (conn, client, sync) + FSFpePtr conn; + pointer client; + Bool sync; +{ + FSClientPtr *prev, cur; + fsCreateACReq crac; + fsSetAuthorizationReq setac; + fsGenericReply rep; + char *authorizations; + int authlen; + Bool new_cur = FALSE; + + for (prev = &conn->clients; cur = *prev; prev = &cur->next) + { + if (cur->client == client) + { + if (prev != &conn->clients) + { + *prev = cur->next; + cur->next = conn->clients; + conn->clients = cur; + } + break; + } + } + if (!cur) + { + cur = (FSClientPtr) xalloc (sizeof (FSClientRec)); + if (!cur) + return; + cur->client = client; + cur->next = conn->clients; + conn->clients = cur; + cur->acid = GetNewFontClientID (); + new_cur = TRUE; + } + if (new_cur || cur->auth_generation != client_auth_generation(client)) + { + if (!new_cur) + { + fsFreeACReq freeac; + freeac.reqType = FS_FreeAC; + freeac.id = cur->acid; + freeac.length = sizeof (fsFreeACReq) >> 2; + _fs_add_req_log(conn, FS_FreeAC); + _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq)); + } + crac.reqType = FS_CreateAC; + crac.num_auths = set_font_authorizations(&authorizations, &authlen, + client); + authlen = crac.num_auths ? (authlen + 3) & ~0x3 : 0; + crac.length = (sizeof (fsCreateACReq) + authlen) >> 2; + crac.acid = cur->acid; + _fs_add_req_log(conn, FS_CreateAC); + _fs_write(conn, (char *) &crac, sizeof (fsCreateACReq)); + _fs_write(conn, authorizations, authlen); + /* if we're synchronous, open_font will be confused by + * the reply; eat it and continue + */ + if (sync) + { + if (_fs_read(conn, (char *) &rep, sizeof (fsGenericReply)) == -1) + return; + fs_handle_unexpected(conn, &rep); + } + /* ignore reply; we don't even care about it */ + conn->curacid = 0; + cur->auth_generation = client_auth_generation(client); + } + if (conn->curacid != cur->acid) + { + setac.reqType = FS_SetAuthorization; + setac.length = sizeof (fsSetAuthorizationReq) >> 2; + setac.id = cur->acid; + _fs_add_req_log(conn, FS_SetAuthorization); + _fs_write(conn, (char *) &setac, sizeof (fsSetAuthorizationReq)); + conn->curacid = cur->acid; + } +} + +/* + * called at server init time + */ + +void +fs_register_fpe_functions() +{ + fs_font_type = RegisterFPEFunctions(fs_name_check, + fs_init_fpe, + fs_free_fpe, + fs_reset_fpe, + fs_open_font, + fs_close_font, + fs_list_fonts, + fs_start_list_with_info, + fs_next_list_with_info, + fs_wakeup, + fs_client_died, + _fs_load_glyphs, + (int (*))0, + (int (*))0, + (void (*))0); +} + +static int +check_fs_open_font(client, fpe, flags, name, namelen, format, fmask, id, ppfont, + alias, non_cachable_font) + pointer client; + FontPathElementPtr fpe; + Mask flags; + char *name; + fsBitmapFormat format; + fsBitmapFormatMask fmask; + int namelen; + XID id; + FontPtr *ppfont; + char **alias; + FontPtr non_cachable_font; /* Not used in this FPE */ +{ + if (XpClientIsBitmapClient(client)) + return (fs_open_font(client, fpe, flags, name, namelen, format, + fmask, id, ppfont, alias, non_cachable_font) ); + return BadFontName; +} + +static int +check_fs_list_fonts(client, fpe, pattern, patlen, maxnames, newnames) + pointer client; + FontPathElementPtr fpe; + char *pattern; + int patlen; + int maxnames; + FontNamesPtr newnames; +{ + if (XpClientIsBitmapClient(client)) + return (fs_list_fonts(client, fpe, pattern, patlen, maxnames, + newnames)); + return BadFontName; +} + +static int +check_fs_start_list_with_info(client, fpe, pattern, len, maxnames, pdata) + pointer client; + FontPathElementPtr fpe; + char *pattern; + int len; + int maxnames; + pointer *pdata; +{ + if (XpClientIsBitmapClient(client)) + return (fs_start_list_with_info(client, fpe, pattern, len, maxnames, + pdata)); + return BadFontName; +} + +static int +check_fs_next_list_with_info(client, fpe, namep, namelenp, pFontInfo, numFonts, + private) + pointer client; + FontPathElementPtr fpe; + char **namep; + int *namelenp; + FontInfoPtr *pFontInfo; + int *numFonts; + pointer private; +{ + if (XpClientIsBitmapClient(client)) + return (fs_next_list_with_info(client, fpe, namep, namelenp, pFontInfo, + numFonts,private)); + return BadFontName; +} + +void +check_fs_register_fpe_functions() +{ + fs_font_type = RegisterFPEFunctions(fs_name_check, + fs_init_fpe, + fs_free_fpe, + fs_reset_fpe, + check_fs_open_font, + fs_close_font, + check_fs_list_fonts, + check_fs_start_list_with_info, + check_fs_next_list_with_info, + fs_wakeup, + fs_client_died, + _fs_load_glyphs, + (int (*))0, + (int (*))0, + (void (*))0); +} |