dixfonts.c revision 05b261ec
1/************************************************************************ 2Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 3 4 All Rights Reserved 5 6Permission to use, copy, modify, and distribute this software and its 7documentation for any purpose and without fee is hereby granted, 8provided that the above copyright notice appear in all copies and that 9both that copyright notice and this permission notice appear in 10supporting documentation, and that the name of Digital not be 11used in advertising or publicity pertaining to distribution of the 12software without specific, written prior permission. 13 14DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 16DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20SOFTWARE. 21 22************************************************************************/ 23/* The panoramix components contained the following notice */ 24/* 25Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. 26 27Permission is hereby granted, free of charge, to any person obtaining a copy 28of this software and associated documentation files (the "Software"), to deal 29in the Software without restriction, including without limitation the rights 30to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 31copies of the Software. 32 33The above copyright notice and this permission notice shall be included in 34all copies or substantial portions of the Software. 35 36THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 37IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 38FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 39DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, 40BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, 41WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 42IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 43 44Except as contained in this notice, the name of Digital Equipment Corporation 45shall not be used in advertising or otherwise to promote the sale, use or other 46dealings in this Software without prior written authorization from Digital 47Equipment Corporation. 48 49******************************************************************/ 50 51#define NEED_REPLIES 52#ifdef HAVE_DIX_CONFIG_H 53#include <dix-config.h> 54#endif 55 56#include <X11/X.h> 57#include <X11/Xmd.h> 58#include <X11/Xproto.h> 59#include "scrnintstr.h" 60#include "resource.h" 61#include "dixstruct.h" 62#include "cursorstr.h" 63#include "misc.h" 64#include "opaque.h" 65#include "dixfontstr.h" 66#include "closestr.h" 67#include "dixfont.h" 68 69#ifdef DEBUG 70#include <stdio.h> 71#endif 72 73#ifdef PANORAMIX 74#include "panoramiX.h" 75#endif 76 77#ifdef XF86BIGFONT 78#define _XF86BIGFONT_SERVER_ 79#include <X11/extensions/xf86bigfont.h> 80#endif 81 82#define QUERYCHARINFO(pci, pr) *(pr) = (pci)->metrics 83 84extern pointer fosNaturalParams; 85extern FontPtr defaultFont; 86 87static FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0; 88static int num_fpes = 0; 89_X_EXPORT FPEFunctions *fpe_functions = (FPEFunctions *) 0; 90static int num_fpe_types = 0; 91 92static unsigned char *font_path_string; 93 94static int num_slept_fpes = 0; 95static int size_slept_fpes = 0; 96static FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0; 97static FontPatternCachePtr patternCache; 98 99_X_EXPORT int 100FontToXError(err) 101 int err; 102{ 103 switch (err) { 104 case Successful: 105 return Success; 106 case AllocError: 107 return BadAlloc; 108 case BadFontName: 109 return BadName; 110 case BadFontPath: 111 case BadFontFormat: /* is there something better? */ 112 case BadCharRange: 113 return BadValue; 114 default: 115 return err; 116 } 117} 118 119 120/* 121 * adding RT_FONT prevents conflict with default cursor font 122 */ 123Bool 124SetDefaultFont(char *defaultfontname) 125{ 126 int err; 127 FontPtr pf; 128 XID fid; 129 130 fid = FakeClientID(0); 131 err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync, 132 (unsigned) strlen(defaultfontname), defaultfontname); 133 if (err != Success) 134 return FALSE; 135 pf = (FontPtr) LookupIDByType(fid, RT_FONT); 136 if (pf == (FontPtr) NULL) 137 return FALSE; 138 defaultFont = pf; 139 return TRUE; 140} 141 142/* 143 * note that the font wakeup queue is not refcounted. this is because 144 * an fpe needs to be added when it's inited, and removed when it's finally 145 * freed, in order to handle any data that isn't requested, like FS events. 146 * 147 * since the only thing that should call these routines is the renderer's 148 * init_fpe() and free_fpe(), there shouldn't be any problem in using 149 * freed data. 150 */ 151void 152QueueFontWakeup(FontPathElementPtr fpe) 153{ 154 int i; 155 FontPathElementPtr *new; 156 157 for (i = 0; i < num_slept_fpes; i++) { 158 if (slept_fpes[i] == fpe) { 159 return; 160 } 161 } 162 if (num_slept_fpes == size_slept_fpes) { 163 new = (FontPathElementPtr *) 164 xrealloc(slept_fpes, 165 sizeof(FontPathElementPtr) * (size_slept_fpes + 4)); 166 if (!new) 167 return; 168 slept_fpes = new; 169 size_slept_fpes += 4; 170 } 171 slept_fpes[num_slept_fpes] = fpe; 172 num_slept_fpes++; 173} 174 175void 176RemoveFontWakeup(FontPathElementPtr fpe) 177{ 178 int i, 179 j; 180 181 for (i = 0; i < num_slept_fpes; i++) { 182 if (slept_fpes[i] == fpe) { 183 for (j = i; j < num_slept_fpes; j++) { 184 slept_fpes[j] = slept_fpes[j + 1]; 185 } 186 num_slept_fpes--; 187 return; 188 } 189 } 190} 191 192void 193FontWakeup(pointer data, int count, pointer LastSelectMask) 194{ 195 int i; 196 FontPathElementPtr fpe; 197 198 if (count < 0) 199 return; 200 /* wake up any fpe's that may be waiting for information */ 201 for (i = 0; i < num_slept_fpes; i++) { 202 fpe = slept_fpes[i]; 203 (void) (*fpe_functions[fpe->type].wakeup_fpe) (fpe, LastSelectMask); 204 } 205} 206 207/* XXX -- these two funcs may want to be broken into macros */ 208static void 209UseFPE(FontPathElementPtr fpe) 210{ 211 fpe->refcount++; 212} 213 214static void 215FreeFPE (FontPathElementPtr fpe) 216{ 217 fpe->refcount--; 218 if (fpe->refcount == 0) { 219 (*fpe_functions[fpe->type].free_fpe) (fpe); 220 xfree(fpe->name); 221 xfree(fpe); 222 } 223} 224 225static Bool 226doOpenFont(ClientPtr client, OFclosurePtr c) 227{ 228 FontPtr pfont = NullFont; 229 FontPathElementPtr fpe = NULL; 230 ScreenPtr pScr; 231 int err = Successful; 232 int i; 233 char *alias, 234 *newname; 235 int newlen; 236 int aliascount = 20; 237 /* 238 * Decide at runtime what FontFormat to use. 239 */ 240 Mask FontFormat = 241 242 ((screenInfo.imageByteOrder == LSBFirst) ? 243 BitmapFormatByteOrderLSB : BitmapFormatByteOrderMSB) | 244 245 ((screenInfo.bitmapBitOrder == LSBFirst) ? 246 BitmapFormatBitOrderLSB : BitmapFormatBitOrderMSB) | 247 248 BitmapFormatImageRectMin | 249 250#if GLYPHPADBYTES == 1 251 BitmapFormatScanlinePad8 | 252#endif 253 254#if GLYPHPADBYTES == 2 255 BitmapFormatScanlinePad16 | 256#endif 257 258#if GLYPHPADBYTES == 4 259 BitmapFormatScanlinePad32 | 260#endif 261 262#if GLYPHPADBYTES == 8 263 BitmapFormatScanlinePad64 | 264#endif 265 266 BitmapFormatScanlineUnit8; 267 268 if (client->clientGone) 269 { 270 if (c->current_fpe < c->num_fpes) 271 { 272 fpe = c->fpe_list[c->current_fpe]; 273 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); 274 } 275 err = Successful; 276 goto bail; 277 } 278 while (c->current_fpe < c->num_fpes) { 279 fpe = c->fpe_list[c->current_fpe]; 280 err = (*fpe_functions[fpe->type].open_font) 281 ((pointer) client, fpe, c->flags, 282 c->fontname, c->fnamelen, FontFormat, 283 BitmapFormatMaskByte | 284 BitmapFormatMaskBit | 285 BitmapFormatMaskImageRectangle | 286 BitmapFormatMaskScanLinePad | 287 BitmapFormatMaskScanLineUnit, 288 c->fontid, &pfont, &alias, 289 c->non_cachable_font && c->non_cachable_font->fpe == fpe ? 290 c->non_cachable_font : 291 (FontPtr)0); 292 293 if (err == FontNameAlias && alias) { 294 newlen = strlen(alias); 295 newname = (char *) xrealloc(c->fontname, newlen); 296 if (!newname) { 297 err = AllocError; 298 break; 299 } 300 memmove(newname, alias, newlen); 301 c->fontname = newname; 302 c->fnamelen = newlen; 303 c->current_fpe = 0; 304 if (--aliascount <= 0) 305 break; 306 continue; 307 } 308 if (err == BadFontName) { 309 c->current_fpe++; 310 continue; 311 } 312 if (err == Suspended) { 313 if (!c->slept) { 314 c->slept = TRUE; 315 ClientSleep(client, (ClientSleepProcPtr)doOpenFont, (pointer) c); 316 } 317 return TRUE; 318 } 319 break; 320 } 321 322 if (err != Successful) 323 goto bail; 324 if (!pfont) { 325 err = BadFontName; 326 goto bail; 327 } 328 /* check values for firstCol, lastCol, firstRow, and lastRow */ 329 if (pfont->info.firstCol > pfont->info.lastCol || 330 pfont->info.firstRow > pfont->info.lastRow || 331 pfont->info.lastCol - pfont->info.firstCol > 255) { 332 err = AllocError; 333 goto bail; 334 } 335 if (!pfont->fpe) 336 pfont->fpe = fpe; 337 pfont->refcnt++; 338 if (pfont->refcnt == 1) { 339 UseFPE(pfont->fpe); 340 for (i = 0; i < screenInfo.numScreens; i++) { 341 pScr = screenInfo.screens[i]; 342 if (pScr->RealizeFont) 343 { 344 if (!(*pScr->RealizeFont) (pScr, pfont)) 345 { 346 CloseFont (pfont, (Font) 0); 347 err = AllocError; 348 goto bail; 349 } 350 } 351 } 352 } 353 if (!AddResource(c->fontid, RT_FONT, (pointer) pfont)) { 354 err = AllocError; 355 goto bail; 356 } 357 if (patternCache && pfont != c->non_cachable_font) 358 CacheFontPattern(patternCache, c->origFontName, c->origFontNameLen, 359 pfont); 360bail: 361 if (err != Successful && c->client != serverClient) { 362 SendErrorToClient(c->client, X_OpenFont, 0, 363 c->fontid, FontToXError(err)); 364 } 365 if (c->slept) 366 ClientWakeup(c->client); 367 for (i = 0; i < c->num_fpes; i++) { 368 FreeFPE(c->fpe_list[i]); 369 } 370 xfree(c->fpe_list); 371 xfree(c->fontname); 372 xfree(c); 373 return TRUE; 374} 375 376int 377OpenFont(ClientPtr client, XID fid, Mask flags, unsigned lenfname, char *pfontname) 378{ 379 OFclosurePtr c; 380 int i; 381 FontPtr cached = (FontPtr)0; 382 383#ifdef FONTDEBUG 384 char *f; 385 f = (char *)xalloc(lenfname + 1); 386 memmove(f, pfontname, lenfname); 387 f[lenfname] = '\0'; 388 ErrorF("OpenFont: fontname is \"%s\"\n", f); 389 xfree(f); 390#endif 391 if (!lenfname || lenfname > XLFDMAXFONTNAMELEN) 392 return BadName; 393 if (patternCache) 394 { 395 396 /* 397 ** Check name cache. If we find a cached version of this font that 398 ** is cachable, immediately satisfy the request with it. If we find 399 ** a cached version of this font that is non-cachable, we do not 400 ** satisfy the request with it. Instead, we pass the FontPtr to the 401 ** FPE's open_font code (the fontfile FPE in turn passes the 402 ** information to the rasterizer; the fserve FPE ignores it). 403 ** 404 ** Presumably, the font is marked non-cachable because the FPE has 405 ** put some licensing restrictions on it. If the FPE, using 406 ** whatever logic it relies on, determines that it is willing to 407 ** share this existing font with the client, then it has the option 408 ** to return the FontPtr we passed it as the newly-opened font. 409 ** This allows the FPE to exercise its licensing logic without 410 ** having to create another instance of a font that already exists. 411 */ 412 413 cached = FindCachedFontPattern(patternCache, pfontname, lenfname); 414 if (cached && cached->info.cachable) 415 { 416 if (!AddResource(fid, RT_FONT, (pointer) cached)) 417 return BadAlloc; 418 cached->refcnt++; 419 return Success; 420 } 421 } 422 c = (OFclosurePtr) xalloc(sizeof(OFclosureRec)); 423 if (!c) 424 return BadAlloc; 425 c->fontname = (char *) xalloc(lenfname); 426 c->origFontName = pfontname; 427 c->origFontNameLen = lenfname; 428 if (!c->fontname) { 429 xfree(c); 430 return BadAlloc; 431 } 432 /* 433 * copy the current FPE list, so that if it gets changed by another client 434 * while we're blocking, the request still appears atomic 435 */ 436 c->fpe_list = (FontPathElementPtr *) 437 xalloc(sizeof(FontPathElementPtr) * num_fpes); 438 if (!c->fpe_list) { 439 xfree(c->fontname); 440 xfree(c); 441 return BadAlloc; 442 } 443 memmove(c->fontname, pfontname, lenfname); 444 for (i = 0; i < num_fpes; i++) { 445 c->fpe_list[i] = font_path_elements[i]; 446 UseFPE(c->fpe_list[i]); 447 } 448 c->client = client; 449 c->fontid = fid; 450 c->current_fpe = 0; 451 c->num_fpes = num_fpes; 452 c->fnamelen = lenfname; 453 c->slept = FALSE; 454 c->flags = flags; 455 c->non_cachable_font = cached; 456 457 (void) doOpenFont(client, c); 458 return Success; 459} 460 461/** 462 * Decrement font's ref count, and free storage if ref count equals zero 463 * 464 * \param value must conform to DeleteType 465 */ 466_X_EXPORT int 467CloseFont(pointer value, XID fid) 468{ 469 int nscr; 470 ScreenPtr pscr; 471 FontPathElementPtr fpe; 472 FontPtr pfont = (FontPtr)value; 473 474 if (pfont == NullFont) 475 return (Success); 476 if (--pfont->refcnt == 0) { 477 if (patternCache) 478 RemoveCachedFontPattern (patternCache, pfont); 479 /* 480 * since the last reference is gone, ask each screen to free any 481 * storage it may have allocated locally for it. 482 */ 483 for (nscr = 0; nscr < screenInfo.numScreens; nscr++) { 484 pscr = screenInfo.screens[nscr]; 485 if (pscr->UnrealizeFont) 486 (*pscr->UnrealizeFont) (pscr, pfont); 487 } 488 if (pfont == defaultFont) 489 defaultFont = NULL; 490#ifdef XF86BIGFONT 491 XF86BigfontFreeFontShm(pfont); 492#endif 493 fpe = pfont->fpe; 494 (*fpe_functions[fpe->type].close_font) (fpe, pfont); 495 FreeFPE(fpe); 496 } 497 return (Success); 498} 499 500 501/***====================================================================***/ 502 503/** 504 * Sets up pReply as the correct QueryFontReply for pFont with the first 505 * nProtoCCIStructs char infos. 506 * 507 * \param pReply caller must allocate this storage 508 */ 509void 510QueryFont(FontPtr pFont, xQueryFontReply *pReply, int nProtoCCIStructs) 511{ 512 FontPropPtr pFP; 513 int r, 514 c, 515 i; 516 xFontProp *prFP; 517 xCharInfo *prCI; 518 xCharInfo *charInfos[256]; 519 unsigned char chars[512]; 520 int ninfos; 521 unsigned long ncols; 522 unsigned long count; 523 524 /* pr->length set in dispatch */ 525 pReply->minCharOrByte2 = pFont->info.firstCol; 526 pReply->defaultChar = pFont->info.defaultCh; 527 pReply->maxCharOrByte2 = pFont->info.lastCol; 528 pReply->drawDirection = pFont->info.drawDirection; 529 pReply->allCharsExist = pFont->info.allExist; 530 pReply->minByte1 = pFont->info.firstRow; 531 pReply->maxByte1 = pFont->info.lastRow; 532 pReply->fontAscent = pFont->info.fontAscent; 533 pReply->fontDescent = pFont->info.fontDescent; 534 535 pReply->minBounds = pFont->info.ink_minbounds; 536 pReply->maxBounds = pFont->info.ink_maxbounds; 537 538 pReply->nFontProps = pFont->info.nprops; 539 pReply->nCharInfos = nProtoCCIStructs; 540 541 for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) (&pReply[1]); 542 i < pFont->info.nprops; 543 i++, pFP++, prFP++) { 544 prFP->name = pFP->name; 545 prFP->value = pFP->value; 546 } 547 548 ninfos = 0; 549 ncols = (unsigned long) (pFont->info.lastCol - pFont->info.firstCol + 1); 550 prCI = (xCharInfo *) (prFP); 551 for (r = pFont->info.firstRow; 552 ninfos < nProtoCCIStructs && r <= (int)pFont->info.lastRow; 553 r++) { 554 i = 0; 555 for (c = pFont->info.firstCol; c <= (int)pFont->info.lastCol; c++) { 556 chars[i++] = r; 557 chars[i++] = c; 558 } 559 (*pFont->get_metrics) (pFont, ncols, chars, 560 TwoD16Bit, &count, charInfos); 561 i = 0; 562 for (i = 0; i < (int) count && ninfos < nProtoCCIStructs; i++) { 563 *prCI = *charInfos[i]; 564 prCI++; 565 ninfos++; 566 } 567 } 568 return; 569} 570 571static Bool 572doListFontsAndAliases(ClientPtr client, LFclosurePtr c) 573{ 574 FontPathElementPtr fpe; 575 int err = Successful; 576 FontNamesPtr names = NULL; 577 char *name, *resolved=NULL; 578 int namelen, resolvedlen; 579 int nnames; 580 int stringLens; 581 int i; 582 xListFontsReply reply; 583 char *bufptr; 584 char *bufferStart; 585 int aliascount = 0; 586 587 if (client->clientGone) 588 { 589 if (c->current.current_fpe < c->num_fpes) 590 { 591 fpe = c->fpe_list[c->current.current_fpe]; 592 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); 593 } 594 err = Successful; 595 goto bail; 596 } 597 598 if (!c->current.patlen) 599 goto finish; 600 601 while (c->current.current_fpe < c->num_fpes) { 602 fpe = c->fpe_list[c->current.current_fpe]; 603 err = Successful; 604 605 if (!fpe_functions[fpe->type].start_list_fonts_and_aliases) 606 { 607 /* This FPE doesn't support/require list_fonts_and_aliases */ 608 609 err = (*fpe_functions[fpe->type].list_fonts) 610 ((pointer) c->client, fpe, c->current.pattern, 611 c->current.patlen, c->current.max_names - c->names->nnames, 612 c->names); 613 614 if (err == Suspended) { 615 if (!c->slept) { 616 c->slept = TRUE; 617 ClientSleep(client, 618 (ClientSleepProcPtr)doListFontsAndAliases, 619 (pointer) c); 620 } 621 return TRUE; 622 } 623 624 err = BadFontName; 625 } 626 else 627 { 628 /* Start of list_fonts_and_aliases functionality. Modeled 629 after list_fonts_with_info in that it resolves aliases, 630 except that the information collected from FPEs is just 631 names, not font info. Each list_next_font_or_alias() 632 returns either a name into name/namelen or an alias into 633 name/namelen and its target name into resolved/resolvedlen. 634 The code at this level then resolves the alias by polling 635 the FPEs. */ 636 637 if (!c->current.list_started) { 638 err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases) 639 ((pointer) c->client, fpe, c->current.pattern, 640 c->current.patlen, c->current.max_names - c->names->nnames, 641 &c->current.private); 642 if (err == Suspended) { 643 if (!c->slept) { 644 ClientSleep(client, 645 (ClientSleepProcPtr)doListFontsAndAliases, 646 (pointer) c); 647 c->slept = TRUE; 648 } 649 return TRUE; 650 } 651 if (err == Successful) 652 c->current.list_started = TRUE; 653 } 654 if (err == Successful) { 655 char *tmpname; 656 name = 0; 657 err = (*fpe_functions[fpe->type].list_next_font_or_alias) 658 ((pointer) c->client, fpe, &name, &namelen, &tmpname, 659 &resolvedlen, c->current.private); 660 if (err == Suspended) { 661 if (!c->slept) { 662 ClientSleep(client, 663 (ClientSleepProcPtr)doListFontsAndAliases, 664 (pointer) c); 665 c->slept = TRUE; 666 } 667 return TRUE; 668 } 669 if (err == FontNameAlias) { 670 if (resolved) xfree(resolved); 671 resolved = (char *) xalloc(resolvedlen + 1); 672 if (resolved) 673 memmove(resolved, tmpname, resolvedlen + 1); 674 } 675 } 676 677 if (err == Successful) 678 { 679 if (c->haveSaved) 680 { 681 if (c->savedName) 682 (void)AddFontNamesName(c->names, c->savedName, 683 c->savedNameLen); 684 } 685 else 686 (void)AddFontNamesName(c->names, name, namelen); 687 } 688 689 /* 690 * When we get an alias back, save our state and reset back to 691 * the start of the FPE looking for the specified name. As 692 * soon as a real font is found for the alias, pop back to the 693 * old state 694 */ 695 else if (err == FontNameAlias) { 696 char tmp_pattern[XLFDMAXFONTNAMELEN]; 697 /* 698 * when an alias recurses, we need to give 699 * the last FPE a chance to clean up; so we call 700 * it again, and assume that the error returned 701 * is BadFontName, indicating the alias resolution 702 * is complete. 703 */ 704 memmove(tmp_pattern, resolved, resolvedlen); 705 if (c->haveSaved) 706 { 707 char *tmpname; 708 int tmpnamelen; 709 710 tmpname = 0; 711 (void) (*fpe_functions[fpe->type].list_next_font_or_alias) 712 ((pointer) c->client, fpe, &tmpname, &tmpnamelen, 713 &tmpname, &tmpnamelen, c->current.private); 714 if (--aliascount <= 0) 715 { 716 err = BadFontName; 717 goto ContBadFontName; 718 } 719 } 720 else 721 { 722 c->saved = c->current; 723 c->haveSaved = TRUE; 724 if (c->savedName) 725 xfree(c->savedName); 726 c->savedName = (char *)xalloc(namelen + 1); 727 if (c->savedName) 728 memmove(c->savedName, name, namelen + 1); 729 c->savedNameLen = namelen; 730 aliascount = 20; 731 } 732 memmove(c->current.pattern, tmp_pattern, resolvedlen); 733 c->current.patlen = resolvedlen; 734 c->current.max_names = c->names->nnames + 1; 735 c->current.current_fpe = -1; 736 c->current.private = 0; 737 err = BadFontName; 738 } 739 } 740 /* 741 * At the end of this FPE, step to the next. If we've finished 742 * processing an alias, pop state back. If we've collected enough 743 * font names, quit. 744 */ 745 if (err == BadFontName) { 746 ContBadFontName: ; 747 c->current.list_started = FALSE; 748 c->current.current_fpe++; 749 err = Successful; 750 if (c->haveSaved) 751 { 752 if (c->names->nnames == c->current.max_names || 753 c->current.current_fpe == c->num_fpes) { 754 c->haveSaved = FALSE; 755 c->current = c->saved; 756 /* Give the saved namelist a chance to clean itself up */ 757 continue; 758 } 759 } 760 if (c->names->nnames == c->current.max_names) 761 break; 762 } 763 } 764 765 /* 766 * send the reply 767 */ 768 if (err != Successful) { 769 SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err)); 770 goto bail; 771 } 772 773finish: 774 775 names = c->names; 776 nnames = names->nnames; 777 client = c->client; 778 stringLens = 0; 779 for (i = 0; i < nnames; i++) 780 stringLens += (names->length[i] <= 255) ? names->length[i] : 0; 781 782 reply.type = X_Reply; 783 reply.length = (stringLens + nnames + 3) >> 2; 784 reply.nFonts = nnames; 785 reply.sequenceNumber = client->sequence; 786 787 bufptr = bufferStart = (char *) ALLOCATE_LOCAL(reply.length << 2); 788 789 if (!bufptr && reply.length) { 790 SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc); 791 goto bail; 792 } 793 /* 794 * since WriteToClient long word aligns things, copy to temp buffer and 795 * write all at once 796 */ 797 for (i = 0; i < nnames; i++) { 798 if (names->length[i] > 255) 799 reply.nFonts--; 800 else 801 { 802 *bufptr++ = names->length[i]; 803 memmove( bufptr, names->names[i], names->length[i]); 804 bufptr += names->length[i]; 805 } 806 } 807 nnames = reply.nFonts; 808 reply.length = (stringLens + nnames + 3) >> 2; 809 client->pSwapReplyFunc = ReplySwapVector[X_ListFonts]; 810 WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply); 811 (void) WriteToClient(client, stringLens + nnames, bufferStart); 812 DEALLOCATE_LOCAL(bufferStart); 813 814bail: 815 if (c->slept) 816 ClientWakeup(client); 817 for (i = 0; i < c->num_fpes; i++) 818 FreeFPE(c->fpe_list[i]); 819 xfree(c->fpe_list); 820 if (c->savedName) xfree(c->savedName); 821 FreeFontNames(names); 822 xfree(c); 823 if (resolved) xfree(resolved); 824 return TRUE; 825} 826 827int 828ListFonts(ClientPtr client, unsigned char *pattern, unsigned length, 829 unsigned max_names) 830{ 831 int i; 832 LFclosurePtr c; 833 834 /* 835 * The right error to return here would be BadName, however the 836 * specification does not allow for a Name error on this request. 837 * Perhaps a better solution would be to return a nil list, i.e. 838 * a list containing zero fontnames. 839 */ 840 if (length > XLFDMAXFONTNAMELEN) 841 return BadAlloc; 842 843 if (!(c = (LFclosurePtr) xalloc(sizeof *c))) 844 return BadAlloc; 845 c->fpe_list = (FontPathElementPtr *) 846 xalloc(sizeof(FontPathElementPtr) * num_fpes); 847 if (!c->fpe_list) { 848 xfree(c); 849 return BadAlloc; 850 } 851 c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100); 852 if (!c->names) 853 { 854 xfree(c->fpe_list); 855 xfree(c); 856 return BadAlloc; 857 } 858 memmove( c->current.pattern, pattern, length); 859 for (i = 0; i < num_fpes; i++) { 860 c->fpe_list[i] = font_path_elements[i]; 861 UseFPE(c->fpe_list[i]); 862 } 863 c->client = client; 864 c->num_fpes = num_fpes; 865 c->current.patlen = length; 866 c->current.current_fpe = 0; 867 c->current.max_names = max_names; 868 c->current.list_started = FALSE; 869 c->current.private = 0; 870 c->haveSaved = FALSE; 871 c->slept = FALSE; 872 c->savedName = 0; 873 doListFontsAndAliases(client, c); 874 return Success; 875} 876 877int 878doListFontsWithInfo(ClientPtr client, LFWIclosurePtr c) 879{ 880 FontPathElementPtr fpe; 881 int err = Successful; 882 char *name; 883 int namelen; 884 int numFonts; 885 FontInfoRec fontInfo, 886 *pFontInfo; 887 xListFontsWithInfoReply *reply; 888 int length; 889 xFontProp *pFP; 890 int i; 891 int aliascount = 0; 892 xListFontsWithInfoReply finalReply; 893 894 if (client->clientGone) 895 { 896 if (c->current.current_fpe < c->num_fpes) 897 { 898 fpe = c->fpe_list[c->current.current_fpe]; 899 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); 900 } 901 err = Successful; 902 goto bail; 903 } 904 client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo]; 905 if (!c->current.patlen) 906 goto finish; 907 while (c->current.current_fpe < c->num_fpes) 908 { 909 fpe = c->fpe_list[c->current.current_fpe]; 910 err = Successful; 911 if (!c->current.list_started) 912 { 913 err = (*fpe_functions[fpe->type].start_list_fonts_with_info) 914 (client, fpe, c->current.pattern, c->current.patlen, 915 c->current.max_names, &c->current.private); 916 if (err == Suspended) 917 { 918 if (!c->slept) 919 { 920 ClientSleep(client, (ClientSleepProcPtr)doListFontsWithInfo, c); 921 c->slept = TRUE; 922 } 923 return TRUE; 924 } 925 if (err == Successful) 926 c->current.list_started = TRUE; 927 } 928 if (err == Successful) 929 { 930 name = 0; 931 pFontInfo = &fontInfo; 932 err = (*fpe_functions[fpe->type].list_next_font_with_info) 933 (client, fpe, &name, &namelen, &pFontInfo, 934 &numFonts, c->current.private); 935 if (err == Suspended) 936 { 937 if (!c->slept) 938 { 939 ClientSleep(client, 940 (ClientSleepProcPtr)doListFontsWithInfo, 941 c); 942 c->slept = TRUE; 943 } 944 return TRUE; 945 } 946 } 947 /* 948 * When we get an alias back, save our state and reset back to the 949 * start of the FPE looking for the specified name. As soon as a real 950 * font is found for the alias, pop back to the old state 951 */ 952 if (err == FontNameAlias) 953 { 954 /* 955 * when an alias recurses, we need to give 956 * the last FPE a chance to clean up; so we call 957 * it again, and assume that the error returned 958 * is BadFontName, indicating the alias resolution 959 * is complete. 960 */ 961 if (c->haveSaved) 962 { 963 char *tmpname; 964 int tmpnamelen; 965 FontInfoPtr tmpFontInfo; 966 967 tmpname = 0; 968 tmpFontInfo = &fontInfo; 969 (void) (*fpe_functions[fpe->type].list_next_font_with_info) 970 (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo, 971 &numFonts, c->current.private); 972 if (--aliascount <= 0) 973 { 974 err = BadFontName; 975 goto ContBadFontName; 976 } 977 } 978 else 979 { 980 c->saved = c->current; 981 c->haveSaved = TRUE; 982 c->savedNumFonts = numFonts; 983 if (c->savedName) 984 xfree(c->savedName); 985 c->savedName = (char *)xalloc(namelen + 1); 986 if (c->savedName) 987 memmove(c->savedName, name, namelen + 1); 988 aliascount = 20; 989 } 990 memmove(c->current.pattern, name, namelen); 991 c->current.patlen = namelen; 992 c->current.max_names = 1; 993 c->current.current_fpe = 0; 994 c->current.private = 0; 995 c->current.list_started = FALSE; 996 } 997 /* 998 * At the end of this FPE, step to the next. If we've finished 999 * processing an alias, pop state back. If we've sent enough font 1000 * names, quit. Always wait for BadFontName to let the FPE 1001 * have a chance to clean up. 1002 */ 1003 else if (err == BadFontName) 1004 { 1005 ContBadFontName: ; 1006 c->current.list_started = FALSE; 1007 c->current.current_fpe++; 1008 err = Successful; 1009 if (c->haveSaved) 1010 { 1011 if (c->current.max_names == 0 || 1012 c->current.current_fpe == c->num_fpes) 1013 { 1014 c->haveSaved = FALSE; 1015 c->saved.max_names -= (1 - c->current.max_names); 1016 c->current = c->saved; 1017 } 1018 } 1019 else if (c->current.max_names == 0) 1020 break; 1021 } 1022 else if (err == Successful) 1023 { 1024 length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp); 1025 reply = c->reply; 1026 if (c->length < length) 1027 { 1028 reply = (xListFontsWithInfoReply *) xrealloc(c->reply, length); 1029 if (!reply) 1030 { 1031 err = AllocError; 1032 break; 1033 } 1034 c->reply = reply; 1035 c->length = length; 1036 } 1037 if (c->haveSaved) 1038 { 1039 numFonts = c->savedNumFonts; 1040 name = c->savedName; 1041 namelen = strlen(name); 1042 } 1043 reply->type = X_Reply; 1044 reply->length = (sizeof *reply - sizeof(xGenericReply) + 1045 pFontInfo->nprops * sizeof(xFontProp) + 1046 namelen + 3) >> 2; 1047 reply->sequenceNumber = client->sequence; 1048 reply->nameLength = namelen; 1049 reply->minBounds = pFontInfo->ink_minbounds; 1050 reply->maxBounds = pFontInfo->ink_maxbounds; 1051 reply->minCharOrByte2 = pFontInfo->firstCol; 1052 reply->maxCharOrByte2 = pFontInfo->lastCol; 1053 reply->defaultChar = pFontInfo->defaultCh; 1054 reply->nFontProps = pFontInfo->nprops; 1055 reply->drawDirection = pFontInfo->drawDirection; 1056 reply->minByte1 = pFontInfo->firstRow; 1057 reply->maxByte1 = pFontInfo->lastRow; 1058 reply->allCharsExist = pFontInfo->allExist; 1059 reply->fontAscent = pFontInfo->fontAscent; 1060 reply->fontDescent = pFontInfo->fontDescent; 1061 reply->nReplies = numFonts; 1062 pFP = (xFontProp *) (reply + 1); 1063 for (i = 0; i < pFontInfo->nprops; i++) 1064 { 1065 pFP->name = pFontInfo->props[i].name; 1066 pFP->value = pFontInfo->props[i].value; 1067 pFP++; 1068 } 1069 WriteSwappedDataToClient(client, length, reply); 1070 (void) WriteToClient(client, namelen, name); 1071 if (pFontInfo == &fontInfo) 1072 { 1073 xfree(fontInfo.props); 1074 xfree(fontInfo.isStringProp); 1075 } 1076 --c->current.max_names; 1077 } 1078 } 1079finish: 1080 length = sizeof(xListFontsWithInfoReply); 1081 bzero((char *) &finalReply, sizeof(xListFontsWithInfoReply)); 1082 finalReply.type = X_Reply; 1083 finalReply.sequenceNumber = client->sequence; 1084 finalReply.length = (sizeof(xListFontsWithInfoReply) 1085 - sizeof(xGenericReply)) >> 2; 1086 WriteSwappedDataToClient(client, length, &finalReply); 1087bail: 1088 if (c->slept) 1089 ClientWakeup(client); 1090 for (i = 0; i < c->num_fpes; i++) 1091 FreeFPE(c->fpe_list[i]); 1092 xfree(c->reply); 1093 xfree(c->fpe_list); 1094 if (c->savedName) xfree(c->savedName); 1095 xfree(c); 1096 return TRUE; 1097} 1098 1099int 1100StartListFontsWithInfo(ClientPtr client, int length, unsigned char *pattern, 1101 int max_names) 1102{ 1103 int i; 1104 LFWIclosurePtr c; 1105 1106 /* 1107 * The right error to return here would be BadName, however the 1108 * specification does not allow for a Name error on this request. 1109 * Perhaps a better solution would be to return a nil list, i.e. 1110 * a list containing zero fontnames. 1111 */ 1112 if (length > XLFDMAXFONTNAMELEN) 1113 return BadAlloc; 1114 1115 if (!(c = (LFWIclosurePtr) xalloc(sizeof *c))) 1116 goto badAlloc; 1117 c->fpe_list = (FontPathElementPtr *) 1118 xalloc(sizeof(FontPathElementPtr) * num_fpes); 1119 if (!c->fpe_list) 1120 { 1121 xfree(c); 1122 goto badAlloc; 1123 } 1124 memmove(c->current.pattern, pattern, length); 1125 for (i = 0; i < num_fpes; i++) 1126 { 1127 c->fpe_list[i] = font_path_elements[i]; 1128 UseFPE(c->fpe_list[i]); 1129 } 1130 c->client = client; 1131 c->num_fpes = num_fpes; 1132 c->reply = 0; 1133 c->length = 0; 1134 c->current.patlen = length; 1135 c->current.current_fpe = 0; 1136 c->current.max_names = max_names; 1137 c->current.list_started = FALSE; 1138 c->current.private = 0; 1139 c->savedNumFonts = 0; 1140 c->haveSaved = FALSE; 1141 c->slept = FALSE; 1142 c->savedName = 0; 1143 doListFontsWithInfo(client, c); 1144 return Success; 1145badAlloc: 1146 return BadAlloc; 1147} 1148 1149#define TextEltHeader 2 1150#define FontShiftSize 5 1151static XID clearGC[] = { CT_NONE }; 1152#define clearGCmask (GCClipMask) 1153 1154int 1155doPolyText(ClientPtr client, PTclosurePtr c) 1156{ 1157 FontPtr pFont = c->pGC->font, oldpFont; 1158 Font fid, oldfid; 1159 int err = Success, lgerr; /* err is in X error, not font error, space */ 1160 enum { NEVER_SLEPT, START_SLEEP, SLEEPING } client_state = NEVER_SLEPT; 1161 FontPathElementPtr fpe; 1162 GC *origGC = NULL; 1163 1164 if (client->clientGone) 1165 { 1166 fpe = c->pGC->font->fpe; 1167 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); 1168 1169 if (c->slept) 1170 { 1171 /* Client has died, but we cannot bail out right now. We 1172 need to clean up after the work we did when going to 1173 sleep. Setting the drawable pointer to 0 makes this 1174 happen without any attempts to render or perform other 1175 unnecessary activities. */ 1176 c->pDraw = (DrawablePtr)0; 1177 } 1178 else 1179 { 1180 err = Success; 1181 goto bail; 1182 } 1183 } 1184 1185 /* Make sure our drawable hasn't disappeared while we slept. */ 1186 if (c->slept && 1187 c->pDraw && 1188 c->pDraw != (DrawablePtr)SecurityLookupIDByClass(client, c->did, 1189 RC_DRAWABLE, DixWriteAccess)) 1190 { 1191 /* Our drawable has disappeared. Treat like client died... ask 1192 the FPE code to clean up after client and avoid further 1193 rendering while we clean up after ourself. */ 1194 fpe = c->pGC->font->fpe; 1195 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); 1196 c->pDraw = (DrawablePtr)0; 1197 } 1198 1199 client_state = c->slept ? SLEEPING : NEVER_SLEPT; 1200 1201 while (c->endReq - c->pElt > TextEltHeader) 1202 { 1203 if (*c->pElt == FontChange) 1204 { 1205 if (c->endReq - c->pElt < FontShiftSize) 1206 { 1207 err = BadLength; 1208 goto bail; 1209 } 1210 1211 oldpFont = pFont; 1212 oldfid = fid; 1213 1214 fid = ((Font)*(c->pElt+4)) /* big-endian */ 1215 | ((Font)*(c->pElt+3)) << 8 1216 | ((Font)*(c->pElt+2)) << 16 1217 | ((Font)*(c->pElt+1)) << 24; 1218 pFont = (FontPtr)SecurityLookupIDByType(client, fid, RT_FONT, 1219 DixReadAccess); 1220 if (!pFont) 1221 { 1222 client->errorValue = fid; 1223 err = BadFont; 1224 /* restore pFont and fid for step 4 (described below) */ 1225 pFont = oldpFont; 1226 fid = oldfid; 1227 1228 /* If we're in START_SLEEP mode, the following step 1229 shortens the request... in the unlikely event that 1230 the fid somehow becomes valid before we come through 1231 again to actually execute the polytext, which would 1232 then mess up our refcounting scheme badly. */ 1233 c->err = err; 1234 c->endReq = c->pElt; 1235 1236 goto bail; 1237 } 1238 1239 /* Step 3 (described below) on our new font */ 1240 if (client_state == START_SLEEP) 1241 pFont->refcnt++; 1242 else 1243 { 1244 if (pFont != c->pGC->font && c->pDraw) 1245 { 1246 ChangeGC( c->pGC, GCFont, &fid); 1247 ValidateGC(c->pDraw, c->pGC); 1248 if (c->reqType == X_PolyText8) 1249 c->polyText = (PolyTextPtr) c->pGC->ops->PolyText8; 1250 else 1251 c->polyText = (PolyTextPtr) c->pGC->ops->PolyText16; 1252 } 1253 1254 /* Undo the refcnt++ we performed when going to sleep */ 1255 if (client_state == SLEEPING) 1256 (void)CloseFont(c->pGC->font, (Font)0); 1257 } 1258 c->pElt += FontShiftSize; 1259 } 1260 else /* print a string */ 1261 { 1262 unsigned char *pNextElt; 1263 pNextElt = c->pElt + TextEltHeader + (*c->pElt)*c->itemSize; 1264 if ( pNextElt > c->endReq) 1265 { 1266 err = BadLength; 1267 goto bail; 1268 } 1269 if (client_state == START_SLEEP) 1270 { 1271 c->pElt = pNextElt; 1272 continue; 1273 } 1274 if (c->pDraw) 1275 { 1276 lgerr = LoadGlyphs(client, c->pGC->font, *c->pElt, c->itemSize, 1277 c->pElt + TextEltHeader); 1278 } 1279 else lgerr = Successful; 1280 1281 if (lgerr == Suspended) 1282 { 1283 if (!c->slept) { 1284 int len; 1285 GC *pGC; 1286 PTclosurePtr new_closure; 1287 1288 /* We're putting the client to sleep. We need to do a few things 1289 to ensure successful and atomic-appearing execution of the 1290 remainder of the request. First, copy the remainder of the 1291 request into a safe malloc'd area. Second, create a scratch GC 1292 to use for the remainder of the request. Third, mark all fonts 1293 referenced in the remainder of the request to prevent their 1294 deallocation. Fourth, make the original GC look like the 1295 request has completed... set its font to the final font value 1296 from this request. These GC manipulations are for the unlikely 1297 (but possible) event that some other client is using the GC. 1298 Steps 3 and 4 are performed by running this procedure through 1299 the remainder of the request in a special no-render mode 1300 indicated by client_state = START_SLEEP. */ 1301 1302 /* Step 1 */ 1303 /* Allocate a malloc'd closure structure to replace 1304 the local one we were passed */ 1305 new_closure = (PTclosurePtr) xalloc(sizeof(PTclosureRec)); 1306 if (!new_closure) 1307 { 1308 err = BadAlloc; 1309 goto bail; 1310 } 1311 *new_closure = *c; 1312 c = new_closure; 1313 1314 len = c->endReq - c->pElt; 1315 c->data = (unsigned char *)xalloc(len); 1316 if (!c->data) 1317 { 1318 xfree(c); 1319 err = BadAlloc; 1320 goto bail; 1321 } 1322 memmove(c->data, c->pElt, len); 1323 c->pElt = c->data; 1324 c->endReq = c->pElt + len; 1325 1326 /* Step 2 */ 1327 1328 pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen); 1329 if (!pGC) 1330 { 1331 xfree(c->data); 1332 xfree(c); 1333 err = BadAlloc; 1334 goto bail; 1335 } 1336 if ((err = CopyGC(c->pGC, pGC, GCFunction | 1337 GCPlaneMask | GCForeground | 1338 GCBackground | GCFillStyle | 1339 GCTile | GCStipple | 1340 GCTileStipXOrigin | 1341 GCTileStipYOrigin | GCFont | 1342 GCSubwindowMode | GCClipXOrigin | 1343 GCClipYOrigin | GCClipMask)) != 1344 Success) 1345 { 1346 FreeScratchGC(pGC); 1347 xfree(c->data); 1348 xfree(c); 1349 err = BadAlloc; 1350 goto bail; 1351 } 1352 origGC = c->pGC; 1353 c->pGC = pGC; 1354 ValidateGC(c->pDraw, c->pGC); 1355 1356 c->slept = TRUE; 1357 ClientSleep(client, 1358 (ClientSleepProcPtr)doPolyText, 1359 (pointer) c); 1360 1361 /* Set up to perform steps 3 and 4 */ 1362 client_state = START_SLEEP; 1363 continue; /* on to steps 3 and 4 */ 1364 } 1365 return TRUE; 1366 } 1367 else if (lgerr != Successful) 1368 { 1369 err = FontToXError(lgerr); 1370 goto bail; 1371 } 1372 if (c->pDraw) 1373 { 1374 c->xorg += *((INT8 *)(c->pElt + 1)); /* must be signed */ 1375 c->xorg = (* c->polyText)(c->pDraw, c->pGC, c->xorg, c->yorg, 1376 *c->pElt, c->pElt + TextEltHeader); 1377 } 1378 c->pElt = pNextElt; 1379 } 1380 } 1381 1382bail: 1383 1384 if (client_state == START_SLEEP) 1385 { 1386 /* Step 4 */ 1387 if (pFont != origGC->font) 1388 { 1389 ChangeGC(origGC, GCFont, &fid); 1390 ValidateGC(c->pDraw, origGC); 1391 } 1392 1393 /* restore pElt pointer for execution of remainder of the request */ 1394 c->pElt = c->data; 1395 return TRUE; 1396 } 1397 1398 if (c->err != Success) err = c->err; 1399 if (err != Success && c->client != serverClient) { 1400#ifdef PANORAMIX 1401 if (noPanoramiXExtension || !c->pGC->pScreen->myNum) 1402#endif 1403 SendErrorToClient(c->client, c->reqType, 0, 0, err); 1404 } 1405 if (c->slept) 1406 { 1407 ClientWakeup(c->client); 1408 ChangeGC(c->pGC, clearGCmask, clearGC); 1409 1410 /* Unreference the font from the scratch GC */ 1411 CloseFont(c->pGC->font, (Font)0); 1412 c->pGC->font = NullFont; 1413 1414 FreeScratchGC(c->pGC); 1415 xfree(c->data); 1416 xfree(c); 1417 } 1418 return TRUE; 1419} 1420 1421int 1422PolyText(ClientPtr client, DrawablePtr pDraw, GC *pGC, unsigned char *pElt, 1423 unsigned char *endReq, int xorg, int yorg, int reqType, XID did) 1424{ 1425 PTclosureRec local_closure; 1426 1427 local_closure.pElt = pElt; 1428 local_closure.endReq = endReq; 1429 local_closure.client = client; 1430 local_closure.pDraw = pDraw; 1431 local_closure.xorg = xorg; 1432 local_closure.yorg = yorg; 1433 if ((local_closure.reqType = reqType) == X_PolyText8) 1434 { 1435 local_closure.polyText = (PolyTextPtr) pGC->ops->PolyText8; 1436 local_closure.itemSize = 1; 1437 } 1438 else 1439 { 1440 local_closure.polyText = (PolyTextPtr) pGC->ops->PolyText16; 1441 local_closure.itemSize = 2; 1442 } 1443 local_closure.pGC = pGC; 1444 local_closure.did = did; 1445 local_closure.err = Success; 1446 local_closure.slept = FALSE; 1447 1448 (void) doPolyText(client, &local_closure); 1449 return Success; 1450} 1451 1452 1453#undef TextEltHeader 1454#undef FontShiftSize 1455 1456int 1457doImageText(ClientPtr client, ITclosurePtr c) 1458{ 1459 int err = Success, lgerr; /* err is in X error, not font error, space */ 1460 FontPathElementPtr fpe; 1461 1462 if (client->clientGone) 1463 { 1464 fpe = c->pGC->font->fpe; 1465 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); 1466 err = Success; 1467 goto bail; 1468 } 1469 1470 /* Make sure our drawable hasn't disappeared while we slept. */ 1471 if (c->slept && 1472 c->pDraw && 1473 c->pDraw != (DrawablePtr)SecurityLookupIDByClass(client, c->did, 1474 RC_DRAWABLE, DixWriteAccess)) 1475 { 1476 /* Our drawable has disappeared. Treat like client died... ask 1477 the FPE code to clean up after client. */ 1478 fpe = c->pGC->font->fpe; 1479 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); 1480 err = Success; 1481 goto bail; 1482 } 1483 1484 lgerr = LoadGlyphs(client, c->pGC->font, c->nChars, c->itemSize, c->data); 1485 if (lgerr == Suspended) 1486 { 1487 if (!c->slept) { 1488 GC *pGC; 1489 unsigned char *data; 1490 ITclosurePtr new_closure; 1491 1492 /* We're putting the client to sleep. We need to 1493 save some state. Similar problem to that handled 1494 in doPolyText, but much simpler because the 1495 request structure is much simpler. */ 1496 1497 new_closure = (ITclosurePtr) xalloc(sizeof(ITclosureRec)); 1498 if (!new_closure) 1499 { 1500 err = BadAlloc; 1501 goto bail; 1502 } 1503 *new_closure = *c; 1504 c = new_closure; 1505 1506 data = (unsigned char *)xalloc(c->nChars * c->itemSize); 1507 if (!data) 1508 { 1509 xfree(c); 1510 err = BadAlloc; 1511 goto bail; 1512 } 1513 memmove(data, c->data, c->nChars * c->itemSize); 1514 c->data = data; 1515 1516 pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen); 1517 if (!pGC) 1518 { 1519 xfree(c->data); 1520 xfree(c); 1521 err = BadAlloc; 1522 goto bail; 1523 } 1524 if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask | 1525 GCForeground | GCBackground | GCFillStyle | 1526 GCTile | GCStipple | GCTileStipXOrigin | 1527 GCTileStipYOrigin | GCFont | 1528 GCSubwindowMode | GCClipXOrigin | 1529 GCClipYOrigin | GCClipMask)) != Success) 1530 { 1531 FreeScratchGC(pGC); 1532 xfree(c->data); 1533 xfree(c); 1534 err = BadAlloc; 1535 goto bail; 1536 } 1537 c->pGC = pGC; 1538 ValidateGC(c->pDraw, c->pGC); 1539 1540 c->slept = TRUE; 1541 ClientSleep(client, (ClientSleepProcPtr)doImageText, (pointer) c); 1542 } 1543 return TRUE; 1544 } 1545 else if (lgerr != Successful) 1546 { 1547 err = FontToXError(lgerr); 1548 goto bail; 1549 } 1550 if (c->pDraw) 1551 { 1552 (* c->imageText)(c->pDraw, c->pGC, c->xorg, c->yorg, 1553 c->nChars, c->data); 1554 } 1555 1556bail: 1557 1558 if (err != Success && c->client != serverClient) { 1559 SendErrorToClient(c->client, c->reqType, 0, 0, err); 1560 } 1561 if (c->slept) 1562 { 1563 ClientWakeup(c->client); 1564 ChangeGC(c->pGC, clearGCmask, clearGC); 1565 1566 /* Unreference the font from the scratch GC */ 1567 CloseFont(c->pGC->font, (Font)0); 1568 c->pGC->font = NullFont; 1569 1570 FreeScratchGC(c->pGC); 1571 xfree(c->data); 1572 xfree(c); 1573 } 1574 return TRUE; 1575} 1576 1577int 1578ImageText(ClientPtr client, DrawablePtr pDraw, GC *pGC, int nChars, 1579 unsigned char *data, int xorg, int yorg, int reqType, XID did) 1580{ 1581 ITclosureRec local_closure; 1582 1583 local_closure.client = client; 1584 local_closure.pDraw = pDraw; 1585 local_closure.pGC = pGC; 1586 local_closure.nChars = nChars; 1587 local_closure.data = data; 1588 local_closure.xorg = xorg; 1589 local_closure.yorg = yorg; 1590 if ((local_closure.reqType = reqType) == X_ImageText8) 1591 { 1592 local_closure.imageText = (ImageTextPtr) pGC->ops->ImageText8; 1593 local_closure.itemSize = 1; 1594 } 1595 else 1596 { 1597 local_closure.imageText = (ImageTextPtr) pGC->ops->ImageText16; 1598 local_closure.itemSize = 2; 1599 } 1600 local_closure.did = did; 1601 local_closure.slept = FALSE; 1602 1603 (void) doImageText(client, &local_closure); 1604 return Success; 1605} 1606 1607 1608/* does the necessary magic to figure out the fpe type */ 1609static int 1610DetermineFPEType(char *pathname) 1611{ 1612 int i; 1613 1614 for (i = 0; i < num_fpe_types; i++) { 1615 if ((*fpe_functions[i].name_check) (pathname)) 1616 return i; 1617 } 1618 return -1; 1619} 1620 1621 1622static void 1623FreeFontPath(FontPathElementPtr *list, int n, Bool force) 1624{ 1625 int i; 1626 1627 for (i = 0; i < n; i++) { 1628 if (force) { 1629 /* Sanity check that all refcounts will be 0 by the time 1630 we get to the end of the list. */ 1631 int found = 1; /* the first reference is us */ 1632 int j; 1633 for (j = i+1; j < n; j++) { 1634 if (list[j] == list[i]) 1635 found++; 1636 } 1637 if (list[i]->refcount != found) { 1638 ErrorF("FreeFontPath: FPE \"%.*s\" refcount is %d, should be %d; fixing.\n", 1639 list[i]->name_length, list[i]->name, 1640 list[i]->refcount, found); 1641 list[i]->refcount = found; /* ensure it will get freed */ 1642 } 1643 } 1644 FreeFPE(list[i]); 1645 } 1646 xfree((char *) list); 1647} 1648 1649static FontPathElementPtr 1650find_existing_fpe(FontPathElementPtr *list, int num, unsigned char *name, int len) 1651{ 1652 FontPathElementPtr fpe; 1653 int i; 1654 1655 for (i = 0; i < num; i++) { 1656 fpe = list[i]; 1657 if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0) 1658 return fpe; 1659 } 1660 return (FontPathElementPtr) 0; 1661} 1662 1663 1664static int 1665SetFontPathElements(int npaths, unsigned char *paths, int *bad, Bool persist) 1666{ 1667 int i, err = 0; 1668 int valid_paths = 0; 1669 unsigned int len; 1670 unsigned char *cp = paths; 1671 FontPathElementPtr fpe = NULL, *fplist; 1672 1673 fplist = (FontPathElementPtr *) 1674 xalloc(sizeof(FontPathElementPtr) * npaths); 1675 if (!fplist) { 1676 *bad = 0; 1677 return BadAlloc; 1678 } 1679 for (i = 0; i < num_fpe_types; i++) { 1680 if (fpe_functions[i].set_path_hook) 1681 (*fpe_functions[i].set_path_hook) (); 1682 } 1683 for (i = 0; i < npaths; i++) 1684 { 1685 len = (unsigned int) (*cp++); 1686 1687 if (len == 0) 1688 { 1689 if (persist) 1690 ErrorF ("Removing empty element from the valid list of fontpaths\n"); 1691 err = BadValue; 1692 } 1693 else 1694 { 1695 /* if it's already in our active list, just reset it */ 1696 /* 1697 * note that this can miss FPE's in limbo -- may be worth catching 1698 * them, though it'd muck up refcounting 1699 */ 1700 fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len); 1701 if (fpe) 1702 { 1703 err = (*fpe_functions[fpe->type].reset_fpe) (fpe); 1704 if (err == Successful) 1705 { 1706 UseFPE(fpe);/* since it'll be decref'd later when freed 1707 * from the old list */ 1708 } 1709 else 1710 fpe = 0; 1711 } 1712 /* if error or can't do it, act like it's a new one */ 1713 if (!fpe) 1714 { 1715 fpe = (FontPathElementPtr) xalloc(sizeof(FontPathElementRec)); 1716 if (!fpe) 1717 { 1718 err = BadAlloc; 1719 goto bail; 1720 } 1721 fpe->name = (char *) xalloc(len + 1); 1722 if (!fpe->name) 1723 { 1724 xfree(fpe); 1725 err = BadAlloc; 1726 goto bail; 1727 } 1728 fpe->refcount = 1; 1729 1730 strncpy(fpe->name, (char *) cp, (int) len); 1731 fpe->name[len] = '\0'; 1732 fpe->name_length = len; 1733 fpe->type = DetermineFPEType(fpe->name); 1734 if (fpe->type == -1) 1735 err = BadValue; 1736 else 1737 err = (*fpe_functions[fpe->type].init_fpe) (fpe); 1738 if (err != Successful) 1739 { 1740 if (persist) 1741 { 1742 ErrorF("Could not init font path element %s, removing from list!\n", 1743 fpe->name); 1744 } 1745 xfree (fpe->name); 1746 xfree (fpe); 1747 } 1748 } 1749 } 1750 if (err != Successful) 1751 { 1752 if (!persist) 1753 goto bail; 1754 } 1755 else 1756 { 1757 fplist[valid_paths++] = fpe; 1758 } 1759 cp += len; 1760 } 1761 1762 FreeFontPath(font_path_elements, num_fpes, FALSE); 1763 font_path_elements = fplist; 1764 if (patternCache) 1765 EmptyFontPatternCache(patternCache); 1766 num_fpes = valid_paths; 1767 1768 return Success; 1769bail: 1770 *bad = i; 1771 while (--valid_paths >= 0) 1772 FreeFPE(fplist[valid_paths]); 1773 xfree(fplist); 1774 return FontToXError(err); 1775} 1776 1777/* XXX -- do we need to pass error down to each renderer? */ 1778int 1779SetFontPath(ClientPtr client, int npaths, unsigned char *paths, int *error) 1780{ 1781 int err = Success; 1782 1783 if (npaths == 0) { 1784 if (SetDefaultFontPath(defaultFontPath) != Success) 1785 return BadValue; 1786 } else { 1787 err = SetFontPathElements(npaths, paths, error, FALSE); 1788 } 1789 return err; 1790} 1791 1792int 1793SetDefaultFontPath(char *path) 1794{ 1795 unsigned char *cp, 1796 *pp, 1797 *nump, 1798 *newpath; 1799 int num = 1, 1800 len, 1801 err, 1802 size = 0, 1803 bad; 1804 1805 /* get enough for string, plus values -- use up commas */ 1806 len = strlen(path) + 1; 1807 nump = cp = newpath = (unsigned char *) ALLOCATE_LOCAL(len); 1808 if (!newpath) 1809 return BadAlloc; 1810 pp = (unsigned char *) path; 1811 cp++; 1812 while (*pp) { 1813 if (*pp == ',') { 1814 *nump = (unsigned char) size; 1815 nump = cp++; 1816 pp++; 1817 num++; 1818 size = 0; 1819 } else { 1820 *cp++ = *pp++; 1821 size++; 1822 } 1823 } 1824 *nump = (unsigned char) size; 1825 1826 err = SetFontPathElements(num, newpath, &bad, TRUE); 1827 1828 DEALLOCATE_LOCAL(newpath); 1829 1830 return err; 1831} 1832 1833unsigned char * 1834GetFontPath(int *count, int *length) 1835{ 1836 int i; 1837 unsigned char *c; 1838 int len; 1839 FontPathElementPtr fpe; 1840 1841 len = 0; 1842 for (i = 0; i < num_fpes; i++) { 1843 fpe = font_path_elements[i]; 1844 len += fpe->name_length + 1; 1845 } 1846 font_path_string = (unsigned char *) xrealloc(font_path_string, len); 1847 if (!font_path_string) 1848 return NULL; 1849 1850 c = font_path_string; 1851 *length = 0; 1852 for (i = 0; i < num_fpes; i++) { 1853 fpe = font_path_elements[i]; 1854 *c = fpe->name_length; 1855 *length += *c++; 1856 memmove(c, fpe->name, fpe->name_length); 1857 c += fpe->name_length; 1858 } 1859 *count = num_fpes; 1860 return font_path_string; 1861} 1862 1863_X_EXPORT int 1864LoadGlyphs(ClientPtr client, FontPtr pfont, unsigned nchars, int item_size, unsigned char *data) 1865{ 1866 if (fpe_functions[pfont->fpe->type].load_glyphs) 1867 return (*fpe_functions[pfont->fpe->type].load_glyphs) 1868 (client, pfont, 0, nchars, item_size, data); 1869 else 1870 return Successful; 1871} 1872 1873void 1874DeleteClientFontStuff(ClientPtr client) 1875{ 1876 int i; 1877 FontPathElementPtr fpe; 1878 1879 for (i = 0; i < num_fpes; i++) 1880 { 1881 fpe = font_path_elements[i]; 1882 if (fpe_functions[fpe->type].client_died) 1883 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); 1884 } 1885} 1886 1887void 1888InitFonts (void) 1889{ 1890 patternCache = MakeFontPatternCache(); 1891 1892#ifndef BUILTIN_FONTS 1893 if (screenInfo.numScreens > screenInfo.numVideoScreens) { 1894 PrinterFontRegisterFpeFunctions(); 1895 FontFileCheckRegisterFpeFunctions(); 1896 check_fs_register_fpe_functions(); 1897 } else 1898#endif 1899 { 1900#ifdef BUILTIN_FONTS 1901 BuiltinRegisterFpeFunctions(); 1902#else 1903 FontFileRegisterFpeFunctions(); 1904#endif 1905#ifndef NOFONTSERVERACCESS 1906 fs_register_fpe_functions(); 1907#endif 1908 } 1909} 1910 1911int 1912GetDefaultPointSize () 1913{ 1914 return 120; 1915} 1916 1917 1918FontResolutionPtr 1919GetClientResolutions (int *num) 1920{ 1921 if (requestingClient && requestingClient->fontResFunc != NULL && 1922 !requestingClient->clientGone) 1923 { 1924 return (*requestingClient->fontResFunc)(requestingClient, num); 1925 } 1926 else { 1927 static struct _FontResolution res; 1928 ScreenPtr pScreen; 1929 1930 pScreen = screenInfo.screens[0]; 1931 res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth; 1932 /* 1933 * XXX - we'll want this as long as bitmap instances are prevalent 1934 so that we can match them from scalable fonts 1935 */ 1936 if (res.x_resolution < 88) 1937 res.x_resolution = 75; 1938 else 1939 res.x_resolution = 100; 1940 res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight; 1941 if (res.y_resolution < 88) 1942 res.y_resolution = 75; 1943 else 1944 res.y_resolution = 100; 1945 res.point_size = 120; 1946 *num = 1; 1947 return &res; 1948 } 1949} 1950 1951/* 1952 * returns the type index of the new fpe 1953 * 1954 * should be called (only once!) by each type of fpe when initialized 1955 */ 1956 1957int 1958RegisterFPEFunctions(NameCheckFunc name_func, 1959 InitFpeFunc init_func, 1960 FreeFpeFunc free_func, 1961 ResetFpeFunc reset_func, 1962 OpenFontFunc open_func, 1963 CloseFontFunc close_func, 1964 ListFontsFunc list_func, 1965 StartLfwiFunc start_lfwi_func, 1966 NextLfwiFunc next_lfwi_func, 1967 WakeupFpeFunc wakeup_func, 1968 ClientDiedFunc client_died, 1969 LoadGlyphsFunc load_glyphs, 1970 StartLaFunc start_list_alias_func, 1971 NextLaFunc next_list_alias_func, 1972 SetPathFunc set_path_func) 1973{ 1974 FPEFunctions *new; 1975 1976 /* grow the list */ 1977 new = (FPEFunctions *) xrealloc(fpe_functions, 1978 (num_fpe_types + 1) * sizeof(FPEFunctions)); 1979 if (!new) 1980 return -1; 1981 fpe_functions = new; 1982 1983 fpe_functions[num_fpe_types].name_check = name_func; 1984 fpe_functions[num_fpe_types].open_font = open_func; 1985 fpe_functions[num_fpe_types].close_font = close_func; 1986 fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func; 1987 fpe_functions[num_fpe_types].list_fonts = list_func; 1988 fpe_functions[num_fpe_types].start_list_fonts_with_info = 1989 start_lfwi_func; 1990 fpe_functions[num_fpe_types].list_next_font_with_info = 1991 next_lfwi_func; 1992 fpe_functions[num_fpe_types].init_fpe = init_func; 1993 fpe_functions[num_fpe_types].free_fpe = free_func; 1994 fpe_functions[num_fpe_types].reset_fpe = reset_func; 1995 fpe_functions[num_fpe_types].client_died = client_died; 1996 fpe_functions[num_fpe_types].load_glyphs = load_glyphs; 1997 fpe_functions[num_fpe_types].start_list_fonts_and_aliases = 1998 start_list_alias_func; 1999 fpe_functions[num_fpe_types].list_next_font_or_alias = 2000 next_list_alias_func; 2001 fpe_functions[num_fpe_types].set_path_hook = set_path_func; 2002 2003 return num_fpe_types++; 2004} 2005 2006void 2007FreeFonts(void) 2008{ 2009 if (patternCache) { 2010 FreeFontPatternCache(patternCache); 2011 patternCache = 0; 2012 } 2013 FreeFontPath(font_path_elements, num_fpes, TRUE); 2014 font_path_elements = 0; 2015 num_fpes = 0; 2016 xfree(fpe_functions); 2017 num_fpe_types = 0; 2018 fpe_functions = (FPEFunctions *) 0; 2019} 2020 2021/* convenience functions for FS interface */ 2022 2023FontPtr 2024find_old_font(XID id) 2025{ 2026 return (FontPtr) SecurityLookupIDByType(NullClient, id, RT_NONE, 2027 DixUnknownAccess); 2028} 2029 2030Font 2031GetNewFontClientID() 2032{ 2033 return FakeClientID(0); 2034} 2035 2036int 2037StoreFontClientFont(FontPtr pfont, Font id) 2038{ 2039 return AddResource(id, RT_NONE, (pointer) pfont); 2040} 2041 2042void 2043DeleteFontClientID(Font id) 2044{ 2045 FreeResource(id, RT_NONE); 2046} 2047 2048int 2049client_auth_generation(ClientPtr client) 2050{ 2051 return 0; 2052} 2053 2054static int fs_handlers_installed = 0; 2055static unsigned int last_server_gen; 2056 2057int 2058init_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler) 2059{ 2060 /* if server has reset, make sure the b&w handlers are reinstalled */ 2061 if (last_server_gen < serverGeneration) { 2062 last_server_gen = serverGeneration; 2063 fs_handlers_installed = 0; 2064 } 2065 if (fs_handlers_installed == 0) { 2066 if (!RegisterBlockAndWakeupHandlers(block_handler, 2067 FontWakeup, (pointer) 0)) 2068 return AllocError; 2069 fs_handlers_installed++; 2070 } 2071 QueueFontWakeup(fpe); 2072 return Successful; 2073} 2074 2075void 2076remove_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler, Bool all) 2077{ 2078 if (all) { 2079 /* remove the handlers if no one else is using them */ 2080 if (--fs_handlers_installed == 0) { 2081 RemoveBlockAndWakeupHandlers(block_handler, FontWakeup, 2082 (pointer) 0); 2083 } 2084 } 2085 RemoveFontWakeup(fpe); 2086} 2087