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