First import
[xorg_rtime.git] / xorg-server-1.4 / dix / dixfonts.c
blobc21b3ecb3d7bd1feb18a7e0bdde473822b9e3605
1 /************************************************************************
2 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
4 All Rights Reserved
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that the name of Digital not be
11 used in advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.
14 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
22 ************************************************************************/
23 /* The panoramix components contained the following notice */
25 Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
27 Permission is hereby granted, free of charge, to any person obtaining a copy
28 of this software and associated documentation files (the "Software"), to deal
29 in the Software without restriction, including without limitation the rights
30 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31 copies of the Software.
33 The above copyright notice and this permission notice shall be included in
34 all copies or substantial portions of the Software.
36 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
39 DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
40 BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
41 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
42 IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
44 Except as contained in this notice, the name of Digital Equipment Corporation
45 shall not be used in advertising or otherwise to promote the sale, use or other
46 dealings in this Software without prior written authorization from Digital
47 Equipment Corporation.
49 ******************************************************************/
51 #define NEED_REPLIES
52 #ifdef HAVE_DIX_CONFIG_H
53 #include <dix-config.h>
54 #endif
56 #include <X11/X.h>
57 #include <X11/Xmd.h>
58 #include <X11/Xproto.h>
59 #include "scrnintstr.h"
60 #include "resource.h"
61 #include "dixstruct.h"
62 #include "cursorstr.h"
63 #include "misc.h"
64 #include "opaque.h"
65 #include "dixfontstr.h"
66 #include "closestr.h"
67 #include "dixfont.h"
69 #ifdef DEBUG
70 #include <stdio.h>
71 #endif
73 #ifdef PANORAMIX
74 #include "panoramiX.h"
75 #endif
77 #ifdef XF86BIGFONT
78 #define _XF86BIGFONT_SERVER_
79 #include <X11/extensions/xf86bigfont.h>
80 #endif
82 #define QUERYCHARINFO(pci, pr) *(pr) = (pci)->metrics
84 extern pointer fosNaturalParams;
85 extern FontPtr defaultFont;
87 static FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0;
88 static int num_fpes = 0;
89 _X_EXPORT FPEFunctions *fpe_functions = (FPEFunctions *) 0;
90 static int num_fpe_types = 0;
92 static unsigned char *font_path_string;
94 static int num_slept_fpes = 0;
95 static int size_slept_fpes = 0;
96 static FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0;
97 static FontPatternCachePtr patternCache;
99 _X_EXPORT int
100 FontToXError(err)
101 int err;
103 switch (err) {
104 case Successful:
105 return Success;
106 case AllocError:
107 return BadAlloc;
108 case BadFontName:
109 return BadName;
110 case BadFontPath:
111 case BadFontFormat: /* is there something better? */
112 case BadCharRange:
113 return BadValue;
114 default:
115 return err;
121 * adding RT_FONT prevents conflict with default cursor font
123 Bool
124 SetDefaultFont(char *defaultfontname)
126 int err;
127 FontPtr pf;
128 XID fid;
130 fid = FakeClientID(0);
131 err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync,
132 (unsigned) strlen(defaultfontname), defaultfontname);
133 if (err != Success)
134 return FALSE;
135 pf = (FontPtr) LookupIDByType(fid, RT_FONT);
136 if (pf == (FontPtr) NULL)
137 return FALSE;
138 defaultFont = pf;
139 return TRUE;
143 * note that the font wakeup queue is not refcounted. this is because
144 * an fpe needs to be added when it's inited, and removed when it's finally
145 * freed, in order to handle any data that isn't requested, like FS events.
147 * since the only thing that should call these routines is the renderer's
148 * init_fpe() and free_fpe(), there shouldn't be any problem in using
149 * freed data.
151 void
152 QueueFontWakeup(FontPathElementPtr fpe)
154 int i;
155 FontPathElementPtr *new;
157 for (i = 0; i < num_slept_fpes; i++) {
158 if (slept_fpes[i] == fpe) {
159 return;
162 if (num_slept_fpes == size_slept_fpes) {
163 new = (FontPathElementPtr *)
164 xrealloc(slept_fpes,
165 sizeof(FontPathElementPtr) * (size_slept_fpes + 4));
166 if (!new)
167 return;
168 slept_fpes = new;
169 size_slept_fpes += 4;
171 slept_fpes[num_slept_fpes] = fpe;
172 num_slept_fpes++;
175 void
176 RemoveFontWakeup(FontPathElementPtr fpe)
178 int i,
181 for (i = 0; i < num_slept_fpes; i++) {
182 if (slept_fpes[i] == fpe) {
183 for (j = i; j < num_slept_fpes; j++) {
184 slept_fpes[j] = slept_fpes[j + 1];
186 num_slept_fpes--;
187 return;
192 void
193 FontWakeup(pointer data, int count, pointer LastSelectMask)
195 int i;
196 FontPathElementPtr fpe;
198 if (count < 0)
199 return;
200 /* wake up any fpe's that may be waiting for information */
201 for (i = 0; i < num_slept_fpes; i++) {
202 fpe = slept_fpes[i];
203 (void) (*fpe_functions[fpe->type].wakeup_fpe) (fpe, LastSelectMask);
207 /* XXX -- these two funcs may want to be broken into macros */
208 static void
209 UseFPE(FontPathElementPtr fpe)
211 fpe->refcount++;
214 static void
215 FreeFPE (FontPathElementPtr fpe)
217 fpe->refcount--;
218 if (fpe->refcount == 0) {
219 (*fpe_functions[fpe->type].free_fpe) (fpe);
220 xfree(fpe->name);
221 xfree(fpe);
225 static Bool
226 doOpenFont(ClientPtr client, OFclosurePtr c)
228 FontPtr pfont = NullFont;
229 FontPathElementPtr fpe = NULL;
230 ScreenPtr pScr;
231 int err = Successful;
232 int i;
233 char *alias,
234 *newname;
235 int newlen;
236 int aliascount = 20;
238 * Decide at runtime what FontFormat to use.
240 Mask FontFormat =
242 ((screenInfo.imageByteOrder == LSBFirst) ?
243 BitmapFormatByteOrderLSB : BitmapFormatByteOrderMSB) |
245 ((screenInfo.bitmapBitOrder == LSBFirst) ?
246 BitmapFormatBitOrderLSB : BitmapFormatBitOrderMSB) |
248 BitmapFormatImageRectMin |
250 #if GLYPHPADBYTES == 1
251 BitmapFormatScanlinePad8 |
252 #endif
254 #if GLYPHPADBYTES == 2
255 BitmapFormatScanlinePad16 |
256 #endif
258 #if GLYPHPADBYTES == 4
259 BitmapFormatScanlinePad32 |
260 #endif
262 #if GLYPHPADBYTES == 8
263 BitmapFormatScanlinePad64 |
264 #endif
266 BitmapFormatScanlineUnit8;
268 if (client->clientGone)
270 if (c->current_fpe < c->num_fpes)
272 fpe = c->fpe_list[c->current_fpe];
273 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
275 err = Successful;
276 goto bail;
278 while (c->current_fpe < c->num_fpes) {
279 fpe = c->fpe_list[c->current_fpe];
280 err = (*fpe_functions[fpe->type].open_font)
281 ((pointer) client, fpe, c->flags,
282 c->fontname, c->fnamelen, FontFormat,
283 BitmapFormatMaskByte |
284 BitmapFormatMaskBit |
285 BitmapFormatMaskImageRectangle |
286 BitmapFormatMaskScanLinePad |
287 BitmapFormatMaskScanLineUnit,
288 c->fontid, &pfont, &alias,
289 c->non_cachable_font && c->non_cachable_font->fpe == fpe ?
290 c->non_cachable_font :
291 (FontPtr)0);
293 if (err == FontNameAlias && alias) {
294 newlen = strlen(alias);
295 newname = (char *) xrealloc(c->fontname, newlen);
296 if (!newname) {
297 err = AllocError;
298 break;
300 memmove(newname, alias, newlen);
301 c->fontname = newname;
302 c->fnamelen = newlen;
303 c->current_fpe = 0;
304 if (--aliascount <= 0)
305 break;
306 continue;
308 if (err == BadFontName) {
309 c->current_fpe++;
310 continue;
312 if (err == Suspended) {
313 if (!c->slept) {
314 c->slept = TRUE;
315 ClientSleep(client, (ClientSleepProcPtr)doOpenFont, (pointer) c);
317 return TRUE;
319 break;
322 if (err != Successful)
323 goto bail;
324 if (!pfont) {
325 err = BadFontName;
326 goto bail;
328 if (!pfont->fpe)
329 pfont->fpe = fpe;
330 pfont->refcnt++;
331 if (pfont->refcnt == 1) {
332 UseFPE(pfont->fpe);
333 for (i = 0; i < screenInfo.numScreens; i++) {
334 pScr = screenInfo.screens[i];
335 if (pScr->RealizeFont)
337 if (!(*pScr->RealizeFont) (pScr, pfont))
339 CloseFont (pfont, (Font) 0);
340 err = AllocError;
341 goto bail;
346 if (!AddResource(c->fontid, RT_FONT, (pointer) pfont)) {
347 err = AllocError;
348 goto bail;
350 if (patternCache && pfont != c->non_cachable_font)
351 CacheFontPattern(patternCache, c->origFontName, c->origFontNameLen,
352 pfont);
353 bail:
354 if (err != Successful && c->client != serverClient) {
355 SendErrorToClient(c->client, X_OpenFont, 0,
356 c->fontid, FontToXError(err));
358 if (c->slept)
359 ClientWakeup(c->client);
360 for (i = 0; i < c->num_fpes; i++) {
361 FreeFPE(c->fpe_list[i]);
363 xfree(c->fpe_list);
364 xfree(c->fontname);
365 xfree(c);
366 return TRUE;
370 OpenFont(ClientPtr client, XID fid, Mask flags, unsigned lenfname, char *pfontname)
372 OFclosurePtr c;
373 int i;
374 FontPtr cached = (FontPtr)0;
376 #ifdef FONTDEBUG
377 char *f;
378 f = (char *)xalloc(lenfname + 1);
379 memmove(f, pfontname, lenfname);
380 f[lenfname] = '\0';
381 ErrorF("OpenFont: fontname is \"%s\"\n", f);
382 xfree(f);
383 #endif
384 if (!lenfname || lenfname > XLFDMAXFONTNAMELEN)
385 return BadName;
386 if (patternCache)
390 ** Check name cache. If we find a cached version of this font that
391 ** is cachable, immediately satisfy the request with it. If we find
392 ** a cached version of this font that is non-cachable, we do not
393 ** satisfy the request with it. Instead, we pass the FontPtr to the
394 ** FPE's open_font code (the fontfile FPE in turn passes the
395 ** information to the rasterizer; the fserve FPE ignores it).
397 ** Presumably, the font is marked non-cachable because the FPE has
398 ** put some licensing restrictions on it. If the FPE, using
399 ** whatever logic it relies on, determines that it is willing to
400 ** share this existing font with the client, then it has the option
401 ** to return the FontPtr we passed it as the newly-opened font.
402 ** This allows the FPE to exercise its licensing logic without
403 ** having to create another instance of a font that already exists.
406 cached = FindCachedFontPattern(patternCache, pfontname, lenfname);
407 if (cached && cached->info.cachable)
409 if (!AddResource(fid, RT_FONT, (pointer) cached))
410 return BadAlloc;
411 cached->refcnt++;
412 return Success;
415 c = (OFclosurePtr) xalloc(sizeof(OFclosureRec));
416 if (!c)
417 return BadAlloc;
418 c->fontname = (char *) xalloc(lenfname);
419 c->origFontName = pfontname;
420 c->origFontNameLen = lenfname;
421 if (!c->fontname) {
422 xfree(c);
423 return BadAlloc;
426 * copy the current FPE list, so that if it gets changed by another client
427 * while we're blocking, the request still appears atomic
429 c->fpe_list = (FontPathElementPtr *)
430 xalloc(sizeof(FontPathElementPtr) * num_fpes);
431 if (!c->fpe_list) {
432 xfree(c->fontname);
433 xfree(c);
434 return BadAlloc;
436 memmove(c->fontname, pfontname, lenfname);
437 for (i = 0; i < num_fpes; i++) {
438 c->fpe_list[i] = font_path_elements[i];
439 UseFPE(c->fpe_list[i]);
441 c->client = client;
442 c->fontid = fid;
443 c->current_fpe = 0;
444 c->num_fpes = num_fpes;
445 c->fnamelen = lenfname;
446 c->slept = FALSE;
447 c->flags = flags;
448 c->non_cachable_font = cached;
450 (void) doOpenFont(client, c);
451 return Success;
455 * Decrement font's ref count, and free storage if ref count equals zero
457 * \param value must conform to DeleteType
459 _X_EXPORT int
460 CloseFont(pointer value, XID fid)
462 int nscr;
463 ScreenPtr pscr;
464 FontPathElementPtr fpe;
465 FontPtr pfont = (FontPtr)value;
467 if (pfont == NullFont)
468 return (Success);
469 if (--pfont->refcnt == 0) {
470 if (patternCache)
471 RemoveCachedFontPattern (patternCache, pfont);
473 * since the last reference is gone, ask each screen to free any
474 * storage it may have allocated locally for it.
476 for (nscr = 0; nscr < screenInfo.numScreens; nscr++) {
477 pscr = screenInfo.screens[nscr];
478 if (pscr->UnrealizeFont)
479 (*pscr->UnrealizeFont) (pscr, pfont);
481 if (pfont == defaultFont)
482 defaultFont = NULL;
483 #ifdef XF86BIGFONT
484 XF86BigfontFreeFontShm(pfont);
485 #endif
486 fpe = pfont->fpe;
487 (*fpe_functions[fpe->type].close_font) (fpe, pfont);
488 FreeFPE(fpe);
490 return (Success);
494 /***====================================================================***/
497 * Sets up pReply as the correct QueryFontReply for pFont with the first
498 * nProtoCCIStructs char infos.
500 * \param pReply caller must allocate this storage
502 void
503 QueryFont(FontPtr pFont, xQueryFontReply *pReply, int nProtoCCIStructs)
505 FontPropPtr pFP;
506 int r,
509 xFontProp *prFP;
510 xCharInfo *prCI;
511 xCharInfo *charInfos[256];
512 unsigned char chars[512];
513 int ninfos;
514 unsigned long ncols;
515 unsigned long count;
517 /* pr->length set in dispatch */
518 pReply->minCharOrByte2 = pFont->info.firstCol;
519 pReply->defaultChar = pFont->info.defaultCh;
520 pReply->maxCharOrByte2 = pFont->info.lastCol;
521 pReply->drawDirection = pFont->info.drawDirection;
522 pReply->allCharsExist = pFont->info.allExist;
523 pReply->minByte1 = pFont->info.firstRow;
524 pReply->maxByte1 = pFont->info.lastRow;
525 pReply->fontAscent = pFont->info.fontAscent;
526 pReply->fontDescent = pFont->info.fontDescent;
528 pReply->minBounds = pFont->info.ink_minbounds;
529 pReply->maxBounds = pFont->info.ink_maxbounds;
531 pReply->nFontProps = pFont->info.nprops;
532 pReply->nCharInfos = nProtoCCIStructs;
534 for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) (&pReply[1]);
535 i < pFont->info.nprops;
536 i++, pFP++, prFP++) {
537 prFP->name = pFP->name;
538 prFP->value = pFP->value;
541 ninfos = 0;
542 ncols = (unsigned long) (pFont->info.lastCol - pFont->info.firstCol + 1);
543 prCI = (xCharInfo *) (prFP);
544 for (r = pFont->info.firstRow;
545 ninfos < nProtoCCIStructs && r <= (int)pFont->info.lastRow;
546 r++) {
547 i = 0;
548 for (c = pFont->info.firstCol; c <= (int)pFont->info.lastCol; c++) {
549 chars[i++] = r;
550 chars[i++] = c;
552 (*pFont->get_metrics) (pFont, ncols, chars,
553 TwoD16Bit, &count, charInfos);
554 i = 0;
555 for (i = 0; i < (int) count && ninfos < nProtoCCIStructs; i++) {
556 *prCI = *charInfos[i];
557 prCI++;
558 ninfos++;
561 return;
564 static Bool
565 doListFontsAndAliases(ClientPtr client, LFclosurePtr c)
567 FontPathElementPtr fpe;
568 int err = Successful;
569 FontNamesPtr names = NULL;
570 char *name, *resolved=NULL;
571 int namelen, resolvedlen;
572 int nnames;
573 int stringLens;
574 int i;
575 xListFontsReply reply;
576 char *bufptr;
577 char *bufferStart;
578 int aliascount = 0;
580 if (client->clientGone)
582 if (c->current.current_fpe < c->num_fpes)
584 fpe = c->fpe_list[c->current.current_fpe];
585 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
587 err = Successful;
588 goto bail;
591 if (!c->current.patlen)
592 goto finish;
594 while (c->current.current_fpe < c->num_fpes) {
595 fpe = c->fpe_list[c->current.current_fpe];
596 err = Successful;
598 if (!fpe_functions[fpe->type].start_list_fonts_and_aliases)
600 /* This FPE doesn't support/require list_fonts_and_aliases */
602 err = (*fpe_functions[fpe->type].list_fonts)
603 ((pointer) c->client, fpe, c->current.pattern,
604 c->current.patlen, c->current.max_names - c->names->nnames,
605 c->names);
607 if (err == Suspended) {
608 if (!c->slept) {
609 c->slept = TRUE;
610 ClientSleep(client,
611 (ClientSleepProcPtr)doListFontsAndAliases,
612 (pointer) c);
614 return TRUE;
617 err = BadFontName;
619 else
621 /* Start of list_fonts_and_aliases functionality. Modeled
622 after list_fonts_with_info in that it resolves aliases,
623 except that the information collected from FPEs is just
624 names, not font info. Each list_next_font_or_alias()
625 returns either a name into name/namelen or an alias into
626 name/namelen and its target name into resolved/resolvedlen.
627 The code at this level then resolves the alias by polling
628 the FPEs. */
630 if (!c->current.list_started) {
631 err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases)
632 ((pointer) c->client, fpe, c->current.pattern,
633 c->current.patlen, c->current.max_names - c->names->nnames,
634 &c->current.private);
635 if (err == Suspended) {
636 if (!c->slept) {
637 ClientSleep(client,
638 (ClientSleepProcPtr)doListFontsAndAliases,
639 (pointer) c);
640 c->slept = TRUE;
642 return TRUE;
644 if (err == Successful)
645 c->current.list_started = TRUE;
647 if (err == Successful) {
648 char *tmpname;
649 name = 0;
650 err = (*fpe_functions[fpe->type].list_next_font_or_alias)
651 ((pointer) c->client, fpe, &name, &namelen, &tmpname,
652 &resolvedlen, c->current.private);
653 if (err == Suspended) {
654 if (!c->slept) {
655 ClientSleep(client,
656 (ClientSleepProcPtr)doListFontsAndAliases,
657 (pointer) c);
658 c->slept = TRUE;
660 return TRUE;
662 if (err == FontNameAlias) {
663 if (resolved) xfree(resolved);
664 resolved = (char *) xalloc(resolvedlen + 1);
665 if (resolved)
666 memmove(resolved, tmpname, resolvedlen + 1);
670 if (err == Successful)
672 if (c->haveSaved)
674 if (c->savedName)
675 (void)AddFontNamesName(c->names, c->savedName,
676 c->savedNameLen);
678 else
679 (void)AddFontNamesName(c->names, name, namelen);
683 * When we get an alias back, save our state and reset back to
684 * the start of the FPE looking for the specified name. As
685 * soon as a real font is found for the alias, pop back to the
686 * old state
688 else if (err == FontNameAlias) {
689 char tmp_pattern[XLFDMAXFONTNAMELEN];
691 * when an alias recurses, we need to give
692 * the last FPE a chance to clean up; so we call
693 * it again, and assume that the error returned
694 * is BadFontName, indicating the alias resolution
695 * is complete.
697 memmove(tmp_pattern, resolved, resolvedlen);
698 if (c->haveSaved)
700 char *tmpname;
701 int tmpnamelen;
703 tmpname = 0;
704 (void) (*fpe_functions[fpe->type].list_next_font_or_alias)
705 ((pointer) c->client, fpe, &tmpname, &tmpnamelen,
706 &tmpname, &tmpnamelen, c->current.private);
707 if (--aliascount <= 0)
709 err = BadFontName;
710 goto ContBadFontName;
713 else
715 c->saved = c->current;
716 c->haveSaved = TRUE;
717 if (c->savedName)
718 xfree(c->savedName);
719 c->savedName = (char *)xalloc(namelen + 1);
720 if (c->savedName)
721 memmove(c->savedName, name, namelen + 1);
722 c->savedNameLen = namelen;
723 aliascount = 20;
725 memmove(c->current.pattern, tmp_pattern, resolvedlen);
726 c->current.patlen = resolvedlen;
727 c->current.max_names = c->names->nnames + 1;
728 c->current.current_fpe = -1;
729 c->current.private = 0;
730 err = BadFontName;
734 * At the end of this FPE, step to the next. If we've finished
735 * processing an alias, pop state back. If we've collected enough
736 * font names, quit.
738 if (err == BadFontName) {
739 ContBadFontName: ;
740 c->current.list_started = FALSE;
741 c->current.current_fpe++;
742 err = Successful;
743 if (c->haveSaved)
745 if (c->names->nnames == c->current.max_names ||
746 c->current.current_fpe == c->num_fpes) {
747 c->haveSaved = FALSE;
748 c->current = c->saved;
749 /* Give the saved namelist a chance to clean itself up */
750 continue;
753 if (c->names->nnames == c->current.max_names)
754 break;
759 * send the reply
761 if (err != Successful) {
762 SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err));
763 goto bail;
766 finish:
768 names = c->names;
769 nnames = names->nnames;
770 client = c->client;
771 stringLens = 0;
772 for (i = 0; i < nnames; i++)
773 stringLens += (names->length[i] <= 255) ? names->length[i] : 0;
775 reply.type = X_Reply;
776 reply.length = (stringLens + nnames + 3) >> 2;
777 reply.nFonts = nnames;
778 reply.sequenceNumber = client->sequence;
780 bufptr = bufferStart = (char *) ALLOCATE_LOCAL(reply.length << 2);
782 if (!bufptr && reply.length) {
783 SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc);
784 goto bail;
787 * since WriteToClient long word aligns things, copy to temp buffer and
788 * write all at once
790 for (i = 0; i < nnames; i++) {
791 if (names->length[i] > 255)
792 reply.nFonts--;
793 else
795 *bufptr++ = names->length[i];
796 memmove( bufptr, names->names[i], names->length[i]);
797 bufptr += names->length[i];
800 nnames = reply.nFonts;
801 reply.length = (stringLens + nnames + 3) >> 2;
802 client->pSwapReplyFunc = ReplySwapVector[X_ListFonts];
803 WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply);
804 (void) WriteToClient(client, stringLens + nnames, bufferStart);
805 DEALLOCATE_LOCAL(bufferStart);
807 bail:
808 if (c->slept)
809 ClientWakeup(client);
810 for (i = 0; i < c->num_fpes; i++)
811 FreeFPE(c->fpe_list[i]);
812 xfree(c->fpe_list);
813 if (c->savedName) xfree(c->savedName);
814 FreeFontNames(names);
815 xfree(c);
816 if (resolved) xfree(resolved);
817 return TRUE;
821 ListFonts(ClientPtr client, unsigned char *pattern, unsigned length,
822 unsigned max_names)
824 int i;
825 LFclosurePtr c;
828 * The right error to return here would be BadName, however the
829 * specification does not allow for a Name error on this request.
830 * Perhaps a better solution would be to return a nil list, i.e.
831 * a list containing zero fontnames.
833 if (length > XLFDMAXFONTNAMELEN)
834 return BadAlloc;
836 if (!(c = (LFclosurePtr) xalloc(sizeof *c)))
837 return BadAlloc;
838 c->fpe_list = (FontPathElementPtr *)
839 xalloc(sizeof(FontPathElementPtr) * num_fpes);
840 if (!c->fpe_list) {
841 xfree(c);
842 return BadAlloc;
844 c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100);
845 if (!c->names)
847 xfree(c->fpe_list);
848 xfree(c);
849 return BadAlloc;
851 memmove( c->current.pattern, pattern, length);
852 for (i = 0; i < num_fpes; i++) {
853 c->fpe_list[i] = font_path_elements[i];
854 UseFPE(c->fpe_list[i]);
856 c->client = client;
857 c->num_fpes = num_fpes;
858 c->current.patlen = length;
859 c->current.current_fpe = 0;
860 c->current.max_names = max_names;
861 c->current.list_started = FALSE;
862 c->current.private = 0;
863 c->haveSaved = FALSE;
864 c->slept = FALSE;
865 c->savedName = 0;
866 doListFontsAndAliases(client, c);
867 return Success;
871 doListFontsWithInfo(ClientPtr client, LFWIclosurePtr c)
873 FontPathElementPtr fpe;
874 int err = Successful;
875 char *name;
876 int namelen;
877 int numFonts;
878 FontInfoRec fontInfo,
879 *pFontInfo;
880 xListFontsWithInfoReply *reply;
881 int length;
882 xFontProp *pFP;
883 int i;
884 int aliascount = 0;
885 xListFontsWithInfoReply finalReply;
887 if (client->clientGone)
889 if (c->current.current_fpe < c->num_fpes)
891 fpe = c->fpe_list[c->current.current_fpe];
892 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
894 err = Successful;
895 goto bail;
897 client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo];
898 if (!c->current.patlen)
899 goto finish;
900 while (c->current.current_fpe < c->num_fpes)
902 fpe = c->fpe_list[c->current.current_fpe];
903 err = Successful;
904 if (!c->current.list_started)
906 err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
907 (client, fpe, c->current.pattern, c->current.patlen,
908 c->current.max_names, &c->current.private);
909 if (err == Suspended)
911 if (!c->slept)
913 ClientSleep(client, (ClientSleepProcPtr)doListFontsWithInfo, c);
914 c->slept = TRUE;
916 return TRUE;
918 if (err == Successful)
919 c->current.list_started = TRUE;
921 if (err == Successful)
923 name = 0;
924 pFontInfo = &fontInfo;
925 err = (*fpe_functions[fpe->type].list_next_font_with_info)
926 (client, fpe, &name, &namelen, &pFontInfo,
927 &numFonts, c->current.private);
928 if (err == Suspended)
930 if (!c->slept)
932 ClientSleep(client,
933 (ClientSleepProcPtr)doListFontsWithInfo,
935 c->slept = TRUE;
937 return TRUE;
941 * When we get an alias back, save our state and reset back to the
942 * start of the FPE looking for the specified name. As soon as a real
943 * font is found for the alias, pop back to the old state
945 if (err == FontNameAlias)
948 * when an alias recurses, we need to give
949 * the last FPE a chance to clean up; so we call
950 * it again, and assume that the error returned
951 * is BadFontName, indicating the alias resolution
952 * is complete.
954 if (c->haveSaved)
956 char *tmpname;
957 int tmpnamelen;
958 FontInfoPtr tmpFontInfo;
960 tmpname = 0;
961 tmpFontInfo = &fontInfo;
962 (void) (*fpe_functions[fpe->type].list_next_font_with_info)
963 (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo,
964 &numFonts, c->current.private);
965 if (--aliascount <= 0)
967 err = BadFontName;
968 goto ContBadFontName;
971 else
973 c->saved = c->current;
974 c->haveSaved = TRUE;
975 c->savedNumFonts = numFonts;
976 if (c->savedName)
977 xfree(c->savedName);
978 c->savedName = (char *)xalloc(namelen + 1);
979 if (c->savedName)
980 memmove(c->savedName, name, namelen + 1);
981 aliascount = 20;
983 memmove(c->current.pattern, name, namelen);
984 c->current.patlen = namelen;
985 c->current.max_names = 1;
986 c->current.current_fpe = 0;
987 c->current.private = 0;
988 c->current.list_started = FALSE;
991 * At the end of this FPE, step to the next. If we've finished
992 * processing an alias, pop state back. If we've sent enough font
993 * names, quit. Always wait for BadFontName to let the FPE
994 * have a chance to clean up.
996 else if (err == BadFontName)
998 ContBadFontName: ;
999 c->current.list_started = FALSE;
1000 c->current.current_fpe++;
1001 err = Successful;
1002 if (c->haveSaved)
1004 if (c->current.max_names == 0 ||
1005 c->current.current_fpe == c->num_fpes)
1007 c->haveSaved = FALSE;
1008 c->saved.max_names -= (1 - c->current.max_names);
1009 c->current = c->saved;
1012 else if (c->current.max_names == 0)
1013 break;
1015 else if (err == Successful)
1017 length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp);
1018 reply = c->reply;
1019 if (c->length < length)
1021 reply = (xListFontsWithInfoReply *) xrealloc(c->reply, length);
1022 if (!reply)
1024 err = AllocError;
1025 break;
1027 c->reply = reply;
1028 c->length = length;
1030 if (c->haveSaved)
1032 numFonts = c->savedNumFonts;
1033 name = c->savedName;
1034 namelen = strlen(name);
1036 reply->type = X_Reply;
1037 reply->length = (sizeof *reply - sizeof(xGenericReply) +
1038 pFontInfo->nprops * sizeof(xFontProp) +
1039 namelen + 3) >> 2;
1040 reply->sequenceNumber = client->sequence;
1041 reply->nameLength = namelen;
1042 reply->minBounds = pFontInfo->ink_minbounds;
1043 reply->maxBounds = pFontInfo->ink_maxbounds;
1044 reply->minCharOrByte2 = pFontInfo->firstCol;
1045 reply->maxCharOrByte2 = pFontInfo->lastCol;
1046 reply->defaultChar = pFontInfo->defaultCh;
1047 reply->nFontProps = pFontInfo->nprops;
1048 reply->drawDirection = pFontInfo->drawDirection;
1049 reply->minByte1 = pFontInfo->firstRow;
1050 reply->maxByte1 = pFontInfo->lastRow;
1051 reply->allCharsExist = pFontInfo->allExist;
1052 reply->fontAscent = pFontInfo->fontAscent;
1053 reply->fontDescent = pFontInfo->fontDescent;
1054 reply->nReplies = numFonts;
1055 pFP = (xFontProp *) (reply + 1);
1056 for (i = 0; i < pFontInfo->nprops; i++)
1058 pFP->name = pFontInfo->props[i].name;
1059 pFP->value = pFontInfo->props[i].value;
1060 pFP++;
1062 WriteSwappedDataToClient(client, length, reply);
1063 (void) WriteToClient(client, namelen, name);
1064 if (pFontInfo == &fontInfo)
1066 xfree(fontInfo.props);
1067 xfree(fontInfo.isStringProp);
1069 --c->current.max_names;
1072 finish:
1073 length = sizeof(xListFontsWithInfoReply);
1074 bzero((char *) &finalReply, sizeof(xListFontsWithInfoReply));
1075 finalReply.type = X_Reply;
1076 finalReply.sequenceNumber = client->sequence;
1077 finalReply.length = (sizeof(xListFontsWithInfoReply)
1078 - sizeof(xGenericReply)) >> 2;
1079 WriteSwappedDataToClient(client, length, &finalReply);
1080 bail:
1081 if (c->slept)
1082 ClientWakeup(client);
1083 for (i = 0; i < c->num_fpes; i++)
1084 FreeFPE(c->fpe_list[i]);
1085 xfree(c->reply);
1086 xfree(c->fpe_list);
1087 if (c->savedName) xfree(c->savedName);
1088 xfree(c);
1089 return TRUE;
1093 StartListFontsWithInfo(ClientPtr client, int length, unsigned char *pattern,
1094 int max_names)
1096 int i;
1097 LFWIclosurePtr c;
1100 * The right error to return here would be BadName, however the
1101 * specification does not allow for a Name error on this request.
1102 * Perhaps a better solution would be to return a nil list, i.e.
1103 * a list containing zero fontnames.
1105 if (length > XLFDMAXFONTNAMELEN)
1106 return BadAlloc;
1108 if (!(c = (LFWIclosurePtr) xalloc(sizeof *c)))
1109 goto badAlloc;
1110 c->fpe_list = (FontPathElementPtr *)
1111 xalloc(sizeof(FontPathElementPtr) * num_fpes);
1112 if (!c->fpe_list)
1114 xfree(c);
1115 goto badAlloc;
1117 memmove(c->current.pattern, pattern, length);
1118 for (i = 0; i < num_fpes; i++)
1120 c->fpe_list[i] = font_path_elements[i];
1121 UseFPE(c->fpe_list[i]);
1123 c->client = client;
1124 c->num_fpes = num_fpes;
1125 c->reply = 0;
1126 c->length = 0;
1127 c->current.patlen = length;
1128 c->current.current_fpe = 0;
1129 c->current.max_names = max_names;
1130 c->current.list_started = FALSE;
1131 c->current.private = 0;
1132 c->savedNumFonts = 0;
1133 c->haveSaved = FALSE;
1134 c->slept = FALSE;
1135 c->savedName = 0;
1136 doListFontsWithInfo(client, c);
1137 return Success;
1138 badAlloc:
1139 return BadAlloc;
1142 #define TextEltHeader 2
1143 #define FontShiftSize 5
1144 static XID clearGC[] = { CT_NONE };
1145 #define clearGCmask (GCClipMask)
1148 doPolyText(ClientPtr client, PTclosurePtr c)
1150 FontPtr pFont = c->pGC->font, oldpFont;
1151 Font fid, oldfid;
1152 int err = Success, lgerr; /* err is in X error, not font error, space */
1153 enum { NEVER_SLEPT, START_SLEEP, SLEEPING } client_state = NEVER_SLEPT;
1154 FontPathElementPtr fpe;
1155 GC *origGC = NULL;
1157 if (client->clientGone)
1159 fpe = c->pGC->font->fpe;
1160 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1162 if (c->slept)
1164 /* Client has died, but we cannot bail out right now. We
1165 need to clean up after the work we did when going to
1166 sleep. Setting the drawable pointer to 0 makes this
1167 happen without any attempts to render or perform other
1168 unnecessary activities. */
1169 c->pDraw = (DrawablePtr)0;
1171 else
1173 err = Success;
1174 goto bail;
1178 /* Make sure our drawable hasn't disappeared while we slept. */
1179 if (c->slept &&
1180 c->pDraw &&
1181 c->pDraw != (DrawablePtr)SecurityLookupIDByClass(client, c->did,
1182 RC_DRAWABLE, DixWriteAccess))
1184 /* Our drawable has disappeared. Treat like client died... ask
1185 the FPE code to clean up after client and avoid further
1186 rendering while we clean up after ourself. */
1187 fpe = c->pGC->font->fpe;
1188 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1189 c->pDraw = (DrawablePtr)0;
1192 client_state = c->slept ? SLEEPING : NEVER_SLEPT;
1194 while (c->endReq - c->pElt > TextEltHeader)
1196 if (*c->pElt == FontChange)
1198 if (c->endReq - c->pElt < FontShiftSize)
1200 err = BadLength;
1201 goto bail;
1204 oldpFont = pFont;
1205 oldfid = fid;
1207 fid = ((Font)*(c->pElt+4)) /* big-endian */
1208 | ((Font)*(c->pElt+3)) << 8
1209 | ((Font)*(c->pElt+2)) << 16
1210 | ((Font)*(c->pElt+1)) << 24;
1211 pFont = (FontPtr)SecurityLookupIDByType(client, fid, RT_FONT,
1212 DixReadAccess);
1213 if (!pFont)
1215 client->errorValue = fid;
1216 err = BadFont;
1217 /* restore pFont and fid for step 4 (described below) */
1218 pFont = oldpFont;
1219 fid = oldfid;
1221 /* If we're in START_SLEEP mode, the following step
1222 shortens the request... in the unlikely event that
1223 the fid somehow becomes valid before we come through
1224 again to actually execute the polytext, which would
1225 then mess up our refcounting scheme badly. */
1226 c->err = err;
1227 c->endReq = c->pElt;
1229 goto bail;
1232 /* Step 3 (described below) on our new font */
1233 if (client_state == START_SLEEP)
1234 pFont->refcnt++;
1235 else
1237 if (pFont != c->pGC->font && c->pDraw)
1239 ChangeGC( c->pGC, GCFont, &fid);
1240 ValidateGC(c->pDraw, c->pGC);
1241 if (c->reqType == X_PolyText8)
1242 c->polyText = (PolyTextPtr) c->pGC->ops->PolyText8;
1243 else
1244 c->polyText = (PolyTextPtr) c->pGC->ops->PolyText16;
1247 /* Undo the refcnt++ we performed when going to sleep */
1248 if (client_state == SLEEPING)
1249 (void)CloseFont(c->pGC->font, (Font)0);
1251 c->pElt += FontShiftSize;
1253 else /* print a string */
1255 unsigned char *pNextElt;
1256 pNextElt = c->pElt + TextEltHeader + (*c->pElt)*c->itemSize;
1257 if ( pNextElt > c->endReq)
1259 err = BadLength;
1260 goto bail;
1262 if (client_state == START_SLEEP)
1264 c->pElt = pNextElt;
1265 continue;
1267 if (c->pDraw)
1269 lgerr = LoadGlyphs(client, c->pGC->font, *c->pElt, c->itemSize,
1270 c->pElt + TextEltHeader);
1272 else lgerr = Successful;
1274 if (lgerr == Suspended)
1276 if (!c->slept) {
1277 int len;
1278 GC *pGC;
1279 PTclosurePtr new_closure;
1281 /* We're putting the client to sleep. We need to do a few things
1282 to ensure successful and atomic-appearing execution of the
1283 remainder of the request. First, copy the remainder of the
1284 request into a safe malloc'd area. Second, create a scratch GC
1285 to use for the remainder of the request. Third, mark all fonts
1286 referenced in the remainder of the request to prevent their
1287 deallocation. Fourth, make the original GC look like the
1288 request has completed... set its font to the final font value
1289 from this request. These GC manipulations are for the unlikely
1290 (but possible) event that some other client is using the GC.
1291 Steps 3 and 4 are performed by running this procedure through
1292 the remainder of the request in a special no-render mode
1293 indicated by client_state = START_SLEEP. */
1295 /* Step 1 */
1296 /* Allocate a malloc'd closure structure to replace
1297 the local one we were passed */
1298 new_closure = (PTclosurePtr) xalloc(sizeof(PTclosureRec));
1299 if (!new_closure)
1301 err = BadAlloc;
1302 goto bail;
1304 *new_closure = *c;
1305 c = new_closure;
1307 len = c->endReq - c->pElt;
1308 c->data = (unsigned char *)xalloc(len);
1309 if (!c->data)
1311 xfree(c);
1312 err = BadAlloc;
1313 goto bail;
1315 memmove(c->data, c->pElt, len);
1316 c->pElt = c->data;
1317 c->endReq = c->pElt + len;
1319 /* Step 2 */
1321 pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
1322 if (!pGC)
1324 xfree(c->data);
1325 xfree(c);
1326 err = BadAlloc;
1327 goto bail;
1329 if ((err = CopyGC(c->pGC, pGC, GCFunction |
1330 GCPlaneMask | GCForeground |
1331 GCBackground | GCFillStyle |
1332 GCTile | GCStipple |
1333 GCTileStipXOrigin |
1334 GCTileStipYOrigin | GCFont |
1335 GCSubwindowMode | GCClipXOrigin |
1336 GCClipYOrigin | GCClipMask)) !=
1337 Success)
1339 FreeScratchGC(pGC);
1340 xfree(c->data);
1341 xfree(c);
1342 err = BadAlloc;
1343 goto bail;
1345 origGC = c->pGC;
1346 c->pGC = pGC;
1347 ValidateGC(c->pDraw, c->pGC);
1349 c->slept = TRUE;
1350 ClientSleep(client,
1351 (ClientSleepProcPtr)doPolyText,
1352 (pointer) c);
1354 /* Set up to perform steps 3 and 4 */
1355 client_state = START_SLEEP;
1356 continue; /* on to steps 3 and 4 */
1358 return TRUE;
1360 else if (lgerr != Successful)
1362 err = FontToXError(lgerr);
1363 goto bail;
1365 if (c->pDraw)
1367 c->xorg += *((INT8 *)(c->pElt + 1)); /* must be signed */
1368 c->xorg = (* c->polyText)(c->pDraw, c->pGC, c->xorg, c->yorg,
1369 *c->pElt, c->pElt + TextEltHeader);
1371 c->pElt = pNextElt;
1375 bail:
1377 if (client_state == START_SLEEP)
1379 /* Step 4 */
1380 if (pFont != origGC->font)
1382 ChangeGC(origGC, GCFont, &fid);
1383 ValidateGC(c->pDraw, origGC);
1386 /* restore pElt pointer for execution of remainder of the request */
1387 c->pElt = c->data;
1388 return TRUE;
1391 if (c->err != Success) err = c->err;
1392 if (err != Success && c->client != serverClient) {
1393 #ifdef PANORAMIX
1394 if (noPanoramiXExtension || !c->pGC->pScreen->myNum)
1395 #endif
1396 SendErrorToClient(c->client, c->reqType, 0, 0, err);
1398 if (c->slept)
1400 ClientWakeup(c->client);
1401 ChangeGC(c->pGC, clearGCmask, clearGC);
1403 /* Unreference the font from the scratch GC */
1404 CloseFont(c->pGC->font, (Font)0);
1405 c->pGC->font = NullFont;
1407 FreeScratchGC(c->pGC);
1408 xfree(c->data);
1409 xfree(c);
1411 return TRUE;
1415 PolyText(ClientPtr client, DrawablePtr pDraw, GC *pGC, unsigned char *pElt,
1416 unsigned char *endReq, int xorg, int yorg, int reqType, XID did)
1418 PTclosureRec local_closure;
1420 local_closure.pElt = pElt;
1421 local_closure.endReq = endReq;
1422 local_closure.client = client;
1423 local_closure.pDraw = pDraw;
1424 local_closure.xorg = xorg;
1425 local_closure.yorg = yorg;
1426 if ((local_closure.reqType = reqType) == X_PolyText8)
1428 local_closure.polyText = (PolyTextPtr) pGC->ops->PolyText8;
1429 local_closure.itemSize = 1;
1431 else
1433 local_closure.polyText = (PolyTextPtr) pGC->ops->PolyText16;
1434 local_closure.itemSize = 2;
1436 local_closure.pGC = pGC;
1437 local_closure.did = did;
1438 local_closure.err = Success;
1439 local_closure.slept = FALSE;
1441 (void) doPolyText(client, &local_closure);
1442 return Success;
1446 #undef TextEltHeader
1447 #undef FontShiftSize
1450 doImageText(ClientPtr client, ITclosurePtr c)
1452 int err = Success, lgerr; /* err is in X error, not font error, space */
1453 FontPathElementPtr fpe;
1455 if (client->clientGone)
1457 fpe = c->pGC->font->fpe;
1458 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1459 err = Success;
1460 goto bail;
1463 /* Make sure our drawable hasn't disappeared while we slept. */
1464 if (c->slept &&
1465 c->pDraw &&
1466 c->pDraw != (DrawablePtr)SecurityLookupIDByClass(client, c->did,
1467 RC_DRAWABLE, DixWriteAccess))
1469 /* Our drawable has disappeared. Treat like client died... ask
1470 the FPE code to clean up after client. */
1471 fpe = c->pGC->font->fpe;
1472 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1473 err = Success;
1474 goto bail;
1477 lgerr = LoadGlyphs(client, c->pGC->font, c->nChars, c->itemSize, c->data);
1478 if (lgerr == Suspended)
1480 if (!c->slept) {
1481 GC *pGC;
1482 unsigned char *data;
1483 ITclosurePtr new_closure;
1485 /* We're putting the client to sleep. We need to
1486 save some state. Similar problem to that handled
1487 in doPolyText, but much simpler because the
1488 request structure is much simpler. */
1490 new_closure = (ITclosurePtr) xalloc(sizeof(ITclosureRec));
1491 if (!new_closure)
1493 err = BadAlloc;
1494 goto bail;
1496 *new_closure = *c;
1497 c = new_closure;
1499 data = (unsigned char *)xalloc(c->nChars * c->itemSize);
1500 if (!data)
1502 xfree(c);
1503 err = BadAlloc;
1504 goto bail;
1506 memmove(data, c->data, c->nChars * c->itemSize);
1507 c->data = data;
1509 pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
1510 if (!pGC)
1512 xfree(c->data);
1513 xfree(c);
1514 err = BadAlloc;
1515 goto bail;
1517 if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask |
1518 GCForeground | GCBackground | GCFillStyle |
1519 GCTile | GCStipple | GCTileStipXOrigin |
1520 GCTileStipYOrigin | GCFont |
1521 GCSubwindowMode | GCClipXOrigin |
1522 GCClipYOrigin | GCClipMask)) != Success)
1524 FreeScratchGC(pGC);
1525 xfree(c->data);
1526 xfree(c);
1527 err = BadAlloc;
1528 goto bail;
1530 c->pGC = pGC;
1531 ValidateGC(c->pDraw, c->pGC);
1533 c->slept = TRUE;
1534 ClientSleep(client, (ClientSleepProcPtr)doImageText, (pointer) c);
1536 return TRUE;
1538 else if (lgerr != Successful)
1540 err = FontToXError(lgerr);
1541 goto bail;
1543 if (c->pDraw)
1545 (* c->imageText)(c->pDraw, c->pGC, c->xorg, c->yorg,
1546 c->nChars, c->data);
1549 bail:
1551 if (err != Success && c->client != serverClient) {
1552 SendErrorToClient(c->client, c->reqType, 0, 0, err);
1554 if (c->slept)
1556 ClientWakeup(c->client);
1557 ChangeGC(c->pGC, clearGCmask, clearGC);
1559 /* Unreference the font from the scratch GC */
1560 CloseFont(c->pGC->font, (Font)0);
1561 c->pGC->font = NullFont;
1563 FreeScratchGC(c->pGC);
1564 xfree(c->data);
1565 xfree(c);
1567 return TRUE;
1571 ImageText(ClientPtr client, DrawablePtr pDraw, GC *pGC, int nChars,
1572 unsigned char *data, int xorg, int yorg, int reqType, XID did)
1574 ITclosureRec local_closure;
1576 local_closure.client = client;
1577 local_closure.pDraw = pDraw;
1578 local_closure.pGC = pGC;
1579 local_closure.nChars = nChars;
1580 local_closure.data = data;
1581 local_closure.xorg = xorg;
1582 local_closure.yorg = yorg;
1583 if ((local_closure.reqType = reqType) == X_ImageText8)
1585 local_closure.imageText = (ImageTextPtr) pGC->ops->ImageText8;
1586 local_closure.itemSize = 1;
1588 else
1590 local_closure.imageText = (ImageTextPtr) pGC->ops->ImageText16;
1591 local_closure.itemSize = 2;
1593 local_closure.did = did;
1594 local_closure.slept = FALSE;
1596 (void) doImageText(client, &local_closure);
1597 return Success;
1601 /* does the necessary magic to figure out the fpe type */
1602 static int
1603 DetermineFPEType(char *pathname)
1605 int i;
1607 for (i = 0; i < num_fpe_types; i++) {
1608 if ((*fpe_functions[i].name_check) (pathname))
1609 return i;
1611 return -1;
1615 static void
1616 FreeFontPath(FontPathElementPtr *list, int n, Bool force)
1618 int i;
1620 for (i = 0; i < n; i++) {
1621 if (force) {
1622 /* Sanity check that all refcounts will be 0 by the time
1623 we get to the end of the list. */
1624 int found = 1; /* the first reference is us */
1625 int j;
1626 for (j = i+1; j < n; j++) {
1627 if (list[j] == list[i])
1628 found++;
1630 if (list[i]->refcount != found) {
1631 ErrorF("FreeFontPath: FPE \"%.*s\" refcount is %d, should be %d; fixing.\n",
1632 list[i]->name_length, list[i]->name,
1633 list[i]->refcount, found);
1634 list[i]->refcount = found; /* ensure it will get freed */
1637 FreeFPE(list[i]);
1639 xfree((char *) list);
1642 static FontPathElementPtr
1643 find_existing_fpe(FontPathElementPtr *list, int num, unsigned char *name, int len)
1645 FontPathElementPtr fpe;
1646 int i;
1648 for (i = 0; i < num; i++) {
1649 fpe = list[i];
1650 if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0)
1651 return fpe;
1653 return (FontPathElementPtr) 0;
1657 static int
1658 SetFontPathElements(int npaths, unsigned char *paths, int *bad, Bool persist)
1660 int i, err = 0;
1661 int valid_paths = 0;
1662 unsigned int len;
1663 unsigned char *cp = paths;
1664 FontPathElementPtr fpe = NULL, *fplist;
1666 fplist = (FontPathElementPtr *)
1667 xalloc(sizeof(FontPathElementPtr) * npaths);
1668 if (!fplist) {
1669 *bad = 0;
1670 return BadAlloc;
1672 for (i = 0; i < num_fpe_types; i++) {
1673 if (fpe_functions[i].set_path_hook)
1674 (*fpe_functions[i].set_path_hook) ();
1676 for (i = 0; i < npaths; i++)
1678 len = (unsigned int) (*cp++);
1680 if (len == 0)
1682 if (persist)
1683 ErrorF ("Removing empty element from the valid list of fontpaths\n");
1684 err = BadValue;
1686 else
1688 /* if it's already in our active list, just reset it */
1690 * note that this can miss FPE's in limbo -- may be worth catching
1691 * them, though it'd muck up refcounting
1693 fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len);
1694 if (fpe)
1696 err = (*fpe_functions[fpe->type].reset_fpe) (fpe);
1697 if (err == Successful)
1699 UseFPE(fpe);/* since it'll be decref'd later when freed
1700 * from the old list */
1702 else
1703 fpe = 0;
1705 /* if error or can't do it, act like it's a new one */
1706 if (!fpe)
1708 fpe = (FontPathElementPtr) xalloc(sizeof(FontPathElementRec));
1709 if (!fpe)
1711 err = BadAlloc;
1712 goto bail;
1714 fpe->name = (char *) xalloc(len + 1);
1715 if (!fpe->name)
1717 xfree(fpe);
1718 err = BadAlloc;
1719 goto bail;
1721 fpe->refcount = 1;
1723 strncpy(fpe->name, (char *) cp, (int) len);
1724 fpe->name[len] = '\0';
1725 fpe->name_length = len;
1726 fpe->type = DetermineFPEType(fpe->name);
1727 if (fpe->type == -1)
1728 err = BadValue;
1729 else
1730 err = (*fpe_functions[fpe->type].init_fpe) (fpe);
1731 if (err != Successful)
1733 if (persist)
1735 ErrorF("Could not init font path element %s, removing from list!\n",
1736 fpe->name);
1738 xfree (fpe->name);
1739 xfree (fpe);
1743 if (err != Successful)
1745 if (!persist)
1746 goto bail;
1748 else
1750 fplist[valid_paths++] = fpe;
1752 cp += len;
1755 FreeFontPath(font_path_elements, num_fpes, FALSE);
1756 font_path_elements = fplist;
1757 if (patternCache)
1758 EmptyFontPatternCache(patternCache);
1759 num_fpes = valid_paths;
1761 return Success;
1762 bail:
1763 *bad = i;
1764 while (--valid_paths >= 0)
1765 FreeFPE(fplist[valid_paths]);
1766 xfree(fplist);
1767 return FontToXError(err);
1770 /* XXX -- do we need to pass error down to each renderer? */
1772 SetFontPath(ClientPtr client, int npaths, unsigned char *paths, int *error)
1774 int err = Success;
1776 if (npaths == 0) {
1777 if (SetDefaultFontPath(defaultFontPath) != Success)
1778 return BadValue;
1779 } else {
1780 err = SetFontPathElements(npaths, paths, error, FALSE);
1782 return err;
1786 SetDefaultFontPath(char *path)
1788 unsigned char *cp,
1789 *pp,
1790 *nump,
1791 *newpath;
1792 int num = 1,
1793 len,
1794 err,
1795 size = 0,
1796 bad;
1798 /* get enough for string, plus values -- use up commas */
1799 len = strlen(path) + 1;
1800 nump = cp = newpath = (unsigned char *) ALLOCATE_LOCAL(len);
1801 if (!newpath)
1802 return BadAlloc;
1803 pp = (unsigned char *) path;
1804 cp++;
1805 while (*pp) {
1806 if (*pp == ',') {
1807 *nump = (unsigned char) size;
1808 nump = cp++;
1809 pp++;
1810 num++;
1811 size = 0;
1812 } else {
1813 *cp++ = *pp++;
1814 size++;
1817 *nump = (unsigned char) size;
1819 err = SetFontPathElements(num, newpath, &bad, TRUE);
1821 DEALLOCATE_LOCAL(newpath);
1823 return err;
1826 unsigned char *
1827 GetFontPath(int *count, int *length)
1829 int i;
1830 unsigned char *c;
1831 int len;
1832 FontPathElementPtr fpe;
1834 len = 0;
1835 for (i = 0; i < num_fpes; i++) {
1836 fpe = font_path_elements[i];
1837 len += fpe->name_length + 1;
1839 font_path_string = (unsigned char *) xrealloc(font_path_string, len);
1840 if (!font_path_string)
1841 return NULL;
1843 c = font_path_string;
1844 *length = 0;
1845 for (i = 0; i < num_fpes; i++) {
1846 fpe = font_path_elements[i];
1847 *c = fpe->name_length;
1848 *length += *c++;
1849 memmove(c, fpe->name, fpe->name_length);
1850 c += fpe->name_length;
1852 *count = num_fpes;
1853 return font_path_string;
1856 _X_EXPORT int
1857 LoadGlyphs(ClientPtr client, FontPtr pfont, unsigned nchars, int item_size, unsigned char *data)
1859 if (fpe_functions[pfont->fpe->type].load_glyphs)
1860 return (*fpe_functions[pfont->fpe->type].load_glyphs)
1861 (client, pfont, 0, nchars, item_size, data);
1862 else
1863 return Successful;
1866 void
1867 DeleteClientFontStuff(ClientPtr client)
1869 int i;
1870 FontPathElementPtr fpe;
1872 for (i = 0; i < num_fpes; i++)
1874 fpe = font_path_elements[i];
1875 if (fpe_functions[fpe->type].client_died)
1876 (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1880 void
1881 InitFonts (void)
1883 patternCache = MakeFontPatternCache();
1885 #ifndef BUILTIN_FONTS
1886 if (screenInfo.numScreens > screenInfo.numVideoScreens) {
1887 PrinterFontRegisterFpeFunctions();
1888 FontFileCheckRegisterFpeFunctions();
1889 check_fs_register_fpe_functions();
1890 } else
1891 #endif
1893 #ifdef BUILTIN_FONTS
1894 BuiltinRegisterFpeFunctions();
1895 #else
1896 FontFileRegisterFpeFunctions();
1897 #endif
1898 #ifndef NOFONTSERVERACCESS
1899 fs_register_fpe_functions();
1900 #endif
1905 GetDefaultPointSize ()
1907 return 120;
1911 FontResolutionPtr
1912 GetClientResolutions (int *num)
1914 if (requestingClient && requestingClient->fontResFunc != NULL &&
1915 !requestingClient->clientGone)
1917 return (*requestingClient->fontResFunc)(requestingClient, num);
1919 else {
1920 static struct _FontResolution res;
1921 ScreenPtr pScreen;
1923 pScreen = screenInfo.screens[0];
1924 res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth;
1926 * XXX - we'll want this as long as bitmap instances are prevalent
1927 so that we can match them from scalable fonts
1929 if (res.x_resolution < 88)
1930 res.x_resolution = 75;
1931 else
1932 res.x_resolution = 100;
1933 res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight;
1934 if (res.y_resolution < 88)
1935 res.y_resolution = 75;
1936 else
1937 res.y_resolution = 100;
1938 res.point_size = 120;
1939 *num = 1;
1940 return &res;
1945 * returns the type index of the new fpe
1947 * should be called (only once!) by each type of fpe when initialized
1951 RegisterFPEFunctions(NameCheckFunc name_func,
1952 InitFpeFunc init_func,
1953 FreeFpeFunc free_func,
1954 ResetFpeFunc reset_func,
1955 OpenFontFunc open_func,
1956 CloseFontFunc close_func,
1957 ListFontsFunc list_func,
1958 StartLfwiFunc start_lfwi_func,
1959 NextLfwiFunc next_lfwi_func,
1960 WakeupFpeFunc wakeup_func,
1961 ClientDiedFunc client_died,
1962 LoadGlyphsFunc load_glyphs,
1963 StartLaFunc start_list_alias_func,
1964 NextLaFunc next_list_alias_func,
1965 SetPathFunc set_path_func)
1967 FPEFunctions *new;
1969 /* grow the list */
1970 new = (FPEFunctions *) xrealloc(fpe_functions,
1971 (num_fpe_types + 1) * sizeof(FPEFunctions));
1972 if (!new)
1973 return -1;
1974 fpe_functions = new;
1976 fpe_functions[num_fpe_types].name_check = name_func;
1977 fpe_functions[num_fpe_types].open_font = open_func;
1978 fpe_functions[num_fpe_types].close_font = close_func;
1979 fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func;
1980 fpe_functions[num_fpe_types].list_fonts = list_func;
1981 fpe_functions[num_fpe_types].start_list_fonts_with_info =
1982 start_lfwi_func;
1983 fpe_functions[num_fpe_types].list_next_font_with_info =
1984 next_lfwi_func;
1985 fpe_functions[num_fpe_types].init_fpe = init_func;
1986 fpe_functions[num_fpe_types].free_fpe = free_func;
1987 fpe_functions[num_fpe_types].reset_fpe = reset_func;
1988 fpe_functions[num_fpe_types].client_died = client_died;
1989 fpe_functions[num_fpe_types].load_glyphs = load_glyphs;
1990 fpe_functions[num_fpe_types].start_list_fonts_and_aliases =
1991 start_list_alias_func;
1992 fpe_functions[num_fpe_types].list_next_font_or_alias =
1993 next_list_alias_func;
1994 fpe_functions[num_fpe_types].set_path_hook = set_path_func;
1996 return num_fpe_types++;
1999 void
2000 FreeFonts(void)
2002 if (patternCache) {
2003 FreeFontPatternCache(patternCache);
2004 patternCache = 0;
2006 FreeFontPath(font_path_elements, num_fpes, TRUE);
2007 font_path_elements = 0;
2008 num_fpes = 0;
2009 xfree(fpe_functions);
2010 num_fpe_types = 0;
2011 fpe_functions = (FPEFunctions *) 0;
2014 /* convenience functions for FS interface */
2016 FontPtr
2017 find_old_font(XID id)
2019 return (FontPtr) SecurityLookupIDByType(NullClient, id, RT_NONE,
2020 DixUnknownAccess);
2023 Font
2024 GetNewFontClientID()
2026 return FakeClientID(0);
2030 StoreFontClientFont(FontPtr pfont, Font id)
2032 return AddResource(id, RT_NONE, (pointer) pfont);
2035 void
2036 DeleteFontClientID(Font id)
2038 FreeResource(id, RT_NONE);
2042 client_auth_generation(ClientPtr client)
2044 return 0;
2047 static int fs_handlers_installed = 0;
2048 static unsigned int last_server_gen;
2051 init_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler)
2053 /* if server has reset, make sure the b&w handlers are reinstalled */
2054 if (last_server_gen < serverGeneration) {
2055 last_server_gen = serverGeneration;
2056 fs_handlers_installed = 0;
2058 if (fs_handlers_installed == 0) {
2059 if (!RegisterBlockAndWakeupHandlers(block_handler,
2060 FontWakeup, (pointer) 0))
2061 return AllocError;
2062 fs_handlers_installed++;
2064 QueueFontWakeup(fpe);
2065 return Successful;
2068 void
2069 remove_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler, Bool all)
2071 if (all) {
2072 /* remove the handlers if no one else is using them */
2073 if (--fs_handlers_installed == 0) {
2074 RemoveBlockAndWakeupHandlers(block_handler, FontWakeup,
2075 (pointer) 0);
2078 RemoveFontWakeup(fpe);