1
/* Cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2014 Lukas Lalinsky
4
 * Copyright © 2005 Red Hat, Inc.
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it either under the terms of the GNU Lesser General Public
8
 * License version 2.1 as published by the Free Software Foundation
9
 * (the "LGPL") or, at your option, under the terms of the Mozilla
10
 * Public License Version 1.1 (the "MPL"). If you do not alter this
11
 * notice, a recipient may use your version of this file under either
12
 * the MPL or the LGPL.
13
 *
14
 * You should have received a copy of the LGPL along with this library
15
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17
 * You should have received a copy of the MPL along with this library
18
 * in the file COPYING-MPL-1.1
19
 *
20
 * The contents of this file are subject to the Mozilla Public License
21
 * Version 1.1 (the "License"); you may not use this file except in
22
 * compliance with the License. You may obtain a copy of the License at
23
 * http://www.mozilla.org/MPL/
24
 *
25
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
 * the specific language governing rights and limitations.
28
 *
29
 * Authors:
30
 *    Lukas Lalinsky <lukas@oxygene.sk>
31
 *
32
 * Partially on code from xftdpy.c
33
 *
34
 * Copyright © 2000 Keith Packard
35
 *
36
 * Permission to use, copy, modify, distribute, and sell this software and its
37
 * documentation for any purpose is hereby granted without fee, provided that
38
 * the above copyright notice appear in all copies and that both that
39
 * copyright notice and this permission notice appear in supporting
40
 * documentation, and that the name of Keith Packard not be used in
41
 * advertising or publicity pertaining to distribution of the software without
42
 * specific, written prior permission.  Keith Packard makes no
43
 * representations about the suitability of this software for any purpose.  It
44
 * is provided "as is" without express or implied warranty.
45
 *
46
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
47
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
48
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
49
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
50
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
51
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
52
 * PERFORMANCE OF THIS SOFTWARE.
53
 */
54

            
55
#include "cairoint.h"
56

            
57
#include "cairo-xcb-private.h"
58

            
59
#include "cairo-fontconfig-private.h"
60

            
61
static void
62
parse_boolean (const char *v, cairo_bool_t *out)
63
{
64
    char c0, c1;
65

            
66
    c0 = *v;
67
    if (c0 == 't' || c0 == 'T' || c0 == 'y' || c0 == 'Y' || c0 == '1')
68
	*out = TRUE;
69
    if (c0 == 'f' || c0 == 'F' || c0 == 'n' || c0 == 'N' || c0 == '0')
70
	*out = FALSE;
71
    if (c0 == 'o') {
72
	c1 = v[1];
73
	if (c1 == 'n' || c1 == 'N')
74
	    *out = TRUE;
75
	if (c1 == 'f' || c1 == 'F')
76
	    *out = FALSE;
77
    }
78
}
79

            
80
static void
81
parse_integer (const char *v, int *out)
82
{
83
    char *e;
84
    int value;
85

            
86
#if CAIRO_HAS_FC_FONT
87
    if (FcNameConstant ((FcChar8 *) v, out))
88
	return;
89
#endif
90

            
91
    value = strtol (v, &e, 0);
92
    if (e != v)
93
	*out = value;
94
}
95

            
96
static char *
97
skip_spaces(char *str)
98
{
99
    while (*str == ' ' || *str == '\t' || *str == '\n')
100
	str++;
101
    return str;
102
}
103

            
104
struct resource_parser {
105
    int buffer_size;
106
    int bytes_in_buffer;
107
    char* buffer;
108
    cairo_xcb_resources_t *resources;
109
};
110

            
111
static cairo_bool_t
112
resource_parse_line (char *name, cairo_xcb_resources_t *resources)
113
{
114
    char *value;
115

            
116
    value = strchr (name, ':');
117
    if (value == NULL)
118
	return FALSE;
119

            
120
    *value++ = 0;
121

            
122
    name = skip_spaces (name);
123
    value = skip_spaces (value);
124

            
125
    if (strcmp (name, "Xft.antialias") == 0)
126
	parse_boolean (value, &(resources->xft_antialias));
127
    else if (strcmp (name, "Xft.lcdfilter") == 0)
128
	parse_integer (value, &(resources->xft_lcdfilter));
129
    else if (strcmp (name, "Xft.rgba") == 0)
130
	parse_integer (value, &(resources->xft_rgba));
131
    else if (strcmp (name, "Xft.hinting") == 0)
132
	parse_boolean (value, &(resources->xft_hinting));
133
    else if (strcmp (name, "Xft.hintstyle") == 0)
134
	parse_integer (value, &(resources->xft_hintstyle));
135

            
136
    return TRUE;
137
}
138

            
139
static int
140
resource_parse_lines (struct resource_parser *parser)
141
{
142
    char *line, *newline;
143

            
144
    line = parser->buffer;
145
    while (1) {
146
	newline = strchr (line, '\n');
147
	if (newline == NULL)
148
	    break;
149

            
150
	*newline++ = 0;
151

            
152
	if (! resource_parse_line (line, parser->resources))
153
	    break;
154

            
155
	line = newline;
156
    }
157

            
158
    return line - parser->buffer;
159
}
160

            
161
static void
162
resource_parser_init (struct resource_parser *parser, cairo_xcb_resources_t *resources)
163
{
164
    parser->buffer_size = 0;
165
    parser->bytes_in_buffer = 0;
166
    parser->buffer = NULL;
167
    parser->resources = resources;
168
}
169

            
170
static cairo_bool_t
171
resource_parser_update (struct resource_parser *parser, const char *data, int length)
172
{
173
    int bytes_parsed;
174

            
175
    if (parser->bytes_in_buffer + length + 1 > parser->buffer_size) {
176
	parser->buffer_size = parser->bytes_in_buffer + length + 1;
177
	parser->buffer = realloc(parser->buffer, parser->buffer_size);
178
	if (! parser->buffer) {
179
	    parser->buffer_size = 0;
180
	    parser->bytes_in_buffer = 0;
181
	    return FALSE;
182
	}
183
    }
184

            
185
    memmove (parser->buffer + parser->bytes_in_buffer, data, length);
186
    parser->bytes_in_buffer += length;
187
    parser->buffer[parser->bytes_in_buffer] = 0;
188

            
189
    bytes_parsed = resource_parse_lines (parser);
190

            
191
    if (parser->bytes_in_buffer > bytes_parsed) {
192
	memmove (parser->buffer, parser->buffer + bytes_parsed, parser->bytes_in_buffer - bytes_parsed);
193
	parser->bytes_in_buffer -= bytes_parsed;
194
    } else {
195
	parser->bytes_in_buffer = 0;
196
    }
197

            
198
    return TRUE;
199
}
200

            
201
static void
202
resource_parser_done (struct resource_parser *parser)
203
{
204
    if (parser->bytes_in_buffer > 0) {
205
	parser->buffer[parser->bytes_in_buffer] = 0;
206
	resource_parse_line (parser->buffer, parser->resources);
207
    }
208

            
209
    free (parser->buffer);
210
}
211

            
212
static void
213
get_resources(xcb_connection_t *connection, xcb_screen_t *screen, cairo_xcb_resources_t *resources)
214
{
215
    xcb_get_property_cookie_t cookie;
216
    xcb_get_property_reply_t *reply;
217
    struct resource_parser parser;
218
    int offset;
219
    cairo_bool_t has_more_data;
220

            
221
    resources->xft_antialias = TRUE;
222
    resources->xft_lcdfilter = -1;
223
    resources->xft_hinting = TRUE;
224
    resources->xft_hintstyle = FC_HINT_FULL;
225
    resources->xft_rgba = FC_RGBA_UNKNOWN;
226

            
227
    resource_parser_init (&parser, resources);
228

            
229
    offset = 0;
230
    has_more_data = FALSE;
231
    do {
232
	cookie = xcb_get_property (connection, 0, screen->root, XCB_ATOM_RESOURCE_MANAGER, XCB_ATOM_STRING, offset, 1024);
233
	reply = xcb_get_property_reply (connection, cookie, NULL);
234

            
235
	if (reply) {
236
	    if (reply->format == 8 && reply->type == XCB_ATOM_STRING) {
237
		char *value = (char *) xcb_get_property_value (reply);
238
		int length = xcb_get_property_value_length (reply);
239

            
240
		offset += length / 4; /* X needs the offset in 'long' units */
241
		has_more_data = reply->bytes_after > 0;
242

            
243
		if (! resource_parser_update (&parser, value, length))
244
		    has_more_data = FALSE; /* early exit on error */
245
	    }
246

            
247
	    free (reply);
248
	}
249
    } while (has_more_data);
250

            
251
    resource_parser_done (&parser);
252
}
253

            
254
void
255
_cairo_xcb_resources_get (cairo_xcb_screen_t *screen, cairo_xcb_resources_t *resources)
256
{
257
    get_resources (screen->connection->xcb_connection, screen->xcb_screen, resources);
258

            
259
    if (resources->xft_rgba == FC_RGBA_UNKNOWN) {
260
	switch (screen->subpixel_order) {
261
	case XCB_RENDER_SUB_PIXEL_UNKNOWN:
262
	    resources->xft_rgba = FC_RGBA_UNKNOWN;
263
	    break;
264
	case XCB_RENDER_SUB_PIXEL_HORIZONTAL_RGB:
265
	    resources->xft_rgba = FC_RGBA_RGB;
266
	    break;
267
	case XCB_RENDER_SUB_PIXEL_HORIZONTAL_BGR:
268
	    resources->xft_rgba = FC_RGBA_BGR;
269
	    break;
270
	case XCB_RENDER_SUB_PIXEL_VERTICAL_RGB:
271
	    resources->xft_rgba = FC_RGBA_VRGB;
272
	    break;
273
	case XCB_RENDER_SUB_PIXEL_VERTICAL_BGR:
274
	    resources->xft_rgba = FC_RGBA_VBGR;
275
	    break;
276
	case XCB_RENDER_SUB_PIXEL_NONE:
277
	    resources->xft_rgba = FC_RGBA_NONE;
278
	    break;
279
	}
280
    }
281
}