// cairo_public cairo_region_t * // cairo_region_copy (const cairo_region_t *original); static int l_cairo_region_copy (lua_State* L) { const cairo_region_t *original = get_cairo_region_t (L, 1); cairo_region_t *v = cairo_region_copy (original); lua_pushlightuserdata(L, v); return 1; }
static void set_unobscured_region (MetaShapedTexture *self, cairo_region_t *unobscured_region) { MetaShapedTexturePrivate *priv = self->priv; g_clear_pointer (&priv->unobscured_region, (GDestroyNotify) cairo_region_destroy); if (unobscured_region) { guint width, height; if (priv->texture) { width = priv->tex_width; height = priv->tex_height; } else { width = priv->fallback_width; height = priv->fallback_height; } cairo_rectangle_int_t bounds = { 0, 0, width, height }; priv->unobscured_region = cairo_region_copy (unobscured_region); cairo_region_intersect_rectangle (priv->unobscured_region, &bounds); } }
cairo_region_t * meta_region_transform (cairo_region_t *region, MetaMonitorTransform transform, int width, int height) { int n_rects, i; cairo_rectangle_int_t *rects; cairo_region_t *transformed_region; if (transform == META_MONITOR_TRANSFORM_NORMAL) return cairo_region_copy (region); n_rects = cairo_region_num_rectangles (region); rects = g_new0 (cairo_rectangle_int_t, n_rects); for (i = 0; i < n_rects; i++) { cairo_region_get_rectangle (region, i, &rects[i]); meta_rectangle_transform (&rects[i], transform, width, height, &rects[i]); } transformed_region = cairo_region_create_rectangles (rects, n_rects); g_free (rects); return transformed_region; }
cairo_region_t * meta_region_scale (cairo_region_t *region, int scale) { int n_rects, i; cairo_rectangle_int_t *rects; cairo_region_t *scaled_region; if (scale == 1) return cairo_region_copy (region); n_rects = cairo_region_num_rectangles (region); rects = g_malloc (sizeof(cairo_rectangle_int_t) * n_rects); for (i = 0; i < n_rects; i++) { cairo_region_get_rectangle (region, i, &rects[i]); rects[i].x *= scale; rects[i].y *= scale; rects[i].width *= scale; rects[i].height *= scale; } scaled_region = cairo_region_create_rectangles (rects, n_rects); g_free (rects); return scaled_region; }
cairo_region_t * meta_region_scale_double (cairo_region_t *region, double scale, MetaRoundingStrategy rounding_strategy) { int n_rects, i; cairo_rectangle_int_t *rects; cairo_region_t *scaled_region; g_return_val_if_fail (scale > 0.0, NULL); if (scale == 1.0) return cairo_region_copy (region); n_rects = cairo_region_num_rectangles (region); rects = g_malloc (sizeof(cairo_rectangle_int_t) * n_rects); for (i = 0; i < n_rects; i++) { cairo_region_get_rectangle (region, i, &rects[i]); meta_rectangle_scale_double (&rects[i], scale, rounding_strategy, &rects[i]); } scaled_region = cairo_region_create_rectangles (rects, n_rects); g_free (rects); return scaled_region; }
/** * gsk_renderer_render: * @renderer: a #GskRenderer * @root: a #GskRenderNode * @region: (nullable): the #cairo_region_t that must be redrawn or %NULL * for the whole window * * Renders the scene graph, described by a tree of #GskRenderNode instances, * ensuring that the given @region gets redrawn. * * Renderers must ensure that changes of the contents given by the @root * node as well as the area given by @region are redrawn. They are however * free to not redraw any pixel outside of @region if they can guarantee that * it didn't change. * * The @renderer will acquire a reference on the #GskRenderNode tree while * the rendering is in progress. */ void gsk_renderer_render (GskRenderer *renderer, GskRenderNode *root, const cairo_region_t *region) { GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); cairo_region_t *clip; g_return_if_fail (GSK_IS_RENDERER (renderer)); g_return_if_fail (priv->is_realized); g_return_if_fail (GSK_IS_RENDER_NODE (root)); g_return_if_fail (priv->root_node == NULL); if (region == NULL || priv->prev_node == NULL || GSK_RENDERER_DEBUG_CHECK (renderer, FULL_REDRAW)) { clip = cairo_region_create_rectangle (&(GdkRectangle) { 0, 0, gdk_surface_get_width (priv->surface), gdk_surface_get_height (priv->surface) }); } else { clip = cairo_region_copy (region); gsk_render_node_diff (priv->prev_node, root, clip); if (cairo_region_is_empty (clip)) { cairo_region_destroy (clip); return; } } priv->root_node = gsk_render_node_ref (root); GSK_RENDERER_GET_CLASS (renderer)->render (renderer, root, clip); #ifdef G_ENABLE_DEBUG if (GSK_RENDERER_DEBUG_CHECK (renderer, RENDERER)) { GString *buf = g_string_new ("*** Frame stats ***\n\n"); gsk_profiler_append_counters (priv->profiler, buf); g_string_append_c (buf, '\n'); gsk_profiler_append_timers (priv->profiler, buf); g_string_append_c (buf, '\n'); g_print ("%s\n***\n\n", buf->str); g_string_free (buf, TRUE); } #endif g_clear_pointer (&priv->prev_node, gsk_render_node_unref); cairo_region_destroy (clip); priv->prev_node = priv->root_node; priv->root_node = NULL; }
wxRegionRefData(const wxRegionRefData& refData) : wxGDIRefData() { #ifdef __WXGTK3__ m_region = cairo_region_copy(refData.m_region); #else m_region = gdk_region_copy(refData.m_region); #endif }
static void set_clip_region (MetaShapedTexture *self, cairo_region_t *clip_region) { MetaShapedTexturePrivate *priv = self->priv; g_clear_pointer (&priv->clip_region, (GDestroyNotify) cairo_region_destroy); if (clip_region) priv->clip_region = cairo_region_copy (clip_region); }
static void set_clip_region (MetaBackgroundActor *self, cairo_region_t *clip_region) { MetaBackgroundActorPrivate *priv = self->priv; g_clear_pointer (&priv->clip_region, (GDestroyNotify) cairo_region_destroy); if (clip_region) priv->clip_region = cairo_region_copy (clip_region); }
/* Region is in canvas coordinates */ void _gtk_pixel_cache_invalidate (GtkPixelCache *cache, cairo_region_t *region) { cairo_rectangle_int_t r; cairo_region_t *free_region = NULL; if (cache->surface == NULL || (region != NULL && cairo_region_is_empty (region))) return; if (region == NULL) { r.x = cache->surface_x; r.y = cache->surface_y; r.width = cache->surface_w; r.height = cache->surface_h; free_region = region = cairo_region_create_rectangle (&r); } if (cache->surface_dirty == NULL) { cache->surface_dirty = cairo_region_copy (region); cairo_region_translate (cache->surface_dirty, -cache->surface_x, -cache->surface_y); } else { cairo_region_translate (region, -cache->surface_x, -cache->surface_y); cairo_region_union (cache->surface_dirty, region); cairo_region_translate (region, cache->surface_x, cache->surface_y); } if (free_region) cairo_region_destroy (free_region); r.x = 0; r.y = 0; r.width = cache->surface_w; r.height = cache->surface_h; cairo_region_intersect_rectangle (cache->surface_dirty, &r); }
static cairo_status_t _cairo_clip_path_reapply_clip_path_translate (cairo_clip_t *clip, cairo_clip_path_t *other_path, int tx, int ty) { cairo_status_t status; cairo_clip_path_t *clip_path; if (other_path->prev != NULL) { status = _cairo_clip_path_reapply_clip_path_translate (clip, other_path->prev, tx, ty); if (unlikely (status)) return status; } clip_path = _cairo_clip_path_create (clip); if (unlikely (clip_path == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_path_fixed_init_copy (&clip_path->path, &other_path->path); if (unlikely (status)) { _cairo_clip_path_destroy (clip_path); return status; } _cairo_path_fixed_translate (&clip_path->path, _cairo_fixed_from_int (tx), _cairo_fixed_from_int (ty)); clip_path->fill_rule = other_path->fill_rule; clip_path->tolerance = other_path->tolerance; clip_path->antialias = other_path->antialias; clip_path->flags = other_path->flags; if (other_path->region != NULL) { clip_path->region = cairo_region_copy (other_path->region); cairo_region_translate (clip_path->region, tx, ty); } clip_path->surface = cairo_surface_reference (other_path->surface); clip_path->extents = other_path->extents; clip_path->extents.x += tx; clip_path->extents.y += ty; return CAIRO_STATUS_SUCCESS; }
cairo_region_t * meta_region_crop_and_scale (cairo_region_t *region, ClutterRect *src_rect, int dst_width, int dst_height) { int n_rects, i; cairo_rectangle_int_t *rects; cairo_region_t *viewport_region; if (src_rect->size.width == dst_width && src_rect->size.height == dst_height && roundf (src_rect->origin.x) == src_rect->origin.x && roundf (src_rect->origin.y) == src_rect->origin.y) { viewport_region = cairo_region_copy (region); if (src_rect->origin.x != 0 || src_rect->origin.y != 0) { cairo_region_translate (viewport_region, (int) src_rect->origin.x, (int) src_rect->origin.y); } return viewport_region; } n_rects = cairo_region_num_rectangles (region); rects = g_new0 (cairo_rectangle_int_t, n_rects); for (i = 0; i < n_rects; i++) { cairo_region_get_rectangle (region, i, &rects[i]); meta_rectangle_crop_and_scale (&rects[i], src_rect, dst_width, dst_height, &rects[i]); } viewport_region = cairo_region_create_rectangles (rects, n_rects); g_free (rects); return viewport_region; }
void gtk_snapshot_push_rounded_clip (GtkSnapshot *snapshot, const GskRoundedRect *bounds, const char *name, ...) { GskRoundedRect *real_bounds; cairo_region_t *clip; cairo_rectangle_int_t rect; char *str; real_bounds = g_slice_new (GskRoundedRect); gsk_rounded_rect_init_copy (real_bounds, bounds); gsk_rounded_rect_offset (real_bounds, snapshot->state->translate_x, snapshot->state->translate_y); if (name) { va_list args; va_start (args, name); str = g_strdup_vprintf (name, args); va_end (args); } else str = NULL; rectangle_init_from_graphene (&rect, &real_bounds->bounds); if (snapshot->state->clip_region) { clip = cairo_region_copy (snapshot->state->clip_region); cairo_region_intersect_rectangle (clip, &rect); } else { clip = cairo_region_create_rectangle (&rect); } snapshot->state = gtk_snapshot_state_new (snapshot->state, str, clip, snapshot->state->translate_x, snapshot->state->translate_y, gtk_snapshot_collect_rounded_clip, real_bounds); cairo_region_destroy (clip); }
GtkInspectorRecording * gtk_inspector_render_recording_new (gint64 timestamp, GskProfiler *profiler, const GdkRectangle *area, const cairo_region_t *clip_region, GskRenderNode *node) { GtkInspectorRenderRecording *recording; recording = g_object_new (GTK_TYPE_INSPECTOR_RENDER_RECORDING, "timestamp", timestamp, NULL); collect_profiler_info (recording, profiler); recording->area = *area; recording->clip_region = cairo_region_copy (clip_region); recording->node = gsk_render_node_ref (node); return GTK_INSPECTOR_RECORDING (recording); }
static GeglTile * gimp_tile_handler_projection_validate (GeglTileSource *source, GeglTile *tile, gint x, gint y) { GimpTileHandlerProjection *projection; cairo_region_t *tile_region; cairo_rectangle_int_t tile_rect; projection = GIMP_TILE_HANDLER_PROJECTION (source); if (cairo_region_is_empty (projection->dirty_region)) return tile; tile_region = cairo_region_copy (projection->dirty_region); tile_rect.x = x * projection->tile_width; tile_rect.y = y * projection->tile_height; tile_rect.width = projection->tile_width; tile_rect.height = projection->tile_height; cairo_region_intersect_rectangle (tile_region, &tile_rect); if (! cairo_region_is_empty (tile_region)) { gint tile_bpp; gint tile_stride; gint n_rects; gint i; if (! tile) tile = gegl_tile_handler_create_tile (GEGL_TILE_HANDLER (source), x, y, 0); cairo_region_subtract_rectangle (projection->dirty_region, &tile_rect); tile_bpp = babl_format_get_bytes_per_pixel (projection->format); tile_stride = tile_bpp * projection->tile_width; gegl_tile_lock (tile); n_rects = cairo_region_num_rectangles (tile_region); #if 0 g_printerr ("%d ", n_rects); #endif for (i = 0; i < n_rects; i++) { cairo_rectangle_int_t blit_rect; cairo_region_get_rectangle (tile_region, i, &blit_rect); #if 0 g_printerr ("constructing projection at %d %d %d %d\n", blit_rect.x, blit_rect.y, blit_rect.width, blit_rect.height); #endif gegl_node_blit (projection->graph, 1.0, GEGL_RECTANGLE (blit_rect.x, blit_rect.y, blit_rect.width, blit_rect.height), projection->format, gegl_tile_get_data (tile) + (blit_rect.y % projection->tile_height) * tile_stride + (blit_rect.x % projection->tile_width) * tile_bpp, tile_stride, GEGL_ABYSS_NONE); } gegl_tile_unlock (tile); } cairo_region_destroy (tile_region); return tile; }
/** * gdk_cairo_draw_from_gl: * @cr: a cairo context * @window: The window we're rendering for (not necessarily into) * @source: The GL ID of the source buffer * @source_type: The type of the @source * @buffer_scale: The scale-factor that the @source buffer is allocated for * @x: The source x position in @source to start copying from in GL coordinates * @y: The source y position in @source to start copying from in GL coordinates * @width: The width of the region to draw * @height: The height of the region to draw * * This is the main way to draw GL content in GTK+. It takes a render buffer ID * (@source_type == #GL_RENDERBUFFER) or a texture id (@source_type == #GL_TEXTURE) * and draws it onto @cr with an OVER operation, respecting the current clip. * The top left corner of the rectangle specified by @x, @y, @width and @height * will be drawn at the current (0,0) position of the cairo_t. * * This will work for *all* cairo_t, as long as @window is realized, but the * fallback implementation that reads back the pixels from the buffer may be * used in the general case. In the case of direct drawing to a window with * no special effects applied to @cr it will however use a more efficient * approach. * * For #GL_RENDERBUFFER the code will always fall back to software for buffers * with alpha components, so make sure you use #GL_TEXTURE if using alpha. * * Calling this may change the current GL context. * * Since: 3.16 */ void gdk_cairo_draw_from_gl (cairo_t *cr, GdkWindow *window, int source, int source_type, int buffer_scale, int x, int y, int width, int height) { GdkGLContext *paint_context; cairo_surface_t *image; cairo_matrix_t matrix; int dx, dy, window_scale; gboolean trivial_transform; cairo_surface_t *group_target; GdkWindow *direct_window, *impl_window; guint framebuffer; int alpha_size = 0; cairo_region_t *clip_region; GdkGLContextPaintData *paint_data; impl_window = window->impl_window; window_scale = gdk_window_get_scale_factor (impl_window); paint_context = gdk_window_get_paint_gl_context (window, NULL); if (paint_context == NULL) { g_warning ("gdk_cairo_draw_gl_render_buffer failed - no paint context"); return; } clip_region = gdk_cairo_region_from_clip (cr); gdk_gl_context_make_current (paint_context); paint_data = gdk_gl_context_get_paint_data (paint_context); if (paint_data->tmp_framebuffer == 0) glGenFramebuffersEXT (1, &paint_data->tmp_framebuffer); if (source_type == GL_RENDERBUFFER) { glBindRenderbuffer (GL_RENDERBUFFER, source); glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_ALPHA_SIZE, &alpha_size); } else if (source_type == GL_TEXTURE) { glBindTexture (GL_TEXTURE_2D, source); glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_ALPHA_SIZE, &alpha_size); } else { g_warning ("Unsupported gl source type %d\n", source_type); return; } group_target = cairo_get_group_target (cr); direct_window = cairo_surface_get_user_data (group_target, &direct_key); cairo_get_matrix (cr, &matrix); dx = matrix.x0; dy = matrix.y0; /* Trivial == integer-only translation */ trivial_transform = (double)dx == matrix.x0 && (double)dy == matrix.y0 && matrix.xx == 1.0 && matrix.xy == 0.0 && matrix.yx == 0.0 && matrix.yy == 1.0; /* For direct paint of non-alpha renderbuffer, we can just do a bitblit */ if ((_gdk_gl_flags & GDK_GL_SOFTWARE_DRAW_GL) == 0 && source_type == GL_RENDERBUFFER && alpha_size == 0 && direct_window != NULL && direct_window->current_paint.use_gl && trivial_transform && clip_region != NULL) { int unscaled_window_height; int i; /* Create a framebuffer with the source renderbuffer and make it the current target for reads */ framebuffer = paint_data->tmp_framebuffer; glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, framebuffer); glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, source); glBindFramebufferEXT (GL_DRAW_FRAMEBUFFER_EXT, 0); /* Translate to impl coords */ cairo_region_translate (clip_region, dx, dy); glEnable (GL_SCISSOR_TEST); gdk_window_get_unscaled_size (impl_window, NULL, &unscaled_window_height); glDrawBuffer (GL_BACK); #define FLIP_Y(_y) (unscaled_window_height - (_y)) for (i = 0; i < cairo_region_num_rectangles (clip_region); i++) { cairo_rectangle_int_t clip_rect, dest; cairo_region_get_rectangle (clip_region, i, &clip_rect); clip_rect.x *= window_scale; clip_rect.y *= window_scale; clip_rect.width *= window_scale; clip_rect.height *= window_scale; glScissor (clip_rect.x, FLIP_Y (clip_rect.y + clip_rect.height), clip_rect.width, clip_rect.height); dest.x = dx * window_scale; dest.y = dy * window_scale; dest.width = width * window_scale / buffer_scale; dest.height = height * window_scale / buffer_scale; if (gdk_rectangle_intersect (&clip_rect, &dest, &dest)) { int clipped_src_x = x + (dest.x - dx * window_scale); int clipped_src_y = y + (height - dest.height - (dest.y - dy * window_scale)); glBlitFramebufferEXT(clipped_src_x, clipped_src_y, (clipped_src_x + dest.width), (clipped_src_y + dest.height), dest.x, FLIP_Y(dest.y + dest.height), dest.x + dest.width, FLIP_Y(dest.y), GL_COLOR_BUFFER_BIT, GL_NEAREST); if (impl_window->current_paint.flushed_region) { cairo_rectangle_int_t flushed_rect; flushed_rect.x = dest.x / window_scale; flushed_rect.y = dest.y / window_scale; flushed_rect.width = (dest.x + dest.width + window_scale - 1) / window_scale - flushed_rect.x; flushed_rect.height = (dest.y + dest.height + window_scale - 1) / window_scale - flushed_rect.y; cairo_region_union_rectangle (impl_window->current_paint.flushed_region, &flushed_rect); cairo_region_subtract_rectangle (impl_window->current_paint.need_blend_region, &flushed_rect); } } } glDisable (GL_SCISSOR_TEST); glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); #undef FLIP_Y } /* For direct paint of alpha or non-alpha textures we can use texturing */ else if ((_gdk_gl_flags & GDK_GL_SOFTWARE_DRAW_GL) == 0 && source_type == GL_TEXTURE && direct_window != NULL && direct_window->current_paint.use_gl && trivial_transform && clip_region != NULL) { int unscaled_window_height; GLint texture_width; GLint texture_height; int i, n_rects, n_quads; GdkTexturedQuad *quads; cairo_rectangle_int_t clip_rect; /* Translate to impl coords */ cairo_region_translate (clip_region, dx, dy); if (alpha_size != 0) { cairo_region_t *opaque_region, *blend_region; opaque_region = cairo_region_copy (clip_region); cairo_region_subtract (opaque_region, impl_window->current_paint.flushed_region); cairo_region_subtract (opaque_region, impl_window->current_paint.need_blend_region); if (!cairo_region_is_empty (opaque_region)) gdk_gl_texture_from_surface (impl_window->current_paint.surface, opaque_region); blend_region = cairo_region_copy (clip_region); cairo_region_intersect (blend_region, impl_window->current_paint.need_blend_region); glEnable (GL_BLEND); if (!cairo_region_is_empty (blend_region)) gdk_gl_texture_from_surface (impl_window->current_paint.surface, blend_region); cairo_region_destroy (opaque_region); cairo_region_destroy (blend_region); } glBindTexture (GL_TEXTURE_2D, source); glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texture_width); glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texture_height); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glEnable (GL_SCISSOR_TEST); gdk_window_get_unscaled_size (impl_window, NULL, &unscaled_window_height); #define FLIP_Y(_y) (unscaled_window_height - (_y)) cairo_region_get_extents (clip_region, &clip_rect); glScissor (clip_rect.x * window_scale, FLIP_Y ((clip_rect.y + clip_rect.height) * window_scale), clip_rect.width * window_scale, clip_rect.height * window_scale); n_quads = 0; n_rects = cairo_region_num_rectangles (clip_region); quads = g_new (GdkTexturedQuad, n_rects); for (i = 0; i < n_rects; i++) { cairo_rectangle_int_t dest; cairo_region_get_rectangle (clip_region, i, &clip_rect); clip_rect.x *= window_scale; clip_rect.y *= window_scale; clip_rect.width *= window_scale; clip_rect.height *= window_scale; dest.x = dx * window_scale; dest.y = dy * window_scale; dest.width = width * window_scale / buffer_scale; dest.height = height * window_scale / buffer_scale; if (gdk_rectangle_intersect (&clip_rect, &dest, &dest)) { int clipped_src_x = x + (dest.x - dx * window_scale); int clipped_src_y = y + (height - dest.height - (dest.y - dy * window_scale)); GdkTexturedQuad quad = { dest.x, FLIP_Y(dest.y), dest.x + dest.width, FLIP_Y(dest.y + dest.height), clipped_src_x / (float)texture_width, (clipped_src_y + dest.height) / (float)texture_height, (clipped_src_x + dest.width) / (float)texture_width, clipped_src_y / (float)texture_height, }; quads[n_quads++] = quad; if (impl_window->current_paint.flushed_region) { cairo_rectangle_int_t flushed_rect; flushed_rect.x = dest.x / window_scale; flushed_rect.y = dest.y / window_scale; flushed_rect.width = (dest.x + dest.width + window_scale - 1) / window_scale - flushed_rect.x; flushed_rect.height = (dest.y + dest.height + window_scale - 1) / window_scale - flushed_rect.y; cairo_region_union_rectangle (impl_window->current_paint.flushed_region, &flushed_rect); cairo_region_subtract_rectangle (impl_window->current_paint.need_blend_region, &flushed_rect); } } } if (n_quads > 0) gdk_gl_texture_quads (paint_context, GL_TEXTURE_2D, n_quads, quads); g_free (quads); if (alpha_size != 0) glDisable (GL_BLEND); #undef FLIP_Y } else { /* Software fallback */ /* TODO: avoid reading back non-required data due to dest clip */ image = cairo_surface_create_similar_image (cairo_get_target (cr), (alpha_size == 0) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32, width, height); cairo_surface_set_device_scale (image, buffer_scale, buffer_scale); framebuffer = paint_data->tmp_framebuffer; glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, framebuffer); if (source_type == GL_RENDERBUFFER) { /* Create a framebuffer with the source renderbuffer and make it the current target for reads */ glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, source); } else { glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, source, 0); } glPixelStorei (GL_PACK_ALIGNMENT, 4); glPixelStorei (GL_PACK_ROW_LENGTH, cairo_image_surface_get_stride (image) / 4); glReadPixels (x, y, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, cairo_image_surface_get_data (image)); glPixelStorei (GL_PACK_ROW_LENGTH, 0); glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); cairo_surface_mark_dirty (image); /* Invert due to opengl having different origin */ cairo_scale (cr, 1, -1); cairo_translate (cr, 0, -height / buffer_scale); cairo_set_source_surface (cr, image, 0, 0); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_paint (cr); cairo_surface_destroy (image); } if (clip_region) cairo_region_destroy (clip_region); }