1721cadac5157e80eef2e4342274619e5313b66e
[framework/uifw/xorg/xcb/xcb-util.git] / renderutil / glyph.c
1 /* Copyright © 2006 Ian Osgood
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a
4  * copy of this software and associated documentation files (the "Software"),
5  * to deal in the Software without restriction, including without limitation
6  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7  * and/or sell copies of the Software, and to permit persons to whom the
8  * Software is furnished to do so, subject to the following conditions:
9  * 
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  * 
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
17  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  * 
20  * Except as contained in this notice, the names of the authors or their
21  * institutions shall not be used in advertising or otherwise to promote the
22  * sale, use or other dealings in this Software without prior written
23  * authorization from the authors.
24  */
25
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "xcb_renderutil.h"
30
31 typedef struct _glyph_header_t {
32         uint8_t count;
33         uint8_t pad0[3];
34         int16_t dx, dy;
35 } _glyph_header_t;
36
37 /* implementation of the opaque stream */
38 struct xcb_render_util_composite_text_stream_t {
39         /* state info */
40         uint32_t glyph_size;            /* 0 for unset, 1/2/4 for 8/16/32 */
41         xcb_render_glyphset_t initial_glyphset;
42         xcb_render_glyphset_t current_glyphset;
43
44         /* dynamically allocated stream */
45         /* contents are 32-bit aligned, network byte order */
46         size_t stream_len;
47         uint32_t *stream;
48         uint32_t *current;
49 };
50
51 #define CURRENT_LEN(s) (((char *)s->current - (char *)s->stream))
52
53 xcb_render_util_composite_text_stream_t *
54 xcb_render_util_composite_text_stream (
55         xcb_render_glyphset_t initial_glyphset,
56         uint32_t              total_glyphs,
57         uint32_t              total_glyphset_changes )
58 {
59         xcb_render_util_composite_text_stream_t *stream;
60         size_t size = 32;
61
62         /* assume worst case: each glyph has its own dx,dy */
63         if (total_glyphs || total_glyphset_changes) {
64                 size = total_glyphs * 3 * sizeof(uint32_t)
65                      + total_glyphset_changes * 3 * sizeof(uint32_t);
66         }
67
68         stream = malloc(sizeof(xcb_render_util_composite_text_stream_t));
69
70         stream->glyph_size = 0;
71         stream->initial_glyphset = initial_glyphset;
72         stream->current_glyphset = initial_glyphset;
73
74         stream->stream_len = size;
75         stream->stream = malloc(size);
76         stream->current = stream->stream;
77
78         return stream;
79 }
80
81 static void
82 _grow_stream( xcb_render_util_composite_text_stream_t *stream, size_t increase )
83 {
84         size_t current_len = CURRENT_LEN(stream);
85         if (current_len + increase > stream->stream_len) {
86                 uint32_t *s = realloc(stream->stream, 2 * stream->stream_len);
87                 if (s != NULL) {
88                         stream->stream_len *= 2;
89                         stream->stream = s;
90                         stream->current = stream->stream + (current_len>>2);
91                 }
92         }
93 }
94
95 void
96 xcb_render_util_glyphs_8 (
97         xcb_render_util_composite_text_stream_t *stream,
98         int16_t  dx,
99         int16_t  dy,
100         uint32_t count,
101         const uint8_t *glyphs )
102 {
103         _glyph_header_t header = { count, {0,0,0}, dx, dy };
104
105         if (count > 252) return; /* FIXME */
106
107         if (stream->glyph_size != sizeof(*glyphs)) {
108                 if (stream->glyph_size != 0)
109                         return;
110                 stream->glyph_size = sizeof(*glyphs);
111         }
112         _grow_stream(stream, sizeof(header) + count+3);
113
114         memcpy(stream->current, &header, sizeof(header));
115         stream->current += 2;
116
117         memcpy(stream->current, glyphs, header.count);
118         stream->current += ((int)header.count+3)>>2;
119 }
120
121 void
122 xcb_render_util_glyphs_16 (
123         xcb_render_util_composite_text_stream_t *stream,
124         int16_t  dx,
125         int16_t  dy,
126         uint32_t count,
127         const uint16_t *glyphs )
128 {
129         _glyph_header_t header = { count, {0,0,0}, dx, dy };
130
131         if (count > 254) return; /* FIXME */
132
133         if (stream->glyph_size != sizeof(*glyphs)) {
134                 if (stream->glyph_size != 0)
135                         return;
136                 stream->glyph_size = sizeof(*glyphs);
137         }
138         _grow_stream(stream, sizeof(header) + count*sizeof(*glyphs)+1);
139
140         memcpy(stream->current, &header, sizeof(header));
141         stream->current += 2;
142
143         memcpy(stream->current, glyphs, header.count*sizeof(*glyphs));
144         stream->current += ((int)header.count*sizeof(*glyphs)+3)>>2;
145 }
146
147 void
148 xcb_render_util_glyphs_32 (
149         xcb_render_util_composite_text_stream_t *stream,
150         int16_t  dx,
151         int16_t  dy,
152         uint32_t count,
153         const uint32_t *glyphs )
154 {
155         _glyph_header_t header = { count, {0,0,0}, dx, dy };
156
157         if (count > 254) return; /* FIXME */
158
159         if (stream->glyph_size != sizeof(*glyphs)) {
160                 if (stream->glyph_size != 0)
161                         return;
162                 stream->glyph_size = sizeof(*glyphs);
163         }
164         _grow_stream(stream, sizeof(header) + count*sizeof(*glyphs)+1);
165
166         memcpy(stream->current, &header, sizeof(header));
167         stream->current += 2;
168
169         memcpy(stream->current, glyphs, header.count*sizeof(*glyphs));
170         stream->current += header.count;
171 }
172
173 /* note: these glyph arrays must be swapped to network byte order */
174
175 void
176 xcb_render_util_change_glyphset (
177         xcb_render_util_composite_text_stream_t *stream,
178         xcb_render_glyphset_t glyphset )
179 {
180         static _glyph_header_t header = { 255, {0,0,0}, 0, 0 };
181
182         if (glyphset == stream->current_glyphset)
183                 return;
184
185         _grow_stream(stream, 3*sizeof(uint32_t));
186
187         memcpy(stream->current, &header, sizeof(header));
188         stream->current += 2;
189
190         *stream->current = glyphset;
191         stream->current++;
192
193         stream->current_glyphset = glyphset;
194 }
195         
196 typedef xcb_void_cookie_t
197 (*xcb_render_composite_glyphs_func) (xcb_connection_t        *c,
198                                      uint8_t                  op,
199                                      xcb_render_picture_t     src,
200                                      xcb_render_picture_t     dst,
201                                      xcb_render_pictformat_t  mask_format,
202                                      xcb_render_glyphset_t    glyphset,
203                                      int16_t                  src_x,
204                                      int16_t                  src_y,
205                                      uint32_t                 glyphcmds_len,
206                                      const uint8_t           *glyphcmds);
207
208
209 xcb_void_cookie_t
210 xcb_render_util_composite_text (
211         xcb_connection_t        *xc,
212         uint8_t                  op,
213         xcb_render_picture_t     src,
214         xcb_render_picture_t     dst,
215         xcb_render_pictformat_t  mask_format,
216         int16_t                  src_x,
217         int16_t                  src_y,
218         xcb_render_util_composite_text_stream_t *stream )
219 {
220         xcb_render_composite_glyphs_func f;
221
222         switch (stream->glyph_size)
223         {
224         case 1:
225                 f = xcb_render_composite_glyphs_8;
226                 break;
227         case 2:
228                 f = xcb_render_composite_glyphs_16;
229                 break;
230         case 4:
231                 f = xcb_render_composite_glyphs_32;
232                 break;
233         default: /* uninitialized */
234                 return xcb_no_operation(xc);
235         }
236         return f(
237                 xc, op, src, dst, mask_format,
238                 stream->initial_glyphset,
239                 src_x, src_y,
240                 CURRENT_LEN(stream),
241                 (uint8_t *)stream->stream
242         );
243 }
244
245 xcb_void_cookie_t
246 xcb_render_util_composite_text_checked (
247         xcb_connection_t        *xc,
248         uint8_t                  op,
249         xcb_render_picture_t     src,
250         xcb_render_picture_t     dst,
251         xcb_render_pictformat_t  mask_format,
252         int16_t                  src_x,
253         int16_t                  src_y,
254         xcb_render_util_composite_text_stream_t *stream )
255 {
256         xcb_render_composite_glyphs_func f;
257
258         switch (stream->glyph_size)
259         {
260         case 1:
261                 f = xcb_render_composite_glyphs_8_checked;
262                 break;
263         case 2:
264                 f = xcb_render_composite_glyphs_16_checked;
265                 break;
266         case 4:
267                 f = xcb_render_composite_glyphs_32_checked;
268                 break;
269         default: /* uninitialized */
270                 return xcb_no_operation_checked(xc);
271         }
272         return f(
273                 xc, op, src, dst, mask_format,
274                 stream->initial_glyphset,
275                 src_x, src_y,
276                 CURRENT_LEN(stream),
277                 (uint8_t *)stream->stream
278         );
279 }
280
281 void
282 xcb_render_util_composite_text_free (
283         xcb_render_util_composite_text_stream_t *stream )
284 {
285         free(stream->stream);
286         free(stream);
287 }