/* A convenience function for when one needs to coerce an image * surface to an alternate format. */ cairo_image_surface_t * _cairo_image_surface_clone (cairo_image_surface_t *surface, cairo_format_t format) { cairo_image_surface_t *clone; cairo_status_t status; cairo_t *cr; double x, y; clone = (cairo_image_surface_t *) cairo_image_surface_create (format, surface->width, surface->height); cairo_surface_get_device_offset (&surface->base, &x, &y); cairo_surface_set_device_offset (&clone->base, x, y); clone->transparency = CAIRO_IMAGE_UNKNOWN; /* XXX Use _cairo_surface_composite directly */ cr = cairo_create (&clone->base); cairo_set_source_surface (cr, &surface->base, 0, 0); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); status = cairo_status (cr); cairo_destroy (cr); if (status) { cairo_surface_destroy (&clone->base); return (cairo_image_surface_t *) _cairo_surface_create_in_error (status); } return clone; }
gfxPoint gfxASurface::GetDeviceOffset() const { gfxPoint pt; cairo_surface_get_device_offset(mSurface, &pt.x, &pt.y); return pt; }
static PyObject * surface_get_device_offset (PycairoSurface *o) { double x_offset, y_offset; cairo_surface_get_device_offset (o->surface, &x_offset, &y_offset); return Py_BuildValue("(dd)", x_offset, y_offset); }
already_AddRefed<gfxASurface> gfxContext::CurrentSurface(gfxFloat *dx, gfxFloat *dy) { cairo_surface_t *s = cairo_get_group_target(mCairo); if (s == mSurface->CairoSurface()) { if (dx && dy) cairo_surface_get_device_offset(s, dx, dy); gfxASurface *ret = mSurface; NS_ADDREF(ret); return ret; } if (dx && dy) cairo_surface_get_device_offset(s, dx, dy); return gfxASurface::Wrap(s); }
IoObject *IoCairoSurface_getDeviceOffset(IoCairoSurface *self, IoObject *locals, IoMessage *m) { double x = 0, y = 0; cairo_surface_get_device_offset(SURFACE(self), &x, &y); CHECK_STATUS(self); return IoSeq_newWithX_y_(IOSTATE, x, y); }
static cairo_test_status_t test_cairo_surface_get_device_offset (cairo_surface_t *surface) { double x, y; cairo_surface_get_device_offset (surface, &x, &y); return CAIRO_TEST_SUCCESS; }
static int surface_get_device_offset (lua_State *L) { cairo_surface_t **obj = luaL_checkudata(L, 1, OOCAIRO_MT_NAME_SURFACE); double x, y; cairo_surface_get_device_offset(*obj, &x, &y); lua_pushnumber(L, x); lua_pushnumber(L, y); return 2; }
static VALUE cr_surface_get_device_offset (VALUE self) { double x_offset, y_offset; cairo_surface_get_device_offset (_SELF, &x_offset, &y_offset); cr_surface_check_status (_SELF); return rb_ary_new3 (2, rb_float_new (x_offset), rb_float_new (y_offset)); }
static cairo_test_status_t draw (cairo_t *cr, int width, int height) { cairo_surface_t *group; double x, y; /* First paint background in blue. */ cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); cairo_paint (cr); /* Then clip so that the group surface ends up smaller than the * original surface. */ cairo_rectangle (cr, PAD, PAD, width - 2 * PAD, height - 2 * PAD); cairo_clip (cr); /* Paint the clipped region in red (which should all be overwritten later). */ cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); cairo_paint (cr); /* Redirect to a new group and get that surface. */ cairo_push_group (cr); group = cairo_get_group_target (cr); /* Then paint in green what we query the group surface size to be. */ cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); cairo_surface_get_device_offset (group, &x, &y); /* Or rather, we calculate the group surface size based on the * only thing we can query which is the device offset. Ideally, * the size would always be the minimal (width - 2 * PAD, height - * 2 * PAD) based on the clip. But currently, group targets are * created oversized for paginated surfaces, so we only subtract * anything from the size if there is a non-zero device offfset. * * The calculation below might also be less confusing if the sign * convention on the device offset were reversed, but it is what * it is. Oh well. */ cairo_rectangle (cr, -x, -y, width + 2 * x, height + 2 * y); cairo_fill (cr); /* Finish up the group painting. */ cairo_pop_group_to_source (cr); cairo_paint (cr); return CAIRO_TEST_SUCCESS; }
cairo_surface_t * Context::Surface::Cairo () { if (!surface) { surface = native->Cairo (); /* replace device offset */ if (!box.IsEmpty ()) { cairo_surface_get_device_offset (surface, &device_offset.x, &device_offset.y); cairo_surface_set_device_offset (surface, -box.x, -box.y); } } return cairo_surface_reference (surface); }
static SeedValue seed_cairo_surface_get_device_offset(SeedContext ctx, SeedObject this_object, SeedString property_name, SeedException *exception) { SeedValue offsets[2]; cairo_surface_t *surf; gdouble x, y; CHECK_THIS(); surf = seed_object_to_cairo_surface (ctx, this_object, exception); cairo_surface_get_device_offset (surf, &x, &y); offsets[0] = seed_value_from_double (ctx, x, exception); offsets[1] = seed_value_from_double (ctx, y, exception); return seed_make_array (ctx, offsets, 2, exception); }
/** * Try the direct path. * @return True if we took the direct path */ bool gfxXlibNativeRenderer::DrawDirect(gfxContext *ctx, nsIntSize size, PRUint32 flags, Screen *screen, Visual *visual) { cairo_t *cr = ctx->GetCairo(); /* Check that the target surface is an xlib surface. */ cairo_surface_t *target = cairo_get_group_target (cr); if (cairo_surface_get_type (target) != CAIRO_SURFACE_TYPE_XLIB) { NATIVE_DRAWING_NOTE("FALLBACK: non-X surface"); return false; } cairo_matrix_t matrix; cairo_get_matrix (cr, &matrix); double device_offset_x, device_offset_y; cairo_surface_get_device_offset (target, &device_offset_x, &device_offset_y); /* Draw() checked that the matrix contained only a very-close-to-integer translation. Here (and in several other places and thebes) device offsets are assumed to be integer. */ NS_ASSERTION(PRInt32(device_offset_x) == device_offset_x && PRInt32(device_offset_y) == device_offset_y, "Expected integer device offsets"); nsIntPoint offset(NS_lroundf(matrix.x0 + device_offset_x), NS_lroundf(matrix.y0 + device_offset_y)); int max_rectangles = 0; if (flags & DRAW_SUPPORTS_CLIP_RECT) { max_rectangles = 1; } if (flags & DRAW_SUPPORTS_CLIP_LIST) { max_rectangles = MAX_STATIC_CLIP_RECTANGLES; } /* The client won't draw outside the surface so consider this when analysing clip rectangles. */ nsIntRect bounds(offset, size); bounds.IntersectRect(bounds, nsIntRect(0, 0, cairo_xlib_surface_get_width(target), cairo_xlib_surface_get_height(target))); bool needs_clip = true; nsIntRect rectangles[MAX_STATIC_CLIP_RECTANGLES]; int rect_count = 0; /* Check that the clip is rectangular and aligned on unit boundaries. */ /* Temporarily set the matrix for _get_rectangular_clip. It's basically the identity matrix, but we must adjust for the fact that our offset-rect is in device coordinates. */ cairo_identity_matrix (cr); cairo_translate (cr, -device_offset_x, -device_offset_y); bool have_rectangular_clip = _get_rectangular_clip (cr, bounds, &needs_clip, rectangles, max_rectangles, &rect_count); cairo_set_matrix (cr, &matrix); if (!have_rectangular_clip) return false; /* Stop now if everything is clipped out */ if (needs_clip && rect_count == 0) return true; /* Check that the screen is supported. Visuals belong to screens, so, if alternate visuals are not supported, then alternate screens cannot be supported. */ bool supports_alternate_visual = (flags & DRAW_SUPPORTS_ALTERNATE_VISUAL) != 0; bool supports_alternate_screen = supports_alternate_visual && (flags & DRAW_SUPPORTS_ALTERNATE_SCREEN); if (!supports_alternate_screen && cairo_xlib_surface_get_screen (target) != screen) { NATIVE_DRAWING_NOTE("FALLBACK: non-default screen"); return false; } /* Check that there is a visual */ Visual *target_visual = cairo_xlib_surface_get_visual (target); if (!target_visual) { NATIVE_DRAWING_NOTE("FALLBACK: no Visual for surface"); return false; } /* Check that the visual is supported */ if (!supports_alternate_visual && target_visual != visual) { // Only the format of the visual is important (not the GLX properties) // for Xlib or XRender drawing. XRenderPictFormat *target_format = cairo_xlib_surface_get_xrender_format (target); if (!target_format || (target_format != XRenderFindVisualFormat (DisplayOfScreen(screen), visual))) { NATIVE_DRAWING_NOTE("FALLBACK: unsupported Visual"); return false; } } /* we're good to go! */ NATIVE_DRAWING_NOTE("TAKING FAST PATH\n"); cairo_surface_flush (target); nsRefPtr<gfxASurface> surface = gfxASurface::Wrap(target); nsresult rv = DrawWithXlib(static_cast<gfxXlibSurface*>(surface.get()), offset, rectangles, needs_clip ? rect_count : 0); if (NS_SUCCEEDED(rv)) { cairo_surface_mark_dirty (target); return true; } return false; }
/* 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); }
/** * Try the direct path. * @param status the status returned by the callback, if we took the direct path * @return True if we took the direct path */ static cairo_bool_t _draw_with_xlib_direct (cairo_t *cr, Display *default_display, cairo_xlib_drawing_callback callback, void *closure, int bounds_width, int bounds_height, cairo_xlib_drawing_support_t capabilities) { cairo_surface_t *target; Drawable d; cairo_matrix_t matrix; short offset_x, offset_y; cairo_bool_t needs_clip; XRectangle rectangles[MAX_STATIC_CLIP_RECTANGLES]; int rect_count; double device_offset_x, device_offset_y; int max_rectangles; Screen *screen; Visual *visual; cairo_bool_t have_rectangular_clip; target = cairo_get_group_target (cr); cairo_surface_get_device_offset (target, &device_offset_x, &device_offset_y); d = cairo_xlib_surface_get_drawable (target); cairo_get_matrix (cr, &matrix); /* Check that the matrix is a pure translation */ /* XXX test some approximation to == 1.0 here? */ if (matrix.xx != 1.0 || matrix.yy != 1.0 || matrix.xy != 0.0 || matrix.yx != 0.0) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: matrix not a pure translation\n"); return False; } /* Check that the matrix translation offsets (adjusted for device offset) are integers */ if (!_convert_coord_to_short (matrix.x0 + device_offset_x, &offset_x) || !_convert_coord_to_short (matrix.y0 + device_offset_y, &offset_y)) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: non-integer offset\n"); return False; } max_rectangles = 0; if (capabilities & CAIRO_XLIB_DRAWING_SUPPORTS_CLIP_RECT) { max_rectangles = 1; } if (capabilities & CAIRO_XLIB_DRAWING_SUPPORTS_CLIP_LIST) { max_rectangles = MAX_STATIC_CLIP_RECTANGLES; } /* Check that the clip is rectangular and aligned on unit boundaries. */ /* Temporarily set the matrix for _get_rectangular_clip. It's basically the identity matrix, but we must adjust for the fact that our offset-rect is in device coordinates. */ cairo_identity_matrix (cr); cairo_translate (cr, -device_offset_x, -device_offset_y); have_rectangular_clip = _get_rectangular_clip (cr, offset_x, offset_y, bounds_width, bounds_height, &needs_clip, rectangles, max_rectangles, &rect_count); cairo_set_matrix (cr, &matrix); if (!have_rectangular_clip) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: unsupported clip\n"); return False; } /* Stop now if everything is clipped out */ if (needs_clip && rect_count == 0) { CAIRO_XLIB_DRAWING_NOTE("TAKING FAST PATH: all clipped\n"); return True; } /* Check that the operator is OVER */ if (cairo_get_operator (cr) != CAIRO_OPERATOR_OVER) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: non-OVER operator\n"); return False; } /* Check that the offset is supported */ if (!(capabilities & CAIRO_XLIB_DRAWING_SUPPORTS_OFFSET) && (offset_x != 0 || offset_y != 0)) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: unsupported offset\n"); return False; } /* Check that the target surface is an xlib surface. Do this late because we might complete early above when when the object to be drawn is completely clipped out. */ if (!d) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: non-X surface\n"); return False; } /* Check that the display is supported */ screen = cairo_xlib_surface_get_screen (target); if (!(capabilities & CAIRO_XLIB_DRAWING_SUPPORTS_ALTERNATE_SCREEN) && screen != DefaultScreenOfDisplay (default_display)) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: non-default display\n"); return False; } /* Check that there is a visual */ visual = cairo_xlib_surface_get_visual (target); if (!visual) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: no Visual for surface\n"); return False; } /* Check that the visual is supported */ if (!(capabilities & CAIRO_XLIB_DRAWING_SUPPORTS_NONDEFAULT_VISUAL) && DefaultVisualOfScreen (screen) != visual) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: non-default visual\n"); return False; } /* we're good to go! */ CAIRO_XLIB_DRAWING_NOTE("TAKING FAST PATH\n"); cairo_surface_flush (target); callback (closure, screen, d, visual, offset_x, offset_y, rectangles, needs_clip ? rect_count : 0); cairo_surface_mark_dirty (target); return True; }