290 lines
7.9 KiB
C
290 lines
7.9 KiB
C
|
/* Copyright © 2006 Ian Osgood
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
* copy of this software and associated documentation files (the "Software"),
|
||
|
* to deal in the Software without restriction, including without limitation
|
||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||
|
* Software is furnished to do so, subject to the following conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be included in
|
||
|
* all copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
* AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
*
|
||
|
* Except as contained in this notice, the names of the authors or their
|
||
|
* institutions shall not be used in advertising or otherwise to promote the
|
||
|
* sale, use or other dealings in this Software without prior written
|
||
|
* authorization from the authors.
|
||
|
*/
|
||
|
|
||
|
#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;
|
||
|
|
||
|
/* implementation of the opaque stream */
|
||
|
struct xcb_render_util_composite_text_stream_t {
|
||
|
/* state info */
|
||
|
uint32_t glyph_size; /* 0 for unset, 1/2/4 for 8/16/32 */
|
||
|
xcb_render_glyphset_t initial_glyphset;
|
||
|
xcb_render_glyphset_t current_glyphset;
|
||
|
|
||
|
/* dynamically allocated stream */
|
||
|
/* contents are 32-bit aligned, network byte order */
|
||
|
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;
|
||
|
|
||
|
/* assume worst case: each glyph has its own dx,dy */
|
||
|
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));
|
||
|
if (!stream)
|
||
|
return NULL;
|
||
|
|
||
|
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; /* FIXME */
|
||
|
|
||
|
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; /* FIXME */
|
||
|
|
||
|
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; /* FIXME */
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/* note: these glyph arrays must be swapped to network byte order */
|
||
|
|
||
|
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: /* uninitialized */
|
||
|
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: /* uninitialized */
|
||
|
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);
|
||
|
}
|