static cairo_test_status_t draw (cairo_t *cr, int width, int height) { cairo_surface_t *surface; cairo_surface_t *image; cairo_surface_t *subimage; cairo_rectangle_int_t extents; cairo_t *cr2; extents.x = extents.y = 10; extents.width = WIDTH - 20; extents.height = HEIGHT - 20; /* We use a similar surface to have way smaller ref images */ surface = cairo_surface_create_similar (cairo_get_target (cr), CAIRO_CONTENT_COLOR_ALPHA, WIDTH, HEIGHT); /* First we have to defeat xcb's deferred clear */ cr2 = cairo_create (surface); cairo_test_paint_checkered (cr2); cairo_destroy (cr2); /* Get us an image surface with a non-natural stride */ image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT); subimage = cairo_surface_map_to_image (image, &extents); /* Paint the subimage to the similar surface and trigger the big upload */ cr2 = cairo_create (surface); cairo_set_source_surface (cr2, subimage, 0, 0); cairo_paint (cr2); cairo_destroy (cr2); /* Finally we make sure that errors aren't lost. */ cairo_surface_unmap_image (image, subimage); cairo_set_source_surface (cr, surface, 0, 0); cairo_paint (cr); cairo_surface_destroy (image); cairo_surface_destroy (surface); return CAIRO_TEST_SUCCESS; }
static int map_to_image(lua_State *L) { cairo_rectangle_int_t rect; cairo_rectangle_int_t *prect; cairo_surface_t **obj = luaL_checkudata(L, 1, OOCAIRO_MT_NAME_SURFACE); cairo_surface_t **res; lua_settop(L, 2); if (lua_isnil(L, 2)) { prect = NULL; } else { prect = ▭ from_lua_rectangle(L, prect, 2); } res = create_surface_userdata(L); *res = cairo_surface_map_to_image(*obj, prect); return 1; }
/* * If we ever support GL/D3D surfaces, we will have to * filter on these surface types * For now, everything is CPU-rendered, so map_to_image * will give us the best possible backend for our blur */ void eventd_nd_draw_blur_surface(cairo_t *cr, gint blur) { cairo_surface_t *target, *surface; target = cairo_get_target(cr); surface = cairo_surface_map_to_image(target, NULL); if ( cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS ) return; gint width, height, stride, channels; guint8 *data, *tmp; switch ( cairo_image_surface_get_format(surface) ) { case CAIRO_FORMAT_ARGB32: case CAIRO_FORMAT_RGB24: channels = 4; break; case CAIRO_FORMAT_A8: channels = 1; break; default: goto fail; } width = cairo_image_surface_get_width(surface); height = cairo_image_surface_get_height(surface); data = cairo_image_surface_get_data(surface); stride = cairo_image_surface_get_stride(surface); tmp = g_alloca(stride * height * sizeof(guint8)); _eventd_nd_draw_blur_gauss(data, tmp, blur, 3 /* number of passes */, width, height, stride, channels); cairo_surface_mark_dirty(surface); fail: cairo_surface_unmap_image(target, surface); }
/* This is always called with the paint context current */ void gdk_gl_texture_from_surface (cairo_surface_t *surface, cairo_region_t *region) { GdkGLContext *paint_context; cairo_surface_t *image; double device_x_offset, device_y_offset; cairo_rectangle_int_t rect, e; int n_rects, i; GdkWindow *window; int unscaled_window_height; unsigned int texture_id; int window_scale; double sx, sy; float umax, vmax; gboolean use_texture_rectangle; guint target; paint_context = gdk_gl_context_get_current (); if ((_gdk_gl_flags & GDK_GL_SOFTWARE_DRAW_SURFACE) == 0 && paint_context && GDK_GL_CONTEXT_GET_CLASS (paint_context)->texture_from_surface && GDK_GL_CONTEXT_GET_CLASS (paint_context)->texture_from_surface (paint_context, surface, region)) return; /* Software fallback */ use_texture_rectangle = gdk_gl_context_use_texture_rectangle (paint_context); window = gdk_gl_context_get_window (paint_context); window_scale = gdk_window_get_scale_factor (window); gdk_window_get_unscaled_size (window, NULL, &unscaled_window_height); sx = sy = 1; cairo_surface_get_device_scale (window->current_paint.surface, &sx, &sy); cairo_surface_get_device_offset (surface, &device_x_offset, &device_y_offset); glGenTextures (1, &texture_id); if (use_texture_rectangle) target = GL_TEXTURE_RECTANGLE_ARB; else target = GL_TEXTURE_2D; glBindTexture (target, texture_id); glEnable (GL_SCISSOR_TEST); glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); n_rects = cairo_region_num_rectangles (region); #define FLIP_Y(_y) (unscaled_window_height - (_y)) for (i = 0; i < n_rects; i++) { cairo_region_get_rectangle (region, i, &rect); glScissor (rect.x * window_scale, FLIP_Y ((rect.y + rect.height) * window_scale), rect.width * window_scale, rect.height * window_scale); e = rect; e.x *= sx; e.y *= sy; e.x += (int)device_x_offset; e.y += (int)device_y_offset; e.width *= sx; e.height *= sy; image = cairo_surface_map_to_image (surface, &e); gdk_gl_context_upload_texture (paint_context, image, e.width, e.height, target); cairo_surface_unmap_image (surface, image); if (use_texture_rectangle) { umax = rect.width * sx; vmax = rect.height * sy; } else { umax = 1.0; vmax = 1.0; } { GdkTexturedQuad quad = { rect.x * window_scale, FLIP_Y(rect.y * window_scale), (rect.x + rect.width) * window_scale, FLIP_Y((rect.y + rect.height) * window_scale), 0, 0, umax, vmax, }; /* We don't want to combine the quads here, because they have different textures. * And we don't want to upload the unused source areas to make it one texture. */ gdk_gl_texture_quads (paint_context, target, 1, &quad); } } #undef FLIP_Y glDisable (GL_SCISSOR_TEST); glDeleteTextures (1, &texture_id); }