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