1 /* Cairo - a vector graphics library with display and print output
3 * Copyright © 2008 Chris Wilson
4 * Copyright © 2009 Intel Corporation
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.
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
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/
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.
30 * Chris Wilson <chris@chris-wilson.co.uk>
35 #include "cairo-xcb-private.h"
36 #include "cairo-list-inline.h"
38 #include "cairo-fontconfig-private.h"
41 _cairo_xcb_init_screen_font_options (cairo_xcb_screen_t
*screen
)
43 cairo_xcb_resources_t res
;
44 cairo_antialias_t antialias
;
45 cairo_subpixel_order_t subpixel_order
;
46 cairo_lcd_filter_t lcd_filter
;
47 cairo_hint_style_t hint_style
;
49 _cairo_xcb_resources_get (screen
, &res
);
51 /* the rest of the code in this function is copied from
52 _cairo_xlib_init_screen_font_options in cairo-xlib-screen.c */
54 if (res
.xft_hinting
) {
55 switch (res
.xft_hintstyle
) {
57 hint_style
= CAIRO_HINT_STYLE_NONE
;
60 hint_style
= CAIRO_HINT_STYLE_SLIGHT
;
63 hint_style
= CAIRO_HINT_STYLE_MEDIUM
;
66 hint_style
= CAIRO_HINT_STYLE_FULL
;
69 hint_style
= CAIRO_HINT_STYLE_DEFAULT
;
72 hint_style
= CAIRO_HINT_STYLE_NONE
;
75 switch (res
.xft_rgba
) {
77 subpixel_order
= CAIRO_SUBPIXEL_ORDER_RGB
;
80 subpixel_order
= CAIRO_SUBPIXEL_ORDER_BGR
;
83 subpixel_order
= CAIRO_SUBPIXEL_ORDER_VRGB
;
86 subpixel_order
= CAIRO_SUBPIXEL_ORDER_VBGR
;
91 subpixel_order
= CAIRO_SUBPIXEL_ORDER_DEFAULT
;
94 switch (res
.xft_lcdfilter
) {
96 lcd_filter
= CAIRO_LCD_FILTER_NONE
;
99 lcd_filter
= CAIRO_LCD_FILTER_FIR5
;
102 lcd_filter
= CAIRO_LCD_FILTER_FIR3
;
105 lcd_filter
= CAIRO_LCD_FILTER_INTRA_PIXEL
;
108 lcd_filter
= CAIRO_LCD_FILTER_DEFAULT
;
112 if (res
.xft_antialias
) {
113 if (subpixel_order
== CAIRO_SUBPIXEL_ORDER_DEFAULT
)
114 antialias
= CAIRO_ANTIALIAS_GRAY
;
116 antialias
= CAIRO_ANTIALIAS_SUBPIXEL
;
118 antialias
= CAIRO_ANTIALIAS_NONE
;
121 cairo_font_options_set_hint_style (&screen
->font_options
, hint_style
);
122 cairo_font_options_set_antialias (&screen
->font_options
, antialias
);
123 cairo_font_options_set_subpixel_order (&screen
->font_options
, subpixel_order
);
124 _cairo_font_options_set_lcd_filter (&screen
->font_options
, lcd_filter
);
125 cairo_font_options_set_hint_metrics (&screen
->font_options
, CAIRO_HINT_METRICS_ON
);
128 struct pattern_cache_entry
{
129 cairo_cache_entry_t key
;
130 cairo_xcb_screen_t
*screen
;
131 cairo_pattern_union_t pattern
;
132 cairo_surface_t
*picture
;
136 _cairo_xcb_screen_finish (cairo_xcb_screen_t
*screen
)
140 CAIRO_MUTEX_LOCK (screen
->connection
->screens_mutex
);
141 cairo_list_del (&screen
->link
);
142 CAIRO_MUTEX_UNLOCK (screen
->connection
->screens_mutex
);
144 while (! cairo_list_is_empty (&screen
->surfaces
)) {
145 cairo_surface_t
*surface
;
147 surface
= &cairo_list_first_entry (&screen
->surfaces
,
151 cairo_surface_finish (surface
);
154 while (! cairo_list_is_empty (&screen
->pictures
)) {
155 cairo_surface_t
*surface
;
157 surface
= &cairo_list_first_entry (&screen
->pictures
,
161 cairo_surface_finish (surface
);
164 for (i
= 0; i
< screen
->solid_cache_size
; i
++)
165 cairo_surface_destroy (screen
->solid_cache
[i
].picture
);
167 for (i
= 0; i
< ARRAY_LENGTH (screen
->stock_colors
); i
++)
168 cairo_surface_destroy (screen
->stock_colors
[i
]);
170 for (i
= 0; i
< ARRAY_LENGTH (screen
->gc
); i
++) {
171 if (screen
->gc_depths
[i
] != 0)
172 _cairo_xcb_connection_free_gc (screen
->connection
, screen
->gc
[i
]);
175 _cairo_cache_fini (&screen
->linear_pattern_cache
);
176 _cairo_cache_fini (&screen
->radial_pattern_cache
);
177 _cairo_freelist_fini (&screen
->pattern_cache_entry_freelist
);
183 _linear_pattern_cache_entry_equal (const void *A
, const void *B
)
185 const struct pattern_cache_entry
*a
= A
, *b
= B
;
187 return _cairo_linear_pattern_equal (&a
->pattern
.gradient
.linear
,
188 &b
->pattern
.gradient
.linear
);
192 _radial_pattern_cache_entry_equal (const void *A
, const void *B
)
194 const struct pattern_cache_entry
*a
= A
, *b
= B
;
196 return _cairo_radial_pattern_equal (&a
->pattern
.gradient
.radial
,
197 &b
->pattern
.gradient
.radial
);
201 _pattern_cache_entry_destroy (void *closure
)
203 struct pattern_cache_entry
*entry
= closure
;
205 _cairo_pattern_fini (&entry
->pattern
.base
);
206 cairo_surface_destroy (entry
->picture
);
207 _cairo_freelist_free (&entry
->screen
->pattern_cache_entry_freelist
, entry
);
210 static int _get_screen_index(cairo_xcb_connection_t
*xcb_connection
,
211 xcb_screen_t
*xcb_screen
)
214 xcb_screen_iterator_t iter
= xcb_setup_roots_iterator(xcb_connection
->root
);
215 for (; iter
.rem
; xcb_screen_next(&iter
), idx
++)
216 if (iter
.data
->root
== xcb_screen
->root
)
223 _cairo_xcb_screen_get (xcb_connection_t
*xcb_connection
,
224 xcb_screen_t
*xcb_screen
)
226 cairo_xcb_connection_t
*connection
;
227 cairo_xcb_screen_t
*screen
;
228 cairo_status_t status
;
232 connection
= _cairo_xcb_connection_get (xcb_connection
);
233 if (unlikely (connection
== NULL
))
236 CAIRO_MUTEX_LOCK (connection
->screens_mutex
);
238 cairo_list_foreach_entry (screen
,
240 &connection
->screens
,
243 if (screen
->xcb_screen
== xcb_screen
) {
244 /* Maintain list in MRU order */
245 if (&screen
->link
!= connection
->screens
.next
)
246 cairo_list_move (&screen
->link
, &connection
->screens
);
252 screen
= malloc (sizeof (cairo_xcb_screen_t
));
253 if (unlikely (screen
== NULL
))
256 screen_idx
= _get_screen_index(connection
, xcb_screen
);
258 screen
->connection
= connection
;
259 screen
->xcb_screen
= xcb_screen
;
260 screen
->has_font_options
= FALSE
;
261 screen
->subpixel_order
= connection
->subpixel_orders
[screen_idx
];
263 _cairo_freelist_init (&screen
->pattern_cache_entry_freelist
,
264 sizeof (struct pattern_cache_entry
));
265 cairo_list_init (&screen
->link
);
266 cairo_list_init (&screen
->surfaces
);
267 cairo_list_init (&screen
->pictures
);
269 memset (screen
->gc_depths
, 0, sizeof (screen
->gc_depths
));
270 memset (screen
->gc
, 0, sizeof (screen
->gc
));
272 screen
->solid_cache_size
= 0;
273 for (i
= 0; i
< ARRAY_LENGTH (screen
->stock_colors
); i
++)
274 screen
->stock_colors
[i
] = NULL
;
276 status
= _cairo_cache_init (&screen
->linear_pattern_cache
,
277 _linear_pattern_cache_entry_equal
,
279 _pattern_cache_entry_destroy
,
281 if (unlikely (status
))
284 status
= _cairo_cache_init (&screen
->radial_pattern_cache
,
285 _radial_pattern_cache_entry_equal
,
287 _pattern_cache_entry_destroy
,
289 if (unlikely (status
))
292 cairo_list_add (&screen
->link
, &connection
->screens
);
295 CAIRO_MUTEX_UNLOCK (connection
->screens_mutex
);
300 _cairo_cache_fini (&screen
->linear_pattern_cache
);
302 CAIRO_MUTEX_UNLOCK (connection
->screens_mutex
);
308 static xcb_gcontext_t
309 _create_gc (cairo_xcb_screen_t
*screen
,
310 xcb_drawable_t drawable
)
312 uint32_t values
[] = { 0 };
314 return _cairo_xcb_connection_create_gc (screen
->connection
, drawable
,
315 XCB_GC_GRAPHICS_EXPOSURES
,
320 _cairo_xcb_screen_get_gc (cairo_xcb_screen_t
*screen
,
321 xcb_drawable_t drawable
,
326 assert (CAIRO_MUTEX_IS_LOCKED (screen
->connection
->device
.mutex
));
328 for (i
= 0; i
< ARRAY_LENGTH (screen
->gc
); i
++) {
329 if (screen
->gc_depths
[i
] == depth
) {
330 screen
->gc_depths
[i
] = 0;
331 return screen
->gc
[i
];
335 return _create_gc (screen
, drawable
);
339 _cairo_xcb_screen_put_gc (cairo_xcb_screen_t
*screen
, int depth
, xcb_gcontext_t gc
)
343 assert (CAIRO_MUTEX_IS_LOCKED (screen
->connection
->device
.mutex
));
345 for (i
= 0; i
< ARRAY_LENGTH (screen
->gc
); i
++) {
346 if (screen
->gc_depths
[i
] == 0)
350 if (i
== ARRAY_LENGTH (screen
->gc
)) {
351 /* perform random substitution to ensure fair caching over depths */
352 i
= rand () % ARRAY_LENGTH (screen
->gc
);
353 _cairo_xcb_connection_free_gc (screen
->connection
, screen
->gc
[i
]);
357 screen
->gc_depths
[i
] = depth
;
361 _cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t
*screen
,
362 const cairo_linear_pattern_t
*linear
,
363 cairo_surface_t
*picture
)
365 struct pattern_cache_entry
*entry
;
366 cairo_status_t status
;
368 assert (CAIRO_MUTEX_IS_LOCKED (screen
->connection
->device
.mutex
));
370 entry
= _cairo_freelist_alloc (&screen
->pattern_cache_entry_freelist
);
371 if (unlikely (entry
== NULL
))
372 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
374 entry
->key
.hash
= _cairo_linear_pattern_hash (_CAIRO_HASH_INIT_VALUE
, linear
);
377 status
= _cairo_pattern_init_copy (&entry
->pattern
.base
, &linear
->base
.base
);
378 if (unlikely (status
)) {
379 _cairo_freelist_free (&screen
->pattern_cache_entry_freelist
, entry
);
383 entry
->picture
= cairo_surface_reference (picture
);
384 entry
->screen
= screen
;
386 status
= _cairo_cache_insert (&screen
->linear_pattern_cache
,
388 if (unlikely (status
)) {
389 cairo_surface_destroy (picture
);
390 _cairo_freelist_free (&screen
->pattern_cache_entry_freelist
, entry
);
394 return CAIRO_STATUS_SUCCESS
;
398 _cairo_xcb_screen_lookup_linear_picture (cairo_xcb_screen_t
*screen
,
399 const cairo_linear_pattern_t
*linear
)
401 cairo_surface_t
*picture
= NULL
;
402 struct pattern_cache_entry tmpl
;
403 struct pattern_cache_entry
*entry
;
405 assert (CAIRO_MUTEX_IS_LOCKED (screen
->connection
->device
.mutex
));
407 tmpl
.key
.hash
= _cairo_linear_pattern_hash (_CAIRO_HASH_INIT_VALUE
, linear
);
408 _cairo_pattern_init_static_copy (&tmpl
.pattern
.base
, &linear
->base
.base
);
410 entry
= _cairo_cache_lookup (&screen
->linear_pattern_cache
, &tmpl
.key
);
412 picture
= cairo_surface_reference (entry
->picture
);
418 _cairo_xcb_screen_store_radial_picture (cairo_xcb_screen_t
*screen
,
419 const cairo_radial_pattern_t
*radial
,
420 cairo_surface_t
*picture
)
422 struct pattern_cache_entry
*entry
;
423 cairo_status_t status
;
425 assert (CAIRO_MUTEX_IS_LOCKED (screen
->connection
->device
.mutex
));
427 entry
= _cairo_freelist_alloc (&screen
->pattern_cache_entry_freelist
);
428 if (unlikely (entry
== NULL
))
429 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
431 entry
->key
.hash
= _cairo_radial_pattern_hash (_CAIRO_HASH_INIT_VALUE
, radial
);
434 status
= _cairo_pattern_init_copy (&entry
->pattern
.base
, &radial
->base
.base
);
435 if (unlikely (status
)) {
436 _cairo_freelist_free (&screen
->pattern_cache_entry_freelist
, entry
);
440 entry
->picture
= cairo_surface_reference (picture
);
441 entry
->screen
= screen
;
443 status
= _cairo_cache_insert (&screen
->radial_pattern_cache
, &entry
->key
);
444 if (unlikely (status
)) {
445 cairo_surface_destroy (picture
);
446 _cairo_freelist_free (&screen
->pattern_cache_entry_freelist
, entry
);
450 return CAIRO_STATUS_SUCCESS
;
454 _cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t
*screen
,
455 const cairo_radial_pattern_t
*radial
)
457 cairo_surface_t
*picture
= NULL
;
458 struct pattern_cache_entry tmpl
;
459 struct pattern_cache_entry
*entry
;
461 assert (CAIRO_MUTEX_IS_LOCKED (screen
->connection
->device
.mutex
));
463 tmpl
.key
.hash
= _cairo_radial_pattern_hash (_CAIRO_HASH_INIT_VALUE
, radial
);
464 _cairo_pattern_init_static_copy (&tmpl
.pattern
.base
, &radial
->base
.base
);
466 entry
= _cairo_cache_lookup (&screen
->radial_pattern_cache
, &tmpl
.key
);
468 picture
= cairo_surface_reference (entry
->picture
);
473 cairo_font_options_t
*
474 _cairo_xcb_screen_get_font_options (cairo_xcb_screen_t
*screen
)
476 if (! screen
->has_font_options
) {
477 _cairo_font_options_init_default (&screen
->font_options
);
478 _cairo_font_options_set_round_glyph_positions (&screen
->font_options
, CAIRO_ROUND_GLYPH_POS_ON
);
480 /* XXX: This is disabled because something seems to be merging
481 font options incorrectly for xcb. This effectively reverts
482 the changes brought in git e691d242, and restores ~150 tests
483 to resume passing. See mailing list archives for Sep 17,
484 2014 for more discussion. */
485 if (0 && ! _cairo_xcb_connection_acquire (screen
->connection
)) {
486 _cairo_xcb_init_screen_font_options (screen
);
487 _cairo_xcb_connection_release (screen
->connection
);
490 screen
->has_font_options
= TRUE
;
493 return &screen
->font_options
;