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