Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright  2000 Keith Packard
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that
      7  * copyright notice and this permission notice appear in supporting
      8  * documentation, and that the name of Keith Packard not be used in
      9  * advertising or publicity pertaining to distribution of the software without
     10  * specific, written prior permission.  Keith Packard makes no
     11  * representations about the suitability of this software for any purpose.  It
     12  * is provided "as is" without express or implied warranty.
     13  *
     14  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     20  * PERFORMANCE OF THIS SOFTWARE.
     21  */
     22 
     23 #include "xftint.h"
     24 
     25 #define BtoS(b) ((b) ? "true" : "false")
     26 
     27 _X_HIDDEN XftDisplayInfo	*_XftDisplayInfo;
     28 
     29 static int
     30 _XftCloseDisplay (Display *dpy, XExtCodes *codes _X_UNUSED)
     31 {
     32     XftDisplayInfo  *info, **prev;
     33 
     34     info = _XftDisplayInfoGet (dpy, FcFalse);
     35     if (!info)
     36 	return 0;
     37 
     38     /*
     39      * Get rid of any dangling unreferenced fonts
     40      */
     41     info->max_unref_fonts = 0;
     42     XftFontManageMemory (dpy);
     43 
     44     /*
     45      * Clean up the default values
     46      */
     47     if (info->defaults)
     48 	FcPatternDestroy (info->defaults);
     49 
     50     /*
     51      * Unhook from the global list
     52      */
     53     for (prev = &_XftDisplayInfo; (info = *prev); prev = &(*prev)->next)
     54 	if (info->display == dpy)
     55 	    break;
     56     if (info != NULL)
     57 	*prev = info->next;
     58 
     59     free (info);
     60     return 0;
     61 }
     62 
     63 
     64 _X_HIDDEN XftDisplayInfo *
     65 _XftDisplayInfoGet (Display *dpy, FcBool createIfNecessary)
     66 {
     67     XftDisplayInfo	*info, **prev;
     68     XRenderPictFormat	pf;
     69     int			i;
     70     int			event_base, error_base;
     71 
     72     for (prev = &_XftDisplayInfo; (info = *prev); prev = &(*prev)->next)
     73     {
     74 	if (info->display == dpy)
     75 	{
     76 	    /*
     77 	     * MRU the list
     78 	     */
     79 	    if (prev != &_XftDisplayInfo)
     80 	    {
     81 		*prev = info->next;
     82 		info->next = _XftDisplayInfo;
     83 		_XftDisplayInfo = info;
     84 	    }
     85 	    return info;
     86 	}
     87     }
     88     if (!createIfNecessary)
     89 	return NULL;
     90 
     91     info = malloc (sizeof (XftDisplayInfo));
     92     if (!info)
     93 	goto bail0;
     94     info->codes = XAddExtension (dpy);
     95     if (!info->codes)
     96 	goto bail1;
     97     (void) XESetCloseDisplay (dpy, info->codes->extension, _XftCloseDisplay);
     98 
     99     info->display = dpy;
    100     info->defaults = NULL;
    101     info->solidFormat = NULL;
    102     info->hasRender = (XRenderQueryExtension (dpy, &event_base, &error_base) &&
    103 		       (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != NULL));
    104     info->use_free_glyphs = FcTrue;
    105     if (info->hasRender)
    106     {
    107 	int major, minor;
    108 	XRenderQueryVersion (dpy, &major, &minor);
    109 	if (major < 0 || (major == 0 && minor <= 2))
    110 	    info->use_free_glyphs = FcFalse;
    111 
    112 	info->hasSolid = FcFalse;
    113 	if (major > 0 || (major == 0 && minor >= 10))
    114 	    info->hasSolid = FcTrue;
    115 
    116 	pf.type = PictTypeDirect;
    117 	pf.depth = 32;
    118 	pf.direct.redMask = 0xff;
    119 	pf.direct.greenMask = 0xff;
    120 	pf.direct.blueMask = 0xff;
    121 	pf.direct.alphaMask = 0xff;
    122 	info->solidFormat = XRenderFindFormat (dpy,
    123 					       (PictFormatType|
    124 						PictFormatDepth|
    125 						PictFormatRedMask|
    126 						PictFormatGreenMask|
    127 						PictFormatBlueMask|
    128 						PictFormatAlphaMask),
    129 					       &pf,
    130 					       0);
    131     }
    132     if (XftDebug () & XFT_DBG_RENDER)
    133     {
    134 	Visual		    *visual = DefaultVisual (dpy, DefaultScreen (dpy));
    135 	XRenderPictFormat   *format = XRenderFindVisualFormat (dpy, visual);
    136 
    137 	printf ("XftDisplayInfoGet Default visual 0x%x ",
    138 		(int) visual->visualid);
    139 	if (format)
    140 	{
    141 	    if (format->type == PictTypeDirect)
    142 	    {
    143 		printf ("format %d,%d,%d,%d\n",
    144 			format->direct.alpha,
    145 			format->direct.red,
    146 			format->direct.green,
    147 			format->direct.blue);
    148 	    }
    149 	    else
    150 	    {
    151 		printf ("format indexed\n");
    152 	    }
    153 	}
    154 	else
    155 	    printf ("No Render format for default visual\n");
    156 
    157 	printf ("XftDisplayInfoGet initialized, hasRender set to \"%s\"\n",
    158 		info->hasRender ? "True" : "False");
    159     }
    160     for (i = 0; i < XFT_NUM_SOLID_COLOR; i++)
    161     {
    162 	info->colors[i].screen = -1;
    163 	info->colors[i].pict = 0;
    164     }
    165     info->fonts = NULL;
    166 
    167     info->next = _XftDisplayInfo;
    168     _XftDisplayInfo = info;
    169 
    170     info->glyph_memory = 0;
    171     info->max_glyph_memory = (unsigned long)XftDefaultGetInteger (dpy,
    172 						   XFT_MAX_GLYPH_MEMORY, 0,
    173 						   XFT_DPY_MAX_GLYPH_MEMORY);
    174     if (XftDebug () & XFT_DBG_CACHE)
    175 	printf ("global max cache memory %lu\n", info->max_glyph_memory);
    176 
    177 
    178     info->num_unref_fonts = 0;
    179     info->max_unref_fonts = XftDefaultGetInteger (dpy,
    180 						  XFT_MAX_UNREF_FONTS, 0,
    181 						  XFT_DPY_MAX_UNREF_FONTS);
    182     if (XftDebug() & XFT_DBG_CACHE)
    183 	printf ("global max unref fonts  %d\n", info->max_unref_fonts);
    184 
    185     info->track_mem_usage = FcFalse;
    186     info->track_mem_usage = XftDefaultGetBool (dpy,
    187 					       XFT_TRACK_MEM_USAGE, 0,
    188 					       FcFalse);
    189     if (XftDebug() & XFT_DBG_CACHE)
    190 	printf ("global track mem usage  %s\n", BtoS(info->track_mem_usage));
    191 
    192     memset (info->fontHash, '\0', sizeof (XftFont *) * XFT_NUM_FONT_HASH);
    193     return info;
    194 
    195 bail1:
    196     free (info);
    197 bail0:
    198     if (XftDebug () & XFT_DBG_RENDER)
    199     {
    200 	printf ("XftDisplayInfoGet failed to initialize, Xft unhappy\n");
    201     }
    202     return NULL;
    203 }
    204 
    205 /*
    206  * Reduce memory usage in X server
    207  */
    208 
    209 static void
    210 _XftDisplayValidateMemory (XftDisplayInfo *info)
    211 {
    212     XftFont	    *public;
    213     XftFontInt	    *font;
    214     unsigned long   glyph_memory;
    215 
    216     glyph_memory = 0;
    217     for (public = info->fonts; public; public = font->next)
    218     {
    219 	font = (XftFontInt *) public;
    220 	glyph_memory += font->glyph_memory;
    221     }
    222     if (glyph_memory != info->glyph_memory)
    223 	printf ("Display glyph cache incorrect has %lu bytes, should have %lu\n",
    224 		info->glyph_memory, glyph_memory);
    225 }
    226 
    227 _X_HIDDEN void
    228 _XftDisplayManageMemory (Display *dpy)
    229 {
    230     XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, False);
    231     unsigned long   glyph_memory;
    232     XftFont	    *public;
    233     XftFontInt	    *font;
    234 
    235     if (!info || !info->max_glyph_memory)
    236 	return;
    237     if (XftDebug () & XFT_DBG_CACHE)
    238     {
    239 	if (info->glyph_memory > info->max_glyph_memory)
    240 	    printf ("Reduce global memory from %lu to %lu\n",
    241 		    info->glyph_memory, info->max_glyph_memory);
    242 	_XftDisplayValidateMemory (info);
    243     }
    244     while (info->glyph_memory > info->max_glyph_memory)
    245     {
    246 	glyph_memory = (unsigned long)rand () % info->glyph_memory;
    247 	public = info->fonts;
    248 	while (public)
    249 	{
    250 	    font = (XftFontInt *) public;
    251 
    252 	    if (font->glyph_memory > glyph_memory)
    253 	    {
    254 		_XftFontUncacheGlyph (dpy, public);
    255 		break;
    256 	    }
    257 	    public = font->next;
    258 	    glyph_memory -= font->glyph_memory;
    259 	}
    260     }
    261     if (XftDebug () & XFT_DBG_CACHE)
    262 	_XftDisplayValidateMemory (info);
    263 }
    264 
    265 _X_EXPORT Bool
    266 XftDefaultHasRender (Display *dpy)
    267 {
    268     XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
    269 
    270     if (!info)
    271 	return False;
    272     return info->hasRender;
    273 }
    274 
    275 _X_EXPORT Bool
    276 XftDefaultSet (Display *dpy, FcPattern *defaults)
    277 {
    278     XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
    279 
    280     if (!info)
    281 	return False;
    282     if (info->defaults)
    283 	FcPatternDestroy (info->defaults);
    284     info->defaults = defaults;
    285 
    286     if (!info->max_glyph_memory)
    287 	info->max_glyph_memory = XFT_DPY_MAX_GLYPH_MEMORY;
    288     info->max_glyph_memory = (unsigned long)XftDefaultGetInteger (dpy,
    289 						   XFT_MAX_GLYPH_MEMORY, 0,
    290 						   (int)info->max_glyph_memory);
    291     if (XftDebug () & XFT_DBG_CACHE)
    292 	printf ("update max cache memory %lu\n", info->max_glyph_memory);
    293 
    294     if (!info->max_unref_fonts)
    295 	info->max_unref_fonts = XFT_DPY_MAX_UNREF_FONTS;
    296     info->max_unref_fonts = XftDefaultGetInteger (dpy,
    297 						  XFT_MAX_UNREF_FONTS, 0,
    298 						  info->max_unref_fonts);
    299     if (XftDebug() & XFT_DBG_CACHE)
    300 	printf ("update max unref fonts  %d\n", info->max_unref_fonts);
    301 
    302     info->track_mem_usage = XftDefaultGetBool (dpy,
    303 					       XFT_TRACK_MEM_USAGE, 0,
    304 					       info->track_mem_usage);
    305     if (XftDebug() & XFT_DBG_CACHE)
    306 	printf ("update track mem usage  %s\n", BtoS(info->track_mem_usage));
    307 
    308     return True;
    309 }
    310 
    311 _X_HIDDEN int
    312 XftDefaultParseBool (const char *v)
    313 {
    314     char    c0, c1;
    315 
    316     c0 = *v;
    317     if (isupper ((int)c0))
    318 	c0 = (char)tolower (c0);
    319     if (c0 == 't' || c0 == 'y' || c0 == '1')
    320 	return 1;
    321     if (c0 == 'f' || c0 == 'n' || c0 == '0')
    322 	return 0;
    323     if (c0 == 'o')
    324     {
    325 	c1 = v[1];
    326 	if (isupper ((int)c1))
    327 	    c1 = (char)tolower (c1);
    328 	if (c1 == 'n')
    329 	    return 1;
    330 	if (c1 == 'f')
    331 	    return 0;
    332     }
    333     return -1;
    334 }
    335 
    336 static Bool
    337 _XftDefaultInitBool (Display *dpy, FcPattern *pat, const char *option)
    338 {
    339     char    *v;
    340     int	    i;
    341 
    342     v = XGetDefault (dpy, "Xft", option);
    343     if (v && (i = XftDefaultParseBool (v)) >= 0)
    344 	return FcPatternAddBool (pat, option, i != 0);
    345     return True;
    346 }
    347 
    348 static Bool
    349 _XftDefaultInitDouble (Display *dpy, FcPattern *pat, const char *option)
    350 {
    351     char    *v, *e;
    352     double  d;
    353 
    354     v = XGetDefault (dpy, "Xft", option);
    355     if (v)
    356     {
    357 	d = strtod (v, &e);
    358 	if (e != v)
    359 	    return FcPatternAddDouble (pat, option, d);
    360     }
    361     return True;
    362 }
    363 
    364 static Bool
    365 _XftDefaultInitInteger (Display *dpy, FcPattern *pat, const char *option)
    366 {
    367     char    *v, *e;
    368     int	    i;
    369 
    370     v = XGetDefault (dpy, "Xft", option);
    371     if (v)
    372     {
    373 	if (FcNameConstant ((FcChar8 *) v, &i))
    374 	    return FcPatternAddInteger (pat, option, i);
    375 	i = (int)strtol (v, &e, 0);
    376 	if (e != v)
    377 	    return FcPatternAddInteger (pat, option, i);
    378     }
    379     return True;
    380 }
    381 
    382 static FcPattern *
    383 _XftDefaultInit (Display *dpy)
    384 {
    385     FcPattern	*pat;
    386 
    387     pat = FcPatternCreate ();
    388     if (!pat)
    389 	goto bail0;
    390 
    391     if (!_XftDefaultInitDouble (dpy, pat, FC_SCALE))
    392 	goto bail1;
    393     if (!_XftDefaultInitDouble (dpy, pat, FC_DPI))
    394 	goto bail1;
    395     if (!_XftDefaultInitBool (dpy, pat, XFT_RENDER))
    396 	goto bail1;
    397     if (!_XftDefaultInitInteger (dpy, pat, FC_RGBA))
    398 	goto bail1;
    399     if (!_XftDefaultInitInteger (dpy, pat, FC_LCD_FILTER))
    400 	goto bail1;
    401     if (!_XftDefaultInitBool (dpy, pat, FC_ANTIALIAS))
    402 	goto bail1;
    403     if (!_XftDefaultInitBool (dpy, pat, FC_EMBOLDEN))
    404 	goto bail1;
    405     if (!_XftDefaultInitBool (dpy, pat, FC_AUTOHINT))
    406 	goto bail1;
    407     if (!_XftDefaultInitInteger (dpy, pat, FC_HINT_STYLE))
    408 	goto bail1;
    409     if (!_XftDefaultInitBool (dpy, pat, FC_HINTING))
    410 	goto bail1;
    411     if (!_XftDefaultInitBool (dpy, pat, FC_MINSPACE))
    412 	goto bail1;
    413     if (!_XftDefaultInitInteger (dpy, pat, XFT_MAX_GLYPH_MEMORY))
    414 	goto bail1;
    415 
    416     return pat;
    417 
    418 bail1:
    419     FcPatternDestroy (pat);
    420 bail0:
    421     return NULL;
    422 }
    423 
    424 static FcResult
    425 _XftDefaultGet (Display *dpy, const char *object, int screen, FcValue *v)
    426 {
    427     XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
    428     FcResult	    r;
    429 
    430     if (!info)
    431 	return FcResultNoMatch;
    432 
    433     if (!info->defaults)
    434     {
    435 	info->defaults = _XftDefaultInit (dpy);
    436 	if (!info->defaults)
    437 	    return FcResultNoMatch;
    438     }
    439     r = FcPatternGet (info->defaults, object, screen, v);
    440     if (r == FcResultNoId && screen > 0)
    441 	r = FcPatternGet (info->defaults, object, 0, v);
    442     return r;
    443 }
    444 
    445 _X_HIDDEN Bool
    446 XftDefaultGetBool (Display *dpy, const char *object, int screen, Bool def)
    447 {
    448     FcResult	    r;
    449     FcValue	    v;
    450 
    451     r = _XftDefaultGet (dpy, object, screen, &v);
    452     if (r != FcResultMatch || v.type != FcTypeBool)
    453 	return def;
    454     return v.u.b;
    455 }
    456 
    457 _X_HIDDEN int
    458 XftDefaultGetInteger (Display *dpy, const char *object, int screen, int def)
    459 {
    460     FcResult	    r;
    461     FcValue	    v;
    462 
    463     r = _XftDefaultGet (dpy, object, screen, &v);
    464     if (r != FcResultMatch || v.type != FcTypeInteger)
    465 	return def;
    466     return v.u.i;
    467 }
    468 
    469 _X_HIDDEN double
    470 XftDefaultGetDouble (Display *dpy, const char *object, int screen, double def)
    471 {
    472     FcResult	    r;
    473     FcValue	    v;
    474 
    475     r = _XftDefaultGet (dpy, object, screen, &v);
    476     if (r != FcResultMatch || v.type != FcTypeDouble)
    477 	return def;
    478     return v.u.d;
    479 }
    480 
    481 _X_EXPORT void
    482 XftDefaultSubstitute (Display *dpy, int screen, FcPattern *pattern)
    483 {
    484     FcValue	v;
    485     double	dpi;
    486 
    487     if (FcPatternGet (pattern, XFT_RENDER, 0, &v) == FcResultNoMatch)
    488     {
    489 	FcPatternAddBool (pattern, XFT_RENDER,
    490 			   XftDefaultGetBool (dpy, XFT_RENDER, screen,
    491 					      XftDefaultHasRender (dpy)));
    492     }
    493     if (FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch)
    494     {
    495 	FcPatternAddBool (pattern, FC_ANTIALIAS,
    496 			   XftDefaultGetBool (dpy, FC_ANTIALIAS, screen,
    497 					      True));
    498     }
    499     if (FcPatternGet (pattern, FC_EMBOLDEN, 0, &v) == FcResultNoMatch)
    500     {
    501 	FcPatternAddBool (pattern, FC_EMBOLDEN,
    502 			   XftDefaultGetBool (dpy, FC_EMBOLDEN, screen,
    503 					      False));
    504     }
    505     if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch)
    506     {
    507 	FcPatternAddBool (pattern, FC_HINTING,
    508 			  XftDefaultGetBool (dpy, FC_HINTING, screen,
    509 					     True));
    510     }
    511     if (FcPatternGet (pattern, FC_HINT_STYLE, 0, &v) == FcResultNoMatch)
    512     {
    513 	FcPatternAddInteger (pattern, FC_HINT_STYLE,
    514 			     XftDefaultGetInteger (dpy, FC_HINT_STYLE, screen,
    515 						   FC_HINT_FULL));
    516     }
    517     if (FcPatternGet (pattern, FC_AUTOHINT, 0, &v) == FcResultNoMatch)
    518     {
    519 	FcPatternAddBool (pattern, FC_AUTOHINT,
    520 			  XftDefaultGetBool (dpy, FC_AUTOHINT, screen,
    521 					     False));
    522     }
    523     if (FcPatternGet (pattern, FC_RGBA, 0, &v) == FcResultNoMatch)
    524     {
    525 	int	subpixel = FC_RGBA_UNKNOWN;
    526 #if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
    527 	if (XftDefaultHasRender (dpy))
    528 	{
    529 	    int render_order = XRenderQuerySubpixelOrder (dpy, screen);
    530 	    switch (render_order) {
    531 	    default:
    532 	    case SubPixelUnknown:	subpixel = FC_RGBA_UNKNOWN; break;
    533 	    case SubPixelHorizontalRGB:	subpixel = FC_RGBA_RGB; break;
    534 	    case SubPixelHorizontalBGR:	subpixel = FC_RGBA_BGR; break;
    535 	    case SubPixelVerticalRGB:	subpixel = FC_RGBA_VRGB; break;
    536 	    case SubPixelVerticalBGR:	subpixel = FC_RGBA_VBGR; break;
    537 	    case SubPixelNone:		subpixel = FC_RGBA_NONE; break;
    538 	    }
    539 	}
    540 #endif
    541 	FcPatternAddInteger (pattern, FC_RGBA,
    542 			      XftDefaultGetInteger (dpy, FC_RGBA, screen,
    543 						    subpixel));
    544     }
    545     if (FcPatternGet (pattern, FC_LCD_FILTER, 0, &v) == FcResultNoMatch)
    546     {
    547 	FcPatternAddInteger (pattern, FC_LCD_FILTER,
    548 			     XftDefaultGetInteger (dpy, FC_LCD_FILTER, screen,
    549 						   FC_LCD_DEFAULT));
    550     }
    551     if (FcPatternGet (pattern, FC_MINSPACE, 0, &v) == FcResultNoMatch)
    552     {
    553 	FcPatternAddBool (pattern, FC_MINSPACE,
    554 			   XftDefaultGetBool (dpy, FC_MINSPACE, screen,
    555 					      False));
    556     }
    557     if (FcPatternGet (pattern, FC_DPI, 0, &v) == FcResultNoMatch)
    558     {
    559 	dpi = (((double) DisplayHeight (dpy, screen) * 25.4) /
    560 	       (double) DisplayHeightMM (dpy, screen));
    561 	FcPatternAddDouble (pattern, FC_DPI,
    562 			    XftDefaultGetDouble (dpy, FC_DPI, screen,
    563 						 dpi));
    564     }
    565     if (FcPatternGet (pattern, FC_SCALE, 0, &v) == FcResultNoMatch)
    566     {
    567 	FcPatternAddDouble (pattern, FC_SCALE,
    568 			    XftDefaultGetDouble (dpy, FC_SCALE, screen, 1.0));
    569     }
    570     if (FcPatternGet (pattern, XFT_MAX_GLYPH_MEMORY, 0, &v) == FcResultNoMatch)
    571     {
    572 	FcPatternAddInteger (pattern, XFT_MAX_GLYPH_MEMORY,
    573 			     XftDefaultGetInteger (dpy, XFT_MAX_GLYPH_MEMORY,
    574 						   screen,
    575 						   XFT_FONT_MAX_GLYPH_MEMORY));
    576     }
    577     FcDefaultSubstitute (pattern);
    578 }
    579 
    580