0eb2b84ab1225ce14579d4ac1f8336935fcdfdd6
[platform/upstream/cairo.git] / src / cairo-xcb-connection-core.c
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 _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     xcb_pixmap_t pixmap = _cairo_xcb_connection_get_xid (connection);
46
47     assert (width > 0);
48     assert (height > 0);
49     xcb_create_pixmap (connection->xcb_connection,
50                        depth, pixmap, drawable,
51                        width, height);
52     return pixmap;
53 }
54
55 void
56 _cairo_xcb_connection_free_pixmap (cairo_xcb_connection_t *connection,
57                                    xcb_pixmap_t pixmap)
58 {
59     xcb_free_pixmap (connection->xcb_connection, pixmap);
60     _cairo_xcb_connection_put_xid (connection, pixmap);
61 }
62
63 xcb_gcontext_t
64 _cairo_xcb_connection_create_gc (cairo_xcb_connection_t *connection,
65                                  xcb_drawable_t drawable,
66                                  uint32_t value_mask,
67                                  uint32_t *values)
68 {
69     xcb_gcontext_t gc = _cairo_xcb_connection_get_xid (connection);
70     xcb_create_gc (connection->xcb_connection, gc, drawable,
71                    value_mask, values);
72     return gc;
73 }
74
75 void
76 _cairo_xcb_connection_free_gc (cairo_xcb_connection_t *connection,
77                                xcb_gcontext_t gc)
78 {
79     xcb_free_gc (connection->xcb_connection, gc);
80     _cairo_xcb_connection_put_xid (connection, gc);
81 }
82
83 void
84 _cairo_xcb_connection_change_gc (cairo_xcb_connection_t *connection,
85                                  xcb_gcontext_t gc,
86                                  uint32_t value_mask,
87                                  uint32_t *values)
88 {
89     xcb_change_gc (connection->xcb_connection, gc,
90                    value_mask, values);
91 }
92
93 void
94 _cairo_xcb_connection_copy_area (cairo_xcb_connection_t *connection,
95                                  xcb_drawable_t src,
96                                  xcb_drawable_t dst,
97                                  xcb_gcontext_t gc,
98                                  int16_t src_x,
99                                  int16_t src_y,
100                                  int16_t dst_x,
101                                  int16_t dst_y,
102                                  uint16_t width,
103                                  uint16_t height)
104 {
105     xcb_copy_area (connection->xcb_connection, src, dst, gc,
106                    src_x, src_y, dst_x, dst_y, width, height);
107 }
108
109 void
110 _cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection,
111                                            xcb_drawable_t dst,
112                                            xcb_gcontext_t gc,
113                                            uint32_t num_rectangles,
114                                            xcb_rectangle_t *rectangles)
115 {
116     xcb_poly_fill_rectangle (connection->xcb_connection, dst, gc,
117                              num_rectangles, rectangles);
118 }
119
120 void
121 _cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
122                                  xcb_drawable_t dst,
123                                  xcb_gcontext_t gc,
124                                  uint16_t width,
125                                  uint16_t height,
126                                  int16_t dst_x,
127                                  int16_t dst_y,
128                                  uint8_t depth,
129                                  uint32_t stride,
130                                  void *data)
131 {
132     const uint32_t req_size = 18;
133     uint32_t length = height * stride;
134     uint32_t len = (req_size + length) >> 2;
135
136     if (len < connection->maximum_request_length) {
137         xcb_put_image (connection->xcb_connection, XCB_IMAGE_FORMAT_Z_PIXMAP,
138                        dst, gc, width, height, dst_x, dst_y, 0, depth,
139                        length, data);
140     } else {
141         int rows = (connection->maximum_request_length - req_size - 4) / stride;
142         if (rows > 0) {
143             do {
144                 if (rows > height)
145                     rows = height;
146
147                 length = rows * stride;
148
149                 xcb_put_image (connection->xcb_connection, XCB_IMAGE_FORMAT_Z_PIXMAP,
150                                dst, gc, width, rows, dst_x, dst_y, 0, depth, length, data);
151
152                 height -= rows;
153                 dst_y += rows;
154                 data = (char *) data + length;
155             } while (height);
156         } else {
157             ASSERT_NOT_REACHED;
158         }
159     }
160 }
161
162 void
163 _cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
164                                     xcb_drawable_t dst,
165                                     xcb_gcontext_t gc,
166                                     int16_t src_x,
167                                     int16_t src_y,
168                                     uint16_t width,
169                                     uint16_t height,
170                                     uint16_t cpp,
171                                     int stride,
172                                     int16_t dst_x,
173                                     int16_t dst_y,
174                                     uint8_t depth,
175                                     void *_data)
176 {
177     xcb_protocol_request_t xcb_req = {
178         0 /* count */,
179         0 /* ext */,
180         XCB_PUT_IMAGE /* opcode */,
181         1 /* isvoid (doesn't cause a reply) */
182     };
183     xcb_put_image_request_t req;
184     struct iovec vec_stack[CAIRO_STACK_ARRAY_LENGTH (struct iovec)];
185     struct iovec *vec = vec_stack;
186     uint32_t len = 0;
187     uint8_t *data = _data;
188     int n = 3;
189     /* Two extra entries are needed for xcb, two for us */
190     int entries_needed = height + 2 + 2;
191
192     req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
193     req.drawable = dst;
194     req.gc = gc;
195     req.width = width;
196     req.height = height;
197     req.dst_x = dst_x;
198     req.dst_y = dst_y;
199     req.left_pad = 0;
200     req.depth = depth;
201     req.pad0[0] = 0;
202     req.pad0[1] = 0;
203
204     if (entries_needed > ARRAY_LENGTH (vec_stack)) {
205         vec = _cairo_malloc_ab (entries_needed, sizeof (struct iovec));
206         if (unlikely (vec == NULL)) {
207             /* XXX loop over ARRAY_LENGTH (vec_stack) */
208             return;
209         }
210     }
211
212     data += src_y * stride + src_x * cpp;
213     /* vec[1] will be used in XCB if it has to use BigRequests or insert a sync,
214      * vec[0] is used if the internal queue needs to be flushed. */
215     vec[2].iov_base = (char *) &req;
216     vec[2].iov_len = sizeof (req);
217
218     /* Now comes the actual data */
219     while (height--) {
220         vec[n].iov_base = data;
221         vec[n].iov_len = cpp * width;
222         len += cpp * width;
223         data += stride;
224         n++;
225     }
226
227     /* And again some padding */
228     vec[n].iov_base = 0;
229     vec[n].iov_len = -len & 3;
230     n++;
231
232     /* For efficiency reasons, this functions writes the request "directly" to
233      * the xcb connection to avoid having to copy the data around. */
234     assert (n == entries_needed);
235     xcb_req.count = n - 2;
236     xcb_send_request (connection->xcb_connection, 0, &vec[2], &xcb_req);
237
238     if (vec != vec_stack)
239         free (vec);
240 }
241
242 cairo_status_t
243 _cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
244                                  xcb_drawable_t src,
245                                  int16_t src_x,
246                                  int16_t src_y,
247                                  uint16_t width,
248                                  uint16_t height,
249                                  xcb_get_image_reply_t **reply)
250 {
251     xcb_generic_error_t *error;
252
253     *reply = xcb_get_image_reply (connection->xcb_connection,
254                                   xcb_get_image (connection->xcb_connection,
255                                                  XCB_IMAGE_FORMAT_Z_PIXMAP,
256                                                  src,
257                                                  src_x, src_y,
258                                                  width, height,
259                                                  (uint32_t) -1),
260
261                                   &error);
262     if (error) {
263         free (error);
264
265         free (*reply);
266         *reply = NULL;
267     }
268
269     return CAIRO_STATUS_SUCCESS;
270 }