/* Cairo - a vector graphics library with display and print output * * Copyright © 2014 Lukas Lalinsky * Copyright © 2005 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * (the "LGPL") or, at your option, under the terms of the Mozilla * Public License Version 1.1 (the "MPL"). If you do not alter this * notice, a recipient may use your version of this file under either * the MPL or the LGPL. * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. * * Authors: * Lukas Lalinsky * * Partially on code from xftdpy.c * * Copyright © 2000 Keith Packard * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Keith Packard not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Keith Packard makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "cairoint.h" #include "cairo-xcb-private.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; } static char * skip_spaces(char *str) { while (*str == ' ' || *str == '\t' || *str == '\n') str++; return str; } struct resource_parser { int buffer_size; int bytes_in_buffer; char* buffer; cairo_xcb_resources_t *resources; }; 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)); 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; *newline++ = 0; if (! resource_parse_line (line, parser->resources)) break; line = newline; } return line - parser->buffer; } 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 + 1 > parser->buffer_size) { parser->buffer_size = parser->bytes_in_buffer + length + 1; parser->buffer = realloc(parser->buffer, parser->buffer_size); if (! parser->buffer) { parser->buffer_size = 0; parser->bytes_in_buffer = 0; return FALSE; } } 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; 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); } void _cairo_xcb_resources_get (cairo_xcb_screen_t *screen, cairo_xcb_resources_t *resources) { get_resources (screen->connection->xcb_connection, screen->xcb_screen, resources); if (resources->xft_rgba == FC_RGBA_UNKNOWN) { switch (screen->subpixel_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; } } }