cairo-xlib-screen.c [plain text]
#include "cairoint.h"
#include "cairo-xlib-private.h"
#include "cairo-xlib-xrender-private.h"
#include "cairo-xlib-surface-private.h"
#include "cairo-error-private.h"
#include "cairo-fontconfig-private.h"
static int
parse_boolean (const char *v)
{
char c0, c1;
c0 = *v;
if (c0 == 't' || c0 == 'T' || c0 == 'y' || c0 == 'Y' || c0 == '1')
return 1;
if (c0 == 'f' || c0 == 'F' || c0 == 'n' || c0 == 'N' || c0 == '0')
return 0;
if (c0 == 'o')
{
c1 = v[1];
if (c1 == 'n' || c1 == 'N')
return 1;
if (c1 == 'f' || c1 == 'F')
return 0;
}
return -1;
}
static cairo_bool_t
get_boolean_default (Display *dpy,
const char *option,
cairo_bool_t *value)
{
char *v;
int i;
v = XGetDefault (dpy, "Xft", option);
if (v) {
i = parse_boolean (v);
if (i >= 0) {
*value = i;
return TRUE;
}
}
return FALSE;
}
static cairo_bool_t
get_integer_default (Display *dpy,
const char *option,
int *value)
{
char *v, *e;
v = XGetDefault (dpy, "Xft", option);
if (v) {
#if CAIRO_HAS_FC_FONT
if (FcNameConstant ((FcChar8 *) v, value))
return TRUE;
#endif
*value = strtol (v, &e, 0);
if (e != v)
return TRUE;
}
return FALSE;
}
static void
_cairo_xlib_init_screen_font_options (Display *dpy,
cairo_xlib_screen_t *info)
{
cairo_bool_t xft_hinting;
cairo_bool_t xft_antialias;
int xft_hintstyle;
int xft_rgba;
int xft_lcdfilter;
cairo_antialias_t antialias;
cairo_subpixel_order_t subpixel_order;
cairo_lcd_filter_t lcd_filter;
cairo_hint_style_t hint_style;
if (!get_boolean_default (dpy, "antialias", &xft_antialias))
xft_antialias = TRUE;
if (!get_integer_default (dpy, "lcdfilter", &xft_lcdfilter)) {
xft_lcdfilter = -1;
}
if (!get_boolean_default (dpy, "hinting", &xft_hinting))
xft_hinting = TRUE;
if (!get_integer_default (dpy, "hintstyle", &xft_hintstyle))
xft_hintstyle = FC_HINT_FULL;
if (!get_integer_default (dpy, "rgba", &xft_rgba))
{
cairo_xlib_display_t *display = (cairo_xlib_display_t *) info->device;
xft_rgba = FC_RGBA_UNKNOWN;
#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
if (display->render_major > 0 || display->render_minor >= 6) {
int render_order = XRenderQuerySubpixelOrder (dpy,
XScreenNumberOfScreen (info->screen));
switch (render_order) {
default:
case SubPixelUnknown:
xft_rgba = FC_RGBA_UNKNOWN;
break;
case SubPixelHorizontalRGB:
xft_rgba = FC_RGBA_RGB;
break;
case SubPixelHorizontalBGR:
xft_rgba = FC_RGBA_BGR;
break;
case SubPixelVerticalRGB:
xft_rgba = FC_RGBA_VRGB;
break;
case SubPixelVerticalBGR:
xft_rgba = FC_RGBA_VBGR;
break;
case SubPixelNone:
xft_rgba = FC_RGBA_NONE;
break;
}
}
#endif
}
if (xft_hinting) {
switch (xft_hintstyle) {
case FC_HINT_NONE:
hint_style = CAIRO_HINT_STYLE_NONE;
break;
case FC_HINT_SLIGHT:
hint_style = CAIRO_HINT_STYLE_SLIGHT;
break;
case FC_HINT_MEDIUM:
hint_style = CAIRO_HINT_STYLE_MEDIUM;
break;
case FC_HINT_FULL:
hint_style = CAIRO_HINT_STYLE_FULL;
break;
default:
hint_style = CAIRO_HINT_STYLE_DEFAULT;
}
} else {
hint_style = CAIRO_HINT_STYLE_NONE;
}
switch (xft_rgba) {
case FC_RGBA_RGB:
subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
break;
case FC_RGBA_BGR:
subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
break;
case FC_RGBA_VRGB:
subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
break;
case FC_RGBA_VBGR:
subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
break;
case FC_RGBA_UNKNOWN:
case FC_RGBA_NONE:
default:
subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
}
switch (xft_lcdfilter) {
case FC_LCD_NONE:
lcd_filter = CAIRO_LCD_FILTER_NONE;
break;
case FC_LCD_DEFAULT:
lcd_filter = CAIRO_LCD_FILTER_FIR5;
break;
case FC_LCD_LIGHT:
lcd_filter = CAIRO_LCD_FILTER_FIR3;
break;
case FC_LCD_LEGACY:
lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL;
break;
default:
lcd_filter = CAIRO_LCD_FILTER_DEFAULT;
break;
}
if (xft_antialias) {
if (subpixel_order == CAIRO_SUBPIXEL_ORDER_DEFAULT)
antialias = CAIRO_ANTIALIAS_GRAY;
else
antialias = CAIRO_ANTIALIAS_SUBPIXEL;
} else {
antialias = CAIRO_ANTIALIAS_NONE;
}
cairo_font_options_set_hint_style (&info->font_options, hint_style);
cairo_font_options_set_antialias (&info->font_options, antialias);
cairo_font_options_set_subpixel_order (&info->font_options, subpixel_order);
_cairo_font_options_set_lcd_filter (&info->font_options, lcd_filter);
cairo_font_options_set_hint_metrics (&info->font_options, CAIRO_HINT_METRICS_ON);
}
void
_cairo_xlib_screen_close_display (cairo_xlib_display_t *display,
cairo_xlib_screen_t *info)
{
Display *dpy;
int i;
dpy = display->display;
for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
if ((info->gc_depths >> (8*i)) & 0xff)
XFreeGC (dpy, info->gc[i]);
}
info->gc_depths = 0;
}
void
_cairo_xlib_screen_destroy (cairo_xlib_screen_t *info)
{
while (! cairo_list_is_empty (&info->visuals)) {
_cairo_xlib_visual_info_destroy (cairo_list_first_entry (&info->visuals,
cairo_xlib_visual_info_t,
link));
}
cairo_list_del (&info->link);
free (info);
}
cairo_status_t
_cairo_xlib_screen_get (Display *dpy,
Screen *screen,
cairo_xlib_screen_t **out)
{
cairo_xlib_display_t *display;
cairo_device_t *device;
cairo_xlib_screen_t *info;
cairo_status_t status;
device = _cairo_xlib_device_create (dpy);
status = device->status;
if (unlikely (status))
goto CLEANUP_DEVICE;
status = _cairo_xlib_display_acquire (device, &display);
if (unlikely (status))
goto CLEANUP_DEVICE;
info = _cairo_xlib_display_get_screen (display, screen);
if (info != NULL) {
*out = info;
goto CLEANUP_DISPLAY;
}
info = malloc (sizeof (cairo_xlib_screen_t));
if (unlikely (info == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_DISPLAY;
}
info->device = device;
info->screen = screen;
info->has_font_options = FALSE;
info->gc_depths = 0;
memset (info->gc, 0, sizeof (info->gc));
cairo_list_init (&info->visuals);
cairo_list_add (&info->link, &display->screens);
*out = info;
CLEANUP_DISPLAY:
cairo_device_release (&display->base);
CLEANUP_DEVICE:
cairo_device_destroy (device);
return status;
}
GC
_cairo_xlib_screen_get_gc (cairo_xlib_display_t *display,
cairo_xlib_screen_t *info,
int depth,
Drawable drawable)
{
GC gc = NULL;
int i;
for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
if (((info->gc_depths >> (8*i)) & 0xff) == depth) {
info->gc_depths &= ~(0xff << (8*i));
gc = info->gc[i];
break;
}
}
if (gc == NULL) {
XGCValues gcv;
gcv.graphics_exposures = False;
gcv.fill_style = FillTiled;
gc = XCreateGC (display->display,
drawable,
GCGraphicsExposures | GCFillStyle, &gcv);
}
return gc;
}
void
_cairo_xlib_screen_put_gc (cairo_xlib_display_t *display,
cairo_xlib_screen_t *info,
int depth,
GC gc)
{
int i;
for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
if (((info->gc_depths >> (8*i)) & 0xff) == 0)
break;
}
if (i == ARRAY_LENGTH (info->gc)) {
cairo_status_t status;
i = rand () % ARRAY_LENGTH (info->gc);
status =
_cairo_xlib_display_queue_work (display,
(cairo_xlib_notify_func) XFreeGC,
info->gc[i],
NULL);
if (unlikely (status)) {
XFree ((char *) info->gc[i]);
}
}
info->gc[i] = gc;
info->gc_depths &= ~(0xff << (8*i));
info->gc_depths |= depth << (8*i);
}
cairo_status_t
_cairo_xlib_screen_get_visual_info (cairo_xlib_display_t *display,
cairo_xlib_screen_t *info,
Visual *v,
cairo_xlib_visual_info_t **out)
{
cairo_xlib_visual_info_t *visual;
cairo_status_t status;
cairo_list_foreach_entry (visual,
cairo_xlib_visual_info_t,
&info->visuals,
link)
{
if (visual->visualid == v->visualid) {
*out = visual;
return CAIRO_STATUS_SUCCESS;
}
}
status = _cairo_xlib_visual_info_create (display->display,
XScreenNumberOfScreen (info->screen),
v->visualid,
&visual);
if (unlikely (status))
return status;
cairo_list_add (&visual->link, &info->visuals);
*out = visual;
return CAIRO_STATUS_SUCCESS;
}
cairo_font_options_t *
_cairo_xlib_screen_get_font_options (cairo_xlib_screen_t *info)
{
if (! info->has_font_options) {
_cairo_font_options_init_default (&info->font_options);
if (info->screen != NULL) {
cairo_xlib_display_t *display;
if (! _cairo_xlib_display_acquire (info->device, &display)) {
_cairo_xlib_init_screen_font_options (display->display,
info);
cairo_device_release (&display->base);
}
}
info->has_font_options = TRUE;
}
return &info->font_options;
}