#include <stdlib.h>
#include <string.h>
#include "xcb_renderutil.h"
typedef struct _glyph_header_t {
uint8_t count;
uint8_t pad0[3];
int16_t dx, dy;
} _glyph_header_t;
struct xcb_render_util_composite_text_stream_t {
uint32_t glyph_size;
xcb_render_glyphset_t initial_glyphset;
xcb_render_glyphset_t current_glyphset;
size_t stream_len;
uint32_t *stream;
uint32_t *current;
};
#define CURRENT_LEN(s) (((char *)s->current - (char *)s->stream))
xcb_render_util_composite_text_stream_t *
xcb_render_util_composite_text_stream (
xcb_render_glyphset_t initial_glyphset,
uint32_t total_glyphs,
uint32_t total_glyphset_changes )
{
xcb_render_util_composite_text_stream_t *stream;
size_t size = 32;
if (total_glyphs || total_glyphset_changes) {
size = total_glyphs * 3 * sizeof(uint32_t)
+ total_glyphset_changes * 3 * sizeof(uint32_t);
}
stream = malloc(sizeof(xcb_render_util_composite_text_stream_t));
stream->glyph_size = 0;
stream->initial_glyphset = initial_glyphset;
stream->current_glyphset = initial_glyphset;
stream->stream_len = size;
stream->stream = malloc(size);
stream->current = stream->stream;
return stream;
}
static void
_grow_stream( xcb_render_util_composite_text_stream_t *stream, size_t increase )
{
size_t current_len = CURRENT_LEN(stream);
if (current_len + increase > stream->stream_len) {
uint32_t *s = realloc(stream->stream, 2 * stream->stream_len);
if (s != NULL) {
stream->stream_len *= 2;
stream->stream = s;
stream->current = stream->stream + (current_len>>2);
}
}
}
void
xcb_render_util_glyphs_8 (
xcb_render_util_composite_text_stream_t *stream,
int16_t dx,
int16_t dy,
uint32_t count,
const uint8_t *glyphs )
{
_glyph_header_t header = { count, {0,0,0}, dx, dy };
if (count > 252) return;
if (stream->glyph_size != sizeof(*glyphs)) {
if (stream->glyph_size != 0)
return;
stream->glyph_size = sizeof(*glyphs);
}
_grow_stream(stream, sizeof(header) + count+3);
memcpy(stream->current, &header, sizeof(header));
stream->current += 2;
memcpy(stream->current, glyphs, header.count);
stream->current += ((int)header.count+3)>>2;
}
void
xcb_render_util_glyphs_16 (
xcb_render_util_composite_text_stream_t *stream,
int16_t dx,
int16_t dy,
uint32_t count,
const uint16_t *glyphs )
{
_glyph_header_t header = { count, {0,0,0}, dx, dy };
if (count > 254) return;
if (stream->glyph_size != sizeof(*glyphs)) {
if (stream->glyph_size != 0)
return;
stream->glyph_size = sizeof(*glyphs);
}
_grow_stream(stream, sizeof(header) + count*sizeof(*glyphs)+1);
memcpy(stream->current, &header, sizeof(header));
stream->current += 2;
memcpy(stream->current, glyphs, header.count*sizeof(*glyphs));
stream->current += ((int)header.count*sizeof(*glyphs)+3)>>2;
}
void
xcb_render_util_glyphs_32 (
xcb_render_util_composite_text_stream_t *stream,
int16_t dx,
int16_t dy,
uint32_t count,
const uint32_t *glyphs )
{
_glyph_header_t header = { count, {0,0,0}, dx, dy };
if (count > 254) return;
if (stream->glyph_size != sizeof(*glyphs)) {
if (stream->glyph_size != 0)
return;
stream->glyph_size = sizeof(*glyphs);
}
_grow_stream(stream, sizeof(header) + count*sizeof(*glyphs)+1);
memcpy(stream->current, &header, sizeof(header));
stream->current += 2;
memcpy(stream->current, glyphs, header.count*sizeof(*glyphs));
stream->current += header.count;
}
void
xcb_render_util_change_glyphset (
xcb_render_util_composite_text_stream_t *stream,
xcb_render_glyphset_t glyphset )
{
static _glyph_header_t header = { 255, {0,0,0}, 0, 0 };
if (glyphset == stream->current_glyphset)
return;
_grow_stream(stream, 3*sizeof(uint32_t));
memcpy(stream->current, &header, sizeof(header));
stream->current += 2;
*stream->current = glyphset;
stream->current++;
stream->current_glyphset = glyphset;
}
typedef xcb_void_cookie_t
(*xcb_render_composite_glyphs_func) (xcb_connection_t *c,
uint8_t op,
xcb_render_picture_t src,
xcb_render_picture_t dst,
xcb_render_pictformat_t mask_format,
xcb_render_glyphset_t glyphset,
int16_t src_x,
int16_t src_y,
uint32_t glyphcmds_len,
const uint8_t *glyphcmds);
xcb_void_cookie_t
xcb_render_util_composite_text (
xcb_connection_t *xc,
uint8_t op,
xcb_render_picture_t src,
xcb_render_picture_t dst,
xcb_render_pictformat_t mask_format,
int16_t src_x,
int16_t src_y,
xcb_render_util_composite_text_stream_t *stream )
{
xcb_render_composite_glyphs_func f;
switch (stream->glyph_size)
{
case 1:
f = xcb_render_composite_glyphs_8;
break;
case 2:
f = xcb_render_composite_glyphs_16;
break;
case 4:
f = xcb_render_composite_glyphs_32;
break;
default:
return xcb_no_operation(xc);
}
return f(
xc, op, src, dst, mask_format,
stream->initial_glyphset,
src_x, src_y,
CURRENT_LEN(stream),
(uint8_t *)stream->stream
);
}
xcb_void_cookie_t
xcb_render_util_composite_text_checked (
xcb_connection_t *xc,
uint8_t op,
xcb_render_picture_t src,
xcb_render_picture_t dst,
xcb_render_pictformat_t mask_format,
int16_t src_x,
int16_t src_y,
xcb_render_util_composite_text_stream_t *stream )
{
xcb_render_composite_glyphs_func f;
switch (stream->glyph_size)
{
case 1:
f = xcb_render_composite_glyphs_8_checked;
break;
case 2:
f = xcb_render_composite_glyphs_16_checked;
break;
case 4:
f = xcb_render_composite_glyphs_32_checked;
break;
default:
return xcb_no_operation_checked(xc);
}
return f(
xc, op, src, dst, mask_format,
stream->initial_glyphset,
src_x, src_y,
CURRENT_LEN(stream),
(uint8_t *)stream->stream
);
}
void
xcb_render_util_composite_text_free (
xcb_render_util_composite_text_stream_t *stream )
{
free(stream->stream);
free(stream);
}