Back to index

lightning-sunbird  0.9+nobinonly
cairo-xlib-screen.c
Go to the documentation of this file.
00001 /* Cairo - a vector graphics library with display and print output
00002  *
00003  * Copyright © 2005 Red Hat, Inc.
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it either under the terms of the GNU Lesser General Public
00007  * License version 2.1 as published by the Free Software Foundation
00008  * (the "LGPL") or, at your option, under the terms of the Mozilla
00009  * Public License Version 1.1 (the "MPL"). If you do not alter this
00010  * notice, a recipient may use your version of this file under either
00011  * the MPL or the LGPL.
00012  *
00013  * You should have received a copy of the LGPL along with this library
00014  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
00015  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00016  * You should have received a copy of the MPL along with this library
00017  * in the file COPYING-MPL-1.1
00018  *
00019  * The contents of this file are subject to the Mozilla Public License
00020  * Version 1.1 (the "License"); you may not use this file except in
00021  * compliance with the License. You may obtain a copy of the License at
00022  * http://www.mozilla.org/MPL/
00023  *
00024  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
00025  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
00026  * the specific language governing rights and limitations.
00027  *
00028  * The Original Code is the cairo graphics library.
00029  *
00030  * The Initial Developer of the Original Code is Red Hat, Inc.
00031  *
00032  * Partially on code from xftdpy.c
00033  *
00034  * Copyright © 2000 Keith Packard
00035  *
00036  * Permission to use, copy, modify, distribute, and sell this software and its
00037  * documentation for any purpose is hereby granted without fee, provided that
00038  * the above copyright notice appear in all copies and that both that
00039  * copyright notice and this permission notice appear in supporting
00040  * documentation, and that the name of Keith Packard not be used in
00041  * advertising or publicity pertaining to distribution of the software without
00042  * specific, written prior permission.  Keith Packard makes no
00043  * representations about the suitability of this software for any purpose.  It
00044  * is provided "as is" without express or implied warranty.
00045  *
00046  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
00047  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
00048  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
00049  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
00050  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
00051  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00052  * PERFORMANCE OF THIS SOFTWARE.
00053  */
00054 #include <stdlib.h>
00055 #include <string.h>
00056 
00057 #include "cairo-xlib-private.h"
00058 
00059 #include <fontconfig/fontconfig.h>
00060 
00061 #include <X11/Xlibint.h>    /* For XESetCloseDisplay */
00062 #include <X11/extensions/Xrender.h>
00063 
00064 static int
00065 parse_boolean (const char *v)
00066 {
00067     char c0, c1;
00068   
00069     c0 = *v;
00070     if (c0 == 't' || c0 == 'T' || c0 == 'y' || c0 == 'Y' || c0 == '1')
00071        return 1;
00072     if (c0 == 'f' || c0 == 'F' || c0 == 'n' || c0 == 'N' || c0 == '0')
00073        return 0;
00074     if (c0 == 'o')
00075     {
00076        c1 = v[1];
00077        if (c1 == 'n' || c1 == 'N')
00078            return 1;
00079        if (c1 == 'f' || c1 == 'F')
00080            return 0;
00081     }
00082   
00083     return -1;
00084 }
00085 
00086 static cairo_bool_t
00087 get_boolean_default (Display       *dpy,
00088                    const char    *option,
00089                    cairo_bool_t  *value)
00090 {
00091     char *v;
00092     int i;
00093   
00094     v = XGetDefault (dpy, "Xft", option);
00095     if (v) {
00096        i = parse_boolean (v);
00097        if (i >= 0) {
00098            *value = i;
00099            return TRUE;
00100        }
00101     }
00102   
00103     return FALSE;
00104 }
00105 
00106 static cairo_bool_t
00107 get_integer_default (Display    *dpy,
00108                    const char *option,
00109                    int        *value)
00110 {
00111     int i;
00112     char *v, *e;
00113   
00114     v = XGetDefault (dpy, "Xft", option);
00115     if (v) {
00116        if (FcNameConstant ((FcChar8 *) v, value))
00117            return TRUE;
00118       
00119        i = strtol (v, &e, 0);
00120        if (e != v)
00121            return TRUE;
00122     }
00123   
00124     return FALSE;
00125 }
00126 
00127 /* Old versions of fontconfig didn't have these options */
00128 #ifndef FC_HINT_NONE
00129 #define FC_HINT_NONE        0
00130 #define FC_HINT_SLIGHT      1
00131 #define FC_HINT_MEDIUM      2
00132 #define FC_HINT_FULL        3
00133 #endif
00134 
00135 static void
00136 _cairo_xlib_init_screen_font_options (cairo_xlib_screen_info_t *info)
00137 {
00138     cairo_bool_t xft_hinting;
00139     cairo_bool_t xft_antialias;
00140     int xft_hintstyle;
00141     int xft_rgba;
00142     cairo_antialias_t antialias;
00143     cairo_subpixel_order_t subpixel_order;
00144     cairo_hint_style_t hint_style;
00145 
00146     if (!get_boolean_default (info->display, "antialias", &xft_antialias))
00147        xft_antialias = TRUE;
00148   
00149     if (!get_boolean_default (info->display, "hinting", &xft_hinting))
00150        xft_hinting = TRUE;
00151   
00152     if (!get_integer_default (info->display, "hintstyle", &xft_hintstyle))
00153        xft_hintstyle = FC_HINT_FULL;
00154 
00155     if (!get_integer_default (info->display, "rgba", &xft_rgba))
00156     {
00157        xft_rgba = FC_RGBA_UNKNOWN;
00158       
00159 #if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
00160        if (info->has_render)
00161        {
00162            int render_order = XRenderQuerySubpixelOrder (info->display,
00163                                                    XScreenNumberOfScreen (info->screen));
00164          
00165            switch (render_order)
00166            {
00167            default:
00168            case SubPixelUnknown:
00169               xft_rgba = FC_RGBA_UNKNOWN;
00170               break;
00171            case SubPixelHorizontalRGB:
00172               xft_rgba = FC_RGBA_RGB;
00173               break;
00174            case SubPixelHorizontalBGR:
00175               xft_rgba = FC_RGBA_BGR;
00176               break;
00177            case SubPixelVerticalRGB:
00178               xft_rgba = FC_RGBA_VRGB;
00179               break;
00180            case SubPixelVerticalBGR:
00181               xft_rgba = FC_RGBA_VBGR;
00182               break;
00183            case SubPixelNone:
00184               xft_rgba = FC_RGBA_NONE;
00185               break;
00186            }
00187        }
00188 #endif
00189     }
00190 
00191     if (xft_hinting) {
00192        switch (xft_hintstyle) {
00193        case FC_HINT_NONE:
00194            hint_style = CAIRO_HINT_STYLE_NONE;
00195            break;
00196        case FC_HINT_SLIGHT:
00197            hint_style = CAIRO_HINT_STYLE_SLIGHT;
00198            break;
00199        case FC_HINT_MEDIUM:
00200            hint_style = CAIRO_HINT_STYLE_MEDIUM;
00201            break;
00202        case FC_HINT_FULL:
00203            hint_style = CAIRO_HINT_STYLE_FULL;
00204            break;
00205        default:
00206            hint_style = CAIRO_HINT_STYLE_DEFAULT;
00207        }
00208     } else {
00209        hint_style = CAIRO_HINT_STYLE_NONE;
00210     }
00211     
00212     switch (xft_rgba) {
00213     case FC_RGBA_RGB:
00214        subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
00215        break;
00216     case FC_RGBA_BGR:
00217        subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
00218        break;
00219     case FC_RGBA_VRGB:
00220        subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
00221        break;
00222     case FC_RGBA_VBGR:
00223        subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
00224        break;
00225     case FC_RGBA_UNKNOWN:
00226     case FC_RGBA_NONE:
00227     default:
00228        subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
00229     }
00230 
00231     if (xft_antialias) {
00232        if (subpixel_order == CAIRO_SUBPIXEL_ORDER_DEFAULT)
00233            antialias = CAIRO_ANTIALIAS_GRAY;
00234        else
00235            antialias = CAIRO_ANTIALIAS_SUBPIXEL;
00236     } else {
00237        antialias = CAIRO_ANTIALIAS_NONE;
00238     }
00239 
00240     _cairo_font_options_init_default (&info->font_options);
00241     cairo_font_options_set_hint_style (&info->font_options, hint_style);
00242     cairo_font_options_set_antialias (&info->font_options, antialias);
00243     cairo_font_options_set_subpixel_order (&info->font_options, subpixel_order);
00244 }
00245 
00246 CAIRO_MUTEX_DECLARE(_xlib_screen_mutex);
00247 
00248 static cairo_xlib_screen_info_t *_cairo_xlib_screen_list = NULL;
00249 
00250 /* XXX: From this function we should also run through and cleanup
00251  * anything else that still has a pointer to this Display*. For
00252  * example, we should clean up any Xlib-specific glyph caches. */
00253 static int
00254 _cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
00255 {
00256     cairo_xlib_screen_info_t *info, *prev;
00257 
00258     /*
00259      * Unhook from the global list
00260      */
00261     CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
00262 
00263     prev = NULL;
00264     for (info = _cairo_xlib_screen_list; info; info = info->next) {
00265        if (info->display == dpy) {
00266            if (prev)
00267               prev->next = info->next;
00268            else
00269               _cairo_xlib_screen_list = info->next;
00270            free (info);
00271            break;
00272        }
00273        prev = info;
00274     }
00275     CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
00276 
00277     /* Return value in accordance with requirements of
00278      * XESetCloseDisplay */
00279     return 0;
00280 }
00281 
00282 static void
00283 _cairo_xlib_screen_info_reset (void)
00284 {
00285     cairo_xlib_screen_info_t *info, *next;
00286 
00287     /*
00288      * Delete everything in the list.
00289      */
00290     CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
00291 
00292     for (info = _cairo_xlib_screen_list; info; info = next) {
00293        next = info->next;
00294        free (info);
00295     }
00296 
00297     _cairo_xlib_screen_list = NULL;
00298 
00299     CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
00300 
00301 }
00302 
00303 cairo_xlib_screen_info_t *
00304 _cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
00305 {
00306     cairo_xlib_screen_info_t *info;
00307     cairo_xlib_screen_info_t **prev;
00308     int event_base, error_base;
00309     XExtCodes *codes;
00310     cairo_bool_t seen_display = FALSE;
00311 
00312     /* There is an apparent deadlock between this mutex and the
00313      * mutex for the display, but it's actually safe. For the
00314      * app to call XCloseDisplay() while any other thread is
00315      * inside this function would be an error in the logic
00316      * app, and the CloseDisplay hook is the only other place we
00317      * acquire this mutex.
00318      */
00319     CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
00320 
00321     for (prev = &_cairo_xlib_screen_list; (info = *prev); prev = &(*prev)->next)
00322     {
00323        if (info->display == dpy) {
00324            seen_display = TRUE;
00325            if (info->screen == screen)
00326            {
00327               /*
00328                * MRU the list
00329                */
00330               if (prev != &_cairo_xlib_screen_list)
00331               {
00332                   *prev = info->next;
00333                   info->next = _cairo_xlib_screen_list;
00334                   _cairo_xlib_screen_list = info;
00335               }
00336               break;
00337            }
00338        }
00339     }
00340 
00341     if (info)
00342        goto out;
00343 
00344     info = malloc (sizeof (cairo_xlib_screen_info_t));
00345     if (!info)
00346        goto out;
00347 
00348     if (!seen_display) {
00349        codes = XAddExtension (dpy);
00350        if (!codes) {
00351            free (info);
00352            info = NULL;
00353            goto out;
00354        }
00355        
00356        XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
00357     }
00358 
00359     info->display = dpy;
00360     info->screen = screen;
00361     info->has_render = (XRenderQueryExtension (dpy, &event_base, &error_base) &&
00362                      (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0));
00363     
00364     _cairo_xlib_init_screen_font_options (info);
00365     
00366     info->next = _cairo_xlib_screen_list;
00367     _cairo_xlib_screen_list = info;
00368 
00369  out:
00370     CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
00371     
00372     return info;
00373 }
00374 
00375 void
00376 _cairo_xlib_screen_reset_static_data (void)
00377 {
00378     _cairo_xlib_screen_info_reset ();
00379 
00380 #if HAVE_XRMFINALIZE
00381     XrmFinalize ();
00382 #endif
00383 
00384 }