[cairo-commit] 16 commits - cairo-version.h src/cairo-clip-surface.c src/cairo-default-context.c src/cairo-gl-traps-compositor.c src/cairo-gstate.c src/cairo.h src/cairo-image-source.c src/cairoint.h src/cairo-mask-compositor.c src/cairo-paginated-surface.c src/cairo-pattern.c src/cairo-pattern-private.h src/cairo-shape-mask-compositor.c src/cairo-spans-compositor.c src/cairo-surface.c src/cairo-surface-subsurface.c src/cairo-surface-wrapper.c src/cairo-traps-compositor.c src/cairo-xcb-surface-render.c src/cairo-xlib-source.c test/cairo-test.c test/cairo-test-private.h test/cairo-test-runner.c util/cairo-script util/cairo-trace
Chris Wilson
ickle at kemper.freedesktop.org
Thu Sep 5 08:16:47 PDT 2013
cairo-version.h | 4
src/cairo-clip-surface.c | 20 +-
src/cairo-default-context.c | 37 ++---
src/cairo-gl-traps-compositor.c | 18 +-
src/cairo-gstate.c | 25 ++-
src/cairo-image-source.c | 65 ++++++++-
src/cairo-mask-compositor.c | 14 +-
src/cairo-paginated-surface.c | 2
src/cairo-pattern-private.h | 4
src/cairo-pattern.c | 10 +
src/cairo-shape-mask-compositor.c | 27 ++-
src/cairo-spans-compositor.c | 23 ++-
src/cairo-surface-subsurface.c | 30 +++-
src/cairo-surface-wrapper.c | 9 -
src/cairo-surface.c | 198 ++++++++++++++++-------------
src/cairo-traps-compositor.c | 48 ++++---
src/cairo-xcb-surface-render.c | 20 +-
src/cairo-xlib-source.c | 36 ++---
src/cairo.h | 10 +
src/cairoint.h | 23 +--
test/cairo-test-private.h | 2
test/cairo-test-runner.c | 88 +++++++-----
test/cairo-test.c | 66 +++++----
util/cairo-script/cairo-script-operators.c | 48 +++++++
util/cairo-trace/trace.c | 12 +
25 files changed, 539 insertions(+), 300 deletions(-)
New commits:
commit 0266cb821fbf0bdd307af7bbcbbd22c4a14201fc
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Thu Sep 5 16:13:56 2013 +0100
script: Add support for replaying device-scale
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index d423fe5..aae6bea 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -4850,6 +4850,30 @@ _set_device_offset (csi_t *ctx)
}
static csi_status_t
+_set_device_scale (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_surface_t *surface;
+ double x, y;
+
+ check (3);
+
+ status = _csi_ostack_get_number (ctx, 0, &y);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &x);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_surface (ctx, 2, &surface);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_surface_set_device_scale (surface, x, y);
+ pop (2);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
_set_extend (csi_t *ctx)
{
csi_status_t status;
@@ -6103,6 +6127,29 @@ _surface (csi_t *ctx)
}
}
+ status = csi_name_new_static (ctx, &key, "device-scale");
+ if (_csi_unlikely (status)) {
+ cairo_surface_destroy (surface);
+ return status;
+ }
+ if (csi_dictionary_has (dict, key.datum.name)) {
+ status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) {
+ csi_array_t *array = obj.datum.array;
+
+ if (array->stack.len == 2) {
+ cairo_surface_set_device_scale (surface,
+ csi_number_get_value
+ (&array->stack.objects[0]),
+ csi_number_get_value
+ (&array->stack.objects[1]));
+ }
+ }
+ }
+
obj.type = CSI_OBJECT_TYPE_SURFACE;
obj.datum.surface = surface;
pop (1);
@@ -6539,6 +6586,7 @@ _defs[] = {
{ "set-antialias", _set_antialias },
{ "set-dash", _set_dash },
{ "set-device-offset", _set_device_offset },
+ { "set-device-scale", _set_device_scale },
{ "set-extend", _set_extend },
{ "set-fallback-resolution", _set_fallback_resolution },
{ "set-fill-rule", _set_fill_rule },
commit a4164142f2a21fb005533d1c5b3cf668c99d1259
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Thu Sep 5 16:12:26 2013 +0100
trace: Record set-device-scale
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 085059f..05e97d2 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -3884,6 +3884,18 @@ cairo_surface_set_device_offset (cairo_surface_t *surface, double x_offset, doub
}
void
+cairo_surface_set_device_scale (cairo_surface_t *surface, double x_offset, double y_offset)
+{
+ _enter_trace ();
+ _emit_line_info ();
+ _emit_surface_op (surface, "%g %g set-device-scale\n",
+ x_offset, y_offset);
+ DLCALL (cairo_surface_set_device_scale, surface, x_offset, y_offset);
+ _exit_trace ();
+}
+
+
+void
cairo_surface_set_fallback_resolution (cairo_surface_t *surface, double x_pixels_per_inch, double y_pixels_per_inch)
{
_enter_trace ();
commit 935c64a43409a80d9b19d491f9133004152de9bb
Author: Alexander Larsson <alexl at redhat.com>
Date: Tue Aug 27 15:10:38 2013 +0200
surface: Inherit device scale in cairo_surface_create_similar()
Without this most code that uses similar surfaces for offscreen
rendering will render in a pixelized fashion if the final
target uses a device scale.
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index cdd75b8..f2f2ef6 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -507,6 +507,10 @@ cairo_surface_create_similar (cairo_surface_t *other,
if (unlikely (other->status))
return _cairo_surface_create_in_error (other->status);
+ /* We inherit the device scale, so create a larger surface */
+ width = width * other->device_transform.xx;
+ height = height * other->device_transform.yy;
+
surface = NULL;
if (other->backend->create_similar)
surface = other->backend->create_similar (other, content, width, height);
@@ -519,6 +523,9 @@ cairo_surface_create_similar (cairo_surface_t *other,
return surface;
_cairo_surface_copy_similar_properties (surface, other);
+ cairo_surface_set_device_scale (surface,
+ other->device_transform.xx,
+ other->device_transform.yy);
if (unlikely (surface->status))
return surface;
commit bc792a5e0e196dd9761649b14c9206465b42ef1d
Author: Alexander Larsson <alexl at redhat.com>
Date: Tue Aug 27 14:46:16 2013 +0200
surface: Merge scratch construction into _cairo_surface_create_scratch
We merge _cairo_surface_create_similar_scratch and
_cairo_surface_create_similar_solid into a single function named
_cairo_surface_create_scratch, to avoid confusion with
cairo_surface_create_similar which now will have a different
behaviour wrt the sizes and the device-scale.
_create_scratch assumes the width and height are in backend
coordinates, while create_similar does not.
diff --git a/src/cairo-clip-surface.c b/src/cairo-clip-surface.c
index fff9724..85feaa6 100644
--- a/src/cairo-clip-surface.c
+++ b/src/cairo-clip-surface.c
@@ -132,11 +132,11 @@ _cairo_clip_get_surface (const cairo_clip_t *clip,
cairo_path_fixed_t path;
int i;
- surface = _cairo_surface_create_similar_solid (target,
- CAIRO_CONTENT_ALPHA,
- clip->extents.width,
- clip->extents.height,
- CAIRO_COLOR_TRANSPARENT);
+ surface = _cairo_surface_create_scratch (target,
+ CAIRO_CONTENT_ALPHA,
+ clip->extents.width,
+ clip->extents.height,
+ CAIRO_COLOR_TRANSPARENT);
if (unlikely (surface->status))
return surface;
@@ -162,11 +162,11 @@ _cairo_clip_get_surface (const cairo_clip_t *clip,
return _cairo_surface_create_in_error (status);
}
} else {
- surface = _cairo_surface_create_similar_solid (target,
- CAIRO_CONTENT_ALPHA,
- clip->extents.width,
- clip->extents.height,
- CAIRO_COLOR_WHITE);
+ surface = _cairo_surface_create_scratch (target,
+ CAIRO_CONTENT_ALPHA,
+ clip->extents.width,
+ clip->extents.height,
+ CAIRO_COLOR_WHITE);
if (unlikely (surface->status))
return surface;
}
diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
index 8964244..1e5067b 100644
--- a/src/cairo-default-context.c
+++ b/src/cairo-default-context.c
@@ -170,11 +170,11 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
group_surface = cairo_recording_surface_create (content, NULL);
extents.x = extents.y = 0;
} else {
- group_surface = _cairo_surface_create_similar_solid (parent_surface,
- content,
- extents.width,
- extents.height,
- CAIRO_COLOR_TRANSPARENT);
+ group_surface = _cairo_surface_create_scratch (parent_surface,
+ content,
+ extents.width,
+ extents.height,
+ CAIRO_COLOR_TRANSPARENT);
}
status = group_surface->status;
if (unlikely (status))
diff --git a/src/cairo-gl-traps-compositor.c b/src/cairo-gl-traps-compositor.c
index ec478ee..125ed4e 100644
--- a/src/cairo-gl-traps-compositor.c
+++ b/src/cairo-gl-traps-compositor.c
@@ -333,10 +333,11 @@ traps_to_operand (void *_dst,
}
}
- mask = _cairo_surface_create_similar_scratch (_dst,
- CAIRO_CONTENT_COLOR_ALPHA,
- extents->width,
- extents->height);
+ mask = _cairo_surface_create_scratch (_dst,
+ CAIRO_CONTENT_COLOR_ALPHA,
+ extents->width,
+ extents->height,
+ NULL);
if (unlikely (mask->status)) {
cairo_surface_destroy (image);
return mask->status;
@@ -445,10 +446,11 @@ tristrip_to_surface (void *_dst,
return (cairo_gl_surface_t *)image;
}
- mask = _cairo_surface_create_similar_scratch (_dst,
- CAIRO_CONTENT_COLOR_ALPHA,
- extents->width,
- extents->height);
+ mask = _cairo_surface_create_scratch (_dst,
+ CAIRO_CONTENT_COLOR_ALPHA,
+ extents->width,
+ extents->height,
+ NULL);
if (unlikely (mask->status)) {
cairo_surface_destroy (image);
return (cairo_gl_surface_t *)mask;
diff --git a/src/cairo-mask-compositor.c b/src/cairo-mask-compositor.c
index d0be144..4d6b118 100644
--- a/src/cairo-mask-compositor.c
+++ b/src/cairo-mask-compositor.c
@@ -163,9 +163,10 @@ create_composite_mask (const cairo_mask_compositor_t *compositor,
struct blt_in info;
int i;
- surface = _cairo_surface_create_similar_scratch (dst, CAIRO_CONTENT_ALPHA,
- extents->bounded.width,
- extents->bounded.height);
+ surface = _cairo_surface_create_scratch (dst, CAIRO_CONTENT_ALPHA,
+ extents->bounded.width,
+ extents->bounded.height,
+ NULL);
if (unlikely (surface->status))
return surface;
@@ -346,9 +347,10 @@ clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
cairo_status_t status;
int clip_x, clip_y;
- tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
- extents->bounded.width,
- extents->bounded.height);
+ tmp = _cairo_surface_create_scratch (dst, dst->content,
+ extents->bounded.width,
+ extents->bounded.height,
+ NULL);
if (unlikely (tmp->status))
return tmp->status;
diff --git a/src/cairo-shape-mask-compositor.c b/src/cairo-shape-mask-compositor.c
index c2425b0..3117267 100644
--- a/src/cairo-shape-mask-compositor.c
+++ b/src/cairo-shape-mask-compositor.c
@@ -62,10 +62,11 @@ _cairo_shape_mask_compositor_stroke (const cairo_compositor_t *_compositor,
return CAIRO_INT_STATUS_UNSUPPORTED;
TRACE ((stderr, "%s\n", __FUNCTION__));
- mask = _cairo_surface_create_similar_scratch (extents->surface,
- CAIRO_CONTENT_ALPHA,
- extents->bounded.width,
- extents->bounded.height);
+ mask = _cairo_surface_create_scratch (extents->surface,
+ CAIRO_CONTENT_ALPHA,
+ extents->bounded.width,
+ extents->bounded.height,
+ NULL);
if (unlikely (mask->status))
return mask->status;
@@ -156,10 +157,11 @@ _cairo_shape_mask_compositor_fill (const cairo_compositor_t *_compositor,
if (! extents->is_bounded)
return CAIRO_INT_STATUS_UNSUPPORTED;
- mask = _cairo_surface_create_similar_scratch (extents->surface,
- CAIRO_CONTENT_ALPHA,
- extents->bounded.width,
- extents->bounded.height);
+ mask = _cairo_surface_create_scratch (extents->surface,
+ CAIRO_CONTENT_ALPHA,
+ extents->bounded.width,
+ extents->bounded.height,
+ NULL);
if (unlikely (mask->status))
return mask->status;
@@ -248,10 +250,11 @@ _cairo_shape_mask_compositor_glyphs (const cairo_compositor_t *_compositor,
return CAIRO_INT_STATUS_UNSUPPORTED;
TRACE ((stderr, "%s\n", __FUNCTION__));
- mask = _cairo_surface_create_similar_scratch (extents->surface,
- CAIRO_CONTENT_ALPHA,
- extents->bounded.width,
- extents->bounded.height);
+ mask = _cairo_surface_create_scratch (extents->surface,
+ CAIRO_CONTENT_ALPHA,
+ extents->bounded.width,
+ extents->bounded.height,
+ NULL);
if (unlikely (mask->status))
return mask->status;
diff --git a/src/cairo-spans-compositor.c b/src/cairo-spans-compositor.c
index 1a46ea3..efbae25 100644
--- a/src/cairo-spans-compositor.c
+++ b/src/cairo-spans-compositor.c
@@ -95,11 +95,11 @@ get_clip_surface (const cairo_spans_compositor_t *compositor,
assert (clip->path);
- surface = _cairo_surface_create_similar_solid (dst,
- CAIRO_CONTENT_ALPHA,
- extents->width,
- extents->height,
- CAIRO_COLOR_TRANSPARENT);
+ surface = _cairo_surface_create_scratch (dst,
+ CAIRO_CONTENT_ALPHA,
+ extents->width,
+ extents->height,
+ CAIRO_COLOR_TRANSPARENT);
_cairo_box_from_rectangle (&box, extents);
_cairo_polygon_init (&polygon, &box, 1);
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 0efb963..b7dfd9d 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -351,10 +351,11 @@ _cairo_surface_subsurface_snapshot (void *abstract_surface)
TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, surface->target->unique_id));
- clone = _cairo_surface_create_similar_scratch (surface->target,
- surface->target->content,
- surface->extents.width,
- surface->extents.height);
+ clone = _cairo_surface_create_scratch (surface->target,
+ surface->target->content,
+ surface->extents.width,
+ surface->extents.height,
+ NULL);
if (unlikely (clone->status))
return clone;
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index 030de67..9236c8b 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -513,8 +513,8 @@ _cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
int width,
int height)
{
- return _cairo_surface_create_similar_scratch (wrapper->target,
- content, width, height);
+ return _cairo_surface_create_scratch (wrapper->target,
+ content, width, height, NULL);
}
cairo_bool_t
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 9caacbb..cdd75b8 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -454,33 +454,6 @@ _cairo_surface_copy_similar_properties (cairo_surface_t *surface,
other->y_fallback_resolution);
}
-cairo_surface_t *
-_cairo_surface_create_similar_scratch (cairo_surface_t *other,
- cairo_content_t content,
- int width,
- int height)
-{
- cairo_surface_t *surface;
-
- if (unlikely (other->status))
- return _cairo_surface_create_in_error (other->status);
-
- surface = NULL;
- if (other->backend->create_similar)
- surface = other->backend->create_similar (other, content, width, height);
- if (surface == NULL)
- surface = cairo_surface_create_similar_image (other,
- _cairo_format_from_content (content),
- width, height);
-
- if (unlikely (surface->status))
- return surface;
-
- _cairo_surface_copy_similar_properties (surface, other);
-
- return surface;
-}
-
/**
* cairo_surface_create_similar:
* @other: an existing surface used to select the backend of the new surface
@@ -879,29 +852,45 @@ error:
}
cairo_surface_t *
-_cairo_surface_create_similar_solid (cairo_surface_t *other,
- cairo_content_t content,
- int width,
- int height,
- const cairo_color_t *color)
+_cairo_surface_create_scratch (cairo_surface_t *other,
+ cairo_content_t content,
+ int width,
+ int height,
+ const cairo_color_t *color)
{
- cairo_status_t status;
cairo_surface_t *surface;
+ cairo_status_t status;
cairo_solid_pattern_t pattern;
- surface = _cairo_surface_create_similar_scratch (other, content,
- width, height);
+ if (unlikely (other->status))
+ return _cairo_surface_create_in_error (other->status);
+
+ surface = NULL;
+ if (other->backend->create_similar)
+ surface = other->backend->create_similar (other, content, width, height);
+ if (surface == NULL)
+ surface = cairo_surface_create_similar_image (other,
+ _cairo_format_from_content (content),
+ width, height);
+
if (unlikely (surface->status))
return surface;
- _cairo_pattern_init_solid (&pattern, color);
- status = _cairo_surface_paint (surface,
- color == CAIRO_COLOR_TRANSPARENT ?
- CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
- &pattern.base, NULL);
- if (unlikely (status)) {
- cairo_surface_destroy (surface);
- surface = _cairo_surface_create_in_error (status);
+ _cairo_surface_copy_similar_properties (surface, other);
+
+ if (unlikely (surface->status))
+ return surface;
+
+ if (color) {
+ _cairo_pattern_init_solid (&pattern, color);
+ status = _cairo_surface_paint (surface,
+ color == CAIRO_COLOR_TRANSPARENT ?
+ CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
+ &pattern.base, NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (surface);
+ surface = _cairo_surface_create_in_error (status);
+ }
}
return surface;
diff --git a/src/cairo-traps-compositor.c b/src/cairo-traps-compositor.c
index 631e172..8d67965 100644
--- a/src/cairo-traps-compositor.c
+++ b/src/cairo-traps-compositor.c
@@ -307,10 +307,11 @@ __clip_to_surface (const cairo_traps_compositor_t *compositor,
if (unlikely (status))
return status;
- mask = _cairo_surface_create_similar_scratch (composite->surface,
- CAIRO_CONTENT_ALPHA,
- extents->width,
- extents->height);
+ mask = _cairo_surface_create_scratch (composite->surface,
+ CAIRO_CONTENT_ALPHA,
+ extents->width,
+ extents->height,
+ NULL);
if (unlikely (mask->status)) {
_cairo_traps_fini (&traps);
return status;
@@ -371,11 +372,11 @@ traps_get_clip_surface (const cairo_traps_compositor_t *compositor,
status = __clip_to_surface (compositor, composite, extents, &surface);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- surface = _cairo_surface_create_similar_solid (composite->surface,
- CAIRO_CONTENT_ALPHA,
- extents->width,
- extents->height,
- CAIRO_COLOR_WHITE);
+ surface = _cairo_surface_create_scratch (composite->surface,
+ CAIRO_CONTENT_ALPHA,
+ extents->width,
+ extents->height,
+ CAIRO_COLOR_WHITE);
if (unlikely (surface->status))
return surface;
@@ -430,9 +431,10 @@ create_composite_mask (const cairo_traps_compositor_t *compositor,
TRACE ((stderr, "%s\n", __FUNCTION__));
- surface = _cairo_surface_create_similar_scratch (dst, CAIRO_CONTENT_ALPHA,
- extents->bounded.width,
- extents->bounded.height);
+ surface = _cairo_surface_create_scratch (dst, CAIRO_CONTENT_ALPHA,
+ extents->bounded.width,
+ extents->bounded.height,
+ NULL);
if (unlikely (surface->status))
return surface;
@@ -590,9 +592,10 @@ clip_and_composite_combine (const cairo_traps_compositor_t *compositor,
TRACE ((stderr, "%s\n", __FUNCTION__));
- tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
- extents->bounded.width,
- extents->bounded.height);
+ tmp = _cairo_surface_create_scratch (dst, dst->content,
+ extents->bounded.width,
+ extents->bounded.height,
+ NULL);
if (unlikely (tmp->status))
return tmp->status;
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 2d52be9..99efe87 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -1101,11 +1101,11 @@ record_to_picture (cairo_surface_t *target,
return _cairo_xcb_transparent_picture ((cairo_xcb_surface_t *) target);
/* Now draw the recording surface to an xcb surface */
- tmp = _cairo_surface_create_similar_solid (target,
- source->content,
- limit.width,
- limit.height,
- CAIRO_COLOR_TRANSPARENT);
+ tmp = _cairo_surface_create_scratch (target,
+ source->content,
+ limit.width,
+ limit.height,
+ CAIRO_COLOR_TRANSPARENT);
if (tmp->status != CAIRO_STATUS_SUCCESS) {
return (cairo_xcb_picture_t *) tmp;
}
@@ -1693,11 +1693,11 @@ get_clip_surface (const cairo_clip_t *clip,
cairo_surface_t *surface;
cairo_status_t status;
- surface = _cairo_surface_create_similar_solid (&target->base,
- CAIRO_CONTENT_ALPHA,
- clip->extents.width,
- clip->extents.height,
- CAIRO_COLOR_WHITE);
+ surface = _cairo_surface_create_scratch (&target->base,
+ CAIRO_CONTENT_ALPHA,
+ clip->extents.width,
+ clip->extents.height,
+ CAIRO_COLOR_WHITE);
if (unlikely (surface->status))
return (cairo_xcb_surface_t *) surface;
diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c
index 746001e..8275da3 100644
--- a/src/cairo-xlib-source.c
+++ b/src/cairo-xlib-source.c
@@ -288,10 +288,11 @@ render_pattern (cairo_xlib_surface_t *dst,
cairo_rectangle_int_t map_extents;
src = (cairo_xlib_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
- is_mask ? CAIRO_CONTENT_ALPHA : CAIRO_CONTENT_COLOR_ALPHA,
- extents->width,
- extents->height);
+ _cairo_surface_create_scratch (&dst->base,
+ is_mask ? CAIRO_CONTENT_ALPHA : CAIRO_CONTENT_COLOR_ALPHA,
+ extents->width,
+ extents->height,
+ NULL);
if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
cairo_surface_destroy (&src->base);
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
@@ -750,10 +751,11 @@ subsurface_source (cairo_xlib_surface_t *dst,
source = &src->embedded_source;
} else {
src = (cairo_xlib_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
- sub->base.content,
- sub->extents.width,
- sub->extents.height);
+ _cairo_surface_create_scratch (&dst->base,
+ sub->base.content,
+ sub->extents.width,
+ sub->extents.height,
+ NULL);
if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
cairo_surface_destroy (&src->base);
return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
@@ -898,10 +900,11 @@ record_source (cairo_xlib_surface_t *dst,
}
src = (cairo_xlib_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
- pattern->surface->content,
- upload.width,
- upload.height);
+ _cairo_surface_create_scratch (&dst->base,
+ pattern->surface->content,
+ upload.width,
+ upload.height,
+ NULL);
if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
cairo_surface_destroy (&src->base);
return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
@@ -1001,10 +1004,11 @@ surface_source (cairo_xlib_surface_t *dst,
}
xsrc = (cairo_xlib_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
- src->content,
- upload.width,
- upload.height);
+ _cairo_surface_create_scratch (&dst->base,
+ src->content,
+ upload.width,
+ upload.height,
+ NULL);
if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
cairo_surface_destroy (src);
cairo_surface_destroy (&xsrc->base);
diff --git a/src/cairoint.h b/src/cairoint.h
index 84e6026..d31e07b 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1288,21 +1288,15 @@ _cairo_surface_set_resolution (cairo_surface_t *surface,
double y_res);
cairo_private cairo_surface_t *
-_cairo_surface_create_similar_scratch (cairo_surface_t *other,
- cairo_content_t content,
- int width,
- int height);
-
-cairo_private cairo_surface_t *
_cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
const cairo_rectangle_int_t *extents);
cairo_private cairo_surface_t *
-_cairo_surface_create_similar_solid (cairo_surface_t *other,
- cairo_content_t content,
- int width,
- int height,
- const cairo_color_t *color);
+_cairo_surface_create_scratch (cairo_surface_t *other,
+ cairo_content_t content,
+ int width,
+ int height,
+ const cairo_color_t *color);
cairo_private void
_cairo_surface_init (cairo_surface_t *surface,
commit bdccf4fe51bca785f73205ccd26c4d020669e312
Author: Alexander Larsson <alexl at redhat.com>
Date: Tue Aug 27 14:33:14 2013 +0200
surface: Opencode create_similar
We copy the _cairo_surface_create_similar_solid code into
cairo_surface_create_similar so that we can separate these later
as one wants to use backend sizes and one not.
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index f07a0f6..9caacbb 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -518,6 +518,8 @@ cairo_surface_create_similar (cairo_surface_t *other,
int height)
{
cairo_surface_t *surface;
+ cairo_status_t status;
+ cairo_solid_pattern_t pattern;
if (unlikely (other->status))
return _cairo_surface_create_in_error (other->status);
@@ -529,9 +531,34 @@ cairo_surface_create_similar (cairo_surface_t *other,
if (unlikely (! CAIRO_CONTENT_VALID (content)))
return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT);
- surface = _cairo_surface_create_similar_solid (other,
- content, width, height,
- CAIRO_COLOR_TRANSPARENT);
+ if (unlikely (other->status))
+ return _cairo_surface_create_in_error (other->status);
+
+ surface = NULL;
+ if (other->backend->create_similar)
+ surface = other->backend->create_similar (other, content, width, height);
+ if (surface == NULL)
+ surface = cairo_surface_create_similar_image (other,
+ _cairo_format_from_content (content),
+ width, height);
+
+ if (unlikely (surface->status))
+ return surface;
+
+ _cairo_surface_copy_similar_properties (surface, other);
+
+ if (unlikely (surface->status))
+ return surface;
+
+ _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_TRANSPARENT);
+ status = _cairo_surface_paint (surface,
+ CAIRO_OPERATOR_CLEAR,
+ &pattern.base, NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (surface);
+ surface = _cairo_surface_create_in_error (status);
+ }
+
assert (surface->is_clear);
return surface;
commit 5f70148467ff2767dc3c6d45f4af1223d7daa301
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jun 3 15:20:05 2013 +0100
test: Allow CAIRO_TEST_MODE to independently enable extended testing
Such as CAIRO_TEST_MODE=scale for testing application of
cairo_surface_set_device_offset.
CAIRO_TEST_MODE=similar - test rendering through similar surfaces
CAIRO_TEST_MODE=offset - test rendering with a device offset
CAIRO_TEST_MODE=scale - test rendering with a device scale
diff --git a/test/cairo-test-runner.c b/test/cairo-test-runner.c
index 71107f3..3fb3ae5 100644
--- a/test/cairo-test-runner.c
+++ b/test/cairo-test-runner.c
@@ -358,7 +358,7 @@ _parse_cmdline (cairo_test_runner_t *runner, int *argc, char **argv[])
switch (c) {
case 'a':
- runner->full_test = TRUE;
+ runner->full_test = ~0;
break;
case 'f':
runner->foreground = TRUE;
@@ -691,6 +691,9 @@ _has_required_rsvg_version (const char *str)
return TRUE;
}
+#define TEST_SIMILAR 0x1
+#define TEST_OFFSET 0x2
+#define TEST_SCALE 0x4
int
main (int argc, char **argv)
{
@@ -722,7 +725,16 @@ main (int argc, char **argv)
const char *env = getenv ("CAIRO_TEST_MODE");
if (strstr (env, "full")) {
- runner.full_test = TRUE;
+ runner.full_test = ~0;
+ }
+ if (strstr (env, "similar")) {
+ runner.full_test |= TEST_SIMILAR;
+ }
+ if (strstr (env, "offset")) {
+ runner.full_test |= TEST_OFFSET;
+ }
+ if (strstr (env, "scale")) {
+ runner.full_test |= TEST_SCALE;
}
if (strstr (env, "foreground")) {
runner.foreground = TRUE;
@@ -743,8 +755,10 @@ main (int argc, char **argv)
cairo_tests_env = getenv("CAIRO_TESTS");
append_argv (&argc, &argv, cairo_tests_env);
- if (runner.full_test) {
+ if (runner.full_test & TEST_OFFSET) {
runner.num_device_offsets = 2;
+ }
+ if (runner.full_test & TEST_SCALE) {
runner.num_device_scales = 2;
}
@@ -910,7 +924,7 @@ main (int argc, char **argv)
target = ctx.targets_to_test[n];
- has_similar = runner.full_test ?
+ has_similar = runner.full_test & TEST_SIMILAR ?
cairo_test_target_has_similar (&ctx, target) :
DIRECT;
for (m = 0; m < runner.num_device_offsets; m++) {
commit 690c61aa54c27e4d35b04d0173abd5931fce507d
Author: Alexander Larsson <alexl at redhat.com>
Date: Mon Jun 3 15:38:22 2013 +0200
tests: Add device scale test to "full" testrun similar to offsets
diff --git a/test/cairo-test-private.h b/test/cairo-test-private.h
index 3e40324..cfd22de 100644
--- a/test/cairo-test-private.h
+++ b/test/cairo-test-private.h
@@ -49,7 +49,7 @@ cairo_test_status_t
_cairo_test_context_run_for_target (cairo_test_context_t *ctx,
const cairo_boilerplate_target_t *target,
cairo_bool_t similar,
- int dev_offset);
+ int dev_offset, int dev_scale);
void
_cairo_test_context_init_for_test (cairo_test_context_t *ctx,
diff --git a/test/cairo-test-runner.c b/test/cairo-test-runner.c
index a5c6705..71107f3 100644
--- a/test/cairo-test-runner.c
+++ b/test/cairo-test-runner.c
@@ -69,6 +69,7 @@ typedef struct _cairo_test_runner {
cairo_test_context_t base;
unsigned int num_device_offsets;
+ unsigned int num_device_scales;
cairo_bool_t passed;
int num_passed;
@@ -232,7 +233,7 @@ _cairo_test_runner_draw (cairo_test_runner_t *runner,
cairo_test_context_t *ctx,
const cairo_boilerplate_target_t *target,
cairo_bool_t similar,
- int device_offset)
+ int device_offset, int device_scale)
{
#if SHOULD_FORK
if (! runner->foreground) {
@@ -244,7 +245,7 @@ _cairo_test_runner_draw (cairo_test_runner_t *runner,
case 0: /* child */
exit (_cairo_test_context_run_for_target (ctx, target,
- similar, device_offset));
+ similar, device_offset, device_scale));
default:
return _cairo_test_wait (pid);
@@ -252,7 +253,7 @@ _cairo_test_runner_draw (cairo_test_runner_t *runner,
}
#endif
return _cairo_test_context_run_for_target (ctx, target,
- similar, device_offset);
+ similar, device_offset, device_scale);
}
static void
@@ -696,7 +697,7 @@ main (int argc, char **argv)
cairo_test_runner_t runner;
cairo_test_list_t *test_list;
cairo_test_status_t *target_status;
- unsigned int n, m;
+ unsigned int n, m, k;
char targets[4096];
int len;
char *cairo_tests_env;
@@ -712,6 +713,7 @@ main (int argc, char **argv)
memset (&runner, 0, sizeof (runner));
runner.num_device_offsets = 1;
+ runner.num_device_scales = 1;
if (is_running_under_debugger ())
runner.foreground = TRUE;
@@ -743,6 +745,7 @@ main (int argc, char **argv)
if (runner.full_test) {
runner.num_device_offsets = 2;
+ runner.num_device_scales = 2;
}
target_status = NULL; /* silence the compiler */
@@ -911,32 +914,35 @@ main (int argc, char **argv)
cairo_test_target_has_similar (&ctx, target) :
DIRECT;
for (m = 0; m < runner.num_device_offsets; m++) {
- int dev_offset = m * 25;
- cairo_test_similar_t similar;
-
- for (similar = DIRECT; similar <= has_similar; similar++) {
- status = _cairo_test_runner_draw (&runner, &ctx, target,
- similar, dev_offset);
- switch (status) {
- case CAIRO_TEST_SUCCESS:
- target_skipped = FALSE;
- break;
- case CAIRO_TEST_XFAILURE:
- target_xfailed = TRUE;
- break;
- case CAIRO_TEST_NEW:
- case CAIRO_TEST_FAILURE:
- target_failed = TRUE;
- break;
- case CAIRO_TEST_ERROR:
- target_error = TRUE;
- break;
- case CAIRO_TEST_NO_MEMORY:
- case CAIRO_TEST_CRASHED:
- target_crashed = TRUE;
- break;
- case CAIRO_TEST_UNTESTED:
- break;
+ for (k = 0; k < runner.num_device_scales; k++) {
+ int dev_offset = m * 25;
+ int dev_scale = k + 1;
+ cairo_test_similar_t similar;
+
+ for (similar = DIRECT; similar <= has_similar; similar++) {
+ status = _cairo_test_runner_draw (&runner, &ctx, target,
+ similar, dev_offset, dev_scale);
+ switch (status) {
+ case CAIRO_TEST_SUCCESS:
+ target_skipped = FALSE;
+ break;
+ case CAIRO_TEST_XFAILURE:
+ target_xfailed = TRUE;
+ break;
+ case CAIRO_TEST_NEW:
+ case CAIRO_TEST_FAILURE:
+ target_failed = TRUE;
+ break;
+ case CAIRO_TEST_ERROR:
+ target_error = TRUE;
+ break;
+ case CAIRO_TEST_NO_MEMORY:
+ case CAIRO_TEST_CRASHED:
+ target_crashed = TRUE;
+ break;
+ case CAIRO_TEST_UNTESTED:
+ break;
+ }
}
}
}
diff --git a/test/cairo-test.c b/test/cairo-test.c
index a3a587a..7bcb0ba 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -101,6 +101,7 @@ static cairo_bool_t print_fail_on_stdout;
static int cairo_test_timeout = 60;
#define NUM_DEVICE_OFFSETS 2
+#define NUM_DEVICE_SCALE 2
static cairo_bool_t
_cairo_test_mkdir (const char *path)
@@ -430,8 +431,8 @@ cairo_test_target_has_similar (const cairo_test_context_t *ctx,
target->content,
ctx->test->width,
ctx->test->height,
- ctx->test->width + 25 * NUM_DEVICE_OFFSETS,
- ctx->test->height + 25 * NUM_DEVICE_OFFSETS,
+ ctx->test->width* NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS,
+ ctx->test->height* NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS,
CAIRO_BOILERPLATE_MODE_TEST,
&closure);
if (surface == NULL)
@@ -628,6 +629,7 @@ static cairo_test_status_t
cairo_test_for_target (cairo_test_context_t *ctx,
const cairo_boilerplate_target_t *target,
int dev_offset,
+ int dev_scale,
cairo_bool_t similar)
{
cairo_test_status_t status;
@@ -635,6 +637,7 @@ cairo_test_for_target (cairo_test_context_t *ctx,
cairo_t *cr;
const char *empty_str = "";
char *offset_str;
+ char *scale_str;
char *base_name, *base_path;
char *out_png_path;
char *ref_path = NULL, *ref_png_path, *cmp_png_path = NULL;
@@ -666,15 +669,23 @@ cairo_test_for_target (cairo_test_context_t *ctx,
else
offset_str = (char *) empty_str;
- xasprintf (&base_name, "%s.%s.%s%s%s",
+ if (dev_scale != 1)
+ xasprintf (&scale_str, ".x%d", dev_scale);
+ else
+ scale_str = (char *) empty_str;
+
+ xasprintf (&base_name, "%s.%s.%s%s%s%s",
ctx->test_name,
target->name,
format,
similar ? ".similar" : "",
- offset_str);
+ offset_str,
+ scale_str);
if (offset_str != empty_str)
free (offset_str);
+ if (scale_str != empty_str)
+ free (scale_str);
ref_png_path = cairo_test_reference_filename (ctx,
base_name,
@@ -782,6 +793,8 @@ cairo_test_for_target (cairo_test_context_t *ctx,
width = ctx->test->width;
height = ctx->test->height;
if (width && height) {
+ width *= dev_scale;
+ height *= dev_scale;
width += dev_offset;
height += dev_offset;
}
@@ -810,8 +823,8 @@ REPEAT:
surface = (target->create_surface) (base_path,
target->content,
width, height,
- ctx->test->width + 25 * NUM_DEVICE_OFFSETS,
- ctx->test->height + 25 * NUM_DEVICE_OFFSETS,
+ ctx->test->width * NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS,
+ ctx->test->height * NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS,
CAIRO_BOILERPLATE_MODE_TEST,
&closure);
if (surface == NULL) {
@@ -878,6 +891,7 @@ REPEAT:
}
cairo_surface_set_device_offset (surface, dev_offset, dev_offset);
+ cairo_surface_set_device_scale (surface, dev_scale, dev_scale);
cr = cairo_create (surface);
if (cairo_set_user_data (cr, &_cairo_test_context_key, (void*) ctx, NULL)) {
@@ -1471,7 +1485,7 @@ cairo_test_status_t
_cairo_test_context_run_for_target (cairo_test_context_t *ctx,
const cairo_boilerplate_target_t *target,
cairo_bool_t similar,
- int dev_offset)
+ int dev_offset, int dev_scale)
{
cairo_test_status_t status;
@@ -1482,15 +1496,15 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
return CAIRO_TEST_UNTESTED;
cairo_test_log (ctx,
- "Testing %s with %s%s target (dev offset %d)\n",
+ "Testing %s with %s%s target (dev offset %d scale: %d)\n",
ctx->test_name,
similar ? " (similar) " : "",
target->name,
- dev_offset);
+ dev_offset, dev_scale);
- printf ("%s.%s.%s [%d]%s:\t", ctx->test_name, target->name,
+ printf ("%s.%s.%s [%dx%d]%s:\t", ctx->test_name, target->name,
cairo_boilerplate_content_name (target->content),
- dev_offset,
+ dev_offset, dev_scale,
similar ? " (similar)": "");
fflush (stdout);
@@ -1519,7 +1533,7 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
old_sigalrm_handler = signal (SIGALRM, segfault_handler);
#endif
if (0 == setjmp (jmpbuf))
- status = cairo_test_for_target (ctx, target, dev_offset, similar);
+ status = cairo_test_for_target (ctx, target, dev_offset, dev_scale, similar);
else
status = CAIRO_TEST_CRASHED;
#ifdef SIGSEGV
@@ -1538,17 +1552,17 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
signal (SIGALRM, old_sigalrm_handler);
#endif
} else {
- status = cairo_test_for_target (ctx, target, dev_offset, similar);
+ status = cairo_test_for_target (ctx, target, dev_offset, dev_scale, similar);
}
#else
- status = cairo_test_for_target (ctx, target, dev_offset, similar);
+ status = cairo_test_for_target (ctx, target, dev_offset, dev_scale, similar);
#endif
cairo_test_log (ctx,
- "TEST: %s TARGET: %s FORMAT: %s OFFSET: %d SIMILAR: %d RESULT: ",
+ "TEST: %s TARGET: %s FORMAT: %s OFFSET: %d SCALE: %d SIMILAR: %d RESULT: ",
ctx->test_name, target->name,
cairo_boilerplate_content_name (target->content),
- dev_offset, similar);
+ dev_offset, dev_scale, similar);
switch (status) {
case CAIRO_TEST_SUCCESS:
printf ("PASS\n");
@@ -1570,9 +1584,9 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
fflush (stdout);
}
cairo_test_log (ctx, "CRASHED\n");
- fprintf (stderr, "%s.%s.%s [%d]%s:\t%s!!!CRASHED!!!%s\n",
+ fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%s!!!CRASHED!!!%s\n",
ctx->test_name, target->name,
- cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
+ cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
fail_face, normal_face);
break;
@@ -1585,9 +1599,9 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
fflush (stdout);
}
cairo_test_log (ctx, "ERROR\n");
- fprintf (stderr, "%s.%s.%s [%d]%s:\t%s!!!ERROR!!!%s\n",
+ fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%s!!!ERROR!!!%s\n",
ctx->test_name, target->name,
- cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
+ cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
fail_face, normal_face);
break;
@@ -1599,9 +1613,9 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
printf ("\r");
fflush (stdout);
}
- fprintf (stderr, "%s.%s.%s [%d]%s:\t%sXFAIL%s\n",
+ fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%sXFAIL%s\n",
ctx->test_name, target->name,
- cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
+ cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
xfail_face, normal_face);
cairo_test_log (ctx, "XFAIL\n");
break;
@@ -1614,9 +1628,9 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
printf ("\r");
fflush (stdout);
}
- fprintf (stderr, "%s.%s.%s [%d]%s:\t%sNEW%s\n",
+ fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%sNEW%s\n",
ctx->test_name, target->name,
- cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
+ cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
fail_face, normal_face);
cairo_test_log (ctx, "NEW\n");
break;
@@ -1630,9 +1644,9 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
printf ("\r");
fflush (stdout);
}
- fprintf (stderr, "%s.%s.%s [%d]%s:\t%sFAIL%s\n",
+ fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%sFAIL%s\n",
ctx->test_name, target->name,
- cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
+ cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
fail_face, normal_face);
cairo_test_log (ctx, "FAIL\n");
break;
commit 7ab34f302be72d9dda54d936b6d69bc7c534c885
Author: Alexander Larsson <alexl at redhat.com>
Date: Thu May 30 19:45:59 2013 +0200
surface: expose the device scale
This adds the new public functions
cairo_surface_set_device_scale and cairo_surface_get_device_scale and
updates old users of the internal functions.
diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
index 078135b..8964244 100644
--- a/src/cairo-default-context.c
+++ b/src/cairo-default-context.c
@@ -189,9 +189,9 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
parent_surface->device_transform.x0 - extents.x,
parent_surface->device_transform.y0 - extents.y);
- _cairo_surface_set_device_scale (group_surface,
- parent_surface->device_transform.xx,
- parent_surface->device_transform.yy);
+ cairo_surface_set_device_scale (group_surface,
+ parent_surface->device_transform.xx,
+ parent_surface->device_transform.yy);
/* If we have a current path, we need to adjust it to compensate for
* the device offset just applied. */
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index fe9ccee..68e4e0e 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -308,7 +308,7 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
image = _cairo_paginated_surface_create_image_surface (surface,
ceil (width * x_scale),
ceil (height * y_scale));
- _cairo_surface_set_device_scale (image, x_scale, y_scale);
+ cairo_surface_set_device_scale (image, x_scale, y_scale);
/* set_device_offset just sets the x0/y0 components of the matrix;
* so we have to do the scaling manually. */
cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 712c0fe..0efb963 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -500,9 +500,9 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target,
surface->snapshot = NULL;
- _cairo_surface_set_device_scale (&surface->base,
- target->device_transform.xx,
- target->device_transform.yy);
+ cairo_surface_set_device_scale (&surface->base,
+ target->device_transform.xx,
+ target->device_transform.yy);
return &surface->base;
}
@@ -542,9 +542,9 @@ _cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
surface->snapshot = NULL;
- _cairo_surface_set_device_scale (&surface->base,
- target->device_transform.xx,
- target->device_transform.yy);
+ cairo_surface_set_device_scale (&surface->base,
+ target->device_transform.xx,
+ target->device_transform.yy);
return &surface->base;
}
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 79b2f2e..f07a0f6 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1624,26 +1624,28 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
slim_hidden_def (cairo_surface_mark_dirty_rectangle);
/**
- * _cairo_surface_set_device_scale:
+ * cairo_surface_set_device_scale:
* @surface: a #cairo_surface_t
* @sx: a scale factor in the X direction
* @sy: a scale factor in the Y direction
*
- * Private function for setting an extra scale factor to affect all
- * drawing to a surface. This is used, for example, when replaying a
- * recording surface to an image fallback intended for an eventual
- * vector-oriented backend. Since the recording surface will record
- * coordinates in one backend space, but the image fallback uses a
- * different backend space, (differing by the fallback resolution
- * scale factors), we need a scale factor correction.
+ * Sets an scale that is multiplied to the device coordinates determined
+ * by the CTM when drawing to @surface. One common use for this is to
+ * render to very high resolution display devices at a scale factor, so
+ * that code that assumes 1 pixel will be a certain size will still work.
+ * Setting a transformation via cairo_translate() isn't
+ * sufficient to do this, since functions like
+ * cairo_device_to_user() will expose the hidden scale.
+ *
+ * Note that the scale affects drawing to the surface as well as
+ * using the surface in a source pattern.
*
- * Caution: Not all places we use device transform correctly handle
- * both a translate and a scale. An audit would be nice.
+ * Since: 1.14
**/
void
-_cairo_surface_set_device_scale (cairo_surface_t *surface,
- double sx,
- double sy)
+cairo_surface_set_device_scale (cairo_surface_t *surface,
+ double sx,
+ double sy)
{
cairo_status_t status;
@@ -1675,6 +1677,30 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface,
_cairo_observers_notify (&surface->device_transform_observers, surface);
}
+slim_hidden_def (cairo_surface_set_device_scale);
+
+/**
+ * cairo_surface_get_device_scale:
+ * @surface: a #cairo_surface_t
+ * @x_scale: the scale in the X direction, in device units
+ * @y_scale: the scale in the Y direction, in device units
+ *
+ * This function returns the previous device offset set by
+ * cairo_surface_set_device_scale().
+ *
+ * Since: 1.14
+ **/
+void
+cairo_surface_get_device_scale (cairo_surface_t *surface,
+ double *x_scale,
+ double *y_scale)
+{
+ if (x_scale)
+ *x_scale = surface->device_transform.xx;
+ if (y_scale)
+ *y_scale = surface->device_transform.yy;
+}
+slim_hidden_def (cairo_surface_get_device_scale);
/**
* cairo_surface_set_device_offset:
diff --git a/src/cairo.h b/src/cairo.h
index a2f5aa3..de35126 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -2456,6 +2456,16 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
int height);
cairo_public void
+cairo_surface_set_device_scale (cairo_surface_t *surface,
+ double x_scale,
+ double y_scale);
+
+cairo_public void
+cairo_surface_get_device_scale (cairo_surface_t *surface,
+ double *x_scale,
+ double *y_scale);
+
+cairo_public void
cairo_surface_set_device_offset (cairo_surface_t *surface,
double x_offset,
double y_offset);
diff --git a/src/cairoint.h b/src/cairoint.h
index 861e2f7..84e6026 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1420,11 +1420,6 @@ cairo_private_no_warn cairo_bool_t
_cairo_surface_get_extents (cairo_surface_t *surface,
cairo_rectangle_int_t *extents);
-cairo_private void
-_cairo_surface_set_device_scale (cairo_surface_t *surface,
- double sx,
- double sy);
-
cairo_private cairo_bool_t
_cairo_surface_has_device_transform (cairo_surface_t *surface) cairo_pure;
@@ -1955,6 +1950,7 @@ slim_hidden_proto (cairo_surface_destroy);
slim_hidden_proto (cairo_surface_finish);
slim_hidden_proto (cairo_surface_flush);
slim_hidden_proto (cairo_surface_get_device_offset);
+slim_hidden_proto (cairo_surface_get_device_scale);
slim_hidden_proto (cairo_surface_get_font_options);
slim_hidden_proto (cairo_surface_get_mime_data);
slim_hidden_proto (cairo_surface_has_show_text_glyphs);
@@ -1962,6 +1958,7 @@ slim_hidden_proto (cairo_surface_mark_dirty);
slim_hidden_proto (cairo_surface_mark_dirty_rectangle);
slim_hidden_proto_no_warn (cairo_surface_reference);
slim_hidden_proto (cairo_surface_set_device_offset);
+slim_hidden_proto (cairo_surface_set_device_scale);
slim_hidden_proto (cairo_surface_set_fallback_resolution);
slim_hidden_proto (cairo_surface_set_mime_data);
slim_hidden_proto (cairo_surface_show_page);
commit 38217d67fc2226778dde8d05817cb916691d4d22
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jun 3 20:32:45 2013 +0100
spans,traps: Undo device transform from source matrix for recording replays
As the replay of the recording surface applies the device_transform of
the matrix once again to all its operations, we end up with a repeated
transform through the source matrix of the recording surface. We need to
remove one of these, and the easiest way to do that appears to be to
undo the application to the source matrix.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-spans-compositor.c b/src/cairo-spans-compositor.c
index 6eb9b42..1a46ea3 100644
--- a/src/cairo-spans-compositor.c
+++ b/src/cairo-spans-compositor.c
@@ -585,6 +585,8 @@ composite_aligned_boxes (const cairo_spans_compositor_t *compositor,
{
cairo_clip_t *recording_clip;
const cairo_pattern_t *source = &extents->source_pattern.base;
+ const cairo_matrix_t *m;
+ cairo_matrix_t matrix;
/* XXX could also do tiling repeat modes... */
@@ -600,10 +602,17 @@ composite_aligned_boxes (const cairo_spans_compositor_t *compositor,
dst->is_clear = TRUE;
}
+ m = &source->matrix;
+ if (_cairo_surface_has_device_transform (dst)) {
+ cairo_matrix_multiply (&matrix,
+ &source->matrix,
+ &dst->device_transform);
+ m = &matrix;
+ }
+
recording_clip = _cairo_clip_from_boxes (boxes);
status = _cairo_recording_surface_replay_with_clip (unwrap_source (source),
- &source->matrix,
- dst, recording_clip);
+ m, dst, recording_clip);
_cairo_clip_destroy (recording_clip);
return status;
diff --git a/src/cairo-traps-compositor.c b/src/cairo-traps-compositor.c
index 988d23c..631e172 100644
--- a/src/cairo-traps-compositor.c
+++ b/src/cairo-traps-compositor.c
@@ -1206,7 +1206,9 @@ composite_aligned_boxes (const cairo_traps_compositor_t *compositor,
&extents->source_sample_area))
{
cairo_clip_t *recording_clip;
- cairo_pattern_t *source = &extents->source_pattern.base;
+ const cairo_pattern_t *source = &extents->source_pattern.base;
+ const cairo_matrix_t *m;
+ cairo_matrix_t matrix;
/* XXX could also do tiling repeat modes... */
@@ -1225,10 +1227,17 @@ composite_aligned_boxes (const cairo_traps_compositor_t *compositor,
return status;
}
+ m = &source->matrix;
+ if (_cairo_surface_has_device_transform (dst)) {
+ cairo_matrix_multiply (&matrix,
+ &source->matrix,
+ &dst->device_transform);
+ m = &matrix;
+ }
+
recording_clip = _cairo_clip_from_boxes (boxes);
status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (source),
- &source->matrix,
- dst, recording_clip);
+ m, dst, recording_clip);
_cairo_clip_destroy (recording_clip);
return status;
commit f0e2cd4494b1ac9a351d095fbeb53d702342d35c
Author: Alexander Larsson <alexl at redhat.com>
Date: Fri May 31 16:44:29 2013 +0200
gstate: Handle device scale on surface as source
When creating a transformed pattern we must apply the device
transform *before* the transform set on the pattern itself, otherwise
e.g. its translation will not be affected by the device scale.
We also fix up the device_transform related handling in
_cairo_default_context_pop_group(). With a device scale we can
no longer just use the device_transform_inverse to unset the
device offset for the extents, so we make that a simple translate
instead.
We also remove some weird code that tries to handle the device
transform but seems unnecessary (maybe a workaround for applying
the device transform in the wrong order?). With that code removed
things work fine, but with it things get translated wrongly when
there is a scale.
diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
index 77b6eef..078135b 100644
--- a/src/cairo-default-context.c
+++ b/src/cairo-default-context.c
@@ -218,7 +218,8 @@ _cairo_default_context_pop_group (void *abstract_cr)
cairo_default_context_t *cr = abstract_cr;
cairo_surface_t *group_surface;
cairo_pattern_t *group_pattern;
- cairo_matrix_t group_matrix, device_transform_matrix;
+ cairo_surface_t *parent_surface;
+ cairo_matrix_t group_matrix;
cairo_status_t status;
/* Verify that we are at the right nesting level */
@@ -232,29 +233,21 @@ _cairo_default_context_pop_group (void *abstract_cr)
status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
assert (status == CAIRO_STATUS_SUCCESS);
+ parent_surface = _cairo_gstate_get_target (cr->gstate);
+
group_pattern = cairo_pattern_create_for_surface (group_surface);
status = group_pattern->status;
if (unlikely (status))
goto done;
_cairo_gstate_get_matrix (cr->gstate, &group_matrix);
- /* Transform by group_matrix centered around device_transform so that when
- * we call _cairo_gstate_copy_transformed_pattern the result is a pattern
- * with a matrix equivalent to the device_transform of group_surface. */
- if (_cairo_surface_has_device_transform (group_surface)) {
- cairo_pattern_set_matrix (group_pattern, &group_surface->device_transform);
- _cairo_pattern_transform (group_pattern, &group_matrix);
- _cairo_pattern_transform (group_pattern, &group_surface->device_transform_inverse);
- } else {
- cairo_pattern_set_matrix (group_pattern, &group_matrix);
- }
+ cairo_pattern_set_matrix (group_pattern, &group_matrix);
/* If we have a current path, we need to adjust it to compensate for
* the device offset just removed. */
- cairo_matrix_multiply (&device_transform_matrix,
- &_cairo_gstate_get_target (cr->gstate)->device_transform,
- &group_surface->device_transform_inverse);
- _cairo_path_fixed_transform (cr->path, &device_transform_matrix);
+ _cairo_path_fixed_translate (cr->path,
+ _cairo_fixed_from_int (parent_surface->device_transform.x0 - group_surface->device_transform.x0),
+ _cairo_fixed_from_int (parent_surface->device_transform.y0 - group_surface->device_transform.y0));
done:
cairo_surface_destroy (group_surface);
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 8ddb3af..b4e988e 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -954,7 +954,7 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
surface = surface_pattern->surface;
if (_cairo_surface_has_device_transform (surface))
- _cairo_pattern_transform (pattern, &surface->device_transform);
+ _cairo_pattern_pretransform (pattern, &surface->device_transform);
}
if (! _cairo_matrix_is_identity (ctm_inverse))
diff --git a/src/cairo-pattern-private.h b/src/cairo-pattern-private.h
index dfd843f..bbcfadd 100644
--- a/src/cairo-pattern-private.h
+++ b/src/cairo-pattern-private.h
@@ -237,6 +237,10 @@ cairo_private void
_cairo_pattern_transform (cairo_pattern_t *pattern,
const cairo_matrix_t *ctm_inverse);
+cairo_private void
+_cairo_pattern_pretransform (cairo_pattern_t *pattern,
+ const cairo_matrix_t *ctm);
+
cairo_private cairo_bool_t
_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern);
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 940227d..57b930b 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -2128,6 +2128,16 @@ cairo_pattern_get_extend (cairo_pattern_t *pattern)
slim_hidden_def (cairo_pattern_get_extend);
void
+_cairo_pattern_pretransform (cairo_pattern_t *pattern,
+ const cairo_matrix_t *ctm)
+{
+ if (pattern->status)
+ return;
+
+ cairo_matrix_multiply (&pattern->matrix, &pattern->matrix, ctm);
+}
+
+void
_cairo_pattern_transform (cairo_pattern_t *pattern,
const cairo_matrix_t *ctm_inverse)
{
commit 900fc4a890026e46a3b0a00967632f57074b8b93
Author: Alexander Larsson <alexl at redhat.com>
Date: Thu May 30 20:53:29 2013 +0200
gstate: Move device-scale font scaling to gstate
If we do this in surface it will be applied twice then
we chain to a different surface, like e.g. a subsurface.
We also remove a hack in cairo-surface-wrapper where it compensated
for the device scale not being applied.
v2: Compute the backend CTM in ensure_scaled_font().
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 56e961e..8ddb3af 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1842,6 +1842,7 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate)
cairo_status_t status;
cairo_font_options_t options;
cairo_scaled_font_t *scaled_font;
+ cairo_matrix_t font_ctm;
if (gstate->scaled_font != NULL)
return gstate->scaled_font->status;
@@ -1853,9 +1854,13 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate)
cairo_surface_get_font_options (gstate->target, &options);
cairo_font_options_merge (&options, &gstate->font_options);
+ cairo_matrix_multiply (&font_ctm,
+ &gstate->ctm,
+ &gstate->target->device_transform);
+
scaled_font = cairo_scaled_font_create (gstate->font_face,
&gstate->font_matrix,
- &gstate->ctm,
+ &font_ctm,
&options);
status = cairo_scaled_font_status (scaled_font);
@@ -2005,6 +2010,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
if (cairo_surface_has_show_text_glyphs (gstate->target) ||
_cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240)
{
+
if (info != NULL) {
status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
info->utf8, info->utf8_len,
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index 578e8e2..030de67 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -437,12 +437,11 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
_cairo_surface_wrapper_get_transform (wrapper, &m);
- if (! _cairo_matrix_is_translation (&wrapper->transform)) {
+ if (! _cairo_matrix_is_translation (&m)) {
cairo_matrix_t ctm;
- /* XXX No device-transform? A bug in the tangle of layers? */
_cairo_matrix_multiply (&ctm,
- &wrapper->transform,
+ &m,
&scaled_font->ctm);
dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
&scaled_font->font_matrix,
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 5e18b07..79b2f2e 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -2459,7 +2459,6 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
const cairo_clip_t *clip)
{
cairo_int_status_t status;
- cairo_scaled_font_t *dev_scaled_font = scaled_font;
TRACE ((stderr, "%s\n", __FUNCTION__));
if (unlikely (surface->status))
@@ -2484,25 +2483,6 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
if (unlikely (status))
return status;
- if (_cairo_surface_has_device_transform (surface) &&
- ! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL))
- {
- cairo_font_options_t font_options;
- cairo_matrix_t dev_ctm, font_matrix;
-
- cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix);
- cairo_scaled_font_get_ctm (scaled_font, &dev_ctm);
- cairo_matrix_multiply (&dev_ctm, &dev_ctm, &surface->device_transform);
- cairo_scaled_font_get_font_options (scaled_font, &font_options);
- dev_scaled_font = cairo_scaled_font_create (cairo_scaled_font_get_font_face (scaled_font),
- &font_matrix,
- &dev_ctm,
- &font_options);
- }
- status = cairo_scaled_font_status (dev_scaled_font);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
-
status = CAIRO_INT_STATUS_UNSUPPORTED;
/* The logic here is duplicated in _cairo_analysis_surface show_glyphs and
@@ -2516,7 +2496,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
- dev_scaled_font,
+ scaled_font,
clip);
}
if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
@@ -2525,7 +2505,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
status = surface->backend->show_glyphs (surface, op,
source,
glyphs, num_glyphs,
- dev_scaled_font,
+ scaled_font,
clip);
}
} else {
@@ -2534,7 +2514,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
status = surface->backend->show_glyphs (surface, op,
source,
glyphs, num_glyphs,
- dev_scaled_font,
+ scaled_font,
clip);
} else if (surface->backend->show_text_glyphs != NULL) {
/* Intentionally only try show_text_glyphs method for show_glyphs
@@ -2550,14 +2530,11 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
- dev_scaled_font,
+ scaled_font,
clip);
}
}
- if (dev_scaled_font != scaled_font)
- cairo_scaled_font_destroy (dev_scaled_font);
-
if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
surface->is_clear = FALSE;
surface->serial++;
commit 25eaec0a3874a2090e1bb97547a328eb5c00b0b1
Author: Alexander Larsson <alexl at redhat.com>
Date: Thu May 30 20:53:15 2013 +0200
subsurface: Handle device scales
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 051e95f..712c0fe 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -465,7 +465,12 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target,
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- assert (_cairo_matrix_is_translation (&target->device_transform));
+ x *= target->device_transform.xx;
+ y *= target->device_transform.yy;
+
+ width *= target->device_transform.xx;
+ height *= target->device_transform.yy;
+
x += target->device_transform.x0;
y += target->device_transform.y0;
@@ -495,6 +500,10 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target,
surface->snapshot = NULL;
+ _cairo_surface_set_device_scale (&surface->base,
+ target->device_transform.xx,
+ target->device_transform.yy);
+
return &surface->base;
}
@@ -515,14 +524,16 @@ _cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- assert (_cairo_matrix_is_translation (&target->device_transform));
-
_cairo_surface_init (&surface->base,
&_cairo_surface_subsurface_backend,
NULL, /* device */
target->content);
surface->extents = *extents;
+ surface->extents.x *= target->device_transform.xx;
+ surface->extents.y *= target->device_transform.yy;
+ surface->extents.width *= target->device_transform.xx;
+ surface->extents.height *= target->device_transform.yy;
surface->extents.x += target->device_transform.x0;
surface->extents.y += target->device_transform.y0;
@@ -531,6 +542,10 @@ _cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
surface->snapshot = NULL;
+ _cairo_surface_set_device_scale (&surface->base,
+ target->device_transform.xx,
+ target->device_transform.yy);
+
return &surface->base;
}
/* XXX observe mark-dirty */
commit 633d573889ad685c8f07e9ee72f6a1d240dfacf2
Author: Alexander Larsson <alexl at redhat.com>
Date: Thu May 30 19:48:33 2013 +0200
default-context: Inherit device scale in push_group surface
Without this we will only render to part of the newly created
surface and then copy+scale that part back, which causes fuzziness.
diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
index aec5b10..77b6eef 100644
--- a/src/cairo-default-context.c
+++ b/src/cairo-default-context.c
@@ -189,6 +189,10 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
parent_surface->device_transform.x0 - extents.x,
parent_surface->device_transform.y0 - extents.y);
+ _cairo_surface_set_device_scale (group_surface,
+ parent_surface->device_transform.xx,
+ parent_surface->device_transform.yy);
+
/* If we have a current path, we need to adjust it to compensate for
* the device offset just applied. */
_cairo_path_fixed_translate (cr->path,
commit db7e551a6bf06a0aa7e2e6b3744b7663807d003f
Author: Alexander Larsson <alexl at redhat.com>
Date: Thu May 30 19:47:19 2013 +0200
gstate: Respect device transform in stroke
We need to apply the device transform to the ctm when stroking, as
otherwise line widths are not affected by the device scale.
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index b8caa63..56e961e 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1155,6 +1155,8 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
cairo_stroke_style_t style;
double dash[2];
cairo_status_t status;
+ cairo_matrix_t aggregate_transform;
+ cairo_matrix_t aggregate_transform_inverse;
status = _cairo_gstate_get_pattern_status (gstate->source);
if (unlikely (status))
@@ -1171,8 +1173,15 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
assert (gstate->opacity == 1.0);
+ cairo_matrix_multiply (&aggregate_transform,
+ &gstate->ctm,
+ &gstate->target->device_transform);
+ cairo_matrix_multiply (&aggregate_transform_inverse,
+ &gstate->target->device_transform_inverse,
+ &gstate->ctm_inverse);
+
memcpy (&style, &gstate->stroke_style, sizeof (gstate->stroke_style));
- if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance)) {
+ if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &aggregate_transform, gstate->tolerance)) {
style.dash = dash;
_cairo_stroke_style_dash_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance,
&style.dash_offset,
@@ -1187,8 +1196,8 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
&source_pattern.base,
path,
&style,
- &gstate->ctm,
- &gstate->ctm_inverse,
+ &aggregate_transform,
+ &aggregate_transform_inverse,
gstate->tolerance,
gstate->antialias,
gstate->clip);
commit fb57ea13e04d82866cbc8e86c83261148bb3e231
Author: Krzysztof KosiÅski <tweenk.pl at gmail.com>
Date: Thu Sep 5 16:02:14 2013 +0100
image: Use convolution filters for sample reconstruction when downscaling
I had a look at how complex would it be to add correct downscaling to
Cairo now that Pixman supports convolution filters. It turns out it
this is rather easy. Here is an initial, minimal attempt. It uses
convolution filters only if the image is being downscaled by more than
half a pixel in at least one dimension.
Some discussion:
1. The sampling and reconstruction kernels are picked in a way that
gives comparable quality when upscaling and downscaling. I paired box
sampling with bilinear reconstruction and impulse (point) sampling
with box reconstruction. This gives the expected result for NEAREST
filter. BEST filter uses Lanczos3 for both kernels.
> Do we need to use a reconstruction filter for NEAREST at all? Or maybe
> differentiate between NEAREST and FAST in that case?
If impulse (point) sampling is used, there must be some reconstruction
filter, otherwise no image is produced. That's because the sampling
grid does not match the data grid, and since there is no
reconstruction filter, values between data points are undefined. The
alternative is to use box sampling + no reconstruction.
2. Subsampling bits are always set to 1, since this doesn't seem to
affect quality at all.
3. I am not sure whether this code works correctly for matrices with a
skew component. It should be OK for any combination of scale, rotation
and translation.
4. This patch causes new failures in the test suite:
- recording-surface*: possibly an effect of improved quality.
- surface-pattern-scale-down*, surface-pattern-big-scale-down: the
reference images should be updated.
- pthread-same-source: I have no idea why this is failing, since this
test shouldn't even trigger the new code.
- large-source-roi: this test attempts to downscale an image which is
30000 pixels wide down to 7 pixels. The filter parameters seem to be
created correctly, but they might trigger an overflow somewhere in the
convolution code; the output rectangle is white instead of red, as if
nothing was drawn.
- device-offset-scale: there are subtle differences which look like
convolution-related smoothing; I'm not sure whether this is OK or not.
diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c
index c5bd228..661bc10 100644
--- a/src/cairo-image-source.c
+++ b/src/cairo-image-source.c
@@ -554,24 +554,42 @@ _pixman_image_set_properties (pixman_image_t *pixman_image,
}
else
{
+ double scale_x, scale_y;
+ int shrink_x, shrink_y;
pixman_filter_t pixman_filter;
+ pixman_kernel_t pixman_kernel_sample, pixman_kernel_reconstruct;
+
+ /* Compute scale factors as the length of basis vectors transformed by
+ * the pattern matrix. These scale factors are from user to pattern space,
+ * and as such they are greater than 1.0 for downscaling and less than 1.0
+ * for upscaling.
+ * TODO: this approach may not be completely correct if the matrix
+ * contains a skew component. */
+ scale_x = hypot (pattern->matrix.xx, pattern->matrix.yx);
+ scale_y = hypot (pattern->matrix.yx, pattern->matrix.yy);
+
+ /* Use convolution filtering if the transformation shrinks the image
+ * by more than half a pixel */
+ shrink_x = (extents->width / scale_x - extents->width) < -0.5;
+ shrink_y = (extents->height / scale_y - extents->height) < -0.5;
switch (pattern->filter) {
case CAIRO_FILTER_FAST:
- pixman_filter = PIXMAN_FILTER_FAST;
- break;
- case CAIRO_FILTER_GOOD:
- pixman_filter = PIXMAN_FILTER_GOOD;
- break;
- case CAIRO_FILTER_BEST:
- pixman_filter = PIXMAN_FILTER_BEST;
- break;
case CAIRO_FILTER_NEAREST:
pixman_filter = PIXMAN_FILTER_NEAREST;
+ pixman_kernel_sample = PIXMAN_KERNEL_IMPULSE;
+ pixman_kernel_reconstruct = PIXMAN_KERNEL_BOX;
break;
+ case CAIRO_FILTER_GOOD:
case CAIRO_FILTER_BILINEAR:
pixman_filter = PIXMAN_FILTER_BILINEAR;
+ pixman_kernel_sample = PIXMAN_KERNEL_BOX;
+ pixman_kernel_reconstruct = PIXMAN_KERNEL_LINEAR;
break;
+ case CAIRO_FILTER_BEST:
+ pixman_filter = PIXMAN_FILTER_BEST;
+ pixman_kernel_sample = PIXMAN_KERNEL_LANCZOS3;
+ pixman_kernel_reconstruct = PIXMAN_KERNEL_LANCZOS3;
case CAIRO_FILTER_GAUSSIAN:
/* XXX: The GAUSSIAN value has no implementation in cairo
* whatsoever, so it was really a mistake to have it in the
@@ -579,10 +597,37 @@ _pixman_image_set_properties (pixman_image_t *pixman_image,
* else inventing semantics and providing an actual
* implementation for it. */
default:
- pixman_filter = PIXMAN_FILTER_BEST;
+ pixman_filter = PIXMAN_FILTER_BILINEAR;
+ pixman_kernel_sample = PIXMAN_KERNEL_BOX;
+ pixman_kernel_reconstruct = PIXMAN_KERNEL_LINEAR;
}
- pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
+ if (pixman_filter != PIXMAN_FILTER_NEAREST && (shrink_x || shrink_y)) {
+ pixman_kernel_t sampling_kernel_x, sampling_kernel_y;
+ int n_params;
+ pixman_fixed_t *params;
+
+ sampling_kernel_x = shrink_x ? pixman_kernel_sample : PIXMAN_KERNEL_IMPULSE;
+ sampling_kernel_y = shrink_y ? pixman_kernel_sample : PIXMAN_KERNEL_IMPULSE;
+
+ n_params = 0;
+ params = pixman_filter_create_separable_convolution (&n_params,
+ scale_x * 65536.0 + 0.5,
+ scale_y * 65536.0 + 0.5,
+ pixman_kernel_reconstruct,
+ pixman_kernel_reconstruct,
+ sampling_kernel_x,
+ sampling_kernel_y,
+ 1, 1);
+
+ pixman_image_set_filter (pixman_image,
+ PIXMAN_FILTER_SEPARABLE_CONVOLUTION,
+ params, n_params);
+
+ free (params);
+ } else {
+ pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
+ }
}
{
commit 28ad0f9f3bec65e462e29a1d0b1757a86d16c129
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Thu Sep 5 15:56:55 2013 +0100
Bump version for new development tree, 1.13.1
diff --git a/cairo-version.h b/cairo-version.h
index 046a614..df272d1 100644
--- a/cairo-version.h
+++ b/cairo-version.h
@@ -2,7 +2,7 @@
#define CAIRO_VERSION_H
#define CAIRO_VERSION_MAJOR 1
-#define CAIRO_VERSION_MINOR 12
-#define CAIRO_VERSION_MICRO 17
+#define CAIRO_VERSION_MINOR 13
+#define CAIRO_VERSION_MICRO 1
#endif
More information about the cairo-commit
mailing list