simple.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * Copyright 2014 Intel Corporation
  3. *
  4. * Permission is hereby granted, free of charge, to any person
  5. * obtaining a copy of this software and associated documentation
  6. * files (the "Software"), to deal in the Software without
  7. * restriction, including without limitation the rights to use, copy,
  8. * modify, merge, publish, distribute, sublicense, and/or sell copies
  9. * of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be
  13. * included in all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  19. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  20. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. * SOFTWARE.
  23. *
  24. * Author: Chris Wilson <chris@chris-wilson.co.uk>
  25. */
  26. #include "cairo-test.h"
  27. /* Test the fidelity of the rasterisation, because Cairo is my favourite
  28. * driver test suite.
  29. */
  30. #define GENERATE_REFERENCE 0
  31. #include "../src/cairo-fixed-type-private.h"
  32. #if GENERATE_REFERENCE
  33. #include <assert.h>
  34. struct coverage {
  35. int width, height;
  36. struct {
  37. int uncovered_area;
  38. int covered_height;
  39. } cells[0];
  40. };
  41. static int pfloor (int v)
  42. {
  43. return v >> CAIRO_FIXED_FRAC_BITS;
  44. }
  45. static int pfrac (int v)
  46. {
  47. return v & ((1 << CAIRO_FIXED_FRAC_BITS) - 1);
  48. }
  49. static void add_edge (struct coverage *coverage,
  50. int x1, int y1, int x2, int y2,
  51. int sign)
  52. {
  53. int dx, dy;
  54. int dxdy_quo, dxdy_rem;
  55. int xq, xr;
  56. int y, t;
  57. if (y2 < y1) {
  58. t = y1;
  59. y1 = y2;
  60. y2 = t;
  61. t = x1;
  62. x1 = x2;
  63. x2 = t;
  64. sign = -sign;
  65. }
  66. dx = x2 - x1;
  67. dy = y2 - y1;
  68. if (dy == 0)
  69. return;
  70. dy *= 2;
  71. dxdy_quo = 2*dx / dy;
  72. dxdy_rem = 2*dx % dy;
  73. xq = x1 + dxdy_quo / 2;
  74. xr = dxdy_rem / 2;
  75. if (xr < 0) {
  76. xq--;
  77. xr += dy;
  78. }
  79. for (y = MAX(0, y1); y < MIN(y2, 256*coverage->height); y++) {
  80. int x = xq + (xr >= dy/2);
  81. if (x < 256*coverage->width) {
  82. int i = pfloor (y) * coverage->width;
  83. if (x > 0) {
  84. i += pfloor (x);
  85. coverage->cells[i].uncovered_area += sign * pfrac(x);
  86. }
  87. coverage->cells[i].covered_height += sign;
  88. }
  89. xq += dxdy_quo;
  90. xr += dxdy_rem;
  91. if (xr < 0) {
  92. xq--;
  93. xr += dy;
  94. } else if (xr >= dy) {
  95. xq++;
  96. xr -= dy;
  97. }
  98. }
  99. }
  100. static struct coverage *
  101. coverage_create (int width, int height)
  102. {
  103. int size;
  104. struct coverage *c;
  105. size = sizeof (struct coverage);
  106. size += width * height * sizeof (int) * 2;
  107. c = malloc (size);
  108. if (c == NULL)
  109. return c;
  110. memset(c, 0, size);
  111. c->width = width;
  112. c->height = height;
  113. return c;
  114. }
  115. static cairo_surface_t *
  116. coverage_to_alpha (struct coverage *c)
  117. {
  118. cairo_surface_t *image;
  119. uint8_t *data;
  120. int x, y, stride;
  121. image = cairo_image_surface_create (CAIRO_FORMAT_A8, c->width, c->height);
  122. data = cairo_image_surface_get_data (image);
  123. stride = cairo_image_surface_get_stride (image);
  124. cairo_surface_flush (image);
  125. for (y = 0; y < c->height; y++) {
  126. uint8_t *row = data + y *stride;
  127. int cover = 0;
  128. for (x = 0; x < c->width; x++) {
  129. int v = y*c->width + x;
  130. cover += c->cells[v].covered_height * 256;
  131. v = cover - c->cells[v].uncovered_area;
  132. v /= 256;
  133. if (v < 0)
  134. v = -v;
  135. row[x] = v - (v >> 8);
  136. }
  137. }
  138. cairo_surface_mark_dirty (image);
  139. free (c);
  140. return image;
  141. }
  142. #endif
  143. static cairo_test_status_t
  144. edge (cairo_t *cr, int width, int height)
  145. {
  146. cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
  147. cairo_paint (cr);
  148. cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
  149. #if GENERATE_REFERENCE
  150. {
  151. struct coverage *c;
  152. cairo_surface_t *mask;
  153. cairo_set_source_rgb (cr, 1, 0, 0);
  154. c = coverage_create (width, height);
  155. add_edge (c, 128*256, 129*256, 129*256, 1*256, 1);
  156. add_edge (c, 128*256, 129*256, 128*256, 131*256, -1);
  157. add_edge (c, 128*256, 131*256, 129*256, 259*256, -1);
  158. add_edge (c, 130*256, 129*256, 129*256, 1*256, -1);
  159. add_edge (c, 130*256, 129*256, 130*256, 131*256, 1);
  160. add_edge (c, 130*256, 131*256, 129*256, 259*256, 1);
  161. mask = coverage_to_alpha (c);
  162. cairo_mask_surface (cr, mask, 0, 0);
  163. cairo_surface_destroy (mask);
  164. c = coverage_create (width, height);
  165. add_edge (c, 128*256/2, 129*256/2, 129*256/2, 1*256/2, 1);
  166. add_edge (c, 128*256/2, 129*256/2, 128*256/2, 131*256/2, -1);
  167. add_edge (c, 128*256/2, 131*256/2, 129*256/2, 259*256/2, -1);
  168. add_edge (c, 130*256/2, 129*256/2, 129*256/2, 1*256/2, -1);
  169. add_edge (c, 130*256/2, 129*256/2, 130*256/2, 131*256/2, 1);
  170. add_edge (c, 130*256/2, 131*256/2, 129*256/2, 259*256/2, 1);
  171. mask = coverage_to_alpha (c);
  172. cairo_mask_surface (cr, mask, 0, 0);
  173. cairo_surface_destroy (mask);
  174. c = coverage_create (width, height);
  175. add_edge (c, (192-2)*256, 129*256, 192*256, 1*256, 1);
  176. add_edge (c, (192-2)*256, 129*256, (192-2)*256, 131*256, -1);
  177. add_edge (c, (192-2)*256, 131*256, 192*256, 259*256, -1);
  178. add_edge (c, (192+2)*256, 129*256, 192*256, 1*256, -1);
  179. add_edge (c, (192+2)*256, 129*256, (192+2)*256, 131*256, 1);
  180. add_edge (c, (192+2)*256, 131*256, 192*256, 259*256, 1);
  181. mask = coverage_to_alpha (c);
  182. cairo_mask_surface (cr, mask, 0, 0);
  183. cairo_surface_destroy (mask);
  184. c = coverage_create (width, height);
  185. add_edge (c, (256-4)*256, 129*256, 256*256, 1*256, 1);
  186. add_edge (c, (256-4)*256, 129*256, (256-4)*256, 131*256, -1);
  187. add_edge (c, (256-4)*256, 131*256, 256*256, 259*256, -1);
  188. add_edge (c, (256+4)*256, 129*256, 256*256, 1*256, -1);
  189. add_edge (c, (256+4)*256, 129*256, (256+4)*256, 131*256, 1);
  190. add_edge (c, (256+4)*256, 131*256, 256*256, 259*256, 1);
  191. mask = coverage_to_alpha (c);
  192. cairo_mask_surface (cr, mask, 0, 0);
  193. cairo_surface_destroy (mask);
  194. cairo_set_source_rgb (cr, 0, 1, 0);
  195. c = coverage_create (width, height);
  196. add_edge (c, 1*256, 129*256, 129*256, 128*256, 1);
  197. add_edge (c, 131*256, 128*256, 259*256, 129*256, 1);
  198. add_edge (c, 1*256, 129*256, 129*256, 130*256, -1);
  199. add_edge (c, 131*256, 130*256, 259*256, 129*256, -1);
  200. mask = coverage_to_alpha (c);
  201. cairo_mask_surface (cr, mask, 0, 0);
  202. cairo_surface_destroy (mask);
  203. c = coverage_create (width, height);
  204. add_edge (c, 1*256/2, 129*256/2, 129*256/2, 128*256/2, 1);
  205. add_edge (c, 131*256/2, 128*256/2, 259*256/2, 129*256/2, 1);
  206. add_edge (c, 1*256/2, 129*256/2, 129*256/2, 130*256/2, -1);
  207. add_edge (c, 131*256/2, 130*256/2, 259*256/2, 129*256/2, -1);
  208. mask = coverage_to_alpha (c);
  209. cairo_mask_surface (cr, mask, 0, 0);
  210. cairo_surface_destroy (mask);
  211. c = coverage_create (width, height);
  212. add_edge (c, 1*256, (192-0)*256, 129*256, (192-2)*256, 1);
  213. add_edge (c, 131*256, (192-2)*256, 259*256, (192-0)*256, 1);
  214. add_edge (c, 1*256, (192+0)*256, 129*256, (192+2)*256, -1);
  215. add_edge (c, 131*256, (192+2)*256, 259*256, (192+0)*256, -1);
  216. mask = coverage_to_alpha (c);
  217. cairo_mask_surface (cr, mask, 0, 0);
  218. cairo_surface_destroy (mask);
  219. c = coverage_create (width, height);
  220. add_edge (c, 1*256, (256-0)*256, 129*256, (256-4)*256, 1);
  221. add_edge (c, 131*256, (256-4)*256, 259*256, (256-0)*256, 1);
  222. add_edge (c, 1*256, (256+0)*256, 129*256, (256+4)*256, -1);
  223. add_edge (c, 131*256, (256+4)*256, 259*256, (256+0)*256, -1);
  224. mask = coverage_to_alpha (c);
  225. cairo_mask_surface (cr, mask, 0, 0);
  226. cairo_surface_destroy (mask);
  227. }
  228. #else
  229. cairo_set_source_rgb (cr, 1, 0, 0);
  230. cairo_move_to (cr, 129, 1);
  231. cairo_line_to (cr, 128, 129);
  232. cairo_line_to (cr, 128, 131);
  233. cairo_line_to (cr, 129, 259);
  234. cairo_line_to (cr, 130, 131);
  235. cairo_line_to (cr, 130, 129);
  236. cairo_fill (cr);
  237. cairo_move_to (cr, 129/2., 1/2.);
  238. cairo_line_to (cr, 128/2., 129/2.);
  239. cairo_line_to (cr, 128/2., 131/2.);
  240. cairo_line_to (cr, 129/2., 259/2.);
  241. cairo_line_to (cr, 130/2., 131/2.);
  242. cairo_line_to (cr, 130/2., 129/2.);
  243. cairo_fill (cr);
  244. cairo_move_to (cr, 192, 1);
  245. cairo_line_to (cr, 192-2, 129);
  246. cairo_line_to (cr, 192-2, 131);
  247. cairo_line_to (cr, 192, 259);
  248. cairo_line_to (cr, 192+2, 131);
  249. cairo_line_to (cr, 192+2, 129);
  250. cairo_fill (cr);
  251. cairo_move_to (cr, 256, 1);
  252. cairo_line_to (cr, 256-4, 129);
  253. cairo_line_to (cr, 256-4, 131);
  254. cairo_line_to (cr, 256, 259);
  255. cairo_line_to (cr, 256+4, 131);
  256. cairo_line_to (cr, 256+4, 129);
  257. cairo_fill (cr);
  258. cairo_set_source_rgb (cr, 0, 1, 0);
  259. cairo_move_to (cr, 1, 129);
  260. cairo_line_to (cr, 129, 128);
  261. cairo_line_to (cr, 131, 128);
  262. cairo_line_to (cr, 259, 129);
  263. cairo_line_to (cr, 131, 130);
  264. cairo_line_to (cr, 129, 130);
  265. cairo_fill (cr);
  266. cairo_move_to (cr, 1/2., 129/2.);
  267. cairo_line_to (cr, 129/2., 128/2.);
  268. cairo_line_to (cr, 131/2., 128/2.);
  269. cairo_line_to (cr, 259/2., 129/2.);
  270. cairo_line_to (cr, 131/2., 130/2.);
  271. cairo_line_to (cr, 129/2., 130/2.);
  272. cairo_fill (cr);
  273. cairo_move_to (cr, 1, 192);
  274. cairo_line_to (cr, 129, 192-2);
  275. cairo_line_to (cr, 131, 192-2);
  276. cairo_line_to (cr, 259, 192);
  277. cairo_line_to (cr, 131, 192+2);
  278. cairo_line_to (cr, 129, 192+2);
  279. cairo_fill (cr);
  280. cairo_move_to (cr, 1, 256);
  281. cairo_line_to (cr, 129, 256-4);
  282. cairo_line_to (cr, 131, 256-4);
  283. cairo_line_to (cr, 259, 256);
  284. cairo_line_to (cr, 131, 256+4);
  285. cairo_line_to (cr, 129, 256+4);
  286. cairo_fill (cr);
  287. #endif
  288. return CAIRO_TEST_SUCCESS;
  289. }
  290. CAIRO_TEST (simple_edge,
  291. "Check the fidelity of the rasterisation.",
  292. NULL, /* keywords */
  293. "target=raster", /* requirements */
  294. 260, 260,
  295. NULL, edge)