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