diff options
Diffstat (limited to 'test/render-glyphs.c')
-rw-r--r-- | test/render-glyphs.c | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/test/render-glyphs.c b/test/render-glyphs.c new file mode 100644 index 00000000..8822e36a --- /dev/null +++ b/test/render-glyphs.c @@ -0,0 +1,441 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdarg.h> +#include <string.h> + +#include <X11/Xutil.h> /* for XDestroyImage */ +#include <pixman.h> /* for pixman blt functions */ + +#include "test.h" + +static const XRenderColor colors[] = { + /* red, green, blue, alpha */ + { 0 }, + { 0, 0, 0, 0xffff }, + { 0xffff, 0, 0, 0xffff }, + { 0, 0xffff, 0, 0xffff }, + { 0, 0, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff }, +}; + +static struct clip { + void *func; +} clips[] = { + { NULL }, +}; + +static int _x_error_occurred; + +static int +_check_error_handler(Display *display, + XErrorEvent *event) +{ + _x_error_occurred = 1; + return False; /* ignored */ +} + +static void clear(struct test_display *dpy, + struct test_target *tt, + const XRenderColor *c) +{ + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, c, + 0, 0, tt->width, tt->height); +} + +static bool check_op(struct test_display *dpy, int op, struct test_target *tt) +{ + XRenderColor render_color = {0}; + + XSync(dpy->dpy, True); + _x_error_occurred = 0; + + XRenderFillRectangle(dpy->dpy, op, + tt->picture, &render_color, + 0, 0, 0, 0); + + XSync(dpy->dpy, True); + return _x_error_occurred == 0; +} + +struct glyph_iter { + enum { + GLYPHS, OP, DST, SRC, MASK, CLIP, + } stage; + + int glyph_format; + int op; + int dst_color; + int src_color; + int mask_format; + int clip; + + struct { + struct test_display *dpy; + struct test_target tt; + GlyphSet glyphset; + Picture src; + XRenderPictFormat *mask_format; + } ref, out; +}; + +static void glyph_iter_init(struct glyph_iter *gi, + struct test *t, enum target target) +{ + memset(gi, 0, sizeof(*gi)); + + gi->out.dpy = &t->out; + test_target_create_render(&t->out, target, &gi->out.tt); + + gi->ref.dpy = &t->ref; + test_target_create_render(&t->ref, target, &gi->ref.tt); + + gi->stage = GLYPHS; + gi->glyph_format = -1; + gi->op = -1; + gi->dst_color = -1; + gi->src_color = -1; + gi->mask_format = -1; + gi->clip = -1; +} + +static void render_clear(char *image, int image_size, int bpp) +{ + memset(image, 0, image_size); +} + +static void render_black(char *image, int image_size, int bpp) +{ + if (bpp == 4) { + uint32_t *p = (uint32_t *)image; + image_size /= 4; + while (image_size--) + *p++ = 0x000000ff; + } else + memset(image, 0x55, image_size); +} + +static void render_green(char *image, int image_size, int bpp) +{ + if (bpp == 4) { + uint32_t *p = (uint32_t *)image; + image_size /= 4; + while (image_size--) + *p++ = 0xffff0000; + } else + memset(image, 0xaa, image_size); +} + +static void render_white(char *image, int image_size, int bpp) +{ + memset(image, 0xff, image_size); +} + +static GlyphSet create_glyphs(Display *dpy, int format_id) +{ +#define N_GLYPHS 4 + XRenderPictFormat *format; + XGlyphInfo glyph = { 8, 8, 0, 0, 8, 0 }; + char image[4*8*8]; + GlyphSet glyphset; + Glyph gid; + int image_size; + int bpp; + int n; + + format = XRenderFindStandardFormat(dpy, format_id); + if (format == NULL) + return 0; + + switch (format_id) { + case PictStandardARGB32: + case PictStandardRGB24: + image_size = 4 * 8 * 8; + bpp = 4; + break; + case PictStandardA8: + case PictStandardA4: + image_size = 8 * 8; + bpp = 1; + break; + case PictStandardA1: + image_size = 8; + bpp = 0; + break; + default: + return 0; + } + + glyphset = XRenderCreateGlyphSet(dpy, format); + for (n = 0; n < N_GLYPHS; n++) { + gid = n; + + switch (n) { + case 0: render_clear(image, image_size, bpp); break; + case 1: render_black(image, image_size, bpp); break; + case 2: render_green(image, image_size, bpp); break; + case 3: render_white(image, image_size, bpp); break; + } + + XRenderAddGlyphs(dpy, glyphset, + &gid, &glyph, 1, image, image_size); + } + + return glyphset; +} + +static const char *glyph_name(int n) +{ + switch (n) { + case 0: return "clear"; + case 1: return "black"; + case 2: return "green"; + case 3: return "white"; + default: return "unknown"; + } +} + +static bool glyph_iter_next(struct glyph_iter *gi) +{ +restart: + if (gi->stage == GLYPHS) { + if (++gi->glyph_format == PictStandardNUM) + return false; + + if (gi->out.glyphset) + XRenderFreeGlyphSet(gi->out.dpy->dpy, + gi->out.glyphset); + gi->out.glyphset = create_glyphs(gi->out.dpy->dpy, + gi->glyph_format); + + if (gi->ref.glyphset) + XRenderFreeGlyphSet(gi->ref.dpy->dpy, + gi->ref.glyphset); + gi->ref.glyphset = create_glyphs(gi->ref.dpy->dpy, + gi->glyph_format); + + gi->stage++; + } + + if (gi->stage == OP) { + do { + if (++gi->op == 255) + goto reset_op; + } while (!check_op(gi->out.dpy, gi->op, &gi->out.tt) || + !check_op(gi->ref.dpy, gi->op, &gi->ref.tt)); + + gi->stage++; + } + + if (gi->stage == DST) { + if (++gi->dst_color == ARRAY_SIZE(colors)) + goto reset_dst; + + gi->stage++; + } + + if (gi->stage == SRC) { + if (++gi->src_color == ARRAY_SIZE(colors)) + goto reset_src; + + if (gi->ref.src) + XRenderFreePicture(gi->ref.dpy->dpy, gi->ref.src); + gi->ref.src = XRenderCreateSolidFill(gi->ref.dpy->dpy, + &colors[gi->src_color]); + + if (gi->out.src) + XRenderFreePicture(gi->out.dpy->dpy, gi->out.src); + gi->out.src = XRenderCreateSolidFill(gi->out.dpy->dpy, + &colors[gi->src_color]); + + gi->stage++; + } + + if (gi->stage == MASK) { + if (++gi->mask_format > PictStandardNUM) + goto reset_mask; + + if (gi->mask_format == PictStandardRGB24) + gi->mask_format++; + + if (gi->mask_format < PictStandardNUM) { + gi->out.mask_format = XRenderFindStandardFormat(gi->out.dpy->dpy, + gi->mask_format); + gi->ref.mask_format = XRenderFindStandardFormat(gi->ref.dpy->dpy, + gi->mask_format); + } else { + gi->out.mask_format = NULL; + gi->ref.mask_format = NULL; + } + + gi->stage++; + } + + if (gi->stage == CLIP) { + if (++gi->clip == ARRAY_SIZE(clips)) + goto reset_clip; + + gi->stage++; + } + + gi->stage--; + return true; + +reset_op: + gi->op = -1; +reset_dst: + gi->dst_color = -1; +reset_src: + gi->src_color = -1; +reset_mask: + gi->mask_format = -1; +reset_clip: + gi->clip = -1; + gi->stage--; + goto restart; +} + +static void glyph_iter_fini(struct glyph_iter *gi) +{ + if (gi->out.glyphset) + XRenderFreeGlyphSet (gi->out.dpy->dpy, gi->out.glyphset); + if (gi->ref.glyphset) + XRenderFreeGlyphSet (gi->ref.dpy->dpy, gi->ref.glyphset); + + test_target_destroy_render(gi->out.dpy, &gi->out.tt); + test_target_destroy_render(gi->ref.dpy, &gi->ref.tt); +} + +static const char *stdformat_to_str(int id) +{ + switch (id) { + case PictStandardARGB32: return "ARGB32"; + case PictStandardRGB24: return "RGB24"; + case PictStandardA8: return "A8"; + case PictStandardA4: return "A4"; + case PictStandardA1: return "A1"; + default: return "none"; + } +} + +static char *glyph_iter_to_string(struct glyph_iter *gi, + const char *format, + ...) +{ + static char buf[100]; + va_list ap; + int len; + + len = sprintf(buf, "glyphs=%s, op=%d, dst=%08x, src=%08x, mask=%s", + stdformat_to_str(gi->glyph_format), gi->op, + xrender_color(&colors[gi->dst_color]), + xrender_color(&colors[gi->src_color]), + stdformat_to_str(gi->mask_format)); + + if (format) { + buf[len++] = ' '; + va_start(ap, format); + vsprintf(buf+len, format, ap); + va_end(ap); + } + + return buf; +} + +static void single(struct test *t, enum target target) +{ + struct glyph_iter gi; + int n; + + printf("Testing single glyph (%s): ", test_target_name(target)); + fflush(stdout); + + glyph_iter_init(&gi, t, target); + while (glyph_iter_next(&gi)) { + XGlyphElt8 elt; + char id[N_GLYPHS]; + + for (n = 0; n < N_GLYPHS; n++) { + id[n] = n; + + elt.chars = &id[n]; + elt.nchars = 1; + elt.xOff = 0; + elt.yOff = 0; + + clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]); + elt.glyphset = gi.out.glyphset; + XRenderCompositeText8 (gi.out.dpy->dpy, gi.op, + gi.out.src, + gi.out.tt.picture, + gi.out.mask_format, + 0, 0, + 0, 8, + &elt, 1); + + clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]); + elt.glyphset = gi.ref.glyphset; + XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op, + gi.ref.src, + gi.ref.tt.picture, + gi.ref.mask_format, + 0, 0, + 0, 8, + &elt, 1); + test_compare(t, + gi.out.tt.draw, gi.out.tt.format, + gi.ref.tt.draw, gi.ref.tt.format, + 0, 0, gi.out.tt.width, gi.out.tt.height, + glyph_iter_to_string(&gi, + "glyph=%s", + glyph_name(n))); + } + + elt.chars = &id[0]; + elt.nchars = n; + clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]); + elt.glyphset = gi.out.glyphset; + XRenderCompositeText8 (gi.out.dpy->dpy, gi.op, + gi.out.src, + gi.out.tt.picture, + gi.out.mask_format, + 0, 0, + 0, 8, + &elt, 1); + + clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]); + elt.glyphset = gi.ref.glyphset; + XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op, + gi.ref.src, + gi.ref.tt.picture, + gi.ref.mask_format, + 0, 0, + 0, 8, + &elt, 1); + test_compare(t, + gi.out.tt.draw, gi.out.tt.format, + gi.ref.tt.draw, gi.ref.tt.format, + 0, 0, gi.out.tt.width, gi.out.tt.height, + glyph_iter_to_string(&gi, "all")); + } + glyph_iter_fini(&gi); +} + +int main(int argc, char **argv) +{ + struct test test; + int t; + + test_init(&test, argc, argv); + XSetErrorHandler(_check_error_handler); + + for (t = TARGET_FIRST; t <= TARGET_LAST; t++) { + single(&test, t); + //overlapping(&test, t); + //gap(&test, t); + //mixed(&test, t); + } + + return 0; +} |