cairo.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. --[[--------------------------------------------------------------------------
  2. LGI testsuite, cairo overrides test group.
  3. Copyright (c) 2012 Pavel Holejsovsky
  4. Licensed under the MIT license:
  5. http://www.opensource.org/licenses/mit-license.php
  6. --]]--------------------------------------------------------------------------
  7. local io = require 'io'
  8. local os = require 'os'
  9. local lgi = require 'lgi'
  10. local check = testsuite.check
  11. local checkv = testsuite.checkv
  12. local cairo = testsuite.group.new('cairo')
  13. function cairo.status()
  14. local cairo = lgi.cairo
  15. for name, value in pairs(cairo.Status) do
  16. if type(name) == 'string' and type(value) == 'number' then
  17. checkv(cairo.Status.to_string(name),
  18. cairo.Status.to_string(value),
  19. 'string')
  20. end
  21. end
  22. end
  23. local function check_matrix(matrix, xx, yx, xy, yy, x0, y0)
  24. checkv(matrix.xx, xx, 'number')
  25. checkv(matrix.yx, yx, 'number')
  26. checkv(matrix.xy, xy, 'number')
  27. checkv(matrix.yy, yy, 'number')
  28. checkv(matrix.x0, x0, 'number')
  29. checkv(matrix.y0, y0, 'number')
  30. end
  31. function cairo.matrix()
  32. local cairo = lgi.cairo
  33. local matrix = cairo.Matrix()
  34. check_matrix(matrix, 0, 0, 0, 0, 0, 0)
  35. matrix = cairo.Matrix { xx = 1, yx =1.5,
  36. xy = 2, yy = 2.5,
  37. x0 = 3, y0 = 3.5 }
  38. check_matrix(matrix, 1, 1.5, 2, 2.5, 3, 3.5)
  39. end
  40. function cairo.matrix_getset()
  41. local cairo = lgi.cairo
  42. local surface = cairo.ImageSurface('ARGB32', 100, 100)
  43. local cr = cairo.Context(surface)
  44. local m = cairo.Matrix { xx = 1, yx =1.5,
  45. xy = 2, yy = 2.5,
  46. x0 = 3, y0 = 3.5 }
  47. cr.matrix = m
  48. local m2 = cr.matrix
  49. check(m.xx == m2.xx)
  50. check(m.yx == m2.yx)
  51. check(m.xy == m2.xy)
  52. check(m.yy == m2.yy)
  53. check(m.x0 == m2.x0)
  54. check(m.y0 == m2.y0)
  55. end
  56. function cairo.matrix_init()
  57. local cairo = lgi.cairo
  58. local m = cairo.Matrix.create_identity()
  59. check_matrix(m, 1, 0, 0, 1, 0, 0)
  60. local m = cairo.Matrix.create_translate(2, 3)
  61. check_matrix(m, 1, 0, 0, 1, 2, 3)
  62. local m = cairo.Matrix.create_scale(2, 3)
  63. check_matrix(m, 2, 0, 0, 3, 0, 0)
  64. local angle = math.pi / 2
  65. local m = cairo.Matrix.create_rotate(angle)
  66. local c, s = math.cos(angle), math.sin(angle)
  67. check_matrix(m, c, s, -s, c, 0, 0)
  68. end
  69. function cairo.matrix_operations()
  70. local cairo = lgi.cairo
  71. local m = cairo.Matrix.create_identity()
  72. m:translate(2, 3)
  73. check_matrix(m, 1, 0, 0, 1, 2, 3)
  74. m:scale(-2, -3)
  75. check_matrix(m, -2, 0, 0, -3, 2, 3)
  76. m:rotate(0)
  77. check_matrix(m, -2, 0, 0, -3, 2, 3)
  78. local m2 = cairo.Matrix.create_translate(2, 3)
  79. local status = m2:invert()
  80. checkv(status, 'SUCCESS', 'string')
  81. check_matrix(m2, 1, 0, 0, 1, -2, -3)
  82. -- XXX: This API could be improved
  83. local result = cairo.Matrix.create_identity()
  84. result:multiply(m, m2)
  85. check_matrix(result, -2, 0, 0, -3, 0, 0)
  86. local x, y = m:transform_point(1, 1)
  87. checkv(x, 0, 'number')
  88. checkv(y, 0, 'number')
  89. local x, y = m:transform_distance(1, 1)
  90. checkv(x, -2, 'number')
  91. checkv(y, -3, 'number')
  92. end
  93. function cairo.dash()
  94. local cairo = lgi.cairo
  95. local surface = cairo.ImageSurface('ARGB32', 100, 100)
  96. local cr = cairo.Context(surface)
  97. local dash, offset = cr:get_dash()
  98. check(type(dash) == 'table')
  99. check(next(dash) == nil)
  100. cr:set_dash({ 1, 2, math.pi }, 2.22)
  101. dash, offset = cr:get_dash()
  102. check(#dash == 3)
  103. check(dash[1] == 1)
  104. check(dash[2] == 2)
  105. check(dash[3] == math.pi)
  106. check(offset == 2.22)
  107. cr:set_dash(nil, 0)
  108. dash, offset = cr:get_dash()
  109. check(type(dash) == 'table')
  110. check(next(dash) == nil)
  111. end
  112. function cairo.path()
  113. local cairo = lgi.cairo
  114. local surface = cairo.ImageSurface('ARGB32', 100, 100)
  115. local cr = cairo.Context(surface)
  116. cr:move_to(10, 11)
  117. cr:curve_to(1, 2, 3, 4, 5, 6)
  118. cr:close_path()
  119. cr:line_to(21, 22)
  120. local i = 1
  121. for t, pts in cr:copy_path():pairs() do
  122. if i == 1 then
  123. checkv(t, 'MOVE_TO', 'string')
  124. check(type(pts) == 'table' and #pts == 1)
  125. checkv(pts[1].x, 10, 'number')
  126. checkv(pts[1].y, 11, 'number')
  127. elseif i == 2 then
  128. checkv(t, 'CURVE_TO', 'string')
  129. check(type(pts) == 'table' and #pts == 3)
  130. checkv(pts[1].x, 1, 'number')
  131. checkv(pts[1].y, 2, 'number')
  132. checkv(pts[2].x, 3, 'number')
  133. checkv(pts[2].y, 4, 'number')
  134. checkv(pts[3].x, 5, 'number')
  135. checkv(pts[3].y, 6, 'number')
  136. elseif i == 3 then
  137. checkv(t, 'CLOSE_PATH', 'string')
  138. check(type(pts) == 'table' and #pts == 0)
  139. elseif i == 4 then
  140. checkv(t, 'MOVE_TO', 'string')
  141. check(type(pts) == 'table' and #pts == 1)
  142. checkv(pts[1].x, 10, 'number')
  143. checkv(pts[1].y, 11, 'number')
  144. elseif i == 5 then
  145. checkv(t, 'LINE_TO', 'string')
  146. check(type(pts) == 'table' and #pts == 1)
  147. checkv(pts[1].x, 21, 'number')
  148. checkv(pts[1].y, 22, 'number')
  149. else
  150. check(false)
  151. end
  152. i = i + 1
  153. end
  154. check(i == 6)
  155. end
  156. function cairo.surface_type()
  157. local cairo = lgi.cairo
  158. local surface = cairo.ImageSurface('ARGB32', 100, 100)
  159. local cr = cairo.Context(surface)
  160. check(cairo.ImageSurface:is_type_of(surface))
  161. check(cairo.Surface:is_type_of(surface))
  162. check(not cairo.RecordingSurface:is_type_of(surface))
  163. local s2 = cr.target
  164. check(cairo.ImageSurface:is_type_of(s2))
  165. check(cairo.Surface:is_type_of(s2))
  166. check(not cairo.RecordingSurface:is_type_of(s2))
  167. local s3 = cr.group_target
  168. check(cairo.ImageSurface:is_type_of(s3))
  169. check(cairo.Surface:is_type_of(s3))
  170. check(not cairo.RecordingSurface:is_type_of(s3))
  171. end
  172. function cairo.pattern_type()
  173. local cairo = lgi.cairo
  174. local pattern
  175. pattern = cairo.Pattern.create_rgb(1, 1, 1)
  176. check(cairo.SolidPattern:is_type_of(pattern))
  177. check(cairo.Pattern:is_type_of(pattern))
  178. pattern = cairo.SolidPattern(1, 1, 1)
  179. check(cairo.SolidPattern:is_type_of(pattern))
  180. pattern = cairo.SolidPattern(1, 1, 1, 1)
  181. check(cairo.SolidPattern:is_type_of(pattern))
  182. local surface = cairo.ImageSurface('ARGB32', 100, 100)
  183. pattern = cairo.Pattern.create_for_surface(surface)
  184. check(select(2, pattern:get_surface()) == surface)
  185. check(cairo.SurfacePattern:is_type_of(pattern))
  186. check(cairo.Pattern:is_type_of(pattern))
  187. pattern = cairo.SurfacePattern(surface)
  188. check(cairo.SurfacePattern:is_type_of(pattern))
  189. pattern = cairo.Pattern.create_linear(0, 0, 10, 10)
  190. check(cairo.LinearPattern:is_type_of(pattern))
  191. check(cairo.GradientPattern:is_type_of(pattern))
  192. check(cairo.Pattern:is_type_of(pattern))
  193. pattern = cairo.LinearPattern(0, 0, 10, 10)
  194. check(cairo.LinearPattern:is_type_of(pattern))
  195. pattern = cairo.Pattern.create_radial(0, 0, 5, 10, 10, 5)
  196. check(cairo.RadialPattern:is_type_of(pattern))
  197. check(cairo.GradientPattern:is_type_of(pattern))
  198. check(cairo.Pattern:is_type_of(pattern))
  199. pattern = cairo.RadialPattern(0, 0, 5, 10, 10, 5)
  200. check(cairo.RadialPattern:is_type_of(pattern))
  201. if cairo.version >= cairo.version_encode(1, 12, 0) then
  202. pattern = cairo.Pattern.create_mesh()
  203. check(cairo.MeshPattern:is_type_of(pattern))
  204. check(not cairo.GradientPattern:is_type_of(pattern))
  205. check(cairo.Pattern:is_type_of(pattern))
  206. pattern = cairo.MeshPattern()
  207. check(cairo.MeshPattern:is_type_of(pattern))
  208. end
  209. end
  210. function cairo.pattern_mesh()
  211. local cairo = lgi.cairo
  212. -- Mesh patterns are introduced in cairo 1.12
  213. if cairo.version < cairo.version_encode(1, 12, 0) then
  214. return
  215. end
  216. local mesh = cairo.Pattern.create_mesh()
  217. local pattern = cairo.Pattern.create_radial(1, 2, 3, 4, 5, 6)
  218. check(cairo.Pattern:is_type_of(mesh))
  219. check(cairo.MeshPattern:is_type_of(mesh))
  220. check(cairo.Pattern:is_type_of(pattern))
  221. check(not cairo.MeshPattern:is_type_of(pattern))
  222. local function check_status(status)
  223. checkv(status, 'SUCCESS', 'string')
  224. end
  225. -- Taken from cairo's pattern-getters test and slightly adapted to use all
  226. -- functions of the mesh pattern API
  227. local status, count = mesh:get_patch_count()
  228. check_status(status)
  229. checkv(count, 0, 'number')
  230. mesh:begin_patch()
  231. mesh:move_to(0, 0)
  232. mesh:line_to(0, 3)
  233. mesh:line_to(3, 3)
  234. mesh:line_to(3, 0)
  235. mesh:set_corner_color_rgba(0, 1, 1, 1, 1)
  236. mesh:end_patch()
  237. local status, count = mesh:get_patch_count()
  238. check_status(status)
  239. checkv(count, 1, 'number')
  240. for k, v in pairs({ { 1, 1 }, { 1, 2 }, { 2, 2 }, { 2, 1 } }) do
  241. local status, x, y = mesh:get_control_point(0, k - 1)
  242. check_status(status)
  243. checkv(x, v[1], 'number')
  244. checkv(y, v[2], 'number')
  245. end
  246. mesh:begin_patch()
  247. mesh:move_to(0, 0)
  248. mesh:line_to(1, 0)
  249. mesh:curve_to(1, 1, 1, 2, 0, 1)
  250. mesh:set_corner_color_rgb(0, 1, 1, 1)
  251. mesh:set_control_point(2, 0.5, 0.5)
  252. mesh:end_patch()
  253. local status, count = mesh:get_patch_count()
  254. check_status(status)
  255. checkv(count, 2, 'number')
  256. for k, v in pairs({ 1, 0, 0, 1 }) do
  257. local status, r, g, b, a = mesh:get_corner_color_rgba(1, k - 1)
  258. check_status(status)
  259. checkv(r, v, 'number')
  260. checkv(g, v, 'number')
  261. checkv(b, v, 'number')
  262. checkv(a, v, 'number')
  263. end
  264. local i = 0
  265. local expected = {
  266. { { 0, 1 }, { 0, 2 }, { 0, 3 } },
  267. { { 1, 3 }, { 2, 3 }, { 3, 3 } },
  268. { { 3, 2 }, { 3, 1 }, { 3, 0 } },
  269. { { 2, 0 }, { 1, 0 }, { 0, 0 } },
  270. }
  271. for t, pts in mesh:get_path(0):pairs() do
  272. if i == 0 then
  273. checkv(t, 'MOVE_TO', 'string')
  274. check(type(pts) == 'table' and #pts == 1)
  275. checkv(pts[1].x, 0, 'number')
  276. checkv(pts[1].y, 0, 'number')
  277. else
  278. -- Mesh patterns turn everything into curves. :-(
  279. checkv(t, 'CURVE_TO', 'string')
  280. check(type(pts) == 'table' and #pts == 3)
  281. for k, v in pairs(expected[i]) do
  282. checkv(pts[k].x, v[1], 'number')
  283. checkv(pts[k].y, v[2], 'number')
  284. end
  285. end
  286. i = i + 1
  287. end
  288. check(i == #expected + 1)
  289. end
  290. function cairo.context_getset()
  291. local cairo = lgi.cairo
  292. local surface = cairo.ImageSurface('ARGB32', 100, 100)
  293. local cr = cairo.Context(surface)
  294. local s2 = cr.target
  295. check(s2 == surface)
  296. local s3 = cr.group_target
  297. check(s3 == surface)
  298. cr.source = cairo.Pattern.create_linear(0, 0, 10, 10)
  299. check(cairo.LinearPattern:is_type_of(cr.source))
  300. cr.antialias = "BEST"
  301. check(cr.antialias == "BEST")
  302. cr.fill_rule = "EVEN_ODD"
  303. check(cr.fill_rule == "EVEN_ODD")
  304. cr.line_cap = "SQUARE"
  305. check(cr.line_cap == "SQUARE")
  306. cr.line_join = "BEVEL"
  307. check(cr.line_join == "BEVEL")
  308. cr.line_width = 42
  309. check(cr.line_width == 42)
  310. cr.miter_limit = 5
  311. check(cr.miter_limit == 5)
  312. cr.operator = "ATOP"
  313. check(cr.operator == "ATOP")
  314. cr.tolerance = 21
  315. check(cr.tolerance == 21)
  316. local m = cairo.Matrix.create_translate(-1, 4)
  317. cr.matrix = m
  318. check_matrix(cr.matrix, 1, 0, 0, 1, -1, 4)
  319. local m = cairo.Matrix.create_scale(2, 3)
  320. cr.font_matrix = m
  321. check_matrix(cr.font_matrix, 2, 0, 0, 3, 0, 0)
  322. -- font size is read-only, but messes with the font matrix
  323. cr.font_size = 100
  324. check_matrix(cr.font_matrix, 100, 0, 0, 100, 0, 0)
  325. local opt = cairo.FontOptions.create()
  326. cr.font_options = opt
  327. check(cr.font_options:equal(opt))
  328. local font_face = cairo.ToyFontFace.create("Arial", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)
  329. cr.font_face = font_face
  330. check(cairo.ToyFontFace:is_type_of(cr.font_face))
  331. local scaled_font = cairo.ScaledFont.create(font_face, m, m, opt)
  332. cr.scaled_font = scaled_font
  333. check(cairo.ScaledFont:is_type_of(cr.scaled_font))
  334. end
  335. function cairo.context_transform()
  336. local cairo = lgi.cairo
  337. local surface = cairo.ImageSurface('ARGB32', 100, 100)
  338. local cr = cairo.Context(surface)
  339. function compare(a, b)
  340. check(math.abs(a-b) < 0.1)
  341. end
  342. cr:rotate(-math.pi / 2)
  343. cr:translate(100, 200)
  344. local x, y = cr:user_to_device(10, 20)
  345. compare(x, 220)
  346. compare(y, -110)
  347. local x, y = cr:device_to_user(220, -110)
  348. compare(x, 10)
  349. compare(y, 20)
  350. local x, y = cr:user_to_device_distance(10, 20)
  351. compare(x, 20)
  352. compare(y, -10)
  353. local x, y = cr:device_to_user_distance(20, -10)
  354. compare(x, 10)
  355. compare(y, 20)
  356. end