1
/* cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2009 Intel Corporation
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it either under the terms of the GNU Lesser General Public
7
 * License version 2.1 as published by the Free Software Foundation
8
 * (the "LGPL") or, at your option, under the terms of the Mozilla
9
 * Public License Version 1.1 (the "MPL"). If you do not alter this
10
 * notice, a recipient may use your version of this file under either
11
 * the MPL or the LGPL.
12
 *
13
 * You should have received a copy of the LGPL along with this library
14
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16
 * You should have received a copy of the MPL along with this library
17
 * in the file COPYING-MPL-1.1
18
 *
19
 * The contents of this file are subject to the Mozilla Public License
20
 * Version 1.1 (the "License"); you may not use this file except in
21
 * compliance with the License. You may obtain a copy of the License at
22
 * http://www.mozilla.org/MPL/
23
 *
24
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26
 * the specific language governing rights and limitations.
27
 *
28
 * Contributor(s):
29
 *	Chris Wilson <chris@chris-wilson.co.uk>
30
 */
31

            
32
#include "cairoint.h"
33

            
34
#include "cairo-xcb-private.h"
35

            
36
#include <xcb/xcbext.h>
37

            
38
xcb_pixmap_t
39
3
_cairo_xcb_connection_create_pixmap (cairo_xcb_connection_t *connection,
40
				     uint8_t depth,
41
				     xcb_drawable_t drawable,
42
				     uint16_t width,
43
				     uint16_t height)
44
{
45
3
    xcb_pixmap_t pixmap = xcb_generate_id (connection->xcb_connection);
46

            
47
3
    assert (width > 0);
48
3
    assert (height > 0);
49
3
    xcb_create_pixmap (connection->xcb_connection,
50
		       depth, pixmap, drawable,
51
		       width, height);
52
3
    return pixmap;
53
}
54

            
55
xcb_gcontext_t
56
_cairo_xcb_connection_create_gc (cairo_xcb_connection_t *connection,
57
				 xcb_drawable_t drawable,
58
				 uint32_t value_mask,
59
				 uint32_t *values)
60
{
61
    xcb_gcontext_t gc = xcb_generate_id (connection->xcb_connection);
62
    xcb_create_gc (connection->xcb_connection, gc, drawable,
63
		   value_mask, values);
64
    return gc;
65
}
66

            
67
void
68
_cairo_xcb_connection_change_gc (cairo_xcb_connection_t *connection,
69
				 xcb_gcontext_t gc,
70
				 uint32_t value_mask,
71
				 uint32_t *values)
72
{
73
    xcb_change_gc (connection->xcb_connection, gc,
74
		   value_mask, values);
75
}
76

            
77
void
78
_cairo_xcb_connection_copy_area (cairo_xcb_connection_t *connection,
79
				 xcb_drawable_t src,
80
				 xcb_drawable_t dst,
81
				 xcb_gcontext_t gc,
82
				 int16_t src_x,
83
				 int16_t src_y,
84
				 int16_t dst_x,
85
				 int16_t dst_y,
86
				 uint16_t width,
87
				 uint16_t height)
88
{
89
    xcb_copy_area (connection->xcb_connection, src, dst, gc,
90
		   src_x, src_y, dst_x, dst_y, width, height);
91
}
92

            
93
void
94
_cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection,
95
					   xcb_drawable_t dst,
96
					   xcb_gcontext_t gc,
97
					   uint32_t num_rectangles,
98
					   xcb_rectangle_t *rectangles)
99
{
100
    xcb_poly_fill_rectangle (connection->xcb_connection, dst, gc,
101
			     num_rectangles, rectangles);
102
}
103

            
104
void
105
_cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
106
				 xcb_drawable_t dst,
107
				 xcb_gcontext_t gc,
108
				 uint16_t width,
109
				 uint16_t height,
110
				 int16_t dst_x,
111
				 int16_t dst_y,
112
				 uint8_t depth,
113
				 uint32_t stride,
114
				 void *data)
115
{
116
    const uint32_t req_size = 18;
117
    uint32_t length = height * stride;
118
    uint32_t len = (req_size + length) >> 2;
119

            
120
    if (len < connection->maximum_request_length) {
121
	xcb_put_image (connection->xcb_connection, XCB_IMAGE_FORMAT_Z_PIXMAP,
122
		       dst, gc, width, height, dst_x, dst_y, 0, depth,
123
		       length, data);
124
    } else {
125
	int rows = (connection->maximum_request_length - req_size - 4) / stride;
126
	if (rows > 0) {
127
	    do {
128
		if (rows > height)
129
		    rows = height;
130

            
131
		length = rows * stride;
132

            
133
		xcb_put_image (connection->xcb_connection, XCB_IMAGE_FORMAT_Z_PIXMAP,
134
			       dst, gc, width, rows, dst_x, dst_y, 0, depth, length, data);
135

            
136
		height -= rows;
137
		dst_y += rows;
138
		data = (char *) data + length;
139
	    } while (height);
140
	} else {
141
	    ASSERT_NOT_REACHED;
142
	}
143
    }
144
}
145

            
146
static void
147
_cairo_xcb_connection_do_put_subimage (cairo_xcb_connection_t *connection,
148
				       xcb_drawable_t dst,
149
				       xcb_gcontext_t gc,
150
				       int16_t src_x,
151
				       int16_t src_y,
152
				       uint16_t width,
153
				       uint16_t height,
154
				       uint16_t cpp,
155
				       int stride,
156
				       int16_t dst_x,
157
				       int16_t dst_y,
158
				       uint8_t depth,
159
				       void *_data)
160
{
161
    xcb_protocol_request_t xcb_req = {
162
	0 /* count */,
163
	0 /* ext */,
164
	XCB_PUT_IMAGE /* opcode */,
165
	1 /* isvoid (doesn't cause a reply) */
166
    };
167
    xcb_put_image_request_t req;
168
    struct iovec vec_stack[CAIRO_STACK_ARRAY_LENGTH (struct iovec)];
169
    struct iovec *vec = vec_stack;
170
    uint32_t len = 0;
171
    uint8_t *data = _data;
172
    int n = 3;
173
    /* Two extra entries are needed for xcb, two for us */
174
    int entries_needed = height + 2 + 2;
175

            
176
    req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
177
    req.drawable = dst;
178
    req.gc = gc;
179
    req.width = width;
180
    req.height = height;
181
    req.dst_x = dst_x;
182
    req.dst_y = dst_y;
183
    req.left_pad = 0;
184
    req.depth = depth;
185
    req.pad0[0] = 0;
186
    req.pad0[1] = 0;
187

            
188
    if (entries_needed > ARRAY_LENGTH (vec_stack)) {
189
	vec = _cairo_malloc_ab (entries_needed, sizeof (struct iovec));
190
	if (unlikely (vec == NULL)) {
191
	    /* XXX loop over ARRAY_LENGTH (vec_stack) */
192
	    return;
193
	}
194
    }
195

            
196
    data += src_y * stride + src_x * cpp;
197
    /* vec[1] will be used in XCB if it has to use BigRequests or insert a sync,
198
     * vec[0] is used if the internal queue needs to be flushed. */
199
    vec[2].iov_base = (char *) &req;
200
    vec[2].iov_len = sizeof (req);
201

            
202
    /* Now comes the actual data */
203
    while (height--) {
204
	vec[n].iov_base = data;
205
	vec[n].iov_len = cpp * width;
206
	len += cpp * width;
207
	data += stride;
208
	n++;
209
    }
210

            
211
    /* And again some padding */
212
    vec[n].iov_base = 0;
213
    vec[n].iov_len = -len & 3;
214
    n++;
215

            
216
    /* For efficiency reasons, this functions writes the request "directly" to
217
     * the xcb connection to avoid having to copy the data around. */
218
    assert (n == entries_needed);
219
    xcb_req.count = n - 2;
220
    xcb_send_request (connection->xcb_connection, 0, &vec[2], &xcb_req);
221

            
222
    if (vec != vec_stack)
223
	free (vec);
224
}
225

            
226
void
227
_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
228
				    xcb_drawable_t dst,
229
				    xcb_gcontext_t gc,
230
				    int16_t src_x,
231
				    int16_t src_y,
232
				    uint16_t width,
233
				    uint16_t height,
234
				    uint16_t cpp,
235
				    int stride,
236
				    int16_t dst_x,
237
				    int16_t dst_y,
238
				    uint8_t depth,
239
				    void *_data)
240
{
241
    const uint32_t req_size = sizeof(xcb_put_image_request_t);
242
    uint32_t length = height * cpp * width;
243
    uint32_t len = (req_size + length) >> 2;
244

            
245
    if (len < connection->maximum_request_length) {
246
	_cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y,
247
			width, height, cpp, stride, dst_x, dst_y, depth, _data);
248
    } else {
249
	int rows = (connection->maximum_request_length - req_size - 4) / (cpp * width);
250
	if (rows > 0) {
251
	    do {
252
		if (rows > height)
253
		    rows = height;
254

            
255
		_cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y,
256
			width, rows, cpp, stride, dst_x, dst_y, depth, _data);
257

            
258
		height -= rows;
259
		dst_y += rows;
260
		_data = (char *) _data + stride * rows;
261
	    } while (height);
262
	} else {
263
	    ASSERT_NOT_REACHED;
264
	}
265
    }
266
}
267

            
268
xcb_get_image_reply_t *
269
3
_cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
270
				 xcb_drawable_t src,
271
				 int16_t src_x,
272
				 int16_t src_y,
273
				 uint16_t width,
274
				 uint16_t height)
275
{
276
3
    return xcb_get_image_reply (connection->xcb_connection,
277
				xcb_get_image (connection->xcb_connection,
278
					       XCB_IMAGE_FORMAT_Z_PIXMAP,
279
					       src,
280
					       src_x, src_y,
281
					       width, height,
282
					       (uint32_t) -1),
283
				NULL);
284
}