Re: [PATCH] xcb: Initialize font options from Xft resources
Uli Schlachter <[email protected]>
| Newsgroups | gmane.comp.lib.cairo |
|---|---|
| Message-ID | <[email protected]> |
Hi again, On 04.09.2014 10:24, Lukáš Lalinský wrote: > On Thu, Sep 4, 2014 at 8:47 AM, Lukáš Lalinský <[email protected]> wrote: >> > Thanks for the review. I'll update the code and send a new patch later >> > today. Some comments bellow. > Updated version attached. I'm also considering extracting the common > code from cairo-xlib and cairo-xcb, but I can't find any instance of > such code sharing between those two backends. Is there anything like > that in already? Nope, as far as I know there is nothing like that already. > 0001-xcb-Initialize-font-options-from-Xft-resources.patch > > > From c3f32c9beb1e7e1cd0f531a76ae53e1f2dd850a9 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. > --- [...] > +static cairo_bool_t > +resource_parse_line (char *name, cairo_xcb_resources_t *resources) > +{ > + char *value; > + > + value = strchr (name, ':'); > + if (value == NULL) > + return FALSE; > + > + *value++ = 0; > + > + name = skip_spaces (name); > + value = skip_spaces (value); > + > + if (strcmp (name, "Xft.antialias") == 0) > + parse_boolean (value, &(resources->xft_antialias)); > + else if (strcmp (name, "Xft.lcdfilter") == 0) > + parse_integer (value, &(resources->xft_lcdfilter)); > + else if (strcmp (name, "Xft.rgba") == 0) > + parse_integer (value, &(resources->xft_rgba)); > + else if (strcmp (name, "Xft.hinting") == 0) > + parse_boolean (value, &(resources->xft_hinting)); > + else if (strcmp (name, "Xft.hintstyle") == 0) > + parse_integer (value, &(resources->xft_hintstyle)); Should this also ignore trailing spaces? I have no clue about this resources stuff... > + return TRUE; > +} > + > +static int > +resource_parse_lines (struct resource_parser *parser) > +{ > + char *line, *newline; > + > + line = parser->buffer; > + while (1) { > + newline = strchr (line, '\n'); > + if (newline == NULL) > + break; This should be intended by tabs (and "tabs + 4 spaces" for the next level). > + > + *newline++ = 0; > + > + if (! resource_parse_line (line, parser->resources)) > + break; > + > + line = newline; > + } > + > + return line - parser->buffer; > +} I like it that you split up this function into two. Makes it easier to follow IMO. > +static void > +resource_parser_init (struct resource_parser *parser, cairo_xcb_resources_t *resources) > +{ > + parser->buffer_size = 0; > + parser->bytes_in_buffer = 0; > + parser->buffer = NULL; > + parser->resources = resources; > +} > + > +static cairo_bool_t > +resource_parser_update (struct resource_parser *parser, const char *data, int length) > +{ > + int bytes_parsed; > + > + if (parser->bytes_in_buffer + length > parser->buffer_size) { Due to the trailing null byte, this should be ">=" instead of ">" (or to make things clearer, explicitly add a "+1" to the left side). > + parser->buffer_size = parser->bytes_in_buffer + length + 1; > + parser->buffer = realloc(parser->buffer, parser->buffer_size); > + if (! parser->buffer) > + return FALSE; Could you set parser->buffer_size and parser->bytes_in_buffer to 0 in this case? That would properly "destroy" the parser. In this version, continuing to use the parser could cause issues. Also, resource_parser_done could dereference a NULL pointer. > + } > + > + 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_lines (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; > + } else { > + parser->bytes_in_buffer = 0; > + } > + > + return TRUE; > +} > + > +static void > +resource_parser_done (struct resource_parser *parser) > +{ > + if (parser->bytes_in_buffer > 0) { > + parser->buffer[parser->bytes_in_buffer] = 0; This zero byte is already inserted in resource_parser_update, no need to add it here again. > + resource_parse_line (parser->buffer, parser->resources); > + } > + > + free (parser->buffer); > +} > + > +static void > +get_resources(xcb_connection_t *connection, xcb_screen_t *screen, cairo_xcb_resources_t *resources) > +{ > + xcb_get_property_cookie_t cookie; > + xcb_get_property_reply_t *reply; > + struct resource_parser parser; > + int offset; > + cairo_bool_t has_more_data; > + > + resources->xft_antialias = TRUE; > + resources->xft_lcdfilter = -1; > + resources->xft_hinting = TRUE; > + resources->xft_hintstyle = FC_HINT_FULL; > + resources->xft_rgba = FC_RGBA_UNKNOWN; > + > + resource_parser_init (&parser, resources); > + > + offset = 0; > + has_more_data = FALSE; > + do { > + cookie = xcb_get_property (connection, 0, screen->root, XCB_ATOM_RESOURCE_MANAGER, XCB_ATOM_STRING, offset, 1024); > + reply = xcb_get_property_reply (connection, cookie, NULL); > + > + if (reply) { > + if (reply->format == 8 && reply->type == XCB_ATOM_STRING) { > + char *value = (char *) xcb_get_property_value (reply); > + int length = xcb_get_property_value_length (reply); > + > + offset += length / 4; /* X needs the offset in 'long' units */ > + has_more_data = reply->bytes_after > 0; > + > + if (! resource_parser_update (&parser, value, length)) > + has_more_data = FALSE; /* early exit on error */ > + } > + > + free (reply); > + } > + } while (has_more_data); > + > + resource_parser_done (&parser); > +} > + > +#if 0 && XCB_RENDER_MAJOR_VERSION > 99 && XCB_RENDER_MINOR_VERSION > 99 > +static void > +get_rgba_from_render (xcb_connection_t *connection, xcb_screen_t *screen, cairo_xcb_resources_t *resources) > +{ > + /* this is a mock-up of what the function might look like, > + xcb_render_query_sub_pixel is not actually implemented in XCB (yet) */ XRenderQuerySubPixel() is just a wrapper in libXrender. It actually sends a RENDER QueryPictFormats request. XRenderQuerySubpixelOrder(dpy, screen) effectively then does just this: return xcb_render_query_pict_formats_subpixels(reply)[screen]; However, the documentation[0] states that this requires at least render 0.6 (so needs a xcb_render_query_version() check and return unknown if major==0&&minor<6, or even better would be to use cairo_xcb_connection_t::flags and add a new flag similar to CAIRO_XCB_RENDER_HAS_FILTERS) and that the list of subpixels may be shorter than the number of screens (which you can check for with xcb_render_query_pict_formats_subpixels_length() and which I am not completely sure libXrender handles correctly). Oh and this apparently requires turning an xcb_screen_t into its screen number which requires way too much code for way too little gain. [0]: http://cgit.freedesktop.org/xorg/proto/renderproto/tree/renderproto.txt#n518 Feel free to leave this as-is and for someone else to fix up later, but in this case it would be nice to update the above comment. > + > + xcb_render_query_sub_pixel_order_cookie_t cookie; > + xcb_render_query_sub_pixel_order_reply_t *reply; > + > + cookie = xcb_render_query_sub_pixel (connection, screen); > + reply = xcb_render_query_sub_pixel_reply (connection, cookie, NULL); > + > + if (reply) { > + switch (reply->sub_pixel_order) { > + case XCB_RENDER_SUB_PIXEL_UNKNOWN: > + resources->xft_rgba = FC_RGBA_UNKNOWN; > + break; > + case XCB_RENDER_SUB_PIXEL_HORIZONTAL_RGB: > + resources->xft_rgba = FC_RGBA_RGB; > + break; > + case XCB_RENDER_SUB_PIXEL_HORIZONTAL_BGR: > + resources->xft_rgba = FC_RGBA_BGR; > + break; > + case XCB_RENDER_SUB_PIXEL_VERTICAL_RGB: > + resources->xft_rgba = FC_RGBA_VRGB; > + break; > + case XCB_RENDER_SUB_PIXEL_VERTICAL_BGR: > + resources->xft_rgba = FC_RGBA_VBGR; > + break; > + case XCB_RENDER_SUB_PIXEL_NONE: > + resources->xft_rgba = FC_RGBA_NONE; > + break; > + } > + > + free(reply); > + } > +} > +#endif [...] > @@ -362,3 +452,20 @@ _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); > + > + _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); Still requires a pair of _cairo_xcb_connection_acquire() / _cairo_xcb_connection_release() somewhere. Cairo-xlib does this in _cairo_xlib_screen_get_font_options(), but you put an assert into _cairo_xcb_screen_get_font_options() making this the caller's responsibility. Either place is fine with me to do the necessary locking. (And yes, CAIRO_MUTEX_IS_LOCKED() is defined to 1 if cairo is using pthreads, so this assert can't actually trigger. It's still nice as documentation.) > } > > static cairo_status_t > -- 1.8.3.2 Nice patch and once again thanks for working on this. Since the above are just some minor things that can easily be addressed, this patch (with those things fixed) is: Reviewed-by: Uli Schlachter <[email protected]> Cheers, Uli -- 99 little bugs in the code 99 little bugs in the code Take one down, patch it around 117 little bugs in the code -- @irqed -- cairo mailing list [email protected] http://lists.cairographics.org/mailman/listinfo/cairo