1 /*
2
3 Copyright 1990, 1991, 1998 The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24
25 * Copyright 1990, 1991 Network Computing Devices;
26 * Portions Copyright 1987 by Digital Equipment Corporation
27 *
28 * Permission to use, copy, modify, distribute, and sell this software and
29 * its documentation for any purpose is hereby granted without fee, provided
30 * that the above copyright notice appear in all copies and that both that
31 * copyright notice and this permission notice appear in supporting
32 * documentation, and that the names of Network Computing Devices, or Digital
33 * not be used in advertising or publicity pertaining to distribution
34 * of the software without specific, written prior permission.
35 *
36 * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH
37 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
38 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
39 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
40 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
41 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
42 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
43 * THIS SOFTWARE.
44 */
45 /*
46 * Defines GetExtents() and GetBitmaps(), which are
47 * called from routines in fontinfo.c.
48 * This file was once on the other side of
49 * the font library interface as util/fsfuncs.c.
50 */
51
52 #include "config.h"
53
54 #include <X11/Xos.h>
55 #include "misc.h"
56 #include <X11/fonts/fontstruct.h>
57
58 #include "clientstr.h"
59 #define FSMD_H
60 #include <X11/fonts/FSproto.h>
61 #include "difs.h"
62
63 #define GLWIDTHBYTESPADDED(bits,nbytes) \
64 ((nbytes) == 1 ? (((bits)+7)>>3) /* pad to 1 byte */ \
65 :(nbytes) == 2 ? ((((bits)+15)>>3)&~1) /* pad to 2 bytes */ \
66 :(nbytes) == 4 ? ((((bits)+31)>>3)&~3) /* pad to 4 bytes */ \
67 :(nbytes) == 8 ? ((((bits)+63)>>3)&~7) /* pad to 8 bytes */ \
68 : 0)
69
70 #define GLYPH_SIZE(ch, nbytes) \
71 GLWIDTHBYTESPADDED((ch)->metrics.rightSideBearing - \
72 (ch)->metrics.leftSideBearing, (nbytes))
73
74 #define n2dChars(pfi) (((pfi)->lastRow - (pfi)->firstRow + 1) * \
75 ((pfi)->lastCol - (pfi)->firstCol + 1))
76
77 #if 0
78 static CharInfoRec junkDefault;
79 #endif
80
81 typedef int (*MetricsFunc)(FontPtr, unsigned long, unsigned char *,
82 FontEncoding, unsigned long *, CharInfoPtr *);
83
84 static int
getCharInfos(FontPtr pfont,int num_ranges,fsRange * range,Bool ink_metrics,int * nump,CharInfoPtr ** retp)85 getCharInfos (
86 FontPtr pfont,
87 int num_ranges,
88 fsRange *range,
89 Bool ink_metrics,
90 int *nump, /* return */
91 CharInfoPtr **retp) /* return */
92 {
93 CharInfoPtr *xchars, *xci;
94 int nchars;
95 FontInfoPtr pinfo = &pfont->info;
96 unsigned int r, c;
97 unsigned char ch[2];
98 int firstCol = pinfo->firstCol;
99 int firstRow = pinfo->firstRow;
100 int lastRow = pinfo->lastRow;
101 int lastCol = pinfo->lastCol;
102 fsRange local_range, *rp;
103 int i;
104 FontEncoding encoding;
105 int err;
106 unsigned long glyphCount;
107 unsigned short defaultCh;
108 CharInfoPtr defaultPtr;
109 MetricsFunc metrics_func;
110
111 /*
112 * compute nchars
113 */
114 if (num_ranges == 0) {
115 if (lastRow)
116 nchars = n2dChars(pinfo);
117 else
118 nchars = lastCol - firstCol + 1;
119 local_range.min_char_low = firstCol;
120 local_range.min_char_high = firstRow;
121 local_range.max_char_low = lastCol;
122 local_range.max_char_high = lastRow;
123 range = &local_range;
124 num_ranges = 1;
125 } else {
126 nchars = 0;
127 for (i = 0, rp = range; i < num_ranges; i++, rp++) {
128 if (rp->min_char_high > rp->max_char_high ||
129 rp->min_char_low > rp->max_char_low)
130 return BadCharRange;
131 nchars += (rp->max_char_high - rp->min_char_high + 1) *
132 (rp->max_char_low - rp->min_char_low + 1);
133 }
134 }
135
136 xchars = (CharInfoPtr *) fsalloc (sizeof (CharInfoPtr) * nchars);
137 if (!xchars)
138 return AllocError;
139 bzero (xchars, sizeof (CharInfoPtr) * nchars);
140
141 if (ink_metrics)
142 metrics_func = (MetricsFunc)pfont->get_metrics;
143 else
144 metrics_func = pfont->get_glyphs;
145
146 xci = xchars;
147 encoding = Linear16Bit;
148 if (lastRow)
149 encoding = TwoD16Bit;
150 defaultCh = pinfo->defaultCh;
151 ch[0] = defaultCh >> 8;
152 ch[1] = defaultCh & 0xff;
153 /* get the default character */
154 (*metrics_func) (pfont, 1, ch, encoding,
155 &glyphCount, &defaultPtr);
156 if (glyphCount != 1)
157 defaultPtr = NULL;
158
159 /* for each range, get each character individually, undoing the
160 default character substitution so we get zero metrics for
161 non-existent characters. */
162 for (i = 0, rp = range; i < num_ranges; i++, rp++) {
163 for (r = rp->min_char_high; r <= rp->max_char_high; r++)
164 {
165 for (c = rp->min_char_low; c <= rp->max_char_low; c++) {
166 ch[0] = r;
167 ch[1] = c;
168 err = (*metrics_func) (pfont, 1, ch, encoding,
169 &glyphCount, xci);
170 if (err != Successful)
171 {
172 fsfree (xchars);
173 return err;
174 }
175 #if 0
176 if (glyphCount != 1 ||
177 (*xci == defaultPtr && defaultCh != ((r<<8)+c)))
178 *xci = &junkDefault;
179 #endif
180 xci++;
181 }
182 }
183 }
184 *retp = xchars;
185 *nump = nchars;
186 return Successful;
187 }
188
189 int
GetExtents(ClientPtr client,FontPtr pfont,Mask flags,unsigned long num_ranges,fsRange * range,unsigned long * num_extents,fsXCharInfo ** data)190 GetExtents(
191 ClientPtr client,
192 FontPtr pfont,
193 Mask flags,
194 unsigned long num_ranges,
195 fsRange *range,
196 unsigned long *num_extents, /* return */
197 fsXCharInfo **data) /* return */
198 {
199 unsigned long size;
200 fsXCharInfo *ci;
201 fsXCharInfo cilocal;
202 char *pci;
203 CharInfoPtr *xchars, *xchars_cur;
204 CharInfoPtr xci;
205 int nchars;
206 int err;
207
208 if (flags & LoadAll)
209 num_ranges = 0;
210 err = getCharInfos (pfont, num_ranges, range,
211 client->major_version > 1 ? TRUE : FALSE,
212 &nchars, &xchars);
213 if (err != Successful)
214 return err;
215
216 size = SIZEOF(fsXCharInfo) * nchars;
217 pci = (char *) fsalloc(size);
218 if (!pci) {
219 fsfree (xchars);
220 return AllocError;
221 }
222
223 ci = (fsXCharInfo *) pci;
224 *num_extents = nchars;
225
226 /* pack the data */
227 xchars_cur = xchars;
228 while (nchars--) {
229 xci = *xchars_cur++;
230 cilocal.ascent = xci->metrics.ascent;
231 cilocal.descent = xci->metrics.descent;
232 cilocal.left = xci->metrics.leftSideBearing;
233 cilocal.right = xci->metrics.rightSideBearing;
234 cilocal.width = xci->metrics.characterWidth;
235 cilocal.attributes = xci->metrics.attributes;
236 memcpy(pci, &cilocal, SIZEOF(fsXCharInfo));
237 pci += SIZEOF(fsXCharInfo);
238 }
239
240 fsfree (xchars);
241
242 *data = ci;
243
244 return Successful;
245 }
246
247 static int
CheckFSFormat(fsBitmapFormat format,fsBitmapFormatMask fmask,int * bit_order,int * byte_order,int * scan,int * glyph,int * image)248 CheckFSFormat(fsBitmapFormat format,
249 fsBitmapFormatMask fmask,
250 int *bit_order,
251 int *byte_order,
252 int *scan,
253 int *glyph,
254 int *image)
255 {
256 /* convert format to what the low levels want */
257 if (fmask & BitmapFormatMaskBit) {
258 *bit_order = format & BitmapFormatBitOrderMask;
259 *bit_order = (*bit_order == BitmapFormatBitOrderMSB)
260 ? MSBFirst : LSBFirst;
261 }
262 if (fmask & BitmapFormatMaskByte) {
263 *byte_order = format & BitmapFormatByteOrderMask;
264 *byte_order = (*byte_order == BitmapFormatByteOrderMSB)
265 ? MSBFirst : LSBFirst;
266 }
267 if (fmask & BitmapFormatMaskScanLineUnit) {
268 *scan = format & BitmapFormatScanlineUnitMask;
269 /* convert byte paddings into byte counts */
270 switch (*scan) {
271 case BitmapFormatScanlineUnit8:
272 *scan = 1;
273 break;
274 case BitmapFormatScanlineUnit16:
275 *scan = 2;
276 break;
277 case BitmapFormatScanlineUnit32:
278 *scan = 4;
279 break;
280 default:
281 return BadFontFormat;
282 }
283 }
284 if (fmask & BitmapFormatMaskScanLinePad) {
285 *glyph = format & BitmapFormatScanlinePadMask;
286 /* convert byte paddings into byte counts */
287 switch (*glyph) {
288 case BitmapFormatScanlinePad8:
289 *glyph = 1;
290 break;
291 case BitmapFormatScanlinePad16:
292 *glyph = 2;
293 break;
294 case BitmapFormatScanlinePad32:
295 *glyph = 4;
296 break;
297 default:
298 return BadFontFormat;
299 }
300 }
301 if (fmask & BitmapFormatMaskImageRectangle) {
302 *image = format & BitmapFormatImageRectMask;
303
304 if (*image != BitmapFormatImageRectMin &&
305 *image != BitmapFormatImageRectMaxWidth &&
306 *image != BitmapFormatImageRectMax)
307 return BadFontFormat;
308 }
309 return Successful;
310 }
311
312 static int
packGlyphs(ClientPtr client,FontPtr pfont,int format,Mask flags,unsigned long num_ranges,fsRange * range,int * tsize,unsigned long * num_glyphs,fsOffset32 ** offsets,pointer * data,int * freeData)313 packGlyphs (
314 ClientPtr client,
315 FontPtr pfont,
316 int format,
317 Mask flags,
318 unsigned long num_ranges,
319 fsRange *range,
320 int *tsize,
321 unsigned long *num_glyphs,
322 fsOffset32 **offsets,
323 pointer *data,
324 int *freeData)
325 {
326 int i;
327 fsOffset32 *lengths, *l;
328 unsigned long size = 0;
329 pointer gdata;
330 unsigned char *gd;
331 int bitorder, byteorder, scanlinepad, scanlineunit, mappad;
332 int height = 0, dstbpr = 0, charsize = 0;
333 int dst_off = 0, src_off;
334 Bool contiguous, reformat;
335 int nchars;
336 int src_glyph_pad = pfont->glyph;
337 int src_bit_order = pfont->bit;
338 int src_byte_order = pfont->byte;
339 int err;
340 int max_ascent = 0, max_descent = 0;
341 int min_left = 0, max_right;
342 int srcbpr;
343 int lshift = 0, rshift = 0, dst_left_bytes = 0, src_left_bytes = 0;
344 unsigned char *srcp;
345 unsigned char *dstp;
346 unsigned char bits1, bits2;
347 int width;
348 int src_extra;
349 int dst_extra;
350 int r, w;
351 CharInfoPtr *bitChars, *bitCharsFree, bitc;
352 CharInfoPtr *inkChars, *inkCharsFree = NULL, inkc;
353 FontInfoPtr pinfo = &pfont->info;
354 xCharInfo *bitm, *inkm;
355
356 err = CheckFSFormat(format, (fsBitmapFormatMask) ~ 0,
357 &bitorder, &byteorder, &scanlineunit, &scanlinepad, &mappad);
358
359 if (err != Successful)
360 return err;
361
362 if (flags & LoadAll)
363 num_ranges = 0;
364
365 err = getCharInfos (pfont, num_ranges, range, FALSE, &nchars, &bitCharsFree);
366
367 if (err != Successful)
368 return err;
369
370 /* compute dstbpr for padded out fonts */
371 reformat = bitorder != src_bit_order || byteorder != src_byte_order;
372
373 /* we need the ink metrics when shrink-wrapping a TE font (sigh),
374 * but only for protocol version > 1 */
375 if (mappad != BitmapFormatImageRectMax &&
376 pinfo->inkMetrics &&
377 client->major_version > 1)
378 {
379 err = getCharInfos (pfont, num_ranges, range, TRUE, &nchars, &inkCharsFree);
380 if (err != Successful)
381 {
382 fsfree (bitCharsFree);
383 return err;
384 }
385 reformat = TRUE;
386 }
387
388 /* get space for glyph offsets */
389 lengths = (fsOffset32 *) fsalloc(SIZEOF(fsOffset32) * nchars);
390 if (!lengths) {
391 fsfree (bitCharsFree);
392 fsfree (inkCharsFree);
393 return AllocError;
394 }
395
396 switch (mappad)
397 {
398 case BitmapFormatImageRectMax:
399 max_ascent = FONT_MAX_ASCENT(pinfo);
400 max_descent = FONT_MAX_DESCENT(pinfo);
401 height = max_ascent + max_descent;
402 /* do font ascent and font descent match bitmap bounds ? */
403 if (height != pinfo->minbounds.ascent + pinfo->minbounds.descent)
404 reformat = TRUE;
405 /* fall through */
406 case BitmapFormatImageRectMaxWidth:
407 min_left = FONT_MIN_LEFT(pinfo);
408 max_right = FONT_MAX_RIGHT(pinfo);
409 if (min_left != pinfo->maxbounds.leftSideBearing)
410 reformat = TRUE;
411 if (max_right != pinfo->maxbounds.rightSideBearing)
412 reformat = TRUE;
413 dstbpr = GLWIDTHBYTESPADDED(max_right - min_left, scanlinepad);
414 break;
415 case BitmapFormatImageRectMin:
416 break;
417 }
418 if (mappad == BitmapFormatImageRectMax)
419 charsize = dstbpr * height;
420 size = 0;
421 gdata = NULL;
422 contiguous = TRUE;
423 l = lengths;
424 inkChars = inkCharsFree;
425 bitChars = bitCharsFree;
426 for (i = 0; i < nchars; i++)
427 {
428 inkc = bitc = *bitChars++;
429 /* when ink metrics != bitmap metrics, use ink metrics */
430 if (inkChars)
431 inkc = *inkChars++;
432 l->position = size;
433 /*
434 * Do not repad characters with no bits except for those
435 * with non-zero width.
436 */
437 if (bitc && (bitc->bits || bitc->metrics.characterWidth)) {
438 if (!gdata)
439 gdata = (pointer) bitc->bits;
440 if ((char *) gdata + size != bitc->bits)
441 contiguous = FALSE;
442 if (mappad == BitmapFormatImageRectMin)
443 dstbpr = GLYPH_SIZE(inkc, scanlinepad);
444 if (dstbpr != GLYPH_SIZE(bitc, src_glyph_pad)) reformat = TRUE;
445 if (mappad != BitmapFormatImageRectMax)
446 {
447 height = inkc->metrics.ascent + inkc->metrics.descent;
448 charsize = height * dstbpr;
449 }
450 l->length = charsize;
451 size += charsize;
452 }
453 else
454 l->length = 0;
455 l++;
456 }
457 if (contiguous && !reformat)
458 {
459 *num_glyphs = nchars;
460 *freeData = FALSE;
461 *data = gdata;
462 *tsize = size;
463 *offsets = lengths;
464 fsfree (bitCharsFree);
465 fsfree (inkCharsFree);
466 return Successful;
467 }
468 if (size)
469 {
470 gdata = (pointer) fsalloc(size);
471 if (!gdata) {
472 fsfree (bitCharsFree);
473 fsfree (inkCharsFree);
474 fsfree (lengths);
475 return AllocError;
476 }
477 bzero ((char *) gdata, size);
478 }
479 else
480 gdata = NULL;
481
482 *freeData = TRUE;
483 l = lengths;
484 gd = gdata;
485
486 /* finally do the work */
487 bitChars = bitCharsFree;
488 inkChars = inkCharsFree;
489 for (i = 0; i < nchars; i++, l++)
490 {
491 inkc = bitc = *bitChars++;
492 if (inkChars)
493 inkc = *inkChars++;
494
495 /* ignore missing chars */
496 if (l->length == 0)
497 continue;
498
499 bitm = &bitc->metrics;
500 inkm = &inkc->metrics;
501
502 /* start address for the destination of bits for this char */
503
504 dstp = gd;
505
506 if (mappad == BitmapFormatImageRectMax)
507 height = max_ascent + max_descent;
508 else
509 height = inkm->ascent + inkm->descent;
510
511 /* adjust destination and calculate shift offsets */
512 switch (mappad) {
513 case BitmapFormatImageRectMax:
514 /* leave the first padded rows blank */
515 if (max_ascent > inkm->ascent)
516 {
517 height -= (max_ascent - inkm->ascent);
518 dstp += dstbpr * (max_ascent - inkm->ascent);
519 }
520 if (max_descent > inkm->descent)
521 {
522 height -= (max_descent - inkm->descent);
523 }
524 /* fall thru */
525 case BitmapFormatImageRectMaxWidth:
526 dst_off = inkm->leftSideBearing - min_left;
527 if (dst_off < 0) dst_off = 0;
528 break;
529 case BitmapFormatImageRectMin:
530 dst_off = 0;
531 dstbpr = GLYPH_SIZE(inkc, scanlinepad);
532 break;
533 }
534
535 srcbpr = GLYPH_SIZE (bitc, src_glyph_pad);
536 srcp = (unsigned char *) bitc->bits;
537
538 /* adjust source */
539 src_off = 0;
540 if (inkm != bitm)
541 {
542 srcp += (bitm->ascent - inkm->ascent) * srcbpr;
543 src_off = inkm->leftSideBearing - bitm->leftSideBearing;
544 }
545
546 dst_left_bytes = dst_off >> 3;
547 dst_off &= 7;
548 src_left_bytes = src_off >> 3;
549 src_off &= 7;
550
551 /* minimum of source/dest bytes per row */
552 width = srcbpr - src_left_bytes;
553 if (width > dstbpr - dst_left_bytes)
554 width = dstbpr - dst_left_bytes;
555 /* extra bytes in source and dest for padding */
556 src_extra = srcbpr - width - src_left_bytes;
557 dst_extra = dstbpr - width - dst_left_bytes;
558
559 #define MSBBitLeft(b,c) ((b) << (c))
560 #define MSBBitRight(b,c) ((b) >> (c))
561 #define LSBBitLeft(b,c) ((b) >> (c))
562 #define LSBBitRight(b,c) ((b) << (c))
563
564 if (dst_off == src_off)
565 {
566 if (srcbpr == dstbpr && src_left_bytes == dst_left_bytes)
567 {
568 r = height * srcbpr;
569 memmove( dstp, srcp, r);
570 dstp += r;
571 }
572 else
573 {
574 for (r = height; r; r--)
575 {
576 dstp += dst_left_bytes;
577 srcp += src_left_bytes;
578 for (w = width; w; w--)
579 *dstp++ = *srcp++;
580 dstp += dst_extra;
581 srcp += src_extra;
582 }
583 }
584 }
585 else
586 {
587 if (dst_off > src_off)
588 {
589 rshift = dst_off - src_off;
590 lshift = 8 - rshift;
591 }
592 else
593 {
594 lshift = src_off - dst_off;
595 rshift = 8 - lshift;
596 /* run the loop one fewer time if necessary */
597 if (src_extra <= dst_extra)
598 {
599 dst_extra++;
600 width--;
601 }
602 else
603 src_extra--;
604 }
605
606 for (r = inkm->ascent + inkm->descent; r; r--)
607 {
608 dstp += dst_left_bytes;
609 srcp += src_left_bytes;
610 bits2 = 0;
611 /* fetch first part of source when necessary */
612 if (dst_off < src_off)
613 bits2 = *srcp++;
614 /*
615 * XXX I bet this does not work when
616 * src_bit_order != src_byte_order && scanlineunit > 1
617 */
618 for (w = width; w; w--)
619 {
620 bits1 = *srcp++;
621 if (src_bit_order == MSBFirst)
622 {
623 *dstp++ = MSBBitRight(bits1, rshift) |
624 MSBBitLeft (bits2, lshift);
625 }
626 else
627 {
628 *dstp++ = LSBBitRight(bits1, rshift) |
629 LSBBitLeft (bits2, lshift);
630 }
631 bits2 = bits1;
632 }
633 /* get the last few bits if we have a place to store them */
634 if (dst_extra > 0)
635 {
636 if (src_bit_order == MSBFirst)
637 *dstp = MSBBitLeft (bits2, lshift);
638 else
639 *dstp = LSBBitLeft (bits2, lshift);
640 }
641 dstp += dst_extra;
642 srcp += src_extra;
643 }
644 }
645 /* skip the amount we just filled in */
646 gd += l->length;
647 }
648
649
650 /* now do the bit, byte, word swapping */
651 if (bitorder != src_bit_order)
652 BitOrderInvert(gdata, size);
653 if (byteorder != src_byte_order)
654 {
655 if (scanlineunit == 2)
656 TwoByteSwap(gdata, size);
657 else if (scanlineunit == 4)
658 FourByteSwap(gdata, size);
659 }
660 fsfree (bitCharsFree);
661 fsfree (inkCharsFree);
662 *num_glyphs = nchars;
663 *data = gdata;
664 *tsize = size;
665 *offsets = lengths;
666
667 return Successful;
668 }
669
670 /* ARGSUSED */
671 int
GetBitmaps(ClientPtr client,FontPtr pfont,fsBitmapFormat format,Mask flags,unsigned long num_ranges,fsRange * range,int * size,unsigned long * num_glyphs,fsOffset32 ** offsets,pointer * data,int * freeData)672 GetBitmaps(
673 ClientPtr client,
674 FontPtr pfont,
675 fsBitmapFormat format,
676 Mask flags,
677 unsigned long num_ranges,
678 fsRange *range,
679 int *size,
680 unsigned long *num_glyphs,
681 fsOffset32 **offsets,
682 pointer *data,
683 int *freeData)
684 {
685 int err;
686
687 assert(pfont);
688
689 *size = 0;
690 *data = (pointer) 0;
691
692 err = LoadGlyphRanges(client, pfont, TRUE, num_ranges * 2, 0,
693 (fsChar2b *)range);
694
695 if (err != Successful)
696 return err;
697
698 return packGlyphs (client, pfont, format, flags,
699 num_ranges, range, size, num_glyphs,
700 offsets, data, freeData);
701 }
702