diff options
author | marha <marha@users.sourceforge.net> | 2011-09-12 11:27:51 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2011-09-12 11:27:51 +0200 |
commit | dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0 (patch) | |
tree | bdf833cc6a4fc9035411779e10dd9e8478201885 /libXfont/src/fc/fserve.c | |
parent | 0b40f5f4b54453a77f4b09c431f8efc6875da61f (diff) | |
download | vcxsrv-dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0.tar.gz vcxsrv-dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0.tar.bz2 vcxsrv-dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0.zip |
Synchronised line endinge with release branch
Diffstat (limited to 'libXfont/src/fc/fserve.c')
-rw-r--r-- | libXfont/src/fc/fserve.c | 6396 |
1 files changed, 3198 insertions, 3198 deletions
diff --git a/libXfont/src/fc/fserve.c b/libXfont/src/fc/fserve.c index f59dbcc9f..b02b0b749 100644 --- a/libXfont/src/fc/fserve.c +++ b/libXfont/src/fc/fserve.c @@ -1,3198 +1,3198 @@ -/*
-
-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 HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef WIN32
-#define _WILLWINSOCK_
-#endif
-#define FONT_t
-#define TRANS_CLIENT
-#include "X11/Xtrans/Xtrans.h"
-#include "X11/Xpoll.h"
-#include <X11/fonts/FS.h>
-#include <X11/fonts/FSproto.h>
-#include <X11/X.h>
-#include <X11/Xos.h>
-#include <X11/fonts/fontmisc.h>
-#include <X11/fonts/fontstruct.h>
-#include "fservestr.h"
-#include <X11/fonts/fontutil.h>
-#include <errno.h>
-
-#include <time.h>
-#define Time_t time_t
-
-#ifdef NCD
-#include <ncd/nvram.h>
-#endif
-
-#include <stddef.h>
-
-#ifndef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
-#endif
-#define TimeCmp(a,c,b) ((int) ((a) - (b)) c 0)
-
-#define NONZEROMETRICS(pci) ((pci)->leftSideBearing || \
- (pci)->rightSideBearing || \
- (pci)->ascent || \
- (pci)->descent || \
- (pci)->characterWidth)
-
-extern void ErrorF(const char *f, ...);
-
-static int fs_read_glyphs ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
-static int fs_read_list ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
-static int fs_read_list_info ( FontPathElementPtr fpe,
- FSBlockDataPtr blockrec );
-
-extern fd_set _fs_fd_mask;
-
-static void fs_block_handler ( pointer data, OSTimePtr wt,
- pointer LastSelectMask );
-static int fs_wakeup ( FontPathElementPtr fpe, unsigned long *mask );
-
-/*
- * List of all FPEs
- */
-static FSFpePtr fs_fpes;
-/*
- * Union of all FPE blockStates
- */
-static CARD32 fs_blockState;
-
-static int _fs_restart_connection ( FSFpePtr conn );
-static void fs_send_query_bitmaps ( FontPathElementPtr fpe,
- FSBlockDataPtr blockrec );
-static int fs_send_close_font ( FontPathElementPtr fpe, Font id );
-static void fs_client_died ( pointer client, FontPathElementPtr fpe );
-static void _fs_client_access ( FSFpePtr conn, pointer client, Bool sync );
-static void _fs_client_resolution ( FSFpePtr conn );
-static fsGenericReply *fs_get_reply (FSFpePtr conn, int *error);
-static int fs_await_reply (FSFpePtr conn);
-static void _fs_do_blocked (FSFpePtr conn);
-static void fs_cleanup_bfont (FSBlockedFontPtr bfont);
-
-char _fs_glyph_undefined;
-char _fs_glyph_requested;
-static char _fs_glyph_zero_length;
-
-static int generationCount;
-
-static int FontServerRequestTimeout = 30 * 1000;
-
-static void
-_fs_close_server (FSFpePtr conn);
-
-static FSFpePtr
-_fs_init_conn (char *servername);
-
-static int
-_fs_wait_connect (FSFpePtr conn);
-
-static int
-_fs_send_init_packets (FSFpePtr conn);
-
-static void
-_fs_check_reconnect (FSFpePtr conn);
-
-static void
-_fs_start_reconnect (FSFpePtr conn);
-
-static void
-_fs_free_conn (FSFpePtr conn);
-
-static int
-fs_free_fpe(FontPathElementPtr fpe);
-
-/*
- * 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.
- */
-
-
-#ifdef DEBUG
-static void
-_fs_add_req_log(FSFpePtr conn, int opcode)
-{
- conn->current_seq++;
- fprintf (stderr, "\t\tRequest: %5d Opcode: %2d\n",
- conn->current_seq, opcode);
- conn->reqbuffer[conn->reqindex].opcode = opcode;
- conn->reqbuffer[conn->reqindex].sequence = conn->current_seq;
- conn->reqindex++;
- if (conn->reqindex == REQUEST_LOG_SIZE)
- conn->reqindex = 0;
-}
-
-static void
-_fs_add_rep_log (FSFpePtr conn, fsGenericReply *rep)
-{
- int i;
-
- for (i = 0; i < REQUEST_LOG_SIZE; i++)
- if (conn->reqbuffer[i].sequence == rep->sequenceNumber)
- break;
- if (i == REQUEST_LOG_SIZE)
- fprintf (stderr, "\t\t\t\t\tReply: %5d Opcode: unknown\n",
- rep->sequenceNumber);
- else
- fprintf (stderr, "\t\t\t\t\tReply: %5d Opcode: %d\n",
- rep->sequenceNumber,
- conn->reqbuffer[i].opcode);
-}
-#else
-#define _fs_add_req_log(conn,op) ((conn)->current_seq++)
-#define _fs_add_rep_log(conn,rep)
-#endif
-
-static Bool
-fs_name_check(char *name)
-{
- /* Just make sure there is a protocol/ prefix */
- return (name && *name != '/' && strchr(name, '/'));
-}
-
-static void
-_fs_client_resolution(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)));
- }
-}
-
-/*
- * close font server and remove any state associated with
- * this connection - this includes any client records.
- */
-
-static void
-fs_close_conn(FSFpePtr conn)
-{
- FSClientPtr client, nclient;
-
- _fs_close_server (conn);
-
- for (client = conn->clients; client; client = nclient)
- {
- nclient = client->next;
- free (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(FontPathElementPtr fpe)
-{
- FSFpePtr conn;
- char *name;
- int err;
- int ret;
-
- /* open font server */
- /* create FS specific fpe info */
- name = fpe->name;
-
- /* hack for old style names */
- if (*name == ':')
- name++; /* skip ':' */
-
- conn = _fs_init_conn (name);
- if (!conn)
- err = AllocError;
- else
- {
- err = init_fs_handlers (fpe, fs_block_handler);
- if (err != Successful)
- {
- _fs_free_conn (conn);
- err = AllocError;
- }
- else
- {
- fpe->private = conn;
- conn->next = fs_fpes;
- fs_fpes = conn;
- ret = _fs_wait_connect (conn);
- if (ret != FSIO_READY)
- {
- fs_free_fpe (fpe);
- err = BadFontPath;
- }
- else
- err = Successful;
- }
- }
-
- if (err == Successful)
- {
-#ifdef NCD
- if (configData.ExtendedFontDiags)
- printf("Connected to font server \"%s\"\n", name);
-#endif
-#ifdef DEBUG
- fprintf (stderr, "connected to FS \"%s\"\n", name);
-#endif
- }
- else
- {
-#ifdef DEBUG
- fprintf(stderr, "failed to connect to FS \"%s\" %d\n", name, err);
-#endif
-#ifdef NCD
- if (configData.ExtendedFontDiags)
- printf("Failed to connect to font server \"%s\"\n", name);
-#endif
- ;
- }
- return err;
-}
-
-static int
-fs_reset_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(FontPathElementPtr fpe)
-{
- FSFpePtr conn = (FSFpePtr) fpe->private, *prev;
-
- /* unhook from chain of all font servers */
- for (prev = &fs_fpes; *prev; prev = &(*prev)->next)
- {
- if (*prev == conn)
- {
- *prev = conn->next;
- break;
- }
- }
- _fs_unmark_block (conn, conn->blockState);
- fs_close_conn(conn);
- remove_fs_handlers(fpe, fs_block_handler, fs_fpes == 0);
- _fs_free_conn (conn);
- fpe->private = (pointer) 0;
-
-#ifdef NCD
- if (configData.ExtendedFontDiags)
- printf("Disconnected from font server \"%s\"\n", fpe->name);
-#endif
-#ifdef DEBUG
- fprintf (stderr, "disconnect from FS \"%s\"\n", fpe->name);
-#endif
-
- return Successful;
-}
-
-static FSBlockDataPtr
-fs_new_block_rec(FontPathElementPtr fpe, pointer client, int type)
-{
- FSBlockDataPtr blockrec,
- *prev;
- FSFpePtr conn = (FSFpePtr) fpe->private;
- int size;
-
- 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:
- size = 0;
- break;
- }
- blockrec = malloc(sizeof(FSBlockDataRec) + size);
- if (!blockrec)
- return (FSBlockDataPtr) 0;
- blockrec->data = (pointer) (blockrec + 1);
- blockrec->client = client;
- blockrec->sequenceNumber = -1;
- blockrec->errcode = StillWorking;
- blockrec->type = type;
- blockrec->depending = 0;
- blockrec->next = (FSBlockDataPtr) 0;
-
- /* stick it on the end of the list (since its expected last) */
- for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
- ;
- *prev = blockrec;
-
- return blockrec;
-}
-
-static void
-_fs_set_pending_reply (FSFpePtr conn)
-{
- FSBlockDataPtr blockrec;
-
- for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
- if (blockrec->errcode == StillWorking)
- break;
- if (blockrec)
- {
- conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
- _fs_mark_block (conn, FS_PENDING_REPLY);
- }
- else
- _fs_unmark_block (conn, FS_PENDING_REPLY);
-}
-
-static void
-_fs_remove_block_rec(FSFpePtr conn, FSBlockDataPtr blockrec)
-{
- FSBlockDataPtr *prev;
-
- for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
- if (*prev == blockrec)
- {
- *prev = blockrec->next;
- break;
- }
- if (blockrec->type == FS_LOAD_GLYPHS)
- {
- FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
- if (bglyph->num_expected_ranges)
- free(bglyph->expected_ranges);
- }
- free(blockrec);
- _fs_set_pending_reply (conn);
-}
-
-static void
-_fs_signal_clients_depending(FSClientsDependingPtr *clients_depending)
-{
- FSClientsDependingPtr p;
-
- while ((p = *clients_depending))
- {
- *clients_depending = p->next;
- ClientSignal(p->client);
- free(p);
- }
-}
-
-static int
-_fs_add_clients_depending(FSClientsDependingPtr *clients_depending, pointer client)
-{
- FSClientsDependingPtr new, cd;
-
- for (; (cd = *clients_depending);
- clients_depending = &(*clients_depending)->next)
- {
- if (cd->client == client)
- return Suspended;
- }
-
- new = malloc (sizeof (FSClientsDependingRec));
- if (!new)
- return BadAlloc;
-
- new->client = client;
- new->next = 0;
- *clients_depending = new;
- return Suspended;
-}
-
-/*
- * When a request is aborted due to a font server failure,
- * signal any depending clients to restart their dependant
- * requests
- */
-static void
-_fs_clean_aborted_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
-{
- switch(blockrec->type) {
- case FS_OPEN_FONT: {
- FSBlockedFontPtr bfont = (FSBlockedFontPtr)blockrec->data;
-
- fs_cleanup_bfont (bfont);
- _fs_signal_clients_depending(&bfont->clients_depending);
- break;
- }
- case FS_LOAD_GLYPHS: {
- FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
-
- _fs_clean_aborted_loadglyphs(bglyph->pfont,
- bglyph->num_expected_ranges,
- bglyph->expected_ranges);
- _fs_signal_clients_depending(&bglyph->clients_depending);
- break;
- }
- case FS_LIST_FONTS:
- break;
- case FS_LIST_WITH_INFO: {
- FSBlockedListInfoPtr binfo;
- binfo = (FSBlockedListInfoPtr) blockrec->data;
- if (binfo->status == FS_LFWI_REPLY)
- FD_SET(conn->fs_fd, &_fs_fd_mask);
- _fs_free_props (&binfo->info);
- }
- default:
- break;
- }
-}
-
-static void
-fs_abort_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
-{
- _fs_clean_aborted_blockrec (conn, blockrec);
- _fs_remove_block_rec (conn, blockrec);
-}
-
-/*
- * Tell the font server we've failed to complete an open and
- * then unload the partially created font
- */
-static void
-fs_cleanup_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(bfont->pfont->fpe, bfont->fontid);
-
- /*
- * Either unload the font if it's being opened for
- * the first time, or smash the generation field to
- * mark this font as an orphan
- */
- if (!(bfont->flags & FontReopen))
- {
- if (bfont->freeFont)
- (*bfont->pfont->unload_font) (bfont->pfont);
-#ifdef DEBUG
- else
- fprintf (stderr, "Not freeing other font in cleanup_bfont\n");
-#endif
- bfont->pfont = 0;
- }
- else
- fsd->generation = -1;
- }
-}
-
-/*
- * Check to see if a complete reply is waiting
- */
-static fsGenericReply *
-fs_get_reply (FSFpePtr conn, int *error)
-{
- char *buf;
- fsGenericReply *rep;
- int ret;
-
- /* block if the connection is down or paused in lfwi */
- if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask))
- {
- *error = FSIO_BLOCK;
- return 0;
- }
-
- ret = _fs_start_read (conn, sizeof (fsGenericReply), &buf);
- if (ret != FSIO_READY)
- {
- *error = FSIO_BLOCK;
- return 0;
- }
-
- rep = (fsGenericReply *) buf;
-
- ret = _fs_start_read (conn, rep->length << 2, &buf);
- if (ret != FSIO_READY)
- {
- *error = FSIO_BLOCK;
- return 0;
- }
-
- *error = FSIO_READY;
-
- return (fsGenericReply *) buf;
-}
-
-static Bool
-fs_reply_ready (FSFpePtr conn)
-{
- fsGenericReply *rep;
-
- if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask))
- return FALSE;
- if (fs_data_read (conn) < sizeof (fsGenericReply))
- return FALSE;
- rep = (fsGenericReply *) (conn->inBuf.buf + conn->inBuf.remove);
- if (fs_data_read (conn) < rep->length << 2)
- return FALSE;
- return TRUE;
-}
-
-static void
-_fs_pending_reply (FSFpePtr conn)
-{
- if (!(conn->blockState & FS_PENDING_REPLY))
- {
- _fs_mark_block (conn, FS_PENDING_REPLY);
- conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
- }
-}
-
-static void
-_fs_prepare_for_reply (FSFpePtr conn)
-{
- _fs_pending_reply (conn);
- _fs_flush (conn);
-}
-
-/*
- * Block (for a while) awaiting a complete reply
- */
-static int
-fs_await_reply (FSFpePtr conn)
-{
- int ret;
-
- if (conn->blockState & FS_COMPLETE_REPLY)
- return FSIO_READY;
-
- while (!fs_get_reply (conn, &ret))
- {
- if (ret != FSIO_BLOCK)
- return ret;
- if (_fs_wait_for_readable (conn, FontServerRequestTimeout) != FSIO_READY)
- {
- _fs_connection_died (conn);
- return FSIO_ERROR;
- }
- }
- return FSIO_READY;
-}
-
-/*
- * Process the reply to an OpenBitmapFont request
- */
-static int
-fs_read_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
-{
- FSFpePtr conn = (FSFpePtr) fpe->private;
- FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
- fsOpenBitmapFontReply *rep;
- FSBlockDataPtr blockOrig;
- FSBlockedFontPtr origBfont;
- int ret;
-
- rep = (fsOpenBitmapFontReply *) fs_get_reply (conn, &ret);
- if (!rep || rep->type == FS_Error)
- {
- if (ret == FSIO_BLOCK)
- return StillWorking;
- if (rep)
- _fs_done_read (conn, rep->length << 2);
- fs_cleanup_bfont (bfont);
- return BadFontName;
- }
-
- /* 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))
- {
- fs_cleanup_bfont (bfont);
-
- /* Find old font if we're completely done getting it from server. */
- bfont->pfont = find_old_font(rep->otherid);
- bfont->freeFont = FALSE;
- bfont->fontid = rep->otherid;
- bfont->state = FS_DONE_REPLY;
- /*
- * look for a blocked request to open the same font
- */
- for (blockOrig = conn->blockedRequests;
- 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 */
- ret = BadFontName;
- }
- else
- ret = AccessDone;
- }
- else
- {
- bfont->pfont->info.cachable = rep->cachable != 0;
- bfont->state = FS_INFO_REPLY;
- /*
- * Reset the blockrec for the next reply
- */
- blockrec->sequenceNumber = bfont->queryInfoSequence;
- conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
- ret = StillWorking;
- }
- _fs_done_read (conn, rep->length << 2);
- return ret;
-}
-
-static Bool
-fs_fonts_match (FontInfoPtr pInfo1, FontInfoPtr pInfo2)
-{
- int i;
-
- if (pInfo1->firstCol != pInfo2->firstCol ||
- pInfo1->lastCol != pInfo2->lastCol ||
- pInfo1->firstRow != pInfo2->firstRow ||
- pInfo1->lastRow != pInfo2->lastRow ||
- pInfo1->defaultCh != pInfo2->defaultCh ||
- pInfo1->noOverlap != pInfo2->noOverlap ||
- pInfo1->terminalFont != pInfo2->terminalFont ||
- pInfo1->constantMetrics != pInfo2->constantMetrics ||
- pInfo1->constantWidth != pInfo2->constantWidth ||
- pInfo1->inkInside != pInfo2->inkInside ||
- pInfo1->inkMetrics != pInfo2->inkMetrics ||
- pInfo1->allExist != pInfo2->allExist ||
- pInfo1->drawDirection != pInfo2->drawDirection ||
- pInfo1->cachable != pInfo2->cachable ||
- pInfo1->anamorphic != pInfo2->anamorphic ||
- pInfo1->maxOverlap != pInfo2->maxOverlap ||
- pInfo1->fontAscent != pInfo2->fontAscent ||
- pInfo1->fontDescent != pInfo2->fontDescent ||
- pInfo1->nprops != pInfo2->nprops)
- return FALSE;
-
-#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(pInfo1->maxbounds, pInfo2->maxbounds) ||
- !MATCH(pInfo1->minbounds, pInfo2->minbounds) ||
- !MATCH(pInfo1->ink_maxbounds, pInfo2->ink_maxbounds) ||
- !MATCH(pInfo1->ink_minbounds, pInfo2->ink_minbounds))
- return FALSE;
-
-#undef MATCH
-
- for (i = 0; i < pInfo1->nprops; i++)
- if (pInfo1->isStringProp[i] !=
- pInfo2->isStringProp[i] ||
- pInfo1->props[i].name !=
- pInfo2->props[i].name ||
- pInfo1->props[i].value !=
- pInfo2->props[i].value)
- {
- return FALSE;
- }
- return TRUE;
-}
-
-static int
-fs_read_query_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
-{
- FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
- FSFpePtr conn = (FSFpePtr) fpe->private;
- fsQueryXInfoReply *rep;
- char *buf;
- fsPropInfo *pi;
- fsPropOffset *po;
- pointer pd;
- FontInfoPtr pInfo;
- FontInfoRec tempInfo;
- int err;
- int ret;
-
- rep = (fsQueryXInfoReply *) fs_get_reply (conn, &ret);
- if (!rep || rep->type == FS_Error)
- {
- if (ret == FSIO_BLOCK)
- return StillWorking;
- if (rep)
- _fs_done_read (conn, rep->length << 2);
- fs_cleanup_bfont (bfont);
- return BadFontName;
- }
-
- /* If this is a reopen, accumulate the query info into a dummy
- font and compare to our original data. */
- if (bfont->flags & FontReopen)
- pInfo = &tempInfo;
- else
- pInfo = &bfont->pfont->info;
-
- buf = (char *) rep;
- buf += SIZEOF(fsQueryXInfoReply);
-
- /* move the data over */
- fsUnpack_XFontInfoHeader(rep, pInfo);
-
- /* compute accelerators */
- _fs_init_fontinfo(conn, pInfo);
-
- /* Compute offsets into the reply */
- pi = (fsPropInfo *) buf;
- buf += SIZEOF (fsPropInfo);
-
- po = (fsPropOffset *) buf;
- buf += pi->num_offsets * SIZEOF(fsPropOffset);
-
- pd = (pointer) buf;
- buf += pi->data_len;
-
- /* convert the properties and step over the reply */
- ret = _fs_convert_props(pi, po, pd, pInfo);
- _fs_done_read (conn, rep->length << 2);
-
- if (ret == -1)
- {
- fs_cleanup_bfont (bfont);
- return AllocError;
- }
-
- if (bfont->flags & FontReopen)
- {
- /* 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 (fs_fonts_match (pInfo, &bfont->pfont->info))
- {
- err = Successful;
- bfont->state = FS_DONE_REPLY;
- }
- else
- {
- fs_cleanup_bfont (bfont);
- err = BadFontName;
- }
- _fs_free_props (pInfo);
-
- return err;
- }
-
- /*
- * Ask for terminal format fonts if possible
- */
- if (bfont->pfont->info.terminalFont)
- bfont->format = ((bfont->format & ~ (BitmapFormatImageRectMask)) |
- BitmapFormatImageRectMax);
-
- /*
- * Figure out if the whole font should get loaded right now.
- */
- if (glyphCachingMode == CACHING_OFF ||
- (glyphCachingMode == CACHE_16_BIT_GLYPHS
- && !bfont->pfont->info.lastRow))
- {
- bfont->flags |= FontLoadAll;
- }
-
- /*
- * Ready to send the query bitmaps; the terminal font bit has
- * been computed and glyphCaching has been considered
- */
- if (bfont->flags & FontLoadBitmaps)
- {
- fs_send_query_bitmaps (fpe, blockrec);
- _fs_flush (conn);
- }
-
- bfont->state = FS_EXTENT_REPLY;
-
- /*
- * Reset the blockrec for the next reply
- */
- blockrec->sequenceNumber = bfont->queryExtentsSequence;
- conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
-
- return StillWorking;
-}
-
-static int
-fs_read_extent_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
-{
- FSFpePtr conn = (FSFpePtr) fpe->private;
- FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
- FSFontDataPtr fsd = (FSFontDataPtr) bfont->pfont->fpePrivate;
- FSFontPtr fsfont = (FSFontPtr) bfont->pfont->fontPrivate;
- fsQueryXExtents16Reply *rep;
- char *buf;
- int i;
- int numExtents;
- int numInfos;
- int ret;
- Bool haveInk = FALSE; /* need separate ink metrics? */
- CharInfoPtr ci, pCI;
- char *fsci;
- fsXCharInfo fscilocal;
- FontInfoRec *fi = &bfont->pfont->info;
-
- rep = (fsQueryXExtents16Reply *) fs_get_reply (conn, &ret);
- if (!rep || rep->type == FS_Error)
- {
- if (ret == FSIO_BLOCK)
- return StillWorking;
- if (rep)
- _fs_done_read (conn, rep->length << 2);
- fs_cleanup_bfont (bfont);
- return BadFontName;
- }
-
- /* move the data over */
- /* need separate inkMetrics for fixed font server protocol version */
- numExtents = rep->num_extents;
- numInfos = numExtents;
- if (bfont->pfont->info.terminalFont && conn->fsMajorVersion > 1)
- {
- numInfos *= 2;
- haveInk = TRUE;
- }
- ci = pCI = malloc(sizeof(CharInfoRec) * numInfos);
-
- if (!pCI)
- {
- _fs_done_read (conn, rep->length << 2);
- fs_cleanup_bfont(bfont);
- return AllocError;
- }
- fsfont->encoding = pCI;
- if (haveInk)
- fsfont->inkMetrics = pCI + numExtents;
- else
- fsfont->inkMetrics = pCI;
-
- buf = (char *) rep;
- buf += SIZEOF (fsQueryXExtents16Reply);
- fsci = buf;
-
- fsd->glyphs_to_get = 0;
- ci = fsfont->inkMetrics;
- for (i = 0; i < numExtents; i++)
- {
- memcpy(&fscilocal, fsci, SIZEOF(fsXCharInfo)); /* align it */
- _fs_convert_char_info(&fscilocal, &ci->metrics);
- /* Bounds check. */
- if (ci->metrics.ascent > fi->maxbounds.ascent)
- {
- ErrorF("fserve: warning: %s %s ascent (%d) > maxascent (%d)\n",
- fpe->name, fsd->name,
- ci->metrics.ascent, fi->maxbounds.ascent);
- ci->metrics.ascent = fi->maxbounds.ascent;
- }
- if (ci->metrics.descent > fi->maxbounds.descent)
- {
- ErrorF("fserve: warning: %s %s descent (%d) > maxdescent (%d)\n",
- fpe->name, fsd->name,
- ci->metrics.descent, fi->maxbounds.descent);
- ci->metrics.descent = fi->maxbounds.descent;
- }
- fsci = fsci + 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++;
- }
-
- /* Done with reply */
- _fs_done_read (conn, rep->length << 2);
-
- /* build bitmap metrics, ImageRectMax style */
- if (haveInk)
- {
- CharInfoPtr ii;
-
- ci = fsfont->encoding;
- ii = fsfont->inkMetrics;
- for (i = 0; i < numExtents; 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;
- }
- /* Bounds check. */
- if (ci->metrics.ascent > fi->maxbounds.ascent)
- {
- ErrorF("fserve: warning: %s %s ascent (%d) "
- "> maxascent (%d)\n",
- fpe->name, fsd->name,
- ci->metrics.ascent, fi->maxbounds.ascent);
- ci->metrics.ascent = fi->maxbounds.ascent;
- }
- if (ci->metrics.descent > fi->maxbounds.descent)
- {
- ErrorF("fserve: warning: %s %s descent (%d) "
- "> maxdescent (%d)\n",
- fpe->name, fsd->name,
- ci->metrics.descent, fi->maxbounds.descent);
- ci->metrics.descent = fi->maxbounds.descent;
- }
- }
- }
- {
- 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)
- {
- /*
- * Reset the blockrec for the next reply
- */
- blockrec->sequenceNumber = bfont->queryBitmapsSequence;
- conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
- return StillWorking;
- }
- return Successful;
-}
-
-#ifdef DEBUG
-static char *fs_open_states[] = {
- "OPEN_REPLY ",
- "INFO_REPLY ",
- "EXTENT_REPLY",
- "GLYPHS_REPLY",
- "DONE_REPLY ",
- "DEPENDING ",
-};
-#endif
-
-static int
-fs_do_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
-{
- FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
- int err;
-
-#ifdef DEBUG
- fprintf (stderr, "fs_do_open_font state %s %s\n",
- fs_open_states[bfont->state],
- ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name);
-#endif
- err = BadFontName;
- switch (bfont->state) {
- case FS_OPEN_REPLY:
- err = fs_read_open_font(fpe, blockrec);
- if (err != StillWorking) { /* already loaded, or error */
- /* if font's already loaded, massage error code */
- switch (bfont->state) {
- case FS_DONE_REPLY:
- err = Successful;
- break;
- case FS_DEPENDING:
- err = StillWorking;
- break;
- }
- }
- break;
- case FS_INFO_REPLY:
- err = fs_read_query_info(fpe, blockrec);
- break;
- case FS_EXTENT_REPLY:
- err = fs_read_extent_info(fpe, blockrec);
- break;
- case FS_GLYPHS_REPLY:
- if (bfont->flags & FontLoadBitmaps)
- err = fs_read_glyphs(fpe, blockrec);
- break;
- case FS_DEPENDING: /* can't happen */
- default:
- break;
- }
-#ifdef DEBUG
- fprintf (stderr, "fs_do_open_font err %d\n", err);
-#endif
- if (err != StillWorking)
- {
- bfont->state = FS_DONE_REPLY; /* for _fs_load_glyphs() */
- while ((blockrec = blockrec->depending))
- {
- bfont = (FSBlockedFontPtr) blockrec->data;
- bfont->state = FS_DONE_REPLY; /* for _fs_load_glyphs() */
- }
- }
- return err;
-}
-
-void
-_fs_mark_block (FSFpePtr conn, CARD32 mask)
-{
- conn->blockState |= mask;
- fs_blockState |= mask;
-}
-
-void
-_fs_unmark_block (FSFpePtr conn, CARD32 mask)
-{
- FSFpePtr c;
-
- if (conn->blockState & mask)
- {
- conn->blockState &= ~mask;
- fs_blockState = 0;
- for (c = fs_fpes; c; c = c->next)
- fs_blockState |= c->blockState;
- }
-}
-
-/* ARGSUSED */
-static void
-fs_block_handler(pointer data, OSTimePtr wt, pointer LastSelectMask)
-{
- static struct timeval block_timeout;
- CARD32 now, earliest, wakeup;
- int soonest;
- FSFpePtr conn;
-
- XFD_ORSET((fd_set *)LastSelectMask, (fd_set *)LastSelectMask,
- &_fs_fd_mask);
- /*
- * Flush all pending output
- */
- if (fs_blockState & FS_PENDING_WRITE)
- for (conn = fs_fpes; conn; conn = conn->next)
- if (conn->blockState & FS_PENDING_WRITE)
- _fs_flush (conn);
- /*
- * Check for any fpe with a complete reply, set sleep time to zero
- */
- if (fs_blockState & FS_COMPLETE_REPLY)
- {
- block_timeout.tv_sec = 0;
- block_timeout.tv_usec = 0;
- if (*wt == NULL)
- *wt = &block_timeout;
- else
- **wt = block_timeout;
- }
- /*
- * Walk through fpe list computing sleep time
- */
- else if (fs_blockState & (FS_BROKEN_WRITE|
- FS_BROKEN_CONNECTION|
- FS_PENDING_REPLY|
- FS_RECONNECTING))
- {
- now = GetTimeInMillis ();
- earliest = now + 10000000;
- for (conn = fs_fpes; conn; conn = conn->next)
- {
- if (conn->blockState & FS_RECONNECTING)
- {
- wakeup = conn->blockedConnectTime;
- if (TimeCmp (wakeup, <, earliest))
- earliest = wakeup;
- }
- if (conn->blockState & FS_BROKEN_CONNECTION)
- {
- wakeup = conn->brokenConnectionTime;
- if (TimeCmp (wakeup, <, earliest))
- earliest = wakeup;
- }
- if (conn->blockState & FS_BROKEN_WRITE)
- {
- wakeup = conn->brokenWriteTime;
- if (TimeCmp (wakeup, <, earliest))
- earliest = wakeup;
- }
- if (conn->blockState & FS_PENDING_REPLY)
- {
- wakeup = conn->blockedReplyTime;
- if (TimeCmp (wakeup, <, earliest))
- earliest = wakeup;
- }
- }
- soonest = earliest - now;
- if (soonest < 0)
- soonest = 0;
- block_timeout.tv_sec = soonest / 1000;
- block_timeout.tv_usec = (soonest % 1000) * 1000;
- if (*wt == NULL)
- *wt = &block_timeout;
- else if (soonest < (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000)
- **wt = block_timeout;
- }
-}
-
-static void
-fs_handle_unexpected(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_done_read (conn, rep->length << 2);
-}
-
-static void
-fs_read_reply (FontPathElementPtr fpe, pointer client)
-{
- FSFpePtr conn = (FSFpePtr) fpe->private;
- FSBlockDataPtr blockrec;
- int ret;
- int err;
- fsGenericReply *rep;
-
- if ((rep = fs_get_reply (conn, &ret)))
- {
- _fs_add_rep_log (conn, rep);
- for (blockrec = conn->blockedRequests;
- blockrec;
- blockrec = blockrec->next)
- {
- if (blockrec->sequenceNumber == rep->sequenceNumber)
- break;
- }
- err = Successful;
- if (!blockrec)
- {
- fs_handle_unexpected(conn, rep);
- }
- else
- {
- /*
- * go read it, and if we're done,
- * wake up the appropriate client
- */
- switch (blockrec->type) {
- case FS_OPEN_FONT:
- blockrec->errcode = fs_do_open_font(fpe, blockrec);
- break;
- case FS_LOAD_GLYPHS:
- blockrec->errcode = fs_read_glyphs(fpe, blockrec);
- break;
- case FS_LIST_FONTS:
- blockrec->errcode = fs_read_list(fpe, blockrec);
- break;
- case FS_LIST_WITH_INFO:
- blockrec->errcode = fs_read_list_info(fpe, blockrec);
- break;
- default:
- break;
- }
- err = blockrec->errcode;
- if (err != StillWorking)
- {
- while (blockrec)
- {
- blockrec->errcode = err;
- if (client != blockrec->client)
- ClientSignal(blockrec->client);
- blockrec = blockrec->depending;
- }
- _fs_unmark_block (conn, FS_PENDING_REPLY);
- }
- }
- if (fs_reply_ready (conn))
- _fs_mark_block (conn, FS_COMPLETE_REPLY);
- else
- _fs_unmark_block (conn, FS_COMPLETE_REPLY);
- }
-}
-
-static int
-fs_wakeup(FontPathElementPtr fpe, unsigned long *mask)
-{
- fd_set *LastSelectMask = (fd_set *) mask;
- FSFpePtr conn = (FSFpePtr) fpe->private;
-
- /*
- * Don't continue if the fd is -1 (which will be true when the
- * font server terminates
- */
- if ((conn->blockState & FS_RECONNECTING))
- _fs_check_reconnect (conn);
- else if ((conn->blockState & FS_COMPLETE_REPLY) ||
- (conn->fs_fd != -1 && FD_ISSET(conn->fs_fd, LastSelectMask)))
- fs_read_reply (fpe, 0);
- if (conn->blockState & (FS_PENDING_REPLY|FS_BROKEN_CONNECTION|FS_BROKEN_WRITE))
- _fs_do_blocked (conn);
-#ifdef DEBUG
- {
- FSBlockDataPtr blockrec;
- FSBlockedFontPtr bfont;
- FSBlockedListPtr blist;
- static CARD32 lastState;
- static FSBlockDataPtr lastBlock;
-
- if (conn->blockState || conn->blockedRequests || lastState || lastBlock)
- {
- fprintf (stderr, " Block State 0x%x\n", (int) conn->blockState);
- lastState = conn->blockState;
- lastBlock = conn->blockedRequests;
- }
- for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
- {
- switch (blockrec->type) {
- case FS_OPEN_FONT:
- bfont = (FSBlockedFontPtr) blockrec->data;
- fprintf (stderr, " Blocked font errcode %d sequence %d state %s %s\n",
- blockrec->errcode,
- blockrec->sequenceNumber,
- fs_open_states[bfont->state],
- bfont->pfont ?
- ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name :
- "<freed>");
- break;
- case FS_LIST_FONTS:
- blist = (FSBlockedListPtr) blockrec->data;
- fprintf (stderr, " Blocked list errcode %d sequence %d\n",
- blockrec->errcode, blockrec->sequenceNumber);
- break;
- default:
- fprintf (stderr, " Blocked type %d errcode %d sequence %d\n",
- blockrec->type,
- blockrec->errcode,
- blockrec->sequenceNumber);
- break;
- }
- }
- }
-#endif
- return FALSE;
-}
-
-/*
- * Notice a dead connection and prepare for reconnect
- */
-
-void
-_fs_connection_died(FSFpePtr conn)
-{
- if (conn->blockState & FS_BROKEN_CONNECTION)
- return;
- fs_close_conn(conn);
- conn->brokenConnectionTime = GetTimeInMillis ();
- _fs_mark_block (conn, FS_BROKEN_CONNECTION);
- _fs_unmark_block (conn, FS_BROKEN_WRITE|FS_PENDING_WRITE|FS_RECONNECTING);
-}
-
-/*
- * Signal clients that the connection has come back up
- */
-static int
-_fs_restart_connection(FSFpePtr conn)
-{
- FSBlockDataPtr block;
-
- _fs_unmark_block (conn, FS_GIVE_UP);
- while ((block = (FSBlockDataPtr) conn->blockedRequests))
- {
- if (block->errcode == StillWorking)
- {
- ClientSignal(block->client);
- fs_abort_blockrec(conn, block);
- }
- }
- return TRUE;
-}
-
-/*
- * Declare this font server connection useless
- */
-static void
-_fs_giveup (FSFpePtr conn)
-{
- FSBlockDataPtr block;
-
- if (conn->blockState & FS_GIVE_UP)
- return;
-#ifdef DEBUG
- fprintf (stderr, "give up on FS \"%s\"\n", conn->servername);
-#endif
- _fs_mark_block (conn, FS_GIVE_UP);
- while ((block = (FSBlockDataPtr) conn->blockedRequests))
- {
- if (block->errcode == StillWorking)
- {
- ClientSignal (block->client);
- fs_abort_blockrec (conn, block);
- }
- }
- if (conn->fs_fd >= 0)
- _fs_connection_died (conn);
-}
-
-static void
-_fs_do_blocked (FSFpePtr conn)
-{
- CARD32 now;
-
- now = GetTimeInMillis ();
- if ((conn->blockState & FS_PENDING_REPLY) &&
- TimeCmp (conn->blockedReplyTime, <=, now))
- {
- _fs_giveup (conn);
- }
- else
- {
- if (conn->blockState & FS_BROKEN_CONNECTION)
- {
- /* Try to reconnect broken connections */
- if (TimeCmp (conn->brokenConnectionTime, <=, now))
- _fs_start_reconnect (conn);
- }
- else if (conn->blockState & FS_BROKEN_WRITE)
- {
- /* Try to flush blocked connections */
- if (TimeCmp (conn->brokenWriteTime, <=, now))
- _fs_flush (conn);
- }
- }
-}
-
-/*
- * sends the actual request out
- */
-/* ARGSUSED */
-static int
-fs_send_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
- char *name, int namelen,
- fsBitmapFormat format, fsBitmapFormatMask fmask,
- XID id, FontPtr *ppfont)
-{
- FSFpePtr conn = (FSFpePtr) fpe->private;
- FontPtr font;
- FSBlockDataPtr blockrec = NULL;
- FSBlockedFontPtr bfont;
- FSFontDataPtr fsd;
- fsOpenBitmapFontReq openreq;
- fsQueryXInfoReq inforeq;
- fsQueryXExtents16Req extreq;
- int err;
- unsigned char buf[1024];
-
- if (conn->blockState & FS_GIVE_UP)
- return BadFontName;
-
- if (namelen <= 0 || namelen > sizeof (buf) - 1)
- return BadFontName;
-
- /*
- * Get the font structure put together, either by reusing
- * the existing one or creating a new one
- */
- if (flags & FontReopen)
- {
- Atom nameatom, fn = None;
- int i;
-
- font = *ppfont;
- fsd = (FSFontDataPtr)font->fpePrivate;
- /* 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 < font->info.nprops; i++)
- if (font->info.props[i].name == nameatom &&
- font->info.isStringProp[i])
- {
- fn = font->info.props[i].value;
- break;
- }
- }
- if (fn == None || !(name = NameForAtom(fn)))
- {
- name = fsd->name;
- namelen = fsd->namelen;
- }
- else
- namelen = strlen(name);
- }
- else
- {
- font = fs_create_font (fpe, name, namelen, format, fmask);
- if (!font)
- return AllocError;
-
- fsd = (FSFontDataPtr)font->fpePrivate;
- }
-
- /* make a new block record, and add it to the end of the list */
- blockrec = fs_new_block_rec(font->fpe, client, FS_OPEN_FONT);
- if (!blockrec)
- {
- if (!(flags & FontReopen))
- (*font->unload_font) (font);
- return AllocError;
- }
-
- /*
- * Must check this before generating any protocol, otherwise we'll
- * mess up a reconnect in progress
- */
- if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
- {
- _fs_pending_reply (conn);
- return Suspended;
- }
-
- fsd->generation = conn->generation;
-
- bfont = (FSBlockedFontPtr) blockrec->data;
- bfont->fontid = fsd->fontid;
- bfont->pfont = font;
- bfont->state = FS_OPEN_REPLY;
- bfont->flags = flags;
- bfont->format = fsd->format;
- bfont->clients_depending = (FSClientsDependingPtr)0;
- bfont->freeFont = (flags & FontReopen) == 0;
-
- _fs_client_access (conn, client, (flags & FontOpenSync) != 0);
- _fs_client_resolution(conn);
-
- /* do an FS_OpenFont, FS_QueryXInfo and FS_QueryXExtents */
- buf[0] = (unsigned char) namelen;
- memcpy(&buf[1], name, namelen);
- openreq.reqType = FS_OpenBitmapFont;
- openreq.pad = 0;
- openreq.fid = fsd->fontid;
- openreq.format_hint = fsd->format;
- openreq.format_mask = fsd->fmask;
- openreq.length = (SIZEOF(fsOpenBitmapFontReq) + namelen + 4) >> 2;
-
- _fs_add_req_log(conn, FS_OpenBitmapFont);
- _fs_write(conn, (char *) &openreq, SIZEOF(fsOpenBitmapFontReq));
- _fs_write_pad(conn, (char *) buf, namelen + 1);
-
- blockrec->sequenceNumber = conn->current_seq;
-
- inforeq.reqType = FS_QueryXInfo;
- inforeq.pad = 0;
- inforeq.id = fsd->fontid;
- inforeq.length = SIZEOF(fsQueryXInfoReq) >> 2;
-
- bfont->queryInfoSequence = conn->current_seq + 1;
-
- _fs_add_req_log(conn, FS_QueryXInfo);
- _fs_write(conn, (char *) &inforeq, SIZEOF(fsQueryXInfoReq));
-
- if (!(bfont->flags & FontReopen))
- {
- extreq.reqType = FS_QueryXExtents16;
- extreq.range = fsTrue;
- extreq.fid = fsd->fontid;
- extreq.num_ranges = 0;
- extreq.length = SIZEOF(fsQueryXExtents16Req) >> 2;
-
- bfont->queryExtentsSequence = conn->current_seq + 1;
-
- _fs_add_req_log(conn, FS_QueryXExtents16);
- _fs_write(conn, (char *) &extreq, SIZEOF(fsQueryXExtents16Req));
- }
-
-#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, font->fpe->name);
- }
-#endif
- _fs_prepare_for_reply (conn);
-
- err = blockrec->errcode;
- if (bfont->flags & FontOpenSync)
- {
- while (blockrec->errcode == StillWorking)
- {
- if (fs_await_reply (conn) != FSIO_READY)
- {
- blockrec->errcode = BadFontName;
- break;
- }
- fs_read_reply (font->fpe, client);
- }
- err = blockrec->errcode;
- if (err == Successful)
- *ppfont = bfont->pfont;
- else
- fs_cleanup_bfont (bfont);
- bfont->freeFont = FALSE;
- _fs_remove_block_rec (conn, blockrec);
- }
- return err == StillWorking ? Suspended : err;
-}
-
-static void
-fs_send_query_bitmaps(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
-{
- FSFpePtr conn = (FSFpePtr) fpe->private;
- FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
- fsQueryXBitmaps16Req bitreq;
-
- /* 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;
-
- bfont->queryBitmapsSequence = conn->current_seq + 1;
-
- _fs_add_req_log(conn, FS_QueryXBitmaps16);
- _fs_write(conn, (char *) &bitreq, SIZEOF(fsQueryXBitmaps16Req));
-}
-
-/* ARGSUSED */
-static int
-fs_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
- char *name, int namelen,
- fsBitmapFormat format, fsBitmapFormatMask fmask,
- XID id, FontPtr *ppfont,
- char **alias, FontPtr non_cachable_font)
-{
- FSFpePtr conn = (FSFpePtr) fpe->private;
- FSBlockDataPtr blockrec;
- FSBlockedFontPtr bfont;
- int err;
-
- /* libfont interface expects ImageRectMin glyphs */
- format = (format & ~BitmapFormatImageRectMask) | BitmapFormatImageRectMin;
-
- *alias = (char *) 0;
- for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
- {
- if (blockrec->type == FS_OPEN_FONT && blockrec->client == client)
- {
- err = blockrec->errcode;
- if (err == StillWorking)
- return Suspended;
-
- bfont = (FSBlockedFontPtr) blockrec->data;
- if (err == Successful)
- *ppfont = bfont->pfont;
- else
- fs_cleanup_bfont (bfont);
- _fs_remove_block_rec (conn, blockrec);
- return err;
- }
- }
- return fs_send_open_font(client, fpe, flags, name, namelen, format, fmask,
- id, ppfont);
-}
-
-/* ARGSUSED */
-static int
-fs_send_close_font(FontPathElementPtr fpe, Font id)
-{
- FSFpePtr conn = (FSFpePtr) fpe->private;
- fsCloseReq req;
-
- if (conn->blockState & FS_GIVE_UP)
- return Successful;
- /* tell the font server to close the font */
- req.reqType = FS_CloseFont;
- req.pad = 0;
- 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 void
-fs_close_font(FontPathElementPtr fpe, FontPtr pfont)
-{
- FSFontDataPtr fsd = (FSFontDataPtr) pfont->fpePrivate;
- FSFpePtr conn = (FSFpePtr) fpe->private;
-
- if (conn->generation == fsd->generation)
- fs_send_close_font(fpe, fsd->fontid);
-
-#ifdef DEBUG
- {
- FSBlockDataPtr blockrec;
- FSBlockedFontPtr bfont;
-
- for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
- {
- if (blockrec->type == FS_OPEN_FONT)
- {
- bfont = (FSBlockedFontPtr) blockrec->data;
- if (bfont->pfont == pfont)
- fprintf (stderr, "closing font which hasn't been opened\n");
- }
- }
- }
-#endif
- (*pfont->unload_font) (pfont);
-}
-
-static int
-fs_read_glyphs(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;
- char *buf;
- fsOffset32 *ppbits;
- fsOffset32 local_off;
- char *off_adr;
- pointer pbitmaps;
- char *bits, *allbits;
-#ifdef DEBUG
- char *origallbits;
-#endif
- int i,
- err;
- int nranges = 0;
- int ret;
- fsRange *nextrange = 0;
- unsigned long minchar, maxchar;
-
- rep = (fsQueryXBitmaps16Reply *) fs_get_reply (conn, &ret);
- if (!rep || rep->type == FS_Error)
- {
- if (ret == FSIO_BLOCK)
- return StillWorking;
- if (rep)
- _fs_done_read (conn, rep->length << 2);
- err = AllocError;
- goto bail;
- }
-
- buf = (char *) rep;
- buf += SIZEOF (fsQueryXBitmaps16Reply);
-
- ppbits = (fsOffset32 *) buf;
- buf += SIZEOF (fsOffset32) * (rep->num_chars);
-
- pbitmaps = (pointer ) buf;
-
- if (blockrec->type == FS_LOAD_GLYPHS)
- {
- nranges = bglyph->num_expected_ranges;
- nextrange = 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;
-
- allbits = fs_alloc_glyphs (pfont, rep->nbytes);
-
- if (!allbits)
- {
- err = AllocError;
- goto bail;
- }
-
-#ifdef DEBUG
- origallbits = allbits;
- fprintf (stderr, "Reading %d glyphs in %d bytes for %s\n",
- (int) rep->num_chars, (int) rep->nbytes, fsd->name);
-#endif
-
- 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)
- {
- /*
- * Broken X font server returns bits for missing characters
- * when font is padded
- */
- if (NONZEROMETRICS(&fsdata->encoding[minchar].metrics))
- {
- if (local_off.length)
- {
- bits = allbits;
- allbits += local_off.length;
- memcpy(bits, (char *)pbitmaps + local_off.position,
- local_off.length);
- }
- else
- 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);
- }
-#ifdef DEBUG
- fprintf (stderr, "Used %d bytes instead of %d\n",
- (int) (allbits - origallbits), (int) rep->nbytes);
-#endif
-
- if (blockrec->type == FS_OPEN_FONT)
- {
- fsd->glyphs_to_get = 0;
- bfont->state = FS_DONE_REPLY;
- }
- err = Successful;
-
-bail:
- _fs_done_read (conn, rep->length << 2);
- return err;
-}
-
-static int
-fs_send_load_glyphs(pointer client, FontPtr pfont,
- int nranges, fsRange *ranges)
-{
- FontPathElementPtr fpe = pfont->fpe;
- FSFpePtr conn = (FSFpePtr) fpe->private;
- FSBlockedGlyphPtr blockedglyph;
- fsQueryXBitmaps16Req req;
- FSBlockDataPtr blockrec;
-
- if (conn->blockState & FS_GIVE_UP)
- return BadCharRange;
-
- /* 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->clients_depending = (FSClientsDependingPtr)0;
-
- if (conn->blockState & (FS_BROKEN_CONNECTION|FS_RECONNECTING))
- {
- _fs_pending_reply (conn);
- return Suspended;
- }
-
- /* 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));
-
- blockrec->sequenceNumber = conn->current_seq;
-
- /* 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);
- }
-
- _fs_prepare_for_reply (conn);
- return Suspended;
-}
-
-
-extern pointer serverClient; /* This could be any number that
- doesn't conflict with existing
- client values. */
-
-static int
-_fs_load_glyphs(pointer client, FontPtr pfont, Bool range_flag,
- unsigned int nchars, int item_size, unsigned char *data)
-{
- FSFpePtr conn = (FSFpePtr) pfont->fpe->private;
- int nranges = 0;
- fsRange *ranges = NULL;
- int res;
- FSBlockDataPtr blockrec;
- FSBlockedGlyphPtr blockedglyph;
- FSClientsDependingPtr *clients_depending = NULL;
- int err;
-
- /* see if the result is already there */
- for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
- {
- if (blockrec->type == FS_LOAD_GLYPHS)
- {
- blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
- if (blockedglyph->pfont == pfont)
- {
- /* Look for this request */
- if (blockrec->client == client)
- {
- err = blockrec->errcode;
- if (err == StillWorking)
- return Suspended;
- _fs_signal_clients_depending(&blockedglyph->clients_depending);
- _fs_remove_block_rec(conn, blockrec);
- return err;
- }
- /* 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)
- {
- /*
- * An OpenFont is pending for this font, this must
- * be from a reopen attempt, so finish the open
- * attempt and retry the LoadGlyphs
- */
- if (blockrec->client == client)
- {
- err = blockrec->errcode;
- if (err == StillWorking)
- return Suspended;
-
- _fs_signal_clients_depending(&bfont->clients_depending);
- _fs_remove_block_rec(conn, blockrec);
- if (err != Successful)
- return err;
- break;
- }
- /* 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 (blockrec->errcode == StillWorking)
- {
- clients_depending = &bfont->clients_depending;
- break;
- }
- }
- }
- }
-
- /*
- * 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);
- free(ranges);
- }
- return _fs_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);
- free(ranges);
-
- /* Now try to reopen the font. */
- return fs_send_open_font(client, pfont->fpe,
- (Mask)FontReopen, (char *)0, 0,
- (fsBitmapFormat)0, (fsBitmapFormatMask)0,
- (XID)0, &pfont);
- }
-
- return fs_send_load_glyphs(client, pfont, nranges, ranges);
-}
-
-int
-fs_load_all_glyphs(FontPtr pfont)
-{
- 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)
- {
- if (fs_await_reply (conn) != FSIO_READY)
- {
- /* Get rid of blockrec */
- fs_client_died(serverClient, pfont->fpe);
- err = BadCharRange;
- break;
- }
- fs_read_reply (pfont->fpe, serverClient);
- }
- return err;
-}
-
-static int
-fs_read_list(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
-{
- FSFpePtr conn = (FSFpePtr) fpe->private;
- FSBlockedListPtr blist = (FSBlockedListPtr) blockrec->data;
- fsListFontsReply *rep;
- char *data;
- int length,
- i,
- ret;
- int err;
-
- rep = (fsListFontsReply *) fs_get_reply (conn, &ret);
- if (!rep || rep->type == FS_Error)
- {
- if (ret == FSIO_BLOCK)
- return StillWorking;
- if (rep)
- _fs_done_read (conn, rep->length << 2);
- return AllocError;
- }
- data = (char *) rep + SIZEOF (fsListFontsReply);
-
- err = Successful;
- /* copy data into FontPathRecord */
- for (i = 0; i < rep->nFonts; i++)
- {
- length = *(unsigned char *)data++;
- err = AddFontNamesName(blist->names, data, length);
- if (err != Successful)
- break;
- data += length;
- }
- _fs_done_read (conn, rep->length << 2);
- return err;
-}
-
-static int
-fs_send_list_fonts(pointer client, FontPathElementPtr fpe, char *pattern,
- int patlen, int maxnames, FontNamesPtr newnames)
-{
- FSFpePtr conn = (FSFpePtr) fpe->private;
- FSBlockDataPtr blockrec;
- FSBlockedListPtr blockedlist;
- fsListFontsReq req;
-
- if (conn->blockState & FS_GIVE_UP)
- return BadFontName;
-
- /* 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->names = newnames;
-
- if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
- {
- _fs_pending_reply (conn);
- return Suspended;
- }
-
- _fs_client_access (conn, client, FALSE);
- _fs_client_resolution(conn);
-
- /* send the request */
- req.reqType = FS_ListFonts;
- req.pad = 0;
- 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);
-
- blockrec->sequenceNumber = conn->current_seq;
-
-#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
-
- _fs_prepare_for_reply (conn);
- return Suspended;
-}
-
-static int
-fs_list_fonts(pointer client, FontPathElementPtr fpe,
- char *pattern, int patlen, int maxnames, FontNamesPtr newnames)
-{
- FSFpePtr conn = (FSFpePtr) fpe->private;
- FSBlockDataPtr blockrec;
- int err;
-
- /* see if the result is already there */
- for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
- {
- if (blockrec->type == FS_LIST_FONTS && blockrec->client == client)
- {
- err = blockrec->errcode;
- if (err == StillWorking)
- return Suspended;
- _fs_remove_block_rec(conn, blockrec);
- return err;
- }
- }
-
- /* didn't find waiting record, so send a new one */
- return fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames);
-}
-
-/*
- * Read a single list info reply and restart for the next reply
- */
-static int
-fs_read_list_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
-{
- FSBlockedListInfoPtr binfo = (FSBlockedListInfoPtr) blockrec->data;
- fsListFontsWithXInfoReply *rep;
- char *buf;
- FSFpePtr conn = (FSFpePtr) fpe->private;
- fsPropInfo *pi;
- fsPropOffset *po;
- pointer pd;
- int ret;
- int err;
-
- /* clean up anything from the last trip */
- _fs_free_props (&binfo->info);
-
- rep = (fsListFontsWithXInfoReply *) fs_get_reply (conn, &ret);
- if (!rep || rep->type == FS_Error)
- {
- if (ret == FSIO_BLOCK)
- return StillWorking;
- binfo->status = FS_LFWI_FINISHED;
- err = AllocError;
- goto done;
- }
- /*
- * Normal termination -- the list ends with a name of length 0
- */
- if (rep->nameLength == 0)
- {
-#ifdef DEBUG
- fprintf (stderr, "fs_read_list_info done\n");
-#endif
- binfo->status = FS_LFWI_FINISHED;
- err = BadFontName;
- goto done;
- }
-
- buf = (char *) rep + SIZEOF (fsListFontsWithXInfoReply);
-
- /*
- * The original FS implementation didn't match
- * the spec, version 1 was respecified to match the FS.
- * Version 2 matches the original intent
- */
- if (conn->fsMajorVersion <= 1)
- {
- memcpy (binfo->name, buf, rep->nameLength);
- buf += _fs_pad_length (rep->nameLength);
- }
- pi = (fsPropInfo *) buf;
- buf += SIZEOF (fsPropInfo);
- po = (fsPropOffset *) buf;
- buf += pi->num_offsets * SIZEOF (fsPropOffset);
- pd = (pointer) buf;
- buf += pi->data_len;
- if (conn->fsMajorVersion > 1)
- {
- memcpy (binfo->name, buf, rep->nameLength);
- buf += _fs_pad_length (rep->nameLength);
- }
-
-#ifdef DEBUG
- binfo->name[rep->nameLength] = '\0';
- fprintf (stderr, "fs_read_list_info %s\n", binfo->name);
-#endif
- err = _fs_convert_lfwi_reply(conn, &binfo->info, rep, pi, po, pd);
- if (err != Successful)
- {
- binfo->status = FS_LFWI_FINISHED;
- goto done;
- }
- binfo->namelen = rep->nameLength;
- binfo->remaining = rep->nReplies;
-
- binfo->status = FS_LFWI_REPLY;
-
- /* disable this font server until we've processed this response */
- _fs_unmark_block (conn, FS_COMPLETE_REPLY);
- FD_CLR(conn->fs_fd, &_fs_fd_mask);
-done:
- _fs_done_read (conn, rep->length << 2);
- return err;
-}
-
-/* ARGSUSED */
-static int
-fs_start_list_with_info(pointer client, FontPathElementPtr fpe,
- char *pattern, int len, int maxnames, pointer *pdata)
-{
- FSFpePtr conn = (FSFpePtr) fpe->private;
- FSBlockDataPtr blockrec;
- FSBlockedListInfoPtr binfo;
- fsListFontsWithXInfoReq req;
-
- if (conn->blockState & FS_GIVE_UP)
- return BadFontName;
-
- /* 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;
-
- binfo = (FSBlockedListInfoPtr) blockrec->data;
- bzero((char *) binfo, sizeof(FSBlockedListInfoRec));
- binfo->status = FS_LFWI_WAITING;
-
- if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
- {
- _fs_pending_reply (conn);
- return Suspended;
- }
-
- _fs_client_access (conn, client, FALSE);
- _fs_client_resolution(conn);
-
- /* send the request */
- req.reqType = FS_ListFontsWithXInfo;
- req.pad = 0;
- 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);
-
- blockrec->sequenceNumber = conn->current_seq;
-
-#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
-
- _fs_prepare_for_reply (conn);
- return Successful;
-}
-
-/* ARGSUSED */
-static int
-fs_next_list_with_info(pointer client, FontPathElementPtr fpe,
- char **namep, int *namelenp,
- FontInfoPtr *pFontInfo, int *numFonts,
- pointer private)
-{
- FSFpePtr conn = (FSFpePtr) fpe->private;
- FSBlockDataPtr blockrec;
- FSBlockedListInfoPtr binfo;
- int err;
-
- /* see if the result is already there */
- for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
- if (blockrec->type == FS_LIST_WITH_INFO && blockrec->client == client)
- break;
-
- 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;
- }
-
- binfo = (FSBlockedListInfoPtr) blockrec->data;
-
- if (binfo->status == FS_LFWI_WAITING)
- return Suspended;
-
- *namep = binfo->name;
- *namelenp = binfo->namelen;
- *pFontInfo = &binfo->info;
- *numFonts = binfo->remaining;
-
- /* Restart reply processing from this font server */
- FD_SET(conn->fs_fd, &_fs_fd_mask);
- if (fs_reply_ready (conn))
- _fs_mark_block (conn, FS_COMPLETE_REPLY);
-
- err = blockrec->errcode;
- switch (binfo->status) {
- case FS_LFWI_FINISHED:
- _fs_remove_block_rec(conn, blockrec);
- break;
- case FS_LFWI_REPLY:
- binfo->status = FS_LFWI_WAITING;
- blockrec->errcode = StillWorking;
- conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
- _fs_mark_block (conn, FS_PENDING_REPLY);
- break;
- }
-
- return err;
-}
-
-/*
- * Called when client exits
- */
-
-static void
-fs_client_died(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.pad = 0;
- 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;
- free (cur);
- break;
- }
- }
- /* find a pending requests */
- for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
- if (blockrec->client == client)
- break;
-
- if (!blockrec)
- return;
-
- /* 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 (FSFpePtr conn, pointer client, Bool sync)
-{
- FSClientPtr *prev, cur;
- fsCreateACReq crac;
- fsSetAuthorizationReq setac;
- char *authorizations;
- int authlen;
- Bool new_cur = FALSE;
- char padding[4] = { 0, 0, 0, 0 };
-
-#ifdef DEBUG
- if (conn->blockState & (FS_RECONNECTING|FS_BROKEN_CONNECTION))
- {
- fprintf (stderr, "Sending requests without a connection\n");
- }
-#endif
- 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 = malloc (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.pad = 0;
- 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);
- /* Work around bug in xfs versions up through modular release 1.0.8
- which rejects CreateAC packets with num_auths = 0 & authlen < 4 */
- if (crac.num_auths == 0) {
- authorizations = padding;
- authlen = 4;
- } else {
- authlen = (authlen + 3) & ~0x3;
- }
- 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);
- /* 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.pad = 0;
- 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;
- }
-}
-
-/*
- * Poll a pending connect
- */
-
-static int
-_fs_check_connect (FSFpePtr conn)
-{
- int ret;
-
- ret = _fs_poll_connect (conn->trans_conn, 0);
- switch (ret) {
- case FSIO_READY:
- conn->fs_fd = _FontTransGetConnectionNumber (conn->trans_conn);
- FD_SET (conn->fs_fd, &_fs_fd_mask);
- break;
- case FSIO_BLOCK:
- break;
- }
- return ret;
-}
-
-/*
- * Return an FSIO status while waiting for the completed connection
- * reply to arrive
- */
-
-static fsConnSetup *
-_fs_get_conn_setup (FSFpePtr conn, int *error, int *setup_len)
-{
- int ret;
- char *data;
- int headlen;
- int len;
- fsConnSetup *setup;
- fsConnSetupAccept *accept;
-
- ret = _fs_start_read (conn, SIZEOF (fsConnSetup), &data);
- if (ret != FSIO_READY)
- {
- *error = ret;
- return 0;
- }
-
- setup = (fsConnSetup *) data;
- if (setup->major_version > FS_PROTOCOL)
- {
- *error = FSIO_ERROR;
- return 0;
- }
-
- headlen = (SIZEOF (fsConnSetup) +
- (setup->alternate_len << 2) +
- (setup->auth_len << 2));
- /* On anything but Success, no extra data is sent */
- if (setup->status != AuthSuccess)
- {
- len = headlen;
- }
- else
- {
- ret = _fs_start_read (conn, headlen + SIZEOF (fsConnSetupAccept), &data);
- if (ret != FSIO_READY)
- {
- *error = ret;
- return 0;
- }
- setup = (fsConnSetup *) data;
- accept = (fsConnSetupAccept *) (data + headlen);
- len = headlen + (accept->length << 2);
- }
- ret = _fs_start_read (conn, len, &data);
- if (ret != FSIO_READY)
- {
- *error = ret;
- return 0;
- }
- *setup_len = len;
- return (fsConnSetup *) data;
-}
-
-static int
-_fs_send_conn_client_prefix (FSFpePtr conn)
-{
- fsConnClientPrefix req;
- int endian;
- int ret;
-
- /* send setup prefix */
- endian = 1;
- if (*(char *) &endian)
- req.byteOrder = 'l';
- else
- req.byteOrder = 'B';
-
- req.major_version = FS_PROTOCOL;
- req.minor_version = FS_PROTOCOL_MINOR;
-
-/* XXX add some auth info here */
- req.num_auths = 0;
- req.auth_len = 0;
- ret = _fs_write (conn, (char *) &req, SIZEOF (fsConnClientPrefix));
- if (ret != FSIO_READY)
- return FSIO_ERROR;
- conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
- return ret;
-}
-
-static int
-_fs_recv_conn_setup (FSFpePtr conn)
-{
- int ret = FSIO_ERROR;
- fsConnSetup *setup;
- FSFpeAltPtr alts;
- int i, alt_len;
- int setup_len;
- char *alt_save, *alt_names;
-
- setup = _fs_get_conn_setup (conn, &ret, &setup_len);
- if (!setup)
- return ret;
- conn->current_seq = 0;
- conn->fsMajorVersion = setup->major_version;
- /*
- * Create an alternate list from the initial server, but
- * don't chain looking for alternates.
- */
- if (conn->alternate == 0)
- {
- /*
- * free any existing alternates list, allowing the list to
- * be updated
- */
- if (conn->alts)
- {
- free (conn->alts);
- conn->alts = 0;
- conn->numAlts = 0;
- }
- if (setup->num_alternates)
- {
- alts = malloc (setup->num_alternates * sizeof (FSFpeAltRec) +
- (setup->alternate_len << 2));
- if (alts)
- {
- alt_names = (char *) (setup + 1);
- alt_save = (char *) (alts + setup->num_alternates);
- for (i = 0; i < setup->num_alternates; i++)
- {
- alts[i].subset = alt_names[0];
- alt_len = alt_names[1];
- alts[i].name = alt_save;
- memcpy (alt_save, alt_names + 2, alt_len);
- alt_save[alt_len] = '\0';
- alt_save += alt_len + 1;
- alt_names += _fs_pad_length (alt_len + 2);
- }
- conn->numAlts = setup->num_alternates;
- conn->alts = alts;
- }
- }
- }
- _fs_done_read (conn, setup_len);
- if (setup->status != AuthSuccess)
- return FSIO_ERROR;
- return FSIO_READY;
-}
-
-static int
-_fs_open_server (FSFpePtr conn)
-{
- int ret;
- char *servername;
-
- if (conn->alternate == 0)
- servername = conn->servername;
- else
- servername = conn->alts[conn->alternate-1].name;
- conn->trans_conn = _fs_connect (servername, &ret);
- conn->blockedConnectTime = GetTimeInMillis () + FS_RECONNECT_WAIT;
- return ret;
-}
-
-static char *
-_fs_catalog_name (char *servername)
-{
- char *sp;
-
- sp = strchr (servername, '/');
- if (!sp)
- return 0;
- return strrchr (sp + 1, '/');
-}
-
-static int
-_fs_send_init_packets (FSFpePtr conn)
-{
- fsSetResolutionReq srreq;
- fsSetCataloguesReq screq;
- int num_cats,
- clen;
- char *catalogues;
- char *cat;
- char len;
- char *end;
- int num_res;
- FontResolutionPtr res;
-
-#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)) != FSIO_READY)
- return FSIO_ERROR;
- if (_fs_write_pad(conn, (char *) res, (num_res * SIZEOF(fsResolution))) != FSIO_READY)
- return FSIO_ERROR;
- }
-
- catalogues = 0;
- if (conn->alternate != 0)
- catalogues = _fs_catalog_name (conn->alts[conn->alternate-1].name);
- if (!catalogues)
- catalogues = _fs_catalog_name (conn->servername);
-
- if (!catalogues)
- {
- conn->has_catalogues = FALSE;
- return FSIO_READY;
- }
- conn->has_catalogues = TRUE;
-
- /* turn cats into counted list */
- catalogues++;
-
- cat = catalogues;
- num_cats = 0;
- clen = 0;
- while (*cat)
- {
- num_cats++;
- end = strchr(cat, CATALOGUE_SEP);
- if (!end)
- end = cat + strlen (cat);
- clen += (end - cat) + 1; /* length byte + string */
- cat = end;
- }
-
- 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)) != FSIO_READY)
- return FSIO_ERROR;
-
- while (*cat)
- {
- num_cats++;
- end = strchr(cat, CATALOGUE_SEP);
- if (!end)
- end = cat + strlen (cat);
- len = end - cat;
- if (_fs_write (conn, &len, 1) != FSIO_READY)
- return FSIO_ERROR;
- if (_fs_write (conn, cat, (int) len) != FSIO_READY)
- return FSIO_ERROR;
- cat = end;
- }
-
- if (_fs_write (conn, "....", _fs_pad_length (clen) - clen) != FSIO_READY)
- return FSIO_ERROR;
-
- return FSIO_READY;
-}
-
-static int
-_fs_send_cat_sync (FSFpePtr conn)
-{
- fsListCataloguesReq lcreq;
-
- /*
- * 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;
- lcreq.pad2 = 0;
- _fs_add_req_log(conn, FS_SetCatalogues);
- if (_fs_write(conn, (char *) &lcreq, SIZEOF(fsListCataloguesReq)) != FSIO_READY)
- return FSIO_ERROR;
- conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
- return FSIO_READY;
-}
-
-static int
-_fs_recv_cat_sync (FSFpePtr conn)
-{
- fsGenericReply *reply;
- fsError *error;
- int err;
- int ret;
-
- reply = fs_get_reply (conn, &err);
- if (!reply)
- return err;
-
- ret = FSIO_READY;
- if (reply->type == FS_Error)
- {
- error = (fsError *) reply;
- if (error->major_opcode == FS_SetCatalogues)
- ret = FSIO_ERROR;
- }
- _fs_done_read (conn, reply->length << 2);
- return ret;
-}
-
-static void
-_fs_close_server (FSFpePtr conn)
-{
- _fs_unmark_block (conn, FS_PENDING_WRITE|FS_BROKEN_WRITE|FS_COMPLETE_REPLY|FS_BROKEN_CONNECTION);
- if (conn->trans_conn)
- {
- _FontTransClose (conn->trans_conn);
- conn->trans_conn = 0;
- _fs_io_reinit (conn);
- }
- if (conn->fs_fd >= 0)
- {
- FD_CLR (conn->fs_fd, &_fs_fd_mask);
- conn->fs_fd = -1;
- }
- conn->fs_conn_state = FS_CONN_UNCONNECTED;
-}
-
-static int
-_fs_do_setup_connection (FSFpePtr conn)
-{
- int ret;
-
- do
- {
-#ifdef DEBUG
- fprintf (stderr, "fs_do_setup_connection state %d\n", conn->fs_conn_state);
-#endif
- switch (conn->fs_conn_state) {
- case FS_CONN_UNCONNECTED:
- ret = _fs_open_server (conn);
- if (ret == FSIO_BLOCK)
- conn->fs_conn_state = FS_CONN_CONNECTING;
- break;
- case FS_CONN_CONNECTING:
- ret = _fs_check_connect (conn);
- break;
- case FS_CONN_CONNECTED:
- ret = _fs_send_conn_client_prefix (conn);
- break;
- case FS_CONN_SENT_PREFIX:
- ret = _fs_recv_conn_setup (conn);
- break;
- case FS_CONN_RECV_INIT:
- ret = _fs_send_init_packets (conn);
- if (conn->has_catalogues)
- ret = _fs_send_cat_sync (conn);
- break;
- case FS_CONN_SENT_CAT:
- if (conn->has_catalogues)
- ret = _fs_recv_cat_sync (conn);
- else
- ret = FSIO_READY;
- break;
- default:
- ret = FSIO_READY;
- break;
- }
- switch (ret) {
- case FSIO_READY:
- if (conn->fs_conn_state < FS_CONN_RUNNING)
- conn->fs_conn_state++;
- break;
- case FSIO_BLOCK:
- if (TimeCmp (GetTimeInMillis (), <, conn->blockedConnectTime))
- break;
- ret = FSIO_ERROR;
- /* fall through... */
- case FSIO_ERROR:
- _fs_close_server (conn);
- /*
- * Try the next alternate
- */
- if (conn->alternate < conn->numAlts)
- {
- conn->alternate++;
- ret = FSIO_READY;
- }
- else
- conn->alternate = 0;
- break;
- }
- } while (conn->fs_conn_state != FS_CONN_RUNNING && ret == FSIO_READY);
- if (ret == FSIO_READY)
- conn->generation = ++generationCount;
- return ret;
-}
-
-static int
-_fs_wait_connect (FSFpePtr conn)
-{
- int ret;
-
- for (;;)
- {
- ret = _fs_do_setup_connection (conn);
- if (ret != FSIO_BLOCK)
- break;
- if (conn->fs_conn_state <= FS_CONN_CONNECTING)
- ret = _fs_poll_connect (conn->trans_conn, 1000);
- else
- ret = _fs_wait_for_readable (conn, 1000);
- if (ret == FSIO_ERROR)
- break;
- }
- return ret;
-}
-
-/*
- * Poll a connection in the process of reconnecting
- */
-static void
-_fs_check_reconnect (FSFpePtr conn)
-{
- int ret;
-
- ret = _fs_do_setup_connection (conn);
- switch (ret) {
- case FSIO_READY:
- _fs_unmark_block (conn, FS_RECONNECTING|FS_GIVE_UP);
- _fs_restart_connection (conn);
- break;
- case FSIO_BLOCK:
- break;
- case FSIO_ERROR:
- conn->brokenConnectionTime = GetTimeInMillis () + FS_RECONNECT_POLL;
- break;
- }
-}
-
-/*
- * Start the reconnection process
- */
-static void
-_fs_start_reconnect (FSFpePtr conn)
-{
- if (conn->blockState & FS_RECONNECTING)
- return;
- conn->alternate = 0;
- _fs_mark_block (conn, FS_RECONNECTING);
- _fs_unmark_block (conn, FS_BROKEN_CONNECTION);
- _fs_check_reconnect (conn);
-}
-
-
-static FSFpePtr
-_fs_init_conn (char *servername)
-{
- FSFpePtr conn;
-
- conn = calloc (1, sizeof (FSFpeRec) + strlen (servername) + 1);
- if (!conn)
- return 0;
- if (!_fs_io_init (conn))
- {
- free (conn);
- return 0;
- }
- conn->servername = (char *) (conn + 1);
- conn->fs_conn_state = FS_CONN_UNCONNECTED;
- conn->fs_fd = -1;
- strcpy (conn->servername, servername);
- return conn;
-}
-
-static void
-_fs_free_conn (FSFpePtr conn)
-{
- _fs_close_server (conn);
- _fs_io_fini (conn);
- if (conn->alts)
- free (conn->alts);
- free (conn);
-}
-
-/*
- * called at server init time
- */
-
-void
-fs_register_fpe_functions(void)
-{
- 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,
- NULL,
- NULL,
- NULL);
-}
+/* + +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 HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef WIN32 +#define _WILLWINSOCK_ +#endif +#define FONT_t +#define TRANS_CLIENT +#include "X11/Xtrans/Xtrans.h" +#include "X11/Xpoll.h" +#include <X11/fonts/FS.h> +#include <X11/fonts/FSproto.h> +#include <X11/X.h> +#include <X11/Xos.h> +#include <X11/fonts/fontmisc.h> +#include <X11/fonts/fontstruct.h> +#include "fservestr.h" +#include <X11/fonts/fontutil.h> +#include <errno.h> + +#include <time.h> +#define Time_t time_t + +#ifdef NCD +#include <ncd/nvram.h> +#endif + +#include <stddef.h> + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif +#define TimeCmp(a,c,b) ((int) ((a) - (b)) c 0) + +#define NONZEROMETRICS(pci) ((pci)->leftSideBearing || \ + (pci)->rightSideBearing || \ + (pci)->ascent || \ + (pci)->descent || \ + (pci)->characterWidth) + +extern void ErrorF(const char *f, ...); + +static int fs_read_glyphs ( FontPathElementPtr fpe, FSBlockDataPtr blockrec ); +static int fs_read_list ( FontPathElementPtr fpe, FSBlockDataPtr blockrec ); +static int fs_read_list_info ( FontPathElementPtr fpe, + FSBlockDataPtr blockrec ); + +extern fd_set _fs_fd_mask; + +static void fs_block_handler ( pointer data, OSTimePtr wt, + pointer LastSelectMask ); +static int fs_wakeup ( FontPathElementPtr fpe, unsigned long *mask ); + +/* + * List of all FPEs + */ +static FSFpePtr fs_fpes; +/* + * Union of all FPE blockStates + */ +static CARD32 fs_blockState; + +static int _fs_restart_connection ( FSFpePtr conn ); +static void fs_send_query_bitmaps ( FontPathElementPtr fpe, + FSBlockDataPtr blockrec ); +static int fs_send_close_font ( FontPathElementPtr fpe, Font id ); +static void fs_client_died ( pointer client, FontPathElementPtr fpe ); +static void _fs_client_access ( FSFpePtr conn, pointer client, Bool sync ); +static void _fs_client_resolution ( FSFpePtr conn ); +static fsGenericReply *fs_get_reply (FSFpePtr conn, int *error); +static int fs_await_reply (FSFpePtr conn); +static void _fs_do_blocked (FSFpePtr conn); +static void fs_cleanup_bfont (FSBlockedFontPtr bfont); + +char _fs_glyph_undefined; +char _fs_glyph_requested; +static char _fs_glyph_zero_length; + +static int generationCount; + +static int FontServerRequestTimeout = 30 * 1000; + +static void +_fs_close_server (FSFpePtr conn); + +static FSFpePtr +_fs_init_conn (char *servername); + +static int +_fs_wait_connect (FSFpePtr conn); + +static int +_fs_send_init_packets (FSFpePtr conn); + +static void +_fs_check_reconnect (FSFpePtr conn); + +static void +_fs_start_reconnect (FSFpePtr conn); + +static void +_fs_free_conn (FSFpePtr conn); + +static int +fs_free_fpe(FontPathElementPtr fpe); + +/* + * 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. + */ + + +#ifdef DEBUG +static void +_fs_add_req_log(FSFpePtr conn, int opcode) +{ + conn->current_seq++; + fprintf (stderr, "\t\tRequest: %5d Opcode: %2d\n", + conn->current_seq, opcode); + conn->reqbuffer[conn->reqindex].opcode = opcode; + conn->reqbuffer[conn->reqindex].sequence = conn->current_seq; + conn->reqindex++; + if (conn->reqindex == REQUEST_LOG_SIZE) + conn->reqindex = 0; +} + +static void +_fs_add_rep_log (FSFpePtr conn, fsGenericReply *rep) +{ + int i; + + for (i = 0; i < REQUEST_LOG_SIZE; i++) + if (conn->reqbuffer[i].sequence == rep->sequenceNumber) + break; + if (i == REQUEST_LOG_SIZE) + fprintf (stderr, "\t\t\t\t\tReply: %5d Opcode: unknown\n", + rep->sequenceNumber); + else + fprintf (stderr, "\t\t\t\t\tReply: %5d Opcode: %d\n", + rep->sequenceNumber, + conn->reqbuffer[i].opcode); +} +#else +#define _fs_add_req_log(conn,op) ((conn)->current_seq++) +#define _fs_add_rep_log(conn,rep) +#endif + +static Bool +fs_name_check(char *name) +{ + /* Just make sure there is a protocol/ prefix */ + return (name && *name != '/' && strchr(name, '/')); +} + +static void +_fs_client_resolution(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))); + } +} + +/* + * close font server and remove any state associated with + * this connection - this includes any client records. + */ + +static void +fs_close_conn(FSFpePtr conn) +{ + FSClientPtr client, nclient; + + _fs_close_server (conn); + + for (client = conn->clients; client; client = nclient) + { + nclient = client->next; + free (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(FontPathElementPtr fpe) +{ + FSFpePtr conn; + char *name; + int err; + int ret; + + /* open font server */ + /* create FS specific fpe info */ + name = fpe->name; + + /* hack for old style names */ + if (*name == ':') + name++; /* skip ':' */ + + conn = _fs_init_conn (name); + if (!conn) + err = AllocError; + else + { + err = init_fs_handlers (fpe, fs_block_handler); + if (err != Successful) + { + _fs_free_conn (conn); + err = AllocError; + } + else + { + fpe->private = conn; + conn->next = fs_fpes; + fs_fpes = conn; + ret = _fs_wait_connect (conn); + if (ret != FSIO_READY) + { + fs_free_fpe (fpe); + err = BadFontPath; + } + else + err = Successful; + } + } + + if (err == Successful) + { +#ifdef NCD + if (configData.ExtendedFontDiags) + printf("Connected to font server \"%s\"\n", name); +#endif +#ifdef DEBUG + fprintf (stderr, "connected to FS \"%s\"\n", name); +#endif + } + else + { +#ifdef DEBUG + fprintf(stderr, "failed to connect to FS \"%s\" %d\n", name, err); +#endif +#ifdef NCD + if (configData.ExtendedFontDiags) + printf("Failed to connect to font server \"%s\"\n", name); +#endif + ; + } + return err; +} + +static int +fs_reset_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(FontPathElementPtr fpe) +{ + FSFpePtr conn = (FSFpePtr) fpe->private, *prev; + + /* unhook from chain of all font servers */ + for (prev = &fs_fpes; *prev; prev = &(*prev)->next) + { + if (*prev == conn) + { + *prev = conn->next; + break; + } + } + _fs_unmark_block (conn, conn->blockState); + fs_close_conn(conn); + remove_fs_handlers(fpe, fs_block_handler, fs_fpes == 0); + _fs_free_conn (conn); + fpe->private = (pointer) 0; + +#ifdef NCD + if (configData.ExtendedFontDiags) + printf("Disconnected from font server \"%s\"\n", fpe->name); +#endif +#ifdef DEBUG + fprintf (stderr, "disconnect from FS \"%s\"\n", fpe->name); +#endif + + return Successful; +} + +static FSBlockDataPtr +fs_new_block_rec(FontPathElementPtr fpe, pointer client, int type) +{ + FSBlockDataPtr blockrec, + *prev; + FSFpePtr conn = (FSFpePtr) fpe->private; + int size; + + 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: + size = 0; + break; + } + blockrec = malloc(sizeof(FSBlockDataRec) + size); + if (!blockrec) + return (FSBlockDataPtr) 0; + blockrec->data = (pointer) (blockrec + 1); + blockrec->client = client; + blockrec->sequenceNumber = -1; + blockrec->errcode = StillWorking; + blockrec->type = type; + blockrec->depending = 0; + blockrec->next = (FSBlockDataPtr) 0; + + /* stick it on the end of the list (since its expected last) */ + for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next) + ; + *prev = blockrec; + + return blockrec; +} + +static void +_fs_set_pending_reply (FSFpePtr conn) +{ + FSBlockDataPtr blockrec; + + for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next) + if (blockrec->errcode == StillWorking) + break; + if (blockrec) + { + conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout; + _fs_mark_block (conn, FS_PENDING_REPLY); + } + else + _fs_unmark_block (conn, FS_PENDING_REPLY); +} + +static void +_fs_remove_block_rec(FSFpePtr conn, FSBlockDataPtr blockrec) +{ + FSBlockDataPtr *prev; + + for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next) + if (*prev == blockrec) + { + *prev = blockrec->next; + break; + } + if (blockrec->type == FS_LOAD_GLYPHS) + { + FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data; + if (bglyph->num_expected_ranges) + free(bglyph->expected_ranges); + } + free(blockrec); + _fs_set_pending_reply (conn); +} + +static void +_fs_signal_clients_depending(FSClientsDependingPtr *clients_depending) +{ + FSClientsDependingPtr p; + + while ((p = *clients_depending)) + { + *clients_depending = p->next; + ClientSignal(p->client); + free(p); + } +} + +static int +_fs_add_clients_depending(FSClientsDependingPtr *clients_depending, pointer client) +{ + FSClientsDependingPtr new, cd; + + for (; (cd = *clients_depending); + clients_depending = &(*clients_depending)->next) + { + if (cd->client == client) + return Suspended; + } + + new = malloc (sizeof (FSClientsDependingRec)); + if (!new) + return BadAlloc; + + new->client = client; + new->next = 0; + *clients_depending = new; + return Suspended; +} + +/* + * When a request is aborted due to a font server failure, + * signal any depending clients to restart their dependant + * requests + */ +static void +_fs_clean_aborted_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec) +{ + switch(blockrec->type) { + case FS_OPEN_FONT: { + FSBlockedFontPtr bfont = (FSBlockedFontPtr)blockrec->data; + + fs_cleanup_bfont (bfont); + _fs_signal_clients_depending(&bfont->clients_depending); + break; + } + case FS_LOAD_GLYPHS: { + FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data; + + _fs_clean_aborted_loadglyphs(bglyph->pfont, + bglyph->num_expected_ranges, + bglyph->expected_ranges); + _fs_signal_clients_depending(&bglyph->clients_depending); + break; + } + case FS_LIST_FONTS: + break; + case FS_LIST_WITH_INFO: { + FSBlockedListInfoPtr binfo; + binfo = (FSBlockedListInfoPtr) blockrec->data; + if (binfo->status == FS_LFWI_REPLY) + FD_SET(conn->fs_fd, &_fs_fd_mask); + _fs_free_props (&binfo->info); + } + default: + break; + } +} + +static void +fs_abort_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec) +{ + _fs_clean_aborted_blockrec (conn, blockrec); + _fs_remove_block_rec (conn, blockrec); +} + +/* + * Tell the font server we've failed to complete an open and + * then unload the partially created font + */ +static void +fs_cleanup_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(bfont->pfont->fpe, bfont->fontid); + + /* + * Either unload the font if it's being opened for + * the first time, or smash the generation field to + * mark this font as an orphan + */ + if (!(bfont->flags & FontReopen)) + { + if (bfont->freeFont) + (*bfont->pfont->unload_font) (bfont->pfont); +#ifdef DEBUG + else + fprintf (stderr, "Not freeing other font in cleanup_bfont\n"); +#endif + bfont->pfont = 0; + } + else + fsd->generation = -1; + } +} + +/* + * Check to see if a complete reply is waiting + */ +static fsGenericReply * +fs_get_reply (FSFpePtr conn, int *error) +{ + char *buf; + fsGenericReply *rep; + int ret; + + /* block if the connection is down or paused in lfwi */ + if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask)) + { + *error = FSIO_BLOCK; + return 0; + } + + ret = _fs_start_read (conn, sizeof (fsGenericReply), &buf); + if (ret != FSIO_READY) + { + *error = FSIO_BLOCK; + return 0; + } + + rep = (fsGenericReply *) buf; + + ret = _fs_start_read (conn, rep->length << 2, &buf); + if (ret != FSIO_READY) + { + *error = FSIO_BLOCK; + return 0; + } + + *error = FSIO_READY; + + return (fsGenericReply *) buf; +} + +static Bool +fs_reply_ready (FSFpePtr conn) +{ + fsGenericReply *rep; + + if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask)) + return FALSE; + if (fs_data_read (conn) < sizeof (fsGenericReply)) + return FALSE; + rep = (fsGenericReply *) (conn->inBuf.buf + conn->inBuf.remove); + if (fs_data_read (conn) < rep->length << 2) + return FALSE; + return TRUE; +} + +static void +_fs_pending_reply (FSFpePtr conn) +{ + if (!(conn->blockState & FS_PENDING_REPLY)) + { + _fs_mark_block (conn, FS_PENDING_REPLY); + conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout; + } +} + +static void +_fs_prepare_for_reply (FSFpePtr conn) +{ + _fs_pending_reply (conn); + _fs_flush (conn); +} + +/* + * Block (for a while) awaiting a complete reply + */ +static int +fs_await_reply (FSFpePtr conn) +{ + int ret; + + if (conn->blockState & FS_COMPLETE_REPLY) + return FSIO_READY; + + while (!fs_get_reply (conn, &ret)) + { + if (ret != FSIO_BLOCK) + return ret; + if (_fs_wait_for_readable (conn, FontServerRequestTimeout) != FSIO_READY) + { + _fs_connection_died (conn); + return FSIO_ERROR; + } + } + return FSIO_READY; +} + +/* + * Process the reply to an OpenBitmapFont request + */ +static int +fs_read_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec) +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + fsOpenBitmapFontReply *rep; + FSBlockDataPtr blockOrig; + FSBlockedFontPtr origBfont; + int ret; + + rep = (fsOpenBitmapFontReply *) fs_get_reply (conn, &ret); + if (!rep || rep->type == FS_Error) + { + if (ret == FSIO_BLOCK) + return StillWorking; + if (rep) + _fs_done_read (conn, rep->length << 2); + fs_cleanup_bfont (bfont); + return BadFontName; + } + + /* 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)) + { + fs_cleanup_bfont (bfont); + + /* Find old font if we're completely done getting it from server. */ + bfont->pfont = find_old_font(rep->otherid); + bfont->freeFont = FALSE; + bfont->fontid = rep->otherid; + bfont->state = FS_DONE_REPLY; + /* + * look for a blocked request to open the same font + */ + for (blockOrig = conn->blockedRequests; + 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 */ + ret = BadFontName; + } + else + ret = AccessDone; + } + else + { + bfont->pfont->info.cachable = rep->cachable != 0; + bfont->state = FS_INFO_REPLY; + /* + * Reset the blockrec for the next reply + */ + blockrec->sequenceNumber = bfont->queryInfoSequence; + conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout; + ret = StillWorking; + } + _fs_done_read (conn, rep->length << 2); + return ret; +} + +static Bool +fs_fonts_match (FontInfoPtr pInfo1, FontInfoPtr pInfo2) +{ + int i; + + if (pInfo1->firstCol != pInfo2->firstCol || + pInfo1->lastCol != pInfo2->lastCol || + pInfo1->firstRow != pInfo2->firstRow || + pInfo1->lastRow != pInfo2->lastRow || + pInfo1->defaultCh != pInfo2->defaultCh || + pInfo1->noOverlap != pInfo2->noOverlap || + pInfo1->terminalFont != pInfo2->terminalFont || + pInfo1->constantMetrics != pInfo2->constantMetrics || + pInfo1->constantWidth != pInfo2->constantWidth || + pInfo1->inkInside != pInfo2->inkInside || + pInfo1->inkMetrics != pInfo2->inkMetrics || + pInfo1->allExist != pInfo2->allExist || + pInfo1->drawDirection != pInfo2->drawDirection || + pInfo1->cachable != pInfo2->cachable || + pInfo1->anamorphic != pInfo2->anamorphic || + pInfo1->maxOverlap != pInfo2->maxOverlap || + pInfo1->fontAscent != pInfo2->fontAscent || + pInfo1->fontDescent != pInfo2->fontDescent || + pInfo1->nprops != pInfo2->nprops) + return FALSE; + +#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(pInfo1->maxbounds, pInfo2->maxbounds) || + !MATCH(pInfo1->minbounds, pInfo2->minbounds) || + !MATCH(pInfo1->ink_maxbounds, pInfo2->ink_maxbounds) || + !MATCH(pInfo1->ink_minbounds, pInfo2->ink_minbounds)) + return FALSE; + +#undef MATCH + + for (i = 0; i < pInfo1->nprops; i++) + if (pInfo1->isStringProp[i] != + pInfo2->isStringProp[i] || + pInfo1->props[i].name != + pInfo2->props[i].name || + pInfo1->props[i].value != + pInfo2->props[i].value) + { + return FALSE; + } + return TRUE; +} + +static int +fs_read_query_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec) +{ + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsQueryXInfoReply *rep; + char *buf; + fsPropInfo *pi; + fsPropOffset *po; + pointer pd; + FontInfoPtr pInfo; + FontInfoRec tempInfo; + int err; + int ret; + + rep = (fsQueryXInfoReply *) fs_get_reply (conn, &ret); + if (!rep || rep->type == FS_Error) + { + if (ret == FSIO_BLOCK) + return StillWorking; + if (rep) + _fs_done_read (conn, rep->length << 2); + fs_cleanup_bfont (bfont); + return BadFontName; + } + + /* If this is a reopen, accumulate the query info into a dummy + font and compare to our original data. */ + if (bfont->flags & FontReopen) + pInfo = &tempInfo; + else + pInfo = &bfont->pfont->info; + + buf = (char *) rep; + buf += SIZEOF(fsQueryXInfoReply); + + /* move the data over */ + fsUnpack_XFontInfoHeader(rep, pInfo); + + /* compute accelerators */ + _fs_init_fontinfo(conn, pInfo); + + /* Compute offsets into the reply */ + pi = (fsPropInfo *) buf; + buf += SIZEOF (fsPropInfo); + + po = (fsPropOffset *) buf; + buf += pi->num_offsets * SIZEOF(fsPropOffset); + + pd = (pointer) buf; + buf += pi->data_len; + + /* convert the properties and step over the reply */ + ret = _fs_convert_props(pi, po, pd, pInfo); + _fs_done_read (conn, rep->length << 2); + + if (ret == -1) + { + fs_cleanup_bfont (bfont); + return AllocError; + } + + if (bfont->flags & FontReopen) + { + /* 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 (fs_fonts_match (pInfo, &bfont->pfont->info)) + { + err = Successful; + bfont->state = FS_DONE_REPLY; + } + else + { + fs_cleanup_bfont (bfont); + err = BadFontName; + } + _fs_free_props (pInfo); + + return err; + } + + /* + * Ask for terminal format fonts if possible + */ + if (bfont->pfont->info.terminalFont) + bfont->format = ((bfont->format & ~ (BitmapFormatImageRectMask)) | + BitmapFormatImageRectMax); + + /* + * Figure out if the whole font should get loaded right now. + */ + if (glyphCachingMode == CACHING_OFF || + (glyphCachingMode == CACHE_16_BIT_GLYPHS + && !bfont->pfont->info.lastRow)) + { + bfont->flags |= FontLoadAll; + } + + /* + * Ready to send the query bitmaps; the terminal font bit has + * been computed and glyphCaching has been considered + */ + if (bfont->flags & FontLoadBitmaps) + { + fs_send_query_bitmaps (fpe, blockrec); + _fs_flush (conn); + } + + bfont->state = FS_EXTENT_REPLY; + + /* + * Reset the blockrec for the next reply + */ + blockrec->sequenceNumber = bfont->queryExtentsSequence; + conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout; + + return StillWorking; +} + +static int +fs_read_extent_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec) +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + FSFontDataPtr fsd = (FSFontDataPtr) bfont->pfont->fpePrivate; + FSFontPtr fsfont = (FSFontPtr) bfont->pfont->fontPrivate; + fsQueryXExtents16Reply *rep; + char *buf; + int i; + int numExtents; + int numInfos; + int ret; + Bool haveInk = FALSE; /* need separate ink metrics? */ + CharInfoPtr ci, pCI; + char *fsci; + fsXCharInfo fscilocal; + FontInfoRec *fi = &bfont->pfont->info; + + rep = (fsQueryXExtents16Reply *) fs_get_reply (conn, &ret); + if (!rep || rep->type == FS_Error) + { + if (ret == FSIO_BLOCK) + return StillWorking; + if (rep) + _fs_done_read (conn, rep->length << 2); + fs_cleanup_bfont (bfont); + return BadFontName; + } + + /* move the data over */ + /* need separate inkMetrics for fixed font server protocol version */ + numExtents = rep->num_extents; + numInfos = numExtents; + if (bfont->pfont->info.terminalFont && conn->fsMajorVersion > 1) + { + numInfos *= 2; + haveInk = TRUE; + } + ci = pCI = malloc(sizeof(CharInfoRec) * numInfos); + + if (!pCI) + { + _fs_done_read (conn, rep->length << 2); + fs_cleanup_bfont(bfont); + return AllocError; + } + fsfont->encoding = pCI; + if (haveInk) + fsfont->inkMetrics = pCI + numExtents; + else + fsfont->inkMetrics = pCI; + + buf = (char *) rep; + buf += SIZEOF (fsQueryXExtents16Reply); + fsci = buf; + + fsd->glyphs_to_get = 0; + ci = fsfont->inkMetrics; + for (i = 0; i < numExtents; i++) + { + memcpy(&fscilocal, fsci, SIZEOF(fsXCharInfo)); /* align it */ + _fs_convert_char_info(&fscilocal, &ci->metrics); + /* Bounds check. */ + if (ci->metrics.ascent > fi->maxbounds.ascent) + { + ErrorF("fserve: warning: %s %s ascent (%d) > maxascent (%d)\n", + fpe->name, fsd->name, + ci->metrics.ascent, fi->maxbounds.ascent); + ci->metrics.ascent = fi->maxbounds.ascent; + } + if (ci->metrics.descent > fi->maxbounds.descent) + { + ErrorF("fserve: warning: %s %s descent (%d) > maxdescent (%d)\n", + fpe->name, fsd->name, + ci->metrics.descent, fi->maxbounds.descent); + ci->metrics.descent = fi->maxbounds.descent; + } + fsci = fsci + 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++; + } + + /* Done with reply */ + _fs_done_read (conn, rep->length << 2); + + /* build bitmap metrics, ImageRectMax style */ + if (haveInk) + { + CharInfoPtr ii; + + ci = fsfont->encoding; + ii = fsfont->inkMetrics; + for (i = 0; i < numExtents; 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; + } + /* Bounds check. */ + if (ci->metrics.ascent > fi->maxbounds.ascent) + { + ErrorF("fserve: warning: %s %s ascent (%d) " + "> maxascent (%d)\n", + fpe->name, fsd->name, + ci->metrics.ascent, fi->maxbounds.ascent); + ci->metrics.ascent = fi->maxbounds.ascent; + } + if (ci->metrics.descent > fi->maxbounds.descent) + { + ErrorF("fserve: warning: %s %s descent (%d) " + "> maxdescent (%d)\n", + fpe->name, fsd->name, + ci->metrics.descent, fi->maxbounds.descent); + ci->metrics.descent = fi->maxbounds.descent; + } + } + } + { + 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) + { + /* + * Reset the blockrec for the next reply + */ + blockrec->sequenceNumber = bfont->queryBitmapsSequence; + conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout; + return StillWorking; + } + return Successful; +} + +#ifdef DEBUG +static char *fs_open_states[] = { + "OPEN_REPLY ", + "INFO_REPLY ", + "EXTENT_REPLY", + "GLYPHS_REPLY", + "DONE_REPLY ", + "DEPENDING ", +}; +#endif + +static int +fs_do_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec) +{ + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + int err; + +#ifdef DEBUG + fprintf (stderr, "fs_do_open_font state %s %s\n", + fs_open_states[bfont->state], + ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name); +#endif + err = BadFontName; + switch (bfont->state) { + case FS_OPEN_REPLY: + err = fs_read_open_font(fpe, blockrec); + if (err != StillWorking) { /* already loaded, or error */ + /* if font's already loaded, massage error code */ + switch (bfont->state) { + case FS_DONE_REPLY: + err = Successful; + break; + case FS_DEPENDING: + err = StillWorking; + break; + } + } + break; + case FS_INFO_REPLY: + err = fs_read_query_info(fpe, blockrec); + break; + case FS_EXTENT_REPLY: + err = fs_read_extent_info(fpe, blockrec); + break; + case FS_GLYPHS_REPLY: + if (bfont->flags & FontLoadBitmaps) + err = fs_read_glyphs(fpe, blockrec); + break; + case FS_DEPENDING: /* can't happen */ + default: + break; + } +#ifdef DEBUG + fprintf (stderr, "fs_do_open_font err %d\n", err); +#endif + if (err != StillWorking) + { + bfont->state = FS_DONE_REPLY; /* for _fs_load_glyphs() */ + while ((blockrec = blockrec->depending)) + { + bfont = (FSBlockedFontPtr) blockrec->data; + bfont->state = FS_DONE_REPLY; /* for _fs_load_glyphs() */ + } + } + return err; +} + +void +_fs_mark_block (FSFpePtr conn, CARD32 mask) +{ + conn->blockState |= mask; + fs_blockState |= mask; +} + +void +_fs_unmark_block (FSFpePtr conn, CARD32 mask) +{ + FSFpePtr c; + + if (conn->blockState & mask) + { + conn->blockState &= ~mask; + fs_blockState = 0; + for (c = fs_fpes; c; c = c->next) + fs_blockState |= c->blockState; + } +} + +/* ARGSUSED */ +static void +fs_block_handler(pointer data, OSTimePtr wt, pointer LastSelectMask) +{ + static struct timeval block_timeout; + CARD32 now, earliest, wakeup; + int soonest; + FSFpePtr conn; + + XFD_ORSET((fd_set *)LastSelectMask, (fd_set *)LastSelectMask, + &_fs_fd_mask); + /* + * Flush all pending output + */ + if (fs_blockState & FS_PENDING_WRITE) + for (conn = fs_fpes; conn; conn = conn->next) + if (conn->blockState & FS_PENDING_WRITE) + _fs_flush (conn); + /* + * Check for any fpe with a complete reply, set sleep time to zero + */ + if (fs_blockState & FS_COMPLETE_REPLY) + { + block_timeout.tv_sec = 0; + block_timeout.tv_usec = 0; + if (*wt == NULL) + *wt = &block_timeout; + else + **wt = block_timeout; + } + /* + * Walk through fpe list computing sleep time + */ + else if (fs_blockState & (FS_BROKEN_WRITE| + FS_BROKEN_CONNECTION| + FS_PENDING_REPLY| + FS_RECONNECTING)) + { + now = GetTimeInMillis (); + earliest = now + 10000000; + for (conn = fs_fpes; conn; conn = conn->next) + { + if (conn->blockState & FS_RECONNECTING) + { + wakeup = conn->blockedConnectTime; + if (TimeCmp (wakeup, <, earliest)) + earliest = wakeup; + } + if (conn->blockState & FS_BROKEN_CONNECTION) + { + wakeup = conn->brokenConnectionTime; + if (TimeCmp (wakeup, <, earliest)) + earliest = wakeup; + } + if (conn->blockState & FS_BROKEN_WRITE) + { + wakeup = conn->brokenWriteTime; + if (TimeCmp (wakeup, <, earliest)) + earliest = wakeup; + } + if (conn->blockState & FS_PENDING_REPLY) + { + wakeup = conn->blockedReplyTime; + if (TimeCmp (wakeup, <, earliest)) + earliest = wakeup; + } + } + soonest = earliest - now; + if (soonest < 0) + soonest = 0; + block_timeout.tv_sec = soonest / 1000; + block_timeout.tv_usec = (soonest % 1000) * 1000; + if (*wt == NULL) + *wt = &block_timeout; + else if (soonest < (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000) + **wt = block_timeout; + } +} + +static void +fs_handle_unexpected(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_done_read (conn, rep->length << 2); +} + +static void +fs_read_reply (FontPathElementPtr fpe, pointer client) +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockDataPtr blockrec; + int ret; + int err; + fsGenericReply *rep; + + if ((rep = fs_get_reply (conn, &ret))) + { + _fs_add_rep_log (conn, rep); + for (blockrec = conn->blockedRequests; + blockrec; + blockrec = blockrec->next) + { + if (blockrec->sequenceNumber == rep->sequenceNumber) + break; + } + err = Successful; + if (!blockrec) + { + fs_handle_unexpected(conn, rep); + } + else + { + /* + * go read it, and if we're done, + * wake up the appropriate client + */ + switch (blockrec->type) { + case FS_OPEN_FONT: + blockrec->errcode = fs_do_open_font(fpe, blockrec); + break; + case FS_LOAD_GLYPHS: + blockrec->errcode = fs_read_glyphs(fpe, blockrec); + break; + case FS_LIST_FONTS: + blockrec->errcode = fs_read_list(fpe, blockrec); + break; + case FS_LIST_WITH_INFO: + blockrec->errcode = fs_read_list_info(fpe, blockrec); + break; + default: + break; + } + err = blockrec->errcode; + if (err != StillWorking) + { + while (blockrec) + { + blockrec->errcode = err; + if (client != blockrec->client) + ClientSignal(blockrec->client); + blockrec = blockrec->depending; + } + _fs_unmark_block (conn, FS_PENDING_REPLY); + } + } + if (fs_reply_ready (conn)) + _fs_mark_block (conn, FS_COMPLETE_REPLY); + else + _fs_unmark_block (conn, FS_COMPLETE_REPLY); + } +} + +static int +fs_wakeup(FontPathElementPtr fpe, unsigned long *mask) +{ + fd_set *LastSelectMask = (fd_set *) mask; + FSFpePtr conn = (FSFpePtr) fpe->private; + + /* + * Don't continue if the fd is -1 (which will be true when the + * font server terminates + */ + if ((conn->blockState & FS_RECONNECTING)) + _fs_check_reconnect (conn); + else if ((conn->blockState & FS_COMPLETE_REPLY) || + (conn->fs_fd != -1 && FD_ISSET(conn->fs_fd, LastSelectMask))) + fs_read_reply (fpe, 0); + if (conn->blockState & (FS_PENDING_REPLY|FS_BROKEN_CONNECTION|FS_BROKEN_WRITE)) + _fs_do_blocked (conn); +#ifdef DEBUG + { + FSBlockDataPtr blockrec; + FSBlockedFontPtr bfont; + FSBlockedListPtr blist; + static CARD32 lastState; + static FSBlockDataPtr lastBlock; + + if (conn->blockState || conn->blockedRequests || lastState || lastBlock) + { + fprintf (stderr, " Block State 0x%x\n", (int) conn->blockState); + lastState = conn->blockState; + lastBlock = conn->blockedRequests; + } + for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next) + { + switch (blockrec->type) { + case FS_OPEN_FONT: + bfont = (FSBlockedFontPtr) blockrec->data; + fprintf (stderr, " Blocked font errcode %d sequence %d state %s %s\n", + blockrec->errcode, + blockrec->sequenceNumber, + fs_open_states[bfont->state], + bfont->pfont ? + ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name : + "<freed>"); + break; + case FS_LIST_FONTS: + blist = (FSBlockedListPtr) blockrec->data; + fprintf (stderr, " Blocked list errcode %d sequence %d\n", + blockrec->errcode, blockrec->sequenceNumber); + break; + default: + fprintf (stderr, " Blocked type %d errcode %d sequence %d\n", + blockrec->type, + blockrec->errcode, + blockrec->sequenceNumber); + break; + } + } + } +#endif + return FALSE; +} + +/* + * Notice a dead connection and prepare for reconnect + */ + +void +_fs_connection_died(FSFpePtr conn) +{ + if (conn->blockState & FS_BROKEN_CONNECTION) + return; + fs_close_conn(conn); + conn->brokenConnectionTime = GetTimeInMillis (); + _fs_mark_block (conn, FS_BROKEN_CONNECTION); + _fs_unmark_block (conn, FS_BROKEN_WRITE|FS_PENDING_WRITE|FS_RECONNECTING); +} + +/* + * Signal clients that the connection has come back up + */ +static int +_fs_restart_connection(FSFpePtr conn) +{ + FSBlockDataPtr block; + + _fs_unmark_block (conn, FS_GIVE_UP); + while ((block = (FSBlockDataPtr) conn->blockedRequests)) + { + if (block->errcode == StillWorking) + { + ClientSignal(block->client); + fs_abort_blockrec(conn, block); + } + } + return TRUE; +} + +/* + * Declare this font server connection useless + */ +static void +_fs_giveup (FSFpePtr conn) +{ + FSBlockDataPtr block; + + if (conn->blockState & FS_GIVE_UP) + return; +#ifdef DEBUG + fprintf (stderr, "give up on FS \"%s\"\n", conn->servername); +#endif + _fs_mark_block (conn, FS_GIVE_UP); + while ((block = (FSBlockDataPtr) conn->blockedRequests)) + { + if (block->errcode == StillWorking) + { + ClientSignal (block->client); + fs_abort_blockrec (conn, block); + } + } + if (conn->fs_fd >= 0) + _fs_connection_died (conn); +} + +static void +_fs_do_blocked (FSFpePtr conn) +{ + CARD32 now; + + now = GetTimeInMillis (); + if ((conn->blockState & FS_PENDING_REPLY) && + TimeCmp (conn->blockedReplyTime, <=, now)) + { + _fs_giveup (conn); + } + else + { + if (conn->blockState & FS_BROKEN_CONNECTION) + { + /* Try to reconnect broken connections */ + if (TimeCmp (conn->brokenConnectionTime, <=, now)) + _fs_start_reconnect (conn); + } + else if (conn->blockState & FS_BROKEN_WRITE) + { + /* Try to flush blocked connections */ + if (TimeCmp (conn->brokenWriteTime, <=, now)) + _fs_flush (conn); + } + } +} + +/* + * sends the actual request out + */ +/* ARGSUSED */ +static int +fs_send_open_font(pointer client, FontPathElementPtr fpe, Mask flags, + char *name, int namelen, + fsBitmapFormat format, fsBitmapFormatMask fmask, + XID id, FontPtr *ppfont) +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FontPtr font; + FSBlockDataPtr blockrec = NULL; + FSBlockedFontPtr bfont; + FSFontDataPtr fsd; + fsOpenBitmapFontReq openreq; + fsQueryXInfoReq inforeq; + fsQueryXExtents16Req extreq; + int err; + unsigned char buf[1024]; + + if (conn->blockState & FS_GIVE_UP) + return BadFontName; + + if (namelen <= 0 || namelen > sizeof (buf) - 1) + return BadFontName; + + /* + * Get the font structure put together, either by reusing + * the existing one or creating a new one + */ + if (flags & FontReopen) + { + Atom nameatom, fn = None; + int i; + + font = *ppfont; + fsd = (FSFontDataPtr)font->fpePrivate; + /* 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 < font->info.nprops; i++) + if (font->info.props[i].name == nameatom && + font->info.isStringProp[i]) + { + fn = font->info.props[i].value; + break; + } + } + if (fn == None || !(name = NameForAtom(fn))) + { + name = fsd->name; + namelen = fsd->namelen; + } + else + namelen = strlen(name); + } + else + { + font = fs_create_font (fpe, name, namelen, format, fmask); + if (!font) + return AllocError; + + fsd = (FSFontDataPtr)font->fpePrivate; + } + + /* make a new block record, and add it to the end of the list */ + blockrec = fs_new_block_rec(font->fpe, client, FS_OPEN_FONT); + if (!blockrec) + { + if (!(flags & FontReopen)) + (*font->unload_font) (font); + return AllocError; + } + + /* + * Must check this before generating any protocol, otherwise we'll + * mess up a reconnect in progress + */ + if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING)) + { + _fs_pending_reply (conn); + return Suspended; + } + + fsd->generation = conn->generation; + + bfont = (FSBlockedFontPtr) blockrec->data; + bfont->fontid = fsd->fontid; + bfont->pfont = font; + bfont->state = FS_OPEN_REPLY; + bfont->flags = flags; + bfont->format = fsd->format; + bfont->clients_depending = (FSClientsDependingPtr)0; + bfont->freeFont = (flags & FontReopen) == 0; + + _fs_client_access (conn, client, (flags & FontOpenSync) != 0); + _fs_client_resolution(conn); + + /* do an FS_OpenFont, FS_QueryXInfo and FS_QueryXExtents */ + buf[0] = (unsigned char) namelen; + memcpy(&buf[1], name, namelen); + openreq.reqType = FS_OpenBitmapFont; + openreq.pad = 0; + openreq.fid = fsd->fontid; + openreq.format_hint = fsd->format; + openreq.format_mask = fsd->fmask; + openreq.length = (SIZEOF(fsOpenBitmapFontReq) + namelen + 4) >> 2; + + _fs_add_req_log(conn, FS_OpenBitmapFont); + _fs_write(conn, (char *) &openreq, SIZEOF(fsOpenBitmapFontReq)); + _fs_write_pad(conn, (char *) buf, namelen + 1); + + blockrec->sequenceNumber = conn->current_seq; + + inforeq.reqType = FS_QueryXInfo; + inforeq.pad = 0; + inforeq.id = fsd->fontid; + inforeq.length = SIZEOF(fsQueryXInfoReq) >> 2; + + bfont->queryInfoSequence = conn->current_seq + 1; + + _fs_add_req_log(conn, FS_QueryXInfo); + _fs_write(conn, (char *) &inforeq, SIZEOF(fsQueryXInfoReq)); + + if (!(bfont->flags & FontReopen)) + { + extreq.reqType = FS_QueryXExtents16; + extreq.range = fsTrue; + extreq.fid = fsd->fontid; + extreq.num_ranges = 0; + extreq.length = SIZEOF(fsQueryXExtents16Req) >> 2; + + bfont->queryExtentsSequence = conn->current_seq + 1; + + _fs_add_req_log(conn, FS_QueryXExtents16); + _fs_write(conn, (char *) &extreq, SIZEOF(fsQueryXExtents16Req)); + } + +#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, font->fpe->name); + } +#endif + _fs_prepare_for_reply (conn); + + err = blockrec->errcode; + if (bfont->flags & FontOpenSync) + { + while (blockrec->errcode == StillWorking) + { + if (fs_await_reply (conn) != FSIO_READY) + { + blockrec->errcode = BadFontName; + break; + } + fs_read_reply (font->fpe, client); + } + err = blockrec->errcode; + if (err == Successful) + *ppfont = bfont->pfont; + else + fs_cleanup_bfont (bfont); + bfont->freeFont = FALSE; + _fs_remove_block_rec (conn, blockrec); + } + return err == StillWorking ? Suspended : err; +} + +static void +fs_send_query_bitmaps(FontPathElementPtr fpe, FSBlockDataPtr blockrec) +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + fsQueryXBitmaps16Req bitreq; + + /* 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; + + bfont->queryBitmapsSequence = conn->current_seq + 1; + + _fs_add_req_log(conn, FS_QueryXBitmaps16); + _fs_write(conn, (char *) &bitreq, SIZEOF(fsQueryXBitmaps16Req)); +} + +/* ARGSUSED */ +static int +fs_open_font(pointer client, FontPathElementPtr fpe, Mask flags, + char *name, int namelen, + fsBitmapFormat format, fsBitmapFormatMask fmask, + XID id, FontPtr *ppfont, + char **alias, FontPtr non_cachable_font) +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockDataPtr blockrec; + FSBlockedFontPtr bfont; + int err; + + /* libfont interface expects ImageRectMin glyphs */ + format = (format & ~BitmapFormatImageRectMask) | BitmapFormatImageRectMin; + + *alias = (char *) 0; + for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next) + { + if (blockrec->type == FS_OPEN_FONT && blockrec->client == client) + { + err = blockrec->errcode; + if (err == StillWorking) + return Suspended; + + bfont = (FSBlockedFontPtr) blockrec->data; + if (err == Successful) + *ppfont = bfont->pfont; + else + fs_cleanup_bfont (bfont); + _fs_remove_block_rec (conn, blockrec); + return err; + } + } + return fs_send_open_font(client, fpe, flags, name, namelen, format, fmask, + id, ppfont); +} + +/* ARGSUSED */ +static int +fs_send_close_font(FontPathElementPtr fpe, Font id) +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + fsCloseReq req; + + if (conn->blockState & FS_GIVE_UP) + return Successful; + /* tell the font server to close the font */ + req.reqType = FS_CloseFont; + req.pad = 0; + 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 void +fs_close_font(FontPathElementPtr fpe, FontPtr pfont) +{ + FSFontDataPtr fsd = (FSFontDataPtr) pfont->fpePrivate; + FSFpePtr conn = (FSFpePtr) fpe->private; + + if (conn->generation == fsd->generation) + fs_send_close_font(fpe, fsd->fontid); + +#ifdef DEBUG + { + FSBlockDataPtr blockrec; + FSBlockedFontPtr bfont; + + for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next) + { + if (blockrec->type == FS_OPEN_FONT) + { + bfont = (FSBlockedFontPtr) blockrec->data; + if (bfont->pfont == pfont) + fprintf (stderr, "closing font which hasn't been opened\n"); + } + } + } +#endif + (*pfont->unload_font) (pfont); +} + +static int +fs_read_glyphs(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; + char *buf; + fsOffset32 *ppbits; + fsOffset32 local_off; + char *off_adr; + pointer pbitmaps; + char *bits, *allbits; +#ifdef DEBUG + char *origallbits; +#endif + int i, + err; + int nranges = 0; + int ret; + fsRange *nextrange = 0; + unsigned long minchar, maxchar; + + rep = (fsQueryXBitmaps16Reply *) fs_get_reply (conn, &ret); + if (!rep || rep->type == FS_Error) + { + if (ret == FSIO_BLOCK) + return StillWorking; + if (rep) + _fs_done_read (conn, rep->length << 2); + err = AllocError; + goto bail; + } + + buf = (char *) rep; + buf += SIZEOF (fsQueryXBitmaps16Reply); + + ppbits = (fsOffset32 *) buf; + buf += SIZEOF (fsOffset32) * (rep->num_chars); + + pbitmaps = (pointer ) buf; + + if (blockrec->type == FS_LOAD_GLYPHS) + { + nranges = bglyph->num_expected_ranges; + nextrange = 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; + + allbits = fs_alloc_glyphs (pfont, rep->nbytes); + + if (!allbits) + { + err = AllocError; + goto bail; + } + +#ifdef DEBUG + origallbits = allbits; + fprintf (stderr, "Reading %d glyphs in %d bytes for %s\n", + (int) rep->num_chars, (int) rep->nbytes, fsd->name); +#endif + + 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) + { + /* + * Broken X font server returns bits for missing characters + * when font is padded + */ + if (NONZEROMETRICS(&fsdata->encoding[minchar].metrics)) + { + if (local_off.length) + { + bits = allbits; + allbits += local_off.length; + memcpy(bits, (char *)pbitmaps + local_off.position, + local_off.length); + } + else + 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); + } +#ifdef DEBUG + fprintf (stderr, "Used %d bytes instead of %d\n", + (int) (allbits - origallbits), (int) rep->nbytes); +#endif + + if (blockrec->type == FS_OPEN_FONT) + { + fsd->glyphs_to_get = 0; + bfont->state = FS_DONE_REPLY; + } + err = Successful; + +bail: + _fs_done_read (conn, rep->length << 2); + return err; +} + +static int +fs_send_load_glyphs(pointer client, FontPtr pfont, + int nranges, fsRange *ranges) +{ + FontPathElementPtr fpe = pfont->fpe; + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockedGlyphPtr blockedglyph; + fsQueryXBitmaps16Req req; + FSBlockDataPtr blockrec; + + if (conn->blockState & FS_GIVE_UP) + return BadCharRange; + + /* 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->clients_depending = (FSClientsDependingPtr)0; + + if (conn->blockState & (FS_BROKEN_CONNECTION|FS_RECONNECTING)) + { + _fs_pending_reply (conn); + return Suspended; + } + + /* 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)); + + blockrec->sequenceNumber = conn->current_seq; + + /* 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); + } + + _fs_prepare_for_reply (conn); + return Suspended; +} + + +extern pointer serverClient; /* This could be any number that + doesn't conflict with existing + client values. */ + +static int +_fs_load_glyphs(pointer client, FontPtr pfont, Bool range_flag, + unsigned int nchars, int item_size, unsigned char *data) +{ + FSFpePtr conn = (FSFpePtr) pfont->fpe->private; + int nranges = 0; + fsRange *ranges = NULL; + int res; + FSBlockDataPtr blockrec; + FSBlockedGlyphPtr blockedglyph; + FSClientsDependingPtr *clients_depending = NULL; + int err; + + /* see if the result is already there */ + for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next) + { + if (blockrec->type == FS_LOAD_GLYPHS) + { + blockedglyph = (FSBlockedGlyphPtr) blockrec->data; + if (blockedglyph->pfont == pfont) + { + /* Look for this request */ + if (blockrec->client == client) + { + err = blockrec->errcode; + if (err == StillWorking) + return Suspended; + _fs_signal_clients_depending(&blockedglyph->clients_depending); + _fs_remove_block_rec(conn, blockrec); + return err; + } + /* 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) + { + /* + * An OpenFont is pending for this font, this must + * be from a reopen attempt, so finish the open + * attempt and retry the LoadGlyphs + */ + if (blockrec->client == client) + { + err = blockrec->errcode; + if (err == StillWorking) + return Suspended; + + _fs_signal_clients_depending(&bfont->clients_depending); + _fs_remove_block_rec(conn, blockrec); + if (err != Successful) + return err; + break; + } + /* 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 (blockrec->errcode == StillWorking) + { + clients_depending = &bfont->clients_depending; + break; + } + } + } + } + + /* + * 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); + free(ranges); + } + return _fs_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); + free(ranges); + + /* Now try to reopen the font. */ + return fs_send_open_font(client, pfont->fpe, + (Mask)FontReopen, (char *)0, 0, + (fsBitmapFormat)0, (fsBitmapFormatMask)0, + (XID)0, &pfont); + } + + return fs_send_load_glyphs(client, pfont, nranges, ranges); +} + +int +fs_load_all_glyphs(FontPtr pfont) +{ + 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) + { + if (fs_await_reply (conn) != FSIO_READY) + { + /* Get rid of blockrec */ + fs_client_died(serverClient, pfont->fpe); + err = BadCharRange; + break; + } + fs_read_reply (pfont->fpe, serverClient); + } + return err; +} + +static int +fs_read_list(FontPathElementPtr fpe, FSBlockDataPtr blockrec) +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockedListPtr blist = (FSBlockedListPtr) blockrec->data; + fsListFontsReply *rep; + char *data; + int length, + i, + ret; + int err; + + rep = (fsListFontsReply *) fs_get_reply (conn, &ret); + if (!rep || rep->type == FS_Error) + { + if (ret == FSIO_BLOCK) + return StillWorking; + if (rep) + _fs_done_read (conn, rep->length << 2); + return AllocError; + } + data = (char *) rep + SIZEOF (fsListFontsReply); + + err = Successful; + /* copy data into FontPathRecord */ + for (i = 0; i < rep->nFonts; i++) + { + length = *(unsigned char *)data++; + err = AddFontNamesName(blist->names, data, length); + if (err != Successful) + break; + data += length; + } + _fs_done_read (conn, rep->length << 2); + return err; +} + +static int +fs_send_list_fonts(pointer client, FontPathElementPtr fpe, char *pattern, + int patlen, int maxnames, FontNamesPtr newnames) +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockDataPtr blockrec; + FSBlockedListPtr blockedlist; + fsListFontsReq req; + + if (conn->blockState & FS_GIVE_UP) + return BadFontName; + + /* 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->names = newnames; + + if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING)) + { + _fs_pending_reply (conn); + return Suspended; + } + + _fs_client_access (conn, client, FALSE); + _fs_client_resolution(conn); + + /* send the request */ + req.reqType = FS_ListFonts; + req.pad = 0; + 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); + + blockrec->sequenceNumber = conn->current_seq; + +#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 + + _fs_prepare_for_reply (conn); + return Suspended; +} + +static int +fs_list_fonts(pointer client, FontPathElementPtr fpe, + char *pattern, int patlen, int maxnames, FontNamesPtr newnames) +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockDataPtr blockrec; + int err; + + /* see if the result is already there */ + for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next) + { + if (blockrec->type == FS_LIST_FONTS && blockrec->client == client) + { + err = blockrec->errcode; + if (err == StillWorking) + return Suspended; + _fs_remove_block_rec(conn, blockrec); + return err; + } + } + + /* didn't find waiting record, so send a new one */ + return fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames); +} + +/* + * Read a single list info reply and restart for the next reply + */ +static int +fs_read_list_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec) +{ + FSBlockedListInfoPtr binfo = (FSBlockedListInfoPtr) blockrec->data; + fsListFontsWithXInfoReply *rep; + char *buf; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsPropInfo *pi; + fsPropOffset *po; + pointer pd; + int ret; + int err; + + /* clean up anything from the last trip */ + _fs_free_props (&binfo->info); + + rep = (fsListFontsWithXInfoReply *) fs_get_reply (conn, &ret); + if (!rep || rep->type == FS_Error) + { + if (ret == FSIO_BLOCK) + return StillWorking; + binfo->status = FS_LFWI_FINISHED; + err = AllocError; + goto done; + } + /* + * Normal termination -- the list ends with a name of length 0 + */ + if (rep->nameLength == 0) + { +#ifdef DEBUG + fprintf (stderr, "fs_read_list_info done\n"); +#endif + binfo->status = FS_LFWI_FINISHED; + err = BadFontName; + goto done; + } + + buf = (char *) rep + SIZEOF (fsListFontsWithXInfoReply); + + /* + * The original FS implementation didn't match + * the spec, version 1 was respecified to match the FS. + * Version 2 matches the original intent + */ + if (conn->fsMajorVersion <= 1) + { + memcpy (binfo->name, buf, rep->nameLength); + buf += _fs_pad_length (rep->nameLength); + } + pi = (fsPropInfo *) buf; + buf += SIZEOF (fsPropInfo); + po = (fsPropOffset *) buf; + buf += pi->num_offsets * SIZEOF (fsPropOffset); + pd = (pointer) buf; + buf += pi->data_len; + if (conn->fsMajorVersion > 1) + { + memcpy (binfo->name, buf, rep->nameLength); + buf += _fs_pad_length (rep->nameLength); + } + +#ifdef DEBUG + binfo->name[rep->nameLength] = '\0'; + fprintf (stderr, "fs_read_list_info %s\n", binfo->name); +#endif + err = _fs_convert_lfwi_reply(conn, &binfo->info, rep, pi, po, pd); + if (err != Successful) + { + binfo->status = FS_LFWI_FINISHED; + goto done; + } + binfo->namelen = rep->nameLength; + binfo->remaining = rep->nReplies; + + binfo->status = FS_LFWI_REPLY; + + /* disable this font server until we've processed this response */ + _fs_unmark_block (conn, FS_COMPLETE_REPLY); + FD_CLR(conn->fs_fd, &_fs_fd_mask); +done: + _fs_done_read (conn, rep->length << 2); + return err; +} + +/* ARGSUSED */ +static int +fs_start_list_with_info(pointer client, FontPathElementPtr fpe, + char *pattern, int len, int maxnames, pointer *pdata) +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockDataPtr blockrec; + FSBlockedListInfoPtr binfo; + fsListFontsWithXInfoReq req; + + if (conn->blockState & FS_GIVE_UP) + return BadFontName; + + /* 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; + + binfo = (FSBlockedListInfoPtr) blockrec->data; + bzero((char *) binfo, sizeof(FSBlockedListInfoRec)); + binfo->status = FS_LFWI_WAITING; + + if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING)) + { + _fs_pending_reply (conn); + return Suspended; + } + + _fs_client_access (conn, client, FALSE); + _fs_client_resolution(conn); + + /* send the request */ + req.reqType = FS_ListFontsWithXInfo; + req.pad = 0; + 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); + + blockrec->sequenceNumber = conn->current_seq; + +#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 + + _fs_prepare_for_reply (conn); + return Successful; +} + +/* ARGSUSED */ +static int +fs_next_list_with_info(pointer client, FontPathElementPtr fpe, + char **namep, int *namelenp, + FontInfoPtr *pFontInfo, int *numFonts, + pointer private) +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockDataPtr blockrec; + FSBlockedListInfoPtr binfo; + int err; + + /* see if the result is already there */ + for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next) + if (blockrec->type == FS_LIST_WITH_INFO && blockrec->client == client) + break; + + 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; + } + + binfo = (FSBlockedListInfoPtr) blockrec->data; + + if (binfo->status == FS_LFWI_WAITING) + return Suspended; + + *namep = binfo->name; + *namelenp = binfo->namelen; + *pFontInfo = &binfo->info; + *numFonts = binfo->remaining; + + /* Restart reply processing from this font server */ + FD_SET(conn->fs_fd, &_fs_fd_mask); + if (fs_reply_ready (conn)) + _fs_mark_block (conn, FS_COMPLETE_REPLY); + + err = blockrec->errcode; + switch (binfo->status) { + case FS_LFWI_FINISHED: + _fs_remove_block_rec(conn, blockrec); + break; + case FS_LFWI_REPLY: + binfo->status = FS_LFWI_WAITING; + blockrec->errcode = StillWorking; + conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout; + _fs_mark_block (conn, FS_PENDING_REPLY); + break; + } + + return err; +} + +/* + * Called when client exits + */ + +static void +fs_client_died(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.pad = 0; + 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; + free (cur); + break; + } + } + /* find a pending requests */ + for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next) + if (blockrec->client == client) + break; + + if (!blockrec) + return; + + /* 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 (FSFpePtr conn, pointer client, Bool sync) +{ + FSClientPtr *prev, cur; + fsCreateACReq crac; + fsSetAuthorizationReq setac; + char *authorizations; + int authlen; + Bool new_cur = FALSE; + char padding[4] = { 0, 0, 0, 0 }; + +#ifdef DEBUG + if (conn->blockState & (FS_RECONNECTING|FS_BROKEN_CONNECTION)) + { + fprintf (stderr, "Sending requests without a connection\n"); + } +#endif + 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 = malloc (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.pad = 0; + 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); + /* Work around bug in xfs versions up through modular release 1.0.8 + which rejects CreateAC packets with num_auths = 0 & authlen < 4 */ + if (crac.num_auths == 0) { + authorizations = padding; + authlen = 4; + } else { + authlen = (authlen + 3) & ~0x3; + } + 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); + /* 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.pad = 0; + 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; + } +} + +/* + * Poll a pending connect + */ + +static int +_fs_check_connect (FSFpePtr conn) +{ + int ret; + + ret = _fs_poll_connect (conn->trans_conn, 0); + switch (ret) { + case FSIO_READY: + conn->fs_fd = _FontTransGetConnectionNumber (conn->trans_conn); + FD_SET (conn->fs_fd, &_fs_fd_mask); + break; + case FSIO_BLOCK: + break; + } + return ret; +} + +/* + * Return an FSIO status while waiting for the completed connection + * reply to arrive + */ + +static fsConnSetup * +_fs_get_conn_setup (FSFpePtr conn, int *error, int *setup_len) +{ + int ret; + char *data; + int headlen; + int len; + fsConnSetup *setup; + fsConnSetupAccept *accept; + + ret = _fs_start_read (conn, SIZEOF (fsConnSetup), &data); + if (ret != FSIO_READY) + { + *error = ret; + return 0; + } + + setup = (fsConnSetup *) data; + if (setup->major_version > FS_PROTOCOL) + { + *error = FSIO_ERROR; + return 0; + } + + headlen = (SIZEOF (fsConnSetup) + + (setup->alternate_len << 2) + + (setup->auth_len << 2)); + /* On anything but Success, no extra data is sent */ + if (setup->status != AuthSuccess) + { + len = headlen; + } + else + { + ret = _fs_start_read (conn, headlen + SIZEOF (fsConnSetupAccept), &data); + if (ret != FSIO_READY) + { + *error = ret; + return 0; + } + setup = (fsConnSetup *) data; + accept = (fsConnSetupAccept *) (data + headlen); + len = headlen + (accept->length << 2); + } + ret = _fs_start_read (conn, len, &data); + if (ret != FSIO_READY) + { + *error = ret; + return 0; + } + *setup_len = len; + return (fsConnSetup *) data; +} + +static int +_fs_send_conn_client_prefix (FSFpePtr conn) +{ + fsConnClientPrefix req; + int endian; + int ret; + + /* send setup prefix */ + endian = 1; + if (*(char *) &endian) + req.byteOrder = 'l'; + else + req.byteOrder = 'B'; + + req.major_version = FS_PROTOCOL; + req.minor_version = FS_PROTOCOL_MINOR; + +/* XXX add some auth info here */ + req.num_auths = 0; + req.auth_len = 0; + ret = _fs_write (conn, (char *) &req, SIZEOF (fsConnClientPrefix)); + if (ret != FSIO_READY) + return FSIO_ERROR; + conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout; + return ret; +} + +static int +_fs_recv_conn_setup (FSFpePtr conn) +{ + int ret = FSIO_ERROR; + fsConnSetup *setup; + FSFpeAltPtr alts; + int i, alt_len; + int setup_len; + char *alt_save, *alt_names; + + setup = _fs_get_conn_setup (conn, &ret, &setup_len); + if (!setup) + return ret; + conn->current_seq = 0; + conn->fsMajorVersion = setup->major_version; + /* + * Create an alternate list from the initial server, but + * don't chain looking for alternates. + */ + if (conn->alternate == 0) + { + /* + * free any existing alternates list, allowing the list to + * be updated + */ + if (conn->alts) + { + free (conn->alts); + conn->alts = 0; + conn->numAlts = 0; + } + if (setup->num_alternates) + { + alts = malloc (setup->num_alternates * sizeof (FSFpeAltRec) + + (setup->alternate_len << 2)); + if (alts) + { + alt_names = (char *) (setup + 1); + alt_save = (char *) (alts + setup->num_alternates); + for (i = 0; i < setup->num_alternates; i++) + { + alts[i].subset = alt_names[0]; + alt_len = alt_names[1]; + alts[i].name = alt_save; + memcpy (alt_save, alt_names + 2, alt_len); + alt_save[alt_len] = '\0'; + alt_save += alt_len + 1; + alt_names += _fs_pad_length (alt_len + 2); + } + conn->numAlts = setup->num_alternates; + conn->alts = alts; + } + } + } + _fs_done_read (conn, setup_len); + if (setup->status != AuthSuccess) + return FSIO_ERROR; + return FSIO_READY; +} + +static int +_fs_open_server (FSFpePtr conn) +{ + int ret; + char *servername; + + if (conn->alternate == 0) + servername = conn->servername; + else + servername = conn->alts[conn->alternate-1].name; + conn->trans_conn = _fs_connect (servername, &ret); + conn->blockedConnectTime = GetTimeInMillis () + FS_RECONNECT_WAIT; + return ret; +} + +static char * +_fs_catalog_name (char *servername) +{ + char *sp; + + sp = strchr (servername, '/'); + if (!sp) + return 0; + return strrchr (sp + 1, '/'); +} + +static int +_fs_send_init_packets (FSFpePtr conn) +{ + fsSetResolutionReq srreq; + fsSetCataloguesReq screq; + int num_cats, + clen; + char *catalogues; + char *cat; + char len; + char *end; + int num_res; + FontResolutionPtr res; + +#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)) != FSIO_READY) + return FSIO_ERROR; + if (_fs_write_pad(conn, (char *) res, (num_res * SIZEOF(fsResolution))) != FSIO_READY) + return FSIO_ERROR; + } + + catalogues = 0; + if (conn->alternate != 0) + catalogues = _fs_catalog_name (conn->alts[conn->alternate-1].name); + if (!catalogues) + catalogues = _fs_catalog_name (conn->servername); + + if (!catalogues) + { + conn->has_catalogues = FALSE; + return FSIO_READY; + } + conn->has_catalogues = TRUE; + + /* turn cats into counted list */ + catalogues++; + + cat = catalogues; + num_cats = 0; + clen = 0; + while (*cat) + { + num_cats++; + end = strchr(cat, CATALOGUE_SEP); + if (!end) + end = cat + strlen (cat); + clen += (end - cat) + 1; /* length byte + string */ + cat = end; + } + + 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)) != FSIO_READY) + return FSIO_ERROR; + + while (*cat) + { + num_cats++; + end = strchr(cat, CATALOGUE_SEP); + if (!end) + end = cat + strlen (cat); + len = end - cat; + if (_fs_write (conn, &len, 1) != FSIO_READY) + return FSIO_ERROR; + if (_fs_write (conn, cat, (int) len) != FSIO_READY) + return FSIO_ERROR; + cat = end; + } + + if (_fs_write (conn, "....", _fs_pad_length (clen) - clen) != FSIO_READY) + return FSIO_ERROR; + + return FSIO_READY; +} + +static int +_fs_send_cat_sync (FSFpePtr conn) +{ + fsListCataloguesReq lcreq; + + /* + * 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; + lcreq.pad2 = 0; + _fs_add_req_log(conn, FS_SetCatalogues); + if (_fs_write(conn, (char *) &lcreq, SIZEOF(fsListCataloguesReq)) != FSIO_READY) + return FSIO_ERROR; + conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout; + return FSIO_READY; +} + +static int +_fs_recv_cat_sync (FSFpePtr conn) +{ + fsGenericReply *reply; + fsError *error; + int err; + int ret; + + reply = fs_get_reply (conn, &err); + if (!reply) + return err; + + ret = FSIO_READY; + if (reply->type == FS_Error) + { + error = (fsError *) reply; + if (error->major_opcode == FS_SetCatalogues) + ret = FSIO_ERROR; + } + _fs_done_read (conn, reply->length << 2); + return ret; +} + +static void +_fs_close_server (FSFpePtr conn) +{ + _fs_unmark_block (conn, FS_PENDING_WRITE|FS_BROKEN_WRITE|FS_COMPLETE_REPLY|FS_BROKEN_CONNECTION); + if (conn->trans_conn) + { + _FontTransClose (conn->trans_conn); + conn->trans_conn = 0; + _fs_io_reinit (conn); + } + if (conn->fs_fd >= 0) + { + FD_CLR (conn->fs_fd, &_fs_fd_mask); + conn->fs_fd = -1; + } + conn->fs_conn_state = FS_CONN_UNCONNECTED; +} + +static int +_fs_do_setup_connection (FSFpePtr conn) +{ + int ret; + + do + { +#ifdef DEBUG + fprintf (stderr, "fs_do_setup_connection state %d\n", conn->fs_conn_state); +#endif + switch (conn->fs_conn_state) { + case FS_CONN_UNCONNECTED: + ret = _fs_open_server (conn); + if (ret == FSIO_BLOCK) + conn->fs_conn_state = FS_CONN_CONNECTING; + break; + case FS_CONN_CONNECTING: + ret = _fs_check_connect (conn); + break; + case FS_CONN_CONNECTED: + ret = _fs_send_conn_client_prefix (conn); + break; + case FS_CONN_SENT_PREFIX: + ret = _fs_recv_conn_setup (conn); + break; + case FS_CONN_RECV_INIT: + ret = _fs_send_init_packets (conn); + if (conn->has_catalogues) + ret = _fs_send_cat_sync (conn); + break; + case FS_CONN_SENT_CAT: + if (conn->has_catalogues) + ret = _fs_recv_cat_sync (conn); + else + ret = FSIO_READY; + break; + default: + ret = FSIO_READY; + break; + } + switch (ret) { + case FSIO_READY: + if (conn->fs_conn_state < FS_CONN_RUNNING) + conn->fs_conn_state++; + break; + case FSIO_BLOCK: + if (TimeCmp (GetTimeInMillis (), <, conn->blockedConnectTime)) + break; + ret = FSIO_ERROR; + /* fall through... */ + case FSIO_ERROR: + _fs_close_server (conn); + /* + * Try the next alternate + */ + if (conn->alternate < conn->numAlts) + { + conn->alternate++; + ret = FSIO_READY; + } + else + conn->alternate = 0; + break; + } + } while (conn->fs_conn_state != FS_CONN_RUNNING && ret == FSIO_READY); + if (ret == FSIO_READY) + conn->generation = ++generationCount; + return ret; +} + +static int +_fs_wait_connect (FSFpePtr conn) +{ + int ret; + + for (;;) + { + ret = _fs_do_setup_connection (conn); + if (ret != FSIO_BLOCK) + break; + if (conn->fs_conn_state <= FS_CONN_CONNECTING) + ret = _fs_poll_connect (conn->trans_conn, 1000); + else + ret = _fs_wait_for_readable (conn, 1000); + if (ret == FSIO_ERROR) + break; + } + return ret; +} + +/* + * Poll a connection in the process of reconnecting + */ +static void +_fs_check_reconnect (FSFpePtr conn) +{ + int ret; + + ret = _fs_do_setup_connection (conn); + switch (ret) { + case FSIO_READY: + _fs_unmark_block (conn, FS_RECONNECTING|FS_GIVE_UP); + _fs_restart_connection (conn); + break; + case FSIO_BLOCK: + break; + case FSIO_ERROR: + conn->brokenConnectionTime = GetTimeInMillis () + FS_RECONNECT_POLL; + break; + } +} + +/* + * Start the reconnection process + */ +static void +_fs_start_reconnect (FSFpePtr conn) +{ + if (conn->blockState & FS_RECONNECTING) + return; + conn->alternate = 0; + _fs_mark_block (conn, FS_RECONNECTING); + _fs_unmark_block (conn, FS_BROKEN_CONNECTION); + _fs_check_reconnect (conn); +} + + +static FSFpePtr +_fs_init_conn (char *servername) +{ + FSFpePtr conn; + + conn = calloc (1, sizeof (FSFpeRec) + strlen (servername) + 1); + if (!conn) + return 0; + if (!_fs_io_init (conn)) + { + free (conn); + return 0; + } + conn->servername = (char *) (conn + 1); + conn->fs_conn_state = FS_CONN_UNCONNECTED; + conn->fs_fd = -1; + strcpy (conn->servername, servername); + return conn; +} + +static void +_fs_free_conn (FSFpePtr conn) +{ + _fs_close_server (conn); + _fs_io_fini (conn); + if (conn->alts) + free (conn->alts); + free (conn); +} + +/* + * called at server init time + */ + +void +fs_register_fpe_functions(void) +{ + 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, + NULL, + NULL, + NULL); +} |