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