1/*
2 * font data query
3 */
4/*
5
6Copyright 1990, 1991, 1998  The Open Group
7
8Permission to use, copy, modify, distribute, and sell this software and its
9documentation for any purpose is hereby granted without fee, provided that
10the above copyright notice appear in all copies and that both that
11copyright notice and this permission notice appear in supporting
12documentation.
13
14The above copyright notice and this permission notice shall be included in
15all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the name of The Open Group shall not be
25used in advertising or otherwise to promote the sale, use or other dealings
26in this Software without prior written authorization from The Open Group.
27
28 * Copyright 1990, 1991 Network Computing Devices;
29 * Portions Copyright 1987 by Digital Equipment Corporation
30 *
31 * Permission to use, copy, modify, distribute, and sell this software and
32 * its documentation for any purpose is hereby granted without fee, provided
33 * that the above copyright notice appear in all copies and that both that
34 * copyright notice and this permission notice appear in supporting
35 * documentation, and that the names of Network Computing Devices, or Digital
36 * not be used in advertising or publicity pertaining to distribution
37 * of the software without specific, written prior permission.
38 *
39 * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH
40 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
41 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
42 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
43 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
44 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
45 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
46 * THIS SOFTWARE.
47 */
48
49#include	"config.h"
50
51#include        <X11/fonts/FS.h>
52#include        <X11/fonts/FSproto.h>
53#include        <stdio.h>
54#include        <X11/Xos.h>
55#include        "clientstr.h"
56#include        "difsfnst.h"
57#include        <X11/fonts/fontstruct.h>
58#include        "closestr.h"
59#include        "globals.h"
60#include	"difs.h"
61#include        "misc.h"
62#include	"dispatch.h"
63#include	<swapreq.h>
64#include	<swaprep.h>
65
66#ifdef HAVE_STDINT_H
67#include	<stdint.h>
68#endif
69#include	<limits.h>
70#ifndef SIZE_MAX
71# ifdef ULONG_MAX
72#  define SIZE_MAX ULONG_MAX
73# else
74#  define SIZE_MAX UINT_MAX
75# endif
76#endif
77
78
79int
80convert_props(
81    FontInfoPtr pinfo,
82    fsPropInfo **props)
83{
84    int i;
85    int data_len, cur_off;
86    const char *str;
87    pointer ptr, off_ptr, string_base;
88    fsPropOffset local_offset;
89
90    /*
91     * compute the size of the property data
92     */
93    data_len = 0;
94    for (i = 0; i < pinfo->nprops; i++)
95    {
96	data_len += strlen(NameForAtom(pinfo->props[i].name));
97	if (NULL != pinfo->isStringProp && pinfo->isStringProp[i])
98	    data_len += strlen(NameForAtom(pinfo->props[i].value));
99    }
100
101    /*
102     * allocate the single chunk that the difs layer requires
103     */
104    ptr = (pointer) FSalloc(SIZEOF(fsPropInfo)
105			    + SIZEOF(fsPropOffset) * pinfo->nprops
106			    + data_len);
107    if (!ptr)
108	return AllocError;
109    string_base = (char *)ptr + SIZEOF(fsPropInfo) + SIZEOF(fsPropOffset) * pinfo->nprops;
110
111    /*
112     * copy in the header
113     */
114    ((fsPropInfo *)ptr)->num_offsets = pinfo->nprops;
115    ((fsPropInfo *)ptr)->data_len = data_len;
116
117    /*
118     * compute the offsets and copy the string data
119     */
120    off_ptr = (char *)ptr + SIZEOF(fsPropInfo);
121    cur_off = 0;
122    for (i = 0; i < pinfo->nprops; i++)
123    {
124	local_offset.name.position = cur_off;
125	str = NameForAtom(pinfo->props[i].name);
126	local_offset.name.length = strlen(str);
127	memmove( (char *)string_base+cur_off, str, local_offset.name.length);
128	cur_off += local_offset.name.length;
129	if (NULL != pinfo->isStringProp && pinfo->isStringProp[i])
130	{
131	    local_offset.value.position = cur_off;
132	    str = NameForAtom(pinfo->props[i].value);
133	    local_offset.value.length = strlen(str);
134	    memmove( (char *)string_base+cur_off, str, local_offset.value.length);
135	    cur_off += local_offset.value.length;
136	    local_offset.type = PropTypeString;
137	} else {
138	    local_offset.value.position = pinfo->props[i].value;
139	    local_offset.value.length = 0; /* protocol says must be zero */
140	    local_offset.type = PropTypeSigned;
141	}
142	memmove( off_ptr, &local_offset, SIZEOF(fsPropOffset));
143	off_ptr = (char *)off_ptr + SIZEOF(fsPropOffset);
144    }
145
146    assert(off_ptr == string_base);
147    assert(cur_off == data_len);
148
149    *props = (fsPropInfo *) ptr;
150    return Successful;
151}
152
153
154/*
155 * does the real work of turning a list of range (or chars) into
156 * a list of ranges
157 */
158static fsRange *
159build_range(
160    Bool        type,
161    pointer     src,
162    int         item_size,
163    int        *num,
164    Bool       *all,
165    FontInfoPtr	pfi)
166{
167    fsRange    *new = (fsRange *) 0,
168               *np;
169    unsigned long src_num;
170    unsigned long i;
171
172    if (type) {			/* range flag is set, deal with data as a list
173				 * of char2bs */
174	char *rp = (char *) src;
175
176	src_num = *num;
177	if (src_num == 0) {
178	    *all = TRUE;
179	    return new;
180	}
181
182	if (src_num >= SIZE_MAX / sizeof(fsRange) * 2 - 1)
183		return NULL;
184	np = new = (fsRange *) FSalloc(sizeof(fsRange) * (src_num + 1) / 2);
185	if (!np)
186	    return np;
187	/* Build a new range */
188	for (i = 1; i < src_num; i += 2)
189	{
190	    np->min_char_high = (item_size == 1) ? 0 : *rp++;
191	    np->min_char_low  = *rp++;
192	    np->max_char_high = (item_size == 1) ? 0 : *rp++;
193	    np->max_char_low  = *rp++;
194	    np++;
195	}
196
197	/* If src_num is odd, we need to determine the final range
198	   by examining the fontinfo */
199	if (i == src_num)
200	{
201	    np->min_char_high = (item_size == 1) ? 0 : *rp++;
202	    np->min_char_low  = *rp++;
203	    np->max_char_high = pfi->lastRow;
204	    np->max_char_low  = pfi->lastCol;
205	    np++;
206	}
207	*num = np - new;
208	return new;
209    } else {			/* deal with data as a list of characters */
210	unsigned char      *pp = src;
211
212	src_num = *num;
213	if (src_num >= SIZE_MAX / sizeof(fsRange))
214		return NULL;
215	np = new = (fsRange *) FSallocarray(src_num, SIZEOF(fsRange));
216	if (!np)
217	    return np;
218
219	/* Build a range, with coalescence, from the list of chars */
220
221	for (i = 0; i < src_num; i++) {
222	    if (item_size == 1) {
223		np->min_char_low = *pp;
224		np->min_char_high = 0;
225	    } else {
226		np->min_char_low = ((fsChar2b *) pp)->low;
227		np->min_char_high = ((fsChar2b *) pp)->high;
228	    }
229	    np->max_char_high = np->min_char_high;
230	    np->max_char_low = np->min_char_low;
231	    /* Can we coalesce? */
232	    if (np > new &&
233		np->max_char_high == np[-1].max_char_high &&
234		np->max_char_low == np[-1].max_char_low + 1)
235		np[-1].max_char_low++;		/* Yes */
236	    else
237		np++;				/* No */
238	    pp += item_size;
239	}
240	*num = np - new;
241	return new;
242    }
243}
244
245/*
246 * provide backward compatibility with version 1, which had
247 * the bytes of char2b backwards
248 */
249static void
250swap_char2b (fsChar2b *values, int number)
251{
252    fsChar2b temp;
253    int i;
254
255    for (i = 0; i < number; i++) {
256	temp.low = ((fsChar2b_version1 *)values)->low;
257	temp.high = ((fsChar2b_version1 *)values)->high;
258	*values++ = temp;
259    }
260}
261
262#define pPtr ((QEclosurePtr) data)
263
264static Bool
265do_query_extents(ClientPtr client, pointer data)
266{
267    int         err;
268    unsigned long num_extents;
269    fsXCharInfo *extents;
270
271    err = GetExtents (pPtr->client, pPtr->pfont,
272		     pPtr->flags, pPtr->nranges, pPtr->range, &num_extents, &extents);
273    if (err == Suspended) {
274	if (!pPtr->slept) {
275	    pPtr->pfont->unload_glyphs = NULL;  /* Not a safe call for this font */
276	    pPtr->slept = TRUE;
277	    ClientSleep(client, do_query_extents, (pointer) pPtr);
278	}
279	return TRUE;
280    }
281    if (err != Successful) {
282	SendErrToClient(pPtr->client, FontToFSError(err), (pointer) 0);
283    }
284    else {
285	unsigned long lendata = SIZEOF(fsXCharInfo) * num_extents;
286	fsQueryXExtents8Reply reply = {
287	    .type = FS_Reply,
288	    .sequenceNumber = pPtr->client->sequence,
289	    .num_extents = num_extents,
290	    .length = (SIZEOF(fsQueryXExtents8Reply) + lendata) >> 2
291	};
292	if (client->swapped)
293	    SwapExtents(extents, num_extents);
294	WriteReplyToClient(pPtr->client, SIZEOF(fsQueryXExtents8Reply), &reply);
295	WriteToClient(pPtr->client, lendata, (char *) extents);
296	FSfree((char *) extents);
297    }
298    if (pPtr->slept)
299	ClientWakeup(pPtr->client);
300    if (pPtr->pfont->unload_glyphs)  /* For rasterizers that want to save memory */
301	(*pPtr->pfont->unload_glyphs)(pPtr->pfont);
302    FSfree(pPtr->range);
303    FSfree(pPtr);
304    return TRUE;
305}
306
307int
308QueryExtents(
309    ClientPtr   client,
310    ClientFontPtr cfp,
311    int         item_size,
312    int         nranges,
313    Bool        range_flag,
314    pointer     range_data)
315{
316    QEclosurePtr c;
317    fsRange    *fixed_range;
318    Bool        all_glyphs = FALSE;
319
320    if (item_size == 2  &&  client->major_version == 1)
321	swap_char2b ((fsChar2b *)range_data, nranges);
322
323    fixed_range = build_range(range_flag, range_data, item_size,
324			      &nranges, &all_glyphs, &cfp->font->info);
325
326    if (!fixed_range && !all_glyphs) {
327	SendErrToClient(client, FSBadRange, NULL);
328	return FSBadRange;
329    }
330    c = (QEclosurePtr) FSalloc(sizeof(QEclosureRec));
331    if (!c) {
332	FSfree(fixed_range);
333	return FSBadAlloc;
334    }
335    c->client = client;
336    c->slept = FALSE;
337    c->pfont = cfp->font;
338    c->flags = (all_glyphs) ? LoadAll : 0;
339    c->flags |= (item_size == 1) ? EightBitFont : SixteenBitFont;
340    c->nranges = nranges;
341    c->range = fixed_range;
342
343    (void) do_query_extents(client, (pointer) c);
344    return FSSuccess;
345}
346
347#undef pPtr
348#define pPtr ((QBclosurePtr) data)
349
350static Bool
351do_query_bitmaps(ClientPtr client, pointer data)
352{
353    int         err;
354    unsigned long num_glyphs;
355    int data_size;
356    fsOffset32   *offsets;
357    pointer     glyph_data;
358    int		freedata;
359
360    err = GetBitmaps (pPtr->client, pPtr->pfont, pPtr->format,
361				    pPtr->flags, pPtr->nranges, pPtr->range,
362			     &data_size, &num_glyphs, &offsets, &glyph_data, &freedata);
363
364    if (err == Suspended) {
365	if (!pPtr->slept) {
366	    pPtr->pfont->unload_glyphs = NULL;  /* Not a safe call for this font */
367	    pPtr->slept = TRUE;
368	    ClientSleep(client, do_query_bitmaps, (pointer) pPtr);
369	}
370	return TRUE;
371    }
372    if (err != Successful) {
373	SendErrToClient(pPtr->client, FontToFSError(err), (pointer) 0);
374    }
375    else {
376	fsQueryXBitmaps8Reply reply = {
377	    .type = FS_Reply,
378	    .sequenceNumber = pPtr->client->sequence,
379	    .length = (SIZEOF(fsQueryXBitmaps8Reply) + data_size +
380		       (SIZEOF(fsOffset32) * num_glyphs) + 3) >> 2,
381	    .replies_hint = 0,
382	    .num_chars = num_glyphs,
383	    .nbytes = data_size
384	};
385
386	WriteReplyToClient(pPtr->client, SIZEOF(fsQueryXBitmaps8Reply), &reply);
387	if (client->swapped)
388	    SwapLongs((long *)offsets, num_glyphs * 2);
389	WriteToClient(pPtr->client, (num_glyphs * SIZEOF(fsOffset32)),
390		      (char *) offsets);
391	WriteToClient(pPtr->client, data_size, (char *) glyph_data);
392	FSfree((char *) offsets);
393	if (freedata)
394	    FSfree((char *) glyph_data);
395    }
396    if (pPtr->slept)
397	ClientWakeup(pPtr->client);
398    if (pPtr->pfont->unload_glyphs)  /* For rasterizers that want to save memory */
399	(*pPtr->pfont->unload_glyphs)(pPtr->pfont);
400    FSfree(pPtr->range);
401    FSfree(pPtr);
402    return TRUE;
403}
404
405int
406QueryBitmaps(
407    ClientPtr   client,
408    ClientFontPtr cfp,
409    int         item_size,
410    fsBitmapFormat format,
411    int         nranges,
412    Bool        range_flag,
413    pointer     range_data)
414{
415    QBclosurePtr c;
416    fsRange    *fixed_range;
417    Bool        all_glyphs = FALSE;
418
419    if (item_size == 2  &&  client->major_version == 1)
420	swap_char2b ((fsChar2b *)range_data, nranges);
421
422    fixed_range = build_range(range_flag, range_data, item_size,
423			      &nranges, &all_glyphs, &cfp->font->info);
424
425    if (!fixed_range && !all_glyphs) {
426	SendErrToClient(client, FSBadRange, NULL);
427	return FSBadRange;
428    }
429    c = (QBclosurePtr) FSalloc(sizeof(QBclosureRec));
430    if (!c) {
431	FSfree(fixed_range);
432	return FSBadAlloc;
433    }
434    c->client = client;
435    c->slept = FALSE;
436    c->pfont = cfp->font;
437    c->flags = (all_glyphs) ? LoadAll : 0;
438    c->nranges = nranges;
439    c->range = fixed_range;
440    c->format = format;
441
442    (void) do_query_bitmaps(client, (pointer) c);
443    return FSSuccess;
444}
445