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 pointer 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 .client = client, 1357 .pDraw = pDraw, 1358 .pGC = pGC, 1359 .pElt = pElt, 1360 .endReq = endReq, 1361 .xorg = xorg, 1362 .yorg = yorg, 1363 .reqType = reqType, 1364 .did = did, 1365 .err = Success 1366 }; 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 if (err != Success) 1691 client->errorValue = bad; 1692 } 1693 return err; 1694} 1695 1696int 1697SetDefaultFontPath(const char *path) 1698{ 1699 const char *start, *end; 1700 char *temp_path; 1701 unsigned char *cp, *pp, *nump, *newpath; 1702 int num = 1, len, err, size = 0, bad; 1703 1704 /* ensure temp_path contains "built-ins" */ 1705 start = path; 1706 while (1) { 1707 start = strstr(start, "built-ins"); 1708 if (start == NULL) 1709 break; 1710 end = start + strlen("built-ins"); 1711 if ((start == path || start[-1] == ',') && (!*end || *end == ',')) 1712 break; 1713 start = end; 1714 } 1715 if (!start) { 1716 if (asprintf(&temp_path, "%s%sbuilt-ins", path, *path ? "," : "") 1717 == -1) 1718 temp_path = NULL; 1719 } 1720 else { 1721 temp_path = strdup(path); 1722 } 1723 if (!temp_path) 1724 return BadAlloc; 1725 1726 /* get enough for string, plus values -- use up commas */ 1727 len = strlen(temp_path) + 1; 1728 nump = cp = newpath = malloc(len); 1729 if (!newpath) { 1730 free(temp_path); 1731 return BadAlloc; 1732 } 1733 pp = (unsigned char *) temp_path; 1734 cp++; 1735 while (*pp) { 1736 if (*pp == ',') { 1737 *nump = (unsigned char) size; 1738 nump = cp++; 1739 pp++; 1740 num++; 1741 size = 0; 1742 } 1743 else { 1744 *cp++ = *pp++; 1745 size++; 1746 } 1747 } 1748 *nump = (unsigned char) size; 1749 1750 err = SetFontPathElements(num, newpath, &bad, TRUE); 1751 1752 free(newpath); 1753 free(temp_path); 1754 1755 return err; 1756} 1757 1758int 1759GetFontPath(ClientPtr client, int *count, int *length, unsigned char **result) 1760{ 1761 int i; 1762 unsigned char *c; 1763 int len; 1764 FontPathElementPtr fpe; 1765 1766 i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); 1767 if (i != Success) 1768 return i; 1769 1770 len = 0; 1771 for (i = 0; i < num_fpes; i++) { 1772 fpe = font_path_elements[i]; 1773 len += fpe->name_length + 1; 1774 } 1775 c = realloc(font_path_string, len); 1776 if (c == NULL) { 1777 free(font_path_string); 1778 font_path_string = NULL; 1779 return BadAlloc; 1780 } 1781 1782 font_path_string = c; 1783 *length = 0; 1784 for (i = 0; i < num_fpes; i++) { 1785 fpe = font_path_elements[i]; 1786 *c = fpe->name_length; 1787 *length += *c++; 1788 memmove(c, fpe->name, fpe->name_length); 1789 c += fpe->name_length; 1790 } 1791 *count = num_fpes; 1792 *result = font_path_string; 1793 return Success; 1794} 1795 1796void 1797DeleteClientFontStuff(ClientPtr client) 1798{ 1799 int i; 1800 FontPathElementPtr fpe; 1801 1802 for (i = 0; i < num_fpes; i++) { 1803 fpe = font_path_elements[i]; 1804 if (fpe_functions[fpe->type]->client_died) 1805 (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe); 1806 } 1807} 1808 1809static int 1810register_fpe_funcs(const xfont2_fpe_funcs_rec *funcs) 1811{ 1812 xfont2_fpe_funcs_rec const **new; 1813 1814 /* grow the list */ 1815 new = reallocarray(fpe_functions, num_fpe_types + 1, sizeof(xfont2_fpe_funcs_ptr)); 1816 if (!new) 1817 return -1; 1818 fpe_functions = new; 1819 1820 fpe_functions[num_fpe_types] = funcs; 1821 1822 return num_fpe_types++; 1823} 1824 1825static unsigned long 1826get_server_generation(void) 1827{ 1828 return serverGeneration; 1829} 1830 1831static void * 1832get_server_client(void) 1833{ 1834 return serverClient; 1835} 1836 1837static int 1838get_default_point_size(void) 1839{ 1840 return 120; 1841} 1842 1843static FontResolutionPtr 1844get_client_resolutions(int *num) 1845{ 1846 static struct _FontResolution res; 1847 ScreenPtr pScreen; 1848 1849 pScreen = screenInfo.screens[0]; 1850 res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth; 1851 /* 1852 * XXX - we'll want this as long as bitmap instances are prevalent 1853 so that we can match them from scalable fonts 1854 */ 1855 if (res.x_resolution < 88) 1856 res.x_resolution = 75; 1857 else 1858 res.x_resolution = 100; 1859 res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight; 1860 if (res.y_resolution < 88) 1861 res.y_resolution = 75; 1862 else 1863 res.y_resolution = 100; 1864 res.point_size = 120; 1865 *num = 1; 1866 return &res; 1867} 1868 1869void 1870FreeFonts(void) 1871{ 1872 if (patternCache) { 1873 xfont2_free_font_pattern_cache(patternCache); 1874 patternCache = 0; 1875 } 1876 FreeFontPath(font_path_elements, num_fpes, TRUE); 1877 font_path_elements = 0; 1878 num_fpes = 0; 1879 free(fpe_functions); 1880 num_fpe_types = 0; 1881 fpe_functions = NULL; 1882} 1883 1884/* convenience functions for FS interface */ 1885 1886static FontPtr 1887find_old_font(XID id) 1888{ 1889 void *pFont; 1890 1891 dixLookupResourceByType(&pFont, id, RT_NONE, serverClient, DixReadAccess); 1892 return (FontPtr) pFont; 1893} 1894 1895static Font 1896get_new_font_client_id(void) 1897{ 1898 return FakeClientID(0); 1899} 1900 1901static int 1902store_font_Client_font(FontPtr pfont, Font id) 1903{ 1904 return AddResource(id, RT_NONE, (void *) pfont); 1905} 1906 1907static void 1908delete_font_client_id(Font id) 1909{ 1910 FreeResource(id, RT_NONE); 1911} 1912 1913static int 1914_client_auth_generation(ClientPtr client) 1915{ 1916 return 0; 1917} 1918 1919static int fs_handlers_installed = 0; 1920static unsigned int last_server_gen; 1921 1922static void fs_block_handler(void *blockData, void *timeout) 1923{ 1924 FontBlockHandlerProcPtr block_handler = blockData; 1925 1926 (*block_handler)(timeout); 1927} 1928 1929struct fs_fd_entry { 1930 struct xorg_list entry; 1931 int fd; 1932 void *data; 1933 FontFdHandlerProcPtr handler; 1934}; 1935 1936static void 1937fs_fd_handler(int fd, int ready, void *data) 1938{ 1939 struct fs_fd_entry *entry = data; 1940 1941 entry->handler(fd, entry->data); 1942} 1943 1944static struct xorg_list fs_fd_list; 1945 1946static int 1947add_fs_fd(int fd, FontFdHandlerProcPtr handler, void *data) 1948{ 1949 struct fs_fd_entry *entry = calloc(1, sizeof (struct fs_fd_entry)); 1950 1951 if (!entry) 1952 return FALSE; 1953 1954 entry->fd = fd; 1955 entry->data = data; 1956 entry->handler = handler; 1957 if (!SetNotifyFd(fd, fs_fd_handler, X_NOTIFY_READ, entry)) { 1958 free(entry); 1959 return FALSE; 1960 } 1961 xorg_list_add(&entry->entry, &fs_fd_list); 1962 return TRUE; 1963} 1964 1965static void 1966remove_fs_fd(int fd) 1967{ 1968 struct fs_fd_entry *entry, *temp; 1969 1970 xorg_list_for_each_entry_safe(entry, temp, &fs_fd_list, entry) { 1971 if (entry->fd == fd) { 1972 xorg_list_del(&entry->entry); 1973 free(entry); 1974 break; 1975 } 1976 } 1977 RemoveNotifyFd(fd); 1978} 1979 1980static void 1981adjust_fs_wait_for_delay(void *wt, unsigned long newdelay) 1982{ 1983 AdjustWaitForDelay(wt, newdelay); 1984} 1985 1986static int 1987_init_fs_handlers(FontPathElementPtr fpe, FontBlockHandlerProcPtr block_handler) 1988{ 1989 /* if server has reset, make sure the b&w handlers are reinstalled */ 1990 if (last_server_gen < serverGeneration) { 1991 last_server_gen = serverGeneration; 1992 fs_handlers_installed = 0; 1993 } 1994 if (fs_handlers_installed == 0) { 1995 if (!RegisterBlockAndWakeupHandlers(fs_block_handler, 1996 FontWakeup, (void *) block_handler)) 1997 return AllocError; 1998 xorg_list_init(&fs_fd_list); 1999 fs_handlers_installed++; 2000 } 2001 QueueFontWakeup(fpe); 2002 return Successful; 2003} 2004 2005static void 2006_remove_fs_handlers(FontPathElementPtr fpe, FontBlockHandlerProcPtr block_handler, 2007 Bool all) 2008{ 2009 if (all) { 2010 /* remove the handlers if no one else is using them */ 2011 if (--fs_handlers_installed == 0) { 2012 RemoveBlockAndWakeupHandlers(fs_block_handler, FontWakeup, 2013 (void *) block_handler); 2014 } 2015 } 2016 RemoveFontWakeup(fpe); 2017} 2018 2019static uint32_t wrap_time_in_millis(void) 2020{ 2021 return GetTimeInMillis(); 2022} 2023 2024static const xfont2_client_funcs_rec xfont2_client_funcs = { 2025 .version = XFONT2_CLIENT_FUNCS_VERSION, 2026 .client_auth_generation = _client_auth_generation, 2027 .client_signal = ClientSignal, 2028 .delete_font_client_id = delete_font_client_id, 2029 .verrorf = VErrorF, 2030 .find_old_font = find_old_font, 2031 .get_client_resolutions = get_client_resolutions, 2032 .get_default_point_size = get_default_point_size, 2033 .get_new_font_client_id = get_new_font_client_id, 2034 .get_time_in_millis = wrap_time_in_millis, 2035 .init_fs_handlers = _init_fs_handlers, 2036 .register_fpe_funcs = register_fpe_funcs, 2037 .remove_fs_handlers = _remove_fs_handlers, 2038 .get_server_client = get_server_client, 2039 .set_font_authorizations = set_font_authorizations, 2040 .store_font_client_font = store_font_Client_font, 2041 .make_atom = MakeAtom, 2042 .valid_atom = ValidAtom, 2043 .name_for_atom = NameForAtom, 2044 .get_server_generation = get_server_generation, 2045 .add_fs_fd = add_fs_fd, 2046 .remove_fs_fd = remove_fs_fd, 2047 .adjust_fs_wait_for_delay = adjust_fs_wait_for_delay, 2048}; 2049 2050xfont2_pattern_cache_ptr fontPatternCache; 2051 2052void 2053InitFonts(void) 2054{ 2055 if (fontPatternCache) 2056 xfont2_free_font_pattern_cache(fontPatternCache); 2057 fontPatternCache = xfont2_make_font_pattern_cache(); 2058 xfont2_init(&xfont2_client_funcs); 2059} 2060