diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:40 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:40 +0000 |
commit | 153e8da44452905ae04a0e20ad0d85f40399b4ca (patch) | |
tree | b4e614de58d4b596dab3dcc7fd4054ec96db592a /src/fc |
R6.6 is the Xorg base-lineXORG-MAIN
Diffstat (limited to 'src/fc')
-rw-r--r-- | src/fc/fsconvert.c | 702 | ||||
-rw-r--r-- | src/fc/fserve.c | 2815 | ||||
-rw-r--r-- | src/fc/fserve.h | 68 | ||||
-rw-r--r-- | src/fc/fservestr.h | 188 | ||||
-rw-r--r-- | src/fc/fsio.c | 612 | ||||
-rw-r--r-- | src/fc/fsio.h | 82 | ||||
-rw-r--r-- | src/fc/fslibos.h | 212 |
7 files changed, 4679 insertions, 0 deletions
diff --git a/src/fc/fsconvert.c b/src/fc/fsconvert.c new file mode 100644 index 0000000..1c8c6d1 --- /dev/null +++ b/src/fc/fsconvert.c @@ -0,0 +1,702 @@ +/* $Xorg: fsconvert.c,v 1.3 2000/08/17 19:46:36 cpqbld Exp $ */ +/* + * 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 name of Network Computing Devices not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Network Computing Devices + * makes no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL NETWORK COMPUTING DEVICES 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 + */ +/* + * FS data conversion + */ + +#include <X11/X.h> +#include "FS.h" +#include "FSproto.h" +#include "fontmisc.h" +#include "fontstruct.h" +#include "fservestr.h" + +extern char _fs_glyph_undefined; +extern char _fs_glyph_requested; +extern char _fs_glyph_zero_length; + +extern int _fs_load_glyphs(); + +/* + * converts data from font server form to X server form + */ + +void +_fs_convert_char_info(src, dst) + fsXCharInfo *src; + xCharInfo *dst; +{ + dst->ascent = src->ascent; + dst->descent = src->descent; + dst->leftSideBearing = src->left; + dst->rightSideBearing = src->right; + dst->characterWidth = src->width; + dst->attributes = src->attributes; +} + +void +_fs_init_fontinfo(conn, pfi) + FSFpePtr conn; + FontInfoPtr pfi; +{ + if (conn->fsMajorVersion == 1) { + unsigned short n; + n = pfi->firstCol; + pfi->firstCol = pfi->firstRow; + pfi->firstRow = n; + n = pfi->lastCol; + pfi->lastCol = pfi->lastRow; + pfi->lastRow = n; + pfi->defaultCh = (pfi->defaultCh >> 8) & 0xff + + ((pfi->defaultCh & 0xff) << 8); + } + + if (FontCouldBeTerminal (pfi)) + { + pfi->terminalFont = TRUE; + pfi->minbounds.ascent = pfi->fontAscent; + pfi->minbounds.descent = pfi->fontDescent; + pfi->minbounds.leftSideBearing = 0; + pfi->minbounds.rightSideBearing = pfi->minbounds.characterWidth; + pfi->maxbounds = pfi->minbounds; + } + + FontComputeInfoAccelerators (pfi); +} + +int +_fs_convert_props(pi, po, pd, pfi) + fsPropInfo *pi; + fsPropOffset *po; + pointer pd; + FontInfoPtr pfi; +{ + FontPropPtr dprop; + int i, + nprops; + char *is_str; + fsPropOffset local_off; + char *off_adr; + +/* stolen from server/include/resource.h */ +#define BAD_RESOURCE 0xe0000000 + + nprops = pfi->nprops = pi->num_offsets; + + dprop = (FontPropPtr) xalloc(sizeof(FontPropRec) * nprops); + is_str = (char *) xalloc(sizeof(char) * nprops); + if (!dprop || !is_str) { + xfree(is_str); + xfree(dprop); + return -1; + } + pfi->props = dprop; + pfi->isStringProp = is_str; + + off_adr = (char *)po; + for (i = 0; i < nprops; i++, dprop++, is_str++) { + memcpy(&local_off, off_adr, SIZEOF(fsPropOffset)); + dprop->name = MakeAtom(&pd[local_off.name.position], + local_off.name.length, 1); + if (local_off.type != PropTypeString) { + *is_str = FALSE; + dprop->value = local_off.value.position; + } else { + *is_str = TRUE; + dprop->value = (INT32) MakeAtom(&pd[local_off.value.position], + local_off.value.length, 1); + if (dprop->value == BAD_RESOURCE) + { + xfree (pfi->props); + xfree (pfi->isStringProp); + pfi->props = 0; + pfi->isStringProp = 0; + return -1; + } + } + off_adr += SIZEOF(fsPropOffset); + } + + return nprops; +} + +int +_fs_convert_lfwi_reply(conn, pfi, fsrep, pi, po, pd) + FSFpePtr conn; + FontInfoPtr pfi; + fsListFontsWithXInfoReply *fsrep; + fsPropInfo *pi; + fsPropOffset *po; + pointer pd; +{ + fsUnpack_XFontInfoHeader(fsrep, pfi); + _fs_init_fontinfo(conn, pfi); + + if (_fs_convert_props(pi, po, pd, pfi) == -1) + return AllocError; + + return Successful; +} + + +#define ENCODING_UNDEFINED(enc) \ + ((enc)->bits == &_fs_glyph_undefined ? \ + TRUE : \ + (access_done = access_done && (enc)->bits != &_fs_glyph_requested, \ + FALSE)) + +#define GLYPH_UNDEFINED(loc) ENCODING_UNDEFINED(encoding + (loc)) + +/* + * figures out what glyphs to request + * + * Includes logic to attempt to reduce number of round trips to the font + * server: when a glyph is requested, fs_build_range() requests a + * 16-glyph range of glyphs that contains the requested glyph. This is + * predicated on the belief that using a glyph increases the chances + * that nearby glyphs will be used: a good assumption for phonetic + * alphabets, but a questionable one for ideographic/pictographic ones. + */ +/* ARGSUSED */ +int +fs_build_range(pfont, range_flag, count, item_size, data, nranges, ranges) + FontPtr pfont; + Bool range_flag; + register unsigned int count; + int item_size; + register unsigned char *data; + int *nranges; + fsRange **ranges; +{ + FSFontDataPtr fsd = (FSFontDataPtr) (pfont->fpePrivate); + FSFontPtr fsfont = (FSFontPtr) (pfont->fontPrivate); + register CharInfoPtr encoding = fsfont->encoding; + FontInfoPtr pfi = &(pfont->info); + fsRange range; + int access_done = TRUE; + int err; + register unsigned long firstrow, lastrow, firstcol, lastcol; + register unsigned long row; + register unsigned long col; + register unsigned long loc; + + if (!fsd->glyphs_to_get) + return AccessDone; + + firstrow = pfi->firstRow; + lastrow = pfi->lastRow; + firstcol = pfi->firstCol; + lastcol = pfi->lastCol; + + /* Make sure we have default char */ + if (fsfont->pDefault && ENCODING_UNDEFINED(fsfont->pDefault)) + { + loc = fsfont->pDefault - encoding; + row = loc / (lastcol - firstcol + 1) + firstrow; + col = loc % (lastcol - firstcol + 1) + firstcol; + + range.min_char_low = range.max_char_low = col; + range.min_char_high = range.max_char_high = row; + + if ((err = add_range(&range, nranges, ranges, FALSE)) != + Successful) return err; + encoding[loc].bits = &_fs_glyph_requested; + access_done = FALSE; + } + + if (!range_flag && item_size == 1) + { + if (firstrow != 0) return AccessDone; + while (count--) + { + col = *data++; + if (col >= firstcol && col <= lastcol && + GLYPH_UNDEFINED(col - firstcol)) + { + int col1, col2; + col1 = col & 0xf0; + col2 = col1 + 15; + if (col1 < firstcol) col1 = firstcol; + if (col2 > lastcol) col2 = lastcol; + /* Collect a 16-glyph neighborhood containing the requested + glyph... should in most cases reduce the number of round + trips to the font server. */ + for (col = col1; col <= col2; col++) + { + if (!GLYPH_UNDEFINED(col - firstcol)) continue; + range.min_char_low = range.max_char_low = col; + range.min_char_high = range.max_char_high = 0; + if ((err = add_range(&range, nranges, ranges, FALSE)) != + Successful) return err; + encoding[col - firstcol].bits = &_fs_glyph_requested; + access_done = FALSE; + } + } + } + } + else + { + fsRange fullrange[1]; + + if (range_flag && count == 0) + { + count = 2; + data = (unsigned char *)fullrange; + fullrange[0].min_char_high = firstrow; + fullrange[0].min_char_low = firstcol; + fullrange[0].max_char_high = lastrow; + fullrange[0].max_char_low = lastcol; + } + + while (count--) + { + int row1, col1, row2, col2; + row1 = row2 = *data++; + col1 = col2 = *data++; + if (range_flag) + { + if (count) + { + row2 = *data++; + col2 = *data++; + count--; + } + else + { + row2 = lastrow; + col2 = lastcol; + } + if (row1 < firstrow) row1 = firstrow; + if (row2 > lastrow) row2 = lastrow; + if (col1 < firstcol) col1 = firstcol; + if (col2 > lastcol) col2 = lastcol; + } + else + { + if (row1 < firstrow || row1 > lastrow || + col1 < firstcol || col1 > lastcol) + continue; + } + for (row = row1; row <= row2; row++) + { + expand_glyph_range: ; + loc = (row - firstrow) * (lastcol + 1 - firstcol) + + (col1 - firstcol); + for (col = col1; col <= col2; col++, loc++) + { + if (GLYPH_UNDEFINED(loc)) + { + if (row1 == row2 && + ((col1 & 0xf) && col1 > firstcol || + (col2 & 0xf) != 0xf) && (col2 < lastcol)) + { + /* If we're loading from a single row, expand + range of glyphs loaded to a multiple of + a 16-glyph range -- attempt to reduce number + of round trips to the font server. */ + col1 &= 0xf0; + col2 = (col2 & 0xf0) + 15; + if (col1 < firstcol) col1 = firstcol; + if (col2 > lastcol) col2 = lastcol; + goto expand_glyph_range; + } + range.min_char_low = range.max_char_low = col; + range.min_char_high = range.max_char_high = row; + if ((err = add_range(&range, nranges, ranges, FALSE)) != + Successful) return err; + encoding[loc].bits = &_fs_glyph_requested; + access_done = FALSE; + } + } + } + } + } + + return access_done ? + AccessDone : + Successful; +} + +#undef GLYPH_UNDEFINED +#undef ENCODING_UNDEFINED + + +/* _fs_clean_aborted_loadglyphs(): Undoes the changes to the encoding array + performed by fs_build_range(); for use if the associated LoadGlyphs + requests needs to be cancelled. */ + +void +_fs_clean_aborted_loadglyphs(pfont, num_expected_ranges, expected_ranges) + FontPtr pfont; + int num_expected_ranges; + fsRange *expected_ranges; +{ + register FSFontPtr fsfont; + register FSFontDataRec *fsd; + register int i; + + fsfont = (FSFontPtr) pfont->fontPrivate; + fsd = (FSFontDataRec *) pfont->fpePrivate; + if (fsfont->encoding) + { + fsRange full_range[1]; + if (!num_expected_ranges) + { + full_range[0].min_char_low = pfont->info.firstCol; + full_range[0].min_char_high = pfont->info.firstRow; + full_range[0].max_char_low = pfont->info.lastCol; + full_range[0].max_char_high = pfont->info.lastRow; + num_expected_ranges = 1; + expected_ranges = full_range; + } + + for (i = 0; i < num_expected_ranges; i++) + { + int row, col; + for (row = expected_ranges[i].min_char_high; + row <= expected_ranges[i].max_char_high; + row++) + { + register CharInfoPtr encoding = fsfont->encoding + + ((row - pfont->info.firstRow) * + (pfont->info.lastCol - + pfont->info.firstCol + 1) + + expected_ranges[i].min_char_low - + pfont->info.firstCol); + for (col = expected_ranges[i].min_char_low; + col <= expected_ranges[i].max_char_low; + encoding++, col++) + { + if (encoding->bits == &_fs_glyph_requested) + encoding->bits = &_fs_glyph_undefined; + } + } + } + } +} + + +/* + * figures out what extents to request + * this is where lots of extra + * smarts wants to live + */ +/* ARGSUSED */ +int +_fs_check_extents(pfont, flags, nranges, range, blockrec) + FontPtr pfont; + Mask flags; + int nranges; + fsRange *range; + FSBlockDataPtr blockrec; +{ +/* XXX -- either fill in the requested info if we have it somewhere + * and return AccessDone, or else return Successful + */ + return Successful; +} + +/* + * figures out what glyphs to request + * this is where lots of extra + * smarts wants to live + */ +/* ARGSUSED */ +int +_fs_check_bitmaps(pfont, format, flags, nranges, range, blockrec) + FontPtr pfont; + fsBitmapFormat format; + Mask flags; + int nranges; + fsRange *range; + FSBlockDataPtr blockrec; +{ +/* XXX -- either fill in the requested info if we have it somewhere + * and return AccessDone, or else return Successful + */ + return Successful; +} + +int +_fs_get_glyphs(pFont, count, chars, charEncoding, glyphCount, glyphs) + FontPtr pFont; + unsigned long count; + register unsigned char *chars; + FontEncoding charEncoding; + unsigned long *glyphCount; /* RETURN */ + CharInfoPtr *glyphs; /* RETURN */ +{ + FSFontPtr fsdata; + unsigned int firstCol; + register unsigned int numCols; + unsigned int firstRow; + unsigned int numRows; + CharInfoPtr *glyphsBase; + register unsigned int c; + register CharInfoPtr pci; + unsigned int r; + CharInfoPtr encoding; + CharInfoPtr pDefault; + FSFontDataPtr fsd = (FSFontDataPtr) pFont->fpePrivate; + int itemSize; + int err = Successful; + + fsdata = (FSFontPtr) pFont->fontPrivate; + encoding = fsdata->encoding; + pDefault = fsdata->pDefault; + firstCol = pFont->info.firstCol; + numCols = pFont->info.lastCol - firstCol + 1; + glyphsBase = glyphs; + + + if (charEncoding == Linear8Bit || charEncoding == TwoD8Bit) + itemSize = 1; + else + itemSize = 2; + + /* In this age of glyph caching, any glyphs gotten through this + procedure should already be loaded. If they are not, we are + dealing with someone (perhaps a ddx driver optimizing a font) + that doesn't understand the finer points of glyph caching. The + CHECK_ENCODING macro checks for this condition... if found, it + calls fs_load_all_glyphs(), which corrects it. Since the caller + of this code will not know how to handle a return value of + Suspended, the fs_load_all_glyphs() procedure will block and + freeze the server until the load operation is done. Moral: the + glyphCachingMode flag really must indicate the capabilities of + the ddx drivers. */ + +#define CHECK_ENCODING(cnum) \ + ( pci = encoding + (cnum), \ + fsd->glyphs_to_get ? \ + ( pci->bits == &_fs_glyph_undefined || pci->bits == &_fs_glyph_requested ? \ + ((err = fs_load_all_glyphs(pFont)), pci) : \ + pci ) : \ + pci ) + + switch (charEncoding) { + + case Linear8Bit: + case TwoD8Bit: + if (pFont->info.firstRow > 0) + break; + if (pFont->info.allExist && pDefault) { + while (err == Successful && count--) { + c = (*chars++) - firstCol; + if (c < numCols) + *glyphs++ = CHECK_ENCODING(c); + else + *glyphs++ = pDefault; + } + } else { + while (err == Successful && count--) { + c = (*chars++) - firstCol; + if (c < numCols && CHECK_ENCODING(c)->bits) + *glyphs++ = pci; + else if (pDefault) + *glyphs++ = pDefault; + } + } + break; + case Linear16Bit: + if (pFont->info.allExist && pDefault) { + while (err == Successful && count--) { + c = *chars++ << 8; + c = (c | *chars++) - firstCol; + if (c < numCols) + *glyphs++ = CHECK_ENCODING(c); + else + *glyphs++ = pDefault; + } + } else { + while (err == Successful && count--) { + c = *chars++ << 8; + c = (c | *chars++) - firstCol; + if (c < numCols && CHECK_ENCODING(c)->bits) + *glyphs++ = pci; + else if (pDefault) + *glyphs++ = pDefault; + } + } + break; + + case TwoD16Bit: + firstRow = pFont->info.firstRow; + numRows = pFont->info.lastRow - firstRow + 1; + while (err == Successful && count--) { + r = (*chars++) - firstRow; + c = (*chars++) - firstCol; + if (r < numRows && c < numCols && + CHECK_ENCODING(r * numCols + c)->bits) + *glyphs++ = pci; + else if (pDefault) + *glyphs++ = pDefault; + } + break; + } + *glyphCount = glyphs - glyphsBase; + return err; +} + + +static int +_fs_get_metrics(pFont, count, chars, charEncoding, glyphCount, glyphs) + FontPtr pFont; + unsigned long count; + register unsigned char *chars; + FontEncoding charEncoding; + unsigned long *glyphCount; /* RETURN */ + xCharInfo **glyphs; /* RETURN */ +{ + FSFontPtr fsdata; + unsigned int firstCol; + register unsigned int numCols; + unsigned int firstRow; + unsigned int numRows; + xCharInfo **glyphsBase; + register unsigned int c; + unsigned int r; + CharInfoPtr encoding; + CharInfoPtr pDefault; + int itemSize; + + fsdata = (FSFontPtr) pFont->fontPrivate; + encoding = fsdata->inkMetrics; + pDefault = fsdata->pDefault; + firstCol = pFont->info.firstCol; + numCols = pFont->info.lastCol - firstCol + 1; + glyphsBase = glyphs; + + + /* XXX - this should be much smarter */ + /* make sure the glyphs are there */ + if (charEncoding == Linear8Bit || charEncoding == TwoD8Bit) + itemSize = 1; + else + itemSize = 2; + + switch (charEncoding) { + + case Linear8Bit: + case TwoD8Bit: + if (pFont->info.firstRow > 0) + break; + if (pFont->info.allExist && pDefault) { + while (count--) { + c = (*chars++) - firstCol; + if (c < numCols) + *glyphs++ = (xCharInfo *)&encoding[c]; + else + *glyphs++ = (xCharInfo *)pDefault; + } + } else { + while (count--) { + c = (*chars++) - firstCol; + if (c < numCols) + *glyphs++ = (xCharInfo *)(encoding + c); + else if (pDefault) + *glyphs++ = (xCharInfo *)pDefault; + } + } + break; + case Linear16Bit: + if (pFont->info.allExist && pDefault) { + while (count--) { + c = *chars++ << 8; + c = (c | *chars++) - firstCol; + if (c < numCols) + *glyphs++ = (xCharInfo *)(encoding + c); + else + *glyphs++ = (xCharInfo *)pDefault; + } + } else { + while (count--) { + c = *chars++ << 8; + c = (c | *chars++) - firstCol; + if (c < numCols) + *glyphs++ = (xCharInfo *)(encoding + c); + else if (pDefault) + *glyphs++ = (xCharInfo *)pDefault; + } + } + break; + + case TwoD16Bit: + firstRow = pFont->info.firstRow; + numRows = pFont->info.lastRow - firstRow + 1; + while (count--) { + r = (*chars++) - firstRow; + c = (*chars++) - firstCol; + if (r < numRows && c < numCols) + *glyphs++ = (xCharInfo *)(encoding + (r * numCols + c)); + else if (pDefault) + *glyphs++ = (xCharInfo *)pDefault; + } + break; + } + *glyphCount = glyphs - glyphsBase; + return Successful; +} + + +void +_fs_unload_font(pfont) + FontPtr pfont; +{ + FSFontPtr fsdata = (FSFontPtr) pfont->fontPrivate; + + if (fsdata->encoding) + { + register int i; + register CharInfoPtr encoding = fsdata->encoding; + FontInfoPtr pfi = &pfont->info; + for (i = (pfi->lastCol - pfi->firstCol + 1) * + (pfi->lastRow - pfi->firstRow + 1); + i > 0; + encoding++, i--) + { + if (encoding->bits && + encoding->bits != &_fs_glyph_undefined && + encoding->bits != &_fs_glyph_requested && + encoding->bits != &_fs_glyph_zero_length) + xfree(encoding->bits); + } + } + xfree(fsdata->encoding); + xfree(fsdata); + + pfont->fontPrivate = 0; +} + +void +_fs_init_font(pfont) + FontPtr pfont; +{ + /* set font function pointers */ + pfont->get_glyphs = _fs_get_glyphs; + pfont->get_metrics = _fs_get_metrics; + pfont->unload_font = _fs_unload_font; + pfont->unload_glyphs = (void (*)())0; +} diff --git a/src/fc/fserve.c b/src/fc/fserve.c new file mode 100644 index 0000000..95ce811 --- /dev/null +++ b/src/fc/fserve.c @@ -0,0 +1,2815 @@ +/* $Xorg: fserve.c,v 1.4 2001/02/09 02:04:02 xorgcvs Exp $ */ +/* + +Copyright 1990, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/* + * Copyright 1990 Network Computing Devices + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the names of Network Computing Devices, or Digital + * not be used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * + * NETWORK COMPUTING DEVICES, AND DIGITAL AND DISCLAIM ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES, + * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + * THIS SOFTWARE. + * + * Author: Dave Lemke, Network Computing Devices, Inc + */ +/* + * font server specific font access + */ + +#ifdef WIN32 +#define _WILLWINSOCK_ +#endif +#include <X11/X.h> +#include <X11/Xos.h> +#include "X11/Xpoll.h" +#include "FS.h" +#include "FSproto.h" +#include "fontmisc.h" +#include "fontstruct.h" +#include "fservestr.h" +#include <errno.h> +#ifdef X_NOT_STDC_ENV +extern int errno; +#define Time_t long +extern Time_t time (); +#else +#include <time.h> +#define Time_t time_t +#endif + +#ifdef NCD +#include <ncd/nvram.h> +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +#define NONZEROMETRICS(pci) ((pci)->leftSideBearing || \ + (pci)->rightSideBearing || \ + (pci)->ascent || \ + (pci)->descent || \ + (pci)->characterWidth) + + +extern FontPtr find_old_font(); + +extern int _fs_build_range(); + +static int fs_read_glyphs(); +static int fs_read_list(); +static int fs_read_list_info(); + +static int fs_font_type; +extern fd_set _fs_fd_mask; + +static void fs_block_handler(); +static int fs_wakeup(); + +static FSFpePtr awaiting_reconnect; + +void _fs_connection_died(); +static int _fs_restart_connection(); +static void _fs_try_reconnect(); +static int fs_send_query_info(); +static int fs_send_query_extents(); +static int fs_send_query_bitmaps(); +static int fs_send_close_font(); +static void fs_client_died(); +static void _fs_client_access(); +static void _fs_client_resolution(); + +char _fs_glyph_undefined; +char _fs_glyph_requested; +char _fs_glyph_zero_length; + +/* + * Font server access + * + * the basic idea for the non-blocking access is to have the function + * called multiple times until the actual data is returned, instead + * of ClientBlocked. + * + * the first call to the function will cause the request to be sent to + * the font server, and a block record to be stored in the fpe's list + * of outstanding requests. the FS block handler also sticks the + * proper set of fd's into the select mask. when data is ready to be + * read in, the FS wakup handler will be hit. this will read the + * data off the wire into the proper block record, and then signal the + * client that caused the block so that it can restart. it will then + * call the access function again, which will realize that the data has + * arrived and return it. + */ + + +/* XXX this should probably be a macro once its fully debugged */ +/* ARGSUSED */ +static void +_fs_add_req_log(conn, opcode) + FSFpePtr conn; + int opcode; +{ + +#ifdef DEBUG + conn->reqbuffer[conn->reqindex++] = opcode; + if (conn->reqindex == REQUEST_LOG_SIZE) + conn->reqindex = 0; +#endif + + conn->current_seq++; +} + +static Bool +fs_name_check(name) + char *name; +{ + /* Just make sure there is a protocol/ prefix */ + + return (name && *name != '/' && strchr(name, '/')); +} + +static void +_fs_client_resolution(conn) + FSFpePtr conn; +{ + fsSetResolutionReq srreq; + int num_res; + FontResolutionPtr res; + + res = GetClientResolutions(&num_res); + + if (num_res) { + srreq.reqType = FS_SetResolution; + srreq.num_resolutions = num_res; + srreq.length = (SIZEOF(fsSetResolutionReq) + + (num_res * SIZEOF(fsResolution)) + 3) >> 2; + + _fs_add_req_log(conn, FS_SetResolution); + if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) != -1) + (void)_fs_write_pad(conn, (char *) res, + (num_res * SIZEOF(fsResolution))); + } +} + +/* + * sends the stuff that's meaningful to a newly opened or reset FS + */ +static int +fs_send_init_packets(conn) + FSFpePtr conn; +{ + fsSetResolutionReq srreq; + fsSetCataloguesReq screq; + fsListCataloguesReq lcreq; + fsListCataloguesReply lcreply; + int num_cats, + clen, + len; + char *client_cat = (char *) 0, + *cp, + *sp, + *end; + int num_res; + FontResolutionPtr res; + int err = Successful; + +#define CATALOGUE_SEP '+' + + res = GetClientResolutions(&num_res); + if (num_res) { + srreq.reqType = FS_SetResolution; + srreq.num_resolutions = num_res; + srreq.length = (SIZEOF(fsSetResolutionReq) + + (num_res * SIZEOF(fsResolution)) + 3) >> 2; + + _fs_add_req_log(conn, FS_SetResolution); + if (_fs_write(conn, (char *) &srreq, SIZEOF(fsSetResolutionReq)) == -1) + { + err = BadFontPath; + goto fail; + } + if (_fs_write_pad(conn, (char *) res, (num_res * SIZEOF(fsResolution))) == -1) + { + err = BadFontPath; + goto fail; + } + } + sp = strrchr(conn->servername, '/'); + + /* don't get tricked by a non-existant catalogue list */ + if (sp == strchr(conn->servername, '/')) { + /* + * try original name -- this might be an alternate with no catalogues + */ + sp = strrchr(conn->requestedname, '/'); + if (sp == strchr(conn->requestedname, '/')) + sp = (char *) 0; + } + if (sp) { /* turn cats into counted list */ + sp++; + /* allocate more than enough room */ + cp = client_cat = (char *) xalloc(strlen(conn->servername)); + if (!cp) { + err = BadAlloc; + goto fail; + } + num_cats = 0; + while (*sp) { + end = strchr(sp, CATALOGUE_SEP); + if (!end) + end = sp + strlen(sp); + *cp++ = len = end - sp; + num_cats++; + memmove(cp, sp, len); + sp += len; + if (*sp == CATALOGUE_SEP) + sp++; + cp += len; + } + clen = cp - client_cat; + /* our list checked out, so send it */ + screq.reqType = FS_SetCatalogues; + screq.num_catalogues = num_cats; + screq.length = (SIZEOF(fsSetCataloguesReq) + clen + 3) >> 2; + + _fs_add_req_log(conn, FS_SetCatalogues); + if (_fs_write(conn, (char *) &screq, SIZEOF(fsSetCataloguesReq)) == -1) + { + err = BadFontPath; + goto fail; + } + if (_fs_write_pad(conn, (char *) client_cat, clen) == -1) + { + err = BadFontPath; + goto fail; + } + + /* + * now sync up with the font server, to see if an error was generated + * by a bogus catalogue + */ + lcreq.reqType = FS_ListCatalogues; + lcreq.length = (SIZEOF(fsListCataloguesReq)) >> 2; + lcreq.maxNames = 0; + lcreq.nbytes = 0; + _fs_add_req_log(conn, FS_SetCatalogues); + if (_fs_write(conn, (char *) &lcreq, SIZEOF(fsListCataloguesReq)) == -1) + { + err = BadFontPath; + goto fail; + } + + /* + * next bit will either by the ListCats reply, or an error followed by + * the reply + */ + if (_fs_read(conn, (char *) &lcreply, SIZEOF(fsGenericReply)) == -1) { + err = BadFontPath; + goto fail; + } + if (lcreply.type == FS_Error && + ((fsError *) & lcreply)->major_opcode == FS_SetCatalogues) { + _fs_eat_rest_of_error(conn, (fsError *) & lcreply); + /* get ListCats response */ + (void) _fs_read(conn, (char *) &lcreply, + SIZEOF(fsListCataloguesReply)); + err = BadFontPath; + goto fail; + } + /* must be reply, swallow the rest of it */ + _fs_eat_rest_of_error(conn, (fsError *) & lcreply); + } +fail: + xfree(client_cat); + return err; +} + +/* + * close font server and remove any state associated with + * this connection - this includes any client records. + */ + +static void +fs_close_conn(conn) + FSFpePtr conn; +{ + FSClientPtr client, nclient; + + /* XXX - hack. The right fix is to remember that the font server + has gone away when we first discovered it. */ + if (conn->trans_conn) + (void) _FontTransClose (conn->trans_conn); + + if (conn->fs_fd != -1) + FD_CLR(conn->fs_fd, &_fs_fd_mask); + + for (client = conn->clients; client; client = nclient) + { + nclient = client->next; + xfree (client); + } + conn->clients = NULL; +} + +/* + * the wakeup handlers have to be set when the FPE is open, and not + * removed until it is freed, in order to handle unexpected data, like + * events + */ +/* ARGSUSED */ +static int +fs_init_fpe(fpe) + FontPathElementPtr fpe; +{ + FSFpePtr conn; + char *name; + int err; + + /* open font server */ + /* create FS specific fpe info */ + errno = 0; + + name = fpe->name; + + /* hack for old style names */ + if (*name == ':') + name++; /* skip ':' */ + + conn = _fs_open_server(name); + if (conn) { + conn->requestedname = fpe->name; /* stash this for later init use */ + fpe->private = (pointer) conn; + err = fs_send_init_packets(conn); + if (err != Successful) { + fs_close_conn(conn); + xfree(conn->servername); + xfree(conn->alts); + xfree(conn); + return err; + } + if (init_fs_handlers(fpe, fs_block_handler) != Successful) + return AllocError; + FD_SET(conn->fs_fd, &_fs_fd_mask); + conn->attemptReconnect = TRUE; + +#ifdef NCD + if (configData.ExtendedFontDiags) + printf("Connected to font server \"%s\"\n", name); +#endif + + return err; + } + +#ifdef DEBUG + fprintf(stderr, "failed to connect to FS \"%s\"\n", name); +#endif + +#ifdef NCD + if (configData.ExtendedFontDiags) + printf("Failed to connect to font server \"%s\"\n", name); +#endif + + return (errno == ENOMEM) ? AllocError : BadFontPath; +} + +static int +fs_reset_fpe(fpe) + FontPathElementPtr fpe; +{ + (void) fs_send_init_packets((FSFpePtr) fpe->private); + return Successful; +} + +/* + * this shouldn't be called till all refs to the FPE are gone + */ + +static int +fs_free_fpe(fpe) + FontPathElementPtr fpe; +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSFpePtr recon, + *prev; + prev = &awaiting_reconnect; + while (*prev) { + recon = *prev; + if (conn == recon) { + *prev = recon->next_reconnect; + break; + } + prev = &recon->next_reconnect; + } + + fs_close_conn(conn); + + remove_fs_handlers(fpe, fs_block_handler, + !XFD_ANYSET(&_fs_fd_mask) && !awaiting_reconnect); + + xfree(conn->alts); + xfree(conn->servername); + xfree(conn); + fpe->private = (pointer) 0; + +#ifdef NCD + if (configData.ExtendedFontDiags) + printf("Disconnected from font server \"%s\"\n", fpe->name); +#endif + + return Successful; +} + +static FSBlockDataPtr +fs_new_block_rec(fpe, client, type) + FontPathElementPtr fpe; + pointer client; + int type; +{ + FSBlockDataPtr blockrec, + br; + FSFpePtr fsfpe = (FSFpePtr) fpe->private; + int size; + + blockrec = (FSBlockDataPtr) xalloc(sizeof(FSBlockDataRec)); + if (!blockrec) + return (FSBlockDataPtr) 0; + switch (type) { + case FS_OPEN_FONT: + size = sizeof(FSBlockedFontRec); + break; + case FS_LOAD_GLYPHS: + size = sizeof(FSBlockedGlyphRec); + break; + case FS_LIST_FONTS: + size = sizeof(FSBlockedListRec); + break; + case FS_LIST_WITH_INFO: + size = sizeof(FSBlockedListInfoRec); + break; + default: + break; + } + blockrec->data = (pointer) xalloc(size); + if (!blockrec->data) { + xfree(blockrec); + return (FSBlockDataPtr) 0; + } + blockrec->client = client; + blockrec->sequence_number = fsfpe->current_seq; + blockrec->type = type; + blockrec->depending = 0; + blockrec->next = (FSBlockDataPtr) 0; + + /* stick it on the end of the list (since its expected last) */ + br = (FSBlockDataPtr) fsfpe->blocked_requests; + if (!br) { + fsfpe->blocked_requests = (pointer) blockrec; + } else { + while (br->next) + br = br->next; + br->next = blockrec; + } + + return blockrec; +} + +static void +_fs_remove_block_rec(conn, blockrec) + FSFpePtr conn; + FSBlockDataPtr blockrec; +{ + FSBlockDataPtr br, + last; + + last = (FSBlockDataPtr) 0; + br = (FSBlockDataPtr) conn->blocked_requests; + while (br) { + if (br == blockrec) { + if (last) + last->next = br->next; + else + conn->blocked_requests = (pointer) br->next; + if (br->type == FS_LOAD_GLYPHS) + { + FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)br->data; + if (bglyph->num_expected_ranges) + xfree(bglyph->expected_ranges); + } + xfree(br->data); + xfree(br); + return; + } + last = br; + br = br->next; + } +} + +static void +signal_clients_depending(clients_depending) +FSClientsDependingPtr *clients_depending; +{ + FSClientsDependingPtr p = *clients_depending, p2; + *clients_depending = (FSClientsDependingPtr)0; + + while (p != (FSClientsDependingPtr)0) + { + p2 = p; + ClientSignal(p->client); + p = p->next; + xfree(p2); + } +} + +static int +add_clients_depending(clients_depending, client) +FSClientsDependingPtr *clients_depending; +pointer client; +{ + while (*clients_depending != (FSClientsDependingPtr)0) + { + if ((*clients_depending)->client == client) return Suspended; + clients_depending = &(*clients_depending)->next; + } + *clients_depending = (FSClientsDependingPtr)xalloc( + sizeof(FSClientsDependingRec)); + if (!*clients_depending) + return BadAlloc; + + (*clients_depending)->client = client; + (*clients_depending)->next = 0; + return Suspended; +} + +static void +clean_aborted_blockrec(blockrec) + FSBlockDataPtr blockrec; +{ + + switch(blockrec->type) + { + case FS_LOAD_GLYPHS: + { + FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr)blockrec->data; + FontPtr pfont = bglyph->pfont; + int num_expected_ranges = bglyph->num_expected_ranges; + fsRange *expected_ranges = bglyph->expected_ranges; + _fs_clean_aborted_loadglyphs(pfont, + num_expected_ranges, + expected_ranges); + signal_clients_depending(&bglyph->clients_depending); + break; + } + case FS_OPEN_FONT: + { + FSBlockedFontPtr bfont = (FSBlockedFontPtr)blockrec->data; + signal_clients_depending(&bfont->clients_depending); + break; + } + default: + break; + } +} + +static void +fs_abort_blockrec(conn, blockrec) + FSFpePtr conn; + FSBlockDataPtr blockrec; +{ + clean_aborted_blockrec(blockrec); + _fs_remove_block_rec(conn, blockrec); +} + + +static void +fs_free_font(bfont) + FSBlockedFontPtr bfont; +{ + FontPtr pfont; + FSFontDataRec *fsd; + + pfont = bfont->pfont; + fsd = (FSFontDataRec *) pfont->fpePrivate; + + /* xfree better be able to handle NULL */ + (*pfont->unload_font)(pfont); + DeleteFontClientID(fsd->fontid); + xfree(fsd->name); + xfree(pfont->info.isStringProp); + xfree(pfont->info.props); + + xfree(pfont); + xfree(fsd); + + bfont->pfont = (FontPtr) 0; +} + +static void +_fs_cleanup_font(bfont) + FSBlockedFontPtr bfont; +{ + FSFontDataRec *fsd; + + if (bfont->pfont) + { + fsd = (FSFontDataRec *) bfont->pfont->fpePrivate; + + /* make sure the FS knows we choked on it */ + fs_send_close_font(fsd->fpe, bfont->fontid); + + fs_free_font(bfont); + } + bfont->errcode = AllocError; +} + + +static int +fs_read_open_font(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsOpenBitmapFontReply rep; + FSBlockDataPtr blockOrig; + FSBlockedFontPtr origBfont; + + /* pull out the OpenFont reply */ + memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply)); + + if (rep.type == FS_Error) { + _fs_eat_rest_of_error(conn, (fsError *) & rep); + return BadFontName; + } else { /* get rest of reply */ + if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply), + SIZEOF(fsOpenBitmapFontReply) - SIZEOF(fsGenericReply)) == -1) { + /* If we're not reopening a font, we'll allocate the + structures again after connection is reestablished. */ + if (!(bfont->flags & FontReopen)) fs_free_font(bfont); + return StillWorking; + } + } + + /* If we're not reopening a font and FS detected a duplicate font + open request, replace our reference to the new font with a + reference to an existing font (possibly one not finished + opening). If this is a reopen, keep the new font reference... + it's got the metrics and extents we read when the font was opened + before. This also gives us the freedom to easily close the font + if we we decide (in fs_read_query_info()) that we don't like what + we got. */ + + if (rep.otherid && !(bfont->flags & FontReopen)) { + (void) fs_send_close_font(fpe, bfont->fontid); + + /* Find old font if we're completely done getting it from server. */ + fs_free_font(bfont); + bfont->pfont = find_old_font(rep.otherid); + bfont->fontid = rep.otherid; + bfont->state = FS_DONE_REPLY; + /* + * look for a blocked request to open the same font + */ + for (blockOrig = (FSBlockDataPtr) conn->blocked_requests; + blockOrig; + blockOrig = blockOrig->next) { + if (blockOrig != blockrec && blockOrig->type == FS_OPEN_FONT) { + origBfont = (FSBlockedFontPtr) blockOrig->data; + if (origBfont->fontid == rep.otherid) { + blockrec->depending = blockOrig->depending; + blockOrig->depending = blockrec; + bfont->state = FS_DEPENDING; + bfont->pfont = origBfont->pfont; + break; + } + } + } + if (bfont->pfont == NULL) + { + /* XXX - something nasty happened */ + return BadFontName; + } + return AccessDone; + } + + bfont->pfont->info.cachable = rep.cachable != 0; + bfont->state = FS_INFO_REPLY; + /* ask for the next stage */ + (void) fs_send_query_info(fpe, blockrec); + return StillWorking; +} + + +static int +fs_read_query_info(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsQueryXInfoReply rep; + fsPropInfo pi; + fsPropOffset *po; + pointer pd; + unsigned long prop_len; + FSBlockedFontRec newbfont, *oldbfont; + FontRec newpfont, *oldpfont; + int err; + + /* If this is a reopen, accumulate the query info into a dummy + font and compare to our original data. */ + if (bfont->flags & FontReopen) + { + newbfont = *(oldbfont = bfont); + bfont = &newbfont; + newpfont = *(oldpfont = oldbfont->pfont); + newpfont.info.isStringProp = NULL; + newpfont.info.props = NULL; + newbfont.pfont = &newpfont; + err = StillWorking; + } + + /* pull out the QueryXInfo reply */ + memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply)); + if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply), + SIZEOF(fsQueryXInfoReply) - SIZEOF(fsGenericReply)) == -1) { + if (bfont->flags & FontReopen) goto bail; + fs_free_font(bfont); + return StillWorking; + } + /* move the data over */ + fsUnpack_XFontInfoHeader(&rep, &bfont->pfont->info); + _fs_init_fontinfo(conn, &bfont->pfont->info); + + if (bfont->pfont->info.terminalFont) + { + bfont->format = + (bfont->format & ~ (BitmapFormatImageRectMask)) | + BitmapFormatImageRectMax; + } + + if (_fs_read(conn, (char *) &pi, SIZEOF(fsPropInfo)) == -1) { + if (bfont->flags & FontReopen) goto bail; + fs_free_font(bfont); + return StillWorking; + } + prop_len = pi.num_offsets * SIZEOF(fsPropOffset); + po = (fsPropOffset *) xalloc(prop_len); + pd = (pointer) xalloc(pi.data_len); + if (!po || !pd) { + xfree(pd); + xfree(po); + /* clear the wire */ + (void) _fs_drain_bytes(conn, prop_len + pi.data_len); + /* clean up the font */ + if (bfont->flags & FontReopen) { err = AllocError ; goto bail; } + (void) _fs_cleanup_font(bfont); + return AllocError; + } + if (_fs_read_pad(conn, (char *) po, prop_len) == -1 || + _fs_read_pad(conn, (char *) pd, pi.data_len) == -1) { + xfree(pd); + xfree(po); + if (bfont->flags & FontReopen) goto bail; + fs_free_font(bfont); + return StillWorking; + } + if (_fs_convert_props(&pi, po, pd, &bfont->pfont->info) == -1) + { + xfree(po); + xfree(pd); + if (bfont->flags & FontReopen) { err = AllocError ; goto bail; } + (void) _fs_cleanup_font(bfont); + return AllocError; + } + xfree(po); + xfree(pd); + + if (bfont->flags & FontReopen) + { + int i; + + err = BadFontName; + + /* We're reopening a font that we lost because of a downed + connection. In the interest of avoiding corruption from + opening a different font than the old one (we already have + its metrics, extents, and probably some of its glyphs), + verify that the metrics and properties all match. */ + + if (newpfont.info.firstCol != oldpfont->info.firstCol || + newpfont.info.lastCol != oldpfont->info.lastCol || + newpfont.info.firstRow != oldpfont->info.firstRow || + newpfont.info.lastRow != oldpfont->info.lastRow || + newpfont.info.defaultCh != oldpfont->info.defaultCh || + newpfont.info.noOverlap != oldpfont->info.noOverlap || + newpfont.info.terminalFont != oldpfont->info.terminalFont || + newpfont.info.constantMetrics != oldpfont->info.constantMetrics || + newpfont.info.constantWidth != oldpfont->info.constantWidth || + newpfont.info.inkInside != oldpfont->info.inkInside || + newpfont.info.inkMetrics != oldpfont->info.inkMetrics || + newpfont.info.allExist != oldpfont->info.allExist || + newpfont.info.drawDirection != oldpfont->info.drawDirection || + newpfont.info.cachable != oldpfont->info.cachable || + newpfont.info.anamorphic != oldpfont->info.anamorphic || + newpfont.info.maxOverlap != oldpfont->info.maxOverlap || + newpfont.info.fontAscent != oldpfont->info.fontAscent || + newpfont.info.fontDescent != oldpfont->info.fontDescent || + newpfont.info.nprops != oldpfont->info.nprops) + goto bail; + +#define MATCH(xci1, xci2) \ + (((xci1).leftSideBearing == (xci2).leftSideBearing) && \ + ((xci1).rightSideBearing == (xci2).rightSideBearing) && \ + ((xci1).characterWidth == (xci2).characterWidth) && \ + ((xci1).ascent == (xci2).ascent) && \ + ((xci1).descent == (xci2).descent) && \ + ((xci1).attributes == (xci2).attributes)) + + if (!MATCH(newpfont.info.maxbounds, oldpfont->info.maxbounds) || + !MATCH(newpfont.info.minbounds, oldpfont->info.minbounds) || + !MATCH(newpfont.info.ink_maxbounds, oldpfont->info.ink_maxbounds) || + !MATCH(newpfont.info.ink_minbounds, oldpfont->info.ink_minbounds)) + goto bail; + +#undef MATCH + + for (i = 0; i < newpfont.info.nprops; i++) + if (newpfont.info.isStringProp[i] != + oldpfont->info.isStringProp[i] || + newpfont.info.props[i].name != + oldpfont->info.props[i].name || + newpfont.info.props[i].value != + oldpfont->info.props[i].value) + goto bail; + + err = Successful; + bail: + if (err != Successful && err != StillWorking) + { + /* Failure. Close the font. */ + fs_send_close_font(((FSFontDataPtr)oldpfont->fpePrivate)->fpe, + bfont->fontid); + ((FSFontDataPtr)oldpfont->fpePrivate)->generation = -1; + } + xfree(newpfont.info.isStringProp); + xfree(newpfont.info.props); + + if (err == Successful) oldbfont->state = FS_DONE_REPLY; + return err; + } + + if (glyphCachingMode == CACHING_OFF || + glyphCachingMode == CACHE_16_BIT_GLYPHS && !bfont->pfont->info.lastRow) + bfont->flags |= FontLoadAll; + + bfont->state = FS_EXTENT_REPLY; + + fs_send_query_extents(fpe, blockrec); + return StillWorking; +} + +static int +fs_read_extent_info(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + FSFontDataPtr fsd = (FSFontDataPtr) bfont->pfont->fpePrivate; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsQueryXExtents16Reply rep; + int i; + int numInfos; + Bool haveInk = FALSE; /* need separate ink metrics? */ + CharInfoPtr ci, + pCI; + FSFontPtr fsfont = (FSFontPtr) bfont->pfont->fontPrivate; + fsXCharInfo *fsci; + fsXCharInfo fscilocal; + pointer fscip; + + /* read the QueryXExtents reply */ + memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply)); + if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply), + SIZEOF(fsQueryXExtents16Reply) - SIZEOF(fsGenericReply)) == -1) { + fs_free_font(bfont); + return StillWorking; + } + /* move the data over */ + /* need separate inkMetrics for fixed font server protocol version */ + numInfos = rep.num_extents; + if (bfont->pfont->info.terminalFont && conn->fsMajorVersion > 1) + { + numInfos *= 2; + haveInk = TRUE; + } + ci = pCI = (CharInfoPtr) xalloc(sizeof(CharInfoRec) * numInfos); +/* XXX this could be done with an ALLOCATE_LOCAL */ + fsci = (fsXCharInfo *) xalloc(SIZEOF(fsXCharInfo) * rep.num_extents); + if (!pCI || !fsci) { + xfree(pCI); + xfree(fsci); + /* clear the unusable data */ + _fs_drain_bytes(conn, SIZEOF(fsXCharInfo) * rep.num_extents); + _fs_cleanup_font(bfont); + return AllocError; + } + fsfont->encoding = pCI; + if (haveInk) + fsfont->inkMetrics = pCI + rep.num_extents; + else + fsfont->inkMetrics = pCI; + + if (_fs_read_pad(conn, (char *) fsci, + SIZEOF(fsXCharInfo) * rep.num_extents) == -1) { + fs_free_font(bfont); + xfree(fsci); + return StillWorking; + } + fsd->glyphs_to_get = 0; + fscip = (pointer) fsci; + ci = fsfont->inkMetrics; + for (i = 0; i < rep.num_extents; i++) { + memcpy(&fscilocal, fscip, SIZEOF(fsXCharInfo)); /* align it */ + _fs_convert_char_info(&fscilocal, &ci->metrics); + fscip += SIZEOF(fsXCharInfo); + /* Initialize the bits field for later glyph-caching use */ + if (NONZEROMETRICS(&ci->metrics)) + { + if (!haveInk && + (ci->metrics.leftSideBearing == ci->metrics.rightSideBearing || + ci->metrics.ascent == -ci->metrics.descent)) + pCI[i].bits = &_fs_glyph_zero_length; + else + { + pCI[i].bits = &_fs_glyph_undefined; + fsd->glyphs_to_get++; + } + } + else + pCI[i].bits = (char *)0; + ci++; + } + + xfree(fsci); + + /* build bitmap metrics, ImageRectMax style */ + if (haveInk) + { + FontInfoRec *fi = &bfont->pfont->info; + CharInfoPtr ii; + + ci = fsfont->encoding; + ii = fsfont->inkMetrics; + for (i = 0; i < rep.num_extents; i++, ci++, ii++) + { + if (NONZEROMETRICS(&ii->metrics)) + { + ci->metrics.leftSideBearing = FONT_MIN_LEFT(fi); + ci->metrics.rightSideBearing = FONT_MAX_RIGHT(fi); + ci->metrics.ascent = FONT_MAX_ASCENT(fi); + ci->metrics.descent = FONT_MAX_DESCENT(fi); + ci->metrics.characterWidth = FONT_MAX_WIDTH(fi); + ci->metrics.attributes = ii->metrics.attributes; + } + else + { + ci->metrics = ii->metrics; + } + } + } + { + unsigned int r, c, numCols, firstCol; + + firstCol = bfont->pfont->info.firstCol; + numCols = bfont->pfont->info.lastCol - firstCol + 1; + c = bfont->pfont->info.defaultCh; + fsfont->pDefault = 0; + if (bfont->pfont->info.lastRow) + { + r = c >> 8; + r -= bfont->pfont->info.firstRow; + c &= 0xff; + c -= firstCol; + if (r < bfont->pfont->info.lastRow-bfont->pfont->info.firstRow+1 && + c < numCols) + fsfont->pDefault = &pCI[r * numCols + c]; + } + else + { + c -= firstCol; + if (c < numCols) + fsfont->pDefault = &pCI[c]; + } + } + bfont->state = FS_GLYPHS_REPLY; + + if (bfont->flags & FontLoadBitmaps) { + fs_send_query_bitmaps(fpe, blockrec); + return StillWorking; + } + return Successful; +} + +/* + * XXX should probably continue to read here if we can, but must be sure + * it's our packet waiting, rather than another interspersed + */ +static int +fs_do_open_font(fpe, blockrec, readheader) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; + Bool readheader; +{ + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + FSFpePtr conn = (FSFpePtr) fpe->private; + int err; + + switch (bfont->state) { + case FS_OPEN_REPLY: + if (readheader) { + /* get the next header */ + if (_fs_read(conn, (char *) &blockrec->header, + SIZEOF(fsGenericReply)) == -1) { + fs_free_font(bfont); + err = StillWorking; + break; + } + } + bfont->errcode = fs_read_open_font(fpe, blockrec); + if (bfont->errcode != StillWorking) { /* already loaded, or error */ + /* if font's already loaded, massage error code */ + switch (bfont->state) { + case FS_DONE_REPLY: + bfont->errcode = Successful; + break; + case FS_DEPENDING: + bfont->errcode = StillWorking; + break; + } + err = bfont->errcode; + break; + } + /* if more data to read or Sync, fall thru, else return */ + if (!(bfont->flags & FontOpenSync)) { + err = bfont->errcode; + break; + } else { + if (_fs_read(conn, (char *) &blockrec->header, + SIZEOF(fsGenericReply)) == -1) { + fs_free_font(bfont); + err = StillWorking; + break; + } + } + /* fall through */ + case FS_INFO_REPLY: + bfont->errcode = fs_read_query_info(fpe, blockrec); + if (bfont->errcode != StillWorking) { + err = bfont->errcode; + break; + } + if (!(bfont->flags & FontOpenSync)) { + err = bfont->errcode; + break; + /* if more data to read, fall thru, else return */ + } else { + if (_fs_read(conn, (char *) &blockrec->header, + SIZEOF(fsGenericReply))) { + fs_free_font(bfont); + err = StillWorking; + break; + } + } + /* fall through */ + case FS_EXTENT_REPLY: + bfont->errcode = fs_read_extent_info(fpe, blockrec); + if (bfont->errcode != StillWorking) { + err = bfont->errcode; + break; + } + if (!(bfont->flags & FontOpenSync)) { + err = bfont->errcode; + break; + } else if (bfont->flags & FontLoadBitmaps) { + if (_fs_read(conn, (char *) &blockrec->header, + SIZEOF(fsGenericReply))) { + fs_free_font(bfont); + err = StillWorking; + break; + } + } + /* fall through */ + case FS_GLYPHS_REPLY: + if (bfont->flags & FontLoadBitmaps) { + bfont->errcode = fs_read_glyphs(fpe, blockrec); + } + err = bfont->errcode; + break; + case FS_DEPENDING: /* can't happen */ + err = bfont->errcode; + default: + err = bfont->errcode; + break; + } + if (err != StillWorking) { + bfont->state = FS_DONE_REPLY; /* for _fs_load_glyphs() */ + while (blockrec = blockrec->depending) { + bfont = (FSBlockedFontPtr) blockrec->data; + bfont->errcode = err; + bfont->state = FS_DONE_REPLY; /* for _fs_load_glyphs() */ + } + } + return err; +} + +/* ARGSUSED */ +static void +fs_block_handler(data, wt, LastSelectMask) + pointer data; + struct timeval **wt; + fd_set* LastSelectMask; +{ + static struct timeval recon_timeout; + Time_t now, + soonest; + FSFpePtr recon; + + XFD_ORSET(LastSelectMask, LastSelectMask, &_fs_fd_mask); + if (recon = awaiting_reconnect) { + now = time((Time_t *) 0); + soonest = recon->time_to_try; + while (recon = recon->next_reconnect) { + if (recon->time_to_try < soonest) + soonest = recon->time_to_try; + } + if (soonest < now) + soonest = now; + soonest = soonest - now; + recon_timeout.tv_sec = soonest; + recon_timeout.tv_usec = 0; + if (*wt == (struct timeval *) 0) { + *wt = &recon_timeout; + } else if ((*wt)->tv_sec > soonest) { + **wt = recon_timeout; + } + } +} + +static void +fs_handle_unexpected(conn, rep) + FSFpePtr conn; + fsGenericReply *rep; +{ + if (rep->type == FS_Event && rep->data1 == KeepAlive) { + fsNoopReq req; + + /* ping it back */ + req.reqType = FS_Noop; + req.length = SIZEOF(fsNoopReq) >> 2; + _fs_add_req_log(conn, FS_Noop); + _fs_write(conn, (char *) &req, SIZEOF(fsNoopReq)); + } + /* this should suck up unexpected replies and events */ + _fs_eat_rest_of_error(conn, (fsError *) rep); +} + +static int +fs_wakeup(fpe, LastSelectMask) + FontPathElementPtr fpe; + fd_set* LastSelectMask; +{ + FSBlockDataPtr blockrec, + br; + FSFpePtr conn = (FSFpePtr) fpe->private; + int err; + fsGenericReply rep; + + /* see if there's any data to be read */ + + /* + * Don't continue if the fd is -1 (which will be true when the + * font server terminates + */ + if (conn->fs_fd == -1) + return FALSE; + + if (FD_ISSET(conn->fs_fd, LastSelectMask)) { + +#ifdef NOTDEF /* bogus - doesn't deal with EOF very well, + * now does it ... */ + /* + * make sure it isn't spurious - mouse events seem to trigger extra + * problems + */ + if (_fs_data_ready(conn) <= 0) { + return FALSE; + } +#endif + + /* get the header */ + if (_fs_read(conn, (char *) &rep, SIZEOF(fsGenericReply)) == -1) + return FALSE; + + /* find the matching block record */ + + for (br = (FSBlockDataPtr) conn->blocked_requests; br; br = br->next) { + if ((CARD16)(br->sequence_number & 0xffff) == + (CARD16)(rep.sequenceNumber - 1)) + break; + } + if (!br) { + fs_handle_unexpected(conn, &rep); + return FALSE; + } + blockrec = br; + + memcpy(&blockrec->header, &rep, SIZEOF(fsGenericReply)); + + /* go read it, and if we're done, wake up the appropriate client */ + switch (blockrec->type) { + case FS_OPEN_FONT: + err = fs_do_open_font(fpe, blockrec, FALSE); + break; + case FS_LOAD_GLYPHS: + err = fs_read_glyphs(fpe, blockrec); + break; + case FS_LIST_FONTS: + err = fs_read_list(fpe, blockrec); + break; + case FS_LIST_WITH_INFO: + err = fs_read_list_info(fpe, blockrec); + break; + default: + break; + } + + if (err != StillWorking) { + while (blockrec) { + ClientSignal(blockrec->client); + blockrec = blockrec->depending; + } + } + /* + * Xx we could loop here and eat any additional replies, but it should + * feel more responsive for other clients if we come back later + */ + } else if (awaiting_reconnect) { + _fs_try_reconnect(); + } + return FALSE; +} + +/* + * Reconnection code + */ + +void +_fs_connection_died(conn) + FSFpePtr conn; +{ + if (!conn->attemptReconnect) + return; + conn->attemptReconnect = FALSE; + fs_close_conn(conn); + conn->time_to_try = time((Time_t *) 0) + FS_RECONNECT_WAIT; + conn->reconnect_delay = FS_RECONNECT_WAIT; + conn->fs_fd = -1; + conn->trans_conn = NULL; + conn->next_reconnect = awaiting_reconnect; + awaiting_reconnect = conn; +} + +static int +_fs_restart_connection(conn) + FSFpePtr conn; +{ + FSBlockDataPtr block; + + conn->current_seq = 0; + FD_SET(conn->fs_fd, &_fs_fd_mask); + if (!fs_send_init_packets(conn)) + return FALSE; + while (block = (FSBlockDataPtr) conn->blocked_requests) { + ClientSignal(block->client); + fs_abort_blockrec(conn, block); + } + return TRUE; +} + +static void +_fs_try_reconnect() +{ + FSFpePtr conn, + *prev; + Time_t now; + + prev = &awaiting_reconnect; + now = time((Time_t *) 0); + while (conn = *prev) { + if (now - conn->time_to_try > 0) { + if (_fs_reopen_server(conn) && _fs_restart_connection(conn)) { + conn->attemptReconnect = TRUE; + *prev = conn->next_reconnect; + if (prev == &awaiting_reconnect) continue; + } else { + if (conn->reconnect_delay < FS_MAX_RECONNECT_WAIT) + conn->reconnect_delay *= 2; + now = time((Time_t *) 0); + conn->time_to_try = now + conn->reconnect_delay; + } + } + prev = &conn->next_reconnect; + } +} + +/* + * sends the actual request out + */ +/* ARGSUSED */ +static int +fs_send_open_font(client, fpe, flags, name, namelen, format, fmask, id, ppfont) + pointer client; + FontPathElementPtr fpe; + Mask flags; + char *name; + int namelen; + fsBitmapFormat format; + fsBitmapFormatMask fmask; + XID id; + FontPtr *ppfont; +{ + FontPtr newfont; + FSBlockDataPtr blockrec = NULL; + FSBlockedFontPtr blockedfont; + FSFontDataPtr fsd; + FSFontPtr fsfont; + FSFpePtr conn; + fsOpenBitmapFontReq openreq; + int err = Suspended; + XID newid; + unsigned char buf[1024]; + char *fontname; + + if (flags & FontReopen) + { + Atom nameatom, fn = None; + int i; + + newfont = *ppfont; + fsd = (FSFontDataPtr)newfont->fpePrivate; + fsfont = (FSFontPtr)newfont->fontPrivate; + fpe = newfont->fpe; + format = fsd->format; + fmask = fsd->fmask; + newid = fsd->fontid; + /* This is an attempt to reopen a font. Did the font have a + NAME property? */ + if ((nameatom = MakeAtom("FONT", 4, 0)) != None) + { + for (i = 0; i < newfont->info.nprops; i++) + if (newfont->info.props[i].name == nameatom && + newfont->info.isStringProp[i]) + { + fn = newfont->info.props[i].value; + break; + } + } + if (fn == None || !(name = NameForAtom(fn))) + { + name = fsd->name; + namelen = fsd->namelen; + } + else + namelen = strlen(name); + } + + conn = (FSFpePtr) fpe->private; + if (namelen > sizeof (buf) - 1) + return BadFontName; + _fs_client_access (conn, client, (flags & FontOpenSync) != 0); + _fs_client_resolution(conn); + + + if (!(flags & FontReopen)) + { + + newid = GetNewFontClientID(); + + /* make the font */ + newfont = (FontPtr) xalloc(sizeof(FontRec)); + + /* and the FS data */ + fsd = (FSFontDataPtr) xalloc(sizeof(FSFontDataRec)); + + fsfont = (FSFontPtr) xalloc(sizeof(FSFontRec)); + + fontname = (char *)xalloc(namelen); + + if (!newfont || !fsd || !fsfont || !fontname) { +lowmem: + if (!(flags & FontReopen)) + { + xfree((char *) newfont); + xfree((char *) fsd); + xfree((char *) fsfont); + xfree((char *) fontname); + } + if (blockrec) fs_abort_blockrec(conn, blockrec); + return AllocError; + } + bzero((char *) newfont, sizeof(FontRec)); + bzero((char *) fsfont, sizeof(FSFontRec)); + bzero((char *) fsd, sizeof(FSFontDataRec)); + } + + /* make a new block record, and add it to the end of the list */ + blockrec = fs_new_block_rec(fpe, client, FS_OPEN_FONT); + if (!blockrec) { + goto lowmem; + } + + if (!(flags & FontReopen)) + { + int bit, byte, scan, glyph; + + newfont->refcnt = 0; + newfont->maxPrivate = -1; + newfont->devPrivates = (pointer *) 0; + newfont->format = format; + + /* These font components will be needed in packGlyphs */ + CheckFSFormat(format, BitmapFormatMaskBit | + BitmapFormatMaskByte | + BitmapFormatMaskScanLineUnit | + BitmapFormatMaskScanLinePad, + &bit, + &byte, + &scan, + &glyph, + NULL); + newfont->bit = bit; + newfont->byte = byte; + newfont->scan = scan; + newfont->glyph = glyph; + + newfont->fpe = fpe; + newfont->fpePrivate = (pointer) fsd; + newfont->fontPrivate = (pointer) fsfont; + _fs_init_font(newfont); + + fsd->fpe = fpe; + fsd->name = fontname; + fsd->namelen = namelen; + memcpy(fontname, name, namelen); + fsd->format = format; + fsd->fmask = fmask; + } + fsd->fontid = newid; + fsd->generation = conn->generation; + + blockedfont = (FSBlockedFontPtr) blockrec->data; + blockedfont->fontid = newid; + blockedfont->pfont = newfont; + blockedfont->state = FS_OPEN_REPLY; + blockedfont->flags = flags; + blockedfont->format = format; + blockedfont->clients_depending = (FSClientsDependingPtr)0; + + /* save the ID */ + if (!StoreFontClientFont(blockedfont->pfont, blockedfont->fontid)) { + goto lowmem; + } + /* do an FS_OpenFont, FS_QueryXInfo and FS_QueryXExtents */ + buf[0] = (unsigned char) namelen; + memcpy(&buf[1], name, namelen); + namelen++; + openreq.reqType = FS_OpenBitmapFont; + openreq.fid = newid; + openreq.format_hint = format; + openreq.format_mask = fmask; + openreq.length = (SIZEOF(fsOpenBitmapFontReq) + namelen + 3) >> 2; + + _fs_add_req_log(conn, FS_OpenBitmapFont); + _fs_write(conn, (char *) &openreq, SIZEOF(fsOpenBitmapFontReq)); + _fs_write_pad(conn, (char *) buf, namelen); + +#ifdef NCD + if (configData.ExtendedFontDiags) { + memcpy(buf, name, MIN(256, namelen)); + buf[MIN(256, namelen)] = '\0'; + printf("Requesting font \"%s\" from font server \"%s\"\n", + buf, fpe->name); + } +#endif + + if (flags & FontOpenSync) { + err = fs_do_open_font(fpe, blockrec, TRUE); + if (blockedfont->errcode == Successful) { + *ppfont = blockedfont->pfont; + } else { + _fs_cleanup_font(blockedfont); + } + _fs_remove_block_rec(conn, blockrec); + } + return err; +} + +static int +fs_send_query_info(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedFontPtr bfont; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsQueryXInfoReq inforeq; + + bfont = (FSBlockedFontPtr) blockrec->data; + + inforeq.reqType = FS_QueryXInfo; + inforeq.id = bfont->fontid; + inforeq.length = SIZEOF(fsQueryXInfoReq) >> 2; + + blockrec->sequence_number = conn->current_seq; + _fs_add_req_log(conn, FS_QueryXInfo); + _fs_write(conn, (char *) &inforeq, SIZEOF(fsQueryXInfoReq)); + + return Successful; +} + +static int +fs_send_query_extents(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedFontPtr bfont; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsQueryXExtents16Req extreq; + + bfont = (FSBlockedFontPtr) blockrec->data; + + extreq.reqType = FS_QueryXExtents16; + extreq.range = fsTrue; + extreq.fid = bfont->fontid; + extreq.num_ranges = 0; + extreq.length = SIZEOF(fsQueryXExtents16Req) >> 2; + + blockrec->sequence_number = conn->current_seq; + _fs_add_req_log(conn, FS_QueryXExtents16); + _fs_write(conn, (char *) &extreq, SIZEOF(fsQueryXExtents16Req)); + + return Successful; +} + +static int +fs_send_query_bitmaps(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedFontPtr bfont; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsQueryXBitmaps16Req bitreq; + + + bfont = (FSBlockedFontPtr) blockrec->data; + + /* send the request */ + bitreq.reqType = FS_QueryXBitmaps16; + bitreq.fid = bfont->fontid; + bitreq.format = bfont->format; + bitreq.range = TRUE; + bitreq.length = SIZEOF(fsQueryXBitmaps16Req) >> 2; + bitreq.num_ranges = 0; + + blockrec->sequence_number = conn->current_seq; + _fs_add_req_log(conn, FS_QueryXBitmaps16); + _fs_write(conn, (char *) &bitreq, SIZEOF(fsQueryXBitmaps16Req)); + + return Successful; +} + +/* ARGSUSED */ +static int +fs_open_font(client, fpe, flags, name, namelen, format, fmask, id, ppfont, + alias, non_cachable_font) + pointer client; + FontPathElementPtr fpe; + Mask flags; + char *name; + fsBitmapFormat format; + fsBitmapFormatMask fmask; + int namelen; + XID id; + FontPtr *ppfont; + char **alias; + FontPtr non_cachable_font; /* Not used in this FPE */ +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockDataPtr blockrec; + FSBlockedFontPtr blockedfont; + int err; + + /* libfont interface expects ImageRectMin glyphs */ + format = format & ~BitmapFormatImageRectMask | BitmapFormatImageRectMin; + + *alias = (char *) 0; + /* XX if we find the blockrec for the font */ + blockrec = (FSBlockDataPtr) conn->blocked_requests; + while (blockrec != (FSBlockDataPtr) 0) { + if (blockrec->type == FS_OPEN_FONT && + blockrec->client == client) { + blockedfont = (FSBlockedFontPtr) blockrec->data; + err = blockedfont->errcode; + if (err == Successful) { + *ppfont = blockedfont->pfont; + } else { + _fs_cleanup_font(blockedfont); + } + /* cleanup */ + _fs_remove_block_rec(conn, blockrec); + return err; + } + blockrec = blockrec->next; + } + return fs_send_open_font(client, fpe, flags, name, namelen, format, fmask, + id, ppfont); +} + +/* ARGSUSED */ +static int +fs_send_close_font(fpe, id) + FontPathElementPtr fpe; + Font id; +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + fsCloseReq req; + + /* tell the font server to close the font */ + req.reqType = FS_CloseFont; + req.length = SIZEOF(fsCloseReq) >> 2; + req.id = id; + _fs_add_req_log(conn, FS_CloseFont); + _fs_write(conn, (char *) &req, SIZEOF(fsCloseReq)); + + return Successful; +} + +/* ARGSUSED */ +static int +fs_close_font(fpe, pfont) + FontPathElementPtr fpe; + FontPtr pfont; +{ + FSFontDataPtr fsd = (FSFontDataPtr) pfont->fpePrivate; + FSFpePtr conn = (FSFpePtr) fpe->private; + + /* XXX we may get called after the resource DB has been cleaned out */ + if (find_old_font(fsd->fontid)) + DeleteFontClientID(fsd->fontid); + if (conn->generation == fsd->generation) + fs_send_close_font(fpe, fsd->fontid); + (*pfont->unload_font) (pfont); + + + xfree(fsd->name); + xfree(fsd); + xfree(pfont->info.isStringProp); + xfree(pfont->info.props); + xfree(pfont->devPrivates); + xfree(pfont); + + + return Successful; +} + +static int +fs_read_glyphs(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedGlyphPtr bglyph = (FSBlockedGlyphPtr) blockrec->data; + FSBlockedFontPtr bfont = (FSBlockedFontPtr) blockrec->data; + FSFpePtr conn = (FSFpePtr) fpe->private; + FontPtr pfont = bglyph->pfont; /* works for either blocked font + or glyph rec... pfont is at + the very beginning of both + blockrec->data structures */ + FSFontDataPtr fsd = (FSFontDataPtr) (pfont->fpePrivate); + FSFontPtr fsdata = (FSFontPtr) pfont->fontPrivate; + FontInfoPtr pfi = &pfont->info; + fsQueryXBitmaps16Reply rep; + fsOffset32 *ppbits; + fsOffset32 local_off; + char *off_adr; + pointer pbitmaps; + char *bits; + int glyph_size, + offset_size, + i, + err; + int nranges = 0; + fsRange *ranges, *nextrange; + unsigned long minchar, maxchar; + + /* get reply header */ + memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply)); + if (rep.type == FS_Error) { +/* XXX -- translate FS error */ + _fs_eat_rest_of_error(conn, (fsError *) & rep); + err = AllocError; + goto bail; + } + if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply), + SIZEOF(fsQueryXBitmaps16Reply) - SIZEOF(fsGenericReply)) == -1) { + if (blockrec->type == FS_OPEN_FONT) + fs_free_font(bfont); + return StillWorking; + } + /* allocate space for glyphs */ + offset_size = SIZEOF(fsOffset32) * (rep.num_chars); + glyph_size = (rep.length << 2) - SIZEOF(fsQueryXBitmaps16Reply) + - offset_size; + ppbits = (fsOffset32 *) xalloc(offset_size); + pbitmaps = (pointer) xalloc(glyph_size); + if (glyph_size && !pbitmaps || !ppbits) + { + xfree(pbitmaps); + xfree(ppbits); + + /* clear wire */ + (void) _fs_drain_bytes_pad(conn, offset_size); + (void) _fs_drain_bytes_pad(conn, glyph_size); + + if (blockrec->type == FS_OPEN_FONT) + _fs_cleanup_font(bfont); + err = AllocError; + goto bail; + } + + /* read offsets */ + if (_fs_read_pad(conn, (char *) ppbits, offset_size) == -1) { + if (blockrec->type == FS_OPEN_FONT) + fs_free_font(bfont); + return StillWorking; + } + + /* read glyphs */ + if (_fs_read_pad(conn, (char *) pbitmaps, glyph_size) == -1) { + if (blockrec->type == FS_OPEN_FONT) + fs_free_font(bfont); + return StillWorking; + } + + if (blockrec->type == FS_LOAD_GLYPHS) + { + nranges = bglyph->num_expected_ranges; + nextrange = ranges = bglyph->expected_ranges; + } + + /* place the incoming glyphs */ + if (nranges) + { + /* We're operating under the assumption that the ranges + requested in the LoadGlyphs call were all legal for this + font, and that individual ranges do not cover multiple + rows... fs_build_range() is designed to ensure this. */ + minchar = (nextrange->min_char_high - pfi->firstRow) * + (pfi->lastCol - pfi->firstCol + 1) + + nextrange->min_char_low - pfi->firstCol; + maxchar = (nextrange->max_char_high - pfi->firstRow) * + (pfi->lastCol - pfi->firstCol + 1) + + nextrange->max_char_low - pfi->firstCol; + nextrange++; + } + else + { + minchar = 0; + maxchar = rep.num_chars; + } + + off_adr = (char *)ppbits; + for (i = 0; i < rep.num_chars; i++) + { + memcpy(&local_off, off_adr, SIZEOF(fsOffset32)); /* align it */ + if (blockrec->type == FS_OPEN_FONT || + fsdata->encoding[minchar].bits == &_fs_glyph_requested) + { + if (local_off.length) + { + bits = (char *)xalloc(local_off.length); + if (bits == NULL) + { + xfree(ppbits); + xfree(pbitmaps); + err = AllocError; + goto bail; + } + memcpy(bits, pbitmaps + local_off.position, + local_off.length); + } + else if (NONZEROMETRICS(&fsdata->encoding[minchar].metrics)) + bits = &_fs_glyph_zero_length; + else + bits = 0; + if (fsdata->encoding[minchar].bits == &_fs_glyph_requested) + fsd->glyphs_to_get--; + fsdata->encoding[minchar].bits = bits; + } + if (minchar++ == maxchar) + { + if (!--nranges) break; + minchar = (nextrange->min_char_high - pfi->firstRow) * + (pfi->lastCol - pfi->firstCol + 1) + + nextrange->min_char_low - pfi->firstCol; + maxchar = (nextrange->max_char_high - pfi->firstRow) * + (pfi->lastCol - pfi->firstCol + 1) + + nextrange->max_char_low - pfi->firstCol; + nextrange++; + } + off_adr += SIZEOF(fsOffset32); + } + + xfree(ppbits); + xfree(pbitmaps); + + if (blockrec->type == FS_OPEN_FONT) + { + fsd->glyphs_to_get = 0; + bfont->state = FS_DONE_REPLY; + } + err = Successful; + +bail: + if (blockrec->type == FS_LOAD_GLYPHS) + { + bglyph->done = TRUE; + bglyph->errcode = err; + } + + return err; +} + + + +static int +fs_send_load_glyphs(client, pfont, nranges, ranges) + pointer client; + FontPtr pfont; + int nranges; + fsRange *ranges; +{ + FSBlockedGlyphPtr blockedglyph; + fsQueryXBitmaps16Req req; + FSFontDataPtr fsd = (FSFontDataPtr) (pfont->fpePrivate); + FontPathElementPtr fpe = fsd->fpe; + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockDataPtr blockrec; + + /* make a new block record, and add it to the end of the list */ + blockrec = fs_new_block_rec(fpe, client, FS_LOAD_GLYPHS); + if (!blockrec) + return AllocError; + blockedglyph = (FSBlockedGlyphPtr) blockrec->data; + blockedglyph->pfont = pfont; + blockedglyph->num_expected_ranges = nranges; + /* Assumption: it's our job to free ranges */ + blockedglyph->expected_ranges = ranges; + blockedglyph->done = FALSE; + blockedglyph->clients_depending = (FSClientsDependingPtr)0; + + blockrec->sequence_number = conn->current_seq; + + /* send the request */ + req.reqType = FS_QueryXBitmaps16; + req.fid = ((FSFontDataPtr) pfont->fpePrivate)->fontid; + req.format = pfont->format; + if (pfont->info.terminalFont) + req.format = req.format & ~(BitmapFormatImageRectMask) | + BitmapFormatImageRectMax; + req.range = TRUE; + /* each range takes up 4 bytes */ + req.length = (SIZEOF(fsQueryXBitmaps16Req) >> 2) + nranges; + req.num_ranges = nranges * 2; /* protocol wants count of fsChar2bs */ + _fs_add_req_log(conn, FS_QueryXBitmaps16); + _fs_write(conn, (char *) &req, SIZEOF(fsQueryXBitmaps16Req)); + + /* Send ranges to the server... pack into a char array by hand + to avoid structure-packing portability problems and to + handle swapping for version1 protocol */ + if (nranges) + { +#define RANGE_BUFFER_SIZE 64 +#define RANGE_BUFFER_SIZE_MASK 63 + int i; + char range_buffer[RANGE_BUFFER_SIZE * 4]; + char *range_buffer_p; + + range_buffer_p = range_buffer; + for (i = 0; i < nranges;) + { + if (conn->fsMajorVersion > 1) + { + *range_buffer_p++ = ranges[i].min_char_high; + *range_buffer_p++ = ranges[i].min_char_low; + *range_buffer_p++ = ranges[i].max_char_high; + *range_buffer_p++ = ranges[i].max_char_low; + } + else + { + *range_buffer_p++ = ranges[i].min_char_low; + *range_buffer_p++ = ranges[i].min_char_high; + *range_buffer_p++ = ranges[i].max_char_low; + *range_buffer_p++ = ranges[i].max_char_high; + } + + if (!(++i & RANGE_BUFFER_SIZE_MASK)) + { + _fs_write(conn, range_buffer, RANGE_BUFFER_SIZE * 4); + range_buffer_p = range_buffer; + } + } + if (i &= RANGE_BUFFER_SIZE_MASK) + _fs_write(conn, range_buffer, i * 4); + } + + return Suspended; +} + + +int +fs_load_all_glyphs(pfont) + FontPtr pfont; +{ + extern pointer serverClient; /* This could be any number that + doesn't conflict with existing + client values. */ + int err; + FSFpePtr conn = (FSFpePtr) pfont->fpe->private; + + /* + * The purpose of this procedure is to load all glyphs in the event + * that we're dealing with someone who doesn't understand the finer + * points of glyph caching... it is called from _fs_get_glyphs() if + * the latter is called to get glyphs that have not yet been loaded. + * We assume that the caller will not know how to handle a return + * value of Suspended (usually the case for a GetGlyphs() caller), + * so this procedure hangs around, freezing the server, for the + * request to complete. This is an unpleasant kluge called to + * perform an unpleasant job that, we hope, will never be required. + */ + + while ((err = _fs_load_glyphs(serverClient, pfont, TRUE, 0, 0, NULL)) == + Suspended) + { + fd_set TempSelectMask; + + FD_ZERO (&TempSelectMask); + + if (_fs_wait_for_readable(conn) == -1) + { + /* We lost our connection. Don't wait to reestablish it; + just give up. */ + _fs_connection_died(conn); + + /* Get rid of blockrec */ + fs_client_died(serverClient, pfont->fpe); + + return BadCharRange; /* As good an error as any other */ + } + FD_SET(conn->fs_fd, &TempSelectMask); + fs_wakeup(pfont->fpe, &TempSelectMask); + } + + return err; +} + + +int +_fs_load_glyphs(client, pfont, range_flag, nchars, item_size, data) + pointer client; + FontPtr pfont; + Bool range_flag; + unsigned int nchars; + int item_size; + unsigned char *data; +{ + + int nranges = 0; + fsRange *ranges = NULL; + int res; + FSBlockDataPtr blockrec; + FSBlockedGlyphPtr blockedglyph; + FSFpePtr conn = (FSFpePtr) pfont->fpe->private; + FSClientsDependingPtr *clients_depending = NULL; + + /* see if the result is already there */ + + blockrec = (FSBlockDataPtr) conn->blocked_requests; + while (blockrec) { + if (blockrec->type == FS_LOAD_GLYPHS) + { + blockedglyph = (FSBlockedGlyphPtr) blockrec->data; + if (blockedglyph->pfont == pfont) + { + if (blockrec->client == client) + { + if (blockedglyph->done) + { + int errcode = blockedglyph->errcode; + signal_clients_depending(&blockedglyph-> + clients_depending); + _fs_remove_block_rec(conn, blockrec); + return errcode; + } + else return Suspended; + } + /* We've found an existing LoadGlyphs blockrec for this + font but for another client. Rather than build a + blockrec for it now (which entails some complex + maintenance), we'll add it to a queue of clients to + be signalled when the existing LoadGlyphs is + completed. */ + clients_depending = &blockedglyph->clients_depending; + break; + } + } + else if (blockrec->type == FS_OPEN_FONT) + { + FSBlockedFontPtr bfont; + bfont = (FSBlockedFontPtr) blockrec->data; + if (bfont->pfont == pfont) + { + if (blockrec->client == client) + { + if (bfont->state == FS_DONE_REPLY) + { + int errcode = bfont->errcode; + signal_clients_depending(&bfont->clients_depending); + _fs_remove_block_rec(conn, blockrec); + if (errcode == Successful) break; + else return errcode; + } + else return Suspended; + } + /* We've found an existing OpenFont blockrec for this + font but for another client. Rather than build a + blockrec for it now (which entails some complex + maintenance), we'll add it to a queue of clients to + be signalled when the existing OpenFont is + completed. */ + if (bfont->state != FS_DONE_REPLY) + { + clients_depending = &bfont->clients_depending; + break; + } + } + } + + blockrec = blockrec->next; + } + + /* + * see if the desired glyphs already exist, and return Successful if they + * do, otherwise build up character range/character string + */ + res = fs_build_range(pfont, range_flag, nchars, item_size, data, + &nranges, &ranges); + + switch (res) + { + case AccessDone: + return Successful; + + case Successful: + break; + + default: + return res; + } + + /* + * If clients_depending is not null, this request must wait for + * some prior request(s) to complete. + */ + if (clients_depending) + { + /* Since we're not ready to send the load_glyphs request yet, + clean up the damage (if any) caused by the fs_build_range() + call. */ + if (nranges) + { + _fs_clean_aborted_loadglyphs(pfont, nranges, ranges); + xfree(ranges); + } + return add_clients_depending(clients_depending, client); + } + + /* + * If fsd->generation != conn->generation, the font has been closed + * due to a lost connection. We will reopen it, which will result + * in one of three things happening: + * 1) The open will succeed and obtain the same font. Life + * is wonderful. + * 2) The open will fail. There is code above to recognize this + * and flunk the LoadGlyphs request. The client might not be + * thrilled. + * 3) Worst case: the open will succeed but the font we open will + * be different. The fs_read_query_info() procedure attempts + * to detect this by comparing the existing metrics and + * properties against those of the reopened font... if they + * don't match, we flunk the reopen, which eventually results + * in flunking the LoadGlyphs request. We could go a step + * further and compare the extents, but this should be + * sufficient. + */ + if (((FSFontDataPtr)pfont->fpePrivate)->generation != conn->generation) + { + /* Since we're not ready to send the load_glyphs request yet, + clean up the damage caused by the fs_build_range() call. */ + _fs_clean_aborted_loadglyphs(pfont, nranges, ranges); + xfree(ranges); + + /* Now try to reopen the font. */ + return fs_send_open_font(client, (FontPathElementPtr)0, + (Mask)FontReopen, (char *)0, 0, + (fsBitmapFormat)0, (fsBitmapFormatMask)0, + (XID)0, &pfont); + } + + return fs_send_load_glyphs(client, pfont, nranges, ranges); +} + + + +static int +fs_read_list(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedListPtr blist = (FSBlockedListPtr) blockrec->data; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsListFontsReply rep; + char *data, + *dp; + int length, + i; + + blist->done = TRUE; + + /* read reply header */ + memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply)); + if (rep.type == FS_Error) { +/* XXX -- translate FS error */ + _fs_eat_rest_of_error(conn, (fsError *) & rep); + return AllocError; + } + if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply), + SIZEOF(fsListFontsReply) - SIZEOF(fsGenericReply)) == -1) { + /* nothing to free (i think) */ + return StillWorking; + } + length = (rep.length << 2) - SIZEOF(fsListFontsReply); + data = (char *) xalloc(length); + if (!data) { + _fs_drain_bytes_pad(conn, length); + return AllocError; + } + /* read the list */ + if (_fs_read_pad(conn, data, length) == -1) { + /* nothing to free (i think) */ + return StillWorking; + } + /* copy data into FontPathRecord */ + dp = data; + for (i = 0; i < rep.nFonts; i++) { + length = *(unsigned char *)dp++; + if (AddFontNamesName(blist->names, dp, length) != Successful) { + blist->errcode = AllocError; + break; + } + dp += length; + } + + xfree(data); + return Successful; +} + +static int +fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames) + pointer client; + FontPathElementPtr fpe; + char *pattern; + int patlen; + int maxnames; + FontNamesPtr newnames; +{ + FSBlockDataPtr blockrec; + FSBlockedListPtr blockedlist; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsListFontsReq req; + + _fs_client_access (conn, client, FALSE); + _fs_client_resolution(conn); + + /* make a new block record, and add it to the end of the list */ + blockrec = fs_new_block_rec(fpe, client, FS_LIST_FONTS); + if (!blockrec) + return AllocError; + blockedlist = (FSBlockedListPtr) blockrec->data; + blockedlist->patlen = patlen; + blockedlist->errcode = Successful; + blockedlist->names = newnames; + blockedlist->done = FALSE; + + /* send the request */ + req.reqType = FS_ListFonts; + req.maxNames = maxnames; + req.nbytes = patlen; + req.length = (SIZEOF(fsListFontsReq) + patlen + 3) >> 2; + _fs_add_req_log(conn, FS_ListFonts); + _fs_write(conn, (char *) &req, SIZEOF(fsListFontsReq)); + _fs_write_pad(conn, (char *) pattern, patlen); + +#ifdef NCD + if (configData.ExtendedFontDiags) { + char buf[256]; + + memcpy(buf, pattern, MIN(256, patlen)); + buf[MIN(256, patlen)] = '\0'; + printf("Listing fonts on pattern \"%s\" from font server \"%s\"\n", + buf, fpe->name); + } +#endif + + return Suspended; +} + +static int +fs_list_fonts(client, fpe, pattern, patlen, maxnames, newnames) + pointer client; + FontPathElementPtr fpe; + char *pattern; + int patlen; + int maxnames; + FontNamesPtr newnames; +{ + FSBlockDataPtr blockrec; + FSBlockedListPtr blockedlist; + FSFpePtr conn = (FSFpePtr) fpe->private; + int err; + + /* see if the result is already there */ + blockrec = (FSBlockDataPtr) conn->blocked_requests; + while (blockrec) { + if (blockrec->type == FS_LIST_FONTS && blockrec->client == client) { + blockedlist = (FSBlockedListPtr) blockrec->data; + if (blockedlist->patlen == patlen && blockedlist->done) { + err = blockedlist->errcode; + _fs_remove_block_rec(conn, blockrec); + return err; + } + } + blockrec = blockrec->next; + } + + /* didn't find waiting record, so send a new one */ + return fs_send_list_fonts(client, fpe, pattern, patlen, maxnames, newnames); +} + +static int padlength[4] = {0, 3, 2, 1}; + +static int +fs_read_list_info(fpe, blockrec) + FontPathElementPtr fpe; + FSBlockDataPtr blockrec; +{ + FSBlockedListInfoPtr binfo = (FSBlockedListInfoPtr) blockrec->data; + fsListFontsWithXInfoReply rep; + FSFpePtr conn = (FSFpePtr) fpe->private; + fsPropInfo pi; + fsPropOffset *po; + char *name; + pointer pd; + int err; + + /* clean up anything from the last trip */ + if (binfo->name) + { + xfree(binfo->name); + binfo->name = NULL; + } + if (binfo->pfi) { + xfree(binfo->pfi->isStringProp); + xfree(binfo->pfi->props); + xfree(binfo->pfi); + binfo->pfi = NULL; + } + /* get reply header */ + memcpy(&rep, &blockrec->header, SIZEOF(fsGenericReply)); + if (rep.type == FS_Error) { +/* XXX -- translate FS error */ + _fs_eat_rest_of_error(conn, (fsError *) & rep); + binfo->errcode = AllocError; + return AllocError; + } + if (conn->fsMajorVersion > 1) + if (rep.nameLength == 0) + goto done; + /* old protocol sent a full-length reply even for the last one */ + if (_fs_read(conn, (char *) &rep + SIZEOF(fsGenericReply), + SIZEOF(fsListFontsWithXInfoReply) - SIZEOF(fsGenericReply)) == -1) { + goto done; + } + if (rep.nameLength == 0) + goto done; + + /* read the data */ + name = (char *) xalloc(rep.nameLength); + binfo->pfi = (FontInfoPtr) xalloc(sizeof(FontInfoRec)); + if (!name || !binfo->pfi) { + xfree(name); + xfree(binfo->pfi); + binfo->pfi = NULL; + _fs_drain_bytes(conn, + rep.length - (SIZEOF(fsListFontsWithXInfoReply) - + SIZEOF(fsGenericReply))); + binfo->errcode = AllocError; + return AllocError; + } + if (conn->fsMajorVersion == 1) + if (_fs_read_pad(conn, name, rep.nameLength) == -1) + goto done; + if (_fs_read_pad(conn, (char *) &pi, SIZEOF(fsPropInfo)) == -1) + goto done; + + po = (fsPropOffset *) xalloc(SIZEOF(fsPropOffset) * pi.num_offsets); + pd = (pointer) xalloc(pi.data_len); + if (!po || !pd) { + xfree(name); + xfree(po); + xfree(pd); + xfree (binfo->pfi); + binfo->pfi = NULL; + binfo->errcode = AllocError; + return AllocError; + } + err = _fs_read_pad(conn, (char *) po, + (pi.num_offsets * SIZEOF(fsPropOffset))); + if (err != -1) + { + if (conn->fsMajorVersion > 1) + err = _fs_read(conn, (char *) pd, pi.data_len); + else + err = _fs_read_pad(conn, (char *) pd, pi.data_len); + } + if (err != -1 && conn->fsMajorVersion != 1) + { + err = _fs_read(conn, name, rep.nameLength); + if (err != -1) + err = _fs_drain_bytes(conn, padlength[(pi.data_len+rep.nameLength)&3]); + } + + if (err == -1) { + xfree(name); + xfree(po); + xfree(pd); + xfree (binfo->pfi); + binfo->pfi = NULL; + goto done; + } + + if (_fs_convert_lfwi_reply(conn, binfo->pfi, &rep, &pi, po, pd) != Successful) + { + xfree(name); + xfree(po); + xfree(pd); + xfree (binfo->pfi); + binfo->pfi = NULL; + goto done; + } + xfree(po); + xfree(pd); + binfo->name = name; + binfo->namelen = rep.nameLength; + binfo->remaining = rep.nReplies; + + binfo->status = FS_LFWI_REPLY; + binfo->errcode = Suspended; + /* disable this font server until we've processed this response */ + FD_CLR(conn->fs_fd, &_fs_fd_mask); + + return Successful; + +done: + binfo->status = FS_LFWI_FINISHED; + binfo->errcode = BadFontName; + binfo->name = (char *) 0; + return Successful; +} + +/* ARGSUSED */ +static int +fs_start_list_with_info(client, fpe, pattern, len, maxnames, pdata) + pointer client; + FontPathElementPtr fpe; + char *pattern; + int len; + int maxnames; + pointer *pdata; +{ + FSBlockDataPtr blockrec; + FSBlockedListInfoPtr blockedinfo; + fsListFontsWithXInfoReq req; + FSFpePtr conn = (FSFpePtr) fpe->private; + + _fs_client_access (conn, client, FALSE); + _fs_client_resolution(conn); + + /* make a new block record, and add it to the end of the list */ + blockrec = fs_new_block_rec(fpe, client, FS_LIST_WITH_INFO); + if (!blockrec) + return AllocError; + blockedinfo = (FSBlockedListInfoPtr) blockrec->data; + bzero((char *) blockedinfo, sizeof(FSBlockedListInfoRec)); + blockedinfo->status = FS_LFWI_WAITING; + blockedinfo->errcode = Suspended; + + /* send the request */ + req.reqType = FS_ListFontsWithXInfo; + req.maxNames = maxnames; + req.nbytes = len; + req.length = (SIZEOF(fsListFontsWithXInfoReq) + len + 3) >> 2; + _fs_add_req_log(conn, FS_ListFontsWithXInfo); + (void) _fs_write(conn, (char *) &req, SIZEOF(fsListFontsWithXInfoReq)); + (void) _fs_write_pad(conn, pattern, len); + +#ifdef NCD + if (configData.ExtendedFontDiags) { + char buf[256]; + + memcpy(buf, pattern, MIN(256, len)); + buf[MIN(256, len)] = '\0'; + printf("Listing fonts with info on pattern \"%s\" from font server \"%s\"\n", + buf, fpe->name); + } +#endif + + return Successful; +} + +/* ARGSUSED */ +static int +fs_next_list_with_info(client, fpe, namep, namelenp, pFontInfo, numFonts, + private) + pointer client; + FontPathElementPtr fpe; + char **namep; + int *namelenp; + FontInfoPtr *pFontInfo; + int *numFonts; + pointer private; +{ + FSBlockDataPtr blockrec; + FSBlockedListInfoPtr blockedinfo; + FSFpePtr conn = (FSFpePtr) fpe->private; + + /* see if the result is already there */ + blockrec = (FSBlockDataPtr) conn->blocked_requests; + while (blockrec) { + if (blockrec->type == FS_LIST_WITH_INFO && + blockrec->client == client) { + blockedinfo = (FSBlockedListInfoPtr) blockrec->data; + break; + } + blockrec = blockrec->next; + } + + if (!blockrec) + { + /* The only good reason for not finding a blockrec would be if + disconnect/reconnect to the font server wiped it out and the + code that called us didn't do the right thing to create + another one. Under those circumstances, we need to return an + error to prevent that code from attempting to interpret the + information we don't return. */ + return BadFontName; + } + + if (blockedinfo->status == FS_LFWI_WAITING) + return Suspended; + + *namep = blockedinfo->name; + *namelenp = blockedinfo->namelen; + *pFontInfo = blockedinfo->pfi; + *numFonts = blockedinfo->remaining; + FD_SET(conn->fs_fd, &_fs_fd_mask); + if (blockedinfo->status == FS_LFWI_FINISHED) { + int err = blockedinfo->errcode; + + _fs_remove_block_rec(conn, blockrec); + return err; + } + if (blockedinfo->status == FS_LFWI_REPLY) { + blockedinfo->status = FS_LFWI_WAITING; + return Successful; + } else { + return blockedinfo->errcode; + } +} + +/* + * Called when client exits + */ + +static void +fs_client_died(client, fpe) + pointer client; + FontPathElementPtr fpe; +{ + FSFpePtr conn = (FSFpePtr) fpe->private; + FSBlockDataPtr blockrec, + depending; + FSClientPtr *prev, cur; + fsFreeACReq freeac; + + for (prev = &conn->clients; cur = *prev; prev = &cur->next) + { + if (cur->client == client) { + freeac.reqType = FS_FreeAC; + freeac.id = cur->acid; + freeac.length = sizeof (fsFreeACReq) >> 2; + _fs_add_req_log(conn, FS_FreeAC); + _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq)); + *prev = cur->next; + xfree (cur); + break; + } + } + /* see if the result is already there */ + blockrec = (FSBlockDataPtr) conn->blocked_requests; + while (blockrec) { + if (blockrec->client == client) + break; + blockrec = blockrec->next; + } + if (!blockrec) + return; + if (blockrec->type == FS_LIST_WITH_INFO) + { + FSBlockedListInfoPtr binfo; + binfo = (FSBlockedListInfoPtr) blockrec->data; + if (binfo->status == FS_LFWI_REPLY) + FD_SET(conn->fs_fd, &_fs_fd_mask); + if (binfo->name) + { + xfree(binfo->name); + binfo->name = NULL; + } + if (binfo->pfi) + { + xfree(binfo->pfi->isStringProp); + xfree(binfo->pfi->props); + xfree(binfo->pfi); + binfo->pfi = NULL; + } + } + /* replace the client pointers in this block rec with the chained one */ + if (depending = blockrec->depending) { + blockrec->client = depending->client; + blockrec->depending = depending->depending; + blockrec = depending; + } + fs_abort_blockrec(conn, blockrec); +} + +static void +_fs_client_access (conn, client, sync) + FSFpePtr conn; + pointer client; + Bool sync; +{ + FSClientPtr *prev, cur; + fsCreateACReq crac; + fsSetAuthorizationReq setac; + fsGenericReply rep; + char *authorizations; + int authlen; + Bool new_cur = FALSE; + + for (prev = &conn->clients; cur = *prev; prev = &cur->next) + { + if (cur->client == client) + { + if (prev != &conn->clients) + { + *prev = cur->next; + cur->next = conn->clients; + conn->clients = cur; + } + break; + } + } + if (!cur) + { + cur = (FSClientPtr) xalloc (sizeof (FSClientRec)); + if (!cur) + return; + cur->client = client; + cur->next = conn->clients; + conn->clients = cur; + cur->acid = GetNewFontClientID (); + new_cur = TRUE; + } + if (new_cur || cur->auth_generation != client_auth_generation(client)) + { + if (!new_cur) + { + fsFreeACReq freeac; + freeac.reqType = FS_FreeAC; + freeac.id = cur->acid; + freeac.length = sizeof (fsFreeACReq) >> 2; + _fs_add_req_log(conn, FS_FreeAC); + _fs_write (conn, (char *) &freeac, sizeof (fsFreeACReq)); + } + crac.reqType = FS_CreateAC; + crac.num_auths = set_font_authorizations(&authorizations, &authlen, + client); + authlen = crac.num_auths ? (authlen + 3) & ~0x3 : 0; + crac.length = (sizeof (fsCreateACReq) + authlen) >> 2; + crac.acid = cur->acid; + _fs_add_req_log(conn, FS_CreateAC); + _fs_write(conn, (char *) &crac, sizeof (fsCreateACReq)); + _fs_write(conn, authorizations, authlen); + /* if we're synchronous, open_font will be confused by + * the reply; eat it and continue + */ + if (sync) + { + if (_fs_read(conn, (char *) &rep, sizeof (fsGenericReply)) == -1) + return; + fs_handle_unexpected(conn, &rep); + } + /* ignore reply; we don't even care about it */ + conn->curacid = 0; + cur->auth_generation = client_auth_generation(client); + } + if (conn->curacid != cur->acid) + { + setac.reqType = FS_SetAuthorization; + setac.length = sizeof (fsSetAuthorizationReq) >> 2; + setac.id = cur->acid; + _fs_add_req_log(conn, FS_SetAuthorization); + _fs_write(conn, (char *) &setac, sizeof (fsSetAuthorizationReq)); + conn->curacid = cur->acid; + } +} + +/* + * called at server init time + */ + +void +fs_register_fpe_functions() +{ + fs_font_type = RegisterFPEFunctions(fs_name_check, + fs_init_fpe, + fs_free_fpe, + fs_reset_fpe, + fs_open_font, + fs_close_font, + fs_list_fonts, + fs_start_list_with_info, + fs_next_list_with_info, + fs_wakeup, + fs_client_died, + _fs_load_glyphs, + (int (*))0, + (int (*))0, + (void (*))0); +} + +static int +check_fs_open_font(client, fpe, flags, name, namelen, format, fmask, id, ppfont, + alias, non_cachable_font) + pointer client; + FontPathElementPtr fpe; + Mask flags; + char *name; + fsBitmapFormat format; + fsBitmapFormatMask fmask; + int namelen; + XID id; + FontPtr *ppfont; + char **alias; + FontPtr non_cachable_font; /* Not used in this FPE */ +{ + if (XpClientIsBitmapClient(client)) + return (fs_open_font(client, fpe, flags, name, namelen, format, + fmask, id, ppfont, alias, non_cachable_font) ); + return BadFontName; +} + +static int +check_fs_list_fonts(client, fpe, pattern, patlen, maxnames, newnames) + pointer client; + FontPathElementPtr fpe; + char *pattern; + int patlen; + int maxnames; + FontNamesPtr newnames; +{ + if (XpClientIsBitmapClient(client)) + return (fs_list_fonts(client, fpe, pattern, patlen, maxnames, + newnames)); + return BadFontName; +} + +static int +check_fs_start_list_with_info(client, fpe, pattern, len, maxnames, pdata) + pointer client; + FontPathElementPtr fpe; + char *pattern; + int len; + int maxnames; + pointer *pdata; +{ + if (XpClientIsBitmapClient(client)) + return (fs_start_list_with_info(client, fpe, pattern, len, maxnames, + pdata)); + return BadFontName; +} + +static int +check_fs_next_list_with_info(client, fpe, namep, namelenp, pFontInfo, numFonts, + private) + pointer client; + FontPathElementPtr fpe; + char **namep; + int *namelenp; + FontInfoPtr *pFontInfo; + int *numFonts; + pointer private; +{ + if (XpClientIsBitmapClient(client)) + return (fs_next_list_with_info(client, fpe, namep, namelenp, pFontInfo, + numFonts,private)); + return BadFontName; +} + +void +check_fs_register_fpe_functions() +{ + fs_font_type = RegisterFPEFunctions(fs_name_check, + fs_init_fpe, + fs_free_fpe, + fs_reset_fpe, + check_fs_open_font, + fs_close_font, + check_fs_list_fonts, + check_fs_start_list_with_info, + check_fs_next_list_with_info, + fs_wakeup, + fs_client_died, + _fs_load_glyphs, + (int (*))0, + (int (*))0, + (void (*))0); +} diff --git a/src/fc/fserve.h b/src/fc/fserve.h new file mode 100644 index 0000000..b5370d0 --- /dev/null +++ b/src/fc/fserve.h @@ -0,0 +1,68 @@ +/* $Xorg: fserve.h,v 1.3 2000/08/17 19:46:36 cpqbld Exp $ */ +/* + * 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 name of Network Computing Devices not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. Network Computing + * Devices makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied + * warranty. + * + * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL NETWORK COMPUTING DEVICES 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 + * + */ + +#ifndef _FSERVE_H_ +#define _FSERVE_H_ +/* + * font server data structures + */ + +/* types of block records */ +#define FS_OPEN_FONT 1 +#define FS_LOAD_GLYPHS 2 +#define FS_LIST_FONTS 3 +#define FS_LIST_WITH_INFO 4 + +/* states of OpenFont */ +#define FS_OPEN_REPLY 0 +#define FS_INFO_REPLY 1 +#define FS_EXTENT_REPLY 2 +#define FS_GLYPHS_REPLY 3 +#define FS_DONE_REPLY 4 +#define FS_DEPENDING 5 + +/* status of ListFontsWithInfo */ +#define FS_LFWI_WAITING 0 +#define FS_LFWI_REPLY 1 +#define FS_LFWI_FINISHED 2 + +#define AccessDone 0x400 + +typedef struct _fs_font_data *FSFontDataPtr; +typedef struct _fs_blocked_font *FSBlockedFontPtr; +typedef struct _fs_blocked_glyphs *FSBlockedGlyphPtr; +typedef struct _fs_blocked_list *FSBlockedListPtr; +typedef struct _fs_blocked_list_info *FSBlockedListInfoPtr; +typedef struct _fs_block_data *FSBlockDataPtr; +typedef struct _fs_font_table *FSFontTablePtr; + +typedef struct _fs_blocked_bitmaps *FSBlockedBitmapPtr; +typedef struct _fs_blocked_extents *FSBlockedExtentPtr; + +extern void fs_convert_char_info(); + +#endif /* _FSERVE_H_ */ diff --git a/src/fc/fservestr.h b/src/fc/fservestr.h new file mode 100644 index 0000000..891d4ae --- /dev/null +++ b/src/fc/fservestr.h @@ -0,0 +1,188 @@ +/* $Xorg: fservestr.h,v 1.3 2000/08/17 19:46:36 cpqbld Exp $ */ +/* + * 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 name of Network Computing Devices not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. Network Computing + * Devices makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied + * warranty. + * + * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL NETWORK COMPUTING DEVICES 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 + */ + +#ifndef _FSERVESTR_H_ +#define _FSERVESTR_H_ + +#include "fserve.h" +#include "fsio.h" + +/* + * font server data structures + */ +/* + * font server private storage + */ + + +typedef struct _fs_font { + CharInfoPtr pDefault; + CharInfoPtr encoding; + CharInfoPtr inkMetrics; +} FSFontRec, *FSFontPtr; + +/* FS special data for the font */ +typedef struct _fs_font_data { + long fontid; + int generation; /* FS generation when opened */ + FontPathElementPtr fpe; + unsigned long glyphs_to_get; /* # glyphs remaining to be gotten */ + + /* Following data needed in case font needs to be reopened. */ + int namelen; + char *name; + fsBitmapFormat format; + fsBitmapFormatMask fmask; +} FSFontDataRec; + +typedef struct fs_clients_depending { + pointer client; + struct fs_clients_depending *next; +} FSClientsDependingRec, *FSClientsDependingPtr; + +/* OpenFont specific data for blocked request */ +typedef struct _fs_blocked_font { + FontPtr pfont; + long fontid; + int state; /* how many of the replies have landed */ + int errcode; + int flags; + fsBitmapFormat format; + FSClientsDependingPtr clients_depending; +} FSBlockedFontRec; + +/* LoadGlyphs data for blocked request */ +typedef struct _fs_blocked_glyphs { + FontPtr pfont; + int num_expected_ranges; + fsRange *expected_ranges; + int errcode; + Bool done; + FSClientsDependingPtr clients_depending; +} FSBlockedGlyphRec; + +/* LoadExtents data for blocked request */ +typedef struct _fs_blocked_extents { + FontPtr pfont; + fsRange *expected_ranges; + int nranges; + Bool done; + unsigned long nextents; + fsXCharInfo *extents; +} FSBlockedExtentRec; + +/* LoadBitmaps data for blocked request */ +typedef struct _fs_blocked_bitmaps { + FontPtr pfont; + fsRange *expected_ranges; + int nranges; + Bool done; + unsigned long size; + unsigned long nglyphs; + fsOffset32 *offsets; + pointer gdata; +} FSBlockedBitmapRec; + +/* state for blocked ListFonts */ +typedef struct _fs_blocked_list { + FontNamesPtr names; + int patlen; + int errcode; + Bool done; +} FSBlockedListRec; + +/* state for blocked ListFontsWithInfo */ +typedef struct _fs_blocked_list_info { + int status; + char *name; + int namelen; + FontInfoPtr pfi; + int remaining; + int errcode; +} FSBlockedListInfoRec; + +/* state for blocked request */ +typedef struct _fs_block_data { + int type; /* Open Font, LoadGlyphs, ListFonts, + * ListWithInfo */ + pointer client; /* who wants it */ + int sequence_number;/* expected */ + fsGenericReply header; + pointer data; /* type specific data */ + struct _fs_block_data *depending; /* clients depending on this one */ + struct _fs_block_data *next; +} FSBlockDataRec; + +/* state for reconnected to dead font server */ +typedef struct _fs_reconnect { + int i; +} FSReconnectRec, *FSReconnectPtr; + + +#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP) +#define fsCat(x,y) x##_##y +#else +#define fsCat(x,y) x/**/_/**/y +#endif + + +/* copy XCharInfo parts of a protocol reply into a xCharInfo */ + +#define fsUnpack_XCharInfo(packet, structure) \ + (structure)->leftSideBearing = fsCat(packet,left); \ + (structure)->rightSideBearing = fsCat(packet,right); \ + (structure)->characterWidth = fsCat(packet,width); \ + (structure)->ascent = fsCat(packet,ascent); \ + (structure)->descent = fsCat(packet,descent); \ + (structure)->attributes = fsCat(packet,attributes) + + +/* copy XFontInfoHeader parts of a protocol reply into a FontInfoRec */ + +#define fsUnpack_XFontInfoHeader(packet, structure) \ + (structure)->allExist = ((packet)->font_header_flags & FontInfoAllCharsExist) != 0; \ + (structure)->drawDirection = \ + ((packet)->font_header_draw_direction == LeftToRightDrawDirection) ? \ + LeftToRight : RightToLeft; \ + (structure)->inkInside = ((packet)->font_header_flags & FontInfoInkInside) != 0; \ + \ + (structure)->firstRow = (packet)->font_hdr_char_range_min_char_high; \ + (structure)->firstCol = (packet)->font_hdr_char_range_min_char_low; \ + (structure)->lastRow = (packet)->font_hdr_char_range_max_char_high; \ + (structure)->lastCol = (packet)->font_hdr_char_range_max_char_low; \ + (structure)->defaultCh = (packet)->font_header_default_char_low \ + + ((packet)->font_header_default_char_high << 8); \ + \ + (structure)->fontDescent = (packet)->font_header_font_descent; \ + (structure)->fontAscent = (packet)->font_header_font_ascent; \ + \ + fsUnpack_XCharInfo((packet)->font_header_min_bounds, &(structure)->minbounds); \ + fsUnpack_XCharInfo((packet)->font_header_min_bounds, &(structure)->ink_minbounds); \ + fsUnpack_XCharInfo((packet)->font_header_max_bounds, &(structure)->maxbounds); \ + fsUnpack_XCharInfo((packet)->font_header_max_bounds, &(structure)->ink_maxbounds) + + +#endif /* _FSERVESTR_H_ */ diff --git a/src/fc/fsio.c b/src/fc/fsio.c new file mode 100644 index 0000000..578d86a --- /dev/null +++ b/src/fc/fsio.c @@ -0,0 +1,612 @@ +/* $Xorg: fsio.c,v 1.3 2000/08/17 19:46:36 cpqbld Exp $ */ +/* + * 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 name of Network Computing Devices not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. Network Computing + * Devices makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied + * warranty. + * + * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL NETWORK COMPUTING DEVICES 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 i/o routines + */ + +#ifdef WIN32 +#define _WILLWINSOCK_ +#endif + +#include "FS.h" +#include "FSproto.h" + +#include "X11/Xtrans.h" +#include "X11/Xpoll.h" +#include "fontmisc.h" +#include "fsio.h" + +#include <stdio.h> +#include <signal.h> +#include <sys/types.h> +#ifndef WIN32 +#include <sys/socket.h> +#endif +#include <errno.h> +#ifdef X_NOT_STDC_ENV +extern int errno; +#endif +#ifdef WIN32 +#define EWOULDBLOCK WSAEWOULDBLOCK +#undef EINTR +#define EINTR WSAEINTR +#endif + +/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX + * systems are broken and return EWOULDBLOCK when they should return EAGAIN + */ +#ifdef WIN32 +#define ETEST() (WSAGetLastError() == WSAEWOULDBLOCK) +#else +#if defined(EAGAIN) && defined(EWOULDBLOCK) +#define ETEST() (errno == EAGAIN || errno == EWOULDBLOCK) +#else +#ifdef EAGAIN +#define ETEST() (errno == EAGAIN) +#else +#define ETEST() (errno == EWOULDBLOCK) +#endif +#endif +#endif +#ifdef WIN32 +#define ECHECK(err) (WSAGetLastError() == err) +#define ESET(val) WSASetLastError(val) +#else +#define ECHECK(err) (errno == err) +#define ESET(val) errno = val +#endif + +static int padlength[4] = {0, 3, 2, 1}; +fd_set _fs_fd_mask; + +int _fs_wait_for_readable(); + +#ifdef SIGNALRETURNSINT +#define SIGNAL_T int +#else +#define SIGNAL_T void +#endif + +/* ARGSUSED */ +static SIGNAL_T +_fs_alarm(foo) + int foo; +{ + return; +} + +static XtransConnInfo +_fs_connect(servername, timeout) + char *servername; + int timeout; +{ + XtransConnInfo trans_conn; /* transport connection object */ + int ret = -1; +#ifdef SIGALRM + unsigned oldTime; + + SIGNAL_T(*oldAlarm) (); +#endif + + /* + * Open the network connection. + */ + if( (trans_conn=_FontTransOpenCOTSClient(servername)) == NULL ) + { + return (NULL); + } + +#ifdef SIGALRM + oldTime = alarm((unsigned) 0); + oldAlarm = signal(SIGALRM, _fs_alarm); + alarm((unsigned) timeout); +#endif + + ret = _FontTransConnect(trans_conn,servername); + +#ifdef SIGALRM + alarm((unsigned) 0); + signal(SIGALRM, oldAlarm); + alarm(oldTime); +#endif + + if (ret < 0) + { + _FontTransClose(trans_conn); + return (NULL); + } + + /* + * Set the connection non-blocking since we use select() to block. + */ + + _FontTransSetOption(trans_conn, TRANS_NONBLOCKING, 1); + + return trans_conn; +} + +static int generationCount; + +/* ARGSUSED */ +static Bool +_fs_setup_connection(conn, servername, timeout, copy_name_p) + FSFpePtr conn; + char *servername; + int timeout; + Bool copy_name_p; +{ + fsConnClientPrefix prefix; + fsConnSetup rep; + int setuplength; + fsConnSetupAccept conn_accept; + int endian; + int i; + int alt_len; + char *auth_data = NULL, + *vendor_string = NULL, + *alt_data = NULL, + *alt_dst; + FSFpeAltPtr alts; + int nalts; + + if ((conn->trans_conn = _fs_connect(servername, 5)) == NULL) + return FALSE; + + conn->fs_fd = _FontTransGetConnectionNumber (conn->trans_conn); + + conn->generation = ++generationCount; + + /* send setup prefix */ + endian = 1; + if (*(char *) &endian) + prefix.byteOrder = 'l'; + else + prefix.byteOrder = 'B'; + + prefix.major_version = FS_PROTOCOL; + prefix.minor_version = FS_PROTOCOL_MINOR; + +/* XXX add some auth info here */ + prefix.num_auths = 0; + prefix.auth_len = 0; + + if (_fs_write(conn, (char *) &prefix, SIZEOF(fsConnClientPrefix)) == -1) + return FALSE; + + /* read setup info */ + if (_fs_read(conn, (char *) &rep, SIZEOF(fsConnSetup)) == -1) + return FALSE; + + conn->fsMajorVersion = rep.major_version; + if (rep.major_version > FS_PROTOCOL) + return FALSE; + + alts = 0; + /* parse alternate list */ + if ((nalts = rep.num_alternates)) { + setuplength = rep.alternate_len << 2; + alts = (FSFpeAltPtr) xalloc(nalts * sizeof(FSFpeAltRec) + + setuplength); + if (!alts) { + _FontTransClose(conn->trans_conn); + errno = ENOMEM; + return FALSE; + } + alt_data = (char *) (alts + nalts); + if (_fs_read(conn, (char *) alt_data, setuplength) == -1) { + xfree(alts); + return FALSE; + } + alt_dst = alt_data; + for (i = 0; i < nalts; i++) { + alts[i].subset = alt_data[0]; + alt_len = alt_data[1]; + alts[i].name = alt_dst; + memmove(alt_dst, alt_data + 2, alt_len); + alt_dst[alt_len] = '\0'; + alt_dst += (alt_len + 1); + alt_data += (2 + alt_len + padlength[(2 + alt_len) & 3]); + } + } + if (conn->alts) + xfree(conn->alts); + conn->alts = alts; + conn->numAlts = nalts; + + setuplength = rep.auth_len << 2; + if (setuplength && + !(auth_data = (char *) xalloc((unsigned int) setuplength))) { + _FontTransClose(conn->trans_conn); + errno = ENOMEM; + return FALSE; + } + if (_fs_read(conn, (char *) auth_data, setuplength) == -1) { + xfree(auth_data); + return FALSE; + } + if (rep.status != AuthSuccess) { + xfree(auth_data); + _FontTransClose(conn->trans_conn); + errno = EPERM; + return FALSE; + } + /* get rest */ + if (_fs_read(conn, (char *) &conn_accept, (long) SIZEOF(fsConnSetupAccept)) == -1) { + xfree(auth_data); + return FALSE; + } + if ((vendor_string = (char *) + xalloc((unsigned) conn_accept.vendor_len + 1)) == NULL) { + xfree(auth_data); + _FontTransClose(conn->trans_conn); + errno = ENOMEM; + return FALSE; + } + if (_fs_read_pad(conn, (char *) vendor_string, conn_accept.vendor_len) == -1) { + xfree(vendor_string); + xfree(auth_data); + return FALSE; + } + xfree(auth_data); + xfree(vendor_string); + + if (copy_name_p) + { + conn->servername = (char *) xalloc(strlen(servername) + 1); + if (conn->servername == NULL) + return FALSE; + strcpy(conn->servername, servername); + } + else + conn->servername = servername; + + return TRUE; +} + +static Bool +_fs_try_alternates(conn, timeout) + FSFpePtr conn; + int timeout; +{ + int i; + + for (i = 0; i < conn->numAlts; i++) + if (_fs_setup_connection(conn, conn->alts[i].name, timeout, TRUE)) + return TRUE; + return FALSE; +} + +#define FS_OPEN_TIMEOUT 30 +#define FS_REOPEN_TIMEOUT 10 + +FSFpePtr +_fs_open_server(servername) + char *servername; +{ + FSFpePtr conn; + + conn = (FSFpePtr) xalloc(sizeof(FSFpeRec)); + if (!conn) { + errno = ENOMEM; + return (FSFpePtr) NULL; + } + bzero((char *) conn, sizeof(FSFpeRec)); + if (!_fs_setup_connection(conn, servername, FS_OPEN_TIMEOUT, TRUE)) { + if (!_fs_try_alternates(conn, FS_OPEN_TIMEOUT)) { + xfree(conn->alts); + xfree(conn); + return (FSFpePtr) NULL; + } + } + return conn; +} + +Bool +_fs_reopen_server(conn) + FSFpePtr conn; +{ + if (_fs_setup_connection(conn, conn->servername, FS_REOPEN_TIMEOUT, FALSE)) + return TRUE; + if (_fs_try_alternates(conn, FS_REOPEN_TIMEOUT)) + return TRUE; + return FALSE; +} + +/* + * expects everything to be here. *not* to be called when reading huge + * numbers of replies, but rather to get each chunk + */ +int +_fs_read(conn, data, size) + FSFpePtr conn; + char *data; + unsigned long size; +{ + long bytes_read; + + if (size == 0) { + +#ifdef DEBUG + fprintf(stderr, "tried to read 0 bytes \n"); +#endif + + return 0; + } + ESET(0); + while ((bytes_read = _FontTransRead(conn->trans_conn, + data, (int) size)) != size) { + if (bytes_read > 0) { + size -= bytes_read; + data += bytes_read; + } else if (ETEST()) { + /* in a perfect world, this shouldn't happen */ + /* ... but then, its less than perfect... */ + if (_fs_wait_for_readable(conn) == -1) { /* check for error */ + _fs_connection_died(conn); + ESET(EPIPE); + return -1; + } + ESET(0); + } else if (ECHECK(EINTR)) { + continue; + } else { /* something bad happened */ + if (conn->fs_fd > 0) + _fs_connection_died(conn); + ESET(EPIPE); + return -1; + } + } + return 0; +} + +int +_fs_write(conn, data, size) + FSFpePtr conn; + char *data; + unsigned long size; +{ + long bytes_written; + + if (size == 0) { + +#ifdef DEBUG + fprintf(stderr, "tried to write 0 bytes \n"); +#endif + + return 0; + } + + /* XXX - hack. The right fix is to remember that the font server + has gone away when we first discovered it. */ + if (!conn->trans_conn) + return -1; + + ESET(0); + while ((bytes_written = _FontTransWrite(conn->trans_conn, + data, (int) size)) != size) { + if (bytes_written > 0) { + size -= bytes_written; + data += bytes_written; + } else if (ETEST()) { + /* XXX -- we assume this can't happen */ + +#ifdef DEBUG + fprintf(stderr, "fs_write blocking\n"); +#endif + } else if (ECHECK(EINTR)) { + continue; + } else { /* something bad happened */ + _fs_connection_died(conn); + ESET(EPIPE); + return -1; + } + } + return 0; +} + +int +_fs_read_pad(conn, data, len) + FSFpePtr conn; + char *data; + int len; +{ + char pad[3]; + + if (_fs_read(conn, data, len) == -1) + return -1; + + /* read the junk */ + if (padlength[len & 3]) { + return _fs_read(conn, pad, padlength[len & 3]); + } + return 0; +} + +int +_fs_write_pad(conn, data, len) + FSFpePtr conn; + char *data; + int len; +{ + static char pad[3]; + + if (_fs_write(conn, data, len) == -1) + return -1; + + /* write the pad */ + if (padlength[len & 3]) { + return _fs_write(conn, pad, padlength[len & 3]); + } + return 0; +} + +/* + * returns the amount of data waiting to be read + */ +int +_fs_data_ready(conn) + FSFpePtr conn; +{ + BytesReadable_t readable; + + if (_FontTransBytesReadable(conn->trans_conn, &readable) < 0) + return -1; + return readable; +} + +int +_fs_wait_for_readable(conn) + FSFpePtr conn; +{ + fd_set r_mask; + fd_set e_mask; + int result; + +#ifdef DEBUG + fprintf(stderr, "read would block\n"); +#endif + + do { + FD_ZERO(&r_mask); + FD_ZERO(&e_mask); + FD_SET(conn->fs_fd, &r_mask); + FD_SET(conn->fs_fd, &e_mask); + result = Select(conn->fs_fd + 1, &r_mask, NULL, &e_mask, NULL); + if (result == -1) { + if (ECHECK(EINTR) || ECHECK(EAGAIN)) + continue; + else + return -1; + } + if (result && FD_ISSET(conn->fs_fd, &e_mask)) + return -1; + } while (result <= 0); + + return 0; +} + +int +_fs_set_bit(mask, fd) + fd_set* mask; + int fd; +{ + FD_SET(fd, mask); + return fd; +} + +int +_fs_is_bit_set(mask, fd) + fd_set* mask; + int fd; +{ + return FD_ISSET(fd, mask); +} + +void +_fs_bit_clear(mask, fd) + fd_set* mask; + int fd; +{ + FD_CLR(fd, mask); +} + +int +_fs_any_bit_set(mask) + fd_set* mask; +{ + return XFD_ANYSET(mask); +} + +void +_fs_or_bits(dst, m1, m2) + fd_set* dst; + fd_set* m1; + fd_set* m2; +{ +#ifdef WIN32 + int i; + if (dst != m1) { + for (i = m1->fd_count; --i >= 0; ) { + if (!FD_ISSET(m1->fd_array[i], dst)) + FD_SET(m1->fd_array[i], dst); + } + } + if (dst != m2) { + for (i = m2->fd_count; --i >= 0; ) { + if (!FD_ISSET(m2->fd_array[i], dst)) + FD_SET(m2->fd_array[i], dst); + } + } +#else + XFD_ORSET(dst, m1, m2); +#endif +} + +int +_fs_drain_bytes(conn, len) + FSFpePtr conn; + int len; +{ + char buf[128]; + +#ifdef DEBUG + fprintf(stderr, "draining wire\n"); +#endif + + while (len > 0) { + if (_fs_read(conn, buf, (len < 128) ? len : 128) < 0) + return -1; + len -= 128; + } + return 0; +} + +void +_fs_drain_bytes_pad(conn, len) + FSFpePtr conn; + int len; +{ + _fs_drain_bytes(conn, len); + + /* read the junk */ + if (padlength[len & 3]) { + _fs_drain_bytes(conn, padlength[len & 3]); + } +} + +void +_fs_eat_rest_of_error(conn, err) + FSFpePtr conn; + fsError *err; +{ + int len = (err->length - (SIZEOF(fsGenericReply) >> 2)) << 2; + +#ifdef DEBUG + fprintf(stderr, "clearing error\n"); +#endif + + _fs_drain_bytes(conn, len); +} diff --git a/src/fc/fsio.h b/src/fc/fsio.h new file mode 100644 index 0000000..dd33cdf --- /dev/null +++ b/src/fc/fsio.h @@ -0,0 +1,82 @@ +/* $Xorg: fsio.h,v 1.3 2000/08/17 19:46:36 cpqbld Exp $ */ +/* + * 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 name of Network Computing Devices not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. Network Computing + * Devices makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied + * warranty. + * + * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL NETWORK COMPUTING DEVICES 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 + */ + +#ifndef _FSIO_H_ +#define _FSIO_H_ + +#define REQUEST_LOG_SIZE 100 + +typedef struct _fs_fpe_alternate { + char *name; + Bool subset; +} FSFpeAltRec, *FSFpeAltPtr; + + +/* Per client access contexts */ +typedef struct _fs_client_data { + pointer client; + struct _fs_client_data *next; + XID acid; + int auth_generation; +} FSClientRec, *FSClientPtr; + +#define FS_RECONNECT_WAIT 5 +#define FS_MAX_RECONNECT_WAIT 80 + +/* FS specific font FontPathElement data */ +typedef struct _fs_fpe_data { + int fs_fd; + int current_seq; + char *servername; + char *requestedname; /* client's name for this connection */ + + int generation; + int numAlts; + int fsMajorVersion; /* font server major version number */ + FSFpeAltPtr alts; + + FSClientPtr clients; + XID curacid; +#ifdef DEBUG + int reqindex; + int reqbuffer[REQUEST_LOG_SIZE]; +#endif + + int attemptReconnect; + +/* XXX massive crock to get around stupid #include interferences */ + pointer blocked_requests; +/* Data for reconnect - put it here to avoid allocate failure nightmare */ + long time_to_try; + long reconnect_delay; + struct _fs_fpe_data *next_reconnect; + struct _XtransConnInfo *trans_conn; /* transport connection object */ +} FSFpeRec, *FSFpePtr; + +FSFpePtr _fs_open_server(); +void _fs_bit_clear(); + +#endif /* _FSIO_H_ */ diff --git a/src/fc/fslibos.h b/src/fc/fslibos.h new file mode 100644 index 0000000..d666ea4 --- /dev/null +++ b/src/fc/fslibos.h @@ -0,0 +1,212 @@ +/* $Xorg: fslibos.h,v 1.4 2001/02/09 02:04:03 xorgcvs Exp $ */ +/* + * Copyright 1990 Network Computing Devices; + * Portions Copyright 1987 by Digital Equipment Corporation + */ + +/* + +Copyright 1987, 1994, 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. + +*/ + +/* + * FSlib networking & os include file + */ + +#include <X11/Xtrans.h> + +#ifndef WIN32 + +/* + * makedepend screws up on #undef OPEN_MAX, so we define a new symbol + */ + +#ifndef FONT_OPEN_MAX + +#ifndef X_NOT_POSIX +#ifdef _POSIX_SOURCE +#include <limits.h> +#else +#define _POSIX_SOURCE +#include <limits.h> +#undef _POSIX_SOURCE +#endif +#endif +#ifndef OPEN_MAX +#ifdef SVR4 +#define OPEN_MAX 256 +#else +#include <sys/param.h> +#ifndef OPEN_MAX +#ifdef __OSF1__ +#define OPEN_MAX 256 +#else +#ifdef NOFILE +#define OPEN_MAX NOFILE +#else +#define OPEN_MAX NOFILES_MAX +#endif +#endif +#endif +#endif +#endif + +#if OPEN_MAX > 256 +#define FONT_OPEN_MAX 256 +#else +#define FONT_OPEN_MAX OPEN_MAX +#endif + +#endif /* FONT_OPEN_MAX */ + +#ifdef WORD64 +#define NMSKBITS 64 +#else +#define NMSKBITS 32 +#endif + +#define MSKCNT ((FONT_OPEN_MAX + NMSKBITS - 1) / NMSKBITS) + +typedef unsigned long FdSet[MSKCNT]; +typedef FdSet FdSetPtr; + +#if (MSKCNT==1) +#define BITMASK(i) (1 << (i)) +#define MASKIDX(i) 0 +#endif + +#if (MSKCNT>1) +#define BITMASK(i) (1 << ((i) & (NMSKBITS - 1))) +#define MASKIDX(i) ((i) / NMSKBITS) +#endif + +#define MASKWORD(buf, i) buf[MASKIDX(i)] +#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i) +#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i) +#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i)) + +#if (MSKCNT==1) +#define COPYBITS(src, dst) dst[0] = src[0] +#define CLEARBITS(buf) buf[0] = 0 +#define MASKANDSETBITS(dst, b1, b2) dst[0] = (b1[0] & b2[0]) +#define ORBITS(dst, b1, b2) dst[0] = (b1[0] | b2[0]) +#define UNSETBITS(dst, b1) (dst[0] &= ~b1[0]) +#define ANYSET(src) (src[0]) +#endif + +#if (MSKCNT==2) +#define COPYBITS(src, dst) { dst[0] = src[0]; dst[1] = src[1]; } +#define CLEARBITS(buf) { buf[0] = 0; buf[1] = 0; } +#define MASKANDSETBITS(dst, b1, b2) {\ + dst[0] = (b1[0] & b2[0]);\ + dst[1] = (b1[1] & b2[1]); } +#define ORBITS(dst, b1, b2) {\ + dst[0] = (b1[0] | b2[0]);\ + dst[1] = (b1[1] | b2[1]); } +#define UNSETBITS(dst, b1) {\ + dst[0] &= ~b1[0]; \ + dst[1] &= ~b1[1]; } +#define ANYSET(src) (src[0] || src[1]) +#endif + +#if (MSKCNT==3) +#define COPYBITS(src, dst) { dst[0] = src[0]; dst[1] = src[1]; \ + dst[2] = src[2]; } +#define CLEARBITS(buf) { buf[0] = 0; buf[1] = 0; buf[2] = 0; } +#define MASKANDSETBITS(dst, b1, b2) {\ + dst[0] = (b1[0] & b2[0]);\ + dst[1] = (b1[1] & b2[1]);\ + dst[2] = (b1[2] & b2[2]); } +#define ORBITS(dst, b1, b2) {\ + dst[0] = (b1[0] | b2[0]);\ + dst[1] = (b1[1] | b2[1]);\ + dst[2] = (b1[2] | b2[2]); } +#define UNSETBITS(dst, b1) {\ + dst[0] &= ~b1[0]; \ + dst[1] &= ~b1[1]; \ + dst[2] &= ~b1[2]; } +#define ANYSET(src) (src[0] || src[1] || src[2]) +#endif + +#if (MSKCNT==4) +#define COPYBITS(src, dst) dst[0] = src[0]; dst[1] = src[1]; \ + dst[2] = src[2]; dst[3] = src[3] +#define CLEARBITS(buf) buf[0] = 0; buf[1] = 0; buf[2] = 0; buf[3] = 0 +#define MASKANDSETBITS(dst, b1, b2) \ + dst[0] = (b1[0] & b2[0]);\ + dst[1] = (b1[1] & b2[1]);\ + dst[2] = (b1[2] & b2[2]);\ + dst[3] = (b1[3] & b2[3]) +#define ORBITS(dst, b1, b2) \ + dst[0] = (b1[0] | b2[0]);\ + dst[1] = (b1[1] | b2[1]);\ + dst[2] = (b1[2] | b2[2]);\ + dst[3] = (b1[3] | b2[3]) +#define UNSETBITS(dst, b1) \ + dst[0] &= ~b1[0]; \ + dst[1] &= ~b1[1]; \ + dst[2] &= ~b1[2]; \ + dst[3] &= ~b1[3] +#define ANYSET(src) (src[0] || src[1] || src[2] || src[3]) +#endif + +#if (MSKCNT>4) +#define COPYBITS(src, dst) memmove((caddr_t) dst, (caddr_t) src,\ + MSKCNT*sizeof(long)) +#define CLEARBITS(buf) bzero((caddr_t) buf, MSKCNT*sizeof(long)) +#define MASKANDSETBITS(dst, b1, b2) \ + { int cri; \ + for (cri=MSKCNT; --cri>=0; ) \ + dst[cri] = (b1[cri] & b2[cri]); } +#define ORBITS(dst, b1, b2) \ + { int cri; \ + for (cri=MSKCNT; --cri>=0; ) \ + dst[cri] = (b1[cri] | b2[cri]); } +#define UNSETBITS(dst, b1) \ + { int cri; \ + for (cri=MSKCNT; --cri>=0; ) \ + dst[cri] &= ~b1[cri]; } +#if (MSKCNT==8) +#define ANYSET(src) (src[0] || src[1] || src[2] || src[3] || \ + src[4] || src[5] || src[6] || src[7]) +#endif +#endif + +#else /* not WIN32 */ + +#include <X11/Xwinsock.h> +#include <X11/Xw32defs.h> + +typedef fd_set FdSet; +typedef FdSet *FdSetPtr; + +#define CLEARBITS(set) FD_ZERO(&set) +#define BITSET(set,s) FD_SET(s,&set) +#define BITCLEAR(set,s) FD_CLR(s,&set) +#define GETBIT(set,s) FD_ISSET(s,&set) +#define ANYSET(set) set->fd_count + +#endif |