render-glyphs.c revision fe8aea9e
1fe8aea9eSmrg#include <stdint.h> 2fe8aea9eSmrg#include <stdio.h> 3fe8aea9eSmrg#include <stdlib.h> 4fe8aea9eSmrg#include <stdbool.h> 5fe8aea9eSmrg#include <stdarg.h> 6fe8aea9eSmrg#include <string.h> 7fe8aea9eSmrg 8fe8aea9eSmrg#include <X11/Xutil.h> /* for XDestroyImage */ 9fe8aea9eSmrg#include <pixman.h> /* for pixman blt functions */ 10fe8aea9eSmrg 11fe8aea9eSmrg#include "test.h" 12fe8aea9eSmrg 13fe8aea9eSmrgstatic const XRenderColor colors[] = { 14fe8aea9eSmrg /* red, green, blue, alpha */ 15fe8aea9eSmrg { 0 }, 16fe8aea9eSmrg { 0, 0, 0, 0xffff }, 17fe8aea9eSmrg { 0xffff, 0, 0, 0xffff }, 18fe8aea9eSmrg { 0, 0xffff, 0, 0xffff }, 19fe8aea9eSmrg { 0, 0, 0xffff, 0xffff }, 20fe8aea9eSmrg { 0xffff, 0xffff, 0xffff, 0xffff }, 21fe8aea9eSmrg}; 22fe8aea9eSmrg 23fe8aea9eSmrgstatic struct clip { 24fe8aea9eSmrg void *func; 25fe8aea9eSmrg} clips[] = { 26fe8aea9eSmrg { NULL }, 27fe8aea9eSmrg}; 28fe8aea9eSmrg 29fe8aea9eSmrgstatic int _x_error_occurred; 30fe8aea9eSmrg 31fe8aea9eSmrgstatic int 32fe8aea9eSmrg_check_error_handler(Display *display, 33fe8aea9eSmrg XErrorEvent *event) 34fe8aea9eSmrg{ 35fe8aea9eSmrg _x_error_occurred = 1; 36fe8aea9eSmrg return False; /* ignored */ 37fe8aea9eSmrg} 38fe8aea9eSmrg 39fe8aea9eSmrgstatic void clear(struct test_display *dpy, 40fe8aea9eSmrg struct test_target *tt, 41fe8aea9eSmrg const XRenderColor *c) 42fe8aea9eSmrg{ 43fe8aea9eSmrg XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, c, 44fe8aea9eSmrg 0, 0, tt->width, tt->height); 45fe8aea9eSmrg} 46fe8aea9eSmrg 47fe8aea9eSmrgstatic bool check_op(struct test_display *dpy, int op, struct test_target *tt) 48fe8aea9eSmrg{ 49fe8aea9eSmrg XRenderColor render_color = {0}; 50fe8aea9eSmrg 51fe8aea9eSmrg XSync(dpy->dpy, True); 52fe8aea9eSmrg _x_error_occurred = 0; 53fe8aea9eSmrg 54fe8aea9eSmrg XRenderFillRectangle(dpy->dpy, op, 55fe8aea9eSmrg tt->picture, &render_color, 56fe8aea9eSmrg 0, 0, 0, 0); 57fe8aea9eSmrg 58fe8aea9eSmrg XSync(dpy->dpy, True); 59fe8aea9eSmrg return _x_error_occurred == 0; 60fe8aea9eSmrg} 61fe8aea9eSmrg 62fe8aea9eSmrgstruct glyph_iter { 63fe8aea9eSmrg enum { 64fe8aea9eSmrg GLYPHS, OP, DST, SRC, MASK, CLIP, 65fe8aea9eSmrg } stage; 66fe8aea9eSmrg 67fe8aea9eSmrg int glyph_format; 68fe8aea9eSmrg int op; 69fe8aea9eSmrg int dst_color; 70fe8aea9eSmrg int src_color; 71fe8aea9eSmrg int mask_format; 72fe8aea9eSmrg int clip; 73fe8aea9eSmrg 74fe8aea9eSmrg struct { 75fe8aea9eSmrg struct test_display *dpy; 76fe8aea9eSmrg struct test_target tt; 77fe8aea9eSmrg GlyphSet glyphset; 78fe8aea9eSmrg Picture src; 79fe8aea9eSmrg XRenderPictFormat *mask_format; 80fe8aea9eSmrg } ref, out; 81fe8aea9eSmrg}; 82fe8aea9eSmrg 83fe8aea9eSmrgstatic void glyph_iter_init(struct glyph_iter *gi, 84fe8aea9eSmrg struct test *t, enum target target) 85fe8aea9eSmrg{ 86fe8aea9eSmrg memset(gi, 0, sizeof(*gi)); 87fe8aea9eSmrg 88fe8aea9eSmrg gi->out.dpy = &t->out; 89fe8aea9eSmrg test_target_create_render(&t->out, target, &gi->out.tt); 90fe8aea9eSmrg 91fe8aea9eSmrg gi->ref.dpy = &t->ref; 92fe8aea9eSmrg test_target_create_render(&t->ref, target, &gi->ref.tt); 93fe8aea9eSmrg 94fe8aea9eSmrg gi->stage = GLYPHS; 95fe8aea9eSmrg gi->glyph_format = -1; 96fe8aea9eSmrg gi->op = -1; 97fe8aea9eSmrg gi->dst_color = -1; 98fe8aea9eSmrg gi->src_color = -1; 99fe8aea9eSmrg gi->mask_format = -1; 100fe8aea9eSmrg gi->clip = -1; 101fe8aea9eSmrg} 102fe8aea9eSmrg 103fe8aea9eSmrgstatic void render_clear(char *image, int image_size, int bpp) 104fe8aea9eSmrg{ 105fe8aea9eSmrg memset(image, 0, image_size); 106fe8aea9eSmrg} 107fe8aea9eSmrg 108fe8aea9eSmrgstatic void render_black(char *image, int image_size, int bpp) 109fe8aea9eSmrg{ 110fe8aea9eSmrg if (bpp == 4) { 111fe8aea9eSmrg uint32_t *p = (uint32_t *)image; 112fe8aea9eSmrg image_size /= 4; 113fe8aea9eSmrg while (image_size--) 114fe8aea9eSmrg *p++ = 0x000000ff; 115fe8aea9eSmrg } else 116fe8aea9eSmrg memset(image, 0x55, image_size); 117fe8aea9eSmrg} 118fe8aea9eSmrg 119fe8aea9eSmrgstatic void render_green(char *image, int image_size, int bpp) 120fe8aea9eSmrg{ 121fe8aea9eSmrg if (bpp == 4) { 122fe8aea9eSmrg uint32_t *p = (uint32_t *)image; 123fe8aea9eSmrg image_size /= 4; 124fe8aea9eSmrg while (image_size--) 125fe8aea9eSmrg *p++ = 0xffff0000; 126fe8aea9eSmrg } else 127fe8aea9eSmrg memset(image, 0xaa, image_size); 128fe8aea9eSmrg} 129fe8aea9eSmrg 130fe8aea9eSmrgstatic void render_white(char *image, int image_size, int bpp) 131fe8aea9eSmrg{ 132fe8aea9eSmrg memset(image, 0xff, image_size); 133fe8aea9eSmrg} 134fe8aea9eSmrg 135fe8aea9eSmrgstatic GlyphSet create_glyphs(Display *dpy, int format_id) 136fe8aea9eSmrg{ 137fe8aea9eSmrg#define N_GLYPHS 4 138fe8aea9eSmrg XRenderPictFormat *format; 139fe8aea9eSmrg XGlyphInfo glyph = { 8, 8, 0, 0, 8, 0 }; 140fe8aea9eSmrg char image[4*8*8]; 141fe8aea9eSmrg GlyphSet glyphset; 142fe8aea9eSmrg Glyph gid; 143fe8aea9eSmrg int image_size; 144fe8aea9eSmrg int bpp; 145fe8aea9eSmrg int n; 146fe8aea9eSmrg 147fe8aea9eSmrg format = XRenderFindStandardFormat(dpy, format_id); 148fe8aea9eSmrg if (format == NULL) 149fe8aea9eSmrg return 0; 150fe8aea9eSmrg 151fe8aea9eSmrg switch (format_id) { 152fe8aea9eSmrg case PictStandardARGB32: 153fe8aea9eSmrg case PictStandardRGB24: 154fe8aea9eSmrg image_size = 4 * 8 * 8; 155fe8aea9eSmrg bpp = 4; 156fe8aea9eSmrg break; 157fe8aea9eSmrg case PictStandardA8: 158fe8aea9eSmrg case PictStandardA4: 159fe8aea9eSmrg image_size = 8 * 8; 160fe8aea9eSmrg bpp = 1; 161fe8aea9eSmrg break; 162fe8aea9eSmrg case PictStandardA1: 163fe8aea9eSmrg image_size = 8; 164fe8aea9eSmrg bpp = 0; 165fe8aea9eSmrg break; 166fe8aea9eSmrg default: 167fe8aea9eSmrg return 0; 168fe8aea9eSmrg } 169fe8aea9eSmrg 170fe8aea9eSmrg glyphset = XRenderCreateGlyphSet(dpy, format); 171fe8aea9eSmrg for (n = 0; n < N_GLYPHS; n++) { 172fe8aea9eSmrg gid = n; 173fe8aea9eSmrg 174fe8aea9eSmrg switch (n) { 175fe8aea9eSmrg case 0: render_clear(image, image_size, bpp); break; 176fe8aea9eSmrg case 1: render_black(image, image_size, bpp); break; 177fe8aea9eSmrg case 2: render_green(image, image_size, bpp); break; 178fe8aea9eSmrg case 3: render_white(image, image_size, bpp); break; 179fe8aea9eSmrg } 180fe8aea9eSmrg 181fe8aea9eSmrg XRenderAddGlyphs(dpy, glyphset, 182fe8aea9eSmrg &gid, &glyph, 1, image, image_size); 183fe8aea9eSmrg } 184fe8aea9eSmrg 185fe8aea9eSmrg return glyphset; 186fe8aea9eSmrg} 187fe8aea9eSmrg 188fe8aea9eSmrgstatic const char *glyph_name(int n) 189fe8aea9eSmrg{ 190fe8aea9eSmrg switch (n) { 191fe8aea9eSmrg case 0: return "clear"; 192fe8aea9eSmrg case 1: return "black"; 193fe8aea9eSmrg case 2: return "green"; 194fe8aea9eSmrg case 3: return "white"; 195fe8aea9eSmrg default: return "unknown"; 196fe8aea9eSmrg } 197fe8aea9eSmrg} 198fe8aea9eSmrg 199fe8aea9eSmrgstatic bool glyph_iter_next(struct glyph_iter *gi) 200fe8aea9eSmrg{ 201fe8aea9eSmrgrestart: 202fe8aea9eSmrg if (gi->stage == GLYPHS) { 203fe8aea9eSmrg if (++gi->glyph_format == PictStandardNUM) 204fe8aea9eSmrg return false; 205fe8aea9eSmrg 206fe8aea9eSmrg if (gi->out.glyphset) 207fe8aea9eSmrg XRenderFreeGlyphSet(gi->out.dpy->dpy, 208fe8aea9eSmrg gi->out.glyphset); 209fe8aea9eSmrg gi->out.glyphset = create_glyphs(gi->out.dpy->dpy, 210fe8aea9eSmrg gi->glyph_format); 211fe8aea9eSmrg 212fe8aea9eSmrg if (gi->ref.glyphset) 213fe8aea9eSmrg XRenderFreeGlyphSet(gi->ref.dpy->dpy, 214fe8aea9eSmrg gi->ref.glyphset); 215fe8aea9eSmrg gi->ref.glyphset = create_glyphs(gi->ref.dpy->dpy, 216fe8aea9eSmrg gi->glyph_format); 217fe8aea9eSmrg 218fe8aea9eSmrg gi->stage++; 219fe8aea9eSmrg } 220fe8aea9eSmrg 221fe8aea9eSmrg if (gi->stage == OP) { 222fe8aea9eSmrg do { 223fe8aea9eSmrg if (++gi->op == 255) 224fe8aea9eSmrg goto reset_op; 225fe8aea9eSmrg } while (!check_op(gi->out.dpy, gi->op, &gi->out.tt) || 226fe8aea9eSmrg !check_op(gi->ref.dpy, gi->op, &gi->ref.tt)); 227fe8aea9eSmrg 228fe8aea9eSmrg gi->stage++; 229fe8aea9eSmrg } 230fe8aea9eSmrg 231fe8aea9eSmrg if (gi->stage == DST) { 232fe8aea9eSmrg if (++gi->dst_color == ARRAY_SIZE(colors)) 233fe8aea9eSmrg goto reset_dst; 234fe8aea9eSmrg 235fe8aea9eSmrg gi->stage++; 236fe8aea9eSmrg } 237fe8aea9eSmrg 238fe8aea9eSmrg if (gi->stage == SRC) { 239fe8aea9eSmrg if (++gi->src_color == ARRAY_SIZE(colors)) 240fe8aea9eSmrg goto reset_src; 241fe8aea9eSmrg 242fe8aea9eSmrg if (gi->ref.src) 243fe8aea9eSmrg XRenderFreePicture(gi->ref.dpy->dpy, gi->ref.src); 244fe8aea9eSmrg gi->ref.src = XRenderCreateSolidFill(gi->ref.dpy->dpy, 245fe8aea9eSmrg &colors[gi->src_color]); 246fe8aea9eSmrg 247fe8aea9eSmrg if (gi->out.src) 248fe8aea9eSmrg XRenderFreePicture(gi->out.dpy->dpy, gi->out.src); 249fe8aea9eSmrg gi->out.src = XRenderCreateSolidFill(gi->out.dpy->dpy, 250fe8aea9eSmrg &colors[gi->src_color]); 251fe8aea9eSmrg 252fe8aea9eSmrg gi->stage++; 253fe8aea9eSmrg } 254fe8aea9eSmrg 255fe8aea9eSmrg if (gi->stage == MASK) { 256fe8aea9eSmrg if (++gi->mask_format > PictStandardNUM) 257fe8aea9eSmrg goto reset_mask; 258fe8aea9eSmrg 259fe8aea9eSmrg if (gi->mask_format == PictStandardRGB24) 260fe8aea9eSmrg gi->mask_format++; 261fe8aea9eSmrg 262fe8aea9eSmrg if (gi->mask_format < PictStandardNUM) { 263fe8aea9eSmrg gi->out.mask_format = XRenderFindStandardFormat(gi->out.dpy->dpy, 264fe8aea9eSmrg gi->mask_format); 265fe8aea9eSmrg gi->ref.mask_format = XRenderFindStandardFormat(gi->ref.dpy->dpy, 266fe8aea9eSmrg gi->mask_format); 267fe8aea9eSmrg } else { 268fe8aea9eSmrg gi->out.mask_format = NULL; 269fe8aea9eSmrg gi->ref.mask_format = NULL; 270fe8aea9eSmrg } 271fe8aea9eSmrg 272fe8aea9eSmrg gi->stage++; 273fe8aea9eSmrg } 274fe8aea9eSmrg 275fe8aea9eSmrg if (gi->stage == CLIP) { 276fe8aea9eSmrg if (++gi->clip == ARRAY_SIZE(clips)) 277fe8aea9eSmrg goto reset_clip; 278fe8aea9eSmrg 279fe8aea9eSmrg gi->stage++; 280fe8aea9eSmrg } 281fe8aea9eSmrg 282fe8aea9eSmrg gi->stage--; 283fe8aea9eSmrg return true; 284fe8aea9eSmrg 285fe8aea9eSmrgreset_op: 286fe8aea9eSmrg gi->op = -1; 287fe8aea9eSmrgreset_dst: 288fe8aea9eSmrg gi->dst_color = -1; 289fe8aea9eSmrgreset_src: 290fe8aea9eSmrg gi->src_color = -1; 291fe8aea9eSmrgreset_mask: 292fe8aea9eSmrg gi->mask_format = -1; 293fe8aea9eSmrgreset_clip: 294fe8aea9eSmrg gi->clip = -1; 295fe8aea9eSmrg gi->stage--; 296fe8aea9eSmrg goto restart; 297fe8aea9eSmrg} 298fe8aea9eSmrg 299fe8aea9eSmrgstatic void glyph_iter_fini(struct glyph_iter *gi) 300fe8aea9eSmrg{ 301fe8aea9eSmrg if (gi->out.glyphset) 302fe8aea9eSmrg XRenderFreeGlyphSet (gi->out.dpy->dpy, gi->out.glyphset); 303fe8aea9eSmrg if (gi->ref.glyphset) 304fe8aea9eSmrg XRenderFreeGlyphSet (gi->ref.dpy->dpy, gi->ref.glyphset); 305fe8aea9eSmrg 306fe8aea9eSmrg test_target_destroy_render(gi->out.dpy, &gi->out.tt); 307fe8aea9eSmrg test_target_destroy_render(gi->ref.dpy, &gi->ref.tt); 308fe8aea9eSmrg} 309fe8aea9eSmrg 310fe8aea9eSmrgstatic const char *stdformat_to_str(int id) 311fe8aea9eSmrg{ 312fe8aea9eSmrg switch (id) { 313fe8aea9eSmrg case PictStandardARGB32: return "ARGB32"; 314fe8aea9eSmrg case PictStandardRGB24: return "RGB24"; 315fe8aea9eSmrg case PictStandardA8: return "A8"; 316fe8aea9eSmrg case PictStandardA4: return "A4"; 317fe8aea9eSmrg case PictStandardA1: return "A1"; 318fe8aea9eSmrg default: return "none"; 319fe8aea9eSmrg } 320fe8aea9eSmrg} 321fe8aea9eSmrg 322fe8aea9eSmrgstatic char *glyph_iter_to_string(struct glyph_iter *gi, 323fe8aea9eSmrg const char *format, 324fe8aea9eSmrg ...) 325fe8aea9eSmrg{ 326fe8aea9eSmrg static char buf[100]; 327fe8aea9eSmrg va_list ap; 328fe8aea9eSmrg int len; 329fe8aea9eSmrg 330fe8aea9eSmrg len = sprintf(buf, "glyphs=%s, op=%d, dst=%08x, src=%08x, mask=%s", 331fe8aea9eSmrg stdformat_to_str(gi->glyph_format), gi->op, 332fe8aea9eSmrg xrender_color(&colors[gi->dst_color]), 333fe8aea9eSmrg xrender_color(&colors[gi->src_color]), 334fe8aea9eSmrg stdformat_to_str(gi->mask_format)); 335fe8aea9eSmrg 336fe8aea9eSmrg if (format) { 337fe8aea9eSmrg buf[len++] = ' '; 338fe8aea9eSmrg va_start(ap, format); 339fe8aea9eSmrg vsprintf(buf+len, format, ap); 340fe8aea9eSmrg va_end(ap); 341fe8aea9eSmrg } 342fe8aea9eSmrg 343fe8aea9eSmrg return buf; 344fe8aea9eSmrg} 345fe8aea9eSmrg 346fe8aea9eSmrgstatic void single(struct test *t, enum target target) 347fe8aea9eSmrg{ 348fe8aea9eSmrg struct glyph_iter gi; 349fe8aea9eSmrg int n; 350fe8aea9eSmrg 351fe8aea9eSmrg printf("Testing single glyph (%s): ", test_target_name(target)); 352fe8aea9eSmrg fflush(stdout); 353fe8aea9eSmrg 354fe8aea9eSmrg glyph_iter_init(&gi, t, target); 355fe8aea9eSmrg while (glyph_iter_next(&gi)) { 356fe8aea9eSmrg XGlyphElt8 elt; 357fe8aea9eSmrg char id[N_GLYPHS]; 358fe8aea9eSmrg 359fe8aea9eSmrg for (n = 0; n < N_GLYPHS; n++) { 360fe8aea9eSmrg id[n] = n; 361fe8aea9eSmrg 362fe8aea9eSmrg elt.chars = &id[n]; 363fe8aea9eSmrg elt.nchars = 1; 364fe8aea9eSmrg elt.xOff = 0; 365fe8aea9eSmrg elt.yOff = 0; 366fe8aea9eSmrg 367fe8aea9eSmrg clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]); 368fe8aea9eSmrg elt.glyphset = gi.out.glyphset; 369fe8aea9eSmrg XRenderCompositeText8 (gi.out.dpy->dpy, gi.op, 370fe8aea9eSmrg gi.out.src, 371fe8aea9eSmrg gi.out.tt.picture, 372fe8aea9eSmrg gi.out.mask_format, 373fe8aea9eSmrg 0, 0, 374fe8aea9eSmrg 0, 8, 375fe8aea9eSmrg &elt, 1); 376fe8aea9eSmrg 377fe8aea9eSmrg clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]); 378fe8aea9eSmrg elt.glyphset = gi.ref.glyphset; 379fe8aea9eSmrg XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op, 380fe8aea9eSmrg gi.ref.src, 381fe8aea9eSmrg gi.ref.tt.picture, 382fe8aea9eSmrg gi.ref.mask_format, 383fe8aea9eSmrg 0, 0, 384fe8aea9eSmrg 0, 8, 385fe8aea9eSmrg &elt, 1); 386fe8aea9eSmrg test_compare(t, 387fe8aea9eSmrg gi.out.tt.draw, gi.out.tt.format, 388fe8aea9eSmrg gi.ref.tt.draw, gi.ref.tt.format, 389fe8aea9eSmrg 0, 0, gi.out.tt.width, gi.out.tt.height, 390fe8aea9eSmrg glyph_iter_to_string(&gi, 391fe8aea9eSmrg "glyph=%s", 392fe8aea9eSmrg glyph_name(n))); 393fe8aea9eSmrg } 394fe8aea9eSmrg 395fe8aea9eSmrg elt.chars = &id[0]; 396fe8aea9eSmrg elt.nchars = n; 397fe8aea9eSmrg clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]); 398fe8aea9eSmrg elt.glyphset = gi.out.glyphset; 399fe8aea9eSmrg XRenderCompositeText8 (gi.out.dpy->dpy, gi.op, 400fe8aea9eSmrg gi.out.src, 401fe8aea9eSmrg gi.out.tt.picture, 402fe8aea9eSmrg gi.out.mask_format, 403fe8aea9eSmrg 0, 0, 404fe8aea9eSmrg 0, 8, 405fe8aea9eSmrg &elt, 1); 406fe8aea9eSmrg 407fe8aea9eSmrg clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]); 408fe8aea9eSmrg elt.glyphset = gi.ref.glyphset; 409fe8aea9eSmrg XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op, 410fe8aea9eSmrg gi.ref.src, 411fe8aea9eSmrg gi.ref.tt.picture, 412fe8aea9eSmrg gi.ref.mask_format, 413fe8aea9eSmrg 0, 0, 414fe8aea9eSmrg 0, 8, 415fe8aea9eSmrg &elt, 1); 416fe8aea9eSmrg test_compare(t, 417fe8aea9eSmrg gi.out.tt.draw, gi.out.tt.format, 418fe8aea9eSmrg gi.ref.tt.draw, gi.ref.tt.format, 419fe8aea9eSmrg 0, 0, gi.out.tt.width, gi.out.tt.height, 420fe8aea9eSmrg glyph_iter_to_string(&gi, "all")); 421fe8aea9eSmrg } 422fe8aea9eSmrg glyph_iter_fini(&gi); 423fe8aea9eSmrg} 424fe8aea9eSmrg 425fe8aea9eSmrgint main(int argc, char **argv) 426fe8aea9eSmrg{ 427fe8aea9eSmrg struct test test; 428fe8aea9eSmrg int t; 429fe8aea9eSmrg 430fe8aea9eSmrg test_init(&test, argc, argv); 431fe8aea9eSmrg XSetErrorHandler(_check_error_handler); 432fe8aea9eSmrg 433fe8aea9eSmrg for (t = TARGET_FIRST; t <= TARGET_LAST; t++) { 434fe8aea9eSmrg single(&test, t); 435fe8aea9eSmrg //overlapping(&test, t); 436fe8aea9eSmrg //gap(&test, t); 437fe8aea9eSmrg //mixed(&test, t); 438fe8aea9eSmrg } 439fe8aea9eSmrg 440fe8aea9eSmrg return 0; 441fe8aea9eSmrg} 442