summaryrefslogtreecommitdiff
path: root/src/fc/fserve.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fc/fserve.c')
-rw-r--r--src/fc/fserve.c2815
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);
+}