ext_cairo_renderer.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2018 K. Lange
  5. *
  6. * Compositor Cairo renderer backend
  7. */
  8. #include <math.h>
  9. #include <cairo.h>
  10. #include <toaru/yutani-server.h>
  11. struct cairo_renderer {
  12. cairo_t * framebuffer_ctx;
  13. cairo_surface_t * framebuffer_surface;
  14. cairo_t * real_ctx;
  15. cairo_surface_t * real_surface;
  16. };
  17. int renderer_alloc(yutani_globals_t * yg) {
  18. struct cairo_renderer * c = malloc(sizeof(struct cairo_renderer));
  19. c->framebuffer_ctx = NULL;
  20. c->framebuffer_surface = NULL;
  21. c->real_ctx = NULL;
  22. c->real_surface = NULL;
  23. yg->renderer_ctx = c;
  24. return 0;
  25. }
  26. int renderer_init(yutani_globals_t * yg) {
  27. struct cairo_renderer * c = yg->renderer_ctx;
  28. int stride = yg->backend_ctx->stride;
  29. c->framebuffer_surface = cairo_image_surface_create_for_data(
  30. yg->backend_framebuffer, CAIRO_FORMAT_ARGB32, yg->width, yg->height, stride);
  31. c->framebuffer_ctx = cairo_create(c->framebuffer_surface);
  32. c->real_surface = cairo_image_surface_create_for_data(
  33. (unsigned char *)yg->backend_ctx->buffer, CAIRO_FORMAT_ARGB32, yg->width, yg->height, stride);
  34. c->real_ctx = cairo_create(c->real_surface);
  35. return 0;
  36. }
  37. int renderer_add_clip(yutani_globals_t * yg, double x, double y, double w, double h) {
  38. struct cairo_renderer * c = yg->renderer_ctx;
  39. cairo_rectangle(c->framebuffer_ctx, x, y, w, h);
  40. if (yg->width > 2490) {
  41. x = 0;
  42. w = yg->width;
  43. }
  44. cairo_rectangle(c->real_ctx, x, y, w, h);
  45. return 0;
  46. }
  47. int renderer_set_clip(yutani_globals_t * yg) {
  48. struct cairo_renderer * c = yg->renderer_ctx;
  49. cairo_clip(c->framebuffer_ctx);
  50. cairo_clip(c->real_ctx);
  51. return 0;
  52. }
  53. int renderer_push_state(yutani_globals_t * yg) {
  54. struct cairo_renderer * c = yg->renderer_ctx;
  55. cairo_save(c->framebuffer_ctx);
  56. cairo_save(c->real_ctx);
  57. return 0;
  58. }
  59. int renderer_pop_state(yutani_globals_t * yg) {
  60. struct cairo_renderer * c = yg->renderer_ctx;
  61. cairo_restore(c->framebuffer_ctx);
  62. cairo_restore(c->real_ctx);
  63. return 0;
  64. }
  65. int renderer_destroy(yutani_globals_t * yg) {
  66. struct cairo_renderer * c = yg->renderer_ctx;
  67. cairo_destroy(c->framebuffer_ctx);
  68. cairo_surface_destroy(c->framebuffer_surface);
  69. cairo_destroy(c->real_ctx);
  70. cairo_surface_destroy(c->real_surface);
  71. return 0;
  72. }
  73. int renderer_blit_screen(yutani_globals_t * yg) {
  74. struct cairo_renderer * c = yg->renderer_ctx;
  75. cairo_set_operator(c->real_ctx, CAIRO_OPERATOR_SOURCE);
  76. cairo_translate(c->real_ctx, 0, 0);
  77. cairo_set_source_surface(c->real_ctx, c->framebuffer_surface, 0, 0);
  78. cairo_paint(c->real_ctx);
  79. return 0;
  80. }
  81. int renderer_blit_window(yutani_globals_t * yg, yutani_server_window_t * window, int x, int y) {
  82. /* Obtain the previously initialized cairo contexts */
  83. struct cairo_renderer * c = yg->renderer_ctx;
  84. cairo_t * cr = c->framebuffer_ctx;
  85. /* Window stride is always 4 bytes per pixel... */
  86. int stride = window->width * 4;
  87. /* Initialize a cairo surface object for this window */
  88. cairo_surface_t * surf = cairo_image_surface_create_for_data(
  89. window->buffer, CAIRO_FORMAT_ARGB32, window->width, window->height, stride);
  90. /* Save cairo context */
  91. cairo_save(cr);
  92. /*
  93. * Offset the rendering context appropriately for the position of the window
  94. * based on the modifier paramters
  95. */
  96. cairo_identity_matrix(cr);
  97. cairo_translate(cr, x, y);
  98. /* Top and bottom windows can not be rotated. */
  99. if (!yutani_window_is_top(yg, window) && !yutani_window_is_bottom(yg, window)) {
  100. /* Calcuate radians from degrees */
  101. if (window->rotation != 0) {
  102. double r = M_PI * (((double)window->rotation) / 180.0);
  103. /* Rotate the render context about the center of the window */
  104. cairo_translate(cr, (int)( window->width / 2), (int)( (int)window->height / 2));
  105. cairo_rotate(cr, r);
  106. cairo_translate(cr, (int)(-window->width / 2), (int)(-window->height / 2));
  107. /* Prefer faster filter when rendering rotated windows */
  108. cairo_pattern_t * p = cairo_get_source(cr);
  109. cairo_pattern_set_filter(p, CAIRO_FILTER_FAST);
  110. }
  111. if (window == yg->resizing_window) {
  112. double x_scale = (double)yg->resizing_w / (double)yg->resizing_window->width;
  113. double y_scale = (double)yg->resizing_h / (double)yg->resizing_window->height;
  114. if (x_scale < 0.00001) {
  115. x_scale = 0.00001;
  116. }
  117. if (y_scale < 0.00001) {
  118. y_scale = 0.00001;
  119. }
  120. cairo_translate(cr, (int)yg->resizing_offset_x, (int)yg->resizing_offset_y);
  121. cairo_scale(cr, x_scale, y_scale);
  122. }
  123. }
  124. if (window->anim_mode) {
  125. int frame = yutani_time_since(yg, window->anim_start);
  126. if (frame >= yutani_animation_lengths[window->anim_mode]) {
  127. if (window->anim_mode == YUTANI_EFFECT_FADE_OUT ||
  128. window->anim_mode == YUTANI_EFFECT_SQUEEZE_OUT) {
  129. list_insert(yg->windows_to_remove, window);
  130. goto draw_finish;
  131. }
  132. window->anim_mode = 0;
  133. window->anim_start = 0;
  134. goto draw_window;
  135. } else {
  136. switch (window->anim_mode) {
  137. case YUTANI_EFFECT_SQUEEZE_OUT:
  138. case YUTANI_EFFECT_FADE_OUT:
  139. {
  140. frame = yutani_animation_lengths[window->anim_mode] - frame;
  141. }
  142. case YUTANI_EFFECT_SQUEEZE_IN:
  143. case YUTANI_EFFECT_FADE_IN:
  144. {
  145. double time_diff = ((double)frame / (float)yutani_animation_lengths[window->anim_mode]);
  146. if (window->server_flags & YUTANI_WINDOW_FLAG_DIALOG_ANIMATION) {
  147. double x = time_diff;
  148. int t_y = (window->height * (1.0 -x)) / 2;
  149. cairo_translate(cr, 0, t_y);
  150. cairo_scale(cr, 1.0, x);
  151. } else if (!yutani_window_is_top(yg, window) && !yutani_window_is_bottom(yg, window) &&
  152. !(window->server_flags & YUTANI_WINDOW_FLAG_ALT_ANIMATION)) {
  153. double x = 0.75 + time_diff * 0.25;
  154. int t_x = (window->width * (1.0 - x)) / 2;
  155. int t_y = (window->height * (1.0 - x)) / 2;
  156. cairo_translate(cr, t_x, t_y);
  157. cairo_scale(cr, x, x);
  158. }
  159. cairo_set_source_surface(cr, surf, 0, 0);
  160. if (window->opacity != 255) {
  161. cairo_paint_with_alpha(cr, time_diff * (double)(window->opacity) / 255.0);
  162. } else {
  163. cairo_paint_with_alpha(cr, time_diff);
  164. }
  165. }
  166. break;
  167. default:
  168. goto draw_window;
  169. break;
  170. }
  171. }
  172. } else {
  173. draw_window:
  174. /* Paint window */
  175. cairo_set_source_surface(cr, surf, 0, 0);
  176. if (window->opacity != 255) {
  177. cairo_paint_with_alpha(cr, (float)(window->opacity)/255.0);
  178. } else {
  179. cairo_paint(cr);
  180. }
  181. }
  182. draw_finish:
  183. /* Clean up */
  184. cairo_surface_destroy(surf);
  185. /* Restore context stack */
  186. cairo_restore(cr);
  187. #if YUTANI_DEBUG_WINDOW_BOUNDS
  188. /*
  189. * If window bound debugging is enabled, we also draw a box
  190. * representing the rectangular (possibly rotated) boundary
  191. * for a window texture.
  192. */
  193. if (yg->debug_bounds) {
  194. cairo_save(cr);
  195. int32_t t_x, t_y;
  196. int32_t s_x, s_y;
  197. int32_t r_x, r_y;
  198. int32_t q_x, q_y;
  199. yutani_window_to_device(window, 0, 0, &t_x, &t_y);
  200. yutani_window_to_device(window, window->width, window->height, &s_x, &s_y);
  201. yutani_window_to_device(window, 0, window->height, &r_x, &r_y);
  202. yutani_window_to_device(window, window->width, 0, &q_x, &q_y);
  203. uint32_t x = yutani_color_for_wid(window->wid);
  204. cairo_set_source_rgba(cr,
  205. _RED(x) / 255.0,
  206. _GRE(x) / 255.0,
  207. _BLU(x) / 255.0,
  208. 0.7
  209. );
  210. cairo_move_to(cr, t_x, t_y);
  211. cairo_line_to(cr, r_x, r_y);
  212. cairo_line_to(cr, s_x, s_y);
  213. cairo_line_to(cr, q_x, q_y);
  214. cairo_fill(cr);
  215. cairo_restore(cr);
  216. }
  217. #endif
  218. return 0;
  219. }