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