fsconvert.c revision a96d7823
1/* 2 * Copyright 1990 Network Computing Devices 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and 5 * its documentation for any purpose is hereby granted without fee, provided 6 * that the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of Network Computing Devices not be used 9 * in advertising or publicity pertaining to distribution of the software 10 * without specific, written prior permission. Network Computing Devices 11 * makes no representations about the suitability of this software for any 12 * purpose. It is provided "as is" without express or implied warranty. 13 * 14 * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 16 * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL, 17 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 18 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 19 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE 20 * OR PERFORMANCE OF THIS SOFTWARE. 21 * 22 * Author: Dave Lemke, Network Computing Devices, Inc 23 */ 24/* 25 * FS data conversion 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include <config.h> 30#endif 31#include "libxfontint.h" 32#include <X11/X.h> 33#include <X11/Xtrans/Xtrans.h> 34#include <X11/Xpoll.h> 35#include <X11/fonts/FS.h> 36#include <X11/fonts/FSproto.h> 37#include <X11/fonts/fontmisc.h> 38#include <X11/fonts/fontstruct.h> 39#include "fservestr.h" 40#include <X11/fonts/fontutil.h> 41#include "fslibos.h" 42 43extern char _fs_glyph_undefined; 44extern char _fs_glyph_requested; 45 46/* 47 * converts data from font server form to X server form 48 */ 49 50void 51_fs_convert_char_info(fsXCharInfo *src, xCharInfo *dst) 52{ 53 dst->ascent = src->ascent; 54 dst->descent = src->descent; 55 dst->leftSideBearing = src->left; 56 dst->rightSideBearing = src->right; 57 dst->characterWidth = src->width; 58 dst->attributes = src->attributes; 59} 60 61void 62_fs_init_fontinfo(FSFpePtr conn, FontInfoPtr pfi) 63{ 64 if (conn->fsMajorVersion == 1) { 65 unsigned short n; 66 n = pfi->firstCol; 67 pfi->firstCol = pfi->firstRow; 68 pfi->firstRow = n; 69 n = pfi->lastCol; 70 pfi->lastCol = pfi->lastRow; 71 pfi->lastRow = n; 72 pfi->defaultCh = ((pfi->defaultCh >> 8) & 0xff) 73 + ((pfi->defaultCh & 0xff) << 8); 74 } 75 76 if (FontCouldBeTerminal (pfi)) 77 { 78 pfi->terminalFont = TRUE; 79 pfi->minbounds.ascent = pfi->fontAscent; 80 pfi->minbounds.descent = pfi->fontDescent; 81 pfi->minbounds.leftSideBearing = 0; 82 pfi->minbounds.rightSideBearing = pfi->minbounds.characterWidth; 83 pfi->maxbounds = pfi->minbounds; 84 } 85 86 FontComputeInfoAccelerators (pfi); 87} 88 89int 90_fs_convert_props(fsPropInfo *pi, fsPropOffset *po, pointer pd, 91 FontInfoPtr pfi) 92{ 93 FontPropPtr dprop; 94 int i, 95 nprops; 96 char *is_str; 97 fsPropOffset local_off; 98 char *off_adr; 99 char *pdc = pd; 100 101/* stolen from server/include/resource.h */ 102#define BAD_RESOURCE 0xe0000000 103 104 nprops = pfi->nprops = pi->num_offsets; 105 106 if (nprops < 0 107 || nprops > SIZE_MAX/(sizeof(FontPropRec) + sizeof(char))) 108 return -1; 109 110 dprop = malloc(sizeof(FontPropRec) * nprops + sizeof (char) * nprops); 111 if (!dprop) 112 return -1; 113 114 is_str = (char *) (dprop + nprops); 115 pfi->props = dprop; 116 pfi->isStringProp = is_str; 117 118 off_adr = (char *)po; 119 for (i = 0; i < nprops; i++, dprop++, is_str++) 120 { 121 memcpy(&local_off, off_adr, SIZEOF(fsPropOffset)); 122 if ((local_off.name.position >= pi->data_len) || 123 (local_off.name.length > 124 (pi->data_len - local_off.name.position))) 125 goto bail; 126 dprop->name = MakeAtom(&pdc[local_off.name.position], 127 local_off.name.length, 1); 128 if (local_off.type != PropTypeString) { 129 *is_str = FALSE; 130 dprop->value = local_off.value.position; 131 } else { 132 *is_str = TRUE; 133 if ((local_off.value.position >= pi->data_len) || 134 (local_off.value.length > 135 (pi->data_len - local_off.value.position))) 136 goto bail; 137 dprop->value = (INT32) MakeAtom(&pdc[local_off.value.position], 138 local_off.value.length, 1); 139 if (dprop->value == BAD_RESOURCE) 140 { 141 bail: 142 free (pfi->props); 143 pfi->nprops = 0; 144 pfi->props = 0; 145 pfi->isStringProp = 0; 146 return -1; 147 } 148 } 149 off_adr += SIZEOF(fsPropOffset); 150 } 151 152 return nprops; 153} 154 155void 156_fs_free_props (FontInfoPtr pfi) 157{ 158 if (pfi->props) 159 { 160 free (pfi->props); 161 pfi->nprops = 0; 162 pfi->props = 0; 163 } 164} 165 166int 167_fs_convert_lfwi_reply(FSFpePtr conn, FontInfoPtr pfi, 168 fsListFontsWithXInfoReply *fsrep, 169 fsPropInfo *pi, fsPropOffset *po, pointer pd) 170{ 171 fsUnpack_XFontInfoHeader(fsrep, pfi); 172 _fs_init_fontinfo(conn, pfi); 173 174 if (_fs_convert_props(pi, po, pd, pfi) == -1) 175 return AllocError; 176 177 return Successful; 178} 179 180 181#define ENCODING_UNDEFINED(enc) \ 182 ((enc)->bits == &_fs_glyph_undefined ? \ 183 TRUE : \ 184 (access_done = access_done && (enc)->bits != &_fs_glyph_requested, \ 185 FALSE)) 186 187#define GLYPH_UNDEFINED(loc) ENCODING_UNDEFINED(encoding + (loc)) 188 189/* 190 * figures out what glyphs to request 191 * 192 * Includes logic to attempt to reduce number of round trips to the font 193 * server: when a glyph is requested, fs_build_range() requests a 194 * 16-glyph range of glyphs that contains the requested glyph. This is 195 * predicated on the belief that using a glyph increases the chances 196 * that nearby glyphs will be used: a good assumption for phonetic 197 * alphabets, but a questionable one for ideographic/pictographic ones. 198 */ 199/* ARGSUSED */ 200int 201fs_build_range(FontPtr pfont, Bool range_flag, unsigned int count, 202 int item_size, unsigned char *data, int *nranges, 203 fsRange **ranges) 204{ 205 FSFontDataPtr fsd = (FSFontDataPtr) (pfont->fpePrivate); 206 FSFontPtr fsfont = (FSFontPtr) (pfont->fontPrivate); 207 register CharInfoPtr encoding = fsfont->encoding; 208 FontInfoPtr pfi = &(pfont->info); 209 fsRange range; 210 int access_done = TRUE; 211 int err; 212 register unsigned long firstrow, lastrow, firstcol, lastcol; 213 register unsigned long row; 214 register unsigned long col; 215 register unsigned long loc; 216 217 if (!fsd->glyphs_to_get) 218 return AccessDone; 219 220 firstrow = pfi->firstRow; 221 lastrow = pfi->lastRow; 222 firstcol = pfi->firstCol; 223 lastcol = pfi->lastCol; 224 225 /* Make sure we have default char */ 226 if (fsfont->pDefault && ENCODING_UNDEFINED(fsfont->pDefault)) 227 { 228 loc = fsfont->pDefault - encoding; 229 row = loc / (lastcol - firstcol + 1) + firstrow; 230 col = loc % (lastcol - firstcol + 1) + firstcol; 231 232 range.min_char_low = range.max_char_low = col; 233 range.min_char_high = range.max_char_high = row; 234 235 if ((err = add_range(&range, nranges, ranges, FALSE)) != 236 Successful) return err; 237 encoding[loc].bits = &_fs_glyph_requested; 238 access_done = FALSE; 239 } 240 241 if (!range_flag && item_size == 1) 242 { 243 if (firstrow != 0) return AccessDone; 244 while (count--) 245 { 246 col = *data++; 247 if (col >= firstcol && col <= lastcol && 248 GLYPH_UNDEFINED(col - firstcol)) 249 { 250 int col1, col2; 251 col1 = col & 0xf0; 252 col2 = col1 + 15; 253 if (col1 < firstcol) col1 = firstcol; 254 if (col2 > lastcol) col2 = lastcol; 255 /* Collect a 16-glyph neighborhood containing the requested 256 glyph... should in most cases reduce the number of round 257 trips to the font server. */ 258 for (col = col1; col <= col2; col++) 259 { 260 if (!GLYPH_UNDEFINED(col - firstcol)) continue; 261 range.min_char_low = range.max_char_low = col; 262 range.min_char_high = range.max_char_high = 0; 263 if ((err = add_range(&range, nranges, ranges, FALSE)) != 264 Successful) return err; 265 encoding[col - firstcol].bits = &_fs_glyph_requested; 266 access_done = FALSE; 267 } 268 } 269 } 270 } 271 else 272 { 273 fsRange fullrange[1]; 274 275 if (range_flag && count == 0) 276 { 277 count = 2; 278 data = (unsigned char *)fullrange; 279 fullrange[0].min_char_high = firstrow; 280 fullrange[0].min_char_low = firstcol; 281 fullrange[0].max_char_high = lastrow; 282 fullrange[0].max_char_low = lastcol; 283 } 284 285 while (count--) 286 { 287 int row1, col1, row2, col2; 288 row1 = row2 = *data++; 289 col1 = col2 = *data++; 290 if (range_flag) 291 { 292 if (count) 293 { 294 row2 = *data++; 295 col2 = *data++; 296 count--; 297 } 298 else 299 { 300 row2 = lastrow; 301 col2 = lastcol; 302 } 303 if (row1 < firstrow) row1 = firstrow; 304 if (row2 > lastrow) row2 = lastrow; 305 if (col1 < firstcol) col1 = firstcol; 306 if (col2 > lastcol) col2 = lastcol; 307 } 308 else 309 { 310 if (row1 < firstrow || row1 > lastrow || 311 col1 < firstcol || col1 > lastcol) 312 continue; 313 } 314 for (row = row1; row <= row2; row++) 315 { 316 expand_glyph_range: ; 317 loc = (row - firstrow) * (lastcol + 1 - firstcol) + 318 (col1 - firstcol); 319 for (col = col1; col <= col2; col++, loc++) 320 { 321 if (GLYPH_UNDEFINED(loc)) 322 { 323 if (row1 == row2 && 324 (((col1 & 0xf) && col1 > firstcol) || 325 (col2 & 0xf) != 0xf) && (col2 < lastcol)) 326 { 327 /* If we're loading from a single row, expand 328 range of glyphs loaded to a multiple of 329 a 16-glyph range -- attempt to reduce number 330 of round trips to the font server. */ 331 col1 &= 0xf0; 332 col2 = (col2 & 0xf0) + 15; 333 if (col1 < firstcol) col1 = firstcol; 334 if (col2 > lastcol) col2 = lastcol; 335 goto expand_glyph_range; 336 } 337 range.min_char_low = range.max_char_low = col; 338 range.min_char_high = range.max_char_high = row; 339 if ((err = add_range(&range, nranges, ranges, FALSE)) != 340 Successful) return err; 341 encoding[loc].bits = &_fs_glyph_requested; 342 access_done = FALSE; 343 } 344 } 345 } 346 } 347 } 348 349 return access_done ? 350 AccessDone : 351 Successful; 352} 353 354#undef GLYPH_UNDEFINED 355#undef ENCODING_UNDEFINED 356 357 358/* _fs_clean_aborted_loadglyphs(): Undoes the changes to the encoding array 359 performed by fs_build_range(); for use if the associated LoadGlyphs 360 requests needs to be cancelled. */ 361 362void 363_fs_clean_aborted_loadglyphs(FontPtr pfont, int num_expected_ranges, 364 fsRange *expected_ranges) 365{ 366 register FSFontPtr fsfont; 367 register int i; 368 369 fsfont = (FSFontPtr) pfont->fontPrivate; 370 if (fsfont->encoding) 371 { 372 fsRange full_range[1]; 373 if (!num_expected_ranges) 374 { 375 full_range[0].min_char_low = pfont->info.firstCol; 376 full_range[0].min_char_high = pfont->info.firstRow; 377 full_range[0].max_char_low = pfont->info.lastCol; 378 full_range[0].max_char_high = pfont->info.lastRow; 379 num_expected_ranges = 1; 380 expected_ranges = full_range; 381 } 382 383 for (i = 0; i < num_expected_ranges; i++) 384 { 385 int row, col; 386 for (row = expected_ranges[i].min_char_high; 387 row <= expected_ranges[i].max_char_high; 388 row++) 389 { 390 register CharInfoPtr encoding = fsfont->encoding + 391 ((row - pfont->info.firstRow) * 392 (pfont->info.lastCol - 393 pfont->info.firstCol + 1) + 394 expected_ranges[i].min_char_low - 395 pfont->info.firstCol); 396 for (col = expected_ranges[i].min_char_low; 397 col <= expected_ranges[i].max_char_low; 398 encoding++, col++) 399 { 400 if (encoding->bits == &_fs_glyph_requested) 401 encoding->bits = &_fs_glyph_undefined; 402 } 403 } 404 } 405 } 406} 407 408static int 409_fs_get_glyphs(FontPtr pFont, unsigned long count, unsigned char *chars, 410 FontEncoding charEncoding, 411 unsigned long *glyphCount, /* RETURN */ 412 CharInfoPtr *glyphs) /* RETURN */ 413{ 414 FSFontPtr fsdata; 415 unsigned int firstCol; 416 register unsigned int numCols; 417 unsigned int firstRow; 418 unsigned int numRows; 419 CharInfoPtr *glyphsBase; 420 register unsigned int c; 421 register CharInfoPtr pci; 422 unsigned int r; 423 CharInfoPtr encoding; 424 CharInfoPtr pDefault; 425 FSFontDataPtr fsd = (FSFontDataPtr) pFont->fpePrivate; 426 int err = Successful; 427 428 fsdata = (FSFontPtr) pFont->fontPrivate; 429 encoding = fsdata->encoding; 430 pDefault = fsdata->pDefault; 431 firstCol = pFont->info.firstCol; 432 numCols = pFont->info.lastCol - firstCol + 1; 433 glyphsBase = glyphs; 434 435 /* In this age of glyph caching, any glyphs gotten through this 436 procedure should already be loaded. If they are not, we are 437 dealing with someone (perhaps a ddx driver optimizing a font) 438 that doesn't understand the finer points of glyph caching. The 439 CHECK_ENCODING macro checks for this condition... if found, it 440 calls fs_load_all_glyphs(), which corrects it. Since the caller 441 of this code will not know how to handle a return value of 442 Suspended, the fs_load_all_glyphs() procedure will block and 443 freeze the server until the load operation is done. Moral: the 444 glyphCachingMode flag really must indicate the capabilities of 445 the ddx drivers. */ 446 447#define CHECK_ENCODING(cnum) \ 448 ( pci = encoding + (cnum), \ 449 fsd->glyphs_to_get ? \ 450 ( pci->bits == &_fs_glyph_undefined || pci->bits == &_fs_glyph_requested ? \ 451 ((err = fs_load_all_glyphs(pFont)), pci) : \ 452 pci ) : \ 453 pci ) 454 455 switch (charEncoding) { 456 457 case Linear8Bit: 458 case TwoD8Bit: 459 if (pFont->info.firstRow > 0) 460 break; 461 if (pFont->info.allExist && pDefault) { 462 while (err == Successful && count--) { 463 c = (*chars++) - firstCol; 464 if (c < numCols) 465 *glyphs++ = CHECK_ENCODING(c); 466 else 467 *glyphs++ = pDefault; 468 } 469 } else { 470 while (err == Successful && count--) { 471 c = (*chars++) - firstCol; 472 if (c < numCols && CHECK_ENCODING(c)->bits) 473 *glyphs++ = pci; 474 else if (pDefault) 475 *glyphs++ = pDefault; 476 } 477 } 478 break; 479 case Linear16Bit: 480 if (pFont->info.allExist && pDefault) { 481 while (err == Successful && count--) { 482 c = *chars++ << 8; 483 c = (c | *chars++) - firstCol; 484 if (c < numCols) 485 *glyphs++ = CHECK_ENCODING(c); 486 else 487 *glyphs++ = pDefault; 488 } 489 } else { 490 while (err == Successful && count--) { 491 c = *chars++ << 8; 492 c = (c | *chars++) - firstCol; 493 if (c < numCols && CHECK_ENCODING(c)->bits) 494 *glyphs++ = pci; 495 else if (pDefault) 496 *glyphs++ = pDefault; 497 } 498 } 499 break; 500 501 case TwoD16Bit: 502 firstRow = pFont->info.firstRow; 503 numRows = pFont->info.lastRow - firstRow + 1; 504 while (err == Successful && count--) { 505 r = (*chars++) - firstRow; 506 c = (*chars++) - firstCol; 507 if (r < numRows && c < numCols && 508 CHECK_ENCODING(r * numCols + c)->bits) 509 *glyphs++ = pci; 510 else if (pDefault) 511 *glyphs++ = pDefault; 512 } 513 break; 514 } 515 *glyphCount = glyphs - glyphsBase; 516 return err; 517} 518 519 520static int 521_fs_get_metrics(FontPtr pFont, unsigned long count, unsigned char *chars, 522 FontEncoding charEncoding, 523 unsigned long *glyphCount, /* RETURN */ 524 xCharInfo **glyphs) /* RETURN */ 525{ 526 FSFontPtr fsdata; 527 unsigned int firstCol; 528 register unsigned int numCols; 529 unsigned int firstRow; 530 unsigned int numRows; 531 xCharInfo **glyphsBase; 532 register unsigned int c; 533 unsigned int r; 534 CharInfoPtr encoding; 535 CharInfoPtr pDefault; 536 537 fsdata = (FSFontPtr) pFont->fontPrivate; 538 encoding = fsdata->inkMetrics; 539 pDefault = fsdata->pDefault; 540 /* convert default bitmap metric to default ink metric */ 541 if (pDefault) 542 pDefault = encoding + (pDefault - fsdata->encoding); 543 firstCol = pFont->info.firstCol; 544 numCols = pFont->info.lastCol - firstCol + 1; 545 glyphsBase = glyphs; 546 547 548 /* XXX - this should be much smarter */ 549 /* make sure the glyphs are there */ 550 switch (charEncoding) { 551 552 case Linear8Bit: 553 case TwoD8Bit: 554 if (pFont->info.firstRow > 0) 555 break; 556 if (pFont->info.allExist && pDefault) { 557 while (count--) { 558 c = (*chars++) - firstCol; 559 if (c < numCols) 560 *glyphs++ = (xCharInfo *)&encoding[c]; 561 else 562 *glyphs++ = (xCharInfo *)pDefault; 563 } 564 } else { 565 while (count--) { 566 c = (*chars++) - firstCol; 567 if (c < numCols) 568 *glyphs++ = (xCharInfo *)(encoding + c); 569 else if (pDefault) 570 *glyphs++ = (xCharInfo *)pDefault; 571 } 572 } 573 break; 574 case Linear16Bit: 575 if (pFont->info.allExist && pDefault) { 576 while (count--) { 577 c = *chars++ << 8; 578 c = (c | *chars++) - firstCol; 579 if (c < numCols) 580 *glyphs++ = (xCharInfo *)(encoding + c); 581 else 582 *glyphs++ = (xCharInfo *)pDefault; 583 } 584 } else { 585 while (count--) { 586 c = *chars++ << 8; 587 c = (c | *chars++) - firstCol; 588 if (c < numCols) 589 *glyphs++ = (xCharInfo *)(encoding + c); 590 else if (pDefault) 591 *glyphs++ = (xCharInfo *)pDefault; 592 } 593 } 594 break; 595 596 case TwoD16Bit: 597 firstRow = pFont->info.firstRow; 598 numRows = pFont->info.lastRow - firstRow + 1; 599 while (count--) { 600 r = (*chars++) - firstRow; 601 c = (*chars++) - firstCol; 602 if (r < numRows && c < numCols) 603 *glyphs++ = (xCharInfo *)(encoding + (r * numCols + c)); 604 else if (pDefault) 605 *glyphs++ = (xCharInfo *)pDefault; 606 } 607 break; 608 } 609 *glyphCount = glyphs - glyphsBase; 610 return Successful; 611} 612 613 614static void 615_fs_unload_font(FontPtr pfont) 616{ 617 FSFontPtr fsdata = (FSFontPtr) pfont->fontPrivate; 618 FSFontDataPtr fsd = (FSFontDataPtr) pfont->fpePrivate; 619 CharInfoPtr encoding = fsdata->encoding; 620 FSGlyphPtr glyphs; 621 622 /* 623 * fsdata points at FSFontRec, FSFontDataRec and name 624 */ 625 if (encoding) 626 free(encoding); 627 628 while ((glyphs = fsdata->glyphs)) 629 { 630 fsdata->glyphs = glyphs->next; 631 free (glyphs); 632 } 633 634 /* XXX we may get called after the resource DB has been cleaned out */ 635 if (find_old_font(fsd->fontid)) 636 DeleteFontClientID (fsd->fontid); 637 638 _fs_free_props (&pfont->info); 639 640 free(fsdata); 641 642 DestroyFontRec(pfont); 643} 644 645FontPtr 646fs_create_font (FontPathElementPtr fpe, 647 const char *name, 648 int namelen, 649 fsBitmapFormat format, 650 fsBitmapFormatMask fmask) 651{ 652 FontPtr pfont; 653 FSFontPtr fsfont; 654 FSFontDataPtr fsd; 655 int bit, byte, scan, glyph; 656 657 pfont = CreateFontRec (); 658 if (!pfont) 659 return 0; 660 fsfont = malloc (sizeof (FSFontRec) + sizeof (FSFontDataRec) + namelen + 1); 661 if (!fsfont) 662 { 663 DestroyFontRec (pfont); 664 return 0; 665 } 666 fsd = (FSFontDataPtr) (fsfont + 1); 667 bzero((char *) fsfont, sizeof(FSFontRec)); 668 bzero((char *) fsd, sizeof(FSFontDataRec)); 669 670 pfont->fpe = fpe; 671 pfont->fontPrivate = (pointer) fsfont; 672 pfont->fpePrivate = (pointer) fsd; 673 674 /* These font components will be needed in packGlyphs */ 675 CheckFSFormat(format, BitmapFormatMaskBit | 676 BitmapFormatMaskByte | 677 BitmapFormatMaskScanLineUnit | 678 BitmapFormatMaskScanLinePad, 679 &bit, 680 &byte, 681 &scan, 682 &glyph, 683 NULL); 684 pfont->format = format; 685 pfont->bit = bit; 686 pfont->byte = byte; 687 pfont->scan = scan; 688 pfont->glyph = glyph; 689 690 pfont->info.nprops = 0; 691 pfont->info.props = 0; 692 pfont->info.isStringProp = 0; 693 694 /* set font function pointers */ 695 pfont->get_glyphs = _fs_get_glyphs; 696 pfont->get_metrics = _fs_get_metrics; 697 pfont->unload_font = _fs_unload_font; 698 pfont->unload_glyphs = NULL; 699 700 /* set the FPE private information */ 701 fsd->format = format; 702 fsd->fmask = fmask; 703 fsd->name = (char *) (fsd + 1); 704 memcpy (fsd->name, name, namelen); 705 fsd->name[namelen] = '\0'; 706 fsd->fontid = GetNewFontClientID (); 707 708 /* save the ID */ 709 if (!StoreFontClientFont(pfont, fsd->fontid)) 710 { 711 free (fsfont); 712 DestroyFontRec (pfont); 713 return 0; 714 } 715 716 return pfont; 717} 718 719pointer 720fs_alloc_glyphs (FontPtr pFont, int size) 721{ 722 FSGlyphPtr glyphs; 723 FSFontPtr fsfont = (FSFontPtr) pFont->fontPrivate; 724 725 if (size < (INT_MAX - sizeof (FSGlyphRec))) 726 glyphs = malloc (sizeof (FSGlyphRec) + size); 727 else 728 glyphs = NULL; 729 if (glyphs == NULL) 730 return NULL; 731 glyphs->next = fsfont->glyphs; 732 fsfont->glyphs = glyphs; 733 return (pointer) (glyphs + 1); 734} 735