ext_cairo_renderer.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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. list_insert(yg->windows_to_remove, window);
  129. goto draw_finish;
  130. }
  131. window->anim_mode = 0;
  132. window->anim_start = 0;
  133. goto draw_window;
  134. } else {
  135. switch (window->anim_mode) {
  136. case YUTANI_EFFECT_FADE_OUT:
  137. {
  138. frame = yutani_animation_lengths[window->anim_mode] - frame;
  139. }
  140. case YUTANI_EFFECT_FADE_IN:
  141. {
  142. double time_diff = ((double)frame / (float)yutani_animation_lengths[window->anim_mode]);
  143. if (!yutani_window_is_top(yg, window) && !yutani_window_is_bottom(yg, window) &&
  144. !(window->server_flags & YUTANI_WINDOW_FLAG_ALT_ANIMATION)) {
  145. double x = 0.75 + time_diff * 0.25;
  146. int t_x = (window->width * (1.0 - x)) / 2;
  147. int t_y = (window->height * (1.0 - x)) / 2;
  148. cairo_translate(cr, t_x, t_y);
  149. cairo_scale(cr, x, x);
  150. }
  151. cairo_set_source_surface(cr, surf, 0, 0);
  152. if (window->opacity != 255) {
  153. cairo_paint_with_alpha(cr, time_diff * (double)(window->opacity) / 255.0);
  154. } else {
  155. cairo_paint_with_alpha(cr, time_diff);
  156. }
  157. }
  158. break;
  159. default:
  160. goto draw_window;
  161. break;
  162. }
  163. }
  164. } else {
  165. draw_window:
  166. /* Paint window */
  167. cairo_set_source_surface(cr, surf, 0, 0);
  168. if (window->opacity != 255) {
  169. cairo_paint_with_alpha(cr, (float)(window->opacity)/255.0);
  170. } else {
  171. cairo_paint(cr);
  172. }
  173. }
  174. draw_finish:
  175. /* Clean up */
  176. cairo_surface_destroy(surf);
  177. /* Restore context stack */
  178. cairo_restore(cr);
  179. #if YUTANI_DEBUG_WINDOW_BOUNDS
  180. /*
  181. * If window bound debugging is enabled, we also draw a box
  182. * representing the rectangular (possibly rotated) boundary
  183. * for a window texture.
  184. */
  185. if (yg->debug_bounds) {
  186. cairo_save(cr);
  187. int32_t t_x, t_y;
  188. int32_t s_x, s_y;
  189. int32_t r_x, r_y;
  190. int32_t q_x, q_y;
  191. yutani_window_to_device(window, 0, 0, &t_x, &t_y);
  192. yutani_window_to_device(window, window->width, window->height, &s_x, &s_y);
  193. yutani_window_to_device(window, 0, window->height, &r_x, &r_y);
  194. yutani_window_to_device(window, window->width, 0, &q_x, &q_y);
  195. uint32_t x = yutani_color_for_wid(window->wid);
  196. cairo_set_source_rgba(cr,
  197. _RED(x) / 255.0,
  198. _GRE(x) / 255.0,
  199. _BLU(x) / 255.0,
  200. 0.7
  201. );
  202. cairo_move_to(cr, t_x, t_y);
  203. cairo_line_to(cr, r_x, r_y);
  204. cairo_line_to(cr, s_x, s_y);
  205. cairo_line_to(cr, q_x, q_y);
  206. cairo_fill(cr);
  207. cairo_restore(cr);
  208. }
  209. #endif
  210. return 0;
  211. }