[PATCH] xcb: Initialize font options from Xft resources

Lukáš Lalinský <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <CAGUtLj_gxyRgLv4_TPdw4nD3i65Bd9bhsdFCU3Z-=3AjxjFsbg@mail.gmail.com>
I realized that when using the XCB backend, default font options do
not respect my system settings, but they do when using the Xlib
backend. It seems that the code to initialize font options was not
implemented in the XCB backend.

XCB doesn't support resources directly, so there is more code than
there should be (probably why it wasn't implemented in the first
place). I'm not sure if this is the right approach.

Lukas

-- 
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
0001-xcb-Initialize-font-options-from-Xft-resources.patch (text/x-patch, 9.8 KB)
From 0be3f607078a4dd24273b793a07240d05f0aff1f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Lalinsk=C3=BD?= <[email protected]>
Date: Wed, 3 Sep 2014 22:53:55 +0200
Subject: [PATCH] xcb: Initialize font options from Xft resources

There is a similar code in the Xlib backend. The logic here is the same, but
XCB doesn't support X resources directly, so there is some custom code
to get and parse the resources from the root window.
---
 src/cairo-xcb-private.h |   6 ++
 src/cairo-xcb-screen.c  | 271 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/cairo-xcb-surface.c |   6 +-
 3 files changed, 280 insertions(+), 3 deletions(-)

diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index 134100a..b343b75 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -199,6 +199,9 @@ struct _cairo_xcb_screen {
     cairo_list_t link;
     cairo_list_t surfaces;
     cairo_list_t pictures;
+
+    cairo_bool_t has_font_options;
+    cairo_font_options_t font_options;
 };
 
 struct _cairo_xcb_connection {
@@ -357,6 +360,9 @@ _cairo_xcb_screen_get_gc (cairo_xcb_screen_t *screen,
 cairo_private void
 _cairo_xcb_screen_put_gc (cairo_xcb_screen_t *screen, int depth, xcb_gcontext_t gc);
 
+cairo_private cairo_font_options_t *
+_cairo_xcb_screen_get_font_options (cairo_xcb_screen_t *screen);
+
 cairo_private cairo_status_t
 _cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen,
 					const cairo_linear_pattern_t *linear,
diff --git a/src/cairo-xcb-screen.c b/src/cairo-xcb-screen.c
index 2858d23..06594a7 100644
--- a/src/cairo-xcb-screen.c
+++ b/src/cairo-xcb-screen.c
@@ -30,11 +30,263 @@
  *    Chris Wilson <[email protected]>
  */
 
+#include <ctype.h>
+
 #include "cairoint.h"
 
 #include "cairo-xcb-private.h"
 #include "cairo-list-inline.h"
 
+#include "cairo-fontconfig-private.h"
+
+static void
+parse_boolean (const char *v, cairo_bool_t *out)
+{
+    char c0, c1;
+
+    c0 = *v;
+    if (c0 == 't' || c0 == 'T' || c0 == 'y' || c0 == 'Y' || c0 == '1')
+        *out = TRUE;
+    if (c0 == 'f' || c0 == 'F' || c0 == 'n' || c0 == 'N' || c0 == '0')
+        *out = FALSE;
+    if (c0 == 'o') {
+        c1 = v[1];
+        if (c1 == 'n' || c1 == 'N')
+            *out = TRUE;
+        if (c1 == 'f' || c1 == 'F')
+            *out = FALSE;
+    }
+}
+
+static void
+parse_integer (const char *v, int *out)
+{
+    char *e;
+    int value;
+
+#if CAIRO_HAS_FC_FONT
+    if (FcNameConstant ((FcChar8 *) v, out))
+        return;
+#endif
+
+    value = strtol (v, &e, 0);
+    if (e != v)
+        *out = value;
+}
+
+struct resource_state {
+    cairo_bool_t xft_antialias;
+    int xft_lcdfilter;
+    cairo_bool_t xft_hinting;
+    int xft_hintstyle;
+    int xft_rgba;
+};
+
+struct resource_parser {
+    int buffer_size;
+    int bytes_in_buffer;
+    char* buffer;
+    struct resource_state *state;
+};
+
+static int
+resource_parse_line (struct resource_parser *parser)
+{
+    char *newline, *name, *value;
+
+    name = parser->buffer;
+    while (1) {
+        newline = strchr (name, '\n');
+        if (newline == NULL)
+            break;
+
+        value = strchr (name, ':');
+        if (value == NULL)
+            break;
+
+        *newline++ = 0;
+        *value++ = 0;
+
+        while (isspace(*value))
+            value++;
+
+        if (strcmp(name, "Xft.antialias") == 0)
+            parse_boolean(value, &(parser->state->xft_antialias));
+        else if (strcmp(name, "Xft.lcdfilter") == 0)
+            parse_integer(value, &(parser->state->xft_lcdfilter));
+        else if (strcmp(name, "Xft.rgba") == 0)
+            parse_integer(value, &(parser->state->xft_rgba));
+        else if (strcmp(name, "Xft.hinting") == 0)
+            parse_integer(value, &(parser->state->xft_hinting));
+        else if (strcmp(name, "Xft.hintstyle") == 0)
+            parse_integer(value, &(parser->state->xft_hintstyle));
+
+        name = newline;
+    }
+
+    return name - parser->buffer;
+}
+
+static void
+resource_parser_init (struct resource_parser *parser, struct resource_state *state)
+{
+    parser->buffer_size = 0;
+    parser->bytes_in_buffer = 0;
+    parser->buffer = 0;
+    parser->state = state;
+}
+
+static void
+resource_parser_done (struct resource_parser *parser)
+{
+    free (parser->buffer);
+}
+
+static void
+resource_parse (struct resource_parser *parser, const char *data, int length)
+{
+    int bytes_parsed;
+
+    if (parser->bytes_in_buffer + length > parser->buffer_size) {
+	parser->buffer_size = parser->bytes_in_buffer + length + 1;
+	parser->buffer = realloc(parser->buffer, parser->buffer_size);
+    }
+
+    memmove (parser->buffer + parser->bytes_in_buffer, data, length);
+    parser->bytes_in_buffer += length;
+    parser->buffer[parser->bytes_in_buffer] = 0;
+
+    bytes_parsed = resource_parse_line (parser);
+
+    if (parser->bytes_in_buffer > bytes_parsed) {
+	memmove (parser->buffer, parser->buffer + bytes_parsed, parser->bytes_in_buffer - bytes_parsed);
+	parser->bytes_in_buffer -= bytes_parsed;
+    }
+}
+
+static void
+get_resources(xcb_connection_t *connection, xcb_screen_t *screen, struct resource_state *state)
+{
+    xcb_get_property_cookie_t rm_cookie;
+    xcb_get_property_reply_t *rm_reply;
+    struct resource_parser parser;
+    int offset = 0, has_more_data = 0;
+
+    resource_parser_init (&parser, state);
+
+    do {
+        rm_cookie = xcb_get_property (connection, 0, screen->root, XCB_ATOM_RESOURCE_MANAGER, XCB_ATOM_STRING, offset, 1024);
+        rm_reply = xcb_get_property_reply (connection, rm_cookie, NULL);
+
+        if (rm_reply) {
+            if (rm_reply->format == 8 && rm_reply->type == XCB_ATOM_STRING) {
+                char *value = (char *) xcb_get_property_value (rm_reply);
+                int length = xcb_get_property_value_length (rm_reply);
+
+                resource_parse (&parser, value, length);
+
+                has_more_data = rm_reply->bytes_after > 0;
+                offset += length / 4;
+            }
+
+            free (rm_reply);
+        }
+    } while (has_more_data);
+
+    resource_parser_done (&parser);
+}
+
+static void
+_cairo_xcb_init_screen_font_options (cairo_xcb_screen_t *screen)
+{
+    struct resource_state res;
+    cairo_antialias_t antialias;
+    cairo_subpixel_order_t subpixel_order;
+    cairo_lcd_filter_t lcd_filter;
+    cairo_hint_style_t hint_style;
+
+    res.xft_antialias = TRUE;
+    res.xft_lcdfilter = -1;
+    res.xft_hinting = TRUE;
+    res.xft_hintstyle = FC_HINT_FULL;
+    res.xft_rgba = FC_RGBA_UNKNOWN;
+
+    get_resources(screen->connection->xcb_connection, screen->xcb_screen, &res);
+
+    if (res.xft_hinting) {
+	switch (res.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 (res.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 (res.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 (res.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 (&screen->font_options, hint_style);
+    cairo_font_options_set_antialias (&screen->font_options, antialias);
+    cairo_font_options_set_subpixel_order (&screen->font_options, subpixel_order);
+    _cairo_font_options_set_lcd_filter (&screen->font_options, lcd_filter);
+    cairo_font_options_set_hint_metrics (&screen->font_options, CAIRO_HINT_METRICS_ON);
+}
+
 struct pattern_cache_entry {
     cairo_cache_entry_t key;
     cairo_xcb_screen_t *screen;
@@ -362,3 +614,22 @@ _cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t *screen,
 
     return picture;
 }
+
+cairo_font_options_t *
+_cairo_xcb_screen_get_font_options (cairo_xcb_screen_t *screen)
+{
+    assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->device.mutex));
+
+    if (! screen->has_font_options) {
+	_cairo_font_options_init_default (&screen->font_options);
+	_cairo_font_options_set_round_glyph_positions (&screen->font_options, CAIRO_ROUND_GLYPH_POS_ON);
+
+	if (screen->xcb_screen != NULL) {
+            _cairo_xcb_init_screen_font_options (screen);
+	}
+
+	screen->has_font_options = TRUE;
+    }
+
+    return &screen->font_options;
+}
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 02e7a19..d7e0d73 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -530,9 +530,9 @@ static void
 _cairo_xcb_surface_get_font_options (void *abstract_surface,
 				     cairo_font_options_t *options)
 {
-    /* XXX  copy from xlib */
-    _cairo_font_options_init_default (options);
-    _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
+    cairo_xcb_surface_t *surface = abstract_surface;
+
+    *options = *_cairo_xcb_screen_get_font_options (surface->screen);
 }
 
 static cairo_status_t
-- 
1.8.3.2
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.