Introduce a new compositor architecture

Having spent the last dev cycle looking at how we could specialize the
compositors for various backends, we once again look for the
commonalities in order to reduce the duplication. In part this is
motivated by the idea that spans is a good interface for both the
existent GL backend and pixman, and so they deserve a dedicated
compositor. xcb/xlib target an identical rendering system and so they
should be using the same compositor, and it should be possible to run
that same compositor locally against pixman to generate reference tests.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

P.S. This brings massive upheaval (read breakage) I've tried delaying in
order to fix as many things as possible but now this one patch does far,
far, far too much. Apologies in advance for breaking your favourite
backend, but trust me in that the end result will be much better. :)
This commit is contained in:
Chris Wilson 2011-07-30 17:28:21 +01:00
parent 0540bf384a
commit af9fbd176b
225 changed files with 27561 additions and 17971 deletions

View file

@ -30,66 +30,133 @@
#include <cairo-types-private.h> #include <cairo-types-private.h>
#include <test-fallback-surface.h> #include <test-compositor-surface.h>
#include <test-fallback16-surface.h> #include <test-null-compositor-surface.h>
#if CAIRO_HAS_TEST_PAGINATED_SURFACE #if CAIRO_HAS_TEST_PAGINATED_SURFACE
#include <test-paginated-surface.h> #include <test-paginated-surface.h>
#endif #endif
#if CAIRO_HAS_TEST_NULL_SURFACE
#include <test-null-surface.h>
#endif
#if CAIRO_HAS_TEST_WRAPPING_SURFACE
#include <test-wrapping-surface.h>
#endif
static cairo_surface_t * static cairo_surface_t *
_cairo_boilerplate_test_fallback_create_surface (const char *name, _cairo_boilerplate_test_base_compositor_create_surface (const char *name,
cairo_content_t content, cairo_content_t content,
double width, double width,
double height, double height,
double max_width, double max_width,
double max_height, double max_height,
cairo_boilerplate_mode_t mode, cairo_boilerplate_mode_t mode,
int id, int id,
void **closure) void **closure)
{ {
*closure = NULL; *closure = NULL;
return _cairo_test_fallback_surface_create (content, return _cairo_test_base_compositor_surface_create (content, ceil (width), ceil (height));
ceil (width), ceil (height)); }
static cairo_surface_t *
_cairo_boilerplate_test_fallback_compositor_create_surface (const char *name,
cairo_content_t content,
double width,
double height,
double max_width,
double max_height,
cairo_boilerplate_mode_t mode,
int id,
void **closure)
{
*closure = NULL;
return _cairo_test_fallback_compositor_surface_create (content, ceil (width), ceil (height));
} }
static cairo_surface_t * static cairo_surface_t *
_cairo_boilerplate_test_fallback16_create_surface (const char *name, _cairo_boilerplate_test_mask_compositor_create_surface (const char *name,
cairo_content_t content, cairo_content_t content,
double width, double width,
double height, double height,
double max_width, double max_width,
double max_height, double max_height,
cairo_boilerplate_mode_t mode, cairo_boilerplate_mode_t mode,
int id, int id,
void **closure) void **closure)
{ {
*closure = NULL; *closure = NULL;
return _cairo_test_fallback16_surface_create (content, return _cairo_test_mask_compositor_surface_create (content, ceil (width), ceil (height));
ceil (width), ceil (height));
} }
#if CAIRO_HAS_TEST_NULL_SURFACE
static cairo_surface_t * static cairo_surface_t *
_cairo_boilerplate_test_null_create_surface (const char *name, _cairo_boilerplate_test_traps_compositor_create_surface (const char *name,
cairo_content_t content, cairo_content_t content,
double width, double width,
double height, double height,
double max_width, double max_width,
double max_height, double max_height,
cairo_boilerplate_mode_t mode, cairo_boilerplate_mode_t mode,
int id, int id,
void **closure) void **closure)
{ {
*closure = NULL; *closure = NULL;
return _cairo_test_null_surface_create (content); return _cairo_test_traps_compositor_surface_create (content, ceil (width), ceil (height));
}
static cairo_surface_t *
_cairo_boilerplate_test_spans_compositor_create_surface (const char *name,
cairo_content_t content,
double width,
double height,
double max_width,
double max_height,
cairo_boilerplate_mode_t mode,
int id,
void **closure)
{
*closure = NULL;
return _cairo_test_spans_compositor_surface_create (content, ceil (width), ceil (height));
}
static cairo_surface_t *
_cairo_boilerplate_test_no_fallback_compositor_create_surface (const char *name,
cairo_content_t content,
double width,
double height,
double max_width,
double max_height,
cairo_boilerplate_mode_t mode,
int id,
void **closure)
{
*closure = NULL;
return _cairo_test_no_fallback_compositor_surface_create (content, ceil (width), ceil (height));
}
static cairo_surface_t *
_cairo_boilerplate_test_no_traps_compositor_create_surface (const char *name,
cairo_content_t content,
double width,
double height,
double max_width,
double max_height,
cairo_boilerplate_mode_t mode,
int id,
void **closure)
{
*closure = NULL;
return _cairo_test_no_traps_compositor_surface_create (content, ceil (width), ceil (height));
}
static cairo_surface_t *
_cairo_boilerplate_test_no_spans_compositor_create_surface (const char *name,
cairo_content_t content,
double width,
double height,
double max_width,
double max_height,
cairo_boilerplate_mode_t mode,
int id,
void **closure)
{
*closure = NULL;
return _cairo_test_no_spans_compositor_surface_create (content, ceil (width), ceil (height));
} }
#endif
#if CAIRO_HAS_TEST_PAGINATED_SURFACE #if CAIRO_HAS_TEST_PAGINATED_SURFACE
static const cairo_user_data_key_t test_paginated_closure_key; static const cairo_user_data_key_t test_paginated_closure_key;
@ -201,40 +268,38 @@ _cairo_boilerplate_test_paginated_cleanup (void *closure)
} }
#endif #endif
#if CAIRO_HAS_TEST_WRAPPING_SURFACE
static cairo_surface_t *
_cairo_boilerplate_test_wrapping_create_surface (const char *name,
cairo_content_t content,
double width,
double height,
double max_width,
double max_height,
cairo_boilerplate_mode_t mode,
int id,
void **closure)
{
cairo_surface_t *target;
cairo_surface_t *surface;
cairo_format_t format;
*closure = NULL;
format = cairo_boilerplate_format_from_content (content);
target = cairo_image_surface_create (format, ceil (width), ceil (height));
surface = _cairo_test_wrapping_surface_create (target);
cairo_surface_destroy (target);
return surface;
}
#endif
static const cairo_boilerplate_target_t targets[] = { static const cairo_boilerplate_target_t targets[] = {
{ {
"test-fallback", "image", NULL, NULL, "test-base", "image", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK, CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR_ALPHA, 0, CAIRO_CONTENT_COLOR_ALPHA, 0,
"_cairo_test_fallback_surface_create", "_cairo_test_base_compositor_surface_create",
_cairo_boilerplate_test_fallback_create_surface, _cairo_boilerplate_test_base_compositor_create_surface,
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
NULL, NULL, NULL, TRUE, FALSE, FALSE
},
{
"test-base", "image", NULL, NULL,
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR, 0,
"_cairo_test_base_compositor_surface_create",
_cairo_boilerplate_test_base_compositor_create_surface,
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
NULL, NULL, NULL, FALSE, FALSE, FALSE
},
{
"test-fallback", "image", NULL, NULL,
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR_ALPHA, 0,
"_cairo_test_fallback_compositor_surface_create",
_cairo_boilerplate_test_fallback_compositor_create_surface,
cairo_surface_create_similar, cairo_surface_create_similar,
NULL, NULL, NULL, NULL,
_cairo_boilerplate_get_image_surface, _cairo_boilerplate_get_image_surface,
@ -243,10 +308,98 @@ static const cairo_boilerplate_target_t targets[] = {
}, },
{ {
"test-fallback", "image", NULL, NULL, "test-fallback", "image", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK, CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR, 0, CAIRO_CONTENT_COLOR, 0,
"_cairo_test_fallback_surface_create", "_cairo_test_fallback_compositor_surface_create",
_cairo_boilerplate_test_fallback_create_surface, _cairo_boilerplate_test_fallback_compositor_create_surface,
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
NULL, NULL, NULL, FALSE, FALSE, FALSE
},
{
"test-mask", "mask", NULL, NULL,
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR_ALPHA, 0,
"_cairo_test_traps_compositor_surface_create",
_cairo_boilerplate_test_mask_compositor_create_surface,
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
NULL, NULL, NULL, TRUE, FALSE, FALSE
},
{
"test-mask", "mask", NULL, NULL,
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR, 0,
"_cairo_test_mask_compositor_surface_create",
_cairo_boilerplate_test_mask_compositor_create_surface,
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
NULL, NULL, NULL, FALSE, FALSE, FALSE
},
{
"test-traps", "traps", NULL, NULL,
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR_ALPHA, 0,
"_cairo_test_traps_compositor_surface_create",
_cairo_boilerplate_test_traps_compositor_create_surface,
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
NULL, NULL, NULL, TRUE, FALSE, FALSE
},
{
"test-traps", "traps", NULL, NULL,
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR, 0,
"_cairo_test_traps_compositor_surface_create",
_cairo_boilerplate_test_traps_compositor_create_surface,
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
NULL, NULL, NULL, FALSE, FALSE, FALSE
},
{
"test-spans", "spans", NULL, NULL,
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR_ALPHA, 0,
"_cairo_test_spans_compositor_surface_create",
_cairo_boilerplate_test_spans_compositor_create_surface,
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
NULL, NULL, NULL, TRUE, FALSE, FALSE
},
{
"test-spans", "spans", NULL, NULL,
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR, 0,
"_cairo_test_spans_compositor_surface_create",
_cairo_boilerplate_test_spans_compositor_create_surface,
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
NULL, NULL, NULL, FALSE, FALSE, FALSE
},
{
"no-fallback", "image", NULL, NULL,
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR_ALPHA, 0,
"_cairo_test_no_fallback_compositor_surface_create",
_cairo_boilerplate_test_no_fallback_compositor_create_surface,
cairo_surface_create_similar, cairo_surface_create_similar,
NULL, NULL, NULL, NULL,
_cairo_boilerplate_get_image_surface, _cairo_boilerplate_get_image_surface,
@ -254,28 +407,28 @@ static const cairo_boilerplate_target_t targets[] = {
NULL, NULL, NULL, FALSE, FALSE, FALSE NULL, NULL, NULL, FALSE, FALSE, FALSE
}, },
{ {
"test-fallback16", "image", NULL, NULL, "no-traps", "traps", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK, CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR_ALPHA, 0, CAIRO_CONTENT_COLOR_ALPHA, 0,
"_cairo_test_fallback16_surface_create", "_cairo_test_no_traps_compositor_surface_create",
_cairo_boilerplate_test_fallback16_create_surface, _cairo_boilerplate_test_no_traps_compositor_create_surface,
cairo_surface_create_similar, cairo_surface_create_similar,
NULL, NULL, NULL, NULL,
NULL, /* _cairo_boilerplate_get_image_surface, */ _cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png, cairo_surface_write_to_png,
NULL, NULL, NULL, FALSE, FALSE, FALSE NULL, NULL, NULL, TRUE, FALSE, FALSE
}, },
{ {
"test-fallback16", "image", NULL, NULL, "no-spans", "spans", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK, CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR, 0, CAIRO_CONTENT_COLOR_ALPHA, 0,
"_cairo_test_fallback16_surface_create", "_cairo_test_no_spans_compositor_surface_create",
_cairo_boilerplate_test_fallback16_create_surface, _cairo_boilerplate_test_no_spans_compositor_create_surface,
cairo_surface_create_similar, cairo_surface_create_similar,
NULL, NULL, NULL, NULL,
NULL, /* _cairo_boilerplate_get_image_surface, */ _cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png, cairo_surface_write_to_png,
NULL, NULL, NULL, FALSE, FALSE, FALSE NULL, NULL, NULL, TRUE, FALSE, FALSE
}, },
#if CAIRO_HAS_TEST_PAGINATED_SURFACE #if CAIRO_HAS_TEST_PAGINATED_SURFACE
{ {
@ -305,33 +458,5 @@ static const cairo_boilerplate_target_t targets[] = {
NULL, NULL, FALSE, TRUE, FALSE NULL, NULL, FALSE, TRUE, FALSE
}, },
#endif #endif
#if CAIRO_HAS_TEST_WRAPPING_SURFACE
{
"test-wrapping", "image", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING,
CAIRO_CONTENT_COLOR_ALPHA, 0,
"_cairo_test_wrapping_surface_create",
_cairo_boilerplate_test_wrapping_create_surface,
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
NULL, NULL, NULL, FALSE, FALSE, FALSE
},
#endif
#if CAIRO_HAS_TEST_NULL_SURFACE
{
"null", "image", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
CAIRO_CONTENT_COLOR_ALPHA, 0,
"_cairo_test_null_surface_create",
_cairo_boilerplate_test_null_create_surface,
cairo_surface_create_similar,
NULL, NULL,
NULL, NULL, NULL,
NULL, NULL,
TRUE, TRUE, FALSE
},
#endif
}; };
CAIRO_BOILERPLATE (test, targets) CAIRO_BOILERPLATE (test, targets)

View file

@ -31,7 +31,6 @@
#if CAIRO_HAS_XLIB_XRENDER_SURFACE #if CAIRO_HAS_XLIB_XRENDER_SURFACE
#include <cairo-xlib-xrender.h> #include <cairo-xlib-xrender.h>
#endif #endif
#include <cairo-xlib-surface-private.h>
#include <X11/Xutil.h> /* for XDestroyImage */ #include <X11/Xutil.h> /* for XDestroyImage */
@ -412,6 +411,7 @@ _cairo_boilerplate_xlib_window_create_surface (const char *name,
cairo_status_t cairo_status_t
cairo_boilerplate_xlib_surface_disable_render (cairo_surface_t *abstract_surface) cairo_boilerplate_xlib_surface_disable_render (cairo_surface_t *abstract_surface)
{ {
#if 0
/* The following stunt doesn't work with xlib-xcb because it doesn't use /* The following stunt doesn't work with xlib-xcb because it doesn't use
* cairo_xlib_surface_t for its surfaces. Sadly, there is no sane * cairo_xlib_surface_t for its surfaces. Sadly, there is no sane
* alternative, so we can't disable render with xlib-xcb. * alternative, so we can't disable render with xlib-xcb.
@ -439,6 +439,7 @@ cairo_boilerplate_xlib_surface_disable_render (cairo_surface_t *abstract_surface
#if CAIRO_XLIB_SURFACE_HAS_BUGGY_REPEAT #if CAIRO_XLIB_SURFACE_HAS_BUGGY_REPEAT
surface->buggy_repeat = TRUE; surface->buggy_repeat = TRUE;
#endif #endif
#endif
#endif #endif
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;

View file

@ -683,16 +683,12 @@ cairo_boilerplate_get_image_target (cairo_content_t content)
if (cairo_boilerplate_targets == NULL) if (cairo_boilerplate_targets == NULL)
_cairo_boilerplate_register_all (); _cairo_boilerplate_register_all ();
for (list = cairo_boilerplate_targets; list != NULL; list = list->next) { switch (content) {
const cairo_boilerplate_target_t *target = list->target; default:
if (target->expected_type == CAIRO_SURFACE_TYPE_IMAGE && case CAIRO_CONTENT_ALPHA: return NULL;
target->content == content) case CAIRO_CONTENT_COLOR: return &builtin_targets[1];
{ case CAIRO_CONTENT_COLOR_ALPHA: return &builtin_targets[0];
return target;
}
} }
return NULL;
} }
const cairo_boilerplate_target_t * const cairo_boilerplate_target_t *

View file

@ -202,11 +202,11 @@ CAIRO_ENABLE_SURFACE_BACKEND(skia, Skia, no, [
[skia_DIR="`pwd`/../skia"]) [skia_DIR="`pwd`/../skia"])
AC_ARG_WITH([skia-bulid], AC_ARG_WITH([skia-bulid],
[AS_HELP_STRING([--with-skia-build=(Release|Debug)] [AS_HELP_STRING([--with-skia-build=(Release|Debug)]
[build of skia to link with, default is Relese])], [build of skia to link with, default is Release])],
[skia_BUILD="$withval"], [skia_BUILD="$withval"],
[skia_BUILD="Release"]) [skia_BUILD="Release"])
skia_NONPKGCONFIG_CFLAGS="-I$skia_DIR/include/config -I$skia_DIR/include/core -I$skia_DIR/include/effects" skia_NONPKGCONFIG_CFLAGS="-I$skia_DIR/include/config -I$skia_DIR/include/core -I$skia_DIR/include/effects"
if test "x$(skia_BUILD)" = x"Relese"; then if test "x$skia_BUILD" = x"Release"; then
skia_NONPKGCONFIG_CFLAGS="-DSK_RELEASE -DSK_CAN_USE_FLOAT $skia_NONPKGCONFIG_CFLAGS" skia_NONPKGCONFIG_CFLAGS="-DSK_RELEASE -DSK_CAN_USE_FLOAT $skia_NONPKGCONFIG_CFLAGS"
fi fi
skia_NONPKGCONFIG_LIBS="--start-group $skia_DIR/out/$skia_BUILD/obj.target/gyp/libeffects.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libimages.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libutils.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libopts.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libcore.a -end-group" skia_NONPKGCONFIG_LIBS="--start-group $skia_DIR/out/$skia_BUILD/obj.target/gyp/libeffects.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libimages.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libutils.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libopts.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libcore.a -end-group"

View file

@ -1,5 +1,6 @@
libcairoperf_sources = \ libcairoperf_sources = \
cairo-perf.c \ cairo-perf.c \
cairo-perf-report.c \
cairo-stats.c \ cairo-stats.c \
$(NULL) $(NULL)

View file

@ -73,7 +73,7 @@ print_change_bar (double change,
double max_change, double max_change,
int use_utf) int use_utf)
{ {
int units_per_cell = (int) ceil (max_change / CHANGE_BAR_WIDTH); int units_per_cell = ceil (max_change / CHANGE_BAR_WIDTH);
static char const *ascii_boxes[8] = { static char const *ascii_boxes[8] = {
"****","***" ,"***", "**", "****","***" ,"***", "**",
"**", "*", "*", "" "**", "*", "*", ""
@ -369,7 +369,7 @@ main (int argc,
if (args.num_filenames) { if (args.num_filenames) {
reports = xcalloc (args.num_filenames, sizeof (cairo_perf_report_t)); reports = xcalloc (args.num_filenames, sizeof (cairo_perf_report_t));
for (i = 0; i < args.num_filenames; i++) { for (i = 0; i < args.num_filenames; i++) {
cairo_perf_report_load (&reports[i], args.filenames[i], cairo_perf_report_load (&reports[i], args.filenames[i], i,
test_report_cmp_name); test_report_cmp_name);
printf ("loaded: %s, %d tests\n", printf ("loaded: %s, %d tests\n",
args.filenames[i], reports[i].tests_count); args.filenames[i], reports[i].tests_count);
@ -377,7 +377,7 @@ main (int argc,
} else { } else {
args.num_filenames = 1; args.num_filenames = 1;
reports = xcalloc (args.num_filenames, sizeof (cairo_perf_report_t)); reports = xcalloc (args.num_filenames, sizeof (cairo_perf_report_t));
cairo_perf_report_load (&reports[0], NULL, test_report_cmp_name); cairo_perf_report_load (&reports[0], NULL, 0, test_report_cmp_name);
} }
cairo_perf_reports_compare (reports, args.num_filenames, &args.options); cairo_perf_reports_compare (reports, args.num_filenames, &args.options);

View file

@ -161,16 +161,14 @@ test_diff_print_binary (test_diff_t *diff,
else else
printf ("%5s %26s", diff->tests[0]->backend, diff->tests[0]->name); printf ("%5s %26s", diff->tests[0]->backend, diff->tests[0]->name);
if (diff->tests[0]->size) { printf (" %6.2f (%.2f %4.2f%%) -> %6.2f (%.2f %4.2f%%): %5.2fx ",
printf (" %6.2f (%.2f %4.2f%%) -> %6.2f (%.2f %4.2f%%): %5.2fx ", diff->tests[0]->stats.min_ticks / diff->tests[0]->stats.ticks_per_ms,
diff->tests[0]->stats.min_ticks / diff->tests[0]->stats.ticks_per_ms, diff->tests[0]->stats.median_ticks / diff->tests[0]->stats.ticks_per_ms,
diff->tests[0]->stats.median_ticks / diff->tests[0]->stats.ticks_per_ms, diff->tests[0]->stats.std_dev * 100,
diff->tests[0]->stats.std_dev * 100, diff->tests[1]->stats.min_ticks / diff->tests[1]->stats.ticks_per_ms,
diff->tests[1]->stats.min_ticks / diff->tests[1]->stats.ticks_per_ms, diff->tests[1]->stats.median_ticks / diff->tests[1]->stats.ticks_per_ms,
diff->tests[1]->stats.median_ticks / diff->tests[1]->stats.ticks_per_ms, diff->tests[1]->stats.std_dev * 100,
diff->tests[1]->stats.std_dev * 100, fabs (diff->change));
fabs (diff->change));
}
if (diff->change > 1.0) if (diff->change > 1.0)
printf ("speedup\n"); printf ("speedup\n");
@ -191,24 +189,32 @@ test_diff_print_multi (test_diff_t *diff,
double test_time; double test_time;
double change; double change;
printf ("%s (backend: %s-%s, size: %d)\n", if (diff->tests[0]->size) {
diff->tests[0]->name, printf ("%s (backend: %s-%s, size: %d)\n",
diff->tests[0]->backend, diff->tests[0]->name,
diff->tests[0]->content, diff->tests[0]->backend,
diff->tests[0]->size); diff->tests[0]->content,
diff->tests[0]->size);
} else {
printf ("%s (backend: %s)\n",
diff->tests[0]->name,
diff->tests[0]->backend);
}
for (i = 0; i < diff->num_tests; i++) { for (i = 0; i < diff->num_tests; i++) {
test_time = diff->tests[i]->stats.min_ticks; test_time = diff->tests[i]->stats.min_ticks;
if (! options->use_ticks) if (! options->use_ticks)
test_time /= diff->tests[i]->stats.ticks_per_ms; test_time /= diff->tests[i]->stats.ticks_per_ms;
change = diff->max / test_time; change = diff->max / test_time;
printf ("%8s %6.2f: %5.2fx ", printf ("[%d] %6.2f: %5.2fx ",
diff->tests[i]->configuration, diff->tests[i]->fileno,
diff->tests[i]->stats.min_ticks / diff->tests[i]->stats.ticks_per_ms, diff->tests[i]->stats.min_ticks / diff->tests[i]->stats.ticks_per_ms,
change); change);
if (options->print_change_bars) if (options->print_change_bars)
print_change_bar (change, max_change, options->use_utf); print_change_bar (change, max_change, options->use_utf);
else
printf("\n");
} }
printf("\n"); printf("\n");
@ -476,8 +482,11 @@ main (int argc,
reports = xmalloc (args.num_filenames * sizeof (cairo_perf_report_t)); reports = xmalloc (args.num_filenames * sizeof (cairo_perf_report_t));
for (i = 0; i < args.num_filenames; i++ ) for (i = 0; i < args.num_filenames; i++ ) {
cairo_perf_report_load (&reports[i], args.filenames[i], NULL); cairo_perf_report_load (&reports[i], args.filenames[i], i, NULL);
printf ("[%d] %s\n", i, args.filenames[i]);
}
printf ("\n");
cairo_perf_reports_compare (reports, args.num_filenames, &args.options); cairo_perf_reports_compare (reports, args.num_filenames, &args.options);

View file

@ -50,12 +50,13 @@
#define CAIRO_PERF_ITERATIONS_DEFAULT 100 #define CAIRO_PERF_ITERATIONS_DEFAULT 100
#define CAIRO_PERF_LOW_STD_DEV 0.03 #define CAIRO_PERF_LOW_STD_DEV 0.03
#define CAIRO_PERF_STABLE_STD_DEV_COUNT 5 #define CAIRO_PERF_STABLE_STD_DEV_COUNT 5
#define CAIRO_PERF_ITERATION_MS_DEFAULT 2000 #define CAIRO_PERF_ITERATION_MS_DEFAULT 2000
#define CAIRO_PERF_ITERATION_MS_FAST 5 #define CAIRO_PERF_ITERATION_MS_FAST 5
typedef struct _cairo_perf_case { typedef struct _cairo_perf_case {
CAIRO_PERF_DECL (*run); CAIRO_PERF_RUN_DECL (*run);
cairo_bool_t (*enabled) (cairo_perf_t *perf);
unsigned int min_size; unsigned int min_size;
unsigned int max_size; unsigned int max_size;
} cairo_perf_case_t; } cairo_perf_case_t;
@ -251,7 +252,7 @@ cairo_perf_run (cairo_perf_t *perf,
cairo_boilerplate_content (perf->target->content)); cairo_boilerplate_content (perf->target->content));
else else
cairo_save (perf->cr); cairo_save (perf->cr);
times[i] = perf_func (perf->cr, perf->size, perf->size, loops) / loops; times[i] = perf_func (perf->cr, perf->size, perf->size, loops) ;
if (similar) if (similar)
cairo_pattern_destroy (cairo_pop_group (perf->cr)); cairo_pattern_destroy (cairo_pop_group (perf->cr));
else else
@ -263,7 +264,7 @@ cairo_perf_run (cairo_perf_t *perf,
_content_to_string (perf->target->content, similar), _content_to_string (perf->target->content, similar),
name, perf->size, name, perf->size,
_cairo_time_to_double (_cairo_time_from_s (1.)) / 1000.); _cairo_time_to_double (_cairo_time_from_s (1.)) / 1000.);
printf (" %lld", (long long) times[i]); printf (" %lld", (long long) (times[i] / (double) loops));
} else if (! perf->exact_iterations) { } else if (! perf->exact_iterations) {
if (i > 0) { if (i > 0) {
_cairo_stats_compute (&stats, times, i+1); _cairo_stats_compute (&stats, times, i+1);
@ -287,18 +288,18 @@ cairo_perf_run (cairo_perf_t *perf,
if (count_func != NULL) { if (count_func != NULL) {
double count = count_func (perf->cr, perf->size, perf->size); double count = count_func (perf->cr, perf->size, perf->size);
fprintf (perf->summary, fprintf (perf->summary,
"%10lld %#8.3f %#8.3f %#5.2f%% %3d: %.2f\n", "%10lld/%d %#8.3f %#8.3f %#5.2f%% %3d: %.2f\n",
(long long) stats.min_ticks, (long long) stats.min_ticks, loops,
_cairo_time_to_s (stats.min_ticks) * 1000.0, _cairo_time_to_s (stats.min_ticks) * 1000.0 / loops,
_cairo_time_to_s (stats.median_ticks) * 1000.0, _cairo_time_to_s (stats.median_ticks) * 1000.0 / loops,
stats.std_dev * 100.0, stats.iterations, stats.std_dev * 100.0, stats.iterations,
count / _cairo_time_to_s (stats.min_ticks)); count / _cairo_time_to_s (stats.min_ticks));
} else { } else {
fprintf (perf->summary, fprintf (perf->summary,
"%10lld %#8.3f %#8.3f %#5.2f%% %3d\n", "%10lld/%d %#8.3f %#8.3f %#5.2f%% %3d\n",
(long long) stats.min_ticks, (long long) stats.min_ticks, loops,
_cairo_time_to_s (stats.min_ticks) * 1000.0, _cairo_time_to_s (stats.min_ticks) * 1000.0 / loops,
_cairo_time_to_s (stats.median_ticks) * 1000.0, _cairo_time_to_s (stats.median_ticks) * 1000.0 / loops,
stats.std_dev * 100.0, stats.iterations); stats.std_dev * 100.0, stats.iterations);
} }
fflush (perf->summary); fflush (perf->summary);
@ -491,6 +492,9 @@ main (int argc,
for (j = 0; perf_cases[j].run; j++) { for (j = 0; perf_cases[j].run; j++) {
const cairo_perf_case_t *perf_case = &perf_cases[j]; const cairo_perf_case_t *perf_case = &perf_cases[j];
if (! perf_case->enabled (&perf))
continue;
for (perf.size = perf_case->min_size; for (perf.size = perf_case->min_size;
perf.size <= perf_case->max_size; perf.size <= perf_case->max_size;
perf.size *= 2) perf.size *= 2)
@ -536,42 +540,48 @@ main (int argc,
return 0; return 0;
} }
#define FUNC(f) f, f##_enabled
const cairo_perf_case_t perf_cases[] = { const cairo_perf_case_t perf_cases[] = {
{ paint, 64, 512}, { FUNC(pixel), 1, 1 },
{ paint_with_alpha, 64, 512}, { FUNC(paint), 64, 512},
{ fill, 64, 512}, { FUNC(paint_with_alpha), 64, 512},
{ stroke, 64, 512}, { FUNC(fill), 64, 512},
{ text, 64, 512}, { FUNC(stroke), 64, 512},
{ glyphs, 64, 512}, { FUNC(text), 64, 512},
{ mask, 64, 512}, { FUNC(glyphs), 64, 512},
{ line, 32, 512}, { FUNC(mask), 64, 512},
{ curve, 32, 512}, { FUNC(line), 32, 512},
{ disjoint, 64, 512}, { FUNC(a1_line), 32, 512},
{ hatching, 64, 512}, { FUNC(curve), 32, 512},
{ tessellate, 100, 100}, { FUNC(a1_curve), 32, 512},
{ subimage_copy, 16, 512}, { FUNC(disjoint), 64, 512},
{ hash_table, 16, 16}, { FUNC(hatching), 64, 512},
{ pattern_create_radial, 16, 16}, { FUNC(tessellate), 100, 100},
{ zrusin, 415, 415}, { FUNC(subimage_copy), 16, 512},
{ world_map, 800, 800}, { FUNC(hash_table), 16, 16},
{ box_outline, 100, 100}, { FUNC(pattern_create_radial), 16, 16},
{ mosaic, 800, 800 }, { FUNC(zrusin), 415, 415},
{ long_lines, 100, 100}, { FUNC(world_map), 800, 800},
{ unaligned_clip, 100, 100}, { FUNC(box_outline), 100, 100},
{ rectangles, 512, 512}, { FUNC(mosaic), 800, 800 },
{ rounded_rectangles, 512, 512}, { FUNC(long_lines), 100, 100},
{ long_dashed_lines, 512, 512}, { FUNC(unaligned_clip), 100, 100},
{ composite_checker, 16, 512}, { FUNC(rectangles), 512, 512},
{ twin, 800, 800}, { FUNC(rounded_rectangles), 512, 512},
{ dragon, 1024, 1024 }, { FUNC(long_dashed_lines), 512, 512},
{ pythagoras_tree, 768, 768 }, { FUNC(composite_checker), 16, 512},
{ intersections, 512, 512 }, { FUNC(twin), 800, 800},
{ many_strokes, 32, 512 }, { FUNC(dragon), 1024, 1024 },
{ wide_strokes, 32, 512 }, { FUNC(sierpinski), 32, 1024 },
{ many_fills, 32, 512 }, { FUNC(pythagoras_tree), 768, 768 },
{ wide_fills, 32, 512 }, { FUNC(intersections), 512, 512 },
{ many_curves, 32, 512 }, { FUNC(many_strokes), 32, 512 },
{ spiral, 512, 512 }, { FUNC(wide_strokes), 32, 512 },
{ wave, 500, 500 }, { FUNC(many_fills), 32, 512 },
{ FUNC(wide_fills), 32, 512 },
{ FUNC(many_curves), 32, 512 },
{ FUNC(spiral), 512, 512 },
{ FUNC(wave), 500, 500 },
{ FUNC(fill_clip), 16, 512 },
{ NULL } { NULL }
}; };

View file

@ -110,6 +110,7 @@ do { \
static test_report_status_t static test_report_status_t
test_report_parse (test_report_t *report, test_report_parse (test_report_t *report,
int fileno,
char *line, char *line,
char *configuration) char *configuration)
{ {
@ -137,6 +138,7 @@ test_report_parse (test_report_t *report,
skip_space (); skip_space ();
report->fileno = fileno;
report->configuration = configuration; report->configuration = configuration;
parse_string (report->backend); parse_string (report->backend);
end = strrchr (report->backend, '.'); end = strrchr (report->backend, '.');
@ -369,7 +371,7 @@ cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report,
void void
cairo_perf_report_load (cairo_perf_report_t *report, cairo_perf_report_load (cairo_perf_report_t *report,
const char *filename, const char *filename, int id,
int (*cmp) (const void *, const void *)) int (*cmp) (const void *, const void *))
{ {
FILE *file; FILE *file;
@ -401,6 +403,7 @@ cairo_perf_report_load (cairo_perf_report_t *report,
report->tests_size = 16; report->tests_size = 16;
report->tests = xmalloc (report->tests_size * sizeof (test_report_t)); report->tests = xmalloc (report->tests_size * sizeof (test_report_t));
report->tests_count = 0; report->tests_count = 0;
report->fileno = id;
if (filename == NULL) { if (filename == NULL) {
file = stdin; file = stdin;
@ -425,7 +428,7 @@ cairo_perf_report_load (cairo_perf_report_t *report,
break; break;
status = test_report_parse (&report->tests[report->tests_count], status = test_report_parse (&report->tests[report->tests_count],
line, report->configuration); id, line, report->configuration);
if (status == TEST_REPORT_STATUS_ERROR) if (status == TEST_REPORT_STATUS_ERROR)
fprintf (stderr, "Ignoring unrecognized line %d of %s:\n%s", fprintf (stderr, "Ignoring unrecognized line %d of %s:\n%s",
line_number, filename, line); line_number, filename, line);

View file

@ -79,7 +79,7 @@ basename_no_ext (char *path)
name = basename (path); name = basename (path);
dot = strchr (name, '.'); dot = strrchr (name, '.');
if (dot) if (dot)
*dot = '\0'; *dot = '\0';
@ -108,6 +108,7 @@ struct trace {
void *closure; void *closure;
cairo_surface_t *surface; cairo_surface_t *surface;
cairo_bool_t observe; cairo_bool_t observe;
int tile_size;
}; };
cairo_bool_t cairo_bool_t
@ -132,7 +133,7 @@ cairo_perf_can_run (cairo_perf_t *perf,
return TRUE; return TRUE;
copy = xstrdup (name); copy = xstrdup (name);
dot = strchr (copy, '.'); dot = strrchr (copy, '.');
if (dot != NULL) if (dot != NULL)
*dot = '\0'; *dot = '\0';
@ -435,6 +436,7 @@ parse_options (cairo_perf_t *perf,
perf->raw = FALSE; perf->raw = FALSE;
perf->observe = FALSE; perf->observe = FALSE;
perf->list_only = FALSE; perf->list_only = FALSE;
perf->tile_size = 0;
perf->names = NULL; perf->names = NULL;
perf->num_names = 0; perf->num_names = 0;
perf->summary = stdout; perf->summary = stdout;
@ -443,7 +445,7 @@ parse_options (cairo_perf_t *perf,
perf->num_exclude_names = 0; perf->num_exclude_names = 0;
while (1) { while (1) {
c = _cairo_getopt (argc, argv, "i:x:lsrvc"); c = _cairo_getopt (argc, argv, "t:i:x:lsrvc");
if (c == -1) if (c == -1)
break; break;
@ -457,6 +459,14 @@ parse_options (cairo_perf_t *perf,
exit (1); exit (1);
} }
break; break;
case 't':
perf->tile_size = strtoul (optarg, &end, 10);
if (*end != '\0') {
fprintf (stderr, "Invalid argument for -t (not an integer): %s\n",
optarg);
exit (1);
}
break;
case 'l': case 'l':
perf->list_only = TRUE; perf->list_only = TRUE;
break; break;
@ -489,6 +499,11 @@ parse_options (cairo_perf_t *perf,
} }
} }
if (perf->observe && perf->tile_size) {
fprintf (stderr, "Can't mix observer and tiling. Sorry.\n");
exit (1);
}
if (verbose && perf->summary == NULL) if (verbose && perf->summary == NULL)
perf->summary = stderr; perf->summary = stderr;
#if HAVE_UNISTD_H #if HAVE_UNISTD_H
@ -535,6 +550,79 @@ have_trace_filenames (cairo_perf_t *perf)
return FALSE; return FALSE;
} }
static void
_tiling_surface_finish (cairo_surface_t *observer,
cairo_surface_t *target,
void *closure)
{
struct trace *args = closure;
cairo_surface_t *surface;
cairo_content_t content;
cairo_rectangle_t r;
int width, height;
int x, y, w, h;
cairo_recording_surface_get_extents (target, &r);
w = r.width;
h = r.height;
content = cairo_surface_get_content (target);
for (y = 0; y < h; y += args->tile_size) {
height = args->tile_size;
if (y + height > h)
height = h - y;
for (x = 0; x < w; x += args->tile_size) {
cairo_t *cr;
width = args->tile_size;
if (x + width > w)
width = w - x;
/* XXX to correctly observe the playback we would need
* to replay the target onto the observer directly.
*/
surface = args->target->create_similar (args->surface,
content, width, height);
cr = cairo_create (surface);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_surface (cr, target, -x, -y);
cairo_paint (cr);
cairo_destroy (cr);
cairo_surface_destroy (surface);
}
}
}
static cairo_surface_t *
_tiling_surface_create (void *closure,
cairo_content_t content,
double width,
double height,
long uid)
{
cairo_rectangle_t r;
cairo_surface_t *surface, *observer;
r.x = r.y = 0;
r.width = width;
r.height = height;
surface = cairo_recording_surface_create (content, &r);
observer = cairo_surface_create_observer (surface,
CAIRO_SURFACE_OBSERVER_NORMAL);
cairo_surface_destroy (surface);
cairo_surface_observer_add_finish_callback (observer,
_tiling_surface_finish,
closure);
return observer;
}
static void static void
cairo_perf_trace (cairo_perf_t *perf, cairo_perf_trace (cairo_perf_t *perf,
const cairo_boilerplate_target_t *target, const cairo_boilerplate_target_t *target,
@ -549,7 +637,7 @@ cairo_perf_trace (cairo_perf_t *perf,
char *trace_cpy, *name; char *trace_cpy, *name;
const cairo_script_interpreter_hooks_t hooks = { const cairo_script_interpreter_hooks_t hooks = {
&args, &args,
_similar_surface_create, perf->tile_size ? _tiling_surface_create : _similar_surface_create,
NULL, /* surface_destroy */ NULL, /* surface_destroy */
_context_create, _context_create,
NULL, /* context_destroy */ NULL, /* context_destroy */
@ -557,6 +645,7 @@ cairo_perf_trace (cairo_perf_t *perf,
NULL /* copy_page */ NULL /* copy_page */
}; };
args.tile_size = perf->tile_size;
args.observe = perf->observe; args.observe = perf->observe;
trace_cpy = xstrdup (trace); trace_cpy = xstrdup (trace);
@ -648,26 +737,30 @@ cairo_perf_trace (cairo_perf_t *perf,
} }
cairo_script_interpreter_run (csi, trace); cairo_script_interpreter_run (csi, trace);
line_no = cairo_script_interpreter_get_line_number (csi);
/* Finish before querying timings in case we are using an intermediate
* target and so need to destroy all surfaces before rendering
* commences.
*/
cairo_script_interpreter_finish (csi);
if (perf->observe) { if (perf->observe) {
cairo_device_t *observer = cairo_surface_get_device (args.surface); cairo_device_t *observer = cairo_surface_get_device (args.surface);
times[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_elapsed (observer)); times[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_elapsed (observer));
paint[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_paint_elapsed (observer)); paint[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_paint_elapsed (observer));
mask[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_mask_elapsed (observer)); mask[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_mask_elapsed (observer));
stroke[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_stroke_elapsed (observer)); stroke[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_stroke_elapsed (observer));
fill[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_fill_elapsed (observer)); fill[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_fill_elapsed (observer));
glyphs[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_glyphs_elapsed (observer)); glyphs[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_glyphs_elapsed (observer));
} else { } else {
clear_surface (args.surface); /* queue a write to the sync'ed surface */ clear_surface (args.surface); /* queue a write to the sync'ed surface */
cairo_perf_timer_stop (); cairo_perf_timer_stop ();
times[i] = cairo_perf_timer_elapsed (); times[i] = cairo_perf_timer_elapsed ();
} }
cairo_script_interpreter_finish (csi);
scache_clear (); scache_clear ();
line_no = cairo_script_interpreter_get_line_number (csi);
cairo_surface_destroy (args.surface); cairo_surface_destroy (args.surface);
if (target->cleanup) if (target->cleanup)
@ -766,28 +859,28 @@ cairo_perf_trace (cairo_perf_t *perf,
fprintf (perf->summary, fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks)); " %#9.3f", _cairo_time_to_s (stats.median_ticks));
_cairo_stats_compute (&stats, paint, i+1); _cairo_stats_compute (&stats, paint, i);
fprintf (perf->summary, fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks)); " %#9.3f", _cairo_time_to_s (stats.median_ticks));
_cairo_stats_compute (&stats, mask, i+1); _cairo_stats_compute (&stats, mask, i);
fprintf (perf->summary, fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks)); " %#9.3f", _cairo_time_to_s (stats.median_ticks));
_cairo_stats_compute (&stats, fill, i+1); _cairo_stats_compute (&stats, fill, i);
fprintf (perf->summary, fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks)); " %#9.3f", _cairo_time_to_s (stats.median_ticks));
_cairo_stats_compute (&stats, stroke, i+1); _cairo_stats_compute (&stats, stroke, i);
fprintf (perf->summary, fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks)); " %#9.3f", _cairo_time_to_s (stats.median_ticks));
_cairo_stats_compute (&stats, glyphs, i+1); _cairo_stats_compute (&stats, glyphs, i);
fprintf (perf->summary, fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks)); " %#9.3f", _cairo_time_to_s (stats.median_ticks));
fprintf (perf->summary, fprintf (perf->summary,
" %5d\n", i+1); " %5d\n", i);
} else { } else {
fprintf (perf->summary, fprintf (perf->summary,
"%#8.3f %#8.3f %#6.2f%% %4d/%d\n", "%#8.3f %#8.3f %#6.2f%% %4d/%d\n",
@ -807,11 +900,6 @@ out:
perf->test_number++; perf->test_number++;
free (trace_cpy); free (trace_cpy);
cairo_debug_reset_static_data ();
#if HAVE_FCFINI
FcFini ();
#endif
} }
static void static void

View file

@ -83,6 +83,8 @@ typedef struct _cairo_perf {
double ms_per_iteration; double ms_per_iteration;
cairo_bool_t fast_and_sloppy; cairo_bool_t fast_and_sloppy;
unsigned int tile_size;
/* Stuff used internally */ /* Stuff used internally */
cairo_time_t *times; cairo_time_t *times;
const cairo_boilerplate_target_t **targets; const cairo_boilerplate_target_t **targets;
@ -121,6 +123,7 @@ cairo_perf_cover_sources_and_operators (cairo_perf_t *perf,
typedef struct _test_report { typedef struct _test_report {
int id; int id;
int fileno;
const char *configuration; const char *configuration;
char *backend; char *backend;
char *content; char *content;
@ -149,6 +152,7 @@ typedef struct _test_diff {
typedef struct _cairo_perf_report { typedef struct _cairo_perf_report {
char *configuration; char *configuration;
const char *name; const char *name;
int fileno;
test_report_t *tests; test_report_t *tests;
int tests_size; int tests_size;
int tests_count; int tests_count;
@ -162,7 +166,7 @@ typedef enum {
void void
cairo_perf_report_load (cairo_perf_report_t *report, cairo_perf_report_load (cairo_perf_report_t *report,
const char *filename, const char *filename, int id,
int (*cmp) (const void *, const void *)); int (*cmp) (const void *, const void *));
void void
@ -177,7 +181,10 @@ int
test_report_cmp_name (const void *a, test_report_cmp_name (const void *a,
const void *b); const void *b);
#define CAIRO_PERF_DECL(func) void (func) (cairo_perf_t *perf, cairo_t *cr, int width, int height) #define CAIRO_PERF_ENABLED_DECL(func) cairo_bool_t (func ## _enabled) (cairo_perf_t *perf)
#define CAIRO_PERF_RUN_DECL(func) void (func) (cairo_perf_t *perf, cairo_t *cr, int width, int height)
#define CAIRO_PERF_DECL(func) CAIRO_PERF_RUN_DECL(func); CAIRO_PERF_ENABLED_DECL(func)
CAIRO_PERF_DECL (fill); CAIRO_PERF_DECL (fill);
CAIRO_PERF_DECL (paint); CAIRO_PERF_DECL (paint);
@ -214,6 +221,11 @@ CAIRO_PERF_DECL (many_fills);
CAIRO_PERF_DECL (wide_fills); CAIRO_PERF_DECL (wide_fills);
CAIRO_PERF_DECL (many_curves); CAIRO_PERF_DECL (many_curves);
CAIRO_PERF_DECL (curve); CAIRO_PERF_DECL (curve);
CAIRO_PERF_DECL (a1_curve);
CAIRO_PERF_DECL (line); CAIRO_PERF_DECL (line);
CAIRO_PERF_DECL (a1_line);
CAIRO_PERF_DECL (pixel);
CAIRO_PERF_DECL (sierpinski);
CAIRO_PERF_DECL (fill_clip);
#endif #endif

View file

@ -25,16 +25,25 @@
#include "cairo-stats.h" #include "cairo-stats.h"
#include <assert.h>
void void
_cairo_stats_compute (cairo_stats_t *stats, _cairo_stats_compute (cairo_stats_t *stats,
cairo_time_t *values, cairo_time_t *values,
int num_values) int num_values)
{ {
int i; cairo_time_t sum, mean, delta, q1, q3, iqr;
cairo_time_t sumtime; cairo_time_t outlier_min, outlier_max;
double sum, mean, delta, q1, q3, iqr; int i, min_valid, num_valid;
double outlier_min, outlier_max;
int min_valid, num_valid; assert (num_values > 0);
if (num_values == 1) {
stats->min_ticks = stats->median_ticks = values[0];
stats->std_dev = 0;
stats->iterations = 1;
return;
}
/* First, identify any outliers, using the definition of "mild /* First, identify any outliers, using the definition of "mild
* outliers" from: * outliers" from:
@ -48,44 +57,35 @@ _cairo_stats_compute (cairo_stats_t *stats,
*/ */
qsort (values, num_values, sizeof (cairo_time_t), _cairo_time_cmp); qsort (values, num_values, sizeof (cairo_time_t), _cairo_time_cmp);
q1 = _cairo_time_to_s (values[(1*num_values)/4]); q1 = values[1*num_values/4];
q3 = _cairo_time_to_s (values[(3*num_values)/4]); q3 = values[3*num_values/4];
/* XXX assumes we have native uint64_t */
iqr = q3 - q1; iqr = q3 - q1;
outlier_min = q1 - 3 * iqr / 2;
outlier_max = q3 + 3 * iqr / 2;
outlier_min = _cairo_time_from_s (q1 - 1.5 * iqr); for (i = 0; i < num_values && values[i] < outlier_min; i++)
outlier_max = _cairo_time_from_s (q3 + 1.5 * iqr); ;
min_valid = i;
min_valid = 0; for (i = 0; i < num_values && values[i] <= outlier_max; i++)
while (min_valid < num_values && ;
_cairo_time_to_s (values[min_valid]) < outlier_min) num_valid = i - min_valid;
{ assert(num_valid);
min_valid++;
}
i = min_valid;
num_valid = 0;
while (i + num_valid < num_values &&
_cairo_time_to_s (values[i+num_valid]) <= outlier_max)
{
num_valid++;
}
stats->iterations = num_valid; stats->iterations = num_valid;
stats->min_ticks = values[min_valid]; stats->min_ticks = values[min_valid];
sumtime = _cairo_time_from_s (0);
for (i = min_valid; i < min_valid + num_valid; i++) {
sumtime = _cairo_time_add (sumtime, values[i]);
stats->min_ticks = _cairo_time_min (stats->min_ticks, values[i]);
}
mean = _cairo_time_to_s (sumtime) / num_valid;
stats->median_ticks = values[min_valid + num_valid / 2]; stats->median_ticks = values[min_valid + num_valid / 2];
sum = 0.0; sum = 0;
for (i = min_valid; i < min_valid + num_valid; i++)
sum = _cairo_time_add (sum, values[i]);
mean = sum / num_valid;
sum = 0;
for (i = min_valid; i < min_valid + num_valid; i++) { for (i = min_valid; i < min_valid + num_valid; i++) {
delta = _cairo_time_to_s (values[i]) - mean; delta = values[i] - mean;
sum += delta * delta; sum += delta * delta;
} }

View file

@ -7,6 +7,7 @@ libcairo_perf_micro_sources = \
hatching.c \ hatching.c \
hash-table.c \ hash-table.c \
line.c \ line.c \
a1-line.c \
long-lines.c \ long-lines.c \
mosaic.c \ mosaic.c \
paint.c \ paint.c \
@ -35,7 +36,11 @@ libcairo_perf_micro_sources = \
wide-fills.c \ wide-fills.c \
many-curves.c \ many-curves.c \
curve.c \ curve.c \
a1-curve.c \
spiral.c \ spiral.c \
pixel.c \
sierpinski.c \
fill-clip.c \
$(NULL) $(NULL)
libcairo_perf_micro_headers = \ libcairo_perf_micro_headers = \

112
perf/micro/a1-curve.c Normal file
View file

@ -0,0 +1,112 @@
/*
* Copyright © 2011 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Author: Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairo-perf.h"
static uint32_t state;
static double
uniform_random (double minval, double maxval)
{
static uint32_t const poly = 0x9a795537U;
uint32_t n = 32;
while (n-->0)
state = 2*state < state ? (2*state ^ poly) : 2*state;
return minval + state * (maxval - minval) / 4294967296.0;
}
static cairo_time_t
do_curve_stroke (cairo_t *cr, int width, int height, int loops)
{
state = 0xc0ffee;
cairo_set_line_width (cr, 2.);
cairo_perf_timer_start ();
while (loops--) {
double x1 = uniform_random (0, width);
double x2 = uniform_random (0, width);
double x3 = uniform_random (0, width);
double y1 = uniform_random (0, height);
double y2 = uniform_random (0, height);
double y3 = uniform_random (0, height);
cairo_move_to (cr, uniform_random (0, width), uniform_random (0, height));
cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
cairo_stroke(cr);
}
cairo_perf_timer_stop ();
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
do_curve_fill (cairo_t *cr, int width, int height, int loops)
{
state = 0xc0ffee;
cairo_perf_timer_start ();
while (loops--) {
double x0 = uniform_random (0, width);
double x1 = uniform_random (0, width);
double x2 = uniform_random (0, width);
double x3 = uniform_random (0, width);
double xm = uniform_random (0, width);
double xn = uniform_random (0, width);
double y0 = uniform_random (0, height);
double y1 = uniform_random (0, height);
double y2 = uniform_random (0, height);
double y3 = uniform_random (0, height);
double ym = uniform_random (0, height);
double yn = uniform_random (0, height);
cairo_move_to (cr, xm, ym);
cairo_curve_to (cr, x1, y1, x2, y2, xn, yn);
cairo_curve_to (cr, x3, y3, x0, y0, xm, ym);
cairo_close_path (cr);
cairo_fill(cr);
}
cairo_perf_timer_stop ();
return cairo_perf_timer_elapsed ();
}
cairo_bool_t
a1_curve_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "a1-curve", NULL);
}
void
a1_curve (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
cairo_set_source_rgb (cr, 1., 1., 1.);
cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
cairo_perf_run (perf, "a1-curve-stroked", do_curve_stroke, NULL);
cairo_perf_run (perf, "a1-curve-filled", do_curve_fill, NULL);
}

223
perf/micro/a1-line.c Normal file
View file

@ -0,0 +1,223 @@
/*
* Copyright © 2011 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Author: Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairo-perf.h"
static cairo_time_t
horizontal (cairo_t *cr, int width, int height, int loops)
{
double h = height/2 + .5;
cairo_move_to (cr, 0, h);
cairo_line_to (cr, width, h);
cairo_perf_timer_start ();
while (loops--)
cairo_stroke_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
horizontal_hair (cairo_t *cr, int width, int height, int loops)
{
cairo_set_line_width (cr, 1.);
return horizontal (cr, width, height, loops);
}
static cairo_time_t
horizontal_wide (cairo_t *cr, int width, int height, int loops)
{
cairo_set_line_width (cr, 5.);
return horizontal (cr, width, height, loops);
}
static cairo_time_t
nearly_horizontal (cairo_t *cr, int width, int height, int loops)
{
double h = height/2;
cairo_move_to (cr, 0, h);
cairo_line_to (cr, width, h+1);
cairo_perf_timer_start ();
while (loops--)
cairo_stroke_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
nearly_horizontal_hair (cairo_t *cr, int width, int height, int loops)
{
cairo_set_line_width (cr, 1.);
return nearly_horizontal (cr, width, height, loops);
}
static cairo_time_t
nearly_horizontal_wide (cairo_t *cr, int width, int height, int loops)
{
cairo_set_line_width (cr, 5.);
return nearly_horizontal (cr, width, height, loops);
}
static cairo_time_t
vertical (cairo_t *cr, int width, int height, int loops)
{
double w = width/2 + .5;
cairo_move_to (cr, w, 0);
cairo_line_to (cr, w, height);
cairo_perf_timer_start ();
while (loops--)
cairo_stroke_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
vertical_hair (cairo_t *cr, int width, int height, int loops)
{
cairo_set_line_width (cr, 1.);
return vertical (cr, width, height, loops);
}
static cairo_time_t
vertical_wide (cairo_t *cr, int width, int height, int loops)
{
cairo_set_line_width (cr, 5.);
return vertical (cr, width, height, loops);
}
static cairo_time_t
nearly_vertical (cairo_t *cr, int width, int height, int loops)
{
double w = width/2;
cairo_move_to (cr, w, 0);
cairo_line_to (cr, w+1, height);
cairo_perf_timer_start ();
while (loops--)
cairo_stroke_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
nearly_vertical_hair (cairo_t *cr, int width, int height, int loops)
{
cairo_set_line_width (cr, 1.);
return nearly_vertical (cr, width, height, loops);
}
static cairo_time_t
nearly_vertical_wide (cairo_t *cr, int width, int height, int loops)
{
cairo_set_line_width (cr, 5.);
return nearly_vertical (cr, width, height, loops);
}
static cairo_time_t
diagonal (cairo_t *cr, int width, int height, int loops)
{
cairo_move_to (cr, 0, 0);
cairo_line_to (cr, width, height);
cairo_perf_timer_start ();
while (loops--)
cairo_stroke_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
diagonal_hair (cairo_t *cr, int width, int height, int loops)
{
cairo_set_line_width (cr, 1.);
return diagonal (cr, width, height, loops);
}
static cairo_time_t
diagonal_wide (cairo_t *cr, int width, int height, int loops)
{
cairo_set_line_width (cr, 5.);
return diagonal (cr, width, height, loops);
}
cairo_bool_t
a1_line_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "a1-line", NULL);
}
void
a1_line (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
cairo_set_source_rgb (cr, 1., 1., 1.);
cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
cairo_perf_run (perf, "a1-line-hh", horizontal_hair, NULL);
cairo_perf_run (perf, "a1-line-hw", horizontal_wide, NULL);
cairo_perf_run (perf, "a1-line-nhh", nearly_horizontal_hair, NULL);
cairo_perf_run (perf, "a1-line-nhw", nearly_horizontal_wide, NULL);
cairo_perf_run (perf, "a1-line-vh", vertical_hair, NULL);
cairo_perf_run (perf, "a1-line-vw", vertical_wide, NULL);
cairo_perf_run (perf, "a1-line-nvh", nearly_vertical_hair, NULL);
cairo_perf_run (perf, "a1-line-nvw", nearly_vertical_wide, NULL);
cairo_perf_run (perf, "a1-line-dh", diagonal_hair, NULL);
cairo_perf_run (perf, "a1-line-dw", diagonal_wide, NULL);
}

View file

@ -64,6 +64,55 @@ box_outline_stroke (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
static cairo_time_t
box_outline_alpha_stroke (cairo_t *cr, int width, int height, int loops)
{
cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
cairo_paint (cr);
cairo_rectangle (cr,
1.5, 1.5,
width - 3, height - 3);
cairo_set_line_width (cr, 1.0);
cairo_set_source_rgba (cr, 1, 0, 0, .5); /* red */
cairo_perf_timer_start ();
while (loops--)
cairo_stroke_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
box_outline_aa_stroke (cairo_t *cr, int width, int height, int loops)
{
cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
cairo_paint (cr);
cairo_translate (cr, .5, .5);
cairo_rectangle (cr,
1.5, 1.5,
width - 3, height - 3);
cairo_set_line_width (cr, 1.0);
cairo_set_source_rgb (cr, 1, 0, 0); /* red */
cairo_perf_timer_start ();
while (loops--)
cairo_stroke_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_time_t static cairo_time_t
box_outline_fill (cairo_t *cr, int width, int height, int loops) box_outline_fill (cairo_t *cr, int width, int height, int loops)
{ {
@ -91,12 +140,76 @@ box_outline_fill (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
static cairo_time_t
box_outline_alpha_fill (cairo_t *cr, int width, int height, int loops)
{
cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
cairo_paint (cr);
cairo_rectangle (cr,
1.0, 1.0,
width - 2, height - 2);
cairo_rectangle (cr,
2.0, 2.0,
width - 4, height - 4);
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
cairo_set_source_rgba (cr, 0, 1, 0, .5); /* green */
cairo_perf_timer_start ();
while (loops--)
cairo_fill_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
box_outline_aa_fill (cairo_t *cr, int width, int height, int loops)
{
cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
cairo_paint (cr);
cairo_translate (cr, .5, .5);
cairo_rectangle (cr,
1.0, 1.0,
width - 2, height - 2);
cairo_rectangle (cr,
2.0, 2.0,
width - 4, height - 4);
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
cairo_set_source_rgb (cr, 0, 1, 0); /* green */
cairo_perf_timer_start ();
while (loops--)
cairo_fill_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
cairo_bool_t
box_outline_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "box-outline", NULL);
}
void void
box_outline (cairo_perf_t *perf, cairo_t *cr, int width, int height) box_outline (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "box-outline", NULL))
return;
cairo_perf_run (perf, "box-outline-stroke", box_outline_stroke, NULL); cairo_perf_run (perf, "box-outline-stroke", box_outline_stroke, NULL);
cairo_perf_run (perf, "box-outline-fill", box_outline_fill, NULL); cairo_perf_run (perf, "box-outline-fill", box_outline_fill, NULL);
cairo_perf_run (perf, "box-outline-alpha-stroke", box_outline_alpha_stroke, NULL);
cairo_perf_run (perf, "box-outline-alpha-fill", box_outline_alpha_fill, NULL);
cairo_perf_run (perf, "box-outline-aa-stroke", box_outline_aa_stroke, NULL);
cairo_perf_run (perf, "box-outline-aa-fill", box_outline_aa_fill, NULL);
} }

View file

@ -75,6 +75,12 @@ do_composite_checker (cairo_t *cr,
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
composite_checker_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "composite-checker", NULL);
}
void void
composite_checker (cairo_perf_t *perf, composite_checker (cairo_perf_t *perf,
cairo_t *cr, cairo_t *cr,
@ -83,9 +89,6 @@ composite_checker (cairo_perf_t *perf,
{ {
cairo_surface_t *image; cairo_surface_t *image;
if (! cairo_perf_can_run (perf, "composite-checker", NULL))
return;
/* Create the checker pattern. We don't actually need to draw /* Create the checker pattern. We don't actually need to draw
* anything on it since that wouldn't affect performance. * anything on it since that wouldn't affect performance.
*/ */

View file

@ -95,12 +95,15 @@ do_curve_fill (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
curve_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "curve", NULL);
}
void void
curve (cairo_perf_t *perf, cairo_t *cr, int width, int height) curve (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "curve", NULL))
return;
cairo_set_source_rgb (cr, 1., 1., 1.); cairo_set_source_rgb (cr, 1., 1., 1.);
cairo_perf_run (perf, "curve-stroked", do_curve_stroke, NULL); cairo_perf_run (perf, "curve-stroked", do_curve_stroke, NULL);

View file

@ -85,6 +85,12 @@ draw (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
disjoint_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "disjoint", NULL);
}
void void
disjoint (cairo_perf_t *perf, cairo_t *cr, int width, int height) disjoint (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {

View file

@ -265,12 +265,15 @@ do_dragon_solid_circle_clip (cairo_t *cr, int width, int height, int loops)
return do_dragon_solid (cr, width, height, loops); return do_dragon_solid (cr, width, height, loops);
} }
cairo_bool_t
dragon_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "dragon", NULL);
}
void void
dragon (cairo_perf_t *perf, cairo_t *cr, int width, int height) dragon (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "dragon", NULL))
return;
cairo_perf_run (perf, "dragon-solid", do_dragon_solid, NULL); cairo_perf_run (perf, "dragon-solid", do_dragon_solid, NULL);
cairo_perf_run (perf, "dragon-unaligned-solid", do_dragon_solid_unaligned, NULL); cairo_perf_run (perf, "dragon-unaligned-solid", do_dragon_solid_unaligned, NULL);
cairo_perf_run (perf, "dragon-solid-aligned-clip", do_dragon_solid_aligned_clip, NULL); cairo_perf_run (perf, "dragon-solid-aligned-clip", do_dragon_solid_aligned_clip, NULL);

126
perf/micro/fill-clip.c Normal file
View file

@ -0,0 +1,126 @@
/*
* Copyright © 2011 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Author: Chris Wilson <chris@chris-wilson.co.uk>
*/
/* Compares the overhead for WebKit's drawRect() */
#include "cairo-perf.h"
#include <pixman.h>
static cairo_time_t
clip_paint (cairo_t *cr, int width, int height, int loops)
{
int x = width/4, w = width/2;
int y = height/4, h = height/2;
cairo_perf_timer_start ();
while (loops--) {
cairo_reset_clip (cr);
cairo_rectangle (cr, x, y, w, h);
cairo_clip (cr);
cairo_paint (cr);
}
cairo_perf_timer_stop ();
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
rect_fill (cairo_t *cr, int width, int height, int loops)
{
int x = width/4, w = width/2;
int y = height/4, h = height/2;
cairo_perf_timer_start ();
while (loops--) {
cairo_rectangle (cr, x, y, w, h);
cairo_fill (cr);
}
cairo_perf_timer_stop ();
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
direct (cairo_t *cr, int width, int height, int loops)
{
int x = width/4, w = width/2;
int y = height/4, h = height/2;
cairo_surface_t *surface, *image;
uint8_t *data;
int stride, bpp;
surface = cairo_get_target (cr);
image = cairo_surface_map_to_image (surface, NULL);
data = cairo_image_surface_get_data (image);
stride = cairo_image_surface_get_stride (image);
switch (cairo_image_surface_get_format (image)) {
default:
case CAIRO_FORMAT_INVALID:
case CAIRO_FORMAT_A1: bpp = 0; break;
case CAIRO_FORMAT_A8: bpp = 8; break;
case CAIRO_FORMAT_RGB16_565: bpp = 16; break;
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_ARGB32: bpp = 32; break;
}
cairo_perf_timer_start ();
while (loops--) {
pixman_fill ((uint32_t *)data, stride / sizeof(uint32_t), bpp,
x, y, w, h,
-1);
}
cairo_perf_timer_stop ();
cairo_surface_unmap_image (surface, image);
return cairo_perf_timer_elapsed ();
}
cairo_bool_t
fill_clip_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "fillclip", NULL);
}
void
fill_clip (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
cairo_set_source_rgb (cr, 1., 1., 1.);
cairo_perf_run (perf, "fillclip-clip", clip_paint, NULL);
cairo_perf_run (perf, "fillclip-fill", rect_fill, NULL);
cairo_perf_run (perf, "fillclip-direct", direct, NULL);
}

View file

@ -107,12 +107,15 @@ do_fill_eo_noaa (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
fill_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "fill", NULL);
}
void void
fill (cairo_perf_t *perf, cairo_t *cr, int width, int height) fill (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "fill", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "fill", do_fill, NULL); cairo_perf_cover_sources_and_operators (perf, "fill", do_fill, NULL);
cairo_perf_cover_sources_and_operators (perf, "fill-annuli", do_fill_annuli, NULL); cairo_perf_cover_sources_and_operators (perf, "fill-annuli", do_fill_annuli, NULL);
cairo_perf_cover_sources_and_operators (perf, "fill-eo-noaa", do_fill_eo_noaa, NULL); cairo_perf_cover_sources_and_operators (perf, "fill-eo-noaa", do_fill_eo_noaa, NULL);

View file

@ -170,12 +170,15 @@ DECL(48ca, 48, CAIRO_ANTIALIAS_SUBPIXEL)
DECL(8mono, 8, CAIRO_ANTIALIAS_NONE) DECL(8mono, 8, CAIRO_ANTIALIAS_NONE)
DECL(48mono, 48, CAIRO_ANTIALIAS_NONE) DECL(48mono, 48, CAIRO_ANTIALIAS_NONE)
cairo_bool_t
glyphs_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "glyphs", NULL);
}
void void
glyphs (cairo_perf_t *perf, cairo_t *cr, int width, int height) glyphs (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "glyphs", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "glyphs8mono", do_glyphs8mono, count_glyphs8mono); cairo_perf_cover_sources_and_operators (perf, "glyphs8mono", do_glyphs8mono, count_glyphs8mono);
cairo_perf_cover_sources_and_operators (perf, "glyphs8", do_glyphs8, count_glyphs8); cairo_perf_cover_sources_and_operators (perf, "glyphs8", do_glyphs8, count_glyphs8);
cairo_perf_cover_sources_and_operators (perf, "glyphs8ca", do_glyphs8ca, count_glyphs8ca); cairo_perf_cover_sources_and_operators (perf, "glyphs8ca", do_glyphs8ca, count_glyphs8ca);

View file

@ -101,12 +101,15 @@ do_hash_table (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
hash_table_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "hash-table", NULL);
}
void void
hash_table (cairo_perf_t *perf, cairo_t *cr, int width, int height) hash_table (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "hash-table", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "hash-table", cairo_perf_cover_sources_and_operators (perf, "hash-table",
do_hash_table, NULL); do_hash_table, NULL);
} }

View file

@ -170,12 +170,15 @@ F(clip_alpha_aligned_mono, clip_alpha, aligned, mono)
F(clip_alpha_misaligned_mono, clip_alpha, misaligned, mono) F(clip_alpha_misaligned_mono, clip_alpha, misaligned, mono)
F(clip_alpha_rotated_mono, clip_alpha, rotated, mono) F(clip_alpha_rotated_mono, clip_alpha, rotated, mono)
cairo_bool_t
hatching_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "hatching", NULL);
}
void void
hatching (cairo_perf_t *perf, cairo_t *cr, int width, int height) hatching (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "hatching", NULL))
return;
cairo_perf_run (perf, "hatching-aligned-aa", draw_aligned_aa, NULL); cairo_perf_run (perf, "hatching-aligned-aa", draw_aligned_aa, NULL);
cairo_perf_run (perf, "hatching-misaligned-aa", draw_misaligned_aa, NULL); cairo_perf_run (perf, "hatching-misaligned-aa", draw_misaligned_aa, NULL);
cairo_perf_run (perf, "hatching-rotated-aa", draw_rotated_aa, NULL); cairo_perf_run (perf, "hatching-rotated-aa", draw_rotated_aa, NULL);

View file

@ -143,12 +143,15 @@ random_curve_nz (cairo_t *cr, int width, int height, int loops)
return draw_random_curve (cr, CAIRO_FILL_RULE_WINDING, width, height, loops); return draw_random_curve (cr, CAIRO_FILL_RULE_WINDING, width, height, loops);
} }
cairo_bool_t
intersections_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "intersections", NULL);
}
void void
intersections (cairo_perf_t *perf, cairo_t *cr, int width, int height) intersections (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "intersections", NULL))
return;
cairo_perf_run (perf, "intersections-nz-fill", random_nz, NULL); cairo_perf_run (perf, "intersections-nz-fill", random_nz, NULL);
cairo_perf_run (perf, "intersections-eo-fill", random_eo, NULL); cairo_perf_run (perf, "intersections-eo-fill", random_eo, NULL);

View file

@ -196,12 +196,15 @@ diagonal_wide (cairo_t *cr, int width, int height, int loops)
return diagonal (cr, width, height, loops); return diagonal (cr, width, height, loops);
} }
cairo_bool_t
line_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "line", NULL);
}
void void
line (cairo_perf_t *perf, cairo_t *cr, int width, int height) line (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "line", NULL))
return;
cairo_set_source_rgb (cr, 1., 1., 1.); cairo_set_source_rgb (cr, 1., 1., 1.);
cairo_perf_run (perf, "line-hh", horizontal_hair, NULL); cairo_perf_run (perf, "line-hh", horizontal_hair, NULL);

View file

@ -61,11 +61,14 @@ do_long_dashed_lines (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
long_dashed_lines_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "long-dashed-lines", NULL);
}
void void
long_dashed_lines (cairo_perf_t *perf, cairo_t *cr, int width, int height) long_dashed_lines (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "long-dashed-lines", NULL))
return;
cairo_perf_run (perf, "long-dashed-lines", do_long_dashed_lines, NULL); cairo_perf_run (perf, "long-dashed-lines", do_long_dashed_lines, NULL);
} }

View file

@ -132,12 +132,15 @@ long_lines_cropped_once (cairo_t *cr, int width, int height, int loops)
return do_long_lines (cr, width, height, loops, LONG_LINES_CROPPED | LONG_LINES_ONCE); return do_long_lines (cr, width, height, loops, LONG_LINES_CROPPED | LONG_LINES_ONCE);
} }
cairo_bool_t
long_lines_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "long-lines", NULL);
}
void void
long_lines (cairo_perf_t *perf, cairo_t *cr, int width, int height) long_lines (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "long-lines", NULL))
return;
cairo_perf_run (perf, "long-lines-uncropped", long_lines_uncropped, NULL); cairo_perf_run (perf, "long-lines-uncropped", long_lines_uncropped, NULL);
cairo_perf_run (perf, "long-lines-uncropped-once", long_lines_uncropped_once, NULL); cairo_perf_run (perf, "long-lines-uncropped-once", long_lines_uncropped_once, NULL);
cairo_perf_run (perf, "long-lines-cropped", long_lines_cropped, NULL); cairo_perf_run (perf, "long-lines-cropped", long_lines_cropped, NULL);

View file

@ -118,12 +118,15 @@ do_many_curves_filled (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
many_curves_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "many-curves", NULL);
}
void void
many_curves (cairo_perf_t *perf, cairo_t *cr, int width, int height) many_curves (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "many-curves", NULL))
return;
cairo_set_source_rgb (cr, 1., 1., 1.); cairo_set_source_rgb (cr, 1., 1., 1.);
cairo_perf_run (perf, "many-curves-hair-stroked", do_many_curves_hair_stroked, NULL); cairo_perf_run (perf, "many-curves-hair-stroked", do_many_curves_hair_stroked, NULL);

View file

@ -170,12 +170,15 @@ do_many_fills (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
many_fills_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "many-fills", NULL);
}
void void
many_fills (cairo_perf_t *perf, cairo_t *cr, int width, int height) many_fills (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "many-fills", NULL))
return;
cairo_perf_run (perf, "many-fills-halign", do_many_fills_ha, NULL); cairo_perf_run (perf, "many-fills-halign", do_many_fills_ha, NULL);
cairo_perf_run (perf, "many-fills-valign", do_many_fills_va, NULL); cairo_perf_run (perf, "many-fills-valign", do_many_fills_va, NULL);
cairo_perf_run (perf, "many-fills-horizontal", do_many_fills_h, NULL); cairo_perf_run (perf, "many-fills-horizontal", do_many_fills_h, NULL);

View file

@ -45,7 +45,7 @@ do_many_strokes_ha (cairo_t *cr, int width, int height, int loops)
state = 0xc0ffee; state = 0xc0ffee;
for (count = 0; count < 1000; count++) { for (count = 0; count < 1000; count++) {
double h = floor (uniform_random (0, height)); double h = floor (uniform_random (0, height)) + .5;
cairo_move_to (cr, floor (uniform_random (0, width)), h); cairo_move_to (cr, floor (uniform_random (0, width)), h);
cairo_line_to (cr, ceil (uniform_random (0, width)), h); cairo_line_to (cr, ceil (uniform_random (0, width)), h);
} }
@ -97,7 +97,7 @@ do_many_strokes_va (cairo_t *cr, int width, int height, int loops)
state = 0xc0ffee; state = 0xc0ffee;
for (count = 0; count < 1000; count++) { for (count = 0; count < 1000; count++) {
double v = floor (uniform_random (0, width)); double v = floor (uniform_random (0, width)) + .5;
cairo_move_to (cr, v, floor (uniform_random (0, height))); cairo_move_to (cr, v, floor (uniform_random (0, height)));
cairo_line_to (cr, v, ceil (uniform_random (0, height))); cairo_line_to (cr, v, ceil (uniform_random (0, height)));
} }
@ -169,12 +169,15 @@ do_many_strokes (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
many_strokes_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "many-strokes", NULL);
}
void void
many_strokes (cairo_perf_t *perf, cairo_t *cr, int width, int height) many_strokes (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "many-strokes", NULL))
return;
cairo_perf_run (perf, "many-strokes-halign", do_many_strokes_ha, NULL); cairo_perf_run (perf, "many-strokes-halign", do_many_strokes_ha, NULL);
cairo_perf_run (perf, "many-strokes-valign", do_many_strokes_va, NULL); cairo_perf_run (perf, "many-strokes-valign", do_many_strokes_va, NULL);
cairo_perf_run (perf, "many-strokes-horizontal", do_many_strokes_h, NULL); cairo_perf_run (perf, "many-strokes-horizontal", do_many_strokes_h, NULL);

View file

@ -272,6 +272,12 @@ do_mask_radial (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
mask_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "mask", NULL);
}
void void
mask (cairo_perf_t *perf, cairo_t *cr, int width, int height) mask (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {

View file

@ -160,12 +160,15 @@ mosaic_tessellate_curves (cairo_t *cr, int width, int height, int loops)
return mosaic_perform (cr, MOSAIC_TESSELLATE | MOSAIC_CURVE_TO, width, height, loops); return mosaic_perform (cr, MOSAIC_TESSELLATE | MOSAIC_CURVE_TO, width, height, loops);
} }
cairo_bool_t
mosaic_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "mosaic", NULL);
}
void void
mosaic (cairo_perf_t *perf, cairo_t *cr, int width, int height) mosaic (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "mosaic", NULL))
return;
cairo_perf_run (perf, "mosaic-fill-curves", mosaic_fill_curves, NULL); cairo_perf_run (perf, "mosaic-fill-curves", mosaic_fill_curves, NULL);
cairo_perf_run (perf, "mosaic-fill-lines", mosaic_fill_lines, NULL); cairo_perf_run (perf, "mosaic-fill-lines", mosaic_fill_lines, NULL);
cairo_perf_run (perf, "mosaic-tessellate-curves", mosaic_tessellate_curves, NULL); cairo_perf_run (perf, "mosaic-tessellate-curves", mosaic_tessellate_curves, NULL);

View file

@ -44,12 +44,15 @@ count_paint_with_alpha (cairo_t *cr, int width, int height)
return width * height / 1e6; /* Mpix/s */ return width * height / 1e6; /* Mpix/s */
} }
cairo_bool_t
paint_with_alpha_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "paint-with-alpha", NULL);
}
void void
paint_with_alpha (cairo_perf_t *perf, cairo_t *cr, int width, int height) paint_with_alpha (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "paint-with-alpha", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "paint-with-alpha", cairo_perf_cover_sources_and_operators (perf, "paint-with-alpha",
do_paint_with_alpha, do_paint_with_alpha,
count_paint_with_alpha); count_paint_with_alpha);

View file

@ -44,11 +44,14 @@ count_paint (cairo_t *cr, int width, int height)
return width * height / 1e6; /* Mpix/s */ return width * height / 1e6; /* Mpix/s */
} }
cairo_bool_t
paint_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "paint", NULL);
}
void void
paint (cairo_perf_t *perf, cairo_t *cr, int width, int height) paint (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "paint", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "paint", do_paint, count_paint); cairo_perf_cover_sources_and_operators (perf, "paint", do_paint, count_paint);
} }

View file

@ -79,14 +79,17 @@ do_pattern_create_radial (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
pattern_create_radial_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "pattern-create-radial", NULL);
}
void void
pattern_create_radial (cairo_perf_t *perf, cairo_t *cr, int width, int height) pattern_create_radial (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
int i; int i;
if (! cairo_perf_can_run (perf, "pattern-create-radial", NULL))
return;
srand (time (0)); srand (time (0));
for (i = 0; i < RADIALS_COUNT; i++) for (i = 0; i < RADIALS_COUNT; i++)
{ {

177
perf/micro/pixel.c Normal file
View file

@ -0,0 +1,177 @@
/*
* Copyright © 2011 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Author: Chris Wilson <chris@chris-wilson.co.uk>
*/
/* Measure the overhead in setting a single pixel */
#include "cairo-perf.h"
static cairo_time_t
pixel_paint (cairo_t *cr, int width, int height, int loops)
{
cairo_perf_timer_start ();
while (loops--)
cairo_paint (cr);
cairo_perf_timer_stop ();
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
pixel_mask (cairo_t *cr, int width, int height, int loops)
{
cairo_surface_t *mask;
cairo_t *cr2;
mask = cairo_surface_create_similar (cairo_get_target (cr),
CAIRO_CONTENT_ALPHA,
1, 1);
cr2 = cairo_create (mask);
cairo_set_source_rgb (cr2, 1,1,1);
cairo_paint (cr2);
cairo_destroy (cr2);
cairo_perf_timer_start ();
while (loops--)
cairo_mask_surface (cr, mask, 0, 0);
cairo_perf_timer_stop ();
cairo_surface_destroy (mask);
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
pixel_rectangle (cairo_t *cr, int width, int height, int loops)
{
cairo_new_path (cr);
cairo_rectangle (cr, 0, 0, 1, 1);
cairo_perf_timer_start ();
while (loops--)
cairo_fill_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
pixel_subrectangle (cairo_t *cr, int width, int height, int loops)
{
cairo_new_path (cr);
cairo_rectangle (cr, 0.1, 0.1, .8, .8);
cairo_perf_timer_start ();
while (loops--)
cairo_fill_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
pixel_triangle (cairo_t *cr, int width, int height, int loops)
{
cairo_new_path (cr);
cairo_move_to (cr, 0, 0);
cairo_line_to (cr, 1, 1);
cairo_line_to (cr, 0, 1);
cairo_perf_timer_start ();
while (loops--)
cairo_fill_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
pixel_circle (cairo_t *cr, int width, int height, int loops)
{
cairo_new_path (cr);
cairo_arc (cr, 0.5, 0.5, 0.5, 0, 2 * M_PI);
cairo_perf_timer_start ();
while (loops--)
cairo_fill_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_time_t
pixel_stroke (cairo_t *cr, int width, int height, int loops)
{
cairo_set_line_width (cr, 1.);
cairo_new_path (cr);
cairo_move_to (cr, 0, 0.5);
cairo_line_to (cr, 1, 0.5);
cairo_perf_timer_start ();
while (loops--)
cairo_stroke_preserve (cr);
cairo_perf_timer_stop ();
cairo_new_path (cr);
return cairo_perf_timer_elapsed ();
}
cairo_bool_t
pixel_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "pixel", NULL);
}
void
pixel (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
cairo_set_source_rgb (cr, 1., 1., 1.);
cairo_perf_run (perf, "pixel-paint", pixel_paint, NULL);
cairo_perf_run (perf, "pixel-mask", pixel_mask, NULL);
cairo_perf_run (perf, "pixel-rectangle", pixel_rectangle, NULL);
cairo_perf_run (perf, "pixel-subrectangle", pixel_subrectangle, NULL);
cairo_perf_run (perf, "pixel-triangle", pixel_triangle, NULL);
cairo_perf_run (perf, "pixel-circle", pixel_circle, NULL);
cairo_perf_run (perf, "pixel-stroke", pixel_stroke, NULL);
}

View file

@ -82,11 +82,14 @@ do_pythagoras_tree (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
pythagoras_tree_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "pythagoras-tree", NULL);
}
void void
pythagoras_tree (cairo_perf_t *perf, cairo_t *cr, int width, int height) pythagoras_tree (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "pythagoras-tree", NULL))
return;
cairo_perf_run (perf, "pythagoras-tree", do_pythagoras_tree, NULL); cairo_perf_run (perf, "pythagoras-tree", do_pythagoras_tree, NULL);
} }

View file

@ -95,14 +95,17 @@ do_rectangle (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
rectangles_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "rectangles", NULL);
}
void void
rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height) rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
int i; int i;
if (! cairo_perf_can_run (perf, "rectangles", NULL))
return;
srand (8478232); srand (8478232);
for (i = 0; i < RECTANGLE_COUNT; i++) for (i = 0; i < RECTANGLE_COUNT; i++)
{ {

View file

@ -119,14 +119,17 @@ do_rectangles_once (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
rounded_rectangles_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "rounded-rectangles", NULL);
}
void void
rounded_rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height) rounded_rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
int i; int i;
if (! cairo_perf_can_run (perf, "rounded-rectangles", NULL))
return;
srand (8478232); srand (8478232);
for (i = 0; i < RECTANGLE_COUNT; i++) { for (i = 0; i < RECTANGLE_COUNT; i++) {
rects[i].x = rand () % width; rects[i].x = rand () % width;

94
perf/micro/sierpinski.c Normal file
View file

@ -0,0 +1,94 @@
/*
* Copyright © 2011 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Author: Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairo-perf.h"
static const double m_1_sqrt_3 = 0.577359269;
static void
T (cairo_t *cr, int size)
{
cairo_move_to (cr, 0, 0);
cairo_line_to (cr, size, 0);
cairo_line_to (cr, size/2, size*m_1_sqrt_3);
size /= 2;
if (size >= 4) {
T (cr, size);
cairo_save (cr); {
cairo_translate (cr, size, 0);
T (cr, size);
} cairo_restore (cr);
cairo_save (cr); {
cairo_translate (cr, size/2, size*m_1_sqrt_3);
T (cr, size);
} cairo_restore (cr);
}
}
static cairo_time_t
draw (cairo_t *cr, int width, int height, int loops)
{
int t_height = height/2;
int t_width = t_height / m_1_sqrt_3;
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_set_line_width (cr, 1.);
cairo_perf_timer_start ();
while (loops--) {
cairo_save (cr);
T (cr, t_width);
cairo_translate (cr, 0, height);
cairo_scale (cr, 1, -1);
T (cr, t_width);
cairo_stroke (cr);
cairo_restore (cr);
}
cairo_perf_timer_stop ();
return cairo_perf_timer_elapsed ();
}
cairo_bool_t
sierpinski_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "sierpinski", NULL);
}
void
sierpinski (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
cairo_perf_run (perf, "sierpinski", draw, NULL);
}

View file

@ -326,12 +326,15 @@ draw_spiral_stroke_na (cairo_t *cr, int width, int height, int loops)
width, height, loops); width, height, loops);
} }
cairo_bool_t
spiral_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "spiral", NULL);
}
void void
spiral (cairo_perf_t *perf, cairo_t *cr, int width, int height) spiral (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "spiral", NULL))
return;
cairo_perf_run (perf, "spiral-box-nonalign-evenodd-fill", draw_spiral_eo_na_box, NULL); cairo_perf_run (perf, "spiral-box-nonalign-evenodd-fill", draw_spiral_eo_na_box, NULL);
cairo_perf_run (perf, "spiral-box-nonalign-nonzero-fill", draw_spiral_nz_na_box, NULL); cairo_perf_run (perf, "spiral-box-nonalign-nonzero-fill", draw_spiral_nz_na_box, NULL);
cairo_perf_run (perf, "spiral-box-pixalign-evenodd-fill", draw_spiral_eo_pa_box, NULL); cairo_perf_run (perf, "spiral-box-pixalign-evenodd-fill", draw_spiral_eo_pa_box, NULL);

View file

@ -86,12 +86,15 @@ do_strokes (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
stroke_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "stroke", NULL);
}
void void
stroke (cairo_perf_t *perf, cairo_t *cr, int width, int height) stroke (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "stroke", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "stroke", do_stroke, NULL); cairo_perf_cover_sources_and_operators (perf, "stroke", do_stroke, NULL);
cairo_perf_cover_sources_and_operators (perf, "strokes", do_strokes, NULL); cairo_perf_cover_sources_and_operators (perf, "strokes", do_strokes, NULL);
} }

View file

@ -52,15 +52,18 @@ do_subimage_copy (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
subimage_copy_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "subimage-copy", NULL);
}
void void
subimage_copy (cairo_perf_t *perf, cairo_t *cr, int width, int height) subimage_copy (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
cairo_surface_t *image; cairo_surface_t *image;
cairo_t *cr2; cairo_t *cr2;
if (! cairo_perf_can_run (perf, "subimage-copy", NULL))
return;
cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
cairo_paint (cr); cairo_paint (cr);

View file

@ -141,12 +141,15 @@ tessellate_256 (cairo_t *cr, int width, int height, int loops)
return do_tessellate (cr, 256, loops); return do_tessellate (cr, 256, loops);
} }
cairo_bool_t
tessellate_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "tessellate", NULL);
}
void void
tessellate (cairo_perf_t *perf, cairo_t *cr, int width, int height) tessellate (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "tessellate", NULL))
return;
cairo_perf_run (perf, "tessellate-16", tessellate_16, NULL); cairo_perf_run (perf, "tessellate-16", tessellate_16, NULL);
cairo_perf_run (perf, "tessellate-64", tessellate_64, NULL); cairo_perf_run (perf, "tessellate-64", tessellate_64, NULL);
cairo_perf_run (perf, "tessellate-256", tessellate_256, NULL); cairo_perf_run (perf, "tessellate-256", tessellate_256, NULL);

View file

@ -56,11 +56,14 @@ do_text (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
text_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "text", NULL);
}
void void
text (cairo_perf_t *perf, cairo_t *cr, int width, int height) text (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "text", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "text", do_text, NULL); cairo_perf_cover_sources_and_operators (perf, "text", do_text, NULL);
} }

View file

@ -43,14 +43,17 @@ do_twin (cairo_t *cr,
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
twin_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "twin", NULL);
}
void void
twin (cairo_perf_t *perf, twin (cairo_perf_t *perf,
cairo_t *cr, cairo_t *cr,
int width, int width,
int height) int height)
{ {
if (! cairo_perf_can_run (perf, "twin", NULL))
return;
cairo_perf_run (perf, "twin", do_twin, NULL); cairo_perf_run (perf, "twin", do_twin, NULL);
} }

View file

@ -60,11 +60,14 @@ do_unaligned_clip (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
unaligned_clip_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "unaligned-clip", NULL);
}
void void
unaligned_clip (cairo_perf_t *perf, cairo_t *cr, int width, int height) unaligned_clip (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "unaligned-clip", NULL))
return;
cairo_perf_run (perf, "unaligned-clip", do_unaligned_clip, NULL); cairo_perf_run (perf, "unaligned-clip", do_unaligned_clip, NULL);
} }

View file

@ -102,11 +102,14 @@ do_wave (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
wave_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "wave", NULL);
}
void void
wave (cairo_perf_t *perf, cairo_t *cr, int width, int height) wave (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "wave", NULL))
return;
cairo_perf_run (perf, "wave", do_wave, NULL); cairo_perf_run (perf, "wave", do_wave, NULL);
} }

View file

@ -170,12 +170,15 @@ do_wide_fills (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
wide_fills_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "wide-fills", NULL);
}
void void
wide_fills (cairo_perf_t *perf, cairo_t *cr, int width, int height) wide_fills (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "wide-fills", NULL))
return;
cairo_perf_run (perf, "wide-fills-halign", do_wide_fills_ha, NULL); cairo_perf_run (perf, "wide-fills-halign", do_wide_fills_ha, NULL);
cairo_perf_run (perf, "wide-fills-valign", do_wide_fills_va, NULL); cairo_perf_run (perf, "wide-fills-valign", do_wide_fills_va, NULL);
cairo_perf_run (perf, "wide-fills-horizontal", do_wide_fills_h, NULL); cairo_perf_run (perf, "wide-fills-horizontal", do_wide_fills_h, NULL);

View file

@ -169,12 +169,15 @@ do_wide_strokes (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
wide_strokes_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "wide-strokes", NULL);
}
void void
wide_strokes (cairo_perf_t *perf, cairo_t *cr, int width, int height) wide_strokes (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "wide-strokes", NULL))
return;
cairo_set_source_rgb (cr, 1., 1., 1.); cairo_set_source_rgb (cr, 1., 1., 1.);
cairo_perf_run (perf, "wide-strokes-halign", do_wide_strokes_ha, NULL); cairo_perf_run (perf, "wide-strokes-halign", do_wide_strokes_ha, NULL);

View file

@ -134,12 +134,15 @@ do_world_map_both (cairo_t *cr, int width, int height, int loops)
return do_world_map (cr, width, height, loops, FILL | STROKE); return do_world_map (cr, width, height, loops, FILL | STROKE);
} }
cairo_bool_t
world_map_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "world-map", NULL);
}
void void
world_map (cairo_perf_t *perf, cairo_t *cr, int width, int height) world_map (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "world-map", NULL))
return;
cairo_perf_run (perf, "world-map-stroke", do_world_map_stroke, NULL); cairo_perf_run (perf, "world-map-stroke", do_world_map_stroke, NULL);
cairo_perf_run (perf, "world-map-fill", do_world_map_fill, NULL); cairo_perf_run (perf, "world-map-fill", do_world_map_fill, NULL);
cairo_perf_run (perf, "world-map", do_world_map_both, NULL); cairo_perf_run (perf, "world-map", do_world_map_both, NULL);

View file

@ -84,11 +84,15 @@ zrusin_another_fill (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed (); return cairo_perf_timer_elapsed ();
} }
cairo_bool_t
zrusin_enabled (cairo_perf_t *perf)
{
return cairo_perf_can_run (perf, "zrusin", NULL);
}
void void
zrusin (cairo_perf_t *perf, cairo_t *cr, int width, int height) zrusin (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{ {
if (! cairo_perf_can_run (perf, "zrusin", NULL))
return;
cairo_perf_run (perf, "zrusin-another-tessellate", zrusin_another_tessellate, NULL); cairo_perf_run (perf, "zrusin-another-tessellate", zrusin_another_tessellate, NULL);
cairo_perf_run (perf, "zrusin-another-fill", zrusin_another_fill, NULL); cairo_perf_run (perf, "zrusin-another-fill", zrusin_another_fill, NULL);

View file

@ -54,6 +54,7 @@ cairo_private = \
cairoint.h \ cairoint.h \
cairo-analysis-surface-private.h \ cairo-analysis-surface-private.h \
cairo-arc-private.h \ cairo-arc-private.h \
cairo-array-private.h \
cairo-atomic-private.h \ cairo-atomic-private.h \
cairo-backend-private.h \ cairo-backend-private.h \
cairo-box-private.h \ cairo-box-private.h \
@ -62,6 +63,7 @@ cairo_private = \
cairo-clip-private.h \ cairo-clip-private.h \
cairo-combsort-private.h \ cairo-combsort-private.h \
cairo-compiler-private.h \ cairo-compiler-private.h \
cairo-compositor-private.h \
cairo-contour-private.h \ cairo-contour-private.h \
cairo-composite-rectangles-private.h \ cairo-composite-rectangles-private.h \
cairo-default-context-private.h \ cairo-default-context-private.h \
@ -97,10 +99,11 @@ cairo_private = \
cairo-scaled-font-private.h \ cairo-scaled-font-private.h \
cairo-slope-private.h \ cairo-slope-private.h \
cairo-spans-private.h \ cairo-spans-private.h \
cairo-spans-compositor-private.h \
cairo-stroke-dash-private.h \ cairo-stroke-dash-private.h \
cairo-surface-fallback-private.h \
cairo-surface-private.h \ cairo-surface-private.h \
cairo-surface-clipper-private.h \ cairo-surface-clipper-private.h \
cairo-surface-fallback-private.h \
cairo-surface-observer-private.h \ cairo-surface-observer-private.h \
cairo-surface-offset-private.h \ cairo-surface-offset-private.h \
cairo-surface-subsurface-private.h \ cairo-surface-subsurface-private.h \
@ -108,6 +111,8 @@ cairo_private = \
cairo-surface-wrapper-private.h \ cairo-surface-wrapper-private.h \
cairo-time-private.h \ cairo-time-private.h \
cairo-types-private.h \ cairo-types-private.h \
cairo-traps-private.h \
cairo-tristrip-private.h \
cairo-user-font-private.h \ cairo-user-font-private.h \
cairo-wideint-private.h \ cairo-wideint-private.h \
cairo-wideint-type-private.h \ cairo-wideint-type-private.h \
@ -134,11 +139,13 @@ cairo_sources = \
cairo-clip-surface.c \ cairo-clip-surface.c \
cairo-color.c \ cairo-color.c \
cairo-composite-rectangles.c \ cairo-composite-rectangles.c \
cairo-compositor.c \
cairo-contour.c \ cairo-contour.c \
cairo-debug.c \ cairo-debug.c \
cairo-default-context.c \ cairo-default-context.c \
cairo-device.c \ cairo-device.c \
cairo-error.c \ cairo-error.c \
cairo-fallback-compositor.c \
cairo-fixed.c \ cairo-fixed.c \
cairo-font-face.c \ cairo-font-face.c \
cairo-font-face-twin.c \ cairo-font-face-twin.c \
@ -149,14 +156,19 @@ cairo_sources = \
cairo-gstate.c \ cairo-gstate.c \
cairo-hash.c \ cairo-hash.c \
cairo-hull.c \ cairo-hull.c \
cairo-image-compositor.c \
cairo-image-info.c \ cairo-image-info.c \
cairo-image-source.c \
cairo-image-surface.c \ cairo-image-surface.c \
cairo-lzw.c \ cairo-lzw.c \
cairo-matrix.c \ cairo-matrix.c \
cairo-mask-compositor.c \
cairo-mesh-pattern-rasterizer.c \ cairo-mesh-pattern-rasterizer.c \
cairo-mime-surface.c \ cairo-mime-surface.c \
cairo-misc.c \ cairo-misc.c \
cairo-mono-scan-converter.c \
cairo-mutex.c \ cairo-mutex.c \
cairo-no-compositor.c \
cairo-observer.c \ cairo-observer.c \
cairo-output-stream.c \ cairo-output-stream.c \
cairo-paginated-surface.c \ cairo-paginated-surface.c \
@ -168,6 +180,7 @@ cairo_sources = \
cairo-path-stroke.c \ cairo-path-stroke.c \
cairo-path-stroke-boxes.c \ cairo-path-stroke-boxes.c \
cairo-path-stroke-polygon.c \ cairo-path-stroke-polygon.c \
cairo-path-stroke-tristrip.c \
cairo-pattern.c \ cairo-pattern.c \
cairo-pen.c \ cairo-pen.c \
cairo-polygon.c \ cairo-polygon.c \
@ -181,12 +194,13 @@ cairo_sources = \
cairo-scaled-font.c \ cairo-scaled-font.c \
cairo-slope.c \ cairo-slope.c \
cairo-spans.c \ cairo-spans.c \
cairo-spans-compositor.c \
cairo-spline.c \ cairo-spline.c \
cairo-stroke-dash.c \ cairo-stroke-dash.c \
cairo-stroke-style.c \ cairo-stroke-style.c \
cairo-surface.c \ cairo-surface.c \
cairo-surface-fallback.c \
cairo-surface-clipper.c \ cairo-surface-clipper.c \
cairo-surface-fallback.c \
cairo-surface-observer.c \ cairo-surface-observer.c \
cairo-surface-offset.c \ cairo-surface-offset.c \
cairo-surface-snapshot.c \ cairo-surface-snapshot.c \
@ -195,8 +209,12 @@ cairo_sources = \
cairo-system.c \ cairo-system.c \
cairo-time.c \ cairo-time.c \
cairo-tor-scan-converter.c \ cairo-tor-scan-converter.c \
cairo-tor22-scan-converter.c \
cairo-clip-tor-scan-converter.c \
cairo-toy-font-face.c \ cairo-toy-font-face.c \
cairo-traps.c \ cairo-traps.c \
cairo-tristrip.c \
cairo-traps-compositor.c \
cairo-unicode.c \ cairo-unicode.c \
cairo-user-font.c \ cairo-user-font.c \
cairo-version.c \ cairo-version.c \
@ -253,18 +271,15 @@ cairo_ft_sources = cairo-ft-font.c
# These are private, even though they look like public headers # These are private, even though they look like public headers
cairo_test_surfaces_private = \ cairo_test_surfaces_private = \
test-fallback-surface.h \ test-compositor-surface.h \
test-fallback16-surface.h \ test-null-compositor-surface.h \
test-null-surface.h \
test-paginated-surface.h \ test-paginated-surface.h \
test-wrapping-surface.h \
$(NULL) $(NULL)
cairo_test_surfaces_sources = \ cairo_test_surfaces_sources = \
test-fallback-surface.c \ test-compositor-surface.c \
test-fallback16-surface.c \ test-null-compositor-surface.c \
test-null-surface.c \ test-base-compositor-surface.c \
test-paginated-surface.c \ test-paginated-surface.c \
test-wrapping-surface.c \
$(NULL) $(NULL)
cairo_xlib_headers = cairo-xlib.h cairo_xlib_headers = cairo-xlib.h
@ -275,7 +290,11 @@ cairo_xlib_private = \
$(NULL) $(NULL)
cairo_xlib_sources = \ cairo_xlib_sources = \
cairo-xlib-display.c \ cairo-xlib-display.c \
cairo-xlib-core-compositor.c \
cairo-xlib-fallback-compositor.c \
cairo-xlib-render-compositor.c \
cairo-xlib-screen.c \ cairo-xlib-screen.c \
cairo-xlib-source.c \
cairo-xlib-surface.c \ cairo-xlib-surface.c \
cairo-xlib-visual.c \ cairo-xlib-visual.c \
cairo-xlib-xcb-surface.c \ cairo-xlib-xcb-surface.c \
@ -343,7 +362,10 @@ cairo_gl_sources = cairo-gl-composite.c \
cairo-gl-glyphs.c \ cairo-gl-glyphs.c \
cairo-gl-gradient.c \ cairo-gl-gradient.c \
cairo-gl-info.c \ cairo-gl-info.c \
cairo-gl-operand.c \
cairo-gl-shaders.c \ cairo-gl-shaders.c \
cairo-gl-spans-compositor.c \
cairo-gl-traps-compositor.c \
cairo-gl-surface.c cairo-gl-surface.c
cairo_glesv2_headers = $(cairo_gl_headers) cairo_glesv2_headers = $(cairo_gl_headers)

View file

@ -144,7 +144,7 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
cairo_analysis_surface_t *tmp; cairo_analysis_surface_t *tmp;
cairo_surface_t *source, *proxy; cairo_surface_t *source, *proxy;
cairo_matrix_t p2d; cairo_matrix_t p2d;
cairo_status_t status; cairo_status_t status, analysis_status;
assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
surface_pattern = (const cairo_surface_pattern_t *) pattern; surface_pattern = (const cairo_surface_pattern_t *) pattern;
@ -175,11 +175,16 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
if (_cairo_surface_is_subsurface (source)) if (_cairo_surface_is_subsurface (source))
source = _cairo_surface_subsurface_get_target (source); source = _cairo_surface_subsurface_get_target (source);
status = _cairo_recording_surface_replay_and_create_regions (source, &tmp->base); status = _cairo_recording_surface_replay_and_create_regions (source,
&tmp->base);
analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS;
detach_proxy (proxy); detach_proxy (proxy);
cairo_surface_destroy (&tmp->base); cairo_surface_destroy (&tmp->base);
return status; if (unlikely (status))
return status;
return analysis_status;
} }
static cairo_int_status_t static cairo_int_status_t
@ -548,8 +553,7 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs, cairo_glyph_t *glyphs,
int num_glyphs, int num_glyphs,
cairo_scaled_font_t *scaled_font, cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip, const cairo_clip_t *clip)
int *remaining_glyphs)
{ {
cairo_analysis_surface_t *surface = abstract_surface; cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t status, backend_status; cairo_int_status_t status, backend_status;
@ -562,8 +566,7 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
source, source,
glyphs, num_glyphs, glyphs, num_glyphs,
scaled_font, scaled_font,
clip, clip);
remaining_glyphs);
if (_cairo_int_status_is_error (backend_status)) if (_cairo_int_status_is_error (backend_status))
return backend_status; return backend_status;
} }
@ -652,21 +655,14 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED &&
surface->target->backend->show_glyphs != NULL) surface->target->backend->show_glyphs != NULL)
{ {
int remaining_glyphs = num_glyphs;
backend_status = backend_status =
surface->target->backend->show_glyphs (surface->target, op, surface->target->backend->show_glyphs (surface->target, op,
source, source,
glyphs, num_glyphs, glyphs, num_glyphs,
scaled_font, scaled_font,
clip, clip);
&remaining_glyphs);
if (_cairo_int_status_is_error (backend_status)) if (_cairo_int_status_is_error (backend_status))
return backend_status; return backend_status;
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
backend_status = CAIRO_STATUS_SUCCESS;
} }
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
@ -701,35 +697,26 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
NULL, /* create_similar_image */ NULL, /* create_similar_image */
NULL, /* map_to_image */ NULL, /* map_to_image */
NULL, /* unmap */ NULL, /* unmap */
NULL, /* acquire_source_image */ NULL, /* acquire_source_image */
NULL, /* release_source_image */ NULL, /* release_source_image */
NULL, /* acquire_dest_image */ NULL, /* snapshot */
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
NULL, /* copy_page */ NULL, /* copy_page */
NULL, /* show_page */ NULL, /* show_page */
_cairo_analysis_surface_get_extents, _cairo_analysis_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */ NULL, /* get_font_options */
NULL, /* flush */ NULL, /* flush */
NULL, /* mark_dirty_rectangle */ NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
_cairo_analysis_surface_paint, _cairo_analysis_surface_paint,
_cairo_analysis_surface_mask, _cairo_analysis_surface_mask,
_cairo_analysis_surface_stroke, _cairo_analysis_surface_stroke,
_cairo_analysis_surface_fill, _cairo_analysis_surface_fill,
_cairo_analysis_surface_show_glyphs,
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* fill_stroke */ NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */ _cairo_analysis_surface_show_glyphs,
NULL, /* can_repaint_solid_pattern_surface */
_cairo_analysis_surface_has_show_text_glyphs, _cairo_analysis_surface_has_show_text_glyphs,
_cairo_analysis_surface_show_text_glyphs _cairo_analysis_surface_show_text_glyphs
}; };
@ -891,48 +878,38 @@ typedef cairo_int_status_t
cairo_glyph_t *glyphs, cairo_glyph_t *glyphs,
int num_glyphs, int num_glyphs,
cairo_scaled_font_t *scaled_font, cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip, const cairo_clip_t *clip);
int *remaining_glyphs);
static const cairo_surface_backend_t cairo_null_surface_backend = { static const cairo_surface_backend_t cairo_null_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_NULL, CAIRO_INTERNAL_SURFACE_TYPE_NULL,
NULL, /* finish */ NULL, /* finish */
_cairo_default_context_create, /* XXX */ NULL, /* only accessed through the surface functions */
NULL, /* create_similar */ NULL, /* create_similar */
NULL, /* create similar image */ NULL, /* create similar image */
NULL, /* map to image */ NULL, /* map to image */
NULL, /* unmap image*/ NULL, /* unmap image*/
NULL, /* acquire_source_image */ NULL, /* acquire_source_image */
NULL, /* release_source_image */ NULL, /* release_source_image */
NULL, /* acquire_dest_image */ NULL, /* snapshot */
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
NULL, /* copy_page */ NULL, /* copy_page */
NULL, /* show_page */ NULL, /* show_page */
NULL, /* get_extents */ NULL, /* get_extents */
NULL, /* old_show_glyphs */
NULL, /* get_font_options */ NULL, /* get_font_options */
NULL, /* flush */ NULL, /* flush */
NULL, /* mark_dirty_rectangle */ NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
(_paint_func) _return_success, /* paint */ (_paint_func) _return_success, /* paint */
(_mask_func) _return_success, /* mask */ (_mask_func) _return_success, /* mask */
(_stroke_func) _return_success, /* stroke */ (_stroke_func) _return_success, /* stroke */
(_fill_func) _return_success, /* fill */ (_fill_func) _return_success, /* fill */
(_show_glyphs_func) _return_success, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* fill_stroke */ NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */ (_show_glyphs_func) _return_success, /* show_glyphs */
NULL, /* can_repaint_solid_pattern_surface */
NULL, /* has_show_text_glyphs */ NULL, /* has_show_text_glyphs */
NULL /* show_text_glyphs */ NULL /* show_text_glyphs */
}; };

90
src/cairo-array-private.h Normal file
View file

@ -0,0 +1,90 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#ifndef CAIRO_ARRAY_PRIVATE_H
#define CAIRO_ARRAY_PRIVATE_H
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
CAIRO_BEGIN_DECLS
/* cairo-array.c structures and functions */
cairo_private void
_cairo_array_init (cairo_array_t *array, unsigned int element_size);
cairo_private void
_cairo_array_fini (cairo_array_t *array);
cairo_private cairo_status_t
_cairo_array_grow_by (cairo_array_t *array, unsigned int additional);
cairo_private void
_cairo_array_truncate (cairo_array_t *array, unsigned int num_elements);
cairo_private cairo_status_t
_cairo_array_append (cairo_array_t *array, const void *element);
cairo_private cairo_status_t
_cairo_array_append_multiple (cairo_array_t *array,
const void *elements,
unsigned int num_elements);
cairo_private cairo_status_t
_cairo_array_allocate (cairo_array_t *array,
unsigned int num_elements,
void **elements);
cairo_private void *
_cairo_array_index (cairo_array_t *array, unsigned int index);
cairo_private const void *
_cairo_array_index_const (const cairo_array_t *array, unsigned int index);
cairo_private void
_cairo_array_copy_element (const cairo_array_t *array, unsigned int index, void *dst);
cairo_private unsigned int
_cairo_array_num_elements (const cairo_array_t *array);
cairo_private unsigned int
_cairo_array_size (const cairo_array_t *array);
CAIRO_END_DECLS
#endif /* CAIRO_ARRAY_PRIVATE_H */

View file

@ -37,6 +37,7 @@
*/ */
#include "cairoint.h" #include "cairoint.h"
#include "cairo-array-private.h"
#include "cairo-error-private.h" #include "cairo-error-private.h"
/** /**
@ -385,11 +386,11 @@ _cairo_user_data_array_fini (cairo_user_data_array_t *array)
cairo_user_data_slot_t *slots; cairo_user_data_slot_t *slots;
slots = _cairo_array_index (array, 0); slots = _cairo_array_index (array, 0);
do { while (num_slots--) {
if (slots->user_data != NULL && slots->destroy != NULL) cairo_user_data_slot_t *s = &slots[num_slots];
slots->destroy (slots->user_data); if (s->user_data != NULL && s->destroy != NULL)
slots++; s->destroy (s->user_data);
} while (--num_slots); }
} }
_cairo_array_fini (array); _cairo_array_fini (array);

View file

@ -79,6 +79,7 @@ _cairo_atomic_ptr_get (void **x)
#endif #endif
# define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1)) # define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1))
# define _cairo_atomic_int_dec(x) ((void) __sync_fetch_and_add(x, -1))
# define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1) # define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_bool_compare_and_swap (x, oldv, newv) # define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_bool_compare_and_swap (x, oldv, newv)
# define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv) # define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
@ -111,6 +112,7 @@ typedef AO_t cairo_atomic_int_t;
# define _cairo_atomic_int_get(x) (AO_load_full (x)) # define _cairo_atomic_int_get(x) (AO_load_full (x))
# define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x)) # define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x))
# define _cairo_atomic_int_dec(x) ((void) AO_fetch_and_sub1_full(x))
# define _cairo_atomic_int_dec_and_test(x) (AO_fetch_and_sub1_full(x) == 1) # define _cairo_atomic_int_dec_and_test(x) (AO_fetch_and_sub1_full(x) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) AO_compare_and_swap_full(x, oldv, newv) # define _cairo_atomic_int_cmpxchg(x, oldv, newv) AO_compare_and_swap_full(x, oldv, newv)
@ -140,6 +142,7 @@ typedef int32_t cairo_atomic_int_t;
# define _cairo_atomic_int_get(x) (OSMemoryBarrier(), *(x)) # define _cairo_atomic_int_get(x) (OSMemoryBarrier(), *(x))
# define _cairo_atomic_int_inc(x) ((void) OSAtomicIncrement32Barrier (x)) # define _cairo_atomic_int_inc(x) ((void) OSAtomicIncrement32Barrier (x))
# define _cairo_atomic_int_dec(x) ((void) OSAtomicDecrement32Barrier (x))
# define _cairo_atomic_int_dec_and_test(x) (OSAtomicDecrement32Barrier (x) == 0) # define _cairo_atomic_int_dec_and_test(x) (OSAtomicDecrement32Barrier (x) == 0)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) OSAtomicCompareAndSwap32Barrier(oldv, newv, x) # define _cairo_atomic_int_cmpxchg(x, oldv, newv) OSAtomicCompareAndSwap32Barrier(oldv, newv, x)
@ -178,6 +181,8 @@ typedef cairo_atomic_intptr_t cairo_atomic_int_t;
cairo_private void cairo_private void
_cairo_atomic_int_inc (cairo_atomic_int_t *x); _cairo_atomic_int_inc (cairo_atomic_int_t *x);
#define _cairo_atomic_int_dec(x) _cairo_atomic_int_dec_and_test(x)
cairo_private cairo_bool_t cairo_private cairo_bool_t
_cairo_atomic_int_dec_and_test (cairo_atomic_int_t *x); _cairo_atomic_int_dec_and_test (cairo_atomic_int_t *x);

View file

@ -42,6 +42,7 @@
#include "cairo-error-private.h" #include "cairo-error-private.h"
#include "cairo-combsort-private.h" #include "cairo-combsort-private.h"
#include "cairo-list-private.h" #include "cairo-list-private.h"
#include "cairo-traps-private.h"
#include <setjmp.h> #include <setjmp.h>
@ -740,7 +741,7 @@ _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 3]; rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 3];
rectangle_t *rectangles, **rectangles_ptrs; rectangle_t *rectangles, **rectangles_ptrs;
rectangle_t *stack_rectangles_chain[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *) ]; rectangle_t *stack_rectangles_chain[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *) ];
rectangle_t **rectangles_chain; rectangle_t **rectangles_chain = NULL;
const struct _cairo_boxes_chunk *chunk; const struct _cairo_boxes_chunk *chunk;
cairo_status_t status; cairo_status_t status;
int i, j, y_min, y_max; int i, j, y_min, y_max;
@ -789,13 +790,15 @@ _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
y_max = _cairo_fixed_integer_floor (y_max) + 1; y_max = _cairo_fixed_integer_floor (y_max) + 1;
y_max -= y_min; y_max -= y_min;
rectangles_chain = stack_rectangles_chain; if (y_max < in->num_boxes) {
if (y_max > ARRAY_LENGTH (stack_rectangles_chain)) { rectangles_chain = stack_rectangles_chain;
rectangles_chain = _cairo_malloc_ab (y_max, sizeof (rectangle_t *)); if (y_max > ARRAY_LENGTH (stack_rectangles_chain)) {
if (unlikely (rectangles_chain == NULL)) rectangles_chain = _cairo_malloc_ab (y_max, sizeof (rectangle_t *));
return _cairo_error (CAIRO_STATUS_NO_MEMORY); if (unlikely (rectangles_chain == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
memset (rectangles_chain, 0, y_max * sizeof (rectangle_t*));
} }
memset (rectangles_chain, 0, y_max * sizeof (rectangle_t*));
rectangles = stack_rectangles; rectangles = stack_rectangles;
rectangles_ptrs = stack_rectangles_ptrs; rectangles_ptrs = stack_rectangles_ptrs;
@ -839,28 +842,38 @@ _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
rectangles[j].top = box[i].p1.y; rectangles[j].top = box[i].p1.y;
rectangles[j].bottom = box[i].p2.y; rectangles[j].bottom = box[i].p2.y;
h = _cairo_fixed_integer_floor (box[i].p1.y) - y_min; if (rectangles_chain) {
rectangles[j].left.next = (edge_t *)rectangles_chain[h]; h = _cairo_fixed_integer_floor (box[i].p1.y) - y_min;
rectangles_chain[h] = &rectangles[j]; rectangles[j].left.next = (edge_t *)rectangles_chain[h];
rectangles_chain[h] = &rectangles[j];
} else {
rectangles_ptrs[j+2] = &rectangles[j];
}
j++; j++;
} }
} }
j = 2; if (rectangles_chain) {
for (y_min = 0; y_min < y_max; y_min++) { j = 2;
rectangle_t *r; for (y_min = 0; y_min < y_max; y_min++) {
int start = j; rectangle_t *r;
for (r = rectangles_chain[y_min]; r; r = (rectangle_t *)r->left.next) int start = j;
rectangles_ptrs[j++] = r; for (r = rectangles_chain[y_min]; r; r = (rectangle_t *)r->left.next)
if (j > start + 1) rectangles_ptrs[j++] = r;
if (j > start + 1)
_rectangle_sort (rectangles_ptrs + start, j - start); _rectangle_sort (rectangles_ptrs + start, j - start);
}
if (rectangles_chain != stack_rectangles_chain)
free (rectangles_chain);
j -= 2;
} else {
_rectangle_sort (rectangles_ptrs + 2, j);
} }
if (rectangles_chain != stack_rectangles_chain)
free (rectangles_chain);
_cairo_boxes_clear (out); _cairo_boxes_clear (out);
status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, j-2, status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, j,
fill_rule, fill_rule,
FALSE, out); FALSE, out);
if (rectangles != stack_rectangles) if (rectangles != stack_rectangles)

View file

@ -41,6 +41,7 @@
#include "cairo-boxes-private.h" #include "cairo-boxes-private.h"
#include "cairo-combsort-private.h" #include "cairo-combsort-private.h"
#include "cairo-error-private.h" #include "cairo-error-private.h"
#include "cairo-traps-private.h"
typedef struct _cairo_bo_edge cairo_bo_edge_t; typedef struct _cairo_bo_edge cairo_bo_edge_t;
typedef struct _cairo_bo_trap cairo_bo_trap_t; typedef struct _cairo_bo_trap cairo_bo_trap_t;
@ -436,74 +437,6 @@ _cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps,
const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule)
{
cairo_status_t status;
cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
cairo_bo_event_t *events;
cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
cairo_bo_event_t **event_ptrs;
cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
cairo_bo_edge_t *edges;
int num_events;
int i, j;
if (unlikely (polygon->num_edges == 0))
return CAIRO_STATUS_SUCCESS;
num_events = 2 * polygon->num_edges;
events = stack_events;
event_ptrs = stack_event_ptrs;
edges = stack_edges;
if (num_events > ARRAY_LENGTH (stack_events)) {
events = _cairo_malloc_ab_plus_c (num_events,
sizeof (cairo_bo_event_t) +
sizeof (cairo_bo_edge_t) +
sizeof (cairo_bo_event_t *),
sizeof (cairo_bo_event_t *));
if (unlikely (events == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
event_ptrs = (cairo_bo_event_t **) (events + num_events);
edges = (cairo_bo_edge_t *) (event_ptrs + num_events + 1);
}
for (i = j = 0; i < polygon->num_edges; i++) {
edges[i].edge = polygon->edges[i];
edges[i].deferred_trap.right = NULL;
edges[i].prev = NULL;
edges[i].next = NULL;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = polygon->edges[i].top;
events[j].point.x = polygon->edges[i].line.p1.x;
events[j].edge = &edges[i];
j++;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = polygon->edges[i].bottom;
events[j].point.x = polygon->edges[i].line.p1.x;
events[j].edge = &edges[i];
j++;
}
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
fill_rule,
TRUE, traps);
if (events != stack_events)
free (events);
traps->is_rectilinear = TRUE;
return status;
}
cairo_status_t cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon, _cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule, cairo_fill_rule_t fill_rule,

View file

@ -41,6 +41,7 @@
#include "cairo-error-private.h" #include "cairo-error-private.h"
#include "cairo-freelist-private.h" #include "cairo-freelist-private.h"
#include "cairo-combsort-private.h" #include "cairo-combsort-private.h"
#include "cairo-traps-private.h"
#define DEBUG_PRINT_STATE 0 #define DEBUG_PRINT_STATE 0
#define DEBUG_EVENTS 0 #define DEBUG_EVENTS 0
@ -1301,7 +1302,14 @@ event_log (const char *fmt, ...)
static inline cairo_bool_t static inline cairo_bool_t
edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b) edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
{ {
if (_line_equal (&a->edge.line, &b->edge.line)) unsigned p;
p = 0;
p |= (a->edge.line.p1.x == b->edge.line.p1.x) << 0;
p |= (a->edge.line.p1.y == b->edge.line.p1.y) << 1;
p |= (a->edge.line.p2.x == b->edge.line.p2.x) << 3;
p |= (a->edge.line.p2.y == b->edge.line.p2.y) << 4;
if (p == ((1 << 0) | (1 << 1) | (1 << 3) | (1 << 4)))
return TRUE; return TRUE;
if (_slope_compare (a, b)) if (_slope_compare (a, b))
@ -1310,8 +1318,9 @@ edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
/* The choice of y is not truly arbitrary since we must guarantee that it /* The choice of y is not truly arbitrary since we must guarantee that it
* is greater than the start of either line. * is greater than the start of either line.
*/ */
if (a->edge.line.p1.y == b->edge.line.p1.y) { if (p != 0) {
return a->edge.line.p1.x == b->edge.line.p1.x; /* colinear if either end-point are coincident */
return ((p >> 1) & p) != 0;
} else if (a->edge.line.p1.y < b->edge.line.p1.y) { } else if (a->edge.line.p1.y < b->edge.line.p1.y) {
return edge_compare_for_y_against_x (b, return edge_compare_for_y_against_x (b,
a->edge.line.p1.y, a->edge.line.p1.y,
@ -1377,8 +1386,9 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
if (left->deferred_trap.right == right) if (left->deferred_trap.right == right)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
assert (right);
if (left->deferred_trap.right != NULL) { if (left->deferred_trap.right != NULL) {
if (right != NULL && edges_colinear (left->deferred_trap.right, right)) if (edges_colinear (left->deferred_trap.right, right))
{ {
/* continuation on right, so just swap edges */ /* continuation on right, so just swap edges */
left->deferred_trap.right = right; left->deferred_trap.right = right;
@ -1390,7 +1400,7 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
return status; return status;
} }
if (right != NULL && ! edges_colinear (left, right)) { if (! edges_colinear (left, right)) {
left->deferred_trap.top = top; left->deferred_trap.top = top;
left->deferred_trap.right = right; left->deferred_trap.right = right;
@ -1406,112 +1416,50 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
} }
static inline cairo_status_t static inline cairo_status_t
_active_edges_to_traps (cairo_bo_edge_t *left, _active_edges_to_traps (cairo_bo_edge_t *pos,
int32_t top, int32_t top,
cairo_fill_rule_t fill_rule, unsigned mask,
cairo_traps_t *traps) cairo_traps_t *traps)
{ {
cairo_bo_edge_t *right; cairo_bo_edge_t *left;
cairo_status_t status; cairo_status_t status;
int in_out;
#if DEBUG_PRINT_STATE #if DEBUG_PRINT_STATE
printf ("Processing active edges for %x\n", top); printf ("Processing active edges for %x\n", top);
#endif #endif
if (fill_rule == CAIRO_FILL_RULE_WINDING) { in_out = 0;
while (left != NULL) { left = pos;
int in_out; while (pos != NULL) {
if (pos != left && pos->deferred_trap.right) {
/* Greedily search for the closing edge, so that we generate the if (edges_colinear (left, pos)) {
* maximal span width with the minimal number of trapezoids. /* continuation on left */
*/ assert (left->deferred_trap.right == NULL);
in_out = left->edge.dir; left->deferred_trap = pos->deferred_trap;
pos->deferred_trap.right = NULL;
/* Check if there is a co-linear edge with an existing trap */ } else {
right = left->next; status = _cairo_bo_edge_end_trap (pos, top, traps);
if (left->deferred_trap.right == NULL) { if (unlikely (status))
while (right != NULL && right->deferred_trap.right == NULL) return status;
right = right->next;
if (right != NULL && edges_colinear (left, right)) {
/* continuation on left */
left->deferred_trap = right->deferred_trap;
right->deferred_trap.right = NULL;
}
} }
/* End all subsumed traps */
right = left->next;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, traps);
if (unlikely (status))
return status;
}
in_out += right->edge.dir;
if (in_out == 0) {
cairo_bo_edge_t *next;
cairo_bool_t skip = FALSE;
/* skip co-linear edges */
next = right->next;
if (next != NULL)
skip = edges_colinear (right, next);
if (! skip)
break;
}
right = right->next;
}
status = _cairo_bo_edge_start_or_continue_trap (left, right,
top, traps);
if (unlikely (status))
return status;
left = right;
if (left != NULL)
left = left->next;
} }
} else {
while (left != NULL) {
int in_out = 0;
right = left->next; in_out += pos->edge.dir;
while (right != NULL) { if ((in_out & mask) == 0) {
if (right->deferred_trap.right != NULL) { /* skip co-linear edges */
status = _cairo_bo_edge_end_trap (right, top, traps); if (pos->next == NULL || ! edges_colinear (pos, pos->next)) {
if (unlikely (status)) status = _cairo_bo_edge_start_or_continue_trap (left, pos,
return status; top, traps);
} if (unlikely (status))
return status;
if ((in_out++ & 1) == 0) { left = pos->next;
cairo_bo_edge_t *next;
cairo_bool_t skip = FALSE;
/* skip co-linear edges */
next = right->next;
if (next != NULL)
skip = edges_colinear (right, next);
if (! skip)
break;
}
right = right->next;
} }
status = _cairo_bo_edge_start_or_continue_trap (left, right,
top, traps);
if (unlikely (status))
return status;
left = right;
if (left != NULL)
left = left->next;
} }
pos = pos->next;
} }
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
@ -1524,7 +1472,7 @@ _active_edges_to_traps (cairo_bo_edge_t *left,
static cairo_status_t static cairo_status_t
_cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t **start_events, _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t **start_events,
int num_events, int num_events,
cairo_fill_rule_t fill_rule, unsigned fill_rule,
cairo_traps_t *traps, cairo_traps_t *traps,
int *num_intersections) int *num_intersections)
{ {
@ -1536,6 +1484,12 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t **start_events,
cairo_bo_edge_t *left, *right; cairo_bo_edge_t *left, *right;
cairo_bo_edge_t *e1, *e2; cairo_bo_edge_t *e1, *e2;
/* convert the fill_rule into a winding mask */
if (fill_rule == CAIRO_FILL_RULE_WINDING)
fill_rule = (unsigned) -1;
else
fill_rule = 1;
#if DEBUG_EVENTS #if DEBUG_EVENTS
{ {
int i; int i;
@ -1781,7 +1735,7 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
for (y = i = 0; y < ymax && i < num_events; y++) { for (y = i = 0; y < ymax && i < num_events; y++) {
cairo_bo_start_event_t *e; cairo_bo_start_event_t *e;
int j = i; int j = i;
for (e = event_y[y]; e; e = (cairo_bo_start_event_t *)e->edge.next) for (e = event_y[y]; e; e = (cairo_bo_start_event_t *)e->edge.next)
event_ptrs[i++] = (cairo_bo_event_t *) e; event_ptrs[i++] = (cairo_bo_event_t *) e;
if (i > j + 1) if (i > j + 1)
_cairo_bo_event_queue_sort (event_ptrs+j, i-j); _cairo_bo_event_queue_sort (event_ptrs+j, i-j);

View file

@ -1397,6 +1397,7 @@ render_rows (cairo_botor_scan_converter_t *self,
if (x > prev_x) { if (x > prev_x) {
spans[num_spans].x = prev_x; spans[num_spans].x = prev_x;
spans[num_spans].inverse = 0;
spans[num_spans].coverage = AREA_TO_ALPHA (cover); spans[num_spans].coverage = AREA_TO_ALPHA (cover);
++num_spans; ++num_spans;
} }
@ -1413,12 +1414,14 @@ render_rows (cairo_botor_scan_converter_t *self,
if (prev_x <= self->xmax) { if (prev_x <= self->xmax) {
spans[num_spans].x = prev_x; spans[num_spans].x = prev_x;
spans[num_spans].inverse = 0;
spans[num_spans].coverage = AREA_TO_ALPHA (cover); spans[num_spans].coverage = AREA_TO_ALPHA (cover);
++num_spans; ++num_spans;
} }
if (cover && prev_x < self->xmax) { if (cover && prev_x < self->xmax) {
spans[num_spans].x = self->xmax; spans[num_spans].x = self->xmax;
spans[num_spans].inverse = 1;
spans[num_spans].coverage = 0; spans[num_spans].coverage = 0;
++num_spans; ++num_spans;
} }
@ -2179,8 +2182,6 @@ _cairo_botor_scan_converter_init (cairo_botor_scan_converter_t *self,
cairo_fill_rule_t fill_rule) cairo_fill_rule_t fill_rule)
{ {
self->base.destroy = _cairo_botor_scan_converter_destroy; self->base.destroy = _cairo_botor_scan_converter_destroy;
self->base.add_edge = _cairo_botor_scan_converter_add_edge;
self->base.add_polygon = _cairo_botor_scan_converter_add_polygon;
self->base.generate = _cairo_botor_scan_converter_generate; self->base.generate = _cairo_botor_scan_converter_generate;
self->extents = *extents; self->extents = *extents;

View file

@ -37,6 +37,7 @@
#include "cairo-types-private.h" #include "cairo-types-private.h"
#include "cairo-compiler-private.h" #include "cairo-compiler-private.h"
#include "cairo-fixed-private.h"
static inline void static inline void
_cairo_box_set (cairo_box_t *box, _cairo_box_set (cairo_box_t *box,
@ -47,6 +48,15 @@ _cairo_box_set (cairo_box_t *box,
box->p2 = *p2; box->p2 = *p2;
} }
static inline void
_cairo_box_from_integers (cairo_box_t *box, int x, int y, int w, int h)
{
box->p1.x = _cairo_fixed_from_int (x);
box->p1.y = _cairo_fixed_from_int (y);
box->p2.x = _cairo_fixed_from_int (x + w);
box->p2.y = _cairo_fixed_from_int (y + h);
}
/* assumes box->p1 is top-left, p2 bottom-right */ /* assumes box->p1 is top-left, p2 bottom-right */
static inline void static inline void
_cairo_box_add_point (cairo_box_t *box, _cairo_box_add_point (cairo_box_t *box,
@ -63,13 +73,49 @@ _cairo_box_add_point (cairo_box_t *box,
box->p2.y = point->y; box->p2.y = point->y;
} }
static inline void
_cairo_box_add_box (cairo_box_t *box,
const cairo_box_t *add)
{
if (add->p1.x < box->p1.x)
box->p1.x = add->p1.x;
if (add->p2.x > box->p2.x)
box->p2.x = add->p2.x;
if (add->p1.y < box->p1.y)
box->p1.y = add->p1.y;
if (add->p2.y > box->p2.y)
box->p2.y = add->p2.y;
}
/* assumes box->p1 is top-left, p2 bottom-right */ /* assumes box->p1 is top-left, p2 bottom-right */
static inline cairo_bool_t static inline cairo_bool_t
_cairo_box_contains_point (cairo_box_t *box, _cairo_box_contains_point (const cairo_box_t *box,
const cairo_point_t *point) const cairo_point_t *point)
{ {
return box->p1.x <= point->x && point->x <= box->p2.x && return box->p1.x <= point->x && point->x <= box->p2.x &&
box->p1.y <= point->y && point->y <= box->p2.y; box->p1.y <= point->y && point->y <= box->p2.y;
} }
static inline cairo_bool_t
_cairo_box_is_pixel_aligned (const cairo_box_t *box)
{
#if CAIRO_FIXED_FRAC_BITS <= 8 && 0
return ((box->p1.x & CAIRO_FIXED_FRAC_MASK) << 24 |
(box->p1.y & CAIRO_FIXED_FRAC_MASK) << 16 |
(box->p2.x & CAIRO_FIXED_FRAC_MASK) << 8 |
(box->p2.y & CAIRO_FIXED_FRAC_MASK) << 0) == 0;
#else /* GCC on i7 prefers this variant (bizarrely according to the profiler) */
cairo_fixed_t f;
f = 0;
f |= box->p1.x & CAIRO_FIXED_FRAC_MASK;
f |= box->p1.y & CAIRO_FIXED_FRAC_MASK;
f |= box->p2.x & CAIRO_FIXED_FRAC_MASK;
f |= box->p2.y & CAIRO_FIXED_FRAC_MASK;
return f == 0;
#endif
}
#endif /* CAIRO_BOX_H */ #endif /* CAIRO_BOX_H */

View file

@ -535,19 +535,44 @@ _cairo_boxes_intersect_with_box (const cairo_boxes_t *boxes,
const cairo_box_t *box, const cairo_box_t *box,
cairo_boxes_t *out) cairo_boxes_t *out)
{ {
const struct _cairo_boxes_chunk *chunk;
cairo_status_t status; cairo_status_t status;
int i; int i, j;
_cairo_boxes_clear (out); if (out == boxes) { /* inplace update */
_cairo_boxes_limit (out, box, 1); struct _cairo_boxes_chunk *chunk;
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) { out->num_boxes = 0;
status = _cairo_boxes_add (out, for (chunk = &out->chunks; chunk != NULL; chunk = chunk->next) {
CAIRO_ANTIALIAS_DEFAULT, for (i = j = 0; i < chunk->count; i++) {
&chunk->base[i]); cairo_box_t *b = &chunk->base[i];
if (unlikely (status))
return status; b->p1.x = MAX (b->p1.x, box->p1.x);
b->p1.y = MAX (b->p1.y, box->p1.y);
b->p2.x = MIN (b->p2.x, box->p2.x);
b->p2.y = MIN (b->p2.y, box->p2.y);
if (b->p1.x < b->p2.x && b->p1.y < b->p2.y) {
if (i != j)
chunk->base[j] = *b;
j++;
}
}
/* XXX unlink empty chains? */
chunk->count = j;
out->num_boxes += j;
}
} else {
const struct _cairo_boxes_chunk *chunk;
_cairo_boxes_clear (out);
_cairo_boxes_limit (out, box, 1);
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
status = _cairo_boxes_add (out,
CAIRO_ANTIALIAS_DEFAULT,
&chunk->base[i]);
if (unlikely (status))
return status;
}
} }
} }

View file

@ -42,11 +42,14 @@
struct _cairo_boxes_t { struct _cairo_boxes_t {
cairo_status_t status; cairo_status_t status;
cairo_box_t limit; cairo_box_t limit;
const cairo_box_t *limits; const cairo_box_t *limits;
int num_limits; int num_limits;
int num_boxes; int num_boxes;
unsigned int is_pixel_aligned : 1;
unsigned int is_pixel_aligned;
struct _cairo_boxes_chunk { struct _cairo_boxes_chunk {
struct _cairo_boxes_chunk *next; struct _cairo_boxes_chunk *next;
@ -69,6 +72,10 @@ _cairo_boxes_init_for_array (cairo_boxes_t *boxes,
cairo_box_t *array, cairo_box_t *array,
int num_boxes); int num_boxes);
cairo_private void
_cairo_boxes_init_from_rectangle (cairo_boxes_t *boxes,
int x, int y, int w, int h);
cairo_private void cairo_private void
_cairo_boxes_limit (cairo_boxes_t *boxes, _cairo_boxes_limit (cairo_boxes_t *boxes,
const cairo_box_t *limits, const cairo_box_t *limits,
@ -81,7 +88,7 @@ _cairo_boxes_add (cairo_boxes_t *boxes,
cairo_private void cairo_private void
_cairo_boxes_extents (const cairo_boxes_t *boxes, _cairo_boxes_extents (const cairo_boxes_t *boxes,
cairo_rectangle_int_t *extents); cairo_box_t *box);
cairo_private cairo_box_t * cairo_private cairo_box_t *
_cairo_boxes_to_array (const cairo_boxes_t *boxes, _cairo_boxes_to_array (const cairo_boxes_t *boxes,
@ -104,6 +111,11 @@ _cairo_boxes_intersect (const cairo_boxes_t *a,
cairo_private void cairo_private void
_cairo_boxes_clear (cairo_boxes_t *boxes); _cairo_boxes_clear (cairo_boxes_t *boxes);
cairo_private_no_warn cairo_bool_t
_cairo_boxes_for_each_box (cairo_boxes_t *boxes,
cairo_bool_t (*func) (cairo_box_t *box, void *data),
void *data);
cairo_private void cairo_private void
_cairo_boxes_fini (cairo_boxes_t *boxes); _cairo_boxes_fini (cairo_boxes_t *boxes);

View file

@ -33,6 +33,7 @@
#include "cairoint.h" #include "cairoint.h"
#include "cairo-box-private.h"
#include "cairo-boxes-private.h" #include "cairo-boxes-private.h"
#include "cairo-error-private.h" #include "cairo-error-private.h"
@ -52,6 +53,16 @@ _cairo_boxes_init (cairo_boxes_t *boxes)
boxes->is_pixel_aligned = TRUE; boxes->is_pixel_aligned = TRUE;
} }
void
_cairo_boxes_init_from_rectangle (cairo_boxes_t *boxes,
int x, int y, int w, int h)
{
_cairo_boxes_init (boxes);
_cairo_box_from_integers (&boxes->chunks.base[0], x, y, w, h);
boxes->num_boxes = 1;
}
void void
_cairo_boxes_init_with_clip (cairo_boxes_t *boxes, _cairo_boxes_init_with_clip (cairo_boxes_t *boxes,
cairo_clip_t *clip) cairo_clip_t *clip)
@ -154,13 +165,8 @@ _cairo_boxes_add_internal (cairo_boxes_t *boxes,
chunk->base[chunk->count++] = *box; chunk->base[chunk->count++] = *box;
boxes->num_boxes++; boxes->num_boxes++;
if (boxes->is_pixel_aligned) { if (boxes->is_pixel_aligned)
boxes->is_pixel_aligned = boxes->is_pixel_aligned = _cairo_box_is_pixel_aligned (box);
_cairo_fixed_is_integer (box->p1.x) &&
_cairo_fixed_is_integer (box->p1.y) &&
_cairo_fixed_is_integer (box->p2.x) &&
_cairo_fixed_is_integer (box->p2.y);
}
} }
cairo_status_t cairo_status_t
@ -261,38 +267,34 @@ _cairo_boxes_add (cairo_boxes_t *boxes,
void void
_cairo_boxes_extents (const cairo_boxes_t *boxes, _cairo_boxes_extents (const cairo_boxes_t *boxes,
cairo_rectangle_int_t *extents) cairo_box_t *box)
{ {
const struct _cairo_boxes_chunk *chunk; const struct _cairo_boxes_chunk *chunk;
cairo_box_t box; cairo_box_t b;
int i; int i;
if (boxes->num_boxes == 0) { if (boxes->num_boxes == 0) {
extents->x = extents->y = extents->width = extents->height = 0; box->p1.x = box->p1.y = box->p2.x = box->p2.y = 0;
return; return;
} }
box.p1.y = box.p1.x = INT_MAX; b = boxes->chunks.base[0];
box.p2.y = box.p2.x = INT_MIN;
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
const cairo_box_t *b = chunk->base;
for (i = 0; i < chunk->count; i++) { for (i = 0; i < chunk->count; i++) {
if (b[i].p1.x < box.p1.x) if (chunk->base[i].p1.x < b.p1.x)
box.p1.x = b[i].p1.x; b.p1.x = chunk->base[i].p1.x;
if (b[i].p1.y < box.p1.y) if (chunk->base[i].p1.y < b.p1.y)
box.p1.y = b[i].p1.y; b.p1.y = chunk->base[i].p1.y;
if (b[i].p2.x > box.p2.x) if (chunk->base[i].p2.x > b.p2.x)
box.p2.x = b[i].p2.x; b.p2.x = chunk->base[i].p2.x;
if (b[i].p2.y > box.p2.y) if (chunk->base[i].p2.y > b.p2.y)
box.p2.y = b[i].p2.y; b.p2.y = chunk->base[i].p2.y;
} }
} }
*box = b;
_cairo_box_round_to_rectangle (&box, extents);
} }
void void
@ -354,17 +356,38 @@ _cairo_boxes_fini (cairo_boxes_t *boxes)
} }
} }
cairo_bool_t
_cairo_boxes_for_each_box (cairo_boxes_t *boxes,
cairo_bool_t (*func) (cairo_box_t *box, void *data),
void *data)
{
struct _cairo_boxes_chunk *chunk;
int i;
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++)
if (! func (&chunk->base[i], data))
return FALSE;
}
return TRUE;
}
void void
_cairo_debug_print_boxes (FILE *stream, const cairo_boxes_t *boxes) _cairo_debug_print_boxes (FILE *stream, const cairo_boxes_t *boxes)
{ {
cairo_rectangle_int_t extents;
const struct _cairo_boxes_chunk *chunk; const struct _cairo_boxes_chunk *chunk;
cairo_box_t extents;
int i; int i;
_cairo_boxes_extents (boxes, &extents); _cairo_boxes_extents (boxes, &extents);
fprintf (stream, "boxes x %d: (%d, %d) x (%d, %d)\n", fprintf (stream, "boxes x %d: (%f, %f) x (%f, %f)\n",
boxes->num_boxes, boxes->num_boxes,
extents.x, extents.y, extents.width, extents.height); _cairo_fixed_to_double (extents.p1.x),
_cairo_fixed_to_double (extents.p1.y),
_cairo_fixed_to_double (extents.p2.x),
_cairo_fixed_to_double (extents.p2.y));
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) { for (i = 0; i < chunk->count; i++) {

View file

@ -42,6 +42,8 @@
#define _BSD_SOURCE /* for snprintf(), strdup() */ #define _BSD_SOURCE /* for snprintf(), strdup() */
#include "cairoint.h" #include "cairoint.h"
#include "cairo-array-private.h"
#include "cairo-error-private.h" #include "cairo-error-private.h"
#if CAIRO_HAS_FONT_SUBSET #if CAIRO_HAS_FONT_SUBSET
@ -2897,7 +2899,7 @@ cairo_bool_t
_cairo_cff_scaled_font_is_cid_cff (cairo_scaled_font_t *scaled_font) _cairo_cff_scaled_font_is_cid_cff (cairo_scaled_font_t *scaled_font)
{ {
const cairo_scaled_font_backend_t *backend; const cairo_scaled_font_backend_t *backend;
cairo_status_t status; cairo_int_status_t status;
unsigned char *data; unsigned char *data;
unsigned long data_length; unsigned long data_length;
unsigned char *current_ptr; unsigned char *current_ptr;
@ -2916,7 +2918,7 @@ _cairo_cff_scaled_font_is_cid_cff (cairo_scaled_font_t *scaled_font)
/* Try to load an OpenType/CFF font */ /* Try to load an OpenType/CFF font */
if (backend->load_truetype_table && if (backend->load_truetype_table &&
(status = backend->load_truetype_table (scaled_font, TT_TAG_CFF, (status = backend->load_truetype_table (scaled_font, TT_TAG_CFF,
0, NULL, &data_length)) == CAIRO_STATUS_SUCCESS) 0, NULL, &data_length)) == CAIRO_INT_STATUS_SUCCESS)
{ {
data = malloc (data_length); data = malloc (data_length);
if (unlikely (data == NULL)) { if (unlikely (data == NULL)) {
@ -2933,7 +2935,7 @@ _cairo_cff_scaled_font_is_cid_cff (cairo_scaled_font_t *scaled_font)
if (status == CAIRO_INT_STATUS_UNSUPPORTED && if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
backend->load_type1_data && backend->load_type1_data &&
(status = backend->load_type1_data (scaled_font, (status = backend->load_type1_data (scaled_font,
0, NULL, &data_length)) == CAIRO_STATUS_SUCCESS) 0, NULL, &data_length)) == CAIRO_INT_STATUS_SUCCESS)
{ {
data = malloc (data_length); data = malloc (data_length);
if (unlikely (data == NULL)) { if (unlikely (data == NULL)) {

View file

@ -40,6 +40,8 @@
*/ */
#include "cairoint.h" #include "cairoint.h"
#include "cairo-box-private.h"
#include "cairo-clip-private.h" #include "cairo-clip-private.h"
#include "cairo-error-private.h" #include "cairo-error-private.h"
#include "cairo-freed-pool-private.h" #include "cairo-freed-pool-private.h"
@ -62,7 +64,6 @@ pot (int v)
return v; return v;
} }
static cairo_bool_t static cairo_bool_t
_cairo_clip_contains_rectangle_box (const cairo_clip_t *clip, _cairo_clip_contains_rectangle_box (const cairo_clip_t *clip,
const cairo_rectangle_int_t *rect, const cairo_rectangle_int_t *rect,
@ -90,7 +91,6 @@ _cairo_clip_contains_rectangle_box (const cairo_clip_t *clip,
} }
/* Check for a clip-box that wholly contains the rectangle */ /* Check for a clip-box that wholly contains the rectangle */
assert (clip->num_boxes);
for (i = 0; i < clip->num_boxes; i++) { for (i = 0; i < clip->num_boxes; i++) {
if (box->p1.x >= clip->boxes[i].p1.x && if (box->p1.x >= clip->boxes[i].p1.x &&
box->p1.y >= clip->boxes[i].p1.y && box->p1.y >= clip->boxes[i].p1.y &&
@ -176,6 +176,8 @@ _cairo_clip_intersect_rectangle_box (cairo_clip_t *clip,
if (! _cairo_rectangle_intersect (&clip->extents, r)) if (! _cairo_rectangle_intersect (&clip->extents, r))
clip = _cairo_clip_set_all_clipped (clip); clip = _cairo_clip_set_all_clipped (clip);
} }
if (clip->path == NULL)
clip->is_region = _cairo_box_is_pixel_aligned (box);
return clip; return clip;
} }
@ -269,6 +271,7 @@ _cairo_clip_intersect_boxes (cairo_clip_t *clip,
const cairo_boxes_t *boxes) const cairo_boxes_t *boxes)
{ {
cairo_boxes_t clip_boxes; cairo_boxes_t clip_boxes;
cairo_box_t limits;
cairo_rectangle_int_t extents; cairo_rectangle_int_t extents;
if (_cairo_clip_is_all_clipped (clip)) if (_cairo_clip_is_all_clipped (clip))
@ -301,10 +304,11 @@ _cairo_clip_intersect_boxes (cairo_clip_t *clip,
} else { } else {
clip->boxes = _cairo_boxes_to_array (boxes, &clip->num_boxes, TRUE); clip->boxes = _cairo_boxes_to_array (boxes, &clip->num_boxes, TRUE);
} }
_cairo_boxes_extents (boxes, &extents); _cairo_boxes_extents (boxes, &limits);
if (boxes == &clip_boxes) if (boxes == &clip_boxes)
_cairo_boxes_fini (&clip_boxes); _cairo_boxes_fini (&clip_boxes);
_cairo_box_round_to_rectangle (&limits, &extents);
if (clip->path == NULL) if (clip->path == NULL)
clip->extents = extents; clip->extents = extents;
else if (! _cairo_rectangle_intersect (&clip->extents, &extents)) else if (! _cairo_rectangle_intersect (&clip->extents, &extents))
@ -557,37 +561,10 @@ _cairo_clip_reduce_for_composite (const cairo_clip_t *clip,
return _cairo_clip_reduce_to_rectangle (clip, r); return _cairo_clip_reduce_to_rectangle (clip, r);
} }
cairo_status_t
_cairo_clip_to_boxes (cairo_clip_t *clip,
cairo_boxes_t *boxes)
{
_cairo_boxes_init_for_array (boxes, clip->boxes, clip->num_boxes);
if (clip->path == NULL) {
cairo_box_t *src = clip->boxes;
int i;
clip->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
if (clip->boxes == NULL) {
clip->boxes = src;
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
for (i = 0; i < clip->num_boxes; i++) {
clip->boxes[i].p1.x = _cairo_fixed_floor (src[i].p1.x);
clip->boxes[i].p1.y = _cairo_fixed_floor (src[i].p1.y);
clip->boxes[i].p2.x = _cairo_fixed_ceil (src[i].p2.x);
clip->boxes[i].p2.y = _cairo_fixed_ceil (src[i].p2.y);
}
}
return CAIRO_STATUS_SUCCESS;
}
cairo_clip_t * cairo_clip_t *
_cairo_clip_from_boxes (const cairo_boxes_t *boxes) _cairo_clip_from_boxes (const cairo_boxes_t *boxes)
{ {
cairo_box_t extents;
cairo_clip_t *clip = _cairo_clip_create (); cairo_clip_t *clip = _cairo_clip_create ();
if (clip == NULL) if (clip == NULL)
return _cairo_clip_set_all_clipped (clip); return _cairo_clip_set_all_clipped (clip);
@ -603,7 +580,8 @@ _cairo_clip_from_boxes (const cairo_boxes_t *boxes)
return _cairo_clip_set_all_clipped (clip); return _cairo_clip_set_all_clipped (clip);
} }
_cairo_boxes_extents (boxes, &clip->extents); _cairo_boxes_extents (boxes, &extents);
_cairo_box_round_to_rectangle (&extents, &clip->extents);
return clip; return clip;
} }

View file

@ -40,6 +40,7 @@
#include "cairo-types-private.h" #include "cairo-types-private.h"
#include "cairo-boxes-private.h" #include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-compiler-private.h" #include "cairo-compiler-private.h"
#include "cairo-error-private.h" #include "cairo-error-private.h"
#include "cairo-path-fixed-private.h" #include "cairo-path-fixed-private.h"
@ -160,14 +161,30 @@ _cairo_clip_get_extents (const cairo_clip_t *clip);
cairo_private cairo_surface_t * cairo_private cairo_surface_t *
_cairo_clip_get_surface (const cairo_clip_t *clip, cairo_surface_t *dst, int *tx, int *ty); _cairo_clip_get_surface (const cairo_clip_t *clip, cairo_surface_t *dst, int *tx, int *ty);
cairo_private cairo_surface_t *
_cairo_clip_get_image (const cairo_clip_t *clip,
cairo_surface_t *target,
const cairo_rectangle_int_t *extents);
cairo_private cairo_status_t cairo_private cairo_status_t
_cairo_clip_combine_with_surface (const cairo_clip_t *clip, _cairo_clip_combine_with_surface (const cairo_clip_t *clip,
cairo_surface_t *dst, cairo_surface_t *dst,
int dst_x, int dst_y); int dst_x, int dst_y);
cairo_private cairo_status_t static inline void
_cairo_clip_to_boxes (cairo_clip_t *clip, _cairo_clip_steal_boxes (cairo_clip_t *clip, cairo_boxes_t *boxes)
cairo_boxes_t *boxes); {
_cairo_boxes_init_for_array (boxes, clip->boxes, clip->num_boxes);
clip->boxes = NULL;
clip->num_boxes = 0;
}
static inline void
_cairo_clip_unsteal_boxes (cairo_clip_t *clip, cairo_boxes_t *boxes)
{
clip->boxes = boxes->chunks.base;
clip->num_boxes = boxes->num_boxes;
}
cairo_private cairo_clip_t * cairo_private cairo_clip_t *
_cairo_clip_from_boxes (const cairo_boxes_t *boxes); _cairo_clip_from_boxes (const cairo_boxes_t *boxes);

View file

@ -105,10 +105,16 @@ _cairo_clip_is_region (const cairo_clip_t *clip)
if (clip == NULL) if (clip == NULL)
return TRUE; return TRUE;
if (clip->is_region)
return TRUE;
/* XXX Geometric reduction? */ /* XXX Geometric reduction? */
if (clip->path) if (clip->path)
return FALSE; return FALSE;
if (clip->num_boxes == 0)
return TRUE;
if (clip->region == NULL) if (clip->region == NULL)
_cairo_clip_extract_region ((cairo_clip_t *) clip); _cairo_clip_extract_region ((cairo_clip_t *) clip);

View file

@ -103,8 +103,7 @@ _cairo_clip_get_surface (const cairo_clip_t *clip,
CAIRO_CONTENT_ALPHA, CAIRO_CONTENT_ALPHA,
clip->extents.width, clip->extents.width,
clip->extents.height, clip->extents.height,
CAIRO_COLOR_TRANSPARENT, CAIRO_COLOR_WHITE);
TRUE);
if (unlikely (surface->status)) if (unlikely (surface->status))
return surface; return surface;
@ -114,12 +113,7 @@ _cairo_clip_get_surface (const cairo_clip_t *clip,
copy_path = copy->path; copy_path = copy->path;
copy->path = NULL; copy->path = NULL;
assert (copy->num_boxes); status = CAIRO_STATUS_SUCCESS;
status = _cairo_surface_paint (surface,
CAIRO_OPERATOR_ADD,
&_cairo_pattern_white.base,
copy);
clip_path = copy_path; clip_path = copy_path;
while (status == CAIRO_STATUS_SUCCESS && clip_path) { while (status == CAIRO_STATUS_SUCCESS && clip_path) {
status = _cairo_surface_fill (surface, status = _cairo_surface_fill (surface,
@ -140,3 +134,32 @@ _cairo_clip_get_surface (const cairo_clip_t *clip,
*ty = clip->extents.y; *ty = clip->extents.y;
return surface; return surface;
} }
cairo_surface_t *
_cairo_clip_get_image (const cairo_clip_t *clip,
cairo_surface_t *target,
const cairo_rectangle_int_t *extents)
{
cairo_surface_t *surface;
cairo_status_t status;
surface = cairo_surface_create_similar_image (target,
CAIRO_FORMAT_A8,
extents->width,
extents->height);
if (unlikely (surface->status))
return surface;
status = _cairo_surface_paint (surface, CAIRO_OPERATOR_SOURCE,
&_cairo_pattern_white.base, NULL);
if (likely (status == CAIRO_STATUS_SUCCESS))
status = _cairo_clip_combine_with_surface (clip, surface,
extents->x, extents->y);
if (unlikely (status)) {
cairo_surface_destroy (surface);
surface = _cairo_surface_create_in_error (status);
}
return surface;
}

File diff suppressed because it is too large Load diff

View file

@ -246,16 +246,9 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
if (extents.width == 0 || extents.height == 0) if (extents.width == 0 || extents.height == 0)
return _cairo_clip_set_all_clipped (clip); return _cairo_clip_set_all_clipped (clip);
if (clip && ! _cairo_rectangle_intersect (&clip->extents, &extents)) clip = _cairo_clip_intersect_rectangle (clip, &extents);
return _cairo_clip_set_all_clipped (clip); if (_cairo_clip_is_all_clipped (clip))
return clip;
if (clip == NULL) {
clip = _cairo_clip_create ();
if (unlikely (clip == NULL))
return _cairo_clip_set_all_clipped (clip);
clip->extents = extents;
}
clip_path = _cairo_clip_path_create (clip); clip_path = _cairo_clip_path_create (clip);
if (unlikely (clip_path == NULL)) if (unlikely (clip_path == NULL))
@ -263,7 +256,7 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
status = _cairo_path_fixed_init_copy (&clip_path->path, path); status = _cairo_path_fixed_init_copy (&clip_path->path, path);
if (unlikely (status)) if (unlikely (status))
return _cairo_clip_set_all_clipped (clip); return _cairo_clip_set_all_clipped (clip);
clip_path->fill_rule = fill_rule; clip_path->fill_rule = fill_rule;
clip_path->tolerance = tolerance; clip_path->tolerance = tolerance;
@ -532,9 +525,10 @@ _cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip)
} }
fprintf (stream, "clip:\n"); fprintf (stream, "clip:\n");
fprintf (stream, " extents: (%d, %d) x (%d, %d)", fprintf (stream, " extents: (%d, %d) x (%d, %d), is-region? %d",
clip->extents.x, clip->extents.y, clip->extents.x, clip->extents.y,
clip->extents.width, clip->extents.height); clip->extents.width, clip->extents.height,
clip->is_region);
fprintf (stream, " num_boxes = %d\n", clip->num_boxes); fprintf (stream, " num_boxes = %d\n", clip->num_boxes);
for (i = 0; i < clip->num_boxes; i++) { for (i = 0; i < clip->num_boxes; i++) {

View file

@ -39,6 +39,7 @@
#include "cairo-types-private.h" #include "cairo-types-private.h"
#include "cairo-error-private.h" #include "cairo-error-private.h"
#include "cairo-pattern-private.h"
CAIRO_BEGIN_DECLS CAIRO_BEGIN_DECLS
@ -52,6 +53,9 @@ CAIRO_BEGIN_DECLS
* *
*/ */
struct _cairo_composite_rectangles { struct _cairo_composite_rectangles {
cairo_surface_t *surface;
cairo_operator_t op;
cairo_rectangle_int_t source; cairo_rectangle_int_t source;
cairo_rectangle_int_t mask; cairo_rectangle_int_t mask;
cairo_rectangle_int_t destination; cairo_rectangle_int_t destination;
@ -60,19 +64,27 @@ struct _cairo_composite_rectangles {
cairo_rectangle_int_t unbounded; /* destination IN clip */ cairo_rectangle_int_t unbounded; /* destination IN clip */
uint32_t is_bounded; uint32_t is_bounded;
cairo_rectangle_int_t source_sample_area;
cairo_rectangle_int_t mask_sample_area;
cairo_pattern_union_t source_pattern;
cairo_pattern_union_t mask_pattern;
const cairo_pattern_t *original_source_pattern;
const cairo_pattern_t *original_mask_pattern;
cairo_clip_t *clip; /* clip will be reduced to the minimal container */ cairo_clip_t *clip; /* clip will be reduced to the minimal container */
}; };
cairo_private cairo_int_status_t cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents, _cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *unbounded, cairo_surface_t *surface,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *source, const cairo_pattern_t *source,
const cairo_clip_t *clip); const cairo_clip_t *clip);
cairo_private cairo_int_status_t cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents, _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *unbounded, cairo_surface_t *surface,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *source, const cairo_pattern_t *source,
const cairo_pattern_t *mask, const cairo_pattern_t *mask,
@ -80,7 +92,7 @@ _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents
cairo_private cairo_int_status_t cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents, _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *unbounded, cairo_surface_t *surface,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *source, const cairo_pattern_t *source,
const cairo_path_fixed_t *path, const cairo_path_fixed_t *path,
@ -90,15 +102,31 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten
cairo_private cairo_int_status_t cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents, _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *unbounded, cairo_surface_t *surface,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *source, const cairo_pattern_t *source,
const cairo_path_fixed_t *path, const cairo_path_fixed_t *path,
const cairo_clip_t *clip); const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_boxes (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_boxes_t *boxes,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_polygon (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_polygon_t *polygon,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents, _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *unbounded, cairo_surface_t *surface,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *source, const cairo_pattern_t *source,
cairo_scaled_font_t *scaled_font, cairo_scaled_font_t *scaled_font,

View file

@ -46,57 +46,93 @@ void _cairo_composite_rectangles_fini (cairo_composite_rectangles_t *extents)
_cairo_clip_destroy (extents->clip); _cairo_clip_destroy (extents->clip);
} }
static void
_cairo_composite_reduce_pattern (const cairo_pattern_t *src,
cairo_pattern_union_t *dst)
{
int tx, ty;
_cairo_pattern_init_static_copy (&dst->base, src);
if (dst->base.type == CAIRO_PATTERN_TYPE_SOLID)
return;
dst->base.filter = _cairo_pattern_analyze_filter (&dst->base, NULL),
tx = ty = 0;
if (_cairo_matrix_is_pixman_translation (&dst->base.matrix,
dst->base.filter,
&tx, &ty))
{
dst->base.matrix.x0 = tx;
dst->base.matrix.y0 = ty;
}
}
static inline cairo_bool_t static inline cairo_bool_t
_cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents, _cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *unbounded, cairo_surface_t *surface,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *source, const cairo_pattern_t *source,
const cairo_clip_t *clip) const cairo_clip_t *clip)
{ {
extents->clip = NULL;
extents->destination = *unbounded;
if (_cairo_clip_is_all_clipped (clip)) if (_cairo_clip_is_all_clipped (clip))
return FALSE; return FALSE;
extents->surface = surface;
extents->op = op;
_cairo_surface_get_extents (surface, &extents->destination);
extents->clip = NULL;
extents->unbounded = extents->destination; extents->unbounded = extents->destination;
if (clip != NULL) { if (clip && ! _cairo_rectangle_intersect (&extents->unbounded,
if (! _cairo_rectangle_intersect (&extents->unbounded, _cairo_clip_get_extents (clip)))
_cairo_clip_get_extents (clip))) return FALSE;
return FALSE;
}
extents->bounded = extents->unbounded; extents->bounded = extents->unbounded;
extents->is_bounded = _cairo_operator_bounded_by_either (op); extents->is_bounded = _cairo_operator_bounded_by_either (op);
_cairo_pattern_get_extents (source, &extents->source); extents->original_source_pattern = source;
_cairo_composite_reduce_pattern (source, &extents->source_pattern);
_cairo_pattern_get_extents (&extents->source_pattern.base,
&extents->source);
if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) { if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) {
if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source)) if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source))
return FALSE; return FALSE;
} }
extents->original_mask_pattern = NULL;
extents->mask_pattern.base.type = CAIRO_PATTERN_TYPE_SOLID;
extents->mask_pattern.solid.color.alpha = 1.; /* XXX full initialisation? */
return TRUE; return TRUE;
} }
cairo_int_status_t cairo_int_status_t
_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents, _cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *unbounded, cairo_surface_t *surface,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *source, const cairo_pattern_t *source,
const cairo_clip_t *clip) const cairo_clip_t *clip)
{ {
if (! _cairo_composite_rectangles_init (extents, unbounded, if (! _cairo_composite_rectangles_init (extents,
op, source, clip)) surface, op, source, clip))
{ {
return CAIRO_INT_STATUS_NOTHING_TO_DO; return CAIRO_INT_STATUS_NOTHING_TO_DO;
} }
extents->mask = *unbounded; extents->mask = extents->destination;
extents->clip = _cairo_clip_reduce_for_composite (clip, extents); extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
if (_cairo_clip_is_all_clipped (extents->clip)) if (_cairo_clip_is_all_clipped (extents->clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO; return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
_cairo_pattern_sampled_area (&extents->source_pattern.base,
&extents->bounded,
&extents->source_sample_area);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -117,6 +153,21 @@ _cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents,
if (_cairo_clip_is_all_clipped (extents->clip)) if (_cairo_clip_is_all_clipped (extents->clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO; return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
_cairo_pattern_sampled_area (&extents->source_pattern.base,
&extents->bounded,
&extents->source_sample_area);
if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
_cairo_pattern_sampled_area (&extents->mask_pattern.base,
&extents->bounded,
&extents->mask_sample_area);
if (extents->mask_sample_area.width == 0 ||
extents->mask_sample_area.height == 0) {
_cairo_composite_rectangles_fini (extents);
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
}
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -125,7 +176,6 @@ _cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t
const cairo_box_t *box) const cairo_box_t *box)
{ {
cairo_rectangle_int_t mask; cairo_rectangle_int_t mask;
cairo_int_status_t status;
cairo_clip_t *clip; cairo_clip_t *clip;
_cairo_box_round_to_rectangle (box, &mask); _cairo_box_round_to_rectangle (box, &mask);
@ -139,39 +189,70 @@ _cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t
_cairo_rectangle_intersect (&extents->mask, &mask); _cairo_rectangle_intersect (&extents->mask, &mask);
mask = extents->bounded;
if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask) &&
extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (mask.width == extents->bounded.width &&
mask.height == extents->bounded.height)
return CAIRO_INT_STATUS_SUCCESS;
if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE))
extents->unbounded = extents->bounded;
extents->mask = mask; extents->mask = mask;
clip = extents->clip; clip = extents->clip;
status = _cairo_composite_rectangles_intersect (extents, clip); extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
if (clip != extents->clip) if (clip != extents->clip)
_cairo_clip_destroy (clip); _cairo_clip_destroy (clip);
return status; if (_cairo_clip_is_all_clipped (extents->clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
_cairo_pattern_sampled_area (&extents->source_pattern.base,
&extents->bounded,
&extents->source_sample_area);
if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
_cairo_pattern_sampled_area (&extents->mask_pattern.base,
&extents->bounded,
&extents->mask_sample_area);
if (extents->mask_sample_area.width == 0 ||
extents->mask_sample_area.height == 0)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
return CAIRO_INT_STATUS_SUCCESS;
} }
cairo_int_status_t cairo_int_status_t
_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents, _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *unbounded, cairo_surface_t*surface,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *source, const cairo_pattern_t *source,
const cairo_pattern_t *mask, const cairo_pattern_t *mask,
const cairo_clip_t *clip) const cairo_clip_t *clip)
{ {
if (! _cairo_composite_rectangles_init (extents, unbounded, if (! _cairo_composite_rectangles_init (extents,
op, source, clip)) surface, op, source, clip))
{ {
return CAIRO_INT_STATUS_NOTHING_TO_DO; return CAIRO_INT_STATUS_NOTHING_TO_DO;
} }
_cairo_pattern_get_extents (mask, &extents->mask);
extents->original_mask_pattern = mask;
_cairo_composite_reduce_pattern (mask, &extents->mask_pattern);
_cairo_pattern_get_extents (&extents->mask_pattern.base, &extents->mask);
return _cairo_composite_rectangles_intersect (extents, clip); return _cairo_composite_rectangles_intersect (extents, clip);
} }
cairo_int_status_t cairo_int_status_t
_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents, _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *unbounded, cairo_surface_t *surface,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *source, const cairo_pattern_t *source,
const cairo_path_fixed_t *path, const cairo_path_fixed_t *path,
@ -179,8 +260,8 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten
const cairo_matrix_t *ctm, const cairo_matrix_t *ctm,
const cairo_clip_t *clip) const cairo_clip_t *clip)
{ {
if (! _cairo_composite_rectangles_init (extents, unbounded, if (! _cairo_composite_rectangles_init (extents,
op, source, clip)) surface, op, source, clip))
{ {
return CAIRO_INT_STATUS_NOTHING_TO_DO; return CAIRO_INT_STATUS_NOTHING_TO_DO;
} }
@ -192,14 +273,14 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten
cairo_int_status_t cairo_int_status_t
_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents, _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *unbounded, cairo_surface_t *surface,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *source, const cairo_pattern_t *source,
const cairo_path_fixed_t *path, const cairo_path_fixed_t *path,
const cairo_clip_t *clip) const cairo_clip_t *clip)
{ {
if (! _cairo_composite_rectangles_init (extents, unbounded, if (! _cairo_composite_rectangles_init (extents,
op, source, clip)) surface, op, source, clip))
{ {
return CAIRO_INT_STATUS_NOTHING_TO_DO; return CAIRO_INT_STATUS_NOTHING_TO_DO;
} }
@ -209,9 +290,48 @@ _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents
return _cairo_composite_rectangles_intersect (extents, clip); return _cairo_composite_rectangles_intersect (extents, clip);
} }
cairo_int_status_t
_cairo_composite_rectangles_init_for_polygon (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_polygon_t *polygon,
const cairo_clip_t *clip)
{
if (! _cairo_composite_rectangles_init (extents,
surface, op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
_cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
return _cairo_composite_rectangles_intersect (extents, clip);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_boxes (cairo_composite_rectangles_t *extents,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_boxes_t *boxes,
const cairo_clip_t *clip)
{
cairo_box_t box;
if (! _cairo_composite_rectangles_init (extents,
surface, op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
_cairo_boxes_extents (boxes, &box);
_cairo_box_round_to_rectangle (&box, &extents->mask);
return _cairo_composite_rectangles_intersect (extents, clip);
}
cairo_int_status_t cairo_int_status_t
_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents, _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
const cairo_rectangle_int_t *unbounded, cairo_surface_t *surface,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *source, const cairo_pattern_t *source,
cairo_scaled_font_t *scaled_font, cairo_scaled_font_t *scaled_font,
@ -222,8 +342,7 @@ _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *exten
{ {
cairo_status_t status; cairo_status_t status;
if (! _cairo_composite_rectangles_init (extents, unbounded, if (! _cairo_composite_rectangles_init (extents, surface, op, source, clip))
op, source, clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO; return CAIRO_INT_STATUS_NOTHING_TO_DO;
/* Computing the exact bbox and the overlap is expensive. /* Computing the exact bbox and the overlap is expensive.

View file

@ -0,0 +1,355 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_COMPOSITOR_PRIVATE_H
#define CAIRO_COMPOSITOR_PRIVATE_H
#include "cairo-composite-rectangles-private.h"
CAIRO_BEGIN_DECLS
typedef struct {
cairo_scaled_font_t *font;
cairo_glyph_t *glyphs;
int num_glyphs;
cairo_bool_t use_mask;
cairo_rectangle_int_t extents;
} cairo_composite_glyphs_info_t;
struct cairo_compositor {
const cairo_compositor_t *delegate;
cairo_warn cairo_int_status_t
(*paint) (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *extents);
cairo_warn cairo_int_status_t
(*mask) (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *extents);
cairo_warn cairo_int_status_t
(*stroke) (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *extents,
const cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias);
cairo_warn cairo_int_status_t
(*fill) (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *extents,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias);
cairo_warn cairo_int_status_t
(*glyphs) (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *extents,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_bool_t overlap);
};
struct cairo_mask_compositor {
cairo_compositor_t base;
cairo_int_status_t (*acquire) (void *surface);
cairo_int_status_t (*release) (void *surface);
cairo_int_status_t (*set_clip_region) (void *surface,
cairo_region_t *clip_region);
cairo_surface_t * (*pattern_to_surface) (cairo_surface_t *dst,
const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *src_x, int *src_y);
cairo_int_status_t (*draw_image_boxes) (void *surface,
cairo_image_surface_t *image,
cairo_boxes_t *boxes,
int dx, int dy);
cairo_int_status_t (*copy_boxes) (void *surface,
cairo_surface_t *src,
cairo_boxes_t *boxes,
const cairo_rectangle_int_t *extents,
int dx, int dy);
cairo_int_status_t
(*fill_rectangles) (void *surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_int_t *rectangles,
int num_rects);
cairo_int_status_t
(*fill_boxes) (void *surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_boxes_t *boxes);
cairo_int_status_t
(*composite) (void *dst,
cairo_operator_t op,
cairo_surface_t *src,
cairo_surface_t *mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height);
cairo_int_status_t
(*composite_boxes) (void *surface,
cairo_operator_t op,
cairo_surface_t *source,
cairo_surface_t *mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
cairo_boxes_t *boxes,
const cairo_rectangle_int_t *extents);
cairo_int_status_t
(*check_composite_glyphs) (const cairo_composite_rectangles_t *extents,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int *num_glyphs);
cairo_int_status_t
(*composite_glyphs) (void *surface,
cairo_operator_t op,
cairo_surface_t *src,
int src_x,
int src_y,
int dst_x,
int dst_y,
cairo_composite_glyphs_info_t *info);
};
struct cairo_traps_compositor {
cairo_compositor_t base;
cairo_int_status_t
(*acquire) (void *surface);
cairo_int_status_t
(*release) (void *surface);
cairo_int_status_t
(*set_clip_region) (void *surface,
cairo_region_t *clip_region);
cairo_surface_t *
(*pattern_to_surface) (cairo_surface_t *dst,
const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *src_x, int *src_y);
cairo_int_status_t (*draw_image_boxes) (void *surface,
cairo_image_surface_t *image,
cairo_boxes_t *boxes,
int dx, int dy);
cairo_int_status_t (*copy_boxes) (void *surface,
cairo_surface_t *src,
cairo_boxes_t *boxes,
const cairo_rectangle_int_t *extents,
int dx, int dy);
cairo_int_status_t
(*fill_boxes) (void *surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_boxes_t *boxes);
cairo_int_status_t
(*composite) (void *dst,
cairo_operator_t op,
cairo_surface_t *src,
cairo_surface_t *mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height);
cairo_int_status_t
(*lerp) (void *_dst,
cairo_surface_t *abstract_src,
cairo_surface_t *abstract_mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height);
cairo_int_status_t
(*composite_boxes) (void *surface,
cairo_operator_t op,
cairo_surface_t *source,
cairo_surface_t *mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
cairo_boxes_t *boxes,
const cairo_rectangle_int_t *extents);
cairo_int_status_t
(*composite_traps) (void *dst,
cairo_operator_t op,
cairo_surface_t *source,
int src_x,
int src_y,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_antialias_t antialias,
cairo_traps_t *traps);
cairo_int_status_t
(*composite_tristrip) (void *dst,
cairo_operator_t op,
cairo_surface_t *source,
int src_x,
int src_y,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_antialias_t antialias,
cairo_tristrip_t *tristrip);
cairo_int_status_t
(*check_composite_glyphs) (const cairo_composite_rectangles_t *extents,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int *num_glyphs);
cairo_int_status_t
(*composite_glyphs) (void *surface,
cairo_operator_t op,
cairo_surface_t *src,
int src_x,
int src_y,
int dst_x,
int dst_y,
cairo_composite_glyphs_info_t *info);
};
cairo_private extern const cairo_compositor_t __cairo_no_compositor;
cairo_private extern const cairo_compositor_t _cairo_fallback_compositor;
cairo_private void
_cairo_mask_compositor_init (cairo_mask_compositor_t *compositor,
const cairo_compositor_t *delegate);
cairo_private void
_cairo_traps_compositor_init (cairo_traps_compositor_t *compositor,
const cairo_compositor_t *delegate);
cairo_private cairo_int_status_t
_cairo_compositor_paint (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_compositor_mask (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_compositor_stroke (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_compositor_fill (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_compositor_glyphs (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip);
CAIRO_END_DECLS
#endif /* CAIRO_COMPOSITOR_PRIVATE_H */

213
src/cairo-compositor.c Normal file
View file

@ -0,0 +1,213 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-compositor-private.h"
#include "cairo-error-private.h"
cairo_int_status_t
_cairo_compositor_paint (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
cairo_int_status_t status;
status = _cairo_composite_rectangles_init_for_paint (&extents, surface,
op, source,
clip);
if (unlikely (status))
return status;
do {
while (compositor->paint == NULL)
compositor = compositor->delegate;
status = compositor->paint (compositor, &extents);
compositor = compositor->delegate;
} while (status == CAIRO_INT_STATUS_UNSUPPORTED);
_cairo_composite_rectangles_fini (&extents);
return status;
}
cairo_int_status_t
_cairo_compositor_mask (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
cairo_int_status_t status;
status = _cairo_composite_rectangles_init_for_mask (&extents, surface,
op, source, mask,
clip);
if (unlikely (status))
return status;
do {
while (compositor->mask == NULL)
compositor = compositor->delegate;
status = compositor->mask (compositor, &extents);
compositor = compositor->delegate;
} while (status == CAIRO_INT_STATUS_UNSUPPORTED);
_cairo_composite_rectangles_fini (&extents);
return status;
}
cairo_int_status_t
_cairo_compositor_stroke (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
const cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
cairo_int_status_t status;
status = _cairo_composite_rectangles_init_for_stroke (&extents, surface,
op, source,
path, style, ctm,
clip);
if (unlikely (status))
return status;
do {
while (compositor->stroke == NULL)
compositor = compositor->delegate;
status = compositor->stroke (compositor, &extents,
path, style, ctm, ctm_inverse,
tolerance, antialias);
compositor = compositor->delegate;
} while (status == CAIRO_INT_STATUS_UNSUPPORTED);
_cairo_composite_rectangles_fini (&extents);
return status;
}
cairo_int_status_t
_cairo_compositor_fill (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
const cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
cairo_int_status_t status;
status = _cairo_composite_rectangles_init_for_fill (&extents, surface,
op, source, path,
clip);
if (unlikely (status))
return status;
do {
while (compositor->fill == NULL)
compositor = compositor->delegate;
status = compositor->fill (compositor, &extents,
path, fill_rule, tolerance, antialias);
compositor = compositor->delegate;
} while (status == CAIRO_INT_STATUS_UNSUPPORTED);
_cairo_composite_rectangles_fini (&extents);
return status;
}
cairo_int_status_t
_cairo_compositor_glyphs (const cairo_compositor_t *compositor,
cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
cairo_bool_t overlap;
cairo_int_status_t status;
status = _cairo_composite_rectangles_init_for_glyphs (&extents, surface,
op, source,
scaled_font,
glyphs, num_glyphs,
clip, &overlap);
if (unlikely (status))
return status;
do {
while (compositor->glyphs == NULL)
compositor = compositor->delegate;
status = compositor->glyphs (compositor, &extents,
scaled_font, glyphs, num_glyphs, overlap);
compositor = compositor->delegate;
} while (status == CAIRO_INT_STATUS_UNSUPPORTED);
_cairo_composite_rectangles_fini (&extents);
return status;
}

View file

@ -158,8 +158,7 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
content, content,
extents.width, extents.width,
extents.height, extents.height,
CAIRO_COLOR_TRANSPARENT, CAIRO_COLOR_TRANSPARENT);
TRUE);
status = group_surface->status; status = group_surface->status;
if (unlikely (status)) if (unlikely (status))
goto bail; goto bail;

View file

@ -0,0 +1,174 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-compositor-private.h"
#include "cairo-surface-offset-private.h"
/* high-level compositor interface */
static cairo_int_status_t
_cairo_fallback_compositor_paint (const cairo_compositor_t *_compositor,
cairo_composite_rectangles_t *extents)
{
cairo_surface_t *image;
cairo_int_status_t status;
image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
status = _cairo_surface_offset_paint (image,
-extents->unbounded.x,
-extents->unbounded.y,
extents->op,
&extents->source_pattern.base,
extents->clip);
cairo_surface_unmap_image (extents->surface, image);
return status;
}
static cairo_int_status_t
_cairo_fallback_compositor_mask (const cairo_compositor_t *_compositor,
cairo_composite_rectangles_t *extents)
{
cairo_surface_t *image;
cairo_int_status_t status;
image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
status = _cairo_surface_offset_mask (image,
extents->unbounded.x,
extents->unbounded.y,
extents->op,
&extents->source_pattern.base,
&extents->mask_pattern.base,
extents->clip);
cairo_surface_unmap_image (extents->surface, image);
return status;
}
static cairo_int_status_t
_cairo_fallback_compositor_stroke (const cairo_compositor_t *_compositor,
cairo_composite_rectangles_t *extents,
const cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias)
{
cairo_surface_t *image;
cairo_int_status_t status;
image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
status = _cairo_surface_offset_stroke (image,
extents->unbounded.x,
extents->unbounded.y,
extents->op,
&extents->source_pattern.base,
path, style,
ctm, ctm_inverse,
tolerance,
antialias,
extents->clip);
cairo_surface_unmap_image (extents->surface, image);
return status;
}
static cairo_int_status_t
_cairo_fallback_compositor_fill (const cairo_compositor_t *_compositor,
cairo_composite_rectangles_t *extents,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_surface_t *image;
cairo_int_status_t status;
image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
status = _cairo_surface_offset_fill (image,
extents->unbounded.x,
extents->unbounded.y,
extents->op,
&extents->source_pattern.base,
path,
fill_rule, tolerance, antialias,
extents->clip);
cairo_surface_unmap_image (extents->surface, image);
return status;
}
static cairo_int_status_t
_cairo_fallback_compositor_glyphs (const cairo_compositor_t *_compositor,
cairo_composite_rectangles_t *extents,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_bool_t overlap)
{
cairo_surface_t *image;
cairo_int_status_t status;
image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
status = _cairo_surface_offset_glyphs (image,
extents->unbounded.x,
extents->unbounded.y,
extents->op,
&extents->source_pattern.base,
scaled_font, glyphs, num_glyphs,
extents->clip);
cairo_surface_unmap_image (extents->surface, image);
return status;
}
const cairo_compositor_t _cairo_fallback_compositor = {
&__cairo_no_compositor,
_cairo_fallback_compositor_paint,
_cairo_fallback_compositor_mask,
_cairo_fallback_compositor_stroke,
_cairo_fallback_compositor_fill,
_cairo_fallback_compositor_glyphs,
};

View file

@ -42,7 +42,9 @@
CAIRO_BEGIN_DECLS CAIRO_BEGIN_DECLS
#if HAS_ATOMIC_OPS #define DISABLE_FREED_POOLS 0
#if HAS_ATOMIC_OPS && ! DISABLE_FREED_POOLS
/* Keep a stash of recently freed clip_paths, since we need to /* Keep a stash of recently freed clip_paths, since we need to
* reallocate them frequently. * reallocate them frequently.
*/ */
@ -128,7 +130,7 @@ typedef int freed_pool_t;
#define _freed_pool_get(pool) NULL #define _freed_pool_get(pool) NULL
#define _freed_pool_put(pool, ptr) free(ptr) #define _freed_pool_put(pool, ptr) free(ptr)
#define _freed_pool_reset(ptr) assert((ptr) != NULL) #define _freed_pool_reset(ptr)
#endif #endif

View file

@ -2586,7 +2586,6 @@ static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = {
_cairo_ft_scaled_glyph_init, _cairo_ft_scaled_glyph_init,
NULL, /* text_to_glyphs */ NULL, /* text_to_glyphs */
_cairo_ft_ucs4_to_index, _cairo_ft_ucs4_to_index,
NULL, /* show_glyphs */
_cairo_ft_load_truetype_table, _cairo_ft_load_truetype_table,
_cairo_ft_index_to_ucs4, _cairo_ft_index_to_ucs4,
_cairo_ft_is_synthetic, _cairo_ft_is_synthetic,

File diff suppressed because it is too large Load diff

View file

@ -113,18 +113,20 @@ static void
_gl_destroy (void *device) _gl_destroy (void *device)
{ {
cairo_gl_context_t *ctx = device; cairo_gl_context_t *ctx = device;
cairo_scaled_font_t *scaled_font, *next_scaled_font;
int n; int n;
ctx->acquire (ctx); ctx->acquire (ctx);
cairo_list_foreach_entry_safe (scaled_font, while (! cairo_list_is_empty (&ctx->fonts)) {
next_scaled_font, cairo_gl_font_t *font;
cairo_scaled_font_t,
&ctx->fonts, font = cairo_list_first_entry (&ctx->fonts,
link) cairo_gl_font_t,
{ link);
_cairo_scaled_font_revoke_ownership (scaled_font);
cairo_list_del (&font->base.link);
cairo_list_del (&font->link);
free (font);
} }
for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++) for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
@ -161,6 +163,8 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
_cairo_device_init (&ctx->base, &_cairo_gl_device_backend); _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
ctx->compositor = _cairo_gl_span_compositor_get ();
memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache)); memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
cairo_list_init (&ctx->fonts); cairo_list_init (&ctx->fonts);

View file

@ -40,6 +40,7 @@
#include "cairo-gl-private.h" #include "cairo-gl-private.h"
#include "cairo-compositor-private.h"
#include "cairo-composite-rectangles-private.h" #include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h" #include "cairo-error-private.h"
#include "cairo-image-surface-private.h" #include "cairo-image-surface-private.h"
@ -50,11 +51,26 @@
#define GLYPH_CACHE_MIN_SIZE 4 #define GLYPH_CACHE_MIN_SIZE 4
#define GLYPH_CACHE_MAX_SIZE 128 #define GLYPH_CACHE_MAX_SIZE 128
typedef struct _cairo_gl_glyph_private { typedef struct _cairo_gl_glyph {
cairo_rtree_node_t node; cairo_rtree_node_t node;
cairo_scaled_glyph_private_t base;
cairo_gl_glyph_cache_t *cache; cairo_gl_glyph_cache_t *cache;
struct { float x, y; } p1, p2; struct { float x, y; } p1, p2;
} cairo_gl_glyph_private_t; } cairo_gl_glyph_t;
static void
_cairo_gl_glyph_fini (cairo_scaled_glyph_private_t *_priv,
cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font)
{
cairo_gl_glyph_t *priv = cairo_container_of (_priv, cairo_gl_glyph_t, base);
priv->node.owner = NULL;
if (! priv->node.pinned) {
/* XXX thread-safety? Probably ok due to the frozen scaled-font. */
_cairo_rtree_node_remove (&priv->cache->rtree, &priv->node);
}
}
static cairo_int_status_t static cairo_int_status_t
_cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx, _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
@ -63,7 +79,7 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
{ {
cairo_image_surface_t *glyph_surface = scaled_glyph->surface; cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
cairo_gl_surface_t *cache_surface; cairo_gl_surface_t *cache_surface;
cairo_gl_glyph_private_t *glyph_private; cairo_gl_glyph_t *glyph_private;
cairo_rtree_node_t *node = NULL; cairo_rtree_node_t *node = NULL;
cairo_int_status_t status; cairo_int_status_t status;
int width, height; int width, height;
@ -101,11 +117,15 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
if (unlikely (status)) if (unlikely (status))
return status; return status;
scaled_glyph->surface_private = node; glyph_private = (cairo_gl_glyph_t *) node;
node->owner = &scaled_glyph->surface_private;
glyph_private = (cairo_gl_glyph_private_t *) node;
glyph_private->cache = cache; glyph_private->cache = cache;
_cairo_scaled_glyph_attach_private (scaled_glyph,
&glyph_private->base,
cache,
_cairo_gl_glyph_fini);
scaled_glyph->dev_private = glyph_private;
scaled_glyph->dev_private_key = cache;
/* compute tex coords */ /* compute tex coords */
glyph_private->p1.x = node->x; glyph_private->p1.x = node->x;
@ -122,11 +142,11 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
static cairo_gl_glyph_private_t * static cairo_gl_glyph_t *
_cairo_gl_glyph_cache_lock (cairo_gl_glyph_cache_t *cache, _cairo_gl_glyph_cache_lock (cairo_gl_glyph_cache_t *cache,
cairo_scaled_glyph_t *scaled_glyph) cairo_scaled_glyph_t *scaled_glyph)
{ {
return _cairo_rtree_pin (&cache->rtree, scaled_glyph->surface_private); return _cairo_rtree_pin (&cache->rtree, scaled_glyph->dev_private);
} }
static cairo_status_t static cairo_status_t
@ -183,63 +203,29 @@ _cairo_gl_glyph_cache_unlock (cairo_gl_glyph_cache_t *cache)
_cairo_rtree_unpin (&cache->rtree); _cairo_rtree_unpin (&cache->rtree);
} }
static cairo_bool_t static void
_cairo_gl_surface_owns_font (cairo_gl_surface_t *surface, _cairo_gl_font_fini (cairo_scaled_font_private_t *_priv,
cairo_scaled_font_t *scaled_font) cairo_scaled_font_t *scaled_font)
{ {
cairo_device_t *font_private; cairo_gl_font_t *priv = (cairo_gl_font_t *)_priv;
font_private = scaled_font->surface_private; cairo_list_del (&priv->link);
if ((scaled_font->surface_backend != NULL && free (priv);
scaled_font->surface_backend != &_cairo_gl_surface_backend) ||
(font_private != NULL && font_private != surface->base.device))
{
return FALSE;
}
return TRUE;
}
void
_cairo_gl_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
{
cairo_list_del (&scaled_font->link);
}
void
_cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font)
{
cairo_gl_glyph_private_t *glyph_private;
glyph_private = scaled_glyph->surface_private;
if (glyph_private != NULL) {
glyph_private->node.owner = NULL;
if (! glyph_private->node.pinned) {
/* XXX thread-safety? Probably ok due to the frozen scaled-font. */
_cairo_rtree_node_remove (&glyph_private->cache->rtree,
&glyph_private->node);
}
}
} }
static cairo_status_t static cairo_status_t
_render_glyphs (cairo_gl_surface_t *dst, render_glyphs (cairo_gl_surface_t *dst,
int dst_x, int dst_y, int dst_x, int dst_y,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *source, const cairo_pattern_t *source,
cairo_glyph_t *glyphs, cairo_composite_glyphs_info_t *info,
int num_glyphs, cairo_bool_t *has_component_alpha)
cairo_scaled_font_t *scaled_font,
const cairo_composite_rectangles_t *extents,
cairo_bool_t *has_component_alpha,
int *remaining_glyphs)
{ {
cairo_format_t last_format = CAIRO_FORMAT_INVALID; cairo_format_t last_format = CAIRO_FORMAT_INVALID;
cairo_gl_glyph_cache_t *cache = NULL; cairo_gl_glyph_cache_t *cache = NULL;
cairo_gl_context_t *ctx; cairo_gl_context_t *ctx;
cairo_gl_composite_t setup; cairo_gl_composite_t setup;
cairo_status_t status; cairo_int_status_t status;
int i = 0; int i = 0;
*has_component_alpha = FALSE; *has_component_alpha = FALSE;
@ -248,45 +234,30 @@ _render_glyphs (cairo_gl_surface_t *dst,
if (unlikely (status)) if (unlikely (status))
return status; return status;
_cairo_scaled_font_freeze_cache (scaled_font); status = _cairo_gl_composite_init (&setup, op, dst, TRUE, &info->extents);
status = _cairo_gl_composite_init (&setup, op, dst,
TRUE, &extents->bounded);
if (unlikely (status)) if (unlikely (status))
goto FINISH; goto FINISH;
if (! _cairo_gl_surface_owns_font (dst, scaled_font)) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto FINISH;
}
status = _cairo_gl_composite_set_source (&setup, source, status = _cairo_gl_composite_set_source (&setup, source,
extents->bounded.x, info->extents.x,
extents->bounded.y, info->extents.y,
dst_x, dst_y, dst_x, dst_y,
extents->bounded.width, info->extents.width,
extents->bounded.height); info->extents.height);
if (unlikely (status)) if (unlikely (status))
goto FINISH; goto FINISH;
if (scaled_font->surface_private == NULL) {
scaled_font->surface_private = ctx;
scaled_font->surface_backend = &_cairo_gl_surface_backend;
cairo_list_add (&scaled_font->link, &ctx->fonts);
}
_cairo_gl_composite_set_clip_region (&setup, //_cairo_gl_composite_set_clip_region (&setup, _cairo_clip_get_region (extents->clip));
_cairo_clip_get_region (extents->clip));
for (i = 0; i < num_glyphs; i++) { for (i = 0; i < info->num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph; cairo_scaled_glyph_t *scaled_glyph;
cairo_gl_glyph_private_t *glyph; cairo_gl_glyph_t *glyph;
double x_offset, y_offset; double x_offset, y_offset;
double x1, x2, y1, y2; double x1, x2, y1, y2;
status = _cairo_scaled_glyph_lookup (scaled_font, status = _cairo_scaled_glyph_lookup (info->font,
glyphs[i].index, info->glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE, CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph); &scaled_glyph);
if (unlikely (status)) if (unlikely (status))
@ -297,13 +268,6 @@ _render_glyphs (cairo_gl_surface_t *dst,
{ {
continue; continue;
} }
if (scaled_glyph->surface->width > GLYPH_CACHE_MAX_SIZE ||
scaled_glyph->surface->height > GLYPH_CACHE_MAX_SIZE)
{
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto FINISH;
}
if (scaled_glyph->surface->format != last_format) { if (scaled_glyph->surface->format != last_format) {
status = cairo_gl_context_get_glyph_cache (ctx, status = cairo_gl_context_get_glyph_cache (ctx,
scaled_glyph->surface->format, scaled_glyph->surface->format,
@ -331,25 +295,35 @@ _render_glyphs (cairo_gl_surface_t *dst,
goto FINISH; goto FINISH;
} }
if (scaled_glyph->surface_private == NULL) { if (scaled_glyph->dev_private_key != cache) {
status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph); cairo_scaled_glyph_private_t *priv;
if (status == CAIRO_INT_STATUS_UNSUPPORTED) { priv = _cairo_scaled_glyph_find_private (scaled_glyph, cache);
/* Cache is full, so flush existing prims and try again. */ if (priv) {
_cairo_gl_composite_flush (ctx); scaled_glyph->dev_private_key = cache;
_cairo_gl_glyph_cache_unlock (cache); scaled_glyph->dev_private = cairo_container_of (priv,
cairo_gl_glyph_t,
base);;
} else {
status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph); status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
}
if (unlikely (_cairo_status_is_error (status))) if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
goto FINISH; /* Cache is full, so flush existing prims and try again. */
_cairo_gl_composite_flush (ctx);
_cairo_gl_glyph_cache_unlock (cache);
status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
}
if (unlikely (_cairo_int_status_is_error (status)))
goto FINISH;
}
} }
x_offset = scaled_glyph->surface->base.device_transform.x0; x_offset = scaled_glyph->surface->base.device_transform.x0;
y_offset = scaled_glyph->surface->base.device_transform.y0; y_offset = scaled_glyph->surface->base.device_transform.y0;
x1 = _cairo_lround (glyphs[i].x - x_offset); x1 = _cairo_lround (info->glyphs[i].x - x_offset);
y1 = _cairo_lround (glyphs[i].y - y_offset); y1 = _cairo_lround (info->glyphs[i].y - y_offset);
x2 = x1 + scaled_glyph->surface->width; x2 = x1 + scaled_glyph->surface->width;
y2 = y1 + scaled_glyph->surface->height; y2 = y1 + scaled_glyph->surface->height;
@ -362,75 +336,59 @@ _render_glyphs (cairo_gl_surface_t *dst,
status = CAIRO_STATUS_SUCCESS; status = CAIRO_STATUS_SUCCESS;
FINISH: FINISH:
_cairo_scaled_font_thaw_cache (scaled_font);
status = _cairo_gl_context_release (ctx, status); status = _cairo_gl_context_release (ctx, status);
_cairo_gl_composite_fini (&setup); _cairo_gl_composite_fini (&setup);
*remaining_glyphs = num_glyphs - i;
return status; return status;
} }
static cairo_int_status_t static cairo_int_status_t
_cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst, render_glyphs_via_mask (cairo_gl_surface_t *dst,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *source, const cairo_surface_t *source,
cairo_glyph_t *glyphs, cairo_composite_glyphs_info_t *info)
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_composite_rectangles_t *extents,
int *remaining_glyphs)
{ {
cairo_surface_t *mask; cairo_surface_t *mask;
cairo_status_t status; cairo_status_t status;
cairo_bool_t has_component_alpha; cairo_bool_t has_component_alpha;
cairo_clip_t *saved_clip;
int i; int i;
/* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */ /* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */
mask = cairo_gl_surface_create (dst->base.device, mask = cairo_gl_surface_create (dst->base.device,
CAIRO_CONTENT_COLOR_ALPHA, CAIRO_CONTENT_COLOR_ALPHA,
extents->bounded.width, info->extents.width,
extents->bounded.height); info->extents.height);
if (unlikely (mask->status)) if (unlikely (mask->status))
return mask->status; return mask->status;
for (i = 0; i < num_glyphs; i++) { for (i = 0; i < info->num_glyphs; i++) {
glyphs[i].x -= extents->bounded.x; info->glyphs[i].x -= info->extents.x;
glyphs[i].y -= extents->bounded.y; info->glyphs[i].y -= info->extents.y;
} }
status = render_glyphs ((cairo_gl_surface_t *) mask, 0, 0,
saved_clip = extents->clip; CAIRO_OPERATOR_ADD,
extents->clip = NULL; &_cairo_pattern_white.base,
status = _render_glyphs ((cairo_gl_surface_t *) mask, 0, 0, info, &has_component_alpha);
CAIRO_OPERATOR_ADD,
&_cairo_pattern_white.base,
glyphs, num_glyphs, scaled_font,
extents,
&has_component_alpha,
remaining_glyphs);
extents->clip = saved_clip;
if (likely (status == CAIRO_STATUS_SUCCESS)) { if (likely (status == CAIRO_STATUS_SUCCESS)) {
/* XXX composite */
#if 0
cairo_surface_pattern_t mask_pattern; cairo_surface_pattern_t mask_pattern;
mask->is_clear = FALSE; mask->is_clear = FALSE;
_cairo_pattern_init_for_surface (&mask_pattern, mask); _cairo_pattern_init_for_surface (&mask_pattern, mask);
mask_pattern.base.has_component_alpha = has_component_alpha; mask_pattern.base.has_component_alpha = has_component_alpha;
cairo_matrix_init_translate (&mask_pattern.base.matrix, cairo_matrix_init_translate (&mask_pattern.base.matrix,
-extents->bounded.x, -extents->bounded.y); -info->extents.x, -info->extents.y);
status = _cairo_surface_mask (&dst->base, op, status = _cairo_surface_mask (&dst->base, op,
source, &mask_pattern.base, source, &mask_pattern.base,
extents->clip); NULL);
_cairo_pattern_fini (&mask_pattern.base); _cairo_pattern_fini (&mask_pattern.base);
#endif
} else { } else {
for (i = 0; i < num_glyphs; i++) { for (i = 0; i < info->num_glyphs; i++) {
glyphs[i].x += extents->bounded.x; info->glyphs[i].x += info->extents.x;
glyphs[i].y += extents->bounded.y; info->glyphs[i].y += info->extents.y;
} }
*remaining_glyphs = num_glyphs;
} }
cairo_surface_destroy (mask); cairo_surface_destroy (mask);
@ -438,143 +396,62 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst,
return status; return status;
} }
cairo_private cairo_bool_t
_cairo_gl_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle);
cairo_int_status_t cairo_int_status_t
_cairo_gl_surface_show_glyphs (void *abstract_dst, _cairo_gl_check_composite_glyphs (const cairo_composite_rectangles_t *extents,
cairo_operator_t op, cairo_scaled_font_t *scaled_font,
const cairo_pattern_t *source, cairo_glyph_t *glyphs,
cairo_glyph_t *glyphs, int *num_glyphs)
int num_glyphs,
cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip,
int *remaining_glyphs)
{ {
cairo_gl_surface_t *dst = abstract_dst; if (! _cairo_gl_operator_is_supported (extents->op))
cairo_composite_rectangles_t extents;
cairo_rectangle_int_t unbounded;
cairo_bool_t overlap, use_mask = FALSE;
cairo_bool_t has_component_alpha;
cairo_status_t status;
int i;
if (! _cairo_gl_operator_is_supported (op))
return UNSUPPORTED ("unsupported operator"); return UNSUPPORTED ("unsupported operator");
if (! _cairo_operator_bounded_by_mask (op)) /* XXX use individual masks for large glyphs? */
use_mask |= TRUE; if (ceil (scaled_font->max_scale) >= GLYPH_CACHE_MAX_SIZE)
return UNSUPPORTED ("glyphs too large");
return CAIRO_STATUS_SUCCESS;
}
cairo_int_status_t
_cairo_gl_composite_glyphs (void *_dst,
cairo_operator_t op,
cairo_surface_t *_src,
int src_x,
int src_y,
int dst_x,
int dst_y,
cairo_composite_glyphs_info_t *info)
{
cairo_gl_surface_t *dst = _dst;
cairo_bool_t has_component_alpha;
int i;
/* If any of the glyphs are component alpha, we have to go through a mask, /* If any of the glyphs are component alpha, we have to go through a mask,
* since only _cairo_gl_surface_composite() currently supports component * since only _cairo_gl_surface_composite() currently supports component
* alpha. * alpha.
*/ */
if (!use_mask && op != CAIRO_OPERATOR_OVER) { if (!dst->base.is_clear && ! info->use_mask && op != CAIRO_OPERATOR_OVER) {
for (i = 0; i < num_glyphs; i++) { for (i = 0; i < info->num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph; cairo_scaled_glyph_t *scaled_glyph;
status = _cairo_scaled_glyph_lookup (scaled_font, if (_cairo_scaled_glyph_lookup (info->font, info->glyphs[i].index,
glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_SURFACE,
CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph) == CAIRO_INT_STATUS_SUCCESS &&
&scaled_glyph);
if (!_cairo_status_is_error (status) &&
scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32) scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32)
{ {
use_mask = TRUE; info->use_mask = TRUE;
break; break;
} }
} }
} }
/* For CLEAR, cairo's rendering equation (quoting Owen's description in: if (info->use_mask) {
* http://lists.cairographics.org/archives/cairo/2005-August/004992.html) return render_glyphs_via_mask (dst, op, _src, info);
* is:
* mask IN clip ? src OP dest : dest
* or more simply:
* mask IN CLIP ? 0 : dest
*
* where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
*
* The model we use in _cairo_gl_set_operator() is Render's:
* src IN mask IN clip OP dest
* which would boil down to:
* 0 (bounded by the extents of the drawing).
*
* However, we can do a Render operation using an opaque source
* and DEST_OUT to produce:
* 1 IN mask IN clip DEST_OUT dest
* which is
* mask IN clip ? 0 : dest
*/
if (op == CAIRO_OPERATOR_CLEAR) {
source = &_cairo_pattern_white.base;
op = CAIRO_OPERATOR_DEST_OUT;
}
/* For SOURCE, cairo's rendering equation is:
* (mask IN clip) ? src OP dest : dest
* or more simply:
* (mask IN clip) ? src : dest.
*
* If we just used the Render equation, we would get:
* (src IN mask IN clip) OP dest
* or:
* (src IN mask IN clip) bounded by extents of the drawing.
*
* The trick is that for GL blending, we only get our 4 source values
* into the blender, and since we need all 4 components of source, we
* can't also get the mask IN clip into the blender. But if we did
* two passes we could make it work:
* dest = (mask IN clip) DEST_OUT dest
* dest = src IN mask IN clip ADD dest
*
* But for now, composite via an intermediate mask.
*/
if (op == CAIRO_OPERATOR_SOURCE)
use_mask |= TRUE;
/* XXX we don't need ownership of the font as we use a global
* glyph cache -- but we do need scaled_glyph eviction notification. :-(
*/
if (! _cairo_gl_surface_owns_font (dst, scaled_font))
return UNSUPPORTED ("do not control font");
_cairo_gl_surface_get_extents (dst, &unbounded);
status = _cairo_composite_rectangles_init_for_glyphs (&extents,
&unbounded,
op, source,
scaled_font,
glyphs, num_glyphs,
clip, &overlap);
if (unlikely (status))
return status;
/* If the glyphs overlap, we need to build an intermediate mask rather
* then perform the compositing directly.
*/
use_mask |= overlap;
use_mask |= ! _cairo_clip_is_region (extents.clip);
if (use_mask) {
status = _cairo_gl_surface_show_glyphs_via_mask (dst, op,
source,
glyphs, num_glyphs,
scaled_font,
&extents,
remaining_glyphs);
} else { } else {
status = _render_glyphs (dst, extents.bounded.x, extents.bounded.y, return render_glyphs (dst, dst_x, dst_y,
op, source, op, _src, info,
glyphs, num_glyphs, scaled_font, &has_component_alpha);
&extents,
&has_component_alpha,
remaining_glyphs);
} }
_cairo_composite_rectangles_fini (&extents);
return status;
} }
void void
@ -584,7 +461,7 @@ _cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache)
GLYPH_CACHE_WIDTH, GLYPH_CACHE_WIDTH,
GLYPH_CACHE_HEIGHT, GLYPH_CACHE_HEIGHT,
GLYPH_CACHE_MIN_SIZE, GLYPH_CACHE_MIN_SIZE,
sizeof (cairo_gl_glyph_private_t)); sizeof (cairo_gl_glyph_t));
} }
void void
@ -598,4 +475,3 @@ _cairo_gl_glyph_cache_fini (cairo_gl_context_t *ctx,
cache->pattern.surface = NULL; cache->pattern.surface = NULL;
} }
} }

538
src/cairo-gl-operand.c Normal file
View file

@ -0,0 +1,538 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005,2010 Red Hat, Inc
* Copyright © 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Benjamin Otte <otte@gnome.org>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
* Eric Anholt <eric@anholt.net>
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-compositor-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
#include "cairo-surface-backend-private.h"
static cairo_int_status_t
_cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
const cairo_gradient_pattern_t *pattern,
cairo_gl_gradient_t **gradient)
{
cairo_gl_context_t *ctx;
cairo_status_t status;
status = _cairo_gl_context_acquire (dst->base.device, &ctx);
if (unlikely (status))
return status;
status = _cairo_gl_gradient_create (ctx, pattern->n_stops, pattern->stops, gradient);
return _cairo_gl_context_release (ctx, status);
}
/*
* Like cairo_pattern_acquire_surface(), but returns a matrix that transforms
* from dest to src coords.
*/
static cairo_status_t
_cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
const cairo_pattern_t *src,
cairo_gl_surface_t *dst,
int src_x, int src_y,
int dst_x, int dst_y,
int width, int height)
{
cairo_status_t status;
cairo_matrix_t m;
cairo_gl_surface_t *surface;
cairo_surface_attributes_t *attributes;
attributes = &operand->texture.attributes;
#if 0
status = _cairo_pattern_acquire_surface (src, &dst->base,
src_x, src_y,
width, height,
CAIRO_PATTERN_ACQUIRE_NONE,
(cairo_surface_t **)
&surface,
attributes);
if (unlikely (status))
return status;
#endif
if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device) &&
(attributes->extend == CAIRO_EXTEND_REPEAT ||
attributes->extend == CAIRO_EXTEND_REFLECT))
{
return UNSUPPORTED ("EXT_texture_rectangle with repeat/reflect");
}
assert (_cairo_gl_surface_is_texture (surface));
operand->type = CAIRO_GL_OPERAND_TEXTURE;
operand->texture.surface = surface;
operand->texture.tex = surface->tex;
/* Translate the matrix from
* (unnormalized src -> unnormalized src) to
* (unnormalized dst -> unnormalized src)
*/
cairo_matrix_init_translate (&m,
src_x - dst_x + attributes->x_offset,
src_y - dst_y + attributes->y_offset);
cairo_matrix_multiply (&attributes->matrix,
&m,
&attributes->matrix);
/* Translate the matrix from
* (unnormalized dst -> unnormalized src) to
* (unnormalized dst -> normalized src)
*/
if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device)) {
cairo_matrix_init_scale (&m,
1.0,
1.0);
} else {
cairo_matrix_init_scale (&m,
1.0 / surface->width,
1.0 / surface->height);
}
cairo_matrix_multiply (&attributes->matrix,
&attributes->matrix,
&m);
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
const cairo_color_t *color)
{
operand->type = CAIRO_GL_OPERAND_CONSTANT;
operand->constant.color[0] = color->red * color->alpha;
operand->constant.color[1] = color->green * color->alpha;
operand->constant.color[2] = color->blue * color->alpha;
operand->constant.color[3] = color->alpha;
}
static cairo_status_t
_cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *pattern,
cairo_gl_surface_t *dst,
int src_x, int src_y,
int dst_x, int dst_y)
{
const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *)pattern;
cairo_status_t status;
assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
if (! _cairo_gl_device_has_glsl (dst->base.device))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_gl_create_gradient_texture (dst,
gradient,
&operand->gradient.gradient);
if (unlikely (status))
return status;
if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
double x0, y0, dx, dy, sf, offset;
dx = linear->pd2.x - linear->pd1.x;
dy = linear->pd2.y - linear->pd1.y;
sf = 1.0 / (dx * dx + dy * dy);
dx *= sf;
dy *= sf;
x0 = linear->pd1.x;
y0 = linear->pd1.y;
offset = dx * x0 + dy * y0;
operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
cairo_matrix_init (&operand->gradient.m, dx, 0, dy, 1, -offset, 0);
if (! _cairo_matrix_is_identity (&pattern->matrix)) {
cairo_matrix_multiply (&operand->gradient.m,
&pattern->matrix,
&operand->gradient.m);
}
} else {
cairo_matrix_t m;
cairo_circle_double_t circles[2];
double x0, y0, r0, dx, dy, dr;
/*
* Some fragment shader implementations use half-floats to
* represent numbers, so the maximum number they can represent
* is about 2^14. Some intermediate computations used in the
* radial gradient shaders can produce results of up to 2*k^4.
* Setting k=8 makes the maximum result about 8192 (assuming
* that the extreme circles are not much smaller than the
* destination image).
*/
_cairo_gradient_pattern_fit_to_range (gradient, 8.,
&operand->gradient.m, circles);
x0 = circles[0].center.x;
y0 = circles[0].center.y;
r0 = circles[0].radius;
dx = circles[1].center.x - x0;
dy = circles[1].center.y - y0;
dr = circles[1].radius - r0;
operand->gradient.a = dx * dx + dy * dy - dr * dr;
operand->gradient.radius_0 = r0;
operand->gradient.circle_d.center.x = dx;
operand->gradient.circle_d.center.y = dy;
operand->gradient.circle_d.radius = dr;
if (operand->gradient.a == 0)
operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0;
else if (pattern->extend == CAIRO_EXTEND_NONE)
operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE;
else
operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT;
cairo_matrix_init_translate (&m, -x0, -y0);
cairo_matrix_multiply (&operand->gradient.m,
&operand->gradient.m,
&m);
}
cairo_matrix_translate (&operand->gradient.m, src_x - dst_x, src_y - dst_y);
operand->gradient.extend = pattern->extend;
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
{
switch (operand->type) {
case CAIRO_GL_OPERAND_CONSTANT:
break;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
_cairo_gl_gradient_destroy (operand->gradient.gradient);
break;
case CAIRO_GL_OPERAND_TEXTURE:
break;
default:
case CAIRO_GL_OPERAND_COUNT:
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
break;
}
operand->type = CAIRO_GL_OPERAND_NONE;
}
cairo_int_status_t
_cairo_gl_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *pattern,
cairo_gl_surface_t *dst,
int src_x, int src_y,
int dst_x, int dst_y,
int width, int height)
{
cairo_int_status_t status;
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
_cairo_gl_solid_operand_init (operand,
&((cairo_solid_pattern_t *) pattern)->color);
return CAIRO_STATUS_SUCCESS;
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
status = _cairo_gl_gradient_operand_init (operand,
pattern, dst,
src_x, src_y,
dst_x, dst_y);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
/* fall through */
default:
case CAIRO_PATTERN_TYPE_MESH:
case CAIRO_PATTERN_TYPE_SURFACE:
return _cairo_gl_pattern_texture_setup (operand,
pattern, dst,
src_x, src_y,
dst_x, dst_y,
width, height);
}
}
cairo_filter_t
_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand)
{
cairo_filter_t filter;
switch ((int) operand->type) {
case CAIRO_GL_OPERAND_TEXTURE:
filter = operand->texture.attributes.filter;
break;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
filter = CAIRO_FILTER_BILINEAR;
break;
default:
filter = CAIRO_FILTER_DEFAULT;
break;
}
return filter;
}
GLint
_cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand)
{
cairo_filter_t filter = _cairo_gl_operand_get_filter (operand);
return filter != CAIRO_FILTER_FAST && filter != CAIRO_FILTER_NEAREST ?
GL_LINEAR :
GL_NEAREST;
}
cairo_extend_t
_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand)
{
cairo_extend_t extend;
switch ((int) operand->type) {
case CAIRO_GL_OPERAND_TEXTURE:
extend = operand->texture.attributes.extend;
break;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
extend = operand->gradient.extend;
break;
default:
extend = CAIRO_EXTEND_NONE;
break;
}
return extend;
}
void
_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
cairo_gl_operand_t *operand,
cairo_gl_tex_t tex_unit)
{
char uniform_name[50];
char *custom_part;
static const char *names[] = { "source", "mask" };
strcpy (uniform_name, names[tex_unit]);
custom_part = uniform_name + strlen (names[tex_unit]);
switch (operand->type) {
default:
case CAIRO_GL_OPERAND_COUNT:
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
break;
case CAIRO_GL_OPERAND_CONSTANT:
strcpy (custom_part, "_constant");
_cairo_gl_shader_bind_vec4 (ctx,
uniform_name,
operand->constant.color[0],
operand->constant.color[1],
operand->constant.color[2],
operand->constant.color[3]);
break;
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
strcpy (custom_part, "_a");
_cairo_gl_shader_bind_float (ctx,
uniform_name,
operand->gradient.a);
/* fall through */
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
strcpy (custom_part, "_circle_d");
_cairo_gl_shader_bind_vec3 (ctx,
uniform_name,
operand->gradient.circle_d.center.x,
operand->gradient.circle_d.center.y,
operand->gradient.circle_d.radius);
strcpy (custom_part, "_radius_0");
_cairo_gl_shader_bind_float (ctx,
uniform_name,
operand->gradient.radius_0);
/* fall through */
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_TEXTURE:
/*
* For GLES2 we use shaders to implement GL_CLAMP_TO_BORDER (used
* with CAIRO_EXTEND_NONE). When bilinear filtering is enabled,
* these shaders need the texture dimensions for their calculations.
*/
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
_cairo_gl_operand_get_extend (operand) == CAIRO_EXTEND_NONE &&
_cairo_gl_operand_get_gl_filter (operand) == GL_LINEAR)
{
float width, height;
if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
width = operand->texture.surface->width;
height = operand->texture.surface->height;
}
else {
width = operand->gradient.gradient->cache_entry.size,
height = 1;
}
strcpy (custom_part, "_texdims");
_cairo_gl_shader_bind_vec2 (ctx, uniform_name, width, height);
}
break;
}
}
cairo_bool_t
_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
cairo_gl_operand_t *source,
unsigned int vertex_offset)
{
if (dest->type != source->type)
return TRUE;
if (dest->vertex_offset != vertex_offset)
return TRUE;
switch (source->type) {
case CAIRO_GL_OPERAND_NONE:
return FALSE;
case CAIRO_GL_OPERAND_CONSTANT:
return dest->constant.color[0] != source->constant.color[0] ||
dest->constant.color[1] != source->constant.color[1] ||
dest->constant.color[2] != source->constant.color[2] ||
dest->constant.color[3] != source->constant.color[3];
case CAIRO_GL_OPERAND_TEXTURE:
return dest->texture.surface != source->texture.surface ||
dest->texture.attributes.extend != source->texture.attributes.extend ||
dest->texture.attributes.filter != source->texture.attributes.filter ||
dest->texture.attributes.has_component_alpha != source->texture.attributes.has_component_alpha;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
/* XXX: improve this */
return TRUE;
default:
case CAIRO_GL_OPERAND_COUNT:
ASSERT_NOT_REACHED;
break;
}
return TRUE;
}
unsigned int
_cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type)
{
switch (type) {
default:
case CAIRO_GL_OPERAND_COUNT:
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
case CAIRO_GL_OPERAND_CONSTANT:
return 0;
case CAIRO_GL_OPERAND_TEXTURE:
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
return 2 * sizeof (GLfloat);
}
}
void
_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
GLfloat ** vb,
GLfloat x,
GLfloat y,
uint8_t alpha)
{
switch (operand->type) {
default:
case CAIRO_GL_OPERAND_COUNT:
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
case CAIRO_GL_OPERAND_CONSTANT:
break;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
{
double s = x;
double t = y;
cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
*(*vb)++ = s;
*(*vb)++ = t;
}
break;
case CAIRO_GL_OPERAND_TEXTURE:
{
cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
double s = x;
double t = y;
cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
*(*vb)++ = s;
*(*vb)++ = t;
}
break;
}
}

View file

@ -48,16 +48,17 @@
#include "cairoint.h" #include "cairoint.h"
#include "cairo-gl.h"
#include "cairo-gl-gradient-private.h" #include "cairo-gl-gradient-private.h"
#include "cairo-device-private.h" #include "cairo-device-private.h"
#include "cairo-error-private.h" #include "cairo-error-private.h"
#include "cairo-rtree-private.h" #include "cairo-rtree-private.h"
#include "cairo-scaled-font-private.h"
#include "cairo-spans-compositor-private.h"
#include <assert.h> #include <assert.h>
#include "cairo-gl.h"
#if CAIRO_HAS_GL_SURFACE #if CAIRO_HAS_GL_SURFACE
#include <GL/gl.h> #include <GL/gl.h>
#include <GL/glext.h> #include <GL/glext.h>
@ -138,7 +139,6 @@ typedef enum cairo_gl_operand_type {
CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0, CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0,
CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE, CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE,
CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT, CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT,
CAIRO_GL_OPERAND_SPANS,
CAIRO_GL_OPERAND_COUNT CAIRO_GL_OPERAND_COUNT
} cairo_gl_operand_type_t; } cairo_gl_operand_type_t;
@ -161,11 +161,10 @@ typedef enum cairo_gl_shader_in {
typedef enum cairo_gl_var_type { typedef enum cairo_gl_var_type {
CAIRO_GL_VAR_NONE, CAIRO_GL_VAR_NONE,
CAIRO_GL_VAR_TEXCOORDS, CAIRO_GL_VAR_TEXCOORDS,
CAIRO_GL_VAR_COVERAGE
} cairo_gl_var_type_t; } cairo_gl_var_type_t;
#define cairo_gl_var_type_hash(src,mask,dest) ((mask) << 2 | (src << 1) | (dest)) #define cairo_gl_var_type_hash(src,mask,spans,dest) ((spans) << 3) | ((mask) << 2 | (src << 1) | (dest))
#define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_COVERAGE << 2) | (CAIRO_GL_VAR_TEXCOORDS << 1) | CAIRO_GL_VAR_TEXCOORDS) #define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_TEXCOORDS << 3) | (CAIRO_GL_VAR_TEXCOORDS << 2) | (CAIRO_GL_VAR_TEXCOORDS << 1) | CAIRO_GL_VAR_TEXCOORDS)
/* This union structure describes a potential source or mask operand to the /* This union structure describes a potential source or mask operand to the
* compositing equation. * compositing equation.
@ -259,6 +258,8 @@ typedef struct _cairo_gl_dispatch {
struct _cairo_gl_context { struct _cairo_gl_context {
cairo_device_t base; cairo_device_t base;
const cairo_compositor_t *compositor;
GLuint texture_load_pbo; GLuint texture_load_pbo;
GLuint vbo; GLuint vbo;
GLint max_framebuffer_size; GLint max_framebuffer_size;
@ -283,6 +284,7 @@ struct _cairo_gl_context {
cairo_gl_shader_t *current_shader; cairo_gl_shader_t *current_shader;
cairo_gl_operand_t operands[2]; cairo_gl_operand_t operands[2];
cairo_bool_t spans;
char *vb; char *vb;
char *vb_mem; char *vb_mem;
@ -311,8 +313,15 @@ typedef struct _cairo_gl_composite {
cairo_gl_operand_t src; cairo_gl_operand_t src;
cairo_gl_operand_t mask; cairo_gl_operand_t mask;
cairo_bool_t spans;
} cairo_gl_composite_t; } cairo_gl_composite_t;
typedef struct _cairo_gl_font {
cairo_scaled_font_private_t base;
cairo_device_t *device;
cairo_list_t link;
} cairo_gl_font_t;
cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend; cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend;
static cairo_always_inline GLenum static cairo_always_inline GLenum
@ -432,6 +441,13 @@ _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
int src_x, int src_y, int src_x, int src_y,
int dst_x, int dst_y, int dst_x, int dst_y,
int width, int height); int width, int height);
cairo_private void
_cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
const cairo_color_t *color);
cairo_private void
_cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
const cairo_gl_operand_t *source);
cairo_private cairo_int_status_t cairo_private cairo_int_status_t
_cairo_gl_composite_set_mask (cairo_gl_composite_t *setup, _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
@ -441,7 +457,11 @@ _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
int width, int height); int width, int height);
cairo_private void cairo_private void
_cairo_gl_composite_set_mask_spans (cairo_gl_composite_t *setup); _cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
const cairo_gl_operand_t *mask);
cairo_private void
_cairo_gl_composite_set_spans (cairo_gl_composite_t *setup);
cairo_private cairo_status_t cairo_private cairo_status_t
_cairo_gl_composite_begin (cairo_gl_composite_t *setup, _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
@ -480,13 +500,6 @@ _cairo_gl_get_image_format_and_type (cairo_gl_flavor_t flavor,
GLenum *type, cairo_bool_t *has_alpha, GLenum *type, cairo_bool_t *has_alpha,
cairo_bool_t *needs_swap); cairo_bool_t *needs_swap);
cairo_private void
_cairo_gl_surface_scaled_font_fini ( cairo_scaled_font_t *scaled_font);
cairo_private void
_cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font);
cairo_private void cairo_private void
_cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache); _cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache);
@ -529,6 +542,7 @@ cairo_private cairo_status_t
_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx, _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
cairo_gl_operand_t *source, cairo_gl_operand_t *source,
cairo_gl_operand_t *mask, cairo_gl_operand_t *mask,
cairo_bool_t use_coverage,
cairo_gl_shader_in_t in, cairo_gl_shader_in_t in,
cairo_gl_shader_t **shader); cairo_gl_shader_t **shader);
@ -585,6 +599,17 @@ cairo_private cairo_status_t
_cairo_gl_dispatch_init(cairo_gl_dispatch_t *dispatch, _cairo_gl_dispatch_init(cairo_gl_dispatch_t *dispatch,
cairo_gl_get_proc_addr_func_t get_proc_addr); cairo_gl_get_proc_addr_func_t get_proc_addr);
cairo_private cairo_int_status_t
_cairo_gl_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *pattern,
cairo_gl_surface_t *dst,
int src_x, int src_y,
int dst_x, int dst_y,
int width, int height);
cairo_private void
_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
const cairo_color_t *color);
cairo_private cairo_filter_t cairo_private cairo_filter_t
_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand); _cairo_gl_operand_get_filter (cairo_gl_operand_t *operand);
@ -594,25 +619,50 @@ _cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand);
cairo_private cairo_extend_t cairo_private cairo_extend_t
_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand); _cairo_gl_operand_get_extend (cairo_gl_operand_t *operand);
cairo_private unsigned int
_cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type);
cairo_private cairo_bool_t cairo_private cairo_bool_t
_cairo_gl_surface_get_extents (void *abstract_surface, _cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
cairo_rectangle_int_t *rectangle); cairo_gl_operand_t *source,
unsigned int vertex_offset);
cairo_private void
_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
cairo_gl_operand_t *operand,
cairo_gl_tex_t tex_unit);
cairo_private void
_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
GLfloat ** vb,
GLfloat x,
GLfloat y,
uint8_t alpha);
cairo_private void
_cairo_gl_operand_destroy (cairo_gl_operand_t *operand);
cairo_private const cairo_compositor_t *
_cairo_gl_span_compositor_get (void);
cairo_private const cairo_compositor_t *
_cairo_gl_traps_compositor_get (void);
cairo_private cairo_int_status_t cairo_private cairo_int_status_t
_cairo_gl_surface_polygon (cairo_gl_surface_t *dst, _cairo_gl_check_composite_glyphs (const cairo_composite_rectangles_t *extents,
cairo_operator_t op, cairo_scaled_font_t *scaled_font,
const cairo_pattern_t *src, cairo_glyph_t *glyphs,
cairo_polygon_t *polygon, int *num_glyphs);
cairo_fill_rule_t fill_rule,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *extents);
cairo_private cairo_int_status_t cairo_private cairo_int_status_t
_cairo_gl_clip_and_composite_boxes (cairo_gl_surface_t *dst, _cairo_gl_composite_glyphs (void *_dst,
cairo_operator_t op, cairo_operator_t op,
const cairo_pattern_t *src, cairo_surface_t *_src,
cairo_boxes_t *boxes, int src_x,
cairo_composite_rectangles_t *extents); int src_y,
int dst_x,
int dst_y,
cairo_composite_glyphs_info_t *info);
slim_hidden_proto (cairo_gl_surface_create); slim_hidden_proto (cairo_gl_surface_create);
slim_hidden_proto (cairo_gl_surface_create_for_texture); slim_hidden_proto (cairo_gl_surface_create_for_texture);

View file

@ -108,6 +108,7 @@ _cairo_gl_shader_compile (cairo_gl_context_t *ctx,
cairo_gl_shader_t *shader, cairo_gl_shader_t *shader,
cairo_gl_var_type_t src, cairo_gl_var_type_t src,
cairo_gl_var_type_t mask, cairo_gl_var_type_t mask,
cairo_bool_t use_coverage,
const char *fragment_text); const char *fragment_text);
/* OpenGL Core 2.0 API. */ /* OpenGL Core 2.0 API. */
@ -426,6 +427,7 @@ _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
&ctx->fill_rectangles_shader, &ctx->fill_rectangles_shader,
CAIRO_GL_VAR_NONE, CAIRO_GL_VAR_NONE,
CAIRO_GL_VAR_NONE, CAIRO_GL_VAR_NONE,
FALSE,
fill_fs_source); fill_fs_source);
if (unlikely (status)) if (unlikely (status))
return status; return status;
@ -475,8 +477,6 @@ cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type)
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
case CAIRO_GL_OPERAND_TEXTURE: case CAIRO_GL_OPERAND_TEXTURE:
return CAIRO_GL_VAR_TEXCOORDS; return CAIRO_GL_VAR_TEXCOORDS;
case CAIRO_GL_OPERAND_SPANS:
return CAIRO_GL_VAR_COVERAGE;
} }
} }
@ -491,13 +491,8 @@ cairo_gl_shader_emit_variable (cairo_output_stream_t *stream,
case CAIRO_GL_VAR_NONE: case CAIRO_GL_VAR_NONE:
break; break;
case CAIRO_GL_VAR_TEXCOORDS: case CAIRO_GL_VAR_TEXCOORDS:
_cairo_output_stream_printf (stream, _cairo_output_stream_printf (stream,
"varying vec2 %s_texcoords;\n", "varying vec2 %s_texcoords;\n",
operand_names[name]);
break;
case CAIRO_GL_VAR_COVERAGE:
_cairo_output_stream_printf (stream,
"varying float %s_coverage;\n",
operand_names[name]); operand_names[name]);
break; break;
} }
@ -514,21 +509,29 @@ cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream,
case CAIRO_GL_VAR_NONE: case CAIRO_GL_VAR_NONE:
break; break;
case CAIRO_GL_VAR_TEXCOORDS: case CAIRO_GL_VAR_TEXCOORDS:
_cairo_output_stream_printf (stream, _cairo_output_stream_printf (stream,
" %s_texcoords = MultiTexCoord%d.xy;\n", " %s_texcoords = MultiTexCoord%d.xy;\n",
operand_names[name], name); operand_names[name], name);
break; break;
case CAIRO_GL_VAR_COVERAGE:
_cairo_output_stream_printf (stream,
" %s_coverage = Color.a;\n",
operand_names[name]);
break;
} }
} }
static void
cairo_gl_shader_dcl_coverage (cairo_output_stream_t *stream)
{
_cairo_output_stream_printf (stream, "varying float coverage;\n");
}
static void
cairo_gl_shader_def_coverage (cairo_output_stream_t *stream)
{
_cairo_output_stream_printf (stream, " coverage = Color.a;\n");
}
static cairo_status_t static cairo_status_t
cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src, cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
cairo_gl_var_type_t mask, cairo_gl_var_type_t mask,
cairo_bool_t use_coverage,
cairo_gl_var_type_t dest, cairo_gl_var_type_t dest,
char **out) char **out)
{ {
@ -539,6 +542,8 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
cairo_gl_shader_emit_variable (stream, src, CAIRO_GL_TEX_SOURCE); cairo_gl_shader_emit_variable (stream, src, CAIRO_GL_TEX_SOURCE);
cairo_gl_shader_emit_variable (stream, mask, CAIRO_GL_TEX_MASK); cairo_gl_shader_emit_variable (stream, mask, CAIRO_GL_TEX_MASK);
if (use_coverage)
cairo_gl_shader_dcl_coverage (stream);
_cairo_output_stream_printf (stream, _cairo_output_stream_printf (stream,
"attribute vec4 Vertex;\n" "attribute vec4 Vertex;\n"
@ -552,6 +557,8 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
cairo_gl_shader_emit_vertex (stream, src, CAIRO_GL_TEX_SOURCE); cairo_gl_shader_emit_vertex (stream, src, CAIRO_GL_TEX_SOURCE);
cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_TEX_MASK); cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_TEX_MASK);
if (use_coverage)
cairo_gl_shader_def_coverage (stream);
_cairo_output_stream_write (stream, _cairo_output_stream_write (stream,
"}\n\0", 3); "}\n\0", 3);
@ -774,15 +781,6 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
namestr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, namestr,
namestr, namestr, namestr, rectstr, namestr); namestr, namestr, namestr, rectstr, namestr);
break; break;
case CAIRO_GL_OPERAND_SPANS:
_cairo_output_stream_printf (stream,
"varying float %s_coverage;\n"
"vec4 get_%s()\n"
"{\n"
" return vec4(0, 0, 0, %s_coverage);\n"
"}\n",
namestr, namestr, namestr);
break;
} }
} }
@ -842,6 +840,7 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
cairo_gl_shader_in_t in, cairo_gl_shader_in_t in,
cairo_gl_operand_t *src, cairo_gl_operand_t *src,
cairo_gl_operand_t *mask, cairo_gl_operand_t *mask,
cairo_bool_t use_coverage,
cairo_gl_operand_type_t dest_type, cairo_gl_operand_type_t dest_type,
char **out) char **out)
{ {
@ -849,6 +848,7 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
unsigned char *source; unsigned char *source;
unsigned long length; unsigned long length;
cairo_status_t status; cairo_status_t status;
const char *coverage_str;
_cairo_output_stream_printf (stream, _cairo_output_stream_printf (stream,
"#ifdef GL_ES\n" "#ifdef GL_ES\n"
@ -865,6 +865,10 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
cairo_gl_shader_emit_color (stream, ctx, src, CAIRO_GL_TEX_SOURCE); cairo_gl_shader_emit_color (stream, ctx, src, CAIRO_GL_TEX_SOURCE);
cairo_gl_shader_emit_color (stream, ctx, mask, CAIRO_GL_TEX_MASK); cairo_gl_shader_emit_color (stream, ctx, mask, CAIRO_GL_TEX_MASK);
coverage_str = "";
if (use_coverage)
coverage_str = " * coverage.a";
_cairo_output_stream_printf (stream, _cairo_output_stream_printf (stream,
"void main()\n" "void main()\n"
"{\n"); "{\n");
@ -874,15 +878,18 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
ASSERT_NOT_REACHED; ASSERT_NOT_REACHED;
case CAIRO_GL_SHADER_IN_NORMAL: case CAIRO_GL_SHADER_IN_NORMAL:
_cairo_output_stream_printf (stream, _cairo_output_stream_printf (stream,
" gl_FragColor = get_source() * get_mask().a;\n"); " gl_FragColor = get_source() * get_mask().a%s;\n",
coverage_str);
break; break;
case CAIRO_GL_SHADER_IN_CA_SOURCE: case CAIRO_GL_SHADER_IN_CA_SOURCE:
_cairo_output_stream_printf (stream, _cairo_output_stream_printf (stream,
" gl_FragColor = get_source() * get_mask();\n"); " gl_FragColor = get_source() * get_mask()%s;\n",
coverage_str);
break; break;
case CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA: case CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA:
_cairo_output_stream_printf (stream, _cairo_output_stream_printf (stream,
" gl_FragColor = get_source().a * get_mask();\n"); " gl_FragColor = get_source().a * get_mask()%s;\n",
coverage_str);
break; break;
} }
@ -902,6 +909,7 @@ _cairo_gl_shader_compile (cairo_gl_context_t *ctx,
cairo_gl_shader_t *shader, cairo_gl_shader_t *shader,
cairo_gl_var_type_t src, cairo_gl_var_type_t src,
cairo_gl_var_type_t mask, cairo_gl_var_type_t mask,
cairo_bool_t use_coverage,
const char *fragment_text) const char *fragment_text)
{ {
unsigned int vertex_shader; unsigned int vertex_shader;
@ -909,12 +917,14 @@ _cairo_gl_shader_compile (cairo_gl_context_t *ctx,
assert (shader->program == 0); assert (shader->program == 0);
vertex_shader = cairo_gl_var_type_hash (src, mask, CAIRO_GL_VAR_NONE); vertex_shader = cairo_gl_var_type_hash (src, mask, use_coverage,
CAIRO_GL_VAR_NONE);
if (ctx->vertex_shaders[vertex_shader] == 0) { if (ctx->vertex_shaders[vertex_shader] == 0) {
char *source; char *source;
status = cairo_gl_shader_get_vertex_source (src, status = cairo_gl_shader_get_vertex_source (src,
mask, mask,
use_coverage,
CAIRO_GL_VAR_NONE, CAIRO_GL_VAR_NONE,
&source); &source);
if (unlikely (status)) if (unlikely (status))
@ -1042,6 +1052,7 @@ cairo_status_t
_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx, _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
cairo_gl_operand_t *source, cairo_gl_operand_t *source,
cairo_gl_operand_t *mask, cairo_gl_operand_t *mask,
cairo_bool_t use_coverage,
cairo_gl_shader_in_t in, cairo_gl_shader_in_t in,
cairo_gl_shader_t **shader) cairo_gl_shader_t **shader)
{ {
@ -1071,6 +1082,7 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
in, in,
source, source,
mask, mask,
use_coverage,
CAIRO_GL_OPERAND_NONE, CAIRO_GL_OPERAND_NONE,
&fs_source); &fs_source);
if (unlikely (status)) if (unlikely (status))
@ -1090,6 +1102,7 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
&entry->shader, &entry->shader,
cairo_gl_operand_get_var_type (source->type), cairo_gl_operand_get_var_type (source->type),
cairo_gl_operand_get_var_type (mask->type), cairo_gl_operand_get_var_type (mask->type),
use_coverage,
fs_source); fs_source);
free (fs_source); free (fs_source);

View file

@ -0,0 +1,502 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005,2010 Red Hat, Inc
* Copyright © 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Benjamin Otte <otte@gnome.org>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
* Eric Anholt <eric@anholt.net>
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-compositor-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
#include "cairo-spans-compositor-private.h"
#include "cairo-surface-backend-private.h"
typedef struct _cairo_gl_span_renderer {
cairo_span_renderer_t base;
cairo_gl_composite_t setup;
double opacity;
int xmin, xmax;
int ymin, ymax;
cairo_gl_context_t *ctx;
} cairo_gl_span_renderer_t;
static cairo_status_t
_cairo_gl_bounded_opaque_spans (void *abstract_renderer,
int y, int height,
const cairo_half_open_span_t *spans,
unsigned num_spans)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
if (num_spans == 0)
return CAIRO_STATUS_SUCCESS;
do {
if (spans[0].coverage) {
_cairo_gl_composite_emit_rect (r->ctx,
spans[0].x, y,
spans[1].x, y + height,
spans[0].coverage);
}
spans++;
} while (--num_spans > 1);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_gl_bounded_spans (void *abstract_renderer,
int y, int height,
const cairo_half_open_span_t *spans,
unsigned num_spans)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
if (num_spans == 0)
return CAIRO_STATUS_SUCCESS;
do {
if (spans[0].coverage) {
_cairo_gl_composite_emit_rect (r->ctx,
spans[0].x, y,
spans[1].x, y + height,
r->opacity * spans[0].coverage);
}
spans++;
} while (--num_spans > 1);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_gl_unbounded_spans (void *abstract_renderer,
int y, int height,
const cairo_half_open_span_t *spans,
unsigned num_spans)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
if (y > r->ymin) {
_cairo_gl_composite_emit_rect (r->ctx,
r->xmin, r->ymin,
r->xmax, y,
0);
}
if (num_spans == 0) {
_cairo_gl_composite_emit_rect (r->ctx,
r->xmin, y,
r->xmax, y + height,
0);
} else {
if (spans[0].x != r->xmin) {
_cairo_gl_composite_emit_rect (r->ctx,
r->xmin, y,
spans[0].x, y + height,
0);
}
do {
_cairo_gl_composite_emit_rect (r->ctx,
spans[0].x, y,
spans[1].x, y + height,
r->opacity * spans[0].coverage);
spans++;
} while (--num_spans > 1);
if (spans[0].x != r->xmax) {
_cairo_gl_composite_emit_rect (r->ctx,
spans[0].x, y,
r->xmax, y + height,
0);
}
}
r->ymin = y + height;
return CAIRO_STATUS_SUCCESS;
}
/* XXX */
static cairo_status_t
_cairo_gl_clipped_spans (void *abstract_renderer,
int y, int height,
const cairo_half_open_span_t *spans,
unsigned num_spans)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
if (y > r->ymin) {
_cairo_gl_composite_emit_rect (r->ctx,
r->xmin, r->ymin,
r->xmax, y,
0);
}
if (num_spans == 0) {
_cairo_gl_composite_emit_rect (r->ctx,
r->xmin, y,
r->xmax, y + height,
0);
} else {
if (spans[0].x != r->xmin) {
_cairo_gl_composite_emit_rect (r->ctx,
r->xmin, y,
spans[0].x, y + height,
0);
}
do {
_cairo_gl_composite_emit_rect (r->ctx,
spans[0].x, y,
spans[1].x, y + height,
r->opacity * spans[0].coverage);
spans++;
} while (--num_spans > 1);
if (spans[0].x != r->xmax) {
_cairo_gl_composite_emit_rect (r->ctx,
spans[0].x, y,
r->xmax, y + height,
0);
}
}
r->ymin = y + height;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_gl_finish_unbounded_spans (void *abstract_renderer)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
if (r->ymax > r->ymin) {
_cairo_gl_composite_emit_rect (r->ctx,
r->xmin, r->ymin,
r->xmax, r->ymax,
0);
}
return _cairo_gl_context_release (r->ctx, CAIRO_STATUS_SUCCESS);
}
static cairo_status_t
_cairo_gl_finish_bounded_spans (void *abstract_renderer)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
return _cairo_gl_context_release (r->ctx, CAIRO_STATUS_SUCCESS);
}
static void
emit_aligned_boxes (cairo_gl_context_t *ctx,
const cairo_boxes_t *boxes)
{
const struct _cairo_boxes_chunk *chunk;
int i;
for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
_cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2, 0);
}
}
}
static cairo_int_status_t
fill_boxes (void *_dst,
cairo_operator_t op,
const cairo_color_t *color,
cairo_boxes_t *boxes)
{
cairo_gl_composite_t setup;
cairo_gl_context_t *ctx;
cairo_int_status_t status;
status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
if (unlikely (status))
goto FAIL;
_cairo_gl_composite_set_solid_source (&setup, color);
status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto FAIL;
emit_aligned_boxes (ctx, boxes);
status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
FAIL:
_cairo_gl_composite_fini (&setup);
return status;
}
typedef struct cairo_gl_source {
cairo_surface_t base;
cairo_gl_operand_t operand;
} cairo_gl_source_t;
static cairo_status_t
_cairo_gl_source_finish (void *abstract_surface)
{
cairo_gl_source_t *source = abstract_surface;
_cairo_gl_operand_destroy (&source->operand);
return CAIRO_STATUS_SUCCESS;
}
static const cairo_surface_backend_t cairo_gl_source_backend = {
CAIRO_SURFACE_TYPE_GL,
_cairo_gl_source_finish,
NULL, /* read-only wrapper */
};
static cairo_surface_t *
pattern_to_surface (cairo_surface_t *dst,
const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *src_x, int *src_y)
{
cairo_gl_source_t *source;
cairo_int_status_t status;
source = malloc (sizeof (*source));
if (unlikely (source == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&source->base,
&cairo_gl_source_backend,
NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
*src_x = *src_y = 0;
status = _cairo_gl_operand_init (&source->operand, pattern, (cairo_gl_surface_t *)dst,
extents->x, extents->y,
extents->x, extents->y,
extents->width, extents->height);
if (unlikely (status)) {
cairo_surface_destroy (&source->base);
return _cairo_surface_create_in_error (status);
}
return &source->base;
}
static inline cairo_gl_operand_t *
source_to_operand (cairo_surface_t *surface)
{
cairo_gl_source_t *source = (cairo_gl_source_t *)surface;
return &source->operand;
}
static cairo_int_status_t
composite_boxes (void *_dst,
cairo_operator_t op,
cairo_surface_t *abstract_src,
cairo_surface_t *abstract_mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
cairo_boxes_t *boxes,
const cairo_rectangle_int_t *extents)
{
cairo_gl_composite_t setup;
cairo_gl_context_t *ctx;
cairo_int_status_t status;
status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, extents);
if (unlikely (status))
goto FAIL;
_cairo_gl_composite_set_source_operand (&setup,
source_to_operand (abstract_src));
_cairo_gl_composite_set_mask_operand (&setup,
source_to_operand (abstract_mask));
status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto FAIL;
emit_aligned_boxes (ctx, boxes);
status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
FAIL:
_cairo_gl_composite_fini (&setup);
return status;
}
static cairo_int_status_t
_cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t *_r,
const cairo_composite_rectangles_t *composite,
cairo_bool_t needs_clip)
{
cairo_gl_span_renderer_t *r = (cairo_gl_span_renderer_t *)_r;
const cairo_pattern_t *source = &composite->source_pattern.base;
cairo_operator_t op = composite->op;
cairo_int_status_t status;
/* XXX earlier! */
if (op == CAIRO_OPERATOR_CLEAR) {
source = &_cairo_pattern_white.base;
op = CAIRO_OPERATOR_DEST_OUT;
} else if (composite->surface->is_clear &&
(op == CAIRO_OPERATOR_SOURCE ||
op == CAIRO_OPERATOR_OVER ||
op == CAIRO_OPERATOR_ADD)) {
op = CAIRO_OPERATOR_SOURCE;
} else if (op == CAIRO_OPERATOR_SOURCE) {
/* no lerp equivalent without some major PITA */
return CAIRO_INT_STATUS_UNSUPPORTED;
} else if (! _cairo_gl_operator_is_supported (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_gl_composite_init (&r->setup,
op, (cairo_gl_surface_t *)composite->surface,
FALSE, &composite->unbounded);
if (unlikely (status))
goto FAIL;
status = _cairo_gl_composite_set_source (&r->setup, source,
composite->unbounded.x,
composite->unbounded.y,
composite->unbounded.x,
composite->unbounded.y,
composite->unbounded.width,
composite->unbounded.height);
if (unlikely (status))
goto FAIL;
r->opacity = 1.0;
if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
r->opacity = composite->mask_pattern.solid.color.alpha;
} else {
status = _cairo_gl_composite_set_mask (&r->setup,
&composite->mask_pattern.base,
composite->unbounded.x,
composite->unbounded.y,
composite->unbounded.x,
composite->unbounded.y,
composite->unbounded.width,
composite->unbounded.height);
if (unlikely (status))
goto FAIL;
}
_cairo_gl_composite_set_spans (&r->setup);
status = _cairo_gl_composite_begin (&r->setup, &r->ctx);
if (unlikely (status))
goto FAIL;
if (composite->is_bounded) {
if (r->opacity == 1.)
r->base.render_rows = _cairo_gl_bounded_opaque_spans;
else
r->base.render_rows = _cairo_gl_bounded_spans;
r->base.finish = _cairo_gl_finish_bounded_spans;
} else {
if (needs_clip)
r->base.render_rows = _cairo_gl_clipped_spans;
else
r->base.render_rows = _cairo_gl_unbounded_spans;
r->base.finish = _cairo_gl_finish_unbounded_spans;
r->xmin = composite->unbounded.x;
r->xmax = composite->unbounded.x + composite->unbounded.width;
r->ymin = composite->unbounded.y;
r->ymax = composite->unbounded.y + composite->unbounded.height;
}
return CAIRO_STATUS_SUCCESS;
FAIL:
return status;
}
static void
_cairo_gl_span_renderer_fini (cairo_abstract_span_renderer_t *_r,
cairo_int_status_t status)
{
cairo_gl_span_renderer_t *r = (cairo_gl_span_renderer_t *) _r;
if (status == CAIRO_INT_STATUS_SUCCESS)
r->base.finish (r);
_cairo_gl_composite_fini (&r->setup);
}
const cairo_compositor_t *
_cairo_gl_span_compositor_get (void)
{
static cairo_spans_compositor_t compositor;
if (compositor.base.delegate == NULL) {
/* The fallback to traps here is essentially just for glyphs... */
_cairo_spans_compositor_init (&compositor,
_cairo_gl_traps_compositor_get());
compositor.fill_boxes = fill_boxes;
//compositor.check_composite_boxes = check_composite_boxes;
compositor.pattern_to_surface = pattern_to_surface;
compositor.composite_boxes = composite_boxes;
//compositor.check_span_renderer = check_span_renderer;
compositor.renderer_init = _cairo_gl_span_renderer_init;
compositor.renderer_fini = _cairo_gl_span_renderer_fini;
}
return &compositor.base;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,550 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Eric Anholt
* Copyright © 2009 Chris Wilson
* Copyright © 2005,2010 Red Hat, Inc
* Copyright © 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Benjamin Otte <otte@gnome.org>
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
* Eric Anholt <eric@anholt.net>
*/
#include "cairoint.h"
#include "cairo-gl-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-compositor-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
#include "cairo-spans-compositor-private.h"
#include "cairo-surface-backend-private.h"
static cairo_int_status_t
acquire (void *abstract_dst)
{
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
release (void *abstract_dst)
{
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
set_clip_region (void *_surface,
cairo_region_t *region)
{
cairo_gl_surface_t *surface = _surface;
//surface->clip_region = region;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
draw_image_boxes (void *_dst,
cairo_image_surface_t *image,
cairo_boxes_t *boxes,
int dx, int dy)
{
cairo_gl_surface_t *dst = _dst;
struct _cairo_boxes_chunk *chunk;
int i;
for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
cairo_box_t *b = &chunk->base[i];
int x = _cairo_fixed_integer_part (b->p1.x);
int y = _cairo_fixed_integer_part (b->p1.y);
int w = _cairo_fixed_integer_part (b->p2.x) - x;
int h = _cairo_fixed_integer_part (b->p2.y) - y;
cairo_status_t status;
status = _cairo_gl_surface_draw_image (dst, image,
x + dx, y + dy,
w, h,
x, y);
if (unlikely (status))
return status;
}
}
return CAIRO_STATUS_SUCCESS;
}
static void
emit_aligned_boxes (cairo_gl_context_t *ctx,
const cairo_boxes_t *boxes)
{
const struct _cairo_boxes_chunk *chunk;
int i;
for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
_cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2, 0);
}
}
}
static cairo_int_status_t
fill_boxes (void *_dst,
cairo_operator_t op,
const cairo_color_t *color,
cairo_boxes_t *boxes)
{
cairo_gl_composite_t setup;
cairo_gl_context_t *ctx;
cairo_int_status_t status;
status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
if (unlikely (status))
goto FAIL;
_cairo_gl_composite_set_solid_source (&setup, color);
status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto FAIL;
emit_aligned_boxes (ctx, boxes);
status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
FAIL:
_cairo_gl_composite_fini (&setup);
return status;
}
typedef struct cairo_gl_source {
cairo_surface_t base;
cairo_gl_operand_t operand;
} cairo_gl_source_t;
static cairo_status_t
_cairo_gl_source_finish (void *abstract_surface)
{
cairo_gl_source_t *source = abstract_surface;
_cairo_gl_operand_destroy (&source->operand);
return CAIRO_STATUS_SUCCESS;
}
static const cairo_surface_backend_t cairo_gl_source_backend = {
CAIRO_SURFACE_TYPE_GL,
_cairo_gl_source_finish,
NULL, /* read-only wrapper */
};
static cairo_surface_t *
pattern_to_surface (cairo_surface_t *dst,
const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *src_x, int *src_y)
{
cairo_gl_source_t *source;
cairo_int_status_t status;
source = malloc (sizeof (*source));
if (unlikely (source == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&source->base,
&cairo_gl_source_backend,
NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
*src_x = *src_y = 0;
status = _cairo_gl_operand_init (&source->operand, pattern, (cairo_gl_surface_t *)dst,
extents->x, extents->y,
extents->x, extents->y,
extents->width, extents->height);
if (unlikely (status)) {
cairo_surface_destroy (&source->base);
return _cairo_surface_create_in_error (status);
}
return &source->base;
}
static inline cairo_gl_operand_t *
source_to_operand (cairo_surface_t *surface)
{
cairo_gl_source_t *source = (cairo_gl_source_t *)surface;
return &source->operand;
}
static cairo_int_status_t
composite_boxes (void *_dst,
cairo_operator_t op,
cairo_surface_t *abstract_src,
cairo_surface_t *abstract_mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
cairo_boxes_t *boxes,
const cairo_rectangle_int_t *extents)
{
cairo_gl_composite_t setup;
cairo_gl_context_t *ctx;
cairo_int_status_t status;
status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, extents);
if (unlikely (status))
goto FAIL;
_cairo_gl_composite_set_source_operand (&setup,
source_to_operand (abstract_src));
_cairo_gl_composite_set_mask_operand (&setup,
source_to_operand (abstract_mask));
status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto FAIL;
emit_aligned_boxes (ctx, boxes);
status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
FAIL:
_cairo_gl_composite_fini (&setup);
return status;
}
static cairo_int_status_t
composite (void *_dst,
cairo_operator_t op,
cairo_surface_t *abstract_src,
cairo_surface_t *abstract_mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
{
cairo_gl_composite_t setup;
cairo_gl_context_t *ctx;
cairo_int_status_t status;
status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
if (unlikely (status))
goto FAIL;
_cairo_gl_composite_set_source_operand (&setup,
source_to_operand (abstract_src));
_cairo_gl_composite_set_mask_operand (&setup,
source_to_operand (abstract_mask));
status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto FAIL;
/* XXX clip */
_cairo_gl_composite_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height, 0);
status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
FAIL:
_cairo_gl_composite_fini (&setup);
return status;
}
static cairo_int_status_t
lerp (void *dst,
cairo_surface_t *src,
cairo_surface_t *mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
{
cairo_int_status_t status;
/* we could avoid some repetition... */
status = composite (dst, CAIRO_OPERATOR_DEST_OUT, src, mask,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
if (unlikely (status))
return status;
status = composite (dst, CAIRO_OPERATOR_ADD, src, mask,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
}
static cairo_gl_surface_t *
traps_to_surface (void *_dst,
const cairo_rectangle_int_t *extents,
cairo_antialias_t antialias,
cairo_traps_t *traps)
{
pixman_format_code_t pixman_format;
pixman_image_t *pixman_image;
cairo_surface_t *image, *mask;
cairo_status_t status;
pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
pixman_image = pixman_image_create_bits (pixman_format,
extents->width,
extents->height,
NULL, 0);
if (unlikely (pixman_image == NULL))
return (cairo_gl_surface_t *)_cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_pixman_image_add_traps (pixman_image, extents->x, extents->y, traps);
image = _cairo_image_surface_create_for_pixman_image (pixman_image,
pixman_format);
if (unlikely (image->status)) {
pixman_image_unref (pixman_image);
return (cairo_gl_surface_t *)image;
}
mask = _cairo_surface_create_similar_scratch (_dst, CAIRO_CONTENT_ALPHA,
extents->width,
extents->height);
if (unlikely (mask->status)) {
cairo_surface_destroy (image);
return (cairo_gl_surface_t *)mask;
}
status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
(cairo_image_surface_t *)image,
0, 0,
extents->width, extents->height,
0, 0);
cairo_surface_destroy (image);
if (unlikely (status)) {
cairo_surface_destroy (mask);
return (cairo_gl_surface_t*)_cairo_surface_create_in_error (status);
}
return (cairo_gl_surface_t*)mask;
}
static cairo_int_status_t
composite_traps (void *_dst,
cairo_operator_t op,
cairo_surface_t *abstract_src,
int src_x,
int src_y,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_antialias_t antialias,
cairo_traps_t *traps)
{
cairo_gl_composite_t setup;
cairo_gl_context_t *ctx;
cairo_gl_surface_t *mask;
cairo_int_status_t status;
mask = traps_to_surface (_dst, extents, antialias, traps);
if (unlikely (mask->base.status))
return mask->base.status;
status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
if (unlikely (status))
goto FAIL;
_cairo_gl_composite_set_source_operand (&setup,
source_to_operand (abstract_src));
//_cairo_gl_composite_set_mask_surface (&setup, mask, 0, 0);
status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto FAIL;
/* XXX clip */
_cairo_gl_composite_emit_rect (ctx,
dst_x, dst_y,
dst_x+extents->width,
dst_y+extents->height, 0);
status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
FAIL:
_cairo_gl_composite_fini (&setup);
cairo_surface_destroy (&mask->base);
return status;
}
static cairo_gl_surface_t *
tristrip_to_surface (void *_dst,
const cairo_rectangle_int_t *extents,
cairo_antialias_t antialias,
cairo_tristrip_t *strip)
{
pixman_format_code_t pixman_format;
pixman_image_t *pixman_image;
cairo_surface_t *image, *mask;
cairo_status_t status;
pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
pixman_image = pixman_image_create_bits (pixman_format,
extents->width,
extents->height,
NULL, 0);
if (unlikely (pixman_image == NULL))
return (cairo_gl_surface_t *)_cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_pixman_image_add_tristrip (pixman_image, extents->x, extents->y, strip);
image = _cairo_image_surface_create_for_pixman_image (pixman_image,
pixman_format);
if (unlikely (image->status)) {
pixman_image_unref (pixman_image);
return (cairo_gl_surface_t *)image;
}
mask = _cairo_surface_create_similar_scratch (_dst, CAIRO_CONTENT_ALPHA,
extents->width,
extents->height);
if (unlikely (mask->status)) {
cairo_surface_destroy (image);
return (cairo_gl_surface_t *)mask;
}
status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
(cairo_image_surface_t *)image,
0, 0,
extents->width, extents->height,
0, 0);
cairo_surface_destroy (image);
if (unlikely (status)) {
cairo_surface_destroy (mask);
return (cairo_gl_surface_t*)_cairo_surface_create_in_error (status);
}
return (cairo_gl_surface_t*)mask;
}
static cairo_int_status_t
composite_tristrip (void *_dst,
cairo_operator_t op,
cairo_surface_t *abstract_src,
int src_x,
int src_y,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
cairo_antialias_t antialias,
cairo_tristrip_t *strip)
{
cairo_gl_composite_t setup;
cairo_gl_context_t *ctx;
cairo_gl_surface_t *mask;
cairo_int_status_t status;
mask = tristrip_to_surface (_dst, extents, antialias, strip);
if (unlikely (mask->base.status))
return mask->base.status;
status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
if (unlikely (status))
goto FAIL;
_cairo_gl_composite_set_source_operand (&setup,
source_to_operand (abstract_src));
//_cairo_gl_composite_set_mask_surface (&setup, mask, 0, 0);
status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto FAIL;
/* XXX clip */
_cairo_gl_composite_emit_rect (ctx,
dst_x, dst_y,
dst_x+extents->width,
dst_y+extents->height, 0);
status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
FAIL:
_cairo_gl_composite_fini (&setup);
cairo_surface_destroy (&mask->base);
return status;
}
const cairo_compositor_t *
_cairo_gl_traps_compositor_get (void)
{
static cairo_traps_compositor_t compositor;
if (compositor.base.delegate == NULL) {
_cairo_traps_compositor_init (&compositor, &_cairo_fallback_compositor);
compositor.acquire = acquire;
compositor.release = release;
compositor.set_clip_region = set_clip_region;
compositor.pattern_to_surface = pattern_to_surface;
compositor.draw_image_boxes = draw_image_boxes;
//compositor.copy_boxes = copy_boxes;
compositor.fill_boxes = fill_boxes;
//compositor.check_composite = check_composite;
compositor.composite = composite;
compositor.lerp = lerp;
//compositor.check_composite_boxes = check_composite_boxes;
compositor.composite_boxes = composite_boxes;
//compositor.check_composite_traps = check_composite_traps;
compositor.composite_traps = composite_traps;
//compositor.check_composite_tristrip = check_composite_traps;
compositor.composite_tristrip = composite_tristrip;
compositor.check_composite_glyphs = _cairo_gl_check_composite_glyphs;
compositor.composite_glyphs = _cairo_gl_composite_glyphs;
}
return &compositor.base;
}

View file

@ -41,6 +41,7 @@
#include "cairo-error-private.h" #include "cairo-error-private.h"
#include "cairo-gstate-private.h" #include "cairo-gstate-private.h"
#include "cairo-pattern-private.h" #include "cairo-pattern-private.h"
#include "cairo-traps-private.h"
#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE) #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
#define ISFINITE(x) isfinite (x) #define ISFINITE(x) isfinite (x)
@ -60,7 +61,7 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate);
static void static void
_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate); _cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate);
static cairo_status_t static void
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate, _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs, const cairo_glyph_t *glyphs,
int num_glyphs, int num_glyphs,
@ -800,11 +801,21 @@ _cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
{ {
cairo_matrix_t matrix_inverse; cairo_matrix_t matrix_inverse;
cairo_matrix_multiply (&matrix_inverse, if (! _cairo_matrix_is_identity (&gstate->target->device_transform_inverse) ||
&gstate->target->device_transform_inverse, ! _cairo_matrix_is_identity (&gstate->ctm_inverse))
&gstate->ctm_inverse); {
_cairo_matrix_transform_bounding_box (&matrix_inverse, cairo_matrix_multiply (&matrix_inverse,
x1, y1, x2, y2, is_tight); &gstate->target->device_transform_inverse,
&gstate->ctm_inverse);
_cairo_matrix_transform_bounding_box (&matrix_inverse,
x1, y1, x2, y2, is_tight);
}
else
{
if (is_tight)
*is_tight = TRUE;
}
} }
/* XXX: NYI /* XXX: NYI
@ -1346,45 +1357,29 @@ _cairo_gstate_show_page (cairo_gstate_t *gstate)
} }
static void static void
_cairo_gstate_traps_extents_to_user_rectangle (cairo_gstate_t *gstate, _cairo_gstate_extents_to_user_rectangle (cairo_gstate_t *gstate,
cairo_traps_t *traps, const cairo_box_t *extents,
double *x1, double *y1, double *x1, double *y1,
double *x2, double *y2) double *x2, double *y2)
{ {
cairo_box_t extents; double px1, py1, px2, py2;
if (traps->num_traps == 0) { px1 = _cairo_fixed_to_double (extents->p1.x);
/* no traps, so we actually won't draw anything */ py1 = _cairo_fixed_to_double (extents->p1.y);
if (x1) px2 = _cairo_fixed_to_double (extents->p2.x);
*x1 = 0.0; py2 = _cairo_fixed_to_double (extents->p2.y);
if (y1)
*y1 = 0.0;
if (x2)
*x2 = 0.0;
if (y2)
*y2 = 0.0;
} else {
double px1, py1, px2, py2;
_cairo_traps_extents (traps, &extents); _cairo_gstate_backend_to_user_rectangle (gstate,
&px1, &py1, &px2, &py2,
px1 = _cairo_fixed_to_double (extents.p1.x); NULL);
py1 = _cairo_fixed_to_double (extents.p1.y); if (x1)
px2 = _cairo_fixed_to_double (extents.p2.x); *x1 = px1;
py2 = _cairo_fixed_to_double (extents.p2.y); if (y1)
*y1 = py1;
_cairo_gstate_backend_to_user_rectangle (gstate, if (x2)
&px1, &py1, &px2, &py2, *x2 = px2;
NULL); if (y2)
if (x1) *y2 = py2;
*x1 = px1;
if (y1)
*y1 = py1;
if (x2)
*x2 = px2;
if (y2)
*y2 = py2;
}
} }
cairo_status_t cairo_status_t
@ -1393,35 +1388,57 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
double *x1, double *y1, double *x1, double *y1,
double *x2, double *y2) double *x2, double *y2)
{ {
cairo_status_t status; cairo_int_status_t status;
cairo_traps_t traps; cairo_box_t extents;
cairo_bool_t empty;
if (gstate->stroke_style.line_width <= 0.0) { if (x1)
if (x1) *x1 = 0.0;
*x1 = 0.0; if (y1)
if (y1) *y1 = 0.0;
*y1 = 0.0; if (x2)
if (x2) *x2 = 0.0;
*x2 = 0.0; if (y2)
if (y2) *y2 = 0.0;
*y2 = 0.0;
if (gstate->stroke_style.line_width <= 0.0)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
status = CAIRO_INT_STATUS_UNSUPPORTED;
if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
cairo_boxes_t boxes;
_cairo_boxes_init (&boxes);
status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
&gstate->stroke_style,
&gstate->ctm,
gstate->antialias,
&boxes);
empty = boxes.num_boxes == 0;
if (! empty)
_cairo_boxes_extents (&boxes, &extents);
_cairo_boxes_fini (&boxes);
} }
_cairo_traps_init (&traps); if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
cairo_traps_t traps;
status = _cairo_path_fixed_stroke_to_traps (path, _cairo_traps_init (&traps);
&gstate->stroke_style, status = _cairo_path_fixed_stroke_to_traps (path,
&gstate->ctm, &gstate->stroke_style,
&gstate->ctm_inverse, &gstate->ctm,
gstate->tolerance, &gstate->ctm_inverse,
&traps); gstate->tolerance,
if (likely (status == CAIRO_STATUS_SUCCESS)) { &traps);
_cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps, empty = traps.num_traps == 0;
x1, y1, x2, y2); if (! empty)
_cairo_traps_extents (&traps, &extents);
_cairo_traps_fini (&traps);
}
if (! empty) {
_cairo_gstate_extents_to_user_rectangle (gstate, &extents,
x1, y1, x2, y2);
} }
_cairo_traps_fini (&traps);
return status; return status;
} }
@ -1433,33 +1450,55 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate,
double *x2, double *y2) double *x2, double *y2)
{ {
cairo_status_t status; cairo_status_t status;
cairo_traps_t traps; cairo_box_t extents;
cairo_bool_t empty;
if (_cairo_path_fixed_fill_is_empty (path)) { if (x1)
if (x1) *x1 = 0.0;
*x1 = 0.0; if (y1)
if (y1) *y1 = 0.0;
*y1 = 0.0; if (x2)
if (x2) *x2 = 0.0;
*x2 = 0.0; if (y2)
if (y2) *y2 = 0.0;
*y2 = 0.0;
if (_cairo_path_fixed_fill_is_empty (path))
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
if (_cairo_path_fixed_fill_is_rectilinear (path)) {
cairo_boxes_t boxes;
_cairo_boxes_init (&boxes);
status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
gstate->fill_rule,
gstate->antialias,
&boxes);
empty = boxes.num_boxes == 0;
if (! empty)
_cairo_boxes_extents (&boxes, &extents);
_cairo_boxes_fini (&boxes);
} else {
cairo_traps_t traps;
_cairo_traps_init (&traps);
status = _cairo_path_fixed_fill_to_traps (path,
gstate->fill_rule,
gstate->tolerance,
&traps);
empty = traps.num_traps == 0;
if (! empty)
_cairo_traps_extents (&traps, &extents);
_cairo_traps_fini (&traps);
} }
_cairo_traps_init (&traps); if (! empty) {
_cairo_gstate_extents_to_user_rectangle (gstate, &extents,
status = _cairo_path_fixed_fill_to_traps (path, x1, y1, x2, y2);
gstate->fill_rule,
gstate->tolerance,
&traps);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
_cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
x1, y1, x2, y2);
} }
_cairo_traps_fini (&traps);
return status; return status;
} }
@ -1834,12 +1873,12 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
int num_glyphs, int num_glyphs,
cairo_glyph_text_info_t *info) cairo_glyph_text_info_t *info)
{ {
cairo_pattern_union_t source_pattern;
const cairo_pattern_t *pattern;
cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)]; cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
cairo_glyph_t *transformed_glyphs;
cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)]; cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
cairo_text_cluster_t *transformed_clusters = NULL; cairo_pattern_union_t source_pattern;
cairo_glyph_t *transformed_glyphs;
const cairo_pattern_t *pattern;
cairo_text_cluster_t *transformed_clusters;
cairo_operator_t op; cairo_operator_t op;
cairo_status_t status; cairo_status_t status;
@ -1858,16 +1897,15 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
return status; return status;
transformed_glyphs = stack_transformed_glyphs; transformed_glyphs = stack_transformed_glyphs;
transformed_clusters = stack_transformed_clusters;
if (num_glyphs > ARRAY_LENGTH (stack_transformed_glyphs)) { if (num_glyphs > ARRAY_LENGTH (stack_transformed_glyphs)) {
transformed_glyphs = cairo_glyph_allocate (num_glyphs); transformed_glyphs = cairo_glyph_allocate (num_glyphs);
if (unlikely (transformed_glyphs == NULL)) { if (unlikely (transformed_glyphs == NULL))
status = _cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_GLYPHS;
}
} }
if (info != NULL) { if (info != NULL) {
transformed_clusters = stack_transformed_clusters;
if (info->num_clusters > ARRAY_LENGTH (stack_transformed_clusters)) { if (info->num_clusters > ARRAY_LENGTH (stack_transformed_clusters)) {
transformed_clusters = cairo_text_cluster_allocate (info->num_clusters); transformed_clusters = cairo_text_cluster_allocate (info->num_clusters);
if (unlikely (transformed_clusters == NULL)) { if (unlikely (transformed_clusters == NULL)) {
@ -1876,24 +1914,24 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
} }
} }
status = _cairo_gstate_transform_glyphs_to_backend (gstate, _cairo_gstate_transform_glyphs_to_backend (gstate,
glyphs, num_glyphs, glyphs, num_glyphs,
info->clusters, info->clusters,
info->num_clusters, info->num_clusters,
info->cluster_flags, info->cluster_flags,
transformed_glyphs, transformed_glyphs,
&num_glyphs, &num_glyphs,
transformed_clusters); transformed_clusters);
} else { } else {
status = _cairo_gstate_transform_glyphs_to_backend (gstate, _cairo_gstate_transform_glyphs_to_backend (gstate,
glyphs, num_glyphs, glyphs, num_glyphs,
NULL, 0, 0, NULL, 0, 0,
transformed_glyphs, transformed_glyphs,
&num_glyphs, &num_glyphs,
NULL); NULL);
} }
if (status || num_glyphs == 0) if (num_glyphs == 0)
goto CLEANUP_GLYPHS; goto CLEANUP_GLYPHS;
op = _reduce_op (gstate); op = _reduce_op (gstate);
@ -1971,35 +2009,32 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
int num_glyphs, int num_glyphs,
cairo_path_fixed_t *path) cairo_path_fixed_t *path)
{ {
cairo_status_t status;
cairo_glyph_t *transformed_glyphs;
cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)]; cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
cairo_glyph_t *transformed_glyphs;
cairo_status_t status;
status = _cairo_gstate_ensure_scaled_font (gstate); status = _cairo_gstate_ensure_scaled_font (gstate);
if (unlikely (status)) if (unlikely (status))
return status; return status;
if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs)) { if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs)) {
transformed_glyphs = stack_transformed_glyphs; transformed_glyphs = stack_transformed_glyphs;
} else { } else {
transformed_glyphs = cairo_glyph_allocate (num_glyphs); transformed_glyphs = cairo_glyph_allocate (num_glyphs);
if (unlikely (transformed_glyphs == NULL)) if (unlikely (transformed_glyphs == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
status = _cairo_gstate_transform_glyphs_to_backend (gstate, _cairo_gstate_transform_glyphs_to_backend (gstate,
glyphs, num_glyphs, glyphs, num_glyphs,
NULL, 0, 0, NULL, 0, 0,
transformed_glyphs, transformed_glyphs,
&num_glyphs, NULL); &num_glyphs, NULL);
if (unlikely (status))
goto CLEANUP_GLYPHS;
status = _cairo_scaled_font_glyph_path (gstate->scaled_font, status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
transformed_glyphs, num_glyphs, transformed_glyphs, num_glyphs,
path); path);
CLEANUP_GLYPHS:
if (transformed_glyphs != stack_transformed_glyphs) if (transformed_glyphs != stack_transformed_glyphs)
cairo_glyph_free (transformed_glyphs); cairo_glyph_free (transformed_glyphs);
@ -2039,7 +2074,7 @@ _cairo_gstate_get_antialias (cairo_gstate_t *gstate)
* This also uses information from the scaled font and the surface to * This also uses information from the scaled font and the surface to
* cull/drop glyphs that will not be visible. * cull/drop glyphs that will not be visible.
**/ **/
static cairo_status_t static void
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate, _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs, const cairo_glyph_t *glyphs,
int num_glyphs, int num_glyphs,
@ -2050,44 +2085,40 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
int *num_transformed_glyphs, int *num_transformed_glyphs,
cairo_text_cluster_t *transformed_clusters) cairo_text_cluster_t *transformed_clusters)
{ {
int i, j, k; cairo_rectangle_int_t surface_extents;
cairo_matrix_t *ctm = &gstate->ctm; cairo_matrix_t *ctm = &gstate->ctm;
cairo_matrix_t *font_matrix = &gstate->font_matrix; cairo_matrix_t *font_matrix = &gstate->font_matrix;
cairo_matrix_t *device_transform = &gstate->target->device_transform; cairo_matrix_t *device_transform = &gstate->target->device_transform;
cairo_bool_t drop = FALSE; cairo_bool_t drop = FALSE;
double x1 = 0, x2 = 0, y1 = 0, y2 = 0; double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
int i, j, k;
if (num_transformed_glyphs != NULL) { drop = TRUE;
cairo_rectangle_int_t surface_extents; if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) {
drop = FALSE; /* unbounded surface */
drop = TRUE; } else {
if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) { double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font);
drop = FALSE; /* unbounded surface */ if (surface_extents.width == 0 || surface_extents.height == 0) {
} else { /* No visible area. Don't draw anything */
double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font); *num_transformed_glyphs = 0;
if (surface_extents.width == 0 || surface_extents.height == 0) { return;
/* No visible area. Don't draw anything */
*num_transformed_glyphs = 0;
return CAIRO_STATUS_SUCCESS;
}
/* XXX We currently drop any glyphs that has its position outside
* of the surface boundaries by a safety margin depending on the
* font scale. This however can fail in extreme cases where the
* font has really long swashes for example... We can correctly
* handle that by looking the glyph up and using its device bbox
* to device if it's going to be visible, but I'm not inclined to
* do that now.
*/
x1 = surface_extents.x - scale10;
y1 = surface_extents.y - scale10;
x2 = surface_extents.x + (int) surface_extents.width + scale10;
y2 = surface_extents.y + (int) surface_extents.height + scale10;
} }
/* XXX We currently drop any glyphs that has its position outside
* of the surface boundaries by a safety margin depending on the
* font scale. This however can fail in extreme cases where the
* font has really long swashes for example... We can correctly
* handle that by looking the glyph up and using its device bbox
* to device if it's going to be visible, but I'm not inclined to
* do that now.
*/
x1 = surface_extents.x - scale10;
y1 = surface_extents.y - scale10;
x2 = surface_extents.x + (int) surface_extents.width + scale10;
y2 = surface_extents.y + (int) surface_extents.height + scale10;
}
if (!drop) if (!drop)
*num_transformed_glyphs = num_glyphs; *num_transformed_glyphs = num_glyphs;
} else
num_transformed_glyphs = &j;
#define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2) #define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2)
@ -2156,6 +2187,8 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
if (!drop || KEEP_GLYPH (transformed_glyphs[j])) if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
j++; j++;
} }
memcpy (transformed_clusters, clusters,
num_clusters * sizeof (cairo_text_cluster_t));
} else { } else {
const cairo_glyph_t *cur_glyph; const cairo_glyph_t *cur_glyph;
@ -2209,6 +2242,8 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
if (! drop || KEEP_GLYPH (transformed_glyphs[j])) if (! drop || KEEP_GLYPH (transformed_glyphs[j]))
j++; j++;
} }
memcpy (transformed_clusters, clusters,
num_clusters * sizeof (cairo_text_cluster_t));
} else { } else {
const cairo_glyph_t *cur_glyph; const cairo_glyph_t *cur_glyph;
@ -2252,6 +2287,4 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
transformed_glyphs[j] = tmp; transformed_glyphs[j] = tmp;
} }
} }
return CAIRO_STATUS_SUCCESS;
} }

1545
src/cairo-image-compositor.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,408 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
* Copyright © 2009,2010,2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
/* This compositor is slightly pointless. Just exists for testing
* and as skeleton code.
*/
#include "cairoint.h"
#include "cairo-image-surface-private.h"
#include "cairo-compositor-private.h"
#include "cairo-region-private.h"
static cairo_int_status_t
acquire (void *abstract_dst)
{
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
release (void *abstract_dst)
{
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
set_clip_region (void *_surface,
cairo_region_t *region)
{
cairo_image_surface_t *surface = _surface;
pixman_region32_t *rgn = region ? &region->rgn : NULL;
if (! pixman_image_set_clip_region32 (surface->pixman_image, rgn))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
}
static cairo_bool_t
has_snapshot (void *_dst,
const cairo_pattern_t *pattern)
{
return FALSE;
}
static cairo_int_status_t
draw_image (void *_dst,
cairo_image_surface_t *image,
int src_x, int src_y,
int width, int height,
int dst_x, int dst_y)
{
cairo_image_surface_t *dst = (cairo_image_surface_t *)_dst;
pixman_image_composite32 (PIXMAN_OP_SRC,
image->pixman_image, NULL, dst->pixman_image,
src_x, src_y,
0, 0,
dst_x, dst_y,
width, height);
return CAIRO_STATUS_SUCCESS;
}
static inline uint32_t
color_to_uint32 (const cairo_color_t *color)
{
return
(color->alpha_short >> 8 << 24) |
(color->red_short >> 8 << 16) |
(color->green_short & 0xff00) |
(color->blue_short >> 8);
}
static inline cairo_bool_t
color_to_pixel (const cairo_color_t *color,
double opacity,
pixman_format_code_t format,
uint32_t *pixel)
{
cairo_color_t opacity_color;
uint32_t c;
if (!(format == PIXMAN_a8r8g8b8 ||
format == PIXMAN_x8r8g8b8 ||
format == PIXMAN_a8b8g8r8 ||
format == PIXMAN_x8b8g8r8 ||
format == PIXMAN_b8g8r8a8 ||
format == PIXMAN_b8g8r8x8 ||
format == PIXMAN_r5g6b5 ||
format == PIXMAN_b5g6r5 ||
format == PIXMAN_a8))
{
return FALSE;
}
if (opacity != 1.0) {
_cairo_color_init_rgba (&opacity_color,
color->red,
color->green,
color->blue,
color->alpha * opacity);
color = &opacity_color;
}
c = color_to_uint32 (color);
if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
c = ((c & 0xff000000) >> 0) |
((c & 0x00ff0000) >> 16) |
((c & 0x0000ff00) >> 0) |
((c & 0x000000ff) << 16);
}
if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
c = ((c & 0xff000000) >> 24) |
((c & 0x00ff0000) >> 8) |
((c & 0x0000ff00) << 8) |
((c & 0x000000ff) << 24);
}
if (format == PIXMAN_a8) {
c = c >> 24;
} else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
c = ((((c) >> 3) & 0x001f) |
(((c) >> 5) & 0x07e0) |
(((c) >> 8) & 0xf800));
}
*pixel = c;
return TRUE;
}
static cairo_int_status_t
fill_rectangles (void *_dst,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_int_t *rects,
int num_rects)
{
cairo_image_surface_t *dst = _dst;
uint32_t pixel;
int i;
if (! color_to_pixel (color, 1.0, dst->pixman_format, &pixel))
return CAIRO_INT_STATUS_UNSUPPORTED;
for (i = 0; i < num_rects; i++) {
pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
PIXMAN_FORMAT_BPP (dst->pixman_format),
rects[i].x, rects[i].y,
rects[i].width, rects[i].height,
pixel);
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
fill_boxes (void *_dst,
cairo_operator_t op,
const cairo_color_t *color,
cairo_boxes_t *boxes)
{
cairo_image_surface_t *dst = _dst;
struct _cairo_boxes_chunk *chunk;
uint32_t pixel;
int i;
assert (boxes->is_pixel_aligned);
if (! color_to_pixel (color, 1.0, dst->pixman_format, &pixel))
return CAIRO_INT_STATUS_UNSUPPORTED;
for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
PIXMAN_FORMAT_BPP (dst->pixman_format),
x1, y1, x2 - x1, y2 - y1,
pixel);
}
}
return CAIRO_STATUS_SUCCESS;
}
static pixman_op_t
_pixman_operator (cairo_operator_t op)
{
switch ((int) op) {
case CAIRO_OPERATOR_CLEAR:
return PIXMAN_OP_CLEAR;
case CAIRO_OPERATOR_SOURCE:
return PIXMAN_OP_SRC;
case CAIRO_OPERATOR_OVER:
return PIXMAN_OP_OVER;
case CAIRO_OPERATOR_IN:
return PIXMAN_OP_IN;
case CAIRO_OPERATOR_OUT:
return PIXMAN_OP_OUT;
case CAIRO_OPERATOR_ATOP:
return PIXMAN_OP_ATOP;
case CAIRO_OPERATOR_DEST:
return PIXMAN_OP_DST;
case CAIRO_OPERATOR_DEST_OVER:
return PIXMAN_OP_OVER_REVERSE;
case CAIRO_OPERATOR_DEST_IN:
return PIXMAN_OP_IN_REVERSE;
case CAIRO_OPERATOR_DEST_OUT:
return PIXMAN_OP_OUT_REVERSE;
case CAIRO_OPERATOR_DEST_ATOP:
return PIXMAN_OP_ATOP_REVERSE;
case CAIRO_OPERATOR_XOR:
return PIXMAN_OP_XOR;
case CAIRO_OPERATOR_ADD:
return PIXMAN_OP_ADD;
case CAIRO_OPERATOR_SATURATE:
return PIXMAN_OP_SATURATE;
case CAIRO_OPERATOR_MULTIPLY:
return PIXMAN_OP_MULTIPLY;
case CAIRO_OPERATOR_SCREEN:
return PIXMAN_OP_SCREEN;
case CAIRO_OPERATOR_OVERLAY:
return PIXMAN_OP_OVERLAY;
case CAIRO_OPERATOR_DARKEN:
return PIXMAN_OP_DARKEN;
case CAIRO_OPERATOR_LIGHTEN:
return PIXMAN_OP_LIGHTEN;
case CAIRO_OPERATOR_COLOR_DODGE:
return PIXMAN_OP_COLOR_DODGE;
case CAIRO_OPERATOR_COLOR_BURN:
return PIXMAN_OP_COLOR_BURN;
case CAIRO_OPERATOR_HARD_LIGHT:
return PIXMAN_OP_HARD_LIGHT;
case CAIRO_OPERATOR_SOFT_LIGHT:
return PIXMAN_OP_SOFT_LIGHT;
case CAIRO_OPERATOR_DIFFERENCE:
return PIXMAN_OP_DIFFERENCE;
case CAIRO_OPERATOR_EXCLUSION:
return PIXMAN_OP_EXCLUSION;
case CAIRO_OPERATOR_HSL_HUE:
return PIXMAN_OP_HSL_HUE;
case CAIRO_OPERATOR_HSL_SATURATION:
return PIXMAN_OP_HSL_SATURATION;
case CAIRO_OPERATOR_HSL_COLOR:
return PIXMAN_OP_HSL_COLOR;
case CAIRO_OPERATOR_HSL_LUMINOSITY:
return PIXMAN_OP_HSL_LUMINOSITY;
default:
ASSERT_NOT_REACHED;
return PIXMAN_OP_OVER;
}
}
static cairo_int_status_t
composite (void *_dst,
cairo_operator_t op,
cairo_surface_t *abstract_src,
cairo_surface_t *abstract_mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
{
cairo_image_surface_t *dst = _dst;
cairo_pixman_source_t *src = (cairo_pixman_source_t *)abstract_src;
cairo_pixman_source_t *mask = (cairo_pixman_source_t *)abstract_mask;
if (mask) {
pixman_image_composite32 (_pixman_operator (op),
src->pixman_image, mask->pixman_image, dst->pixman_image,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
} else {
pixman_image_composite32 (_pixman_operator (op),
src->pixman_image, NULL, dst->pixman_image,
src_x, src_y,
0, 0,
dst_x, dst_y,
width, height);
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
composite_boxes (void *_dst,
cairo_operator_t op,
cairo_surface_t *abstract_src,
cairo_surface_t *abstract_mask,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
cairo_boxes_t *boxes)
{
cairo_image_surface_t *dst = _dst;
cairo_pixman_source_t *src = (cairo_pixman_source_t *)abstract_src;
cairo_pixman_source_t *mask = (cairo_pixman_source_t *)abstract_mask;
struct _cairo_boxes_chunk *chunk;
int i;
assert (boxes->is_pixel_aligned);
op = _pixman_operator (op);
for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
if (mask) {
pixman_image_composite32 (op,
src->pixman_image, mask->pixman_image, dst->pixman_image,
x1 + src_x, y1 + src_y,
x1 + mask_x, y1 + mask_y,
x1 + dst_x, y1 + dst_y,
x2 - x1, y2 - y1);
} else {
pixman_image_composite32 (op,
src->pixman_image, NULL, dst->pixman_image,
x1 + src_x, y1 + src_y,
0, 0,
x1 + dst_x, y1 + dst_y,
x2 - x1, y2 - y1);
}
}
}
return CAIRO_STATUS_SUCCESS;
}
const cairo_compositor_t *
_cairo_image_mask_compositor_get (void)
{
static cairo_mask_compositor_t compositor;
if (compositor.base.delegate == NULL) {
_cairo_mask_compositor_init (&compositor,
_cairo_image_traps_compositor_get ());
compositor.acquire = acquire;
compositor.release = release;
compositor.set_clip_region = set_clip_region;
compositor.pattern_to_surface = _cairo_pixman_source_create_for_pattern;
compositor.has_snapshot = has_snapshot;
compositor.draw_image = draw_image;
compositor.fill_rectangles = fill_rectangles;
compositor.fill_boxes = fill_boxes;
//compositor.check_composite = check_composite;
compositor.composite = composite;
//compositor.check_composite_boxes = check_composite_boxes;
compositor.composite_boxes = composite_boxes;
}
return &compositor.base;
}

975
src/cairo-image-source.c Normal file
View file

@ -0,0 +1,975 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
* Copyright © 2009,2010,2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
/* The purpose of this file/surface is to simply translate a pattern
* to a pixman_image_t and thence to feed it back to the general
* compositor interface.
*/
#include "cairoint.h"
#include "cairo-image-surface-private.h"
#include "cairo-compositor-private.h"
#include "cairo-error-private.h"
#include "cairo-pattern-private.h"
#include "cairo-paginated-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-surface-observer-private.h"
#include "cairo-surface-snapshot-private.h"
#include "cairo-surface-subsurface-private.h"
#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
#if CAIRO_NO_MUTEX
#define PIXMAN_HAS_ATOMIC_OPS 1
#endif
#if PIXMAN_HAS_ATOMIC_OPS
static pixman_image_t *__pixman_transparent_image;
static pixman_image_t *__pixman_black_image;
static pixman_image_t *__pixman_white_image;
static pixman_image_t *
_pixman_transparent_image (void)
{
pixman_image_t *image;
image = __pixman_transparent_image;
if (unlikely (image == NULL)) {
pixman_color_t color;
color.red = 0x00;
color.green = 0x00;
color.blue = 0x00;
color.alpha = 0x00;
image = pixman_image_create_solid_fill (&color);
if (unlikely (image == NULL))
return NULL;
if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
NULL, image))
{
pixman_image_ref (image);
}
} else {
pixman_image_ref (image);
}
return image;
}
static pixman_image_t *
_pixman_black_image (void)
{
pixman_image_t *image;
image = __pixman_black_image;
if (unlikely (image == NULL)) {
pixman_color_t color;
color.red = 0x00;
color.green = 0x00;
color.blue = 0x00;
color.alpha = 0xffff;
image = pixman_image_create_solid_fill (&color);
if (unlikely (image == NULL))
return NULL;
if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
NULL, image))
{
pixman_image_ref (image);
}
} else {
pixman_image_ref (image);
}
return image;
}
static pixman_image_t *
_pixman_white_image (void)
{
pixman_image_t *image;
image = __pixman_white_image;
if (unlikely (image == NULL)) {
pixman_color_t color;
color.red = 0xffff;
color.green = 0xffff;
color.blue = 0xffff;
color.alpha = 0xffff;
image = pixman_image_create_solid_fill (&color);
if (unlikely (image == NULL))
return NULL;
if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
NULL, image))
{
pixman_image_ref (image);
}
} else {
pixman_image_ref (image);
}
return image;
}
static uint32_t
hars_petruska_f54_1_random (void)
{
#define rol(x,k) ((x << k) | (x >> (32-k)))
static uint32_t x;
return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
#undef rol
}
static struct {
cairo_color_t color;
pixman_image_t *image;
} cache[16];
static int n_cached;
#else /* !PIXMAN_HAS_ATOMIC_OPS */
static pixman_image_t *
_pixman_transparent_image (void)
{
return _pixman_image_for_color (CAIRO_COLOR_TRANSPARENT);
}
static pixman_image_t *
_pixman_black_image (void)
{
return _pixman_image_for_color (CAIRO_COLOR_BLACK);
}
static pixman_image_t *
_pixman_white_image (void)
{
return _pixman_image_for_color (CAIRO_COLOR_WHITE);
}
#endif /* !PIXMAN_HAS_ATOMIC_OPS */
pixman_image_t *
_pixman_image_for_color (const cairo_color_t *cairo_color)
{
pixman_color_t color;
pixman_image_t *image;
#if PIXMAN_HAS_ATOMIC_OPS
int i;
if (CAIRO_COLOR_IS_CLEAR (cairo_color))
return _pixman_transparent_image ();
if (CAIRO_COLOR_IS_OPAQUE (cairo_color)) {
if (cairo_color->red_short <= 0x00ff &&
cairo_color->green_short <= 0x00ff &&
cairo_color->blue_short <= 0x00ff)
{
return _pixman_black_image ();
}
if (cairo_color->red_short >= 0xff00 &&
cairo_color->green_short >= 0xff00 &&
cairo_color->blue_short >= 0xff00)
{
return _pixman_white_image ();
}
}
CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex);
for (i = 0; i < n_cached; i++) {
if (_cairo_color_equal (&cache[i].color, cairo_color)) {
image = pixman_image_ref (cache[i].image);
goto UNLOCK;
}
}
#endif
color.red = cairo_color->red_short;
color.green = cairo_color->green_short;
color.blue = cairo_color->blue_short;
color.alpha = cairo_color->alpha_short;
image = pixman_image_create_solid_fill (&color);
#if PIXMAN_HAS_ATOMIC_OPS
if (image == NULL)
goto UNLOCK;
if (n_cached < ARRAY_LENGTH (cache)) {
i = n_cached++;
} else {
i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
pixman_image_unref (cache[i].image);
}
cache[i].image = pixman_image_ref (image);
cache[i].color = *cairo_color;
UNLOCK:
CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
#endif
return image;
}
void
_cairo_image_reset_static_data (void)
{
#if PIXMAN_HAS_ATOMIC_OPS
while (n_cached)
pixman_image_unref (cache[--n_cached].image);
if (__pixman_transparent_image) {
pixman_image_unref (__pixman_transparent_image);
__pixman_transparent_image = NULL;
}
if (__pixman_black_image) {
pixman_image_unref (__pixman_black_image);
__pixman_black_image = NULL;
}
if (__pixman_white_image) {
pixman_image_unref (__pixman_white_image);
__pixman_white_image = NULL;
}
#endif
}
static pixman_image_t *
_pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
const cairo_rectangle_int_t *extents,
int *ix, int *iy)
{
pixman_image_t *pixman_image;
pixman_gradient_stop_t pixman_stops_static[2];
pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
pixman_transform_t pixman_transform;
cairo_matrix_t matrix;
cairo_circle_double_t extremes[2];
pixman_point_fixed_t p1, p2;
unsigned int i;
cairo_int_status_t status;
if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
pixman_stops = _cairo_malloc_ab (pattern->n_stops,
sizeof(pixman_gradient_stop_t));
if (unlikely (pixman_stops == NULL))
return NULL;
}
for (i = 0; i < pattern->n_stops; i++) {
pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
pixman_stops[i].color.red = pattern->stops[i].color.red_short;
pixman_stops[i].color.green = pattern->stops[i].color.green_short;
pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
}
_cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
pixman_stops,
pattern->n_stops);
} else {
pixman_fixed_t r1, r2;
r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
pixman_stops,
pattern->n_stops);
}
if (pixman_stops != pixman_stops_static)
free (pixman_stops);
if (unlikely (pixman_image == NULL))
return NULL;
*ix = *iy = 0;
status = _cairo_matrix_to_pixman_matrix_offset (&matrix, pattern->base.filter,
extents->x + extents->width/2.,
extents->y + extents->height/2.,
&pixman_transform, ix, iy);
if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) ||
! pixman_image_set_transform (pixman_image, &pixman_transform))
{
pixman_image_unref (pixman_image);
return NULL;
}
}
{
pixman_repeat_t pixman_repeat;
switch (pattern->base.extend) {
default:
case CAIRO_EXTEND_NONE:
pixman_repeat = PIXMAN_REPEAT_NONE;
break;
case CAIRO_EXTEND_REPEAT:
pixman_repeat = PIXMAN_REPEAT_NORMAL;
break;
case CAIRO_EXTEND_REFLECT:
pixman_repeat = PIXMAN_REPEAT_REFLECT;
break;
case CAIRO_EXTEND_PAD:
pixman_repeat = PIXMAN_REPEAT_PAD;
break;
}
pixman_image_set_repeat (pixman_image, pixman_repeat);
}
return pixman_image;
}
static pixman_image_t *
_pixman_image_for_mesh (const cairo_mesh_pattern_t *pattern,
const cairo_rectangle_int_t *extents,
int *tx, int *ty)
{
pixman_image_t *image;
int width, height;
*tx = -extents->x;
*ty = -extents->y;
width = extents->width;
height = extents->height;
image = pixman_image_create_bits (PIXMAN_a8r8g8b8, width, height, NULL, 0);
if (unlikely (image == NULL))
return NULL;
_cairo_mesh_pattern_rasterize (pattern,
pixman_image_get_data (image),
width, height,
pixman_image_get_stride (image),
*tx, *ty);
return image;
}
struct acquire_source_cleanup {
cairo_surface_t *surface;
cairo_image_surface_t *image;
void *image_extra;
};
static void
_acquire_source_cleanup (pixman_image_t *pixman_image,
void *closure)
{
struct acquire_source_cleanup *data = closure;
_cairo_surface_release_source_image (data->surface,
data->image,
data->image_extra);
free (data);
}
static uint16_t
expand_channel (uint16_t v, uint32_t bits)
{
int offset = 16 - bits;
while (offset > 0) {
v |= v >> bits;
offset -= bits;
bits += bits;
}
return v;
}
static pixman_image_t *
_pixel_to_solid (cairo_image_surface_t *image, int x, int y)
{
uint32_t pixel;
pixman_color_t color;
switch (image->format) {
default:
case CAIRO_FORMAT_INVALID:
ASSERT_NOT_REACHED;
return NULL;
case CAIRO_FORMAT_A1:
pixel = *(uint8_t *) (image->data + y * image->stride + x/8);
return pixel & (1 << (x&7)) ? _pixman_black_image () : _pixman_transparent_image ();
case CAIRO_FORMAT_A8:
color.alpha = *(uint8_t *) (image->data + y * image->stride + x);
color.alpha |= color.alpha << 8;
if (color.alpha == 0)
return _pixman_transparent_image ();
if (color.alpha == 0xffff)
return _pixman_black_image ();
color.red = color.green = color.blue = 0;
return pixman_image_create_solid_fill (&color);
case CAIRO_FORMAT_RGB16_565:
pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
if (pixel == 0)
return _pixman_black_image ();
if (pixel == 0xffff)
return _pixman_white_image ();
color.alpha = 0xffff;
color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
return pixman_image_create_solid_fill (&color);
case CAIRO_FORMAT_RGB30:
pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
pixel &= 0x3fffffff; /* ignore alpha bits */
if (pixel == 0)
return _pixman_black_image ();
if (pixel == 0x3fffffff)
return _pixman_white_image ();
/* convert 10bpc to 16bpc */
color.alpha = 0xffff;
color.red = expand_channel((pixel >> 20) & 0x3fff, 10);
color.green = expand_channel((pixel >> 10) & 0x3fff, 10);
color.blue = expand_channel(pixel & 0x3fff, 10);
return pixman_image_create_solid_fill (&color);
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
if (color.alpha == 0)
return _pixman_transparent_image ();
if (pixel == 0xffffffff)
return _pixman_white_image ();
if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
return _pixman_black_image ();
color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
return pixman_image_create_solid_fill (&color);
}
}
static cairo_bool_t
_pixman_image_set_properties (pixman_image_t *pixman_image,
const cairo_pattern_t *pattern,
const cairo_rectangle_int_t *extents,
int *ix,int *iy)
{
pixman_transform_t pixman_transform;
cairo_int_status_t status;
status = _cairo_matrix_to_pixman_matrix_offset (&pattern->matrix,
pattern->filter,
extents->x + extents->width/2.,
extents->y + extents->height/2.,
&pixman_transform, ix, iy);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
{
/* If the transform is an identity, we don't need to set it
* and we can use any filtering, so choose the fastest one. */
pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
}
else if (unlikely (status != CAIRO_INT_STATUS_SUCCESS ||
! pixman_image_set_transform (pixman_image,
&pixman_transform)))
{
return FALSE;
}
else
{
pixman_filter_t pixman_filter;
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;
break;
case CAIRO_FILTER_BILINEAR:
pixman_filter = PIXMAN_FILTER_BILINEAR;
break;
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
* API. We could fix this by officially deprecating it, or
* else inventing semantics and providing an actual
* implementation for it. */
default:
pixman_filter = PIXMAN_FILTER_BEST;
}
pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
}
{
pixman_repeat_t pixman_repeat;
switch (pattern->extend) {
default:
case CAIRO_EXTEND_NONE:
pixman_repeat = PIXMAN_REPEAT_NONE;
break;
case CAIRO_EXTEND_REPEAT:
pixman_repeat = PIXMAN_REPEAT_NORMAL;
break;
case CAIRO_EXTEND_REFLECT:
pixman_repeat = PIXMAN_REPEAT_REFLECT;
break;
case CAIRO_EXTEND_PAD:
pixman_repeat = PIXMAN_REPEAT_PAD;
break;
}
pixman_image_set_repeat (pixman_image, pixman_repeat);
}
if (pattern->has_component_alpha)
pixman_image_set_component_alpha (pixman_image, TRUE);
return TRUE;
}
static pixman_image_t *
_pixman_image_for_recording (cairo_image_surface_t *dst,
const cairo_surface_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *ix, int *iy)
{
cairo_surface_t *source, *clone;
cairo_rectangle_int_t limit;
pixman_image_t *pixman_image;
cairo_status_t status;
cairo_extend_t extend;
cairo_matrix_t *m, matrix;
int tx = 0, ty = 0;
*ix = *iy = 0;
source = pattern->surface;
if (_cairo_surface_is_subsurface (source))
source = _cairo_surface_subsurface_get_target_with_offset (source, &tx, &ty);
if (_cairo_surface_is_snapshot (source))
source = _cairo_surface_snapshot_get_target (source);
if (_cairo_surface_is_observer (source))
source = _cairo_surface_observer_get_target (source);
if (_cairo_surface_is_paginated (source))
source = _cairo_paginated_surface_get_target (source);
extend = pattern->base.extend;
if (_cairo_surface_get_extents (source, &limit)) {
if (sample->x >= limit.x &&
sample->y >= limit.y &&
sample->x + sample->width <= limit.x + limit.width &&
sample->y + sample->height <= limit.y + limit.height)
{
extend = CAIRO_EXTEND_NONE;
}
else if (extend == CAIRO_EXTEND_NONE &&
(sample->x + sample->width <= limit.x ||
sample->x >= limit.x + limit.width ||
sample->y + sample->height <= limit.y ||
sample->y >= limit.y + limit.height))
{
return _pixman_transparent_image ();
}
} else
extend = CAIRO_EXTEND_NONE;
if (extents == CAIRO_EXTEND_NONE)
limit = *extents;
clone = cairo_image_surface_create (dst->format, limit.width, limit.height);
cairo_surface_set_device_offset (clone, limit.x, limit.y);
m = NULL;
if (extend == CAIRO_EXTEND_NONE) {
m = &matrix;
cairo_matrix_multiply (m,
&dst->base.device_transform,
&pattern->base.matrix);
if (tx | ty)
cairo_matrix_translate (m, tx, ty);
} else {
/* XXX extract scale factor for repeating patterns */
}
status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL);
if (unlikely (status)) {
cairo_surface_destroy (clone);
return NULL;
}
pixman_image = pixman_image_ref (((cairo_image_surface_t *)clone)->pixman_image);
cairo_surface_destroy (clone);
if (extend != CAIRO_EXTEND_NONE) {
if (! _pixman_image_set_properties (pixman_image,
&pattern->base, extents,
ix, iy)) {
pixman_image_unref (pixman_image);
pixman_image= NULL;
}
}
return pixman_image;
}
static pixman_image_t *
_pixman_image_for_surface (cairo_image_surface_t *dst,
const cairo_surface_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *ix, int *iy)
{
cairo_extend_t extend = pattern->base.extend;
pixman_image_t *pixman_image;
*ix = *iy = 0;
pixman_image = NULL;
if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
return _pixman_image_for_recording(dst, pattern,
is_mask, extents, sample,
ix, iy);
if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE &&
(! is_mask || ! pattern->base.has_component_alpha ||
(pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
{
cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
cairo_surface_type_t type;
if (_cairo_surface_is_snapshot (&source->base))
source = (cairo_image_surface_t *) _cairo_surface_snapshot_get_target (&source->base);
type = source->base.backend->type;
if (type == CAIRO_SURFACE_TYPE_IMAGE) {
if (extend != CAIRO_EXTEND_NONE &&
sample->x >= 0 &&
sample->y >= 0 &&
sample->x + sample->width <= source->width &&
sample->y + sample->height <= source->height)
{
extend = CAIRO_EXTEND_NONE;
}
if (sample->width == 1 && sample->height == 1) {
if (sample->x < 0 ||
sample->y < 0 ||
sample->x >= source->width ||
sample->y >= source->height)
{
if (extend == CAIRO_EXTEND_NONE)
return _pixman_transparent_image ();
}
else
{
pixman_image = _pixel_to_solid (source,
sample->x, sample->y);
if (pixman_image)
return pixman_image;
}
}
#if PIXMAN_HAS_ATOMIC_OPS
/* avoid allocating a 'pattern' image if we can reuse the original */
*ix = *iy = 0;
if (extend == CAIRO_EXTEND_NONE &&
_cairo_matrix_is_pixman_translation (&pattern->base.matrix,
pattern->base.filter,
ix, iy))
{
return pixman_image_ref (source->pixman_image);
}
#endif
pixman_image = pixman_image_create_bits (source->pixman_format,
source->width,
source->height,
(uint32_t *) source->data,
source->stride);
if (unlikely (pixman_image == NULL))
return NULL;
} else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
cairo_surface_subsurface_t *sub;
cairo_bool_t is_contained = FALSE;
sub = (cairo_surface_subsurface_t *) source;
source = (cairo_image_surface_t *) sub->target;
if (sample->x >= 0 &&
sample->y >= 0 &&
sample->x + sample->width <= sub->extents.width &&
sample->y + sample->height <= sub->extents.height)
{
is_contained = TRUE;
}
if (sample->width == 1 && sample->height == 1) {
if (is_contained) {
pixman_image = _pixel_to_solid (source,
sub->extents.x + sample->x,
sub->extents.y + sample->y);
if (pixman_image)
return pixman_image;
} else {
if (extend == CAIRO_EXTEND_NONE)
return _pixman_transparent_image ();
}
}
#if PIXMAN_HAS_ATOMIC_OPS
*ix = sub->extents.x;
*iy = sub->extents.y;
if (is_contained &&
_cairo_matrix_is_pixman_translation (&pattern->base.matrix,
pattern->base.filter,
ix, iy))
{
return pixman_image_ref (source->pixman_image);
}
#endif
/* Avoid sub-byte offsets, force a copy in that case. */
if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
void *data = source->data
+ sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8
+ sub->extents.y * source->stride;
pixman_image = pixman_image_create_bits (source->pixman_format,
sub->extents.width,
sub->extents.height,
data,
source->stride);
if (unlikely (pixman_image == NULL))
return NULL;
}
}
}
#if PIXMAN_HAS_ATOMIC_OPS
*ix = *iy = 0;
#endif
if (pixman_image == NULL) {
struct acquire_source_cleanup *cleanup;
cairo_image_surface_t *image;
void *extra;
cairo_status_t status;
status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra);
if (unlikely (status))
return NULL;
if (sample->x >= 0 && sample->y >= 0 &&
sample->x + sample->width <= image->width &&
sample->y + sample->height <= image->height)
{
extend = CAIRO_EXTEND_NONE;
}
if (sample->width == 1 && sample->height == 1) {
if (sample->x < 0 ||
sample->y < 0 ||
sample->x >= image->width ||
sample->y >= image->height)
{
if (extend == CAIRO_EXTEND_NONE) {
pixman_image = _pixman_transparent_image ();
_cairo_surface_release_source_image (pattern->surface, image, extra);
return pixman_image;
}
}
else
{
pixman_image = _pixel_to_solid (image, sample->x, sample->y);
if (pixman_image) {
_cairo_surface_release_source_image (pattern->surface, image, extra);
return pixman_image;
}
}
}
pixman_image = pixman_image_create_bits (image->pixman_format,
image->width,
image->height,
(uint32_t *) image->data,
image->stride);
if (unlikely (pixman_image == NULL)) {
_cairo_surface_release_source_image (pattern->surface, image, extra);
return NULL;
}
cleanup = malloc (sizeof (*cleanup));
if (unlikely (cleanup == NULL)) {
_cairo_surface_release_source_image (pattern->surface, image, extra);
pixman_image_unref (pixman_image);
return NULL;
}
cleanup->surface = pattern->surface;
cleanup->image = image;
cleanup->image_extra = extra;
pixman_image_set_destroy_function (pixman_image,
_acquire_source_cleanup, cleanup);
}
if (! _pixman_image_set_properties (pixman_image,
&pattern->base, extents,
ix, iy)) {
pixman_image_unref (pixman_image);
pixman_image= NULL;
}
return pixman_image;
}
pixman_image_t *
_pixman_image_for_pattern (cairo_image_surface_t *dst,
const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *tx, int *ty)
{
*tx = *ty = 0;
if (pattern == NULL)
return _pixman_white_image ();
switch (pattern->type) {
default:
ASSERT_NOT_REACHED;
case CAIRO_PATTERN_TYPE_SOLID:
return _pixman_image_for_color (&((const cairo_solid_pattern_t *) pattern)->color);
case CAIRO_PATTERN_TYPE_RADIAL:
case CAIRO_PATTERN_TYPE_LINEAR:
return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
extents, tx, ty);
case CAIRO_PATTERN_TYPE_MESH:
return _pixman_image_for_mesh ((const cairo_mesh_pattern_t *) pattern,
extents, tx, ty);
case CAIRO_PATTERN_TYPE_SURFACE:
return _pixman_image_for_surface (dst,
(const cairo_surface_pattern_t *) pattern,
is_mask, extents, sample,
tx, ty);
}
}
static cairo_status_t
_cairo_image_source_finish (void *abstract_surface)
{
cairo_image_source_t *source = abstract_surface;
pixman_image_unref (source->pixman_image);
return CAIRO_STATUS_SUCCESS;
}
static const cairo_surface_backend_t cairo_image_source_backend = {
CAIRO_SURFACE_TYPE_IMAGE,
_cairo_image_source_finish,
NULL, /* read-only wrapper */
};
cairo_surface_t *
_cairo_image_source_create_for_pattern (cairo_surface_t *dst,
const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *src_x, int *src_y)
{
cairo_image_source_t *source;
source = malloc (sizeof (cairo_image_source_t));
if (unlikely (source == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
source->pixman_image =
_pixman_image_for_pattern ((cairo_image_surface_t *)dst,
pattern, is_mask,
extents, sample,
src_x, src_y);
if (unlikely (source->pixman_image == NULL)) {
free (source);
return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
}
_cairo_surface_init (&source->base,
&cairo_image_source_backend,
NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
source->is_opaque_solid =
pattern == NULL || _cairo_pattern_is_opaque_solid (pattern);
return &source->base;
}

View file

@ -0,0 +1,131 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
* Copyright © 2009,2010,2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-compositor-private.h"
#include "cairo-image-surface-private.h"
#include "cairo-spans-compositor-private.h"
typedef struct _cairo_image_span_renderer {
cairo_span_renderer_t base;
pixman_image_compositor_t *compositor;
pixman_image_t *src;
float opacity;
cairo_rectangle_int_t extents;
} cairo_image_span_renderer_t;
static cairo_status_t
_cairo_image_span_renderer_init (cairo_abstract_span_renderer_t *_r,
cairo_surface_t *dst,
cairo_operator_t op,
cairo_surface_t *src,
int src_x, int src_y;
float opacity,
const cairo_composite_rectangles_t *composite,
cairo_bool_t needs_clip)
{
cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
cairo_pixman_source_t *src = (cairo_pixman_source_t *)_src;
int src_x, src_y;
if (op == CAIRO_OPERATOR_CLEAR) {
op = CAIRO_OPERATOR_DEST_OUT;
pattern = NULL;
}
r->src = ((cairo_pixman_source_t *) src)->pixman_image;
r->opacity = opacity;
if (composite->is_bounded) {
if (opacity == 1.)
r->base.render_rows = _cairo_image_bounded_opaque_spans;
else
r->base.render_rows = _cairo_image_bounded_spans;
r->base.finish = NULL;
} else {
if (needs_clip)
r->base.render_rows = _cairo_image_clipped_spans;
else
r->base.render_rows = _cairo_image_unbounded_spans;
r->base.finish = _cairo_image_finish_unbounded_spans;
r->extents = composite->unbounded;
r->extents.height += r->extents.y;
}
r->compositor =
pixman_image_create_compositor (_pixman_operator (op),
r->src, NULL, dst->pixman_image,
composite->bounded.x + src_x,
composite->bounded.y + src_y,
0, 0,
composite->bounded.x,
composite->bounded.y,
composite->bounded.width,
composite->bounded.height);
if (unlikely (r->compositor == NULL))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_image_span_renderer_fini (cairo_abstract_span_renderer_t *_r)
{
cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) r;
pixman_image_compositor_destroy (r->compositor);
}
const cairo_compositor_t *
_cairo_image_spans_compositor_get (void)
{
static cairo_spans_compositor_t compositor;
if (compositor.base.delegate == NULL) {
/* Can't fallback to the mask compositor as that will simply
* call the spans-compositor again to render the mask!
*/
_cairo_spans_compositor_init (&compositor,
_cairo_image_traps_compositor_get());
}
return &compositor.base;
}

View file

@ -44,9 +44,13 @@
CAIRO_BEGIN_DECLS CAIRO_BEGIN_DECLS
/* The canonical image backend */
struct _cairo_image_surface { struct _cairo_image_surface {
cairo_surface_t base; cairo_surface_t base;
pixman_image_t *pixman_image;
const cairo_compositor_t *compositor;
pixman_format_code_t pixman_format; pixman_format_code_t pixman_format;
cairo_format_t format; cairo_format_t format;
unsigned char *data; unsigned char *data;
@ -56,20 +60,55 @@ struct _cairo_image_surface {
int stride; int stride;
int depth; int depth;
pixman_image_t *pixman_image;
unsigned owns_data : 1; unsigned owns_data : 1;
unsigned transparency : 2; unsigned transparency : 2;
unsigned color : 2; unsigned color : 2;
}; };
extern const cairo_private cairo_surface_backend_t _cairo_image_surface_backend; /* A wrapper for holding pixman images returned by create_for_pattern */
typedef struct _cairo_image_source {
cairo_surface_t base;
pixman_image_t *pixman_image;
unsigned is_opaque_solid : 1;
} cairo_image_source_t;
cairo_private extern const cairo_surface_backend_t _cairo_image_surface_backend;
cairo_private const cairo_compositor_t *
_cairo_image_mask_compositor_get (void);
cairo_private const cairo_compositor_t *
_cairo_image_traps_compositor_get (void);
cairo_private const cairo_compositor_t *
_cairo_image_spans_compositor_get (void);
cairo_private void cairo_private void
_cairo_image_surface_init (cairo_image_surface_t *surface, _cairo_image_surface_init (cairo_image_surface_t *surface,
pixman_image_t *pixman_image, pixman_image_t *pixman_image,
pixman_format_code_t pixman_format); pixman_format_code_t pixman_format);
cairo_private cairo_surface_t *
_cairo_image_surface_map_to_image (void *abstract_other,
const cairo_rectangle_int_t *extents);
cairo_private cairo_int_status_t
_cairo_image_surface_unmap_image (void *abstract_surface,
cairo_image_surface_t *image);
cairo_private cairo_status_t
_cairo_image_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra);
cairo_private void
_cairo_image_surface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra);
cairo_private cairo_surface_t *
_cairo_image_surface_snapshot (void *abstract_surface);
cairo_private_no_warn cairo_bool_t cairo_private_no_warn cairo_bool_t
_cairo_image_surface_get_extents (void *abstract_surface, _cairo_image_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle); cairo_rectangle_int_t *rectangle);
@ -78,9 +117,52 @@ cairo_private void
_cairo_image_surface_get_font_options (void *abstract_surface, _cairo_image_surface_get_font_options (void *abstract_surface,
cairo_font_options_t *options); cairo_font_options_t *options);
cairo_private cairo_surface_t *
_cairo_image_source_create_for_pattern (cairo_surface_t *dst,
const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *src_x, int *src_y);
cairo_private cairo_status_t cairo_private cairo_status_t
_cairo_image_surface_finish (void *abstract_surface); _cairo_image_surface_finish (void *abstract_surface);
cairo_private pixman_image_t *
_pixman_image_for_color (const cairo_color_t *cairo_color);
cairo_private pixman_image_t *
_pixman_image_for_pattern (cairo_image_surface_t *dst,
const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
const cairo_rectangle_int_t *extents,
const cairo_rectangle_int_t *sample,
int *tx, int *ty);
cairo_private void
_pixman_image_add_traps (pixman_image_t *image,
int dst_x, int dst_y,
cairo_traps_t *traps);
cairo_private void
_pixman_image_add_tristrip (pixman_image_t *image,
int dst_x, int dst_y,
cairo_tristrip_t *strip);
/**
* _cairo_surface_is_image:
* @surface: a #cairo_surface_t
*
* Checks if a surface is an #cairo_image_surface_t
*
* Return value: %TRUE if the surface is an image surface
**/
static inline cairo_bool_t
_cairo_surface_is_image (const cairo_surface_t *surface)
{
return surface->backend == &_cairo_image_surface_backend;
}
CAIRO_END_DECLS CAIRO_END_DECLS
#endif /* CAIRO_IMAGE_SURFACE_PRIVATE_H */ #endif /* CAIRO_IMAGE_SURFACE_PRIVATE_H */

File diff suppressed because it is too large Load diff

1412
src/cairo-mask-compositor.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -889,6 +889,9 @@ _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
{ {
double a, b, c, d, f, g, h, i, j; double a, b, c, d, f, g, h, i, j;
if (_cairo_matrix_has_unity_scale (matrix))
return radius;
_cairo_matrix_get_affine (matrix, _cairo_matrix_get_affine (matrix,
&a, &b, &a, &b,
&c, &d, &c, &d,
@ -1043,6 +1046,9 @@ _cairo_matrix_is_pixman_translation (const cairo_matrix_t *matrix,
if (!_cairo_matrix_is_translation (matrix)) if (!_cairo_matrix_is_translation (matrix))
return FALSE; return FALSE;
if (matrix->x0 == 0. && matrix->y0 == 0.)
return TRUE;
tx = matrix->x0 + *x_offset; tx = matrix->x0 + *x_offset;
ty = matrix->y0 + *y_offset; ty = matrix->y0 + *y_offset;

Some files were not shown because too many files have changed in this diff Show more