dixfonts.c revision 475c125c
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 1483 /* We're putting the client to sleep. We need to 1484 save some state. Similar problem to that handled 1485 in doPolyText, but much simpler because the 1486 request structure is much simpler. */ 1487 1488 new_closure = malloc(sizeof(ITclosureRec)); 1489 if (!new_closure) 1490 { 1491 err = BadAlloc; 1492 goto bail; 1493 } 1494 *new_closure = *c; 1495 c = new_closure; 1496 1497 data = malloc(c->nChars * itemSize); 1498 if (!data) 1499 { 1500 free(c); 1501 err = BadAlloc; 1502 goto bail; 1503 } 1504 memmove(data, c->data, c->nChars * itemSize); 1505 c->data = data; 1506 1507 pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen); 1508 if (!pGC) 1509 { 1510 free(c->data); 1511 free(c); 1512 err = BadAlloc; 1513 goto bail; 1514 } 1515 if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask | 1516 GCForeground | GCBackground | GCFillStyle | 1517 GCTile | GCStipple | GCTileStipXOrigin | 1518 GCTileStipYOrigin | GCFont | 1519 GCSubwindowMode | GCClipXOrigin | 1520 GCClipYOrigin | GCClipMask)) != Success) 1521 { 1522 FreeScratchGC(pGC); 1523 free(c->data); 1524 free(c); 1525 err = BadAlloc; 1526 goto bail; 1527 } 1528 c->pGC = pGC; 1529 ValidateGC(c->pDraw, c->pGC); 1530 1531 ClientSleep(client, (ClientSleepProcPtr)doImageText, c); 1532 } 1533 else 1534 goto xinerama_sleep; 1535 return TRUE; 1536 } 1537 else if (lgerr != Successful) 1538 { 1539 err = FontToXError(lgerr); 1540 goto bail; 1541 } 1542 if (c->pDraw) 1543 { 1544 if (c->reqType == X_ImageText8) 1545 (* c->pGC->ops->ImageText8)(c->pDraw, c->pGC, c->xorg, c->yorg, 1546 c->nChars, (char *) c->data); 1547 else 1548 (* c->pGC->ops->ImageText16)(c->pDraw, c->pGC, c->xorg, c->yorg, 1549 c->nChars, (unsigned short *) c->data); 1550 } 1551 1552bail: 1553 1554 if (err != Success && c->client != serverClient) { 1555 SendErrorToClient(c->client, c->reqType, 0, 0, err); 1556 } 1557 if (ClientIsAsleep(client)) 1558 { 1559 ClientWakeup(c->client); 1560xinerama_sleep: 1561 ChangeGC(NullClient, c->pGC, clearGCmask, clearGC); 1562 1563 /* Unreference the font from the scratch GC */ 1564 CloseFont(c->pGC->font, (Font)0); 1565 c->pGC->font = NullFont; 1566 1567 FreeScratchGC(c->pGC); 1568 free(c->data); 1569 free(c); 1570 } 1571 return TRUE; 1572} 1573 1574int 1575ImageText(ClientPtr client, DrawablePtr pDraw, GC *pGC, int nChars, 1576 unsigned char *data, int xorg, int yorg, int reqType, XID did) 1577{ 1578 ITclosureRec local_closure; 1579 1580 local_closure.client = client; 1581 local_closure.pDraw = pDraw; 1582 local_closure.pGC = pGC; 1583 local_closure.nChars = nChars; 1584 local_closure.data = data; 1585 local_closure.xorg = xorg; 1586 local_closure.yorg = yorg; 1587 local_closure.reqType = reqType; 1588 local_closure.did = did; 1589 1590 (void) doImageText(client, &local_closure); 1591 return Success; 1592} 1593 1594 1595/* does the necessary magic to figure out the fpe type */ 1596static int 1597DetermineFPEType(char *pathname) 1598{ 1599 int i; 1600 1601 for (i = 0; i < num_fpe_types; i++) { 1602 if ((*fpe_functions[i].name_check) (pathname)) 1603 return i; 1604 } 1605 return -1; 1606} 1607 1608 1609static void 1610FreeFontPath(FontPathElementPtr *list, int n, Bool force) 1611{ 1612 int i; 1613 1614 for (i = 0; i < n; i++) { 1615 if (force) { 1616 /* Sanity check that all refcounts will be 0 by the time 1617 we get to the end of the list. */ 1618 int found = 1; /* the first reference is us */ 1619 int j; 1620 for (j = i+1; j < n; j++) { 1621 if (list[j] == list[i]) 1622 found++; 1623 } 1624 if (list[i]->refcount != found) { 1625 list[i]->refcount = found; /* ensure it will get freed */ 1626 } 1627 } 1628 FreeFPE(list[i]); 1629 } 1630 free(list); 1631} 1632 1633static FontPathElementPtr 1634find_existing_fpe(FontPathElementPtr *list, int num, unsigned char *name, int len) 1635{ 1636 FontPathElementPtr fpe; 1637 int i; 1638 1639 for (i = 0; i < num; i++) { 1640 fpe = list[i]; 1641 if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0) 1642 return fpe; 1643 } 1644 return (FontPathElementPtr) 0; 1645} 1646 1647 1648static int 1649SetFontPathElements(int npaths, unsigned char *paths, int *bad, Bool persist) 1650{ 1651 int i, err = 0; 1652 int valid_paths = 0; 1653 unsigned int len; 1654 unsigned char *cp = paths; 1655 FontPathElementPtr fpe = NULL, *fplist; 1656 1657 fplist = malloc(sizeof(FontPathElementPtr) * npaths); 1658 if (!fplist) { 1659 *bad = 0; 1660 return BadAlloc; 1661 } 1662 for (i = 0; i < num_fpe_types; i++) { 1663 if (fpe_functions[i].set_path_hook) 1664 (*fpe_functions[i].set_path_hook) (); 1665 } 1666 for (i = 0; i < npaths; i++) 1667 { 1668 len = (unsigned int) (*cp++); 1669 1670 if (len == 0) 1671 { 1672 if (persist) 1673 ErrorF("[dix] Removing empty element from the valid list of fontpaths\n"); 1674 err = BadValue; 1675 } 1676 else 1677 { 1678 /* if it's already in our active list, just reset it */ 1679 /* 1680 * note that this can miss FPE's in limbo -- may be worth catching 1681 * them, though it'd muck up refcounting 1682 */ 1683 fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len); 1684 if (fpe) 1685 { 1686 err = (*fpe_functions[fpe->type].reset_fpe) (fpe); 1687 if (err == Successful) 1688 { 1689 UseFPE(fpe);/* since it'll be decref'd later when freed 1690 * from the old list */ 1691 } 1692 else 1693 fpe = 0; 1694 } 1695 /* if error or can't do it, act like it's a new one */ 1696 if (!fpe) 1697 { 1698 fpe = malloc(sizeof(FontPathElementRec)); 1699 if (!fpe) 1700 { 1701 err = BadAlloc; 1702 goto bail; 1703 } 1704 fpe->name = malloc(len + 1); 1705 if (!fpe->name) 1706 { 1707 free(fpe); 1708 err = BadAlloc; 1709 goto bail; 1710 } 1711 fpe->refcount = 1; 1712 1713 strncpy(fpe->name, (char *) cp, (int) len); 1714 fpe->name[len] = '\0'; 1715 fpe->name_length = len; 1716 fpe->type = DetermineFPEType(fpe->name); 1717 if (fpe->type == -1) 1718 err = BadValue; 1719 else 1720 err = (*fpe_functions[fpe->type].init_fpe) (fpe); 1721 if (err != Successful) 1722 { 1723 if (persist) 1724 { 1725 ErrorF("[dix] Could not init font path element %s, removing from list!\n", 1726 fpe->name); 1727 } 1728 free(fpe->name); 1729 free(fpe); 1730 } 1731 } 1732 } 1733 if (err != Successful) 1734 { 1735 if (!persist) 1736 goto bail; 1737 } 1738 else 1739 { 1740 fplist[valid_paths++] = fpe; 1741 } 1742 cp += len; 1743 } 1744 1745 FreeFontPath(font_path_elements, num_fpes, FALSE); 1746 font_path_elements = fplist; 1747 if (patternCache) 1748 EmptyFontPatternCache(patternCache); 1749 num_fpes = valid_paths; 1750 1751 return Success; 1752bail: 1753 *bad = i; 1754 while (--valid_paths >= 0) 1755 FreeFPE(fplist[valid_paths]); 1756 free(fplist); 1757 return FontToXError(err); 1758} 1759 1760int 1761SetFontPath(ClientPtr client, int npaths, unsigned char *paths) 1762{ 1763 int err = XaceHook(XACE_SERVER_ACCESS, client, DixManageAccess); 1764 if (err != Success) 1765 return err; 1766 1767 if (npaths == 0) { 1768 if (SetDefaultFontPath(defaultFontPath) != Success) 1769 return BadValue; 1770 } else { 1771 int bad; 1772 err = SetFontPathElements(npaths, paths, &bad, FALSE); 1773 client->errorValue = bad; 1774 } 1775 return err; 1776} 1777 1778int 1779SetDefaultFontPath(char *path) 1780{ 1781 char *temp_path, 1782 *start, 1783 *end; 1784 unsigned char *cp, 1785 *pp, 1786 *nump, 1787 *newpath; 1788 int num = 1, 1789 len, 1790 err, 1791 size = 0, 1792 bad; 1793 1794 /* ensure temp_path contains "built-ins" */ 1795 start = path; 1796 while (1) { 1797 start = strstr(start, "built-ins"); 1798 if (start == NULL) 1799 break; 1800 end = start + strlen("built-ins"); 1801 if ((start == path || start[-1] == ',') && (!*end || *end == ',')) 1802 break; 1803 start = end; 1804 } 1805 if (!start) { 1806 if (asprintf(&temp_path, "%s%sbuilt-ins", path, *path ? "," : "") 1807 == -1) 1808 temp_path = NULL; 1809 } else { 1810 temp_path = strdup(path); 1811 } 1812 if (!temp_path) 1813 return BadAlloc; 1814 1815 /* get enough for string, plus values -- use up commas */ 1816 len = strlen(temp_path) + 1; 1817 nump = cp = newpath = malloc(len); 1818 if (!newpath) { 1819 free(temp_path); 1820 return BadAlloc; 1821 } 1822 pp = (unsigned char *) temp_path; 1823 cp++; 1824 while (*pp) { 1825 if (*pp == ',') { 1826 *nump = (unsigned char) size; 1827 nump = cp++; 1828 pp++; 1829 num++; 1830 size = 0; 1831 } else { 1832 *cp++ = *pp++; 1833 size++; 1834 } 1835 } 1836 *nump = (unsigned char) size; 1837 1838 err = SetFontPathElements(num, newpath, &bad, TRUE); 1839 1840 free(newpath); 1841 free(temp_path); 1842 1843 return err; 1844} 1845 1846int 1847GetFontPath(ClientPtr client, int *count, int *length, unsigned char **result) 1848{ 1849 int i; 1850 unsigned char *c; 1851 int len; 1852 FontPathElementPtr fpe; 1853 1854 i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); 1855 if (i != Success) 1856 return i; 1857 1858 len = 0; 1859 for (i = 0; i < num_fpes; i++) { 1860 fpe = font_path_elements[i]; 1861 len += fpe->name_length + 1; 1862 } 1863 font_path_string = (unsigned char *) realloc(font_path_string, len); 1864 if (!font_path_string) 1865 return BadAlloc; 1866 1867 c = font_path_string; 1868 *length = 0; 1869 for (i = 0; i < num_fpes; i++) { 1870 fpe = font_path_elements[i]; 1871 *c = fpe->name_length; 1872 *length += *c++; 1873 memmove(c, fpe->name, fpe->name_length); 1874 c += fpe->name_length; 1875 } 1876 *count = num_fpes; 1877 *result = font_path_string; 1878 return Success; 1879} 1880 1881void 1882DeleteClientFontStuff(ClientPtr client) 1883{ 1884 int i; 1885 FontPathElementPtr fpe; 1886 1887 for (i = 0; i < num_fpes; i++) 1888 { 1889 fpe = font_path_elements[i]; 1890 if (fpe_functions[fpe->type].client_died) 1891 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); 1892 } 1893} 1894 1895void 1896InitFonts (void) 1897{ 1898 patternCache = MakeFontPatternCache(); 1899 1900 register_fpe_functions(); 1901} 1902 1903int 1904GetDefaultPointSize (void) 1905{ 1906 return 120; 1907} 1908 1909 1910FontResolutionPtr 1911GetClientResolutions (int *num) 1912{ 1913 static struct _FontResolution res; 1914 ScreenPtr pScreen; 1915 1916 pScreen = screenInfo.screens[0]; 1917 res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth; 1918 /* 1919 * XXX - we'll want this as long as bitmap instances are prevalent 1920 so that we can match them from scalable fonts 1921 */ 1922 if (res.x_resolution < 88) 1923 res.x_resolution = 75; 1924 else 1925 res.x_resolution = 100; 1926 res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight; 1927 if (res.y_resolution < 88) 1928 res.y_resolution = 75; 1929 else 1930 res.y_resolution = 100; 1931 res.point_size = 120; 1932 *num = 1; 1933 return &res; 1934} 1935 1936/* 1937 * returns the type index of the new fpe 1938 * 1939 * should be called (only once!) by each type of fpe when initialized 1940 */ 1941 1942int 1943RegisterFPEFunctions(NameCheckFunc name_func, 1944 InitFpeFunc init_func, 1945 FreeFpeFunc free_func, 1946 ResetFpeFunc reset_func, 1947 OpenFontFunc open_func, 1948 CloseFontFunc close_func, 1949 ListFontsFunc list_func, 1950 StartLfwiFunc start_lfwi_func, 1951 NextLfwiFunc next_lfwi_func, 1952 WakeupFpeFunc wakeup_func, 1953 ClientDiedFunc client_died, 1954 LoadGlyphsFunc load_glyphs, 1955 StartLaFunc start_list_alias_func, 1956 NextLaFunc next_list_alias_func, 1957 SetPathFunc set_path_func) 1958{ 1959 FPEFunctions *new; 1960 1961 /* grow the list */ 1962 new = (FPEFunctions *) realloc(fpe_functions, 1963 (num_fpe_types + 1) * sizeof(FPEFunctions)); 1964 if (!new) 1965 return -1; 1966 fpe_functions = new; 1967 1968 fpe_functions[num_fpe_types].name_check = name_func; 1969 fpe_functions[num_fpe_types].open_font = open_func; 1970 fpe_functions[num_fpe_types].close_font = close_func; 1971 fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func; 1972 fpe_functions[num_fpe_types].list_fonts = list_func; 1973 fpe_functions[num_fpe_types].start_list_fonts_with_info = 1974 start_lfwi_func; 1975 fpe_functions[num_fpe_types].list_next_font_with_info = 1976 next_lfwi_func; 1977 fpe_functions[num_fpe_types].init_fpe = init_func; 1978 fpe_functions[num_fpe_types].free_fpe = free_func; 1979 fpe_functions[num_fpe_types].reset_fpe = reset_func; 1980 fpe_functions[num_fpe_types].client_died = client_died; 1981 fpe_functions[num_fpe_types].load_glyphs = load_glyphs; 1982 fpe_functions[num_fpe_types].start_list_fonts_and_aliases = 1983 start_list_alias_func; 1984 fpe_functions[num_fpe_types].list_next_font_or_alias = 1985 next_list_alias_func; 1986 fpe_functions[num_fpe_types].set_path_hook = set_path_func; 1987 1988 return num_fpe_types++; 1989} 1990 1991void 1992FreeFonts(void) 1993{ 1994 if (patternCache) { 1995 FreeFontPatternCache(patternCache); 1996 patternCache = 0; 1997 } 1998 FreeFontPath(font_path_elements, num_fpes, TRUE); 1999 font_path_elements = 0; 2000 num_fpes = 0; 2001 free(fpe_functions); 2002 num_fpe_types = 0; 2003 fpe_functions = (FPEFunctions *) 0; 2004} 2005 2006/* convenience functions for FS interface */ 2007 2008FontPtr 2009find_old_font(XID id) 2010{ 2011 pointer pFont; 2012 dixLookupResourceByType(&pFont, id, RT_NONE, serverClient, DixReadAccess); 2013 return (FontPtr)pFont; 2014} 2015 2016Font 2017GetNewFontClientID(void) 2018{ 2019 return FakeClientID(0); 2020} 2021 2022int 2023StoreFontClientFont(FontPtr pfont, Font id) 2024{ 2025 return AddResource(id, RT_NONE, (pointer) pfont); 2026} 2027 2028void 2029DeleteFontClientID(Font id) 2030{ 2031 FreeResource(id, RT_NONE); 2032} 2033 2034int 2035client_auth_generation(ClientPtr client) 2036{ 2037 return 0; 2038} 2039 2040static int fs_handlers_installed = 0; 2041static unsigned int last_server_gen; 2042 2043int 2044init_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler) 2045{ 2046 /* if server has reset, make sure the b&w handlers are reinstalled */ 2047 if (last_server_gen < serverGeneration) { 2048 last_server_gen = serverGeneration; 2049 fs_handlers_installed = 0; 2050 } 2051 if (fs_handlers_installed == 0) { 2052 if (!RegisterBlockAndWakeupHandlers(block_handler, 2053 FontWakeup, (pointer) 0)) 2054 return AllocError; 2055 fs_handlers_installed++; 2056 } 2057 QueueFontWakeup(fpe); 2058 return Successful; 2059} 2060 2061void 2062remove_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler, Bool all) 2063{ 2064 if (all) { 2065 /* remove the handlers if no one else is using them */ 2066 if (--fs_handlers_installed == 0) { 2067 RemoveBlockAndWakeupHandlers(block_handler, FontWakeup, 2068 (pointer) 0); 2069 } 2070 } 2071 RemoveFontWakeup(fpe); 2072} 2073