#pragma once
#include "gdkcolorstateprivate.h"
#include "gdkcolorprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytexture.h"
#include "gdkrectangleprivate.h"
#include <cairo.h>
#include <graphene.h>
static inline cairo_format_t
gdk_cairo_format_for_depth (GdkMemoryDepth depth)
{
switch (depth)
{
case GDK_MEMORY_NONE:
case GDK_MEMORY_U8:
return CAIRO_FORMAT_ARGB32;
case GDK_MEMORY_FLOAT16:
case GDK_MEMORY_FLOAT32:
return CAIRO_FORMAT_RGBA128F;
case GDK_N_DEPTHS:
default :
g_return_val_if_reached (CAIRO_FORMAT_ARGB32);
}
}
static inline GdkMemoryFormat
gdk_cairo_format_to_memory_format (cairo_format_t format)
{
GdkMemoryFormat result;
if (!gdk_memory_format_find_by_cairo_format (format, &result))
result = GDK_MEMORY_DEFAULT;
return result;
}
static inline cairo_format_t
gdk_cairo_format_for_content (cairo_content_t content)
{
switch (content)
{
case CAIRO_CONTENT_COLOR:
return CAIRO_FORMAT_RGB24;
case CAIRO_CONTENT_ALPHA:
return CAIRO_FORMAT_A8;
case CAIRO_CONTENT_COLOR_ALPHA:
return CAIRO_FORMAT_ARGB32;
default :
g_return_val_if_reached (CAIRO_FORMAT_ARGB32);
}
}
static inline void
gdk_cairo_set_source_color (cairo_t *cr,
GdkColorState *ccs,
const GdkColor *color)
{
float c[
4 ];
gdk_color_to_float (color, ccs, c);
cairo_set_source_rgba (cr, c[
0 ], c[
1 ], c[
2 ], c[
3 ]);
}
static inline void
gdk_cairo_set_source_rgba_ccs (cairo_t *cr,
GdkColorState *ccs,
const GdkRGBA *rgba)
{
GdkColor c;
gdk_color_init_from_rgba (&c, rgba);
gdk_cairo_set_source_color (cr, ccs, &c);
gdk_color_finish (&c);
}
static inline void
gdk_cairo_pattern_add_color_stop_rgba_ccs (cairo_pattern_t *pattern,
GdkColorState *ccs,
double offset,
const GdkRGBA *rgba)
{
float color[
4 ];
gdk_color_state_from_rgba (ccs, rgba, color);
cairo_pattern_add_color_stop_rgba (pattern, offset, color[
0 ], color[
1 ], color[
2 ], colo
r[3 ]);
}
static inline void
gdk_cairo_pattern_add_color_stop_color (cairo_pattern_t *pattern,
GdkColorState *ccs,
double offset,
const GdkColor *color)
{
float values[4 ];
gdk_color_to_float (color, ccs, values);
cairo_pattern_add_color_stop_rgba (pattern, offset, values[0 ], values[1 ], values[2 ], values[3 ]);
}
static inline void
gdk_cairo_rect (cairo_t *cr,
const graphene_rect_t *rect)
{
cairo_rectangle (cr,
rect->origin.x, rect->origin.y,
rect->size.width, rect->size.height);
}
static inline void
gdk_cairo_surface_convert_color_state (cairo_surface_t *surface,
GdkColorState *source,
GdkColorState *target)
{
cairo_surface_t *image_surface;
int status, width, height;
if (gdk_color_state_equal (source, target))
return ;
image_surface = cairo_surface_map_to_image (surface, NULL);
status = cairo_surface_status (image_surface);
width = cairo_image_surface_get_width (image_surface);
height = cairo_image_surface_get_height (image_surface);
if (status == CAIRO_STATUS_SUCCESS && width > 0 && height > 0 )
{
gdk_memory_convert_color_state (cairo_image_surface_get_data (image_surface),
&GDK_MEMORY_LAYOUT_SIMPLE (
gdk_cairo_format_to_memory_format (cairo_image_surface_get_format (image_surface)),
width,
height,
cairo_image_surface_get_stride (image_surface)),
source,
target);
}
cairo_surface_mark_dirty (image_surface);
cairo_surface_unmap_image (surface, image_surface);
/* https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/487 */
cairo_surface_mark_dirty (surface);
}
static inline cairo_region_t *
gdk_cairo_region_scale_grow (const cairo_region_t *region,
double scale_x,
double scale_y)
{
cairo_region_t *result;
result = cairo_region_create ();
for (int i = 0 ; i < cairo_region_num_rectangles (region); i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
cairo_region_union_rectangle (result, &(cairo_rectangle_int_t) {
.x = (int ) floor (rect.x * scale_x),
.y = (int ) floor (rect.y * scale_y),
.width = (int ) ceil ((rect.x + rect.width) * scale_x) - floor (rect.x * scale_x),
.height = (int ) ceil ((rect.y + rect.height) * scale_y) - floor (rect.y * scale_y),
});
}
return result;
}
static inline char *
gdk_cairo_region_to_debug_string (const cairo_region_t *region)
{
GString *string;
cairo_rectangle_int_t extents;
cairo_region_get_extents (region, &extents);
string = g_string_new (NULL);
g_string_append_printf (string, "{ %d, %d, %d, %d } (%d rects)" ,
extents.x, extents.y, extents.width, extents.height,
cairo_region_num_rectangles (region));
return g_string_free (string, FALSE );
}
static inline gboolean
gdk_cairo_is_all_clipped (cairo_t *cr)
{
double x1, y1, x2, y2;
cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
return x1 >= x2 || y1 >= y2;
}
/* apply a rectangle that bounds @rect in
* pixel - aligned device coordinates .
*
* This is useful for clipping to minimize the rectangle
* in push_group ( ) or when blurring .
*/
static inline void
gdk_cairo_rectangle_snap_to_grid (cairo_t *cr,
const graphene_rect_t *rect)
{
double x0, x1, x2, x3;
double y0, y1, y2, y3;
double xmin, xmax, ymin, ymax;
x0 = rect->origin.x;
y0 = rect->origin.y;
cairo_user_to_device (cr, &x0, &y0);
x1 = rect->origin.x + rect->size.width;
y1 = rect->origin.y;
cairo_user_to_device (cr, &x1, &y1);
x2 = rect->origin.x;
y2 = rect->origin.y + rect->size.height;
cairo_user_to_device (cr, &x2, &y2);
x3 = rect->origin.x + rect->size.width;
y3 = rect->origin.y + rect->size.height;
cairo_user_to_device (cr, &x3, &y3);
xmin = MIN (MIN (x0, x1), MIN (x2, x3));
ymin = MIN (MIN (y0, y1), MIN (y2, y3));
xmax = MAX (MAX (x0, x1), MAX (x2, x3));
ymax = MAX (MAX (y0, y1), MAX (y2, y3));
xmin = floor (xmin);
ymin = floor (ymin);
xmax = ceil (xmax);
ymax = ceil (ymax);
cairo_save (cr);
cairo_identity_matrix (cr);
cairo_rectangle (cr, xmin, ymin, xmax - xmin, ymax - ymin);
cairo_restore (cr);
}
/**
* gdk_cairo_create_similar_surface :
* @ cr : cairo context
* @ content : the kind of surface to create
* @ bounds : the bounds to create the surface for
*
* Creates a surface for offscreen rendering that isn ' t
* confined by Cairo ' s clipping behavior . So this is
* useful as an alternative to cairo_push_group ( ) if
* you want a guarantee that the whole area will be
* created , for example when blurring and needing a larger
* input area .
*
* This function will set the surface ' s device scale and offset .
*
* Once done with rendering to the returned surface , you
* can render it to the given bounds with this code :
*
* ` ` ` c
* cairo_set_source_surface ( cr , surface ) ;
* cairo_paint ( cr ) ;
* ` ` `
*
* Returns : a new cairo surface
**/
static inline cairo_surface_t *
gdk_cairo_create_similar_surface (cairo_t *cr,
cairo_content_t content,
const graphene_rect_t *bounds)
{
cairo_matrix_t matrix;
double xscale, yscale, det, width, height;
cairo_surface_t *surface;
cairo_get_matrix (cr, &matrix);
cairo_surface_get_device_scale (cairo_get_target (cr), &xscale, &yscale);
det = matrix.xx * matrix.yy - matrix.xy * matrix.yx;
if (matrix.xx != 0 || matrix.yx != 0 )
{
width = sqrt (matrix.xx * matrix.xx + matrix.yx * matrix.yx);
height = det / width;
}
else if (matrix.yx != 0 || matrix.yy != 0 )
{
height = sqrt (matrix.yx * matrix.yx + matrix.yy * matrix.yy);
width = det / height;
}
else
{
g_return_val_if_reached (NULL);
}
width = ABS (ceil (width * bounds->size.width * xscale));
height = ABS (ceil (height * bounds->size.height * yscale));
surface = cairo_surface_create_similar (cairo_get_group_target (cr),
content,
width, height);
xscale = width / bounds->size.width;
yscale = height / bounds->size.height;
cairo_surface_set_device_scale (surface, xscale, yscale);
cairo_surface_set_device_offset (surface,
- bounds->origin.x * xscale,
- bounds->origin.y * yscale);
return surface;
}
static inline void
gdk_cairo_region_union_affine (cairo_region_t *region,
const cairo_region_t *sub,
float scale_x,
float scale_y,
float offset_x,
float offset_y)
{
cairo_rectangle_int_t rect;
int i;
for (i = 0 ; i < cairo_region_num_rectangles (sub); i++)
{
cairo_region_get_rectangle (sub, i, &rect);
gdk_rectangle_transform_affine (&rect, scale_x, scale_y, offset_x, offset_y, &rect);
cairo_region_union_rectangle (region, &rect);
}
}
/*
* gdk_cairo_region_is_rectangle :
* @ region : a cairo region
*
* Checks if the region can be represented by a rectangle .
*
* This rectangle can be queried with cairo_region_get_extents ( ) .
*
* FIXME : Should this return TRUE or FALSE for an empty region ?
* Currently I have no use case , so it returns whatever .
*
* Returns : true if the region is a rectangle .
**/
static inline gboolean
gdk_cairo_region_is_rectangle (cairo_region_t *region)
{
return cairo_region_num_rectangles (region) == 1 ;
}
static inline void
gdk_cairo_surface_get_device_matrix (cairo_surface_t *surface,
cairo_matrix_t *matrix)
{
cairo_surface_get_device_scale (surface, &matrix->xx, &matrix->yy);
cairo_surface_get_device_offset (surface, &matrix->x0, &matrix->y0);
matrix->yx = matrix->xy = 0 ;
}
Messung V0.5 in Prozent C=98 H=93 G=95
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-07-03)
¤
*© Formatika GbR, Deutschland