From 41527b50abcdd47b3268e3376b680366764034db Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 26 Sep 2021 02:44:54 +0200 Subject: [PATCH] Add crude color management impl for cairo --- gsk/gskcairorenderer.c | 75 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/gsk/gskcairorenderer.c b/gsk/gskcairorenderer.c index 24675ce35f..52adecfdeb 100644 --- a/gsk/gskcairorenderer.c +++ b/gsk/gskcairorenderer.c @@ -1,5 +1,5 @@ /* - * Copyright © 2016 Endless + * Copyright © 2016 Endless * 2018 Benjamin Otte * * This library is free software; you can redistribute it and/or @@ -25,6 +25,9 @@ #include "gskdebugprivate.h" #include "gskrendererprivate.h" #include "gskrendernodeprivate.h" + +#include "gdk/gdkcolorprofileprivate.h" +#include "gdk/gdkmemorytextureprivate.h" #include "gdk/gdktextureprivate.h" #ifdef G_ENABLE_DEBUG @@ -40,6 +43,7 @@ struct _GskCairoRenderer GdkCairoContext *cairo_context; + gboolean color_managed; #ifdef G_ENABLE_DEBUG ProfileTimers profile_timers; #endif @@ -78,8 +82,8 @@ gsk_cairo_renderer_do_render (GskRenderer *renderer, cairo_t *cr, GskRenderNode *root) { -#ifdef G_ENABLE_DEBUG GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer); +#ifdef G_ENABLE_DEBUG GskProfiler *profiler; gint64 cpu_time; #endif @@ -104,6 +108,7 @@ gsk_cairo_renderer_render_texture (GskRenderer *renderer, GskRenderNode *root, const graphene_rect_t *viewport) { + GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer); GdkTexture *texture; cairo_surface_t *surface; cairo_t *cr; @@ -127,7 +132,7 @@ gsk_cairo_renderer_render_texture (GskRenderer *renderer, { for (x = 0; x < width; x += MAX_IMAGE_SIZE) { - texture = gsk_cairo_renderer_render_texture (renderer, root, + texture = gsk_cairo_renderer_render_texture (renderer, root, &GRAPHENE_RECT_INIT (x, y, MIN (MAX_IMAGE_SIZE, viewport->size.width - x), MIN (MAX_IMAGE_SIZE, viewport->size.height - y))); @@ -145,6 +150,9 @@ gsk_cairo_renderer_render_texture (GskRenderer *renderer, } surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + if (self->color_managed) + gdk_cairo_surface_set_color_profile (surface, gdk_color_profile_get_srgb_linear ()); + cr = cairo_create (surface); cairo_translate (cr, - viewport->origin.x, - viewport->origin.y); @@ -189,7 +197,64 @@ gsk_cairo_renderer_render (GskRenderer *renderer, } #endif - gsk_cairo_renderer_do_render (renderer, cr, root); + if (!self->color_managed || + gdk_color_profile_is_linear (gdk_cairo_get_color_profile (cr))) + { + gsk_cairo_renderer_do_render (renderer, cr, root); + } + else + { + GdkSurface *surface = gsk_renderer_get_surface (renderer); + GdkColorProfile *target_profile = gdk_cairo_get_color_profile (cr); + cairo_surface_t *cairo_surface; + cairo_t *cr2; + GdkTexture *color_correct; + const cairo_region_t *frame_region; + cairo_rectangle_int_t extents; + guint i, n; + + frame_region = gdk_draw_context_get_frame_region (GDK_DRAW_CONTEXT (self->cairo_context)); + cairo_region_get_extents (frame_region, &extents); + /* We can't use cairo_push_group() here, because we'd lose the + * color profile information. + */ + cairo_surface = gdk_surface_create_similar_surface (surface, + CAIRO_CONTENT_COLOR_ALPHA, + extents.width, + extents.height); + gdk_cairo_surface_set_color_profile (cairo_surface, + gdk_color_profile_get_srgb_linear ()); + + cr2 = cairo_create (cairo_surface); + cairo_translate (cr2, -extents.x, -extents.y); + gdk_cairo_region (cr2, frame_region); + cairo_clip (cr2); + gsk_cairo_renderer_do_render (renderer, cr2, root); + cairo_destroy (cr2); + + color_correct = gdk_texture_new_for_surface (cairo_surface); + cairo_surface_destroy (cairo_surface); + n = cairo_region_num_rectangles (frame_region); + for (i = 0; i < n; i++) + { + cairo_rectangle_int_t rect; + GdkTexture *sub; + + cairo_region_get_rectangle (frame_region, i, &rect); + rect.x -= extents.x; + rect.y -= extents.y; + + sub = gdk_memory_texture_new_subtexture (GDK_MEMORY_TEXTURE (color_correct), + rect.x, rect.y, rect.width, rect.height); + cairo_surface = gdk_texture_download_surface (sub, target_profile); + cairo_set_source_surface (cr, cairo_surface, rect.x + extents.x, rect.y + extents.y); + cairo_paint (cr); + cairo_surface_destroy (cairo_surface); + g_object_unref (sub); + } + g_object_unref (color_correct); + + } cairo_destroy (cr); @@ -210,6 +275,8 @@ gsk_cairo_renderer_class_init (GskCairoRendererClass *klass) static void gsk_cairo_renderer_init (GskCairoRenderer *self) { + self->color_managed = TRUE; + #ifdef G_ENABLE_DEBUG GskProfiler *profiler = gsk_renderer_get_profiler (GSK_RENDERER (self));