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