Browse Source

Add Cairo backend for compositor

K. Lange 4 years ago
parent
commit
8a6438b3d2
2 changed files with 224 additions and 0 deletions
  1. 1 0
      Makefile
  2. 223 0
      ext/ext_cairo_renderer.c

+ 1 - 0
Makefile

@@ -327,3 +327,4 @@ ifeq (,$(findstring clean,$(MAKECMDGOALS)))
 endif
 
 ext-freetype: base/lib/libtoaru_ext_freetype_fonts.so
+ext-cairo: base/lib/libtoaru_ext_cairo_renderer.so

+ 223 - 0
ext/ext_cairo_renderer.c

@@ -0,0 +1,223 @@
+/* vim: tabstop=4 shiftwidth=4 noexpandtab
+ * This file is part of ToaruOS and is released under the terms
+ * of the NCSA / University of Illinois License - see LICENSE.md
+ * Copyright (C) 2018 K. Lange
+ *
+ * Compositor Cairo renderer backend
+ */
+
+#include <math.h>
+#include <cairo.h>
+#include <toaru/yutani-server.h>
+
+struct cairo_renderer {
+	cairo_t * framebuffer_ctx;
+	cairo_surface_t * framebuffer_surface;
+};
+
+int renderer_alloc(yutani_globals_t * yg) {
+	struct cairo_renderer * c = malloc(sizeof(struct cairo_renderer));
+	c->framebuffer_ctx = NULL;
+	c->framebuffer_surface = NULL;
+	yg->renderer_ctx = c;
+	return 0;
+}
+
+int renderer_init(yutani_globals_t * yg) {
+	struct cairo_renderer * c = yg->renderer_ctx;
+
+	int stride = yg->width * 4;
+	c->framebuffer_surface = cairo_image_surface_create_for_data(
+			yg->backend_framebuffer, CAIRO_FORMAT_ARGB32, yg->width, yg->height, stride);
+	c->framebuffer_ctx = cairo_create(c->framebuffer_surface);
+
+	return 0;
+}
+
+int renderer_add_clip(yutani_globals_t * yg, double x, double y, double w, double h) {
+	struct cairo_renderer * c = yg->renderer_ctx;
+	cairo_rectangle(c->framebuffer_ctx, x, y, w, h);
+	return 0;
+}
+
+int renderer_set_clip(yutani_globals_t * yg) {
+	struct cairo_renderer * c = yg->renderer_ctx;
+	cairo_clip(c->framebuffer_ctx);
+	return 0;
+}
+
+int renderer_push_state(yutani_globals_t * yg) {
+	struct cairo_renderer * c = yg->renderer_ctx;
+	cairo_save(c->framebuffer_ctx);
+	return 0;
+}
+
+int renderer_pop_state(yutani_globals_t * yg) {
+	struct cairo_renderer * c = yg->renderer_ctx;
+	cairo_restore(c->framebuffer_ctx);
+	return 0;
+}
+
+int renderer_destroy(yutani_globals_t * yg) {
+	struct cairo_renderer * c = yg->renderer_ctx;
+	cairo_destroy(c->framebuffer_ctx);
+	cairo_surface_destroy(c->framebuffer_surface);
+	return 0;
+}
+
+
+int renderer_blit_window(yutani_globals_t * yg, yutani_server_window_t * window, int x, int y) {
+	/* Obtain the previously initialized cairo contexts */
+	struct cairo_renderer * c = yg->renderer_ctx;
+	cairo_t * cr = c->framebuffer_ctx;
+
+	/* Window stride is always 4 bytes per pixel... */
+	int stride = window->width * 4;
+
+	/* Initialize a cairo surface object for this window */
+	cairo_surface_t * surf = cairo_image_surface_create_for_data(
+			window->buffer, CAIRO_FORMAT_ARGB32, window->width, window->height, stride);
+
+	/* Save cairo context */
+	cairo_save(cr);
+
+	/*
+	 * Offset the rendering context appropriately for the position of the window
+	 * based on the modifier paramters
+	 */
+	cairo_identity_matrix(cr);
+	cairo_translate(cr, x, y);
+
+	/* Top and bottom windows can not be rotated. */
+	if (!yutani_window_is_top(yg, window) && !yutani_window_is_bottom(yg, window)) {
+		/* Calcuate radians from degrees */
+
+		if (window->rotation != 0) {
+			double r = M_PI * (((double)window->rotation) / 180.0);
+
+			/* Rotate the render context about the center of the window */
+			cairo_translate(cr, (int)( window->width / 2), (int)( (int)window->height / 2));
+			cairo_rotate(cr, r);
+			cairo_translate(cr, (int)(-window->width / 2), (int)(-window->height / 2));
+
+			/* Prefer faster filter when rendering rotated windows */
+			cairo_pattern_t * p = cairo_get_source(cr);
+			cairo_pattern_set_filter(p, CAIRO_FILTER_FAST);
+		}
+
+		if (window == yg->resizing_window) {
+			double x_scale = (double)yg->resizing_w / (double)yg->resizing_window->width;
+			double y_scale = (double)yg->resizing_h / (double)yg->resizing_window->height;
+			if (x_scale < 0.00001) {
+				x_scale = 0.00001;
+			}
+			if (y_scale < 0.00001) {
+				y_scale = 0.00001;
+			}
+			cairo_translate(cr, (int)yg->resizing_offset_x, (int)yg->resizing_offset_y);
+			cairo_scale(cr, x_scale, y_scale);
+		}
+
+	}
+	if (window->anim_mode) {
+		int frame = yutani_time_since(yg, window->anim_start);
+		if (frame >= yutani_animation_lengths[window->anim_mode]) {
+			if (window->anim_mode == YUTANI_EFFECT_FADE_OUT) {
+				list_insert(yg->windows_to_remove, window);
+				goto draw_finish;
+			}
+			window->anim_mode = 0;
+			window->anim_start = 0;
+			goto draw_window;
+		} else {
+			switch (window->anim_mode) {
+				case YUTANI_EFFECT_FADE_OUT:
+					{
+						frame = yutani_animation_lengths[window->anim_mode] - frame;
+					}
+				case YUTANI_EFFECT_FADE_IN:
+					{
+						double time_diff = ((double)frame / (float)yutani_animation_lengths[window->anim_mode]);
+
+						if (!yutani_window_is_top(yg, window) && !yutani_window_is_bottom(yg, window) &&
+							!(window->server_flags & YUTANI_WINDOW_FLAG_ALT_ANIMATION)) {
+							double x = 0.75 + time_diff * 0.25;
+							int t_x = (window->width * (1.0 - x)) / 2;
+							int t_y = (window->height * (1.0 - x)) / 2;
+							cairo_translate(cr, t_x, t_y);
+							cairo_scale(cr, x, x);
+						}
+
+						cairo_set_source_surface(cr, surf, 0, 0);
+						if (window->opacity != 255) {
+							cairo_paint_with_alpha(cr, time_diff * (double)(window->opacity) / 255.0);
+						} else {
+							cairo_paint_with_alpha(cr, time_diff);
+						}
+					}
+					break;
+				default:
+					goto draw_window;
+					break;
+			}
+		}
+	} else {
+draw_window:
+		/* Paint window */
+		cairo_set_source_surface(cr, surf, 0, 0);
+
+		if (window->opacity != 255) {
+			cairo_paint_with_alpha(cr, (float)(window->opacity)/255.0);
+		} else {
+			cairo_paint(cr);
+		}
+	}
+
+draw_finish:
+
+	/* Clean up */
+	cairo_surface_destroy(surf);
+
+	/* Restore context stack */
+	cairo_restore(cr);
+
+#if YUTANI_DEBUG_WINDOW_BOUNDS
+	/*
+	 * If window bound debugging is enabled, we also draw a box
+	 * representing the rectangular (possibly rotated) boundary
+	 * for a window texture.
+	 */
+	if (yg->debug_bounds) {
+		cairo_save(cr);
+
+		int32_t t_x, t_y;
+		int32_t s_x, s_y;
+		int32_t r_x, r_y;
+		int32_t q_x, q_y;
+
+		yutani_window_to_device(window, 0, 0, &t_x, &t_y);
+		yutani_window_to_device(window, window->width, window->height, &s_x, &s_y);
+		yutani_window_to_device(window, 0, window->height, &r_x, &r_y);
+		yutani_window_to_device(window, window->width, 0, &q_x, &q_y);
+
+		uint32_t x = yutani_color_for_wid(window->wid);
+		cairo_set_source_rgba(cr,
+				_RED(x) / 255.0,
+				_GRE(x) / 255.0,
+				_BLU(x) / 255.0,
+				0.7
+		);
+
+		cairo_move_to(cr, t_x, t_y);
+		cairo_line_to(cr, r_x, r_y);
+		cairo_line_to(cr, s_x, s_y);
+		cairo_line_to(cr, q_x, q_y);
+		cairo_fill(cr);
+
+		cairo_restore(cr);
+	}
+#endif
+
+
+	return 0;
+}