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