3 Copyright 1990, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
28 * Copyright 1990 Network Computing Devices
30 * Permission to use, copy, modify, distribute, and sell this software and
31 * its documentation for any purpose is hereby granted without fee, provided
32 * that the above copyright notice appear in all copies and that both that
33 * copyright notice and this permission notice appear in supporting
34 * documentation, and that the names of Network Computing Devices, or Digital
35 * not be used in advertising or publicity pertaining to distribution
36 * of the software without specific, written prior permission.
38 * NETWORK COMPUTING DEVICES, AND DIGITAL AND DISCLAIM ALL WARRANTIES WITH
39 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
40 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
41 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
42 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
43 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
44 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
47 * Author: Dave Lemke, Network Computing Devices, Inc
50 * font server specific font access
62 #include "X11/Xtrans/Xtrans.h"
63 #include "X11/Xpoll.h"
64 #include <X11/fonts/FS.h>
65 #include <X11/fonts/FSproto.h>
68 #include <X11/fonts/fontmisc.h>
69 #include <X11/fonts/fontstruct.h>
70 #include "fservestr.h"
71 #include <X11/fonts/fontutil.h>
78 #include <ncd/nvram.h>
84 #define MIN(a,b) ((a)<(b)?(a):(b))
86 #define TimeCmp(a,c,b) ((int) ((a) - (b)) c 0)
88 #define NONZEROMETRICS(pci) ((pci)->leftSideBearing || \
89 (pci)->rightSideBearing || \
92 (pci)->characterWidth)
94 extern void ErrorF(const char *f, ...);
96 static int fs_read_glyphs ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
97 static int fs_read_list ( FontPathElementPtr fpe, FSBlockDataPtr blockrec );
98 static int fs_read_list_info ( FontPathElementPtr fpe,
99 FSBlockDataPtr blockrec );
101 extern fd_set _fs_fd_mask;
103 static void fs_block_handler ( pointer data, OSTimePtr wt,
104 pointer LastSelectMask );
105 static int fs_wakeup ( FontPathElementPtr fpe, unsigned long *mask );
110 static FSFpePtr fs_fpes;
112 * Union of all FPE blockStates
114 static CARD32 fs_blockState;
116 static int _fs_restart_connection ( FSFpePtr conn );
117 static void fs_send_query_bitmaps ( FontPathElementPtr fpe,
118 FSBlockDataPtr blockrec );
119 static int fs_send_close_font ( FontPathElementPtr fpe, Font id );
120 static void fs_client_died ( pointer client, FontPathElementPtr fpe );
121 static void _fs_client_access ( FSFpePtr conn, pointer client, Bool sync );
122 static void _fs_client_resolution ( FSFpePtr conn );
123 static fsGenericReply *fs_get_reply (FSFpePtr conn, int *error);
124 static int fs_await_reply (FSFpePtr conn);
125 static void _fs_do_blocked (FSFpePtr conn);
126 static void fs_cleanup_bfont (FSBlockedFontPtr bfont);
128 char _fs_glyph_undefined;
129 char _fs_glyph_requested;
130 static char _fs_glyph_zero_length;
132 static int generationCount;
134 static int FontServerRequestTimeout = 30 * 1000;
137 _fs_close_server (FSFpePtr conn);
140 _fs_init_conn (char *servername);
143 _fs_wait_connect (FSFpePtr conn);
146 _fs_send_init_packets (FSFpePtr conn);
149 _fs_check_reconnect (FSFpePtr conn);
152 _fs_start_reconnect (FSFpePtr conn);
155 _fs_free_conn (FSFpePtr conn);
158 fs_free_fpe(FontPathElementPtr fpe);
163 * the basic idea for the non-blocking access is to have the function
164 * called multiple times until the actual data is returned, instead
167 * the first call to the function will cause the request to be sent to
168 * the font server, and a block record to be stored in the fpe's list
169 * of outstanding requests. the FS block handler also sticks the
170 * proper set of fd's into the select mask. when data is ready to be
171 * read in, the FS wakup handler will be hit. this will read the
172 * data off the wire into the proper block record, and then signal the
173 * client that caused the block so that it can restart. it will then
174 * call the access function again, which will realize that the data has
175 * arrived and return it.
181 _fs_add_req_log(FSFpePtr conn, int opcode)
184 fprintf (stderr, "\t\tRequest: %5d Opcode: %2d\n",
185 conn->current_seq, opcode);
186 conn->reqbuffer[conn->reqindex].opcode = opcode;
187 conn->reqbuffer[conn->reqindex].sequence = conn->current_seq;
189 if (conn->reqindex == REQUEST_LOG_SIZE)
194 _fs_add_rep_log (FSFpePtr conn, fsGenericReply *rep)
198 for (i = 0; i < REQUEST_LOG_SIZE; i++)
199 if (conn->reqbuffer[i].sequence == rep->sequenceNumber)
201 if (i == REQUEST_LOG_SIZE)
202 fprintf (stderr, "\t\t\t\t\tReply: %5d Opcode: unknown\n",
203 rep->sequenceNumber);
205 fprintf (stderr, "\t\t\t\t\tReply: %5d Opcode: %d\n",
207 conn->reqbuffer[i].opcode);
210 #define _fs_add_req_log(conn,op) ((conn)->current_seq++)
211 #define _fs_add_rep_log(conn,rep)
215 fs_name_check(char *name)
217 /* Just make sure there is a protocol/ prefix */
218 return (name && *name != '/' && strchr(name, '/'));
222 _fs_client_resolution(FSFpePtr conn)
224 fsSetResolutionReq srreq;
226 FontResolutionPtr res;
228 res = GetClientResolutions(&num_res);
231 srreq.reqType = FS_SetResolution;
232 srreq.num_resolutions = num_res;
233 srreq.length = (SIZEOF(fsSetResolutionReq) +
234 (num_res * SIZEOF(fsResolution)) + 3) >> 2;
236 _fs_add_req_log(conn, FS_SetResolution);
237 if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != -1)
238 (void)_fs_write_pad(conn, (char *) res,
239 (num_res * SIZEOF(fsResolution)));
244 * close font server and remove any state associated with
245 * this connection - this includes any client records.
249 fs_close_conn(FSFpePtr conn)
251 FSClientPtr client, nclient;
253 _fs_close_server (conn);
255 for (client = conn->clients; client; client = nclient)
257 nclient = client->next;
260 conn->clients = NULL;
264 * the wakeup handlers have to be set when the FPE is open, and not
265 * removed until it is freed, in order to handle unexpected data, like
270 fs_init_fpe(FontPathElementPtr fpe)
277 /* open font server */
278 /* create FS specific fpe info */
281 /* hack for old style names */
283 name++; /* skip ':' */
285 conn = _fs_init_conn (name);
290 err = init_fs_handlers (fpe, fs_block_handler);
291 if (err != Successful)
293 _fs_free_conn (conn);
299 conn->next = fs_fpes;
301 ret = _fs_wait_connect (conn);
302 if (ret != FSIO_READY)
312 if (err == Successful)
315 if (configData.ExtendedFontDiags)
316 printf("Connected to font server \"%s\"\n", name);
319 fprintf (stderr, "connected to FS \"%s\"\n", name);
325 fprintf(stderr, "failed to connect to FS \"%s\" %d\n", name, err);
328 if (configData.ExtendedFontDiags)
329 printf("Failed to connect to font server \"%s\"\n", name);
337 fs_reset_fpe(FontPathElementPtr fpe)
339 (void) _fs_send_init_packets((FSFpePtr) fpe->private);
344 * this shouldn't be called till all refs to the FPE are gone
348 fs_free_fpe(FontPathElementPtr fpe)
350 FSFpePtr conn = (FSFpePtr) fpe->private, *prev;
352 /* unhook from chain of all font servers */
353 for (prev = &fs_fpes; *prev; prev = &(*prev)->next)
361 _fs_unmark_block (conn, conn->blockState);
363 remove_fs_handlers(fpe, fs_block_handler, fs_fpes == 0);
364 _fs_free_conn (conn);
365 fpe->private = (pointer) 0;
368 if (configData.ExtendedFontDiags)
369 printf("Disconnected from font server \"%s\"\n", fpe->name);
372 fprintf (stderr, "disconnect from FS \"%s\"\n", fpe->name);
378 static FSBlockDataPtr
379 fs_new_block_rec(FontPathElementPtr fpe, pointer client, int type)
381 FSBlockDataPtr blockrec,
383 FSFpePtr conn = (FSFpePtr) fpe->private;
388 size = sizeof(FSBlockedFontRec);
391 size = sizeof(FSBlockedGlyphRec);
394 size = sizeof(FSBlockedListRec);
396 case FS_LIST_WITH_INFO:
397 size = sizeof(FSBlockedListInfoRec);
403 blockrec = malloc(sizeof(FSBlockDataRec) + size);
405 return (FSBlockDataPtr) 0;
406 blockrec->data = (pointer) (blockrec + 1);
407 blockrec->client = client;
408 blockrec->sequenceNumber = -1;
409 blockrec->errcode = StillWorking;
410 blockrec->type = type;
411 blockrec->depending = 0;
412 blockrec->next = (FSBlockDataPtr) 0;
414 /* stick it on the end of the list (since its expected last) */
415 for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
423 _fs_set_pending_reply (FSFpePtr conn)
425 FSBlockDataPtr blockrec;
427 for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
428 if (blockrec->errcode == StillWorking)
432 conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
433 _fs_mark_block (conn, FS_PENDING_REPLY);
436 _fs_unmark_block (conn, FS_PENDING_REPLY);
440 _fs_remove_block_rec(FSFpePtr conn, FSBlockDataPtr blockrec)
442 FSBlockDataPtr *prev;
444 for (prev = &conn->blockedRequests; *prev; prev = &(*prev)->next)
445 if (*prev == blockrec)
447 *prev = blockrec->next;
450 if (blockrec->type == FS_LOAD_GLYPHS)
452 FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
453 if (bglyph->num_expected_ranges)
454 free(bglyph->expected_ranges);
457 _fs_set_pending_reply (conn);
461 _fs_signal_clients_depending(FSClientsDependingPtr *clients_depending)
463 FSClientsDependingPtr p;
465 while ((p = *clients_depending))
467 *clients_depending = p->next;
468 ClientSignal(p->client);
474 _fs_add_clients_depending(FSClientsDependingPtr *clients_depending, pointer client)
476 FSClientsDependingPtr new, cd;
478 for (; (cd = *clients_depending);
479 clients_depending = &(*clients_depending)->next)
481 if (cd->client == client)
485 new = malloc (sizeof (FSClientsDependingRec));
489 new->client = client;
491 *clients_depending = new;
496 * When a request is aborted due to a font server failure,
497 * signal any depending clients to restart their dependant
501 _fs_clean_aborted_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
503 switch(blockrec->type) {
505 FSBlockedFontPtr bfont = (FSBlockedFontPtr)blockrec->data;
507 fs_cleanup_bfont (bfont);
508 _fs_signal_clients_depending(&bfont->clients_depending);
511 case FS_LOAD_GLYPHS: {
512 FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data;
514 _fs_clean_aborted_loadglyphs(bglyph->pfont,
515 bglyph->num_expected_ranges,
516 bglyph->expected_ranges);
517 _fs_signal_clients_depending(&bglyph->clients_depending);
522 case FS_LIST_WITH_INFO: {
523 FSBlockedListInfoPtr binfo;
524 binfo = (FSBlockedListInfoPtr) blockrec->data;
525 if (binfo->status == FS_LFWI_REPLY)
526 FD_SET(conn->fs_fd, &_fs_fd_mask);
527 _fs_free_props (&binfo->info);
535 fs_abort_blockrec(FSFpePtr conn, FSBlockDataPtr blockrec)
537 _fs_clean_aborted_blockrec (conn, blockrec);
538 _fs_remove_block_rec (conn, blockrec);
542 * Tell the font server we've failed to complete an open and
543 * then unload the partially created font
546 fs_cleanup_bfont (FSBlockedFontPtr bfont)
552 fsd = (FSFontDataRec *) bfont->pfont->fpePrivate;
554 /* make sure the FS knows we choked on it */
555 fs_send_close_font(bfont->pfont->fpe, bfont->fontid);
558 * Either unload the font if it's being opened for
559 * the first time, or smash the generation field to
560 * mark this font as an orphan
562 if (!(bfont->flags & FontReopen))
565 (*bfont->pfont->unload_font) (bfont->pfont);
568 fprintf (stderr, "Not freeing other font in cleanup_bfont\n");
573 fsd->generation = -1;
578 * Check to see if a complete reply is waiting
580 static fsGenericReply *
581 fs_get_reply (FSFpePtr conn, int *error)
587 /* block if the connection is down or paused in lfwi */
588 if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask))
594 ret = _fs_start_read (conn, sizeof (fsGenericReply), &buf);
595 if (ret != FSIO_READY)
601 rep = (fsGenericReply *) buf;
603 ret = _fs_start_read (conn, rep->length << 2, &buf);
604 if (ret != FSIO_READY)
612 return (fsGenericReply *) buf;
616 fs_reply_ready (FSFpePtr conn)
620 if (conn->fs_fd == -1 || !FD_ISSET (conn->fs_fd, &_fs_fd_mask))
622 if (fs_data_read (conn) < sizeof (fsGenericReply))
624 rep = (fsGenericReply *) (conn->inBuf.buf + conn->inBuf.remove);
625 if (fs_data_read (conn) < rep->length << 2)
631 _fs_pending_reply (FSFpePtr conn)
633 if (!(conn->blockState & FS_PENDING_REPLY))
635 _fs_mark_block (conn, FS_PENDING_REPLY);
636 conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
641 _fs_prepare_for_reply (FSFpePtr conn)
643 _fs_pending_reply (conn);
648 * Block (for a while) awaiting a complete reply
651 fs_await_reply (FSFpePtr conn)
655 if (conn->blockState & FS_COMPLETE_REPLY)
658 while (!fs_get_reply (conn, &ret))
660 if (ret != FSIO_BLOCK)
662 if (_fs_wait_for_readable (conn, FontServerRequestTimeout) != FSIO_READY)
664 _fs_connection_died (conn);
672 * Process the reply to an OpenBitmapFont request
675 fs_read_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
677 FSFpePtr conn = (FSFpePtr) fpe->private;
678 FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
679 fsOpenBitmapFontReply *rep;
680 FSBlockDataPtr blockOrig;
681 FSBlockedFontPtr origBfont;
684 rep = (fsOpenBitmapFontReply *) fs_get_reply (conn, &ret);
685 if (!rep || rep->type == FS_Error)
687 if (ret == FSIO_BLOCK)
690 _fs_done_read (conn, rep->length << 2);
691 fs_cleanup_bfont (bfont);
695 /* If we're not reopening a font and FS detected a duplicate font
696 open request, replace our reference to the new font with a
697 reference to an existing font (possibly one not finished
698 opening). If this is a reopen, keep the new font reference...
699 it's got the metrics and extents we read when the font was opened
700 before. This also gives us the freedom to easily close the font
701 if we we decide (in fs_read_query_info()) that we don't like what
704 if (rep->otherid && !(bfont->flags & FontReopen))
706 fs_cleanup_bfont (bfont);
708 /* Find old font if we're completely done getting it from server. */
709 bfont->pfont = find_old_font(rep->otherid);
710 bfont->freeFont = FALSE;
711 bfont->fontid = rep->otherid;
712 bfont->state = FS_DONE_REPLY;
714 * look for a blocked request to open the same font
716 for (blockOrig = conn->blockedRequests;
718 blockOrig = blockOrig->next)
720 if (blockOrig != blockrec && blockOrig->type == FS_OPEN_FONT)
722 origBfont = (FSBlockedFontPtr) blockOrig->data;
723 if (origBfont->fontid == rep->otherid)
725 blockrec->depending = blockOrig->depending;
726 blockOrig->depending = blockrec;
727 bfont->state = FS_DEPENDING;
728 bfont->pfont = origBfont->pfont;
733 if (bfont->pfont == NULL)
735 /* XXX - something nasty happened */
743 bfont->pfont->info.cachable = rep->cachable != 0;
744 bfont->state = FS_INFO_REPLY;
746 * Reset the blockrec for the next reply
748 blockrec->sequenceNumber = bfont->queryInfoSequence;
749 conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
752 _fs_done_read (conn, rep->length << 2);
757 fs_fonts_match (FontInfoPtr pInfo1, FontInfoPtr pInfo2)
761 if (pInfo1->firstCol != pInfo2->firstCol ||
762 pInfo1->lastCol != pInfo2->lastCol ||
763 pInfo1->firstRow != pInfo2->firstRow ||
764 pInfo1->lastRow != pInfo2->lastRow ||
765 pInfo1->defaultCh != pInfo2->defaultCh ||
766 pInfo1->noOverlap != pInfo2->noOverlap ||
767 pInfo1->terminalFont != pInfo2->terminalFont ||
768 pInfo1->constantMetrics != pInfo2->constantMetrics ||
769 pInfo1->constantWidth != pInfo2->constantWidth ||
770 pInfo1->inkInside != pInfo2->inkInside ||
771 pInfo1->inkMetrics != pInfo2->inkMetrics ||
772 pInfo1->allExist != pInfo2->allExist ||
773 pInfo1->drawDirection != pInfo2->drawDirection ||
774 pInfo1->cachable != pInfo2->cachable ||
775 pInfo1->anamorphic != pInfo2->anamorphic ||
776 pInfo1->maxOverlap != pInfo2->maxOverlap ||
777 pInfo1->fontAscent != pInfo2->fontAscent ||
778 pInfo1->fontDescent != pInfo2->fontDescent ||
779 pInfo1->nprops != pInfo2->nprops)
782 #define MATCH(xci1, xci2) \
783 (((xci1).leftSideBearing == (xci2).leftSideBearing) && \
784 ((xci1).rightSideBearing == (xci2).rightSideBearing) && \
785 ((xci1).characterWidth == (xci2).characterWidth) && \
786 ((xci1).ascent == (xci2).ascent) && \
787 ((xci1).descent == (xci2).descent) && \
788 ((xci1).attributes == (xci2).attributes))
790 if (!MATCH(pInfo1->maxbounds, pInfo2->maxbounds) ||
791 !MATCH(pInfo1->minbounds, pInfo2->minbounds) ||
792 !MATCH(pInfo1->ink_maxbounds, pInfo2->ink_maxbounds) ||
793 !MATCH(pInfo1->ink_minbounds, pInfo2->ink_minbounds))
798 for (i = 0; i < pInfo1->nprops; i++)
799 if (pInfo1->isStringProp[i] !=
800 pInfo2->isStringProp[i] ||
801 pInfo1->props[i].name !=
802 pInfo2->props[i].name ||
803 pInfo1->props[i].value !=
804 pInfo2->props[i].value)
812 fs_read_query_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
814 FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
815 FSFpePtr conn = (FSFpePtr) fpe->private;
816 fsQueryXInfoReply *rep;
822 FontInfoRec tempInfo;
826 rep = (fsQueryXInfoReply *) fs_get_reply (conn, &ret);
827 if (!rep || rep->type == FS_Error)
829 if (ret == FSIO_BLOCK)
832 _fs_done_read (conn, rep->length << 2);
833 fs_cleanup_bfont (bfont);
837 /* If this is a reopen, accumulate the query info into a dummy
838 font and compare to our original data. */
839 if (bfont->flags & FontReopen)
842 pInfo = &bfont->pfont->info;
845 buf += SIZEOF(fsQueryXInfoReply);
847 /* move the data over */
848 fsUnpack_XFontInfoHeader(rep, pInfo);
850 /* compute accelerators */
851 _fs_init_fontinfo(conn, pInfo);
853 /* Compute offsets into the reply */
854 pi = (fsPropInfo *) buf;
855 buf += SIZEOF (fsPropInfo);
857 po = (fsPropOffset *) buf;
858 buf += pi->num_offsets * SIZEOF(fsPropOffset);
863 /* convert the properties and step over the reply */
864 ret = _fs_convert_props(pi, po, pd, pInfo);
865 _fs_done_read (conn, rep->length << 2);
869 fs_cleanup_bfont (bfont);
873 if (bfont->flags & FontReopen)
875 /* We're reopening a font that we lost because of a downed
876 connection. In the interest of avoiding corruption from
877 opening a different font than the old one (we already have
878 its metrics, extents, and probably some of its glyphs),
879 verify that the metrics and properties all match. */
881 if (fs_fonts_match (pInfo, &bfont->pfont->info))
884 bfont->state = FS_DONE_REPLY;
888 fs_cleanup_bfont (bfont);
891 _fs_free_props (pInfo);
897 * Ask for terminal format fonts if possible
899 if (bfont->pfont->info.terminalFont)
900 bfont->format = ((bfont->format & ~ (BitmapFormatImageRectMask)) |
901 BitmapFormatImageRectMax);
904 * Figure out if the whole font should get loaded right now.
906 if (glyphCachingMode == CACHING_OFF ||
907 (glyphCachingMode == CACHE_16_BIT_GLYPHS
908 && !bfont->pfont->info.lastRow))
910 bfont->flags |= FontLoadAll;
914 * Ready to send the query bitmaps; the terminal font bit has
915 * been computed and glyphCaching has been considered
917 if (bfont->flags & FontLoadBitmaps)
919 fs_send_query_bitmaps (fpe, blockrec);
923 bfont->state = FS_EXTENT_REPLY;
926 * Reset the blockrec for the next reply
928 blockrec->sequenceNumber = bfont->queryExtentsSequence;
929 conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
935 fs_read_extent_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
937 FSFpePtr conn = (FSFpePtr) fpe->private;
938 FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
939 FSFontDataPtr fsd = (FSFontDataPtr) bfont->pfont->fpePrivate;
940 FSFontPtr fsfont = (FSFontPtr) bfont->pfont->fontPrivate;
941 fsQueryXExtents16Reply *rep;
947 Bool haveInk = FALSE; /* need separate ink metrics? */
950 fsXCharInfo fscilocal;
951 FontInfoRec *fi = &bfont->pfont->info;
953 rep = (fsQueryXExtents16Reply *) fs_get_reply (conn, &ret);
954 if (!rep || rep->type == FS_Error)
956 if (ret == FSIO_BLOCK)
959 _fs_done_read (conn, rep->length << 2);
960 fs_cleanup_bfont (bfont);
964 /* move the data over */
965 /* need separate inkMetrics for fixed font server protocol version */
966 numExtents = rep->num_extents;
967 numInfos = numExtents;
968 if (bfont->pfont->info.terminalFont && conn->fsMajorVersion > 1)
973 ci = pCI = malloc(sizeof(CharInfoRec) * numInfos);
977 _fs_done_read (conn, rep->length << 2);
978 fs_cleanup_bfont(bfont);
981 fsfont->encoding = pCI;
983 fsfont->inkMetrics = pCI + numExtents;
985 fsfont->inkMetrics = pCI;
988 buf += SIZEOF (fsQueryXExtents16Reply);
991 fsd->glyphs_to_get = 0;
992 ci = fsfont->inkMetrics;
993 for (i = 0; i < numExtents; i++)
995 memcpy(&fscilocal, fsci, SIZEOF(fsXCharInfo)); /* align it */
996 _fs_convert_char_info(&fscilocal, &ci->metrics);
998 if (ci->metrics.ascent > fi->maxbounds.ascent)
1000 ErrorF("fserve: warning: %s %s ascent (%d) > maxascent (%d)\n",
1001 fpe->name, fsd->name,
1002 ci->metrics.ascent, fi->maxbounds.ascent);
1003 ci->metrics.ascent = fi->maxbounds.ascent;
1005 if (ci->metrics.descent > fi->maxbounds.descent)
1007 ErrorF("fserve: warning: %s %s descent (%d) > maxdescent (%d)\n",
1008 fpe->name, fsd->name,
1009 ci->metrics.descent, fi->maxbounds.descent);
1010 ci->metrics.descent = fi->maxbounds.descent;
1012 fsci = fsci + SIZEOF(fsXCharInfo);
1013 /* Initialize the bits field for later glyph-caching use */
1014 if (NONZEROMETRICS(&ci->metrics))
1017 (ci->metrics.leftSideBearing == ci->metrics.rightSideBearing ||
1018 ci->metrics.ascent == -ci->metrics.descent))
1019 pCI[i].bits = &_fs_glyph_zero_length;
1022 pCI[i].bits = &_fs_glyph_undefined;
1023 fsd->glyphs_to_get++;
1027 pCI[i].bits = (char *)0;
1031 /* Done with reply */
1032 _fs_done_read (conn, rep->length << 2);
1034 /* build bitmap metrics, ImageRectMax style */
1039 ci = fsfont->encoding;
1040 ii = fsfont->inkMetrics;
1041 for (i = 0; i < numExtents; i++, ci++, ii++)
1043 if (NONZEROMETRICS(&ii->metrics))
1045 ci->metrics.leftSideBearing = FONT_MIN_LEFT(fi);
1046 ci->metrics.rightSideBearing = FONT_MAX_RIGHT(fi);
1047 ci->metrics.ascent = FONT_MAX_ASCENT(fi);
1048 ci->metrics.descent = FONT_MAX_DESCENT(fi);
1049 ci->metrics.characterWidth = FONT_MAX_WIDTH(fi);
1050 ci->metrics.attributes = ii->metrics.attributes;
1054 ci->metrics = ii->metrics;
1057 if (ci->metrics.ascent > fi->maxbounds.ascent)
1059 ErrorF("fserve: warning: %s %s ascent (%d) "
1060 "> maxascent (%d)\n",
1061 fpe->name, fsd->name,
1062 ci->metrics.ascent, fi->maxbounds.ascent);
1063 ci->metrics.ascent = fi->maxbounds.ascent;
1065 if (ci->metrics.descent > fi->maxbounds.descent)
1067 ErrorF("fserve: warning: %s %s descent (%d) "
1068 "> maxdescent (%d)\n",
1069 fpe->name, fsd->name,
1070 ci->metrics.descent, fi->maxbounds.descent);
1071 ci->metrics.descent = fi->maxbounds.descent;
1076 unsigned int r, c, numCols, firstCol;
1078 firstCol = bfont->pfont->info.firstCol;
1079 numCols = bfont->pfont->info.lastCol - firstCol + 1;
1080 c = bfont->pfont->info.defaultCh;
1081 fsfont->pDefault = 0;
1082 if (bfont->pfont->info.lastRow)
1085 r -= bfont->pfont->info.firstRow;
1088 if (r < bfont->pfont->info.lastRow-bfont->pfont->info.firstRow+1 &&
1090 fsfont->pDefault = &pCI[r * numCols + c];
1096 fsfont->pDefault = &pCI[c];
1099 bfont->state = FS_GLYPHS_REPLY;
1101 if (bfont->flags & FontLoadBitmaps)
1104 * Reset the blockrec for the next reply
1106 blockrec->sequenceNumber = bfont->queryBitmapsSequence;
1107 conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
1108 return StillWorking;
1114 static char *fs_open_states[] = {
1125 fs_do_open_font(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
1127 FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
1131 fprintf (stderr, "fs_do_open_font state %s %s\n",
1132 fs_open_states[bfont->state],
1133 ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name);
1136 switch (bfont->state) {
1138 err = fs_read_open_font(fpe, blockrec);
1139 if (err != StillWorking) { /* already loaded, or error */
1140 /* if font's already loaded, massage error code */
1141 switch (bfont->state) {
1152 err = fs_read_query_info(fpe, blockrec);
1154 case FS_EXTENT_REPLY:
1155 err = fs_read_extent_info(fpe, blockrec);
1157 case FS_GLYPHS_REPLY:
1158 if (bfont->flags & FontLoadBitmaps)
1159 err = fs_read_glyphs(fpe, blockrec);
1161 case FS_DEPENDING: /* can't happen */
1166 fprintf (stderr, "fs_do_open_font err %d\n", err);
1168 if (err != StillWorking)
1170 bfont->state = FS_DONE_REPLY; /* for _fs_load_glyphs() */
1171 while ((blockrec = blockrec->depending))
1173 bfont = (FSBlockedFontPtr) blockrec->data;
1174 bfont->state = FS_DONE_REPLY; /* for _fs_load_glyphs() */
1181 _fs_mark_block (FSFpePtr conn, CARD32 mask)
1183 conn->blockState |= mask;
1184 fs_blockState |= mask;
1188 _fs_unmark_block (FSFpePtr conn, CARD32 mask)
1192 if (conn->blockState & mask)
1194 conn->blockState &= ~mask;
1196 for (c = fs_fpes; c; c = c->next)
1197 fs_blockState |= c->blockState;
1203 fs_block_handler(pointer data, OSTimePtr wt, pointer LastSelectMask)
1205 static struct timeval block_timeout;
1206 CARD32 now, earliest, wakeup;
1210 XFD_ORSET((fd_set *)LastSelectMask, (fd_set *)LastSelectMask,
1213 * Flush all pending output
1215 if (fs_blockState & FS_PENDING_WRITE)
1216 for (conn = fs_fpes; conn; conn = conn->next)
1217 if (conn->blockState & FS_PENDING_WRITE)
1220 * Check for any fpe with a complete reply, set sleep time to zero
1222 if (fs_blockState & FS_COMPLETE_REPLY)
1224 block_timeout.tv_sec = 0;
1225 block_timeout.tv_usec = 0;
1227 *wt = &block_timeout;
1229 **wt = block_timeout;
1232 * Walk through fpe list computing sleep time
1234 else if (fs_blockState & (FS_BROKEN_WRITE|
1235 FS_BROKEN_CONNECTION|
1239 now = GetTimeInMillis ();
1240 earliest = now + 10000000;
1241 for (conn = fs_fpes; conn; conn = conn->next)
1243 if (conn->blockState & FS_RECONNECTING)
1245 wakeup = conn->blockedConnectTime;
1246 if (TimeCmp (wakeup, <, earliest))
1249 if (conn->blockState & FS_BROKEN_CONNECTION)
1251 wakeup = conn->brokenConnectionTime;
1252 if (TimeCmp (wakeup, <, earliest))
1255 if (conn->blockState & FS_BROKEN_WRITE)
1257 wakeup = conn->brokenWriteTime;
1258 if (TimeCmp (wakeup, <, earliest))
1261 if (conn->blockState & FS_PENDING_REPLY)
1263 wakeup = conn->blockedReplyTime;
1264 if (TimeCmp (wakeup, <, earliest))
1268 soonest = earliest - now;
1271 block_timeout.tv_sec = soonest / 1000;
1272 block_timeout.tv_usec = (soonest % 1000) * 1000;
1274 *wt = &block_timeout;
1275 else if (soonest < (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000)
1276 **wt = block_timeout;
1281 fs_handle_unexpected(FSFpePtr conn, fsGenericReply *rep)
1283 if (rep->type == FS_Event && rep->data1 == KeepAlive)
1288 req.reqType = FS_Noop;
1289 req.length = SIZEOF(fsNoopReq) >> 2;
1290 _fs_add_req_log(conn, FS_Noop);
1291 _fs_write(conn, (char *) &req, SIZEOF(fsNoopReq));
1293 /* this should suck up unexpected replies and events */
1294 _fs_done_read (conn, rep->length << 2);
1298 fs_read_reply (FontPathElementPtr fpe, pointer client)
1300 FSFpePtr conn = (FSFpePtr) fpe->private;
1301 FSBlockDataPtr blockrec;
1304 fsGenericReply *rep;
1306 if ((rep = fs_get_reply (conn, &ret)))
1308 _fs_add_rep_log (conn, rep);
1309 for (blockrec = conn->blockedRequests;
1311 blockrec = blockrec->next)
1313 if (blockrec->sequenceNumber == rep->sequenceNumber)
1319 fs_handle_unexpected(conn, rep);
1324 * go read it, and if we're done,
1325 * wake up the appropriate client
1327 switch (blockrec->type) {
1329 blockrec->errcode = fs_do_open_font(fpe, blockrec);
1331 case FS_LOAD_GLYPHS:
1332 blockrec->errcode = fs_read_glyphs(fpe, blockrec);
1335 blockrec->errcode = fs_read_list(fpe, blockrec);
1337 case FS_LIST_WITH_INFO:
1338 blockrec->errcode = fs_read_list_info(fpe, blockrec);
1343 err = blockrec->errcode;
1344 if (err != StillWorking)
1348 blockrec->errcode = err;
1349 if (client != blockrec->client)
1350 ClientSignal(blockrec->client);
1351 blockrec = blockrec->depending;
1353 _fs_unmark_block (conn, FS_PENDING_REPLY);
1356 if (fs_reply_ready (conn))
1357 _fs_mark_block (conn, FS_COMPLETE_REPLY);
1359 _fs_unmark_block (conn, FS_COMPLETE_REPLY);
1364 fs_wakeup(FontPathElementPtr fpe, unsigned long *mask)
1366 fd_set *LastSelectMask = (fd_set *) mask;
1367 FSFpePtr conn = (FSFpePtr) fpe->private;
1370 * Don't continue if the fd is -1 (which will be true when the
1371 * font server terminates
1373 if ((conn->blockState & FS_RECONNECTING))
1374 _fs_check_reconnect (conn);
1375 else if ((conn->blockState & FS_COMPLETE_REPLY) ||
1376 (conn->fs_fd != -1 && FD_ISSET(conn->fs_fd, LastSelectMask)))
1377 fs_read_reply (fpe, 0);
1378 if (conn->blockState & (FS_PENDING_REPLY|FS_BROKEN_CONNECTION|FS_BROKEN_WRITE))
1379 _fs_do_blocked (conn);
1382 FSBlockDataPtr blockrec;
1383 FSBlockedFontPtr bfont;
1384 FSBlockedListPtr blist;
1385 static CARD32 lastState;
1386 static FSBlockDataPtr lastBlock;
1388 if (conn->blockState || conn->blockedRequests || lastState || lastBlock)
1390 fprintf (stderr, " Block State 0x%x\n", (int) conn->blockState);
1391 lastState = conn->blockState;
1392 lastBlock = conn->blockedRequests;
1394 for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
1396 switch (blockrec->type) {
1398 bfont = (FSBlockedFontPtr) blockrec->data;
1399 fprintf (stderr, " Blocked font errcode %d sequence %d state %s %s\n",
1401 blockrec->sequenceNumber,
1402 fs_open_states[bfont->state],
1404 ((FSFontDataPtr) (bfont->pfont->fpePrivate))->name :
1408 blist = (FSBlockedListPtr) blockrec->data;
1409 fprintf (stderr, " Blocked list errcode %d sequence %d\n",
1410 blockrec->errcode, blockrec->sequenceNumber);
1413 fprintf (stderr, " Blocked type %d errcode %d sequence %d\n",
1416 blockrec->sequenceNumber);
1426 * Notice a dead connection and prepare for reconnect
1430 _fs_connection_died(FSFpePtr conn)
1432 if (conn->blockState & FS_BROKEN_CONNECTION)
1434 fs_close_conn(conn);
1435 conn->brokenConnectionTime = GetTimeInMillis ();
1436 _fs_mark_block (conn, FS_BROKEN_CONNECTION);
1437 _fs_unmark_block (conn, FS_BROKEN_WRITE|FS_PENDING_WRITE|FS_RECONNECTING);
1441 * Signal clients that the connection has come back up
1444 _fs_restart_connection(FSFpePtr conn)
1446 FSBlockDataPtr block;
1448 _fs_unmark_block (conn, FS_GIVE_UP);
1449 while ((block = (FSBlockDataPtr) conn->blockedRequests))
1451 if (block->errcode == StillWorking)
1453 ClientSignal(block->client);
1454 fs_abort_blockrec(conn, block);
1461 * Declare this font server connection useless
1464 _fs_giveup (FSFpePtr conn)
1466 FSBlockDataPtr block;
1468 if (conn->blockState & FS_GIVE_UP)
1471 fprintf (stderr, "give up on FS \"%s\"\n", conn->servername);
1473 _fs_mark_block (conn, FS_GIVE_UP);
1474 while ((block = (FSBlockDataPtr) conn->blockedRequests))
1476 if (block->errcode == StillWorking)
1478 ClientSignal (block->client);
1479 fs_abort_blockrec (conn, block);
1482 if (conn->fs_fd >= 0)
1483 _fs_connection_died (conn);
1487 _fs_do_blocked (FSFpePtr conn)
1491 now = GetTimeInMillis ();
1492 if ((conn->blockState & FS_PENDING_REPLY) &&
1493 TimeCmp (conn->blockedReplyTime, <=, now))
1499 if (conn->blockState & FS_BROKEN_CONNECTION)
1501 /* Try to reconnect broken connections */
1502 if (TimeCmp (conn->brokenConnectionTime, <=, now))
1503 _fs_start_reconnect (conn);
1505 else if (conn->blockState & FS_BROKEN_WRITE)
1507 /* Try to flush blocked connections */
1508 if (TimeCmp (conn->brokenWriteTime, <=, now))
1515 * sends the actual request out
1519 fs_send_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
1520 char *name, int namelen,
1521 fsBitmapFormat format, fsBitmapFormatMask fmask,
1522 XID id, FontPtr *ppfont)
1524 FSFpePtr conn = (FSFpePtr) fpe->private;
1526 FSBlockDataPtr blockrec = NULL;
1527 FSBlockedFontPtr bfont;
1529 fsOpenBitmapFontReq openreq;
1530 fsQueryXInfoReq inforeq;
1531 fsQueryXExtents16Req extreq;
1533 unsigned char buf[1024];
1535 if (conn->blockState & FS_GIVE_UP)
1538 if (namelen <= 0 || namelen > sizeof (buf) - 1)
1542 * Get the font structure put together, either by reusing
1543 * the existing one or creating a new one
1545 if (flags & FontReopen)
1547 Atom nameatom, fn = None;
1551 fsd = (FSFontDataPtr)font->fpePrivate;
1552 /* This is an attempt to reopen a font. Did the font have a
1554 if ((nameatom = MakeAtom("FONT", 4, 0)) != None)
1556 for (i = 0; i < font->info.nprops; i++)
1557 if (font->info.props[i].name == nameatom &&
1558 font->info.isStringProp[i])
1560 fn = font->info.props[i].value;
1564 if (fn == None || !(name = NameForAtom(fn)))
1567 namelen = fsd->namelen;
1570 namelen = strlen(name);
1574 font = fs_create_font (fpe, name, namelen, format, fmask);
1578 fsd = (FSFontDataPtr)font->fpePrivate;
1581 /* make a new block record, and add it to the end of the list */
1582 blockrec = fs_new_block_rec(font->fpe, client, FS_OPEN_FONT);
1585 if (!(flags & FontReopen))
1586 (*font->unload_font) (font);
1591 * Must check this before generating any protocol, otherwise we'll
1592 * mess up a reconnect in progress
1594 if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
1596 _fs_pending_reply (conn);
1600 fsd->generation = conn->generation;
1602 bfont = (FSBlockedFontPtr) blockrec->data;
1603 bfont->fontid = fsd->fontid;
1604 bfont->pfont = font;
1605 bfont->state = FS_OPEN_REPLY;
1606 bfont->flags = flags;
1607 bfont->format = fsd->format;
1608 bfont->clients_depending = (FSClientsDependingPtr)0;
1609 bfont->freeFont = (flags & FontReopen) == 0;
1611 _fs_client_access (conn, client, (flags & FontOpenSync) != 0);
1612 _fs_client_resolution(conn);
1614 /* do an FS_OpenFont, FS_QueryXInfo and FS_QueryXExtents */
1615 buf[0] = (unsigned char) namelen;
1616 memcpy(&buf[1], name, namelen);
1617 openreq.reqType = FS_OpenBitmapFont;
1619 openreq.fid = fsd->fontid;
1620 openreq.format_hint = fsd->format;
1621 openreq.format_mask = fsd->fmask;
1622 openreq.length = (SIZEOF(fsOpenBitmapFontReq) + namelen + 4) >> 2;
1624 _fs_add_req_log(conn, FS_OpenBitmapFont);
1625 _fs_write(conn, (char *) &openreq, SIZEOF(fsOpenBitmapFontReq));
1626 _fs_write_pad(conn, (char *) buf, namelen + 1);
1628 blockrec->sequenceNumber = conn->current_seq;
1630 inforeq.reqType = FS_QueryXInfo;
1632 inforeq.id = fsd->fontid;
1633 inforeq.length = SIZEOF(fsQueryXInfoReq) >> 2;
1635 bfont->queryInfoSequence = conn->current_seq + 1;
1637 _fs_add_req_log(conn, FS_QueryXInfo);
1638 _fs_write(conn, (char *) &inforeq, SIZEOF(fsQueryXInfoReq));
1640 if (!(bfont->flags & FontReopen))
1642 extreq.reqType = FS_QueryXExtents16;
1643 extreq.range = fsTrue;
1644 extreq.fid = fsd->fontid;
1645 extreq.num_ranges = 0;
1646 extreq.length = SIZEOF(fsQueryXExtents16Req) >> 2;
1648 bfont->queryExtentsSequence = conn->current_seq + 1;
1650 _fs_add_req_log(conn, FS_QueryXExtents16);
1651 _fs_write(conn, (char *) &extreq, SIZEOF(fsQueryXExtents16Req));
1655 if (configData.ExtendedFontDiags)
1657 memcpy(buf, name, MIN(256, namelen));
1658 buf[MIN(256, namelen)] = '\0';
1659 printf("Requesting font \"%s\" from font server \"%s\"\n",
1660 buf, font->fpe->name);
1663 _fs_prepare_for_reply (conn);
1665 err = blockrec->errcode;
1666 if (bfont->flags & FontOpenSync)
1668 while (blockrec->errcode == StillWorking)
1670 if (fs_await_reply (conn) != FSIO_READY)
1672 blockrec->errcode = BadFontName;
1675 fs_read_reply (font->fpe, client);
1677 err = blockrec->errcode;
1678 if (err == Successful)
1679 *ppfont = bfont->pfont;
1681 fs_cleanup_bfont (bfont);
1682 bfont->freeFont = FALSE;
1683 _fs_remove_block_rec (conn, blockrec);
1685 return err == StillWorking ? Suspended : err;
1689 fs_send_query_bitmaps(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
1691 FSFpePtr conn = (FSFpePtr) fpe->private;
1692 FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
1693 fsQueryXBitmaps16Req bitreq;
1695 /* send the request */
1696 bitreq.reqType = FS_QueryXBitmaps16;
1697 bitreq.fid = bfont->fontid;
1698 bitreq.format = bfont->format;
1699 bitreq.range = TRUE;
1700 bitreq.length = SIZEOF(fsQueryXBitmaps16Req) >> 2;
1701 bitreq.num_ranges = 0;
1703 bfont->queryBitmapsSequence = conn->current_seq + 1;
1705 _fs_add_req_log(conn, FS_QueryXBitmaps16);
1706 _fs_write(conn, (char *) &bitreq, SIZEOF(fsQueryXBitmaps16Req));
1711 fs_open_font(pointer client, FontPathElementPtr fpe, Mask flags,
1712 char *name, int namelen,
1713 fsBitmapFormat format, fsBitmapFormatMask fmask,
1714 XID id, FontPtr *ppfont,
1715 char **alias, FontPtr non_cachable_font)
1717 FSFpePtr conn = (FSFpePtr) fpe->private;
1718 FSBlockDataPtr blockrec;
1719 FSBlockedFontPtr bfont;
1722 /* libfont interface expects ImageRectMin glyphs */
1723 format = (format & ~BitmapFormatImageRectMask) | BitmapFormatImageRectMin;
1725 *alias = (char *) 0;
1726 for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
1728 if (blockrec->type == FS_OPEN_FONT && blockrec->client == client)
1730 err = blockrec->errcode;
1731 if (err == StillWorking)
1734 bfont = (FSBlockedFontPtr) blockrec->data;
1735 if (err == Successful)
1736 *ppfont = bfont->pfont;
1738 fs_cleanup_bfont (bfont);
1739 _fs_remove_block_rec (conn, blockrec);
1743 return fs_send_open_font(client, fpe, flags, name, namelen, format, fmask,
1749 fs_send_close_font(FontPathElementPtr fpe, Font id)
1751 FSFpePtr conn = (FSFpePtr) fpe->private;
1754 if (conn->blockState & FS_GIVE_UP)
1756 /* tell the font server to close the font */
1757 req.reqType = FS_CloseFont;
1759 req.length = SIZEOF(fsCloseReq) >> 2;
1761 _fs_add_req_log(conn, FS_CloseFont);
1762 _fs_write(conn, (char *) &req, SIZEOF(fsCloseReq));
1769 fs_close_font(FontPathElementPtr fpe, FontPtr pfont)
1771 FSFontDataPtr fsd = (FSFontDataPtr) pfont->fpePrivate;
1772 FSFpePtr conn = (FSFpePtr) fpe->private;
1774 if (conn->generation == fsd->generation)
1775 fs_send_close_font(fpe, fsd->fontid);
1779 FSBlockDataPtr blockrec;
1780 FSBlockedFontPtr bfont;
1782 for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
1784 if (blockrec->type == FS_OPEN_FONT)
1786 bfont = (FSBlockedFontPtr) blockrec->data;
1787 if (bfont->pfont == pfont)
1788 fprintf (stderr, "closing font which hasn't been opened\n");
1793 (*pfont->unload_font) (pfont);
1797 fs_read_glyphs(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
1799 FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr) blockrec->data;
1800 FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data;
1801 FSFpePtr conn = (FSFpePtr) fpe->private;
1802 FontPtr pfont = bglyph->pfont;
1803 /* works for either blocked font
1804 or glyph rec... pfont is at
1805 the very beginning of both
1806 blockrec->data structures */
1807 FSFontDataPtr fsd = (FSFontDataPtr) (pfont->fpePrivate);
1808 FSFontPtr fsdata = (FSFontPtr) pfont->fontPrivate;
1809 FontInfoPtr pfi = &pfont->info;
1810 fsQueryXBitmaps16Reply *rep;
1813 fsOffset32 local_off;
1816 char *bits, *allbits;
1824 fsRange *nextrange = 0;
1825 unsigned long minchar, maxchar;
1827 rep = (fsQueryXBitmaps16Reply *) fs_get_reply (conn, &ret);
1828 if (!rep || rep->type == FS_Error)
1830 if (ret == FSIO_BLOCK)
1831 return StillWorking;
1833 _fs_done_read (conn, rep->length << 2);
1839 buf += SIZEOF (fsQueryXBitmaps16Reply);
1841 ppbits = (fsOffset32 *) buf;
1842 buf += SIZEOF (fsOffset32) * (rep->num_chars);
1844 pbitmaps = (pointer ) buf;
1846 if (blockrec->type == FS_LOAD_GLYPHS)
1848 nranges = bglyph->num_expected_ranges;
1849 nextrange = bglyph->expected_ranges;
1852 /* place the incoming glyphs */
1855 /* We're operating under the assumption that the ranges
1856 requested in the LoadGlyphs call were all legal for this
1857 font, and that individual ranges do not cover multiple
1858 rows... fs_build_range() is designed to ensure this. */
1859 minchar = (nextrange->min_char_high - pfi->firstRow) *
1860 (pfi->lastCol - pfi->firstCol + 1) +
1861 nextrange->min_char_low - pfi->firstCol;
1862 maxchar = (nextrange->max_char_high - pfi->firstRow) *
1863 (pfi->lastCol - pfi->firstCol + 1) +
1864 nextrange->max_char_low - pfi->firstCol;
1870 maxchar = rep->num_chars;
1873 off_adr = (char *)ppbits;
1875 allbits = fs_alloc_glyphs (pfont, rep->nbytes);
1884 origallbits = allbits;
1885 fprintf (stderr, "Reading %d glyphs in %d bytes for %s\n",
1886 (int) rep->num_chars, (int) rep->nbytes, fsd->name);
1889 for (i = 0; i < rep->num_chars; i++)
1891 memcpy(&local_off, off_adr, SIZEOF(fsOffset32)); /* align it */
1892 if (blockrec->type == FS_OPEN_FONT ||
1893 fsdata->encoding[minchar].bits == &_fs_glyph_requested)
1896 * Broken X font server returns bits for missing characters
1897 * when font is padded
1899 if (NONZEROMETRICS(&fsdata->encoding[minchar].metrics))
1901 if (local_off.length)
1904 allbits += local_off.length;
1905 memcpy(bits, (char *)pbitmaps + local_off.position,
1909 bits = &_fs_glyph_zero_length;
1913 if (fsdata->encoding[minchar].bits == &_fs_glyph_requested)
1914 fsd->glyphs_to_get--;
1915 fsdata->encoding[minchar].bits = bits;
1917 if (minchar++ == maxchar)
1919 if (!--nranges) break;
1920 minchar = (nextrange->min_char_high - pfi->firstRow) *
1921 (pfi->lastCol - pfi->firstCol + 1) +
1922 nextrange->min_char_low - pfi->firstCol;
1923 maxchar = (nextrange->max_char_high - pfi->firstRow) *
1924 (pfi->lastCol - pfi->firstCol + 1) +
1925 nextrange->max_char_low - pfi->firstCol;
1928 off_adr += SIZEOF(fsOffset32);
1931 fprintf (stderr, "Used %d bytes instead of %d\n",
1932 (int) (allbits - origallbits), (int) rep->nbytes);
1935 if (blockrec->type == FS_OPEN_FONT)
1937 fsd->glyphs_to_get = 0;
1938 bfont->state = FS_DONE_REPLY;
1943 _fs_done_read (conn, rep->length << 2);
1948 fs_send_load_glyphs(pointer client, FontPtr pfont,
1949 int nranges, fsRange *ranges)
1951 FontPathElementPtr fpe = pfont->fpe;
1952 FSFpePtr conn = (FSFpePtr) fpe->private;
1953 FSBlockedGlyphPtr blockedglyph;
1954 fsQueryXBitmaps16Req req;
1955 FSBlockDataPtr blockrec;
1957 if (conn->blockState & FS_GIVE_UP)
1958 return BadCharRange;
1960 /* make a new block record, and add it to the end of the list */
1961 blockrec = fs_new_block_rec(fpe, client, FS_LOAD_GLYPHS);
1964 blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
1965 blockedglyph->pfont = pfont;
1966 blockedglyph->num_expected_ranges = nranges;
1967 /* Assumption: it's our job to free ranges */
1968 blockedglyph->expected_ranges = ranges;
1969 blockedglyph->clients_depending = (FSClientsDependingPtr)0;
1971 if (conn->blockState & (FS_BROKEN_CONNECTION|FS_RECONNECTING))
1973 _fs_pending_reply (conn);
1977 /* send the request */
1978 req.reqType = FS_QueryXBitmaps16;
1979 req.fid = ((FSFontDataPtr) pfont->fpePrivate)->fontid;
1980 req.format = pfont->format;
1981 if (pfont->info.terminalFont)
1982 req.format = (req.format & ~(BitmapFormatImageRectMask)) |
1983 BitmapFormatImageRectMax;
1985 /* each range takes up 4 bytes */
1986 req.length = (SIZEOF(fsQueryXBitmaps16Req) >> 2) + nranges;
1987 req.num_ranges = nranges * 2; /* protocol wants count of fsChar2bs */
1988 _fs_add_req_log(conn, FS_QueryXBitmaps16);
1989 _fs_write(conn, (char *) &req, SIZEOF(fsQueryXBitmaps16Req));
1991 blockrec->sequenceNumber = conn->current_seq;
1993 /* Send ranges to the server... pack into a char array by hand
1994 to avoid structure-packing portability problems and to
1995 handle swapping for version1 protocol */
1998 #define RANGE_BUFFER_SIZE 64
1999 #define RANGE_BUFFER_SIZE_MASK 63
2001 char range_buffer[RANGE_BUFFER_SIZE * 4];
2002 char *range_buffer_p;
2004 range_buffer_p = range_buffer;
2005 for (i = 0; i < nranges;)
2007 if (conn->fsMajorVersion > 1)
2009 *range_buffer_p++ = ranges[i].min_char_high;
2010 *range_buffer_p++ = ranges[i].min_char_low;
2011 *range_buffer_p++ = ranges[i].max_char_high;
2012 *range_buffer_p++ = ranges[i].max_char_low;
2016 *range_buffer_p++ = ranges[i].min_char_low;
2017 *range_buffer_p++ = ranges[i].min_char_high;
2018 *range_buffer_p++ = ranges[i].max_char_low;
2019 *range_buffer_p++ = ranges[i].max_char_high;
2022 if (!(++i & RANGE_BUFFER_SIZE_MASK))
2024 _fs_write(conn, range_buffer, RANGE_BUFFER_SIZE * 4);
2025 range_buffer_p = range_buffer;
2028 if (i &= RANGE_BUFFER_SIZE_MASK)
2029 _fs_write(conn, range_buffer, i * 4);
2032 _fs_prepare_for_reply (conn);
2037 extern pointer serverClient; /* This could be any number that
2038 doesn't conflict with existing
2042 _fs_load_glyphs(pointer client, FontPtr pfont, Bool range_flag,
2043 unsigned int nchars, int item_size, unsigned char *data)
2045 FSFpePtr conn = (FSFpePtr) pfont->fpe->private;
2047 fsRange *ranges = NULL;
2049 FSBlockDataPtr blockrec;
2050 FSBlockedGlyphPtr blockedglyph;
2051 FSClientsDependingPtr *clients_depending = NULL;
2054 /* see if the result is already there */
2055 for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
2057 if (blockrec->type == FS_LOAD_GLYPHS)
2059 blockedglyph = (FSBlockedGlyphPtr) blockrec->data;
2060 if (blockedglyph->pfont == pfont)
2062 /* Look for this request */
2063 if (blockrec->client == client)
2065 err = blockrec->errcode;
2066 if (err == StillWorking)
2068 _fs_signal_clients_depending(&blockedglyph->clients_depending);
2069 _fs_remove_block_rec(conn, blockrec);
2072 /* We've found an existing LoadGlyphs blockrec for this
2073 font but for another client. Rather than build a
2074 blockrec for it now (which entails some complex
2075 maintenance), we'll add it to a queue of clients to
2076 be signalled when the existing LoadGlyphs is
2078 clients_depending = &blockedglyph->clients_depending;
2082 else if (blockrec->type == FS_OPEN_FONT)
2084 FSBlockedFontPtr bfont;
2085 bfont = (FSBlockedFontPtr) blockrec->data;
2086 if (bfont->pfont == pfont)
2089 * An OpenFont is pending for this font, this must
2090 * be from a reopen attempt, so finish the open
2091 * attempt and retry the LoadGlyphs
2093 if (blockrec->client == client)
2095 err = blockrec->errcode;
2096 if (err == StillWorking)
2099 _fs_signal_clients_depending(&bfont->clients_depending);
2100 _fs_remove_block_rec(conn, blockrec);
2101 if (err != Successful)
2105 /* We've found an existing OpenFont blockrec for this
2106 font but for another client. Rather than build a
2107 blockrec for it now (which entails some complex
2108 maintenance), we'll add it to a queue of clients to
2109 be signalled when the existing OpenFont is
2111 if (blockrec->errcode == StillWorking)
2113 clients_depending = &bfont->clients_depending;
2121 * see if the desired glyphs already exist, and return Successful if they
2122 * do, otherwise build up character range/character string
2124 res = fs_build_range(pfont, range_flag, nchars, item_size, data,
2140 * If clients_depending is not null, this request must wait for
2141 * some prior request(s) to complete.
2143 if (clients_depending)
2145 /* Since we're not ready to send the load_glyphs request yet,
2146 clean up the damage (if any) caused by the fs_build_range()
2150 _fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
2153 return _fs_add_clients_depending(clients_depending, client);
2157 * If fsd->generation != conn->generation, the font has been closed
2158 * due to a lost connection. We will reopen it, which will result
2159 * in one of three things happening:
2160 * 1) The open will succeed and obtain the same font. Life
2162 * 2) The open will fail. There is code above to recognize this
2163 * and flunk the LoadGlyphs request. The client might not be
2165 * 3) Worst case: the open will succeed but the font we open will
2166 * be different. The fs_read_query_info() procedure attempts
2167 * to detect this by comparing the existing metrics and
2168 * properties against those of the reopened font... if they
2169 * don't match, we flunk the reopen, which eventually results
2170 * in flunking the LoadGlyphs request. We could go a step
2171 * further and compare the extents, but this should be
2174 if (((FSFontDataPtr)pfont->fpePrivate)->generation != conn->generation)
2176 /* Since we're not ready to send the load_glyphs request yet,
2177 clean up the damage caused by the fs_build_range() call. */
2178 _fs_clean_aborted_loadglyphs(pfont, nranges, ranges);
2181 /* Now try to reopen the font. */
2182 return fs_send_open_font(client, pfont->fpe,
2183 (Mask)FontReopen, (char *)0, 0,
2184 (fsBitmapFormat)0, (fsBitmapFormatMask)0,
2188 return fs_send_load_glyphs(client, pfont, nranges, ranges);
2192 fs_load_all_glyphs(FontPtr pfont)
2195 FSFpePtr conn = (FSFpePtr) pfont->fpe->private;
2198 * The purpose of this procedure is to load all glyphs in the event
2199 * that we're dealing with someone who doesn't understand the finer
2200 * points of glyph caching... it is called from _fs_get_glyphs() if
2201 * the latter is called to get glyphs that have not yet been loaded.
2202 * We assume that the caller will not know how to handle a return
2203 * value of Suspended (usually the case for a GetGlyphs() caller),
2204 * so this procedure hangs around, freezing the server, for the
2205 * request to complete. This is an unpleasant kluge called to
2206 * perform an unpleasant job that, we hope, will never be required.
2209 while ((err = _fs_load_glyphs(serverClient, pfont, TRUE, 0, 0, NULL)) ==
2212 if (fs_await_reply (conn) != FSIO_READY)
2214 /* Get rid of blockrec */
2215 fs_client_died(serverClient, pfont->fpe);
2219 fs_read_reply (pfont->fpe, serverClient);
2225 fs_read_list(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
2227 FSFpePtr conn = (FSFpePtr) fpe->private;
2228 FSBlockedListPtr blist = (FSBlockedListPtr) blockrec->data;
2229 fsListFontsReply *rep;
2236 rep = (fsListFontsReply *) fs_get_reply (conn, &ret);
2237 if (!rep || rep->type == FS_Error)
2239 if (ret == FSIO_BLOCK)
2240 return StillWorking;
2242 _fs_done_read (conn, rep->length << 2);
2245 data = (char *) rep + SIZEOF (fsListFontsReply);
2248 /* copy data into FontPathRecord */
2249 for (i = 0; i < rep->nFonts; i++)
2251 length = *(unsigned char *)data++;
2252 err = AddFontNamesName(blist->names, data, length);
2253 if (err != Successful)
2257 _fs_done_read (conn, rep->length << 2);
2262 fs_send_list_fonts(pointer client, FontPathElementPtr fpe, char *pattern,
2263 int patlen, int maxnames, FontNamesPtr newnames)
2265 FSFpePtr conn = (FSFpePtr) fpe->private;
2266 FSBlockDataPtr blockrec;
2267 FSBlockedListPtr blockedlist;
2270 if (conn->blockState & FS_GIVE_UP)
2273 /* make a new block record, and add it to the end of the list */
2274 blockrec = fs_new_block_rec(fpe, client, FS_LIST_FONTS);
2277 blockedlist = (FSBlockedListPtr) blockrec->data;
2278 blockedlist->names = newnames;
2280 if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
2282 _fs_pending_reply (conn);
2286 _fs_client_access (conn, client, FALSE);
2287 _fs_client_resolution(conn);
2289 /* send the request */
2290 req.reqType = FS_ListFonts;
2292 req.maxNames = maxnames;
2293 req.nbytes = patlen;
2294 req.length = (SIZEOF(fsListFontsReq) + patlen + 3) >> 2;
2295 _fs_add_req_log(conn, FS_ListFonts);
2296 _fs_write(conn, (char *) &req, SIZEOF(fsListFontsReq));
2297 _fs_write_pad(conn, (char *) pattern, patlen);
2299 blockrec->sequenceNumber = conn->current_seq;
2302 if (configData.ExtendedFontDiags) {
2305 memcpy(buf, pattern, MIN(256, patlen));
2306 buf[MIN(256, patlen)] = '\0';
2307 printf("Listing fonts on pattern \"%s\" from font server \"%s\"\n",
2312 _fs_prepare_for_reply (conn);
2317 fs_list_fonts(pointer client, FontPathElementPtr fpe,
2318 char *pattern, int patlen, int maxnames, FontNamesPtr newnames)
2320 FSFpePtr conn = (FSFpePtr) fpe->private;
2321 FSBlockDataPtr blockrec;
2324 /* see if the result is already there */
2325 for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
2327 if (blockrec->type == FS_LIST_FONTS && blockrec->client == client)
2329 err = blockrec->errcode;
2330 if (err == StillWorking)
2332 _fs_remove_block_rec(conn, blockrec);
2337 /* didn't find waiting record, so send a new one */
2338 return fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames);
2342 * Read a single list info reply and restart for the next reply
2345 fs_read_list_info(FontPathElementPtr fpe, FSBlockDataPtr blockrec)
2347 FSBlockedListInfoPtr binfo = (FSBlockedListInfoPtr) blockrec->data;
2348 fsListFontsWithXInfoReply *rep;
2350 FSFpePtr conn = (FSFpePtr) fpe->private;
2357 /* clean up anything from the last trip */
2358 _fs_free_props (&binfo->info);
2360 rep = (fsListFontsWithXInfoReply *) fs_get_reply (conn, &ret);
2361 if (!rep || rep->type == FS_Error)
2363 if (ret == FSIO_BLOCK)
2364 return StillWorking;
2365 binfo->status = FS_LFWI_FINISHED;
2370 * Normal termination -- the list ends with a name of length 0
2372 if (rep->nameLength == 0)
2375 fprintf (stderr, "fs_read_list_info done\n");
2377 binfo->status = FS_LFWI_FINISHED;
2382 buf = (char *) rep + SIZEOF (fsListFontsWithXInfoReply);
2385 * The original FS implementation didn't match
2386 * the spec, version 1 was respecified to match the FS.
2387 * Version 2 matches the original intent
2389 if (conn->fsMajorVersion <= 1)
2391 memcpy (binfo->name, buf, rep->nameLength);
2392 buf += _fs_pad_length (rep->nameLength);
2394 pi = (fsPropInfo *) buf;
2395 buf += SIZEOF (fsPropInfo);
2396 po = (fsPropOffset *) buf;
2397 buf += pi->num_offsets * SIZEOF (fsPropOffset);
2399 buf += pi->data_len;
2400 if (conn->fsMajorVersion > 1)
2402 memcpy (binfo->name, buf, rep->nameLength);
2403 buf += _fs_pad_length (rep->nameLength);
2407 binfo->name[rep->nameLength] = '\0';
2408 fprintf (stderr, "fs_read_list_info %s\n", binfo->name);
2410 err = _fs_convert_lfwi_reply(conn, &binfo->info, rep, pi, po, pd);
2411 if (err != Successful)
2413 binfo->status = FS_LFWI_FINISHED;
2416 binfo->namelen = rep->nameLength;
2417 binfo->remaining = rep->nReplies;
2419 binfo->status = FS_LFWI_REPLY;
2421 /* disable this font server until we've processed this response */
2422 _fs_unmark_block (conn, FS_COMPLETE_REPLY);
2423 FD_CLR(conn->fs_fd, &_fs_fd_mask);
2425 _fs_done_read (conn, rep->length << 2);
2431 fs_start_list_with_info(pointer client, FontPathElementPtr fpe,
2432 char *pattern, int len, int maxnames, pointer *pdata)
2434 FSFpePtr conn = (FSFpePtr) fpe->private;
2435 FSBlockDataPtr blockrec;
2436 FSBlockedListInfoPtr binfo;
2437 fsListFontsWithXInfoReq req;
2439 if (conn->blockState & FS_GIVE_UP)
2442 /* make a new block record, and add it to the end of the list */
2443 blockrec = fs_new_block_rec(fpe, client, FS_LIST_WITH_INFO);
2447 binfo = (FSBlockedListInfoPtr) blockrec->data;
2448 bzero((char *) binfo, sizeof(FSBlockedListInfoRec));
2449 binfo->status = FS_LFWI_WAITING;
2451 if (conn->blockState & (FS_BROKEN_CONNECTION | FS_RECONNECTING))
2453 _fs_pending_reply (conn);
2457 _fs_client_access (conn, client, FALSE);
2458 _fs_client_resolution(conn);
2460 /* send the request */
2461 req.reqType = FS_ListFontsWithXInfo;
2463 req.maxNames = maxnames;
2465 req.length = (SIZEOF(fsListFontsWithXInfoReq) + len + 3) >> 2;
2466 _fs_add_req_log(conn, FS_ListFontsWithXInfo);
2467 (void) _fs_write(conn, (char *) &req, SIZEOF(fsListFontsWithXInfoReq));
2468 (void) _fs_write_pad(conn, pattern, len);
2470 blockrec->sequenceNumber = conn->current_seq;
2473 if (configData.ExtendedFontDiags) {
2476 memcpy(buf, pattern, MIN(256, len));
2477 buf[MIN(256, len)] = '\0';
2478 printf("Listing fonts with info on pattern \"%s\" from font server \"%s\"\n",
2483 _fs_prepare_for_reply (conn);
2489 fs_next_list_with_info(pointer client, FontPathElementPtr fpe,
2490 char **namep, int *namelenp,
2491 FontInfoPtr *pFontInfo, int *numFonts,
2494 FSFpePtr conn = (FSFpePtr) fpe->private;
2495 FSBlockDataPtr blockrec;
2496 FSBlockedListInfoPtr binfo;
2499 /* see if the result is already there */
2500 for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
2501 if (blockrec->type == FS_LIST_WITH_INFO && blockrec->client == client)
2506 /* The only good reason for not finding a blockrec would be if
2507 disconnect/reconnect to the font server wiped it out and the
2508 code that called us didn't do the right thing to create
2509 another one. Under those circumstances, we need to return an
2510 error to prevent that code from attempting to interpret the
2511 information we don't return. */
2515 binfo = (FSBlockedListInfoPtr) blockrec->data;
2517 if (binfo->status == FS_LFWI_WAITING)
2520 *namep = binfo->name;
2521 *namelenp = binfo->namelen;
2522 *pFontInfo = &binfo->info;
2523 *numFonts = binfo->remaining;
2525 /* Restart reply processing from this font server */
2526 FD_SET(conn->fs_fd, &_fs_fd_mask);
2527 if (fs_reply_ready (conn))
2528 _fs_mark_block (conn, FS_COMPLETE_REPLY);
2530 err = blockrec->errcode;
2531 switch (binfo->status) {
2532 case FS_LFWI_FINISHED:
2533 _fs_remove_block_rec(conn, blockrec);
2536 binfo->status = FS_LFWI_WAITING;
2537 blockrec->errcode = StillWorking;
2538 conn->blockedReplyTime = GetTimeInMillis () + FontServerRequestTimeout;
2539 _fs_mark_block (conn, FS_PENDING_REPLY);
2547 * Called when client exits
2551 fs_client_died(pointer client, FontPathElementPtr fpe)
2553 FSFpePtr conn = (FSFpePtr) fpe->private;
2554 FSBlockDataPtr blockrec,
2556 FSClientPtr *prev, cur;
2559 for (prev = &conn->clients; (cur = *prev); prev = &cur->next)
2561 if (cur->client == client) {
2562 freeac.reqType = FS_FreeAC;
2564 freeac.id = cur->acid;
2565 freeac.length = sizeof (fsFreeACReq) >> 2;
2566 _fs_add_req_log(conn, FS_FreeAC);
2567 _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
2573 /* find a pending requests */
2574 for (blockrec = conn->blockedRequests; blockrec; blockrec = blockrec->next)
2575 if (blockrec->client == client)
2581 /* replace the client pointers in this block rec with the chained one */
2582 if ((depending = blockrec->depending))
2584 blockrec->client = depending->client;
2585 blockrec->depending = depending->depending;
2586 blockrec = depending;
2588 fs_abort_blockrec(conn, blockrec);
2592 _fs_client_access (FSFpePtr conn, pointer client, Bool sync)
2594 FSClientPtr *prev, cur;
2596 fsSetAuthorizationReq setac;
2597 char *authorizations;
2599 Bool new_cur = FALSE;
2600 char padding[4] = { 0, 0, 0, 0 };
2603 if (conn->blockState & (FS_RECONNECTING|FS_BROKEN_CONNECTION))
2605 fprintf (stderr, "Sending requests without a connection\n");
2608 for (prev = &conn->clients; (cur = *prev); prev = &cur->next)
2610 if (cur->client == client)
2612 if (prev != &conn->clients)
2615 cur->next = conn->clients;
2616 conn->clients = cur;
2623 cur = malloc (sizeof (FSClientRec));
2626 cur->client = client;
2627 cur->next = conn->clients;
2628 conn->clients = cur;
2629 cur->acid = GetNewFontClientID ();
2632 if (new_cur || cur->auth_generation != client_auth_generation(client))
2637 freeac.reqType = FS_FreeAC;
2639 freeac.id = cur->acid;
2640 freeac.length = sizeof (fsFreeACReq) >> 2;
2641 _fs_add_req_log(conn, FS_FreeAC);
2642 _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq));
2644 crac.reqType = FS_CreateAC;
2645 crac.num_auths = set_font_authorizations(&authorizations, &authlen,
2647 /* Work around bug in xfs versions up through modular release 1.0.8
2648 which rejects CreateAC packets with num_auths = 0 & authlen < 4 */
2649 if (crac.num_auths == 0) {
2650 authorizations = padding;
2653 authlen = (authlen + 3) & ~0x3;
2655 crac.length = (sizeof (fsCreateACReq) + authlen) >> 2;
2656 crac.acid = cur->acid;
2657 _fs_add_req_log(conn, FS_CreateAC);
2658 _fs_write(conn, (char *) &crac, sizeof (fsCreateACReq));
2659 _fs_write(conn, authorizations, authlen);
2660 /* ignore reply; we don't even care about it */
2662 cur->auth_generation = client_auth_generation(client);
2664 if (conn->curacid != cur->acid)
2666 setac.reqType = FS_SetAuthorization;
2668 setac.length = sizeof (fsSetAuthorizationReq) >> 2;
2669 setac.id = cur->acid;
2670 _fs_add_req_log(conn, FS_SetAuthorization);
2671 _fs_write(conn, (char *) &setac, sizeof (fsSetAuthorizationReq));
2672 conn->curacid = cur->acid;
2677 * Poll a pending connect
2681 _fs_check_connect (FSFpePtr conn)
2685 ret = _fs_poll_connect (conn->trans_conn, 0);
2688 conn->fs_fd = _FontTransGetConnectionNumber (conn->trans_conn);
2689 FD_SET (conn->fs_fd, &_fs_fd_mask);
2698 * Return an FSIO status while waiting for the completed connection
2702 static fsConnSetup *
2703 _fs_get_conn_setup (FSFpePtr conn, int *error, int *setup_len)
2710 fsConnSetupAccept *accept;
2712 ret = _fs_start_read (conn, SIZEOF (fsConnSetup), &data);
2713 if (ret != FSIO_READY)
2719 setup = (fsConnSetup *) data;
2720 if (setup->major_version > FS_PROTOCOL)
2722 *error = FSIO_ERROR;
2726 headlen = (SIZEOF (fsConnSetup) +
2727 (setup->alternate_len << 2) +
2728 (setup->auth_len << 2));
2729 /* On anything but Success, no extra data is sent */
2730 if (setup->status != AuthSuccess)
2736 ret = _fs_start_read (conn, headlen + SIZEOF (fsConnSetupAccept), &data);
2737 if (ret != FSIO_READY)
2742 setup = (fsConnSetup *) data;
2743 accept = (fsConnSetupAccept *) (data + headlen);
2744 len = headlen + (accept->length << 2);
2746 ret = _fs_start_read (conn, len, &data);
2747 if (ret != FSIO_READY)
2753 return (fsConnSetup *) data;
2757 _fs_send_conn_client_prefix (FSFpePtr conn)
2759 fsConnClientPrefix req;
2763 /* send setup prefix */
2765 if (*(char *) &endian)
2766 req.byteOrder = 'l';
2768 req.byteOrder = 'B';
2770 req.major_version = FS_PROTOCOL;
2771 req.minor_version = FS_PROTOCOL_MINOR;
2773 /* XXX add some auth info here */
2776 ret = _fs_write (conn, (char *) &req, SIZEOF (fsConnClientPrefix));
2777 if (ret != FSIO_READY)
2779 conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
2784 _fs_recv_conn_setup (FSFpePtr conn)
2786 int ret = FSIO_ERROR;
2791 char *alt_save, *alt_names;
2793 setup = _fs_get_conn_setup (conn, &ret, &setup_len);
2796 conn->current_seq = 0;
2797 conn->fsMajorVersion = setup->major_version;
2799 * Create an alternate list from the initial server, but
2800 * don't chain looking for alternates.
2802 if (conn->alternate == 0)
2805 * free any existing alternates list, allowing the list to
2814 if (setup->num_alternates)
2816 alts = malloc (setup->num_alternates * sizeof (FSFpeAltRec) +
2817 (setup->alternate_len << 2));
2820 alt_names = (char *) (setup + 1);
2821 alt_save = (char *) (alts + setup->num_alternates);
2822 for (i = 0; i < setup->num_alternates; i++)
2824 alts[i].subset = alt_names[0];
2825 alt_len = alt_names[1];
2826 alts[i].name = alt_save;
2827 memcpy (alt_save, alt_names + 2, alt_len);
2828 alt_save[alt_len] = '\0';
2829 alt_save += alt_len + 1;
2830 alt_names += _fs_pad_length (alt_len + 2);
2832 conn->numAlts = setup->num_alternates;
2837 _fs_done_read (conn, setup_len);
2838 if (setup->status != AuthSuccess)
2844 _fs_open_server (FSFpePtr conn)
2849 if (conn->alternate == 0)
2850 servername = conn->servername;
2852 servername = conn->alts[conn->alternate-1].name;
2853 conn->trans_conn = _fs_connect (servername, &ret);
2854 conn->blockedConnectTime = GetTimeInMillis () + FS_RECONNECT_WAIT;
2859 _fs_catalog_name (char *servername)
2863 sp = strchr (servername, '/');
2866 return strrchr (sp + 1, '/');
2870 _fs_send_init_packets (FSFpePtr conn)
2872 fsSetResolutionReq srreq;
2873 fsSetCataloguesReq screq;
2881 FontResolutionPtr res;
2883 #define CATALOGUE_SEP '+'
2885 res = GetClientResolutions(&num_res);
2888 srreq.reqType = FS_SetResolution;
2889 srreq.num_resolutions = num_res;
2890 srreq.length = (SIZEOF(fsSetResolutionReq) +
2891 (num_res * SIZEOF(fsResolution)) + 3) >> 2;
2893 _fs_add_req_log(conn, FS_SetResolution);
2894 if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != FSIO_READY)
2896 if (_fs_write_pad(conn, (char *) res, (num_res * SIZEOF(fsResolution))) != FSIO_READY)
2901 if (conn->alternate != 0)
2902 catalogues = _fs_catalog_name (conn->alts[conn->alternate-1].name);
2904 catalogues = _fs_catalog_name (conn->servername);
2908 conn->has_catalogues = FALSE;
2911 conn->has_catalogues = TRUE;
2913 /* turn cats into counted list */
2922 end = strchr(cat, CATALOGUE_SEP);
2924 end = cat + strlen (cat);
2925 clen += (end - cat) + 1; /* length byte + string */
2929 screq.reqType = FS_SetCatalogues;
2930 screq.num_catalogues = num_cats;
2931 screq.length = (SIZEOF(fsSetCataloguesReq) + clen + 3) >> 2;
2933 _fs_add_req_log(conn, FS_SetCatalogues);
2934 if (_fs_write(conn, (char *) &screq, SIZEOF(fsSetCataloguesReq)) != FSIO_READY)
2940 end = strchr(cat, CATALOGUE_SEP);
2942 end = cat + strlen (cat);
2944 if (_fs_write (conn, &len, 1) != FSIO_READY)
2946 if (_fs_write (conn, cat, (int) len) != FSIO_READY)
2951 if (_fs_write (conn, "....", _fs_pad_length (clen) - clen) != FSIO_READY)
2958 _fs_send_cat_sync (FSFpePtr conn)
2960 fsListCataloguesReq lcreq;
2963 * now sync up with the font server, to see if an error was generated
2964 * by a bogus catalogue
2966 lcreq.reqType = FS_ListCatalogues;
2967 lcreq.length = (SIZEOF(fsListCataloguesReq)) >> 2;
2971 _fs_add_req_log(conn, FS_SetCatalogues);
2972 if (_fs_write(conn, (char *) &lcreq, SIZEOF(fsListCataloguesReq)) != FSIO_READY)
2974 conn->blockedConnectTime = GetTimeInMillis () + FontServerRequestTimeout;
2979 _fs_recv_cat_sync (FSFpePtr conn)
2981 fsGenericReply *reply;
2986 reply = fs_get_reply (conn, &err);
2991 if (reply->type == FS_Error)
2993 error = (fsError *) reply;
2994 if (error->major_opcode == FS_SetCatalogues)
2997 _fs_done_read (conn, reply->length << 2);
3002 _fs_close_server (FSFpePtr conn)
3004 _fs_unmark_block (conn, FS_PENDING_WRITE|FS_BROKEN_WRITE|FS_COMPLETE_REPLY|FS_BROKEN_CONNECTION);
3005 if (conn->trans_conn)
3007 _FontTransClose (conn->trans_conn);
3008 conn->trans_conn = 0;
3009 _fs_io_reinit (conn);
3011 if (conn->fs_fd >= 0)
3013 FD_CLR (conn->fs_fd, &_fs_fd_mask);
3016 conn->fs_conn_state = FS_CONN_UNCONNECTED;
3020 _fs_do_setup_connection (FSFpePtr conn)
3027 fprintf (stderr, "fs_do_setup_connection state %d\n", conn->fs_conn_state);
3029 switch (conn->fs_conn_state) {
3030 case FS_CONN_UNCONNECTED:
3031 ret = _fs_open_server (conn);
3032 if (ret == FSIO_BLOCK)
3033 conn->fs_conn_state = FS_CONN_CONNECTING;
3035 case FS_CONN_CONNECTING:
3036 ret = _fs_check_connect (conn);
3038 case FS_CONN_CONNECTED:
3039 ret = _fs_send_conn_client_prefix (conn);
3041 case FS_CONN_SENT_PREFIX:
3042 ret = _fs_recv_conn_setup (conn);
3044 case FS_CONN_RECV_INIT:
3045 ret = _fs_send_init_packets (conn);
3046 if (conn->has_catalogues)
3047 ret = _fs_send_cat_sync (conn);
3049 case FS_CONN_SENT_CAT:
3050 if (conn->has_catalogues)
3051 ret = _fs_recv_cat_sync (conn);
3061 if (conn->fs_conn_state < FS_CONN_RUNNING)
3062 conn->fs_conn_state++;
3065 if (TimeCmp (GetTimeInMillis (), <, conn->blockedConnectTime))
3068 /* fall through... */
3070 _fs_close_server (conn);
3072 * Try the next alternate
3074 if (conn->alternate < conn->numAlts)
3080 conn->alternate = 0;
3083 } while (conn->fs_conn_state != FS_CONN_RUNNING && ret == FSIO_READY);
3084 if (ret == FSIO_READY)
3085 conn->generation = ++generationCount;
3090 _fs_wait_connect (FSFpePtr conn)
3096 ret = _fs_do_setup_connection (conn);
3097 if (ret != FSIO_BLOCK)
3099 if (conn->fs_conn_state <= FS_CONN_CONNECTING)
3100 ret = _fs_poll_connect (conn->trans_conn, 1000);
3102 ret = _fs_wait_for_readable (conn, 1000);
3103 if (ret == FSIO_ERROR)
3110 * Poll a connection in the process of reconnecting
3113 _fs_check_reconnect (FSFpePtr conn)
3117 ret = _fs_do_setup_connection (conn);
3120 _fs_unmark_block (conn, FS_RECONNECTING|FS_GIVE_UP);
3121 _fs_restart_connection (conn);
3126 conn->brokenConnectionTime = GetTimeInMillis () + FS_RECONNECT_POLL;
3132 * Start the reconnection process
3135 _fs_start_reconnect (FSFpePtr conn)
3137 if (conn->blockState & FS_RECONNECTING)
3139 conn->alternate = 0;
3140 _fs_mark_block (conn, FS_RECONNECTING);
3141 _fs_unmark_block (conn, FS_BROKEN_CONNECTION);
3142 _fs_check_reconnect (conn);
3147 _fs_init_conn (char *servername)
3151 conn = calloc (1, sizeof (FSFpeRec) + strlen (servername) + 1);
3154 if (!_fs_io_init (conn))
3159 conn->servername = (char *) (conn + 1);
3160 conn->fs_conn_state = FS_CONN_UNCONNECTED;
3162 strcpy (conn->servername, servername);
3167 _fs_free_conn (FSFpePtr conn)
3169 _fs_close_server (conn);
3177 * called at server init time
3181 fs_register_fpe_functions(void)
3183 RegisterFPEFunctions(fs_name_check,
3190 fs_start_list_with_info,
3191 fs_next_list_with_info,