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