Merge branch 'stroke-with-spans'

This branch brings self-intersection removal with virtually no
performance regression. (Compare with the initial implementation that
incurred a 5-10x slowdown due to having to tessellate whole strokes at a
time.) The importance of self-intersection removal is the improved visual
quality it brings - gone are those annoying sparkles on the outside of
rounded-rectangles for instance. Most of the performance overhead
associated with the self-intersection removal is avoided by switching from
trapezoids to spans for strokes. Obviously we are not able to do so for
the xlib backend as we do not yet have a polygon image type, and so the
tessellators are overhauled instead, along with more special casing for
frequent operations to avoid the increased complexity along the general
paths.

Speedups
========
 xlib-rgba             swfdec-youtube-0    11371.13 (11406.01 0.28%) -> 10450.00 (10461.84 0.66%):  1.09x speedup
▏
image-rgba          firefox-talos-svg-0    73696.53 (73828.28 3.42%) -> 68324.30 (70269.79 1.36%):  1.08x speedup
▏
image-rgba             swfdec-youtube-0    7843.08 (7873.89 2.57%) -> 7393.96 (7399.68 0.18%):  1.06x speedup

 xvfb-rgba             swfdec-youtube-0    9627.25 (9634.43 0.16%) -> 9020.55 (9040.97 0.27%):  1.07x speedup
▏
Slowdowns
=========
 xvfb-rgba         gnome-terminal-vim-0    7695.12 (7697.87 0.44%) -> 8569.45 (8588.29 0.19%):  1.11x slowdown
▏
 xvfb-rgba         swfdec-giant-steps-0    3811.77 (3815.06 0.23%) -> 4246.67 (4569.17 3.52%):  1.11x slowdown
▏
image-rgba                       gvim-0    7150.90 (7181.96 29.36%) -> 14641.04 (14651.36 0.11%):  2.05x slowdown
█

One method for overcoming these regressions is to reduce the complexity of
the polygons being fed into the tessellator (both in the number of edges
and intersections). This should be feasible by coupling into Jeff Muizelaar's
stroke-to-path work, which early indications suggest will bring a
significant performance improvement. On top of this, our span
implementation for the image backend is not as efficient as we would hope
for - and Joonas promises a much faster implementation soon.
This commit is contained in:
Chris Wilson 2009-08-29 17:45:48 +01:00
commit 19ebf83b67
353 changed files with 18884 additions and 4693 deletions

18
NEWS
View file

@ -69,6 +69,24 @@ New experimental backends:
more offloading onto the GPU.
The initial work on the backend was performed by Eric Anholt.
Long standing bugs fixed:
Self-intersecting strokes.
A long standing bug where the coverage from overlapping semi-opaque
strokes (including neighbouring edges) was simply summed in lieu of
a costly global calculation has been fixed (by performing the costly
global calculation!) In order to mitigate the extra cost, the
tessellator has been overhauled and tune, which handles the fallback
for when we are unable to use the new span rasteriser on the stroke
(e.g. when using the current RENDER protocol). The large number of
pixel artefacts that implementing self-intersection elimination
removes is ample justification for the potential performance
regression. If you unfortunately do suffer a substantial performance
regression in your application, please consider obtaining a
cairo-trace and submitting it to us for analysis and inclusion into
our performance suite.
Snapshot 1.9.2 (2009-06-12)
===========================

View file

@ -23,6 +23,9 @@ libcairoboilerplate_la_SOURCES = \
cairo-boilerplate-constructors.c \
$(NULL)
libcairoboilerplate_la_LIBADD = $(top_builddir)/src/libcairo.la
if CAIRO_HAS_DL
libcairoboilerplate_la_LIBADD += -ldl
endif
if CAIRO_HAS_BEOS_SURFACE
# BeOS system headers trigger this warning

View file

@ -36,6 +36,7 @@ cairo_boilerplate_ps_sources = cairo-boilerplate-ps.c
cairo_boilerplate_qt_sources = cairo-boilerplate-qt.cpp
cairo_boilerplate_quartz_sources = cairo-boilerplate-quartz.c
cairo_boilerplate_script_sources = cairo-boilerplate-script.c
cairo_boilerplate_skia_sources = cairo-boilerplate-skia.c
cairo_boilerplate_svg_sources = cairo-boilerplate-svg.c
cairo_boilerplate_test_surfaces_sources = cairo-boilerplate-test-surfaces.c
cairo_boilerplate_win32_sources = cairo-boilerplate-win32.c cairo-boilerplate-win32-printing.c

View file

@ -109,6 +109,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_win32_font_private)
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_win32_font_sources)
endif
unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_skia_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_skia_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_skia_private)
all_cairo_boilerplate_sources += $(cairo_boilerplate_skia_sources)
ifeq ($(CAIRO_HAS_SKIA_SURFACE),1)
enabled_cairo_boilerplate_headers += $(cairo_boilerplate_skia_headers)
enabled_cairo_boilerplate_private += $(cairo_boilerplate_skia_private)
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_skia_sources)
endif
unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_os2_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_os2_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_os2_private)
@ -312,6 +322,24 @@ enabled_cairo_boilerplate_headers += $(cairo_boilerplate_meta_headers)
enabled_cairo_boilerplate_private += $(cairo_boilerplate_meta_private)
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_meta_sources)
supported_cairo_boilerplate_headers += $(cairo_boilerplate_tee_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_tee_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_tee_private)
all_cairo_boilerplate_sources += $(cairo_boilerplate_tee_sources)
enabled_cairo_boilerplate_headers += $(cairo_boilerplate_tee_headers)
enabled_cairo_boilerplate_private += $(cairo_boilerplate_tee_private)
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_tee_sources)
supported_cairo_boilerplate_headers += $(cairo_boilerplate_xml_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_xml_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_xml_private)
all_cairo_boilerplate_sources += $(cairo_boilerplate_xml_sources)
ifeq ($(CAIRO_HAS_XML_SURFACE),1)
enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xml_headers)
enabled_cairo_boilerplate_private += $(cairo_boilerplate_xml_private)
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xml_sources)
endif
supported_cairo_boilerplate_headers += $(cairo_boilerplate_user_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_user_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_user_private)

View file

@ -211,6 +211,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"directfb", "directfb", NULL, NULL,
CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR, 0,
"cairo_directfb_surface_create",
_cairo_boilerplate_directfb_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -220,6 +221,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"directfb-bitmap", "directfb", NULL, NULL,
CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR_ALPHA, 0,
"cairo_directfb_surface_create",
_cairo_boilerplate_directfb_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,

View file

@ -70,6 +70,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"drm", "drm", NULL, NULL,
CAIRO_SURFACE_TYPE_DRM, CAIRO_CONTENT_COLOR_ALPHA, 1,
"cairo_drm_surface_create",
_cairo_boilerplate_drm_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -80,6 +81,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"drm", "drm", NULL, NULL,
CAIRO_SURFACE_TYPE_DRM, CAIRO_CONTENT_COLOR, 1,
"cairo_drm_surface_create",
_cairo_boilerplate_drm_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,

View file

@ -141,6 +141,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"gl", "gl", NULL, NULL,
CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
"cairo_gl_surface_create",
_cairo_boilerplate_gl_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -151,6 +152,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"gl", "gl", NULL, NULL,
CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR, 1,
"cairo_gl_surface_create",
_cairo_boilerplate_gl_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,

View file

@ -169,6 +169,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"glitz-agl", "glitz", NULL, NULL,
CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA, 0,
"cairo_glitz_surface_create",
_cairo_boilerplate_glitz_agl_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -178,6 +179,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"glitz-agl", "glitz", NULL, NULL,
CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0,
"cairo_glitz_surface_create",
_cairo_boilerplate_glitz_agl_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,

View file

@ -243,6 +243,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"glitz-glx", "glitz", NULL, NULL,
CAIRO_SURFACE_TYPE_GLITZ,CAIRO_CONTENT_COLOR_ALPHA, 0,
"cairo_glitz_surface_create",
_cairo_boilerplate_glitz_glx_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -252,6 +253,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"glitz-glx", "glitz", NULL, NULL,
CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0,
"cairo_glitz_surface_create",
_cairo_boilerplate_glitz_glx_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,

View file

@ -166,6 +166,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"glitz-wgl", "glitz", NULL, NULL,
CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA, 0,
"cairo_glitz_surface_create",
_cairo_boilerplate_glitz_wgl_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -175,6 +176,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"glitz-wgl", "glitz", NULL, NULL,
CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0,
"cairo_glitz_surface_create",
_cairo_boilerplate_glitz_wgl_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,

View file

@ -229,6 +229,7 @@ static const cairo_boilerplate_target_t targets[] = {
"pdf", "pdf", ".pdf", NULL,
CAIRO_SURFACE_TYPE_PDF,
CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
"cairo_pdf_surface_create",
_cairo_boilerplate_pdf_create_surface,
_cairo_boilerplate_pdf_force_fallbacks,
_cairo_boilerplate_pdf_finish_surface,
@ -240,6 +241,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"pdf", "pdf", ".pdf", NULL,
CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
"cairo_pdf_surface_create",
_cairo_boilerplate_pdf_create_surface,
_cairo_boilerplate_pdf_force_fallbacks,
_cairo_boilerplate_pdf_finish_surface,

View file

@ -294,6 +294,7 @@ static const cairo_boilerplate_target_t targets[] = {
"ps2", "ps", ".ps", NULL,
CAIRO_SURFACE_TYPE_PS,
CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
"cairo_ps_surface_create",
_cairo_boilerplate_ps2_create_surface,
_cairo_boilerplate_ps_force_fallbacks,
_cairo_boilerplate_ps_finish_surface,
@ -305,6 +306,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"ps2", "ps", ".ps", NULL,
CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
"cairo_ps_surface_create",
_cairo_boilerplate_ps2_create_surface,
_cairo_boilerplate_ps_force_fallbacks,
_cairo_boilerplate_ps_finish_surface,
@ -317,6 +319,7 @@ static const cairo_boilerplate_target_t targets[] = {
"ps3", "ps", ".ps", NULL,
CAIRO_SURFACE_TYPE_PS,
CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
"cairo_ps_surface_create",
_cairo_boilerplate_ps3_create_surface,
_cairo_boilerplate_ps_force_fallbacks,
_cairo_boilerplate_ps_finish_surface,
@ -328,6 +331,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"ps3", "ps", ".ps", NULL,
CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
"cairo_ps_surface_create",
_cairo_boilerplate_ps3_create_surface,
_cairo_boilerplate_ps_force_fallbacks,
_cairo_boilerplate_ps_finish_surface,

View file

@ -52,6 +52,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"quartz", "quartz", NULL, NULL,
CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR_ALPHA, 0,
"cairo_quartz_surface_create",
_cairo_boilerplate_quartz_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -60,6 +61,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"quartz", "quartz", NULL, NULL,
CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR, 0,
"cairo_quartz_surface_create",
_cairo_boilerplate_quartz_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,

View file

@ -48,6 +48,7 @@ _cairo_boilerplate_script_create_surface (const char *name,
void **closure)
{
script_target_closure_t *ptc;
cairo_script_context_t *ctx;
cairo_surface_t *surface;
cairo_status_t status;
@ -59,7 +60,9 @@ _cairo_boilerplate_script_create_surface (const char *name,
xasprintf (&ptc->filename, "%s.out.cs", name);
xunlink (ptc->filename);
surface = cairo_script_surface_create (ptc->filename, width, height);
ctx = cairo_script_context_create (ptc->filename);
surface = cairo_script_surface_create (ctx, content, width, height);
cairo_script_context_destroy (ctx);
status = cairo_surface_set_user_data (surface,
&script_closure_key, ptc, NULL);
@ -126,6 +129,7 @@ _cairo_boilerplate_script_cleanup (void *closure)
static const cairo_boilerplate_target_t target[] = {{
"script", "script", ".cs", NULL,
CAIRO_SURFACE_TYPE_SCRIPT, CAIRO_CONTENT_COLOR_ALPHA, 0,
"cairo_script_surface_create",
_cairo_boilerplate_script_create_surface,
NULL,
_cairo_boilerplate_script_finish_surface,

View file

@ -0,0 +1,52 @@
#include "cairo-boilerplate-private.h"
#include <cairo-skia.h>
static cairo_surface_t *
_cairo_boilerplate_skia_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_format_t format;
*closure = NULL;
if (content == CAIRO_CONTENT_COLOR_ALPHA) {
format = CAIRO_FORMAT_ARGB32;
} else if (content == CAIRO_CONTENT_COLOR) {
format = CAIRO_FORMAT_RGB24;
} else {
return NULL;
}
return cairo_skia_surface_create (format, width, height);
}
static const cairo_boilerplate_target_t targets[] = {
{
"skia", "skia", NULL, NULL,
CAIRO_SURFACE_TYPE_SKIA, CAIRO_CONTENT_COLOR_ALPHA, 0,
"cairo_skia_surface_create",
_cairo_boilerplate_skia_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png
},
{
"skia", "skia", NULL, NULL,
CAIRO_SURFACE_TYPE_SKIA, CAIRO_CONTENT_COLOR, 0,
"cairo_skia_surface_create",
_cairo_boilerplate_skia_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png
},
};
CAIRO_BOILERPLATE (skia, targets)

View file

@ -274,6 +274,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"svg11", "svg", NULL, NULL,
CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA, 1,
"cairo_svg_surface_create",
_cairo_boilerplate_svg11_create_surface,
_cairo_boilerplate_svg_force_fallbacks,
_cairo_boilerplate_svg_finish_surface,
@ -285,6 +286,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"svg11", "svg", NULL, NULL,
CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 1,
"cairo_svg_surface_create",
_cairo_boilerplate_svg11_create_surface,
_cairo_boilerplate_svg_force_fallbacks,
_cairo_boilerplate_svg_finish_surface,
@ -296,6 +298,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"svg12", "svg", NULL, NULL,
CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA, 1,
"cairo_svg_surface_create",
_cairo_boilerplate_svg12_create_surface,
_cairo_boilerplate_svg_force_fallbacks,
_cairo_boilerplate_svg_finish_surface,
@ -307,6 +310,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"svg12", "svg", NULL, NULL,
CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 1,
"cairo_svg_surface_create",
_cairo_boilerplate_svg12_create_surface,
_cairo_boilerplate_svg_force_fallbacks,
_cairo_boilerplate_svg_finish_surface,

View file

@ -233,6 +233,7 @@ static const cairo_boilerplate_target_t targets[] = {
"test-fallback", "image", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
CAIRO_CONTENT_COLOR_ALPHA, 0,
"_cairo_test_fallback_surface_create",
_cairo_boilerplate_test_fallback_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -242,6 +243,7 @@ static const cairo_boilerplate_target_t targets[] = {
"test-fallback", "image", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
CAIRO_CONTENT_COLOR, 0,
"_cairo_test_fallback_surface_create",
_cairo_boilerplate_test_fallback_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -251,6 +253,7 @@ static const cairo_boilerplate_target_t targets[] = {
"test-fallback16", "image", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
CAIRO_CONTENT_COLOR_ALPHA, 0,
"_cairo_test_fallback16_surface_create",
_cairo_boilerplate_test_fallback16_create_surface,
NULL, NULL,
NULL, /* _cairo_boilerplate_get_image_surface, */
@ -260,6 +263,7 @@ static const cairo_boilerplate_target_t targets[] = {
"test-fallback16", "image", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
CAIRO_CONTENT_COLOR, 0,
"_cairo_test_fallback16_surface_create",
_cairo_boilerplate_test_fallback16_create_surface,
NULL, NULL,
NULL, /* _cairo_boilerplate_get_image_surface, */
@ -270,6 +274,7 @@ static const cairo_boilerplate_target_t targets[] = {
"test-paginated", "image", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
CAIRO_CONTENT_COLOR_ALPHA, 0,
"_cairo_test_paginated_surface_create",
_cairo_boilerplate_test_paginated_create_surface,
NULL, NULL,
_cairo_boilerplate_test_paginated_get_image_surface,
@ -282,6 +287,7 @@ static const cairo_boilerplate_target_t targets[] = {
"test-paginated", "image", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
CAIRO_CONTENT_COLOR, 0,
"_cairo_test_paginated_surface_create",
_cairo_boilerplate_test_paginated_create_surface,
NULL, NULL,
_cairo_boilerplate_test_paginated_get_image_surface,
@ -296,6 +302,7 @@ static const cairo_boilerplate_target_t targets[] = {
"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,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -307,6 +314,7 @@ static const cairo_boilerplate_target_t targets[] = {
"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,
NULL, NULL,
NULL, NULL, NULL,

View file

@ -305,6 +305,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"vg-glx", "vg", NULL, NULL,
CAIRO_SURFACE_TYPE_VG, CAIRO_CONTENT_COLOR_ALPHA, 1,
"cairo_vg_context_create_for_glx",
_cairo_boilerplate_vg_create_surface_glx,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -315,6 +316,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"vg-glx", "vg", NULL, NULL,
CAIRO_SURFACE_TYPE_VG, CAIRO_CONTENT_COLOR, 1,
"cairo_vg_context_create_for_glx",
_cairo_boilerplate_vg_create_surface_glx,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -327,6 +329,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"vg-egl", "vg", NULL, NULL,
CAIRO_SURFACE_TYPE_VG, CAIRO_CONTENT_COLOR_ALPHA, 1,
"cairo_vg_context_create_for_egl",
_cairo_boilerplate_vg_create_surface_egl,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -337,6 +340,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"vg-egl", "vg", NULL, NULL,
CAIRO_SURFACE_TYPE_VG, CAIRO_CONTENT_COLOR, 1,
"cairo_vg_context_create_for_egl",
_cairo_boilerplate_vg_create_surface_egl,
NULL, NULL,
_cairo_boilerplate_get_image_surface,

View file

@ -347,6 +347,7 @@ static const cairo_boilerplate_target_t targets[] = {
"win32-printing", "win32", ".ps", NULL,
CAIRO_SURFACE_TYPE_WIN32_PRINTING,
CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
"cairo_win32_printing_surface_create",
_cairo_boilerplate_win32_printing_create_surface,
NULL, NULL,
_cairo_boilerplate_win32_printing_get_image_surface,
@ -357,6 +358,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"win32-printing", "win32", ".ps", NULL,
CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
"cairo_win32_printing_surface_create",
_cairo_boilerplate_win32_printing_create_surface,
NULL, NULL,
_cairo_boilerplate_win32_printing_get_image_surface,

View file

@ -52,6 +52,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"win32", "win32", NULL, NULL,
CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR, 0,
"cairo_win32_surface_create_with_dib",
_cairo_boilerplate_win32_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -63,6 +64,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"win32", "win32", NULL, NULL,
CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR_ALPHA, 0,
"cairo_win32_surface_create_with_dib",
_cairo_boilerplate_win32_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,

View file

@ -119,6 +119,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"xcb", "xcb", NULL, NULL,
CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1,
"cairo_xcb_surface_create_with_xrender_format",
_cairo_boilerplate_xcb_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,

View file

@ -439,6 +439,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"xlib", "xlib", NULL, "xlib-reference",
CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR_ALPHA, 1,
"cairo_xlib_surface_create_with_xrender_format",
_cairo_boilerplate_xlib_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -449,6 +450,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"xlib", "xlib", NULL, "xlib-reference",
CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
"cairo_xlib_surface_create_with_xrender_format",
_cairo_boilerplate_xlib_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -459,6 +461,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"xlib-reference", "xlib", NULL, NULL,
CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
"cairo_xlib_surface_create",
_cairo_boilerplate_xlib_reference_create_surface,
NULL, NULL,
NULL, /* get_image */
@ -473,6 +476,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"xlib-fallback", "xlib", NULL, NULL,
CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
"cairo_xlib_surface_create",
_cairo_boilerplate_xlib_fallback_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,

View file

@ -45,6 +45,10 @@
#include <assert.h>
#include <errno.h>
#if HAVE_DL
#include <dlfcn.h>
#endif
#if HAVE_UNISTD_H && HAVE_FCNTL_H && HAVE_SIGNAL_H && HAVE_SYS_STAT_H && HAVE_SYS_SOCKET_H && HAVE_SYS_UN_H
#include <unistd.h>
#include <fcntl.h>
@ -151,17 +155,6 @@ _cairo_boilerplate_meta_create_surface (const char *name,
extents.height = height;
return cairo_meta_surface_create (content, &extents);
}
#if CAIRO_HAS_SCRIPT_SURFACE
static cairo_status_t
stdio_write (void *closure, const unsigned char *data, unsigned int len)
{
if (fwrite (data, len, 1, closure) != 1)
return CAIRO_STATUS_WRITE_ERROR;
return CAIRO_STATUS_SUCCESS;
}
#endif
#endif
const cairo_user_data_key_t cairo_boilerplate_output_basename_key;
@ -172,7 +165,6 @@ _cairo_boilerplate_get_image_surface (cairo_surface_t *src,
int width,
int height)
{
FILE *file = NULL;
cairo_surface_t *surface, *image;
cairo_t *cr;
cairo_status_t status;
@ -195,17 +187,14 @@ _cairo_boilerplate_get_image_surface (cairo_surface_t *src,
test_name = cairo_surface_get_user_data (src,
&cairo_boilerplate_output_basename_key);
if (test_name != NULL) {
cairo_script_context_t *ctx;
char *filename;
xasprintf (&filename, "%s.out.trace", test_name);
file = fopen (filename, "w");
ctx = cairo_script_context_create (filename);
surface = cairo_script_surface_create_for_target (ctx, image);
cairo_script_context_destroy (ctx);
free (filename);
if (file != NULL) {
surface = cairo_script_surface_create_for_target (image,
stdio_write,
file);
}
}
}
#endif
@ -224,9 +213,6 @@ _cairo_boilerplate_get_image_surface (cairo_surface_t *src,
}
cairo_destroy (cr);
if (file != NULL)
fclose (file);
return image;
}
@ -296,7 +282,7 @@ static const cairo_boilerplate_target_t builtin_targets[] = {
{
"image", "image", NULL, NULL,
CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR_ALPHA, 0,
_cairo_boilerplate_image_create_surface,
NULL, _cairo_boilerplate_image_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png
@ -304,7 +290,7 @@ static const cairo_boilerplate_target_t builtin_targets[] = {
{
"image", "image", NULL, NULL,
CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR, 0,
_cairo_boilerplate_image_create_surface,
NULL, _cairo_boilerplate_image_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png
@ -313,6 +299,7 @@ static const cairo_boilerplate_target_t builtin_targets[] = {
{
"meta", "image", NULL, NULL,
CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR_ALPHA, 0,
"cairo_meta_surface_create",
_cairo_boilerplate_meta_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -323,6 +310,7 @@ static const cairo_boilerplate_target_t builtin_targets[] = {
{
"meta", "image", NULL, NULL,
CAIRO_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
"cairo_meta_surface_create",
_cairo_boilerplate_meta_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@ -339,6 +327,19 @@ static struct cairo_boilerplate_target_list {
const cairo_boilerplate_target_t *target;
} *cairo_boilerplate_targets;
static cairo_bool_t
probe_target (const cairo_boilerplate_target_t *target)
{
if (target->probe == NULL)
return TRUE;
#if HAVE_DL
return dlsym (NULL, target->probe) != NULL;
#else
return TRUE;
#endif
}
void
_cairo_boilerplate_register_backend (const cairo_boilerplate_target_t *targets,
unsigned int count)
@ -347,9 +348,13 @@ _cairo_boilerplate_register_backend (const cairo_boilerplate_target_t *targets,
while (count--) {
struct cairo_boilerplate_target_list *list;
--targets;
if (! probe_target (targets))
continue;
list = xmalloc (sizeof (*list));
list->next = cairo_boilerplate_targets;
list->target = --targets;
list->target = targets;
cairo_boilerplate_targets = list;
}
}

View file

@ -157,6 +157,7 @@ typedef struct _cairo_boilerplate_target {
cairo_surface_type_t expected_type;
cairo_content_t content;
unsigned int error_tolerance;
const char *probe; /* runtime dl check */
cairo_boilerplate_create_surface_t create_surface;
cairo_boilerplate_force_fallbacks_t force_fallbacks;
cairo_boilerplate_finish_surface_t finish_surface;

View file

@ -9,6 +9,7 @@ CAIRO_HAS_QUARTZ_FONT=0
CAIRO_HAS_QUARTZ_IMAGE_SURFACE=0
CAIRO_HAS_WIN32_SURFACE=1
CAIRO_HAS_WIN32_FONT=1
CAIRO_HAS_SKIA_SURFACE=0
CAIRO_HAS_OS2_SURFACE=0
CAIRO_HAS_BEOS_SURFACE=0
CAIRO_HAS_DRM_SURFACE=0
@ -28,3 +29,4 @@ CAIRO_HAS_PS_SURFACE=1
CAIRO_HAS_PDF_SURFACE=1
CAIRO_HAS_SVG_SURFACE=1
CAIRO_HAS_TEST_SURFACES=0
CAIRO_HAS_XML_SURFACE=1

View file

@ -32,6 +32,9 @@ endif
ifeq ($(CAIRO_HAS_WIN32_FONT),1)
@echo "#define CAIRO_HAS_WIN32_FONT 1" >> src/cairo-features.h
endif
ifeq ($(CAIRO_HAS_SKIA_SURFACE),1)
@echo "#define CAIRO_HAS_SKIA_SURFACE 1" >> src/cairo-features.h
endif
ifeq ($(CAIRO_HAS_OS2_SURFACE),1)
@echo "#define CAIRO_HAS_OS2_SURFACE 1" >> src/cairo-features.h
endif
@ -91,5 +94,9 @@ ifeq ($(CAIRO_HAS_TEST_SURFACES),1)
endif
@echo "#define CAIRO_HAS_IMAGE_SURFACE 1" >> src/cairo-features.h
@echo "#define CAIRO_HAS_META_SURFACE 1" >> src/cairo-features.h
@echo "#define CAIRO_HAS_TEE_SURFACE 1" >> src/cairo-features.h
ifeq ($(CAIRO_HAS_XML_SURFACE),1)
@echo "#define CAIRO_HAS_XML_SURFACE 1" >> src/cairo-features.h
endif
@echo "#define CAIRO_HAS_USER_FONT 1" >> src/cairo-features.h
@echo "#endif" >> src/cairo-features.h

View file

@ -358,6 +358,9 @@ AC_DEFUN([CAIRO_REPORT],
echo "The following surface backends:"
echo " Image: yes (always builtin)"
echo " Meta: yes (always builtin)"
echo " Tee: yes (always builtin)"
echo " XML: $use_xml"
echo " Skia: $use_skia"
echo " Xlib: $use_xlib"
echo " Xlib Xrender: $use_xlib_xrender"
echo " Qt: $use_qt"

View file

@ -5,13 +5,17 @@ dnl skipped and all flags rechecked. So there's no need to do anything
dnl else. If for any reason you need to force a recheck, just change
dnl MAYBE_WARN in an ignorable way (like adding whitespace)
# -Wcast-align generates lots of false positive reports we need to
# cast image data from uint8_t to uin32_t.
MAYBE_WARN="-Wall -Wextra \
-Wsign-compare -Werror-implicit-function-declaration \
-Wpointer-arith -Wwrite-strings -Wstrict-prototypes \
-Wmissing-prototypes -Wmissing-declarations -Wnested-externs \
-Wold-style-definition \
-Wmissing-declarations -Werror-implicit-function-declaration \
-Wnested-externs -Wpointer-arith -Wwrite-strings \
-Wsign-compare -Wstrict-prototpes -Wmissig-prototyess \
-Wpacked -Wswitch-enum -Wmissing-format-attribute \
-Wbad-function-cast -Wvolatile-register-var \
-Wstrict-aliasing=2 -Winit-self -Wunsafe-loop-optimizations \
-Wdeclaration-after-statement -Wold-style-definition \
-Wno-missing-field-initializers -Wno-unused-parameter \
-Wno-attributes -Wno-long-long -Winline"

View file

@ -36,6 +36,13 @@ AC_CHECK_LIB(z, compress,
[have_libz="no (requires zlib http://www.gzip.org/zlib/)"])],
[have_libz="no (requires zlib http://www.gzip.org/zlib/)"])
AC_CHECK_LIB(dl, dlsym,
[AC_CHECK_HEADER(dlfcn.h, [
have_dl=yes
AC_DEFINE(HAVE_DL, 1, [Define to 1 if you have dl available]),
], [have_dl=no])], [have_dl=no])
AM_CONDITIONAL(CAIRO_HAS_DL, test "x$have_dl" = "xyes")
dnl ===========================================================================
CAIRO_ENABLE_SURFACE_BACKEND(xlib, Xlib, auto, [
@ -142,6 +149,19 @@ AM_CONDITIONAL(CAIRO_CAN_TEST_WIN32_PRINTING_SURFACE, test "x$test_win32_printin
dnl ===========================================================================
CAIRO_ENABLE_SURFACE_BACKEND(skia, Skia, no, [
AC_ARG_WITH([skia],
[AS_HELP_STRING([--with-skia=/path/to/skia],
[directory to find compiled skia sources])],
[skia_DIR="$withval"],
[skia_DIR="`pwd`/../mesa"])
skia_NONPKGCONFIG_CFLAGS="-I$skia_DIR/include/config -I$skia_DIR/include/core -I$skia_DIR/include/effects"
skia_NONPKGCONFIG_LIBS="$skia_DIR/out/libskia.a"
AC_SUBST(skia_DIR)
])
dnl ===========================================================================
CAIRO_ENABLE_SURFACE_BACKEND(os2, OS/2, no, [
case "$host" in
*-*-os2*)
@ -313,14 +333,22 @@ CAIRO_ENABLE_FUNCTIONS(egl, EGL, auto, [
if test "x$use_egl" = "xyes"; then
egl_NONPKGCONFIG_CFLAGS=
egl_NONPKGCONFIG_LIBS=
for lib in EGL egl13 egl12 egl11; do
save_LIBS="$LIBS"
other_egl_LIBS=""
# Temporary workaround for missing link from egl13
AC_CHECK_LIB(csi, csi_stream_attachresource, other_egl_LIBS="-lcsi")
LIBS="$other_egl_LIBS $LIBS"
for egl_lib in EGL egl13 egl12 egl11; do
if test -z "$egl_NONPKGCONFIG_LIBS"; then
AC_CHECK_LIB($lib, eglGetError, egl_NONPKGCONFIG_LIBS="-l$lib")
AC_CHECK_LIB($egl_lib, eglGetError, egl_NONPKGCONFIG_LIBS="-l$egl_lib")
fi
done
if test -z "$egl_NONPKGCONFIG_LIBS"; then
use_egl="no (EGL library not found)"
else
egl_NONPKGCONFIG_LIBS="$egl_NONPKGCONFIG_LIBS $other_egl_LIBS"
fi
LIBS="$save_LIBS"
fi
else
use_egl="no (not required by any backend)"
@ -570,6 +598,11 @@ CAIRO_ENABLE_SURFACE_BACKEND(image, image, always, [
dnl ===========================================================================
CAIRO_ENABLE_SURFACE_BACKEND(meta, meta, always)
CAIRO_ENABLE_SURFACE_BACKEND(tee, tee, always)
CAIRO_ENABLE_SURFACE_BACKEND(xml, xml, yes, [
use_xml=$have_libz
xml_NONPKGCONFIG_LIBS=-lz
])
dnl ===========================================================================
@ -615,6 +648,8 @@ AM_CONDITIONAL(BUILD_TRACE,
test "x$have_ld_preload" = "xyes" \
-a "x$have_libz" = "xyes")
AM_CONDITIONAL(BUILD_SCRIPT, test "x$have_libz" = "xyes")
AC_CHECK_LIB(bfd, bfd_openr,
[AC_CHECK_HEADER(bfd.h, [have_bfd=yes],
[have_bfd=no])], [have_bfd=no])
@ -625,6 +660,11 @@ if test "x$have_bfd" = "xyes"; then
AC_SUBST(BFD_LIBS)
fi
PKG_CHECK_MODULES(glib, glib-2.0, have_glib=yes, have_glib=no)
AC_SUBST(glib_CFLAGS)
AC_SUBST(glib_LIBS)
AM_CONDITIONAL(BUILD_SPHINX, test "x$have_glib" = "xyes")
dnl ===========================================================================
AC_ARG_ENABLE(some-floating-point,
@ -666,8 +706,10 @@ test/Makefile
test/pdiff/Makefile
perf/Makefile
util/Makefile
util/cairo-fdr/Makefile
util/cairo-script/Makefile
util/cairo-script/examples/Makefile
util/cairo-sphinx/Makefile
util/cairo-trace/Makefile
util/cairo-trace/cairo-trace
doc/Makefile

View file

@ -14,6 +14,7 @@ EXTRA_PROGRAMS += cairo-perf \
cairo-perf-trace \
cairo-perf-diff-files \
cairo-perf-print \
cairo-perf-chart \
cairo-perf-compare-backends \
cairo-perf-graph-files
EXTRA_DIST += cairo-perf-diff COPYING
@ -103,6 +104,9 @@ cairo_perf_diff_files_SOURCES = \
cairo_perf_print_SOURCES = \
cairo-perf-print.c
cairo_perf_chart_SOURCES = \
cairo-perf-chart.c
cairo_perf_compare_backends_SOURCES = \
cairo-perf-compare-backends.c

View file

@ -94,7 +94,7 @@ box_outline_fill (cairo_t *cr, int width, int height, int loops)
void
box_outline (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "box-outline"))
if (! cairo_perf_can_run (perf, "box-outline", NULL))
return;
cairo_perf_run (perf, "box-outline-stroke", box_outline_stroke);

751
perf/cairo-perf-chart.c Normal file
View file

@ -0,0 +1,751 @@
/*
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2009 Chris Wilson
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of the
* copyright holders not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*
* Authors: Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairo-perf.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <math.h>
#include <assert.h>
struct chart {
cairo_perf_report_t *reports;
const char **names;
cairo_t *cr;
int width, height;
int num_tests, num_reports;
double min_value, max_value;
cairo_bool_t use_html;
cairo_bool_t relative;
};
struct color {
double red, green, blue;
};
#define FONT_SIZE 12
#define PAD (FONT_SIZE/2+1)
#define MAX(a,b) ((a) > (b) ? (a) : (b))
static double
to_factor (double x)
{
#if 1
if (x > 1.)
return (x-1) * 100.;
else
return (1. - 1./x) * 100.;
#else
return log (x);
#endif
}
static void
find_ranges (struct chart *chart)
{
test_report_t **tests, *min_test;
double min = 0, max = 0;
double test_time;
int seen_non_null;
int num_tests = 0;
int i;
tests = xmalloc (chart->num_reports * sizeof (test_report_t *));
for (i = 0; i < chart->num_reports; i++)
tests[i] = chart->reports[i].tests;
while (1) {
/* We expect iterations values of 0 when multiple raw reports
* for the same test have been condensed into the stats of the
* first. So we just skip these later reports that have no
* stats. */
seen_non_null = 0;
for (i = 0; i < chart->num_reports; i++) {
while (tests[i]->name && tests[i]->stats.iterations == 0)
tests[i]++;
if (tests[i]->name)
seen_non_null++;
}
if (! seen_non_null)
break;
num_tests++;
/* Find the minimum of all current tests, (we have to do this
* in case some reports don't have a particular test). */
for (i = 0; i < chart->num_reports; i++) {
if (tests[i]->name) {
min_test = tests[i];
break;
}
}
for (++i; i < chart->num_reports; i++) {
if (tests[i]->name && test_report_cmp_name (tests[i], min_test) < 0)
min_test = tests[i];
}
test_time = 0;
for (i = 0; i < chart->num_reports; i++) {
double report_time = HUGE_VAL;
while (tests[i]->name &&
test_report_cmp_name (tests[i], min_test) == 0)
{
double time = tests[i]->stats.min_ticks;
if (time < report_time) {
time /= tests[i]->stats.ticks_per_ms;
if (time < report_time)
report_time = time;
}
tests[i]++;
}
if (report_time != HUGE_VAL) {
if (test_time == 0)
test_time = report_time;
if (chart->relative) {
double v;
v = to_factor (test_time / report_time);
if (v < min)
min = v;
if (v > max)
max = v;
} else {
if (report_time < min)
min = report_time;
if (report_time > max)
max = report_time;
}
}
}
}
free (tests);
chart->min_value = min;
chart->max_value = max;
chart->num_tests = num_tests;
}
#define SET_COLOR(C, R, G, B) (C)->red = (R), (C)->green = (G), (C)->blue = (B)
static void
hsv_to_rgb (double h, double s, double v, struct color *color)
{
double m, n, f;
int i;
while (h < 0)
h += 6.;
while (h > 6.)
h -= 6.;
if (s < 0.)
s = 0.;
if (s > 1.)
s = 1.;
if (v < 0.)
v = 0.;
if (v > 1.)
v = 1.;
i = floor (h);
f = h - i;
if ((i & 1) == 0)
f = 1 - f;
m = v * (1 - s);
n = v * (1 - s * f);
switch(i){
default:
case 6:
case 0: SET_COLOR (color, v, n, m); break;
case 1: SET_COLOR (color, n, v, m); break;
case 2: SET_COLOR (color, m, v, n); break;
case 3: SET_COLOR (color, m, n, v); break;
case 4: SET_COLOR (color, n, m, v); break;
case 5: SET_COLOR (color, v, m, n); break;
}
}
static void set_report_color (struct chart *chart, int report)
{
struct color color;
hsv_to_rgb (6. / chart->num_reports * report, .7, .7, &color);
cairo_set_source_rgb (chart->cr, color.red, color.green, color.blue);
}
static void
test_background (struct chart *c, int test)
{
double dx, x;
dx = c->width / (double) c->num_tests;
x = dx * test;
if (test & 1)
cairo_set_source_rgba (c->cr, .2, .2, .2, .2);
else
cairo_set_source_rgba (c->cr, .8, .8, .8, .2);
cairo_rectangle (c->cr, floor (x), 0,
floor (dx + x) - floor (x), c->height);
cairo_fill (c->cr);
}
static void
add_chart (struct chart *c, int test, int report, double value)
{
double dx, dy, x;
if (fabs (value) < 0.1)
return;
set_report_color (c, report);
if (c->relative) {
dy = (c->height/2. - PAD) / MAX (-c->min_value, c->max_value);
/* the first report is always skipped, as it is used as the baseline */
dx = c->width / (double) (c->num_tests * c->num_reports);
x = dx * (c->num_reports * test + report - .5);
cairo_rectangle (c->cr,
floor (x), c->height / 2.,
floor (x + dx) - floor (x),
ceil (-dy*value - c->height/2.) + c->height/2.);
} else {
dy = (c->height - PAD) / c->max_value;
dx = c->width / (double) (c->num_tests * (c->num_reports+1));
x = dx * ((c->num_reports+1) * test + report + .5);
cairo_rectangle (c->cr,
floor (x), c->height,
floor (x + dx) - floor (x),
floor (c->height - dy*value) - c->height);
}
cairo_fill (c->cr);
}
static void
add_label (struct chart *c, int test, const char *label)
{
cairo_text_extents_t extents;
double dx, x;
cairo_save (c->cr);
dx = c->width / (double) c->num_tests;
if (dx / 2 - PAD < 6)
return;
cairo_set_font_size (c->cr, dx / 2 - PAD);
cairo_text_extents (c->cr, label, &extents);
x = (test + .5) * dx;
cairo_translate (c->cr, x, PAD / 2 - (extents.height / 2. + extents.y_bearing));
cairo_rotate (c->cr, -M_PI/2);
cairo_translate (c->cr, -extents.width, 0);
cairo_set_source_rgba (c->cr, 1, 1, 1, .5);
cairo_move_to (c->cr, 0, 0);
cairo_show_text (c->cr, label);
cairo_restore (c->cr);
}
static void
add_base_line (struct chart *c)
{
double y;
cairo_save (c->cr);
cairo_set_line_width (c->cr, 2.);
if (c->relative) {
y = c->height / 2.;
} else {
y = c->height;
}
cairo_move_to (c->cr, 0, y);
cairo_line_to (c->cr, c->width, y);
cairo_set_source_rgb (c->cr, 1, 1, 1);
cairo_stroke (c->cr);
cairo_restore (c->cr);
}
static void
add_absolute_lines (struct chart *c)
{
const double dashes[] = { 2, 4 };
const double vlog_steps[] = { 10, 5, 4, 3, 2, 1, .5, .4, .3, .2, .1};
double v, y, dy;
unsigned int i;
char buf[80];
cairo_text_extents_t extents;
v = c->max_value / 2.;
for (i = 0; i < sizeof (vlog_steps) / sizeof (vlog_steps[0]); i++) {
double vlog = log (v) / log (vlog_steps[i]);
if (vlog > 1) {
v = pow (vlog_steps[i], floor (vlog));
goto done;
}
}
return;
done:
dy = (c->height - PAD) / c->max_value;
cairo_save (c->cr);
cairo_set_line_width (c->cr, 1.);
cairo_set_dash (c->cr, dashes, sizeof (dashes) / sizeof (dashes[0]), 0);
i = 0;
do {
y = c->height - ++i * v * dy;
if (y < PAD)
break;
cairo_set_source_rgba (c->cr, .95, .95, .95, .5);
cairo_move_to (c->cr, 0, floor (y) + .5);
cairo_line_to (c->cr, c->width, floor (y) + .5);
cairo_stroke (c->cr);
cairo_set_font_size (c->cr, 8);
cairo_set_source_rgba (c->cr, 0, .75, 0, .95);
sprintf (buf, "%.0fs", i*v/1000);
cairo_text_extents (c->cr, buf, &extents);
cairo_move_to (c->cr, -extents.x_bearing, floor (y) - (extents.height/2 + extents.y_bearing) + .5);
cairo_show_text (c->cr, buf);
cairo_move_to (c->cr, c->width-extents.width+extents.x_bearing, floor (y) - (extents.height/2 + extents.y_bearing) + .5);
cairo_show_text (c->cr, buf);
} while (1);
cairo_restore (c->cr);
}
static void
add_relative_lines (struct chart *c)
{
const double dashes[] = { 2, 4 };
const double vlog_steps[] = { 10, 5, 4, 3, 2, 1, .5, .4, .3, .2, .1};
double v, y, dy, mid;
unsigned int i;
char buf[80];
cairo_text_extents_t extents;
v = MAX (-c->min_value, c->max_value) / 2.;
for (i = 0; i < sizeof (vlog_steps) / sizeof (vlog_steps[0]); i++) {
double vlog = log (v) / log (vlog_steps[i]);
if (vlog > 1) {
v = pow (vlog_steps[i], floor (vlog));
goto done;
}
}
return;
done:
mid = c->height/2.;
dy = (mid - PAD) / MAX (-c->min_value, c->max_value);
cairo_save (c->cr);
cairo_set_line_width (c->cr, 1.);
cairo_set_dash (c->cr, dashes, sizeof (dashes) / sizeof (dashes[0]), 0);
i = 0;
do {
y = ++i * v * dy;
if (y > mid)
break;
cairo_set_source_rgba (c->cr, .95, .95, .95, .5);
cairo_move_to (c->cr, 0, floor (mid + y) + .5);
cairo_line_to (c->cr, c->width, floor (mid + y) + .5);
cairo_move_to (c->cr, 0, ceil (mid - y) + .5);
cairo_line_to (c->cr, c->width, ceil (mid - y) + .5);
cairo_stroke (c->cr);
cairo_set_font_size (c->cr, 8);
cairo_set_source_rgba (c->cr, .75, 0, 0, .95);
sprintf (buf, "%.0fx", i*v/100 + 1);
cairo_text_extents (c->cr, buf, &extents);
cairo_move_to (c->cr, -extents.x_bearing, floor (mid + y) - (extents.height/2 + extents.y_bearing)+ .5);
cairo_show_text (c->cr, buf);
cairo_move_to (c->cr, c->width-extents.width+extents.x_bearing, floor (mid + y) - (extents.height/2 + extents.y_bearing)+ .5);
cairo_show_text (c->cr, buf);
cairo_set_source_rgba (c->cr, 0, .75, 0, .95);
cairo_move_to (c->cr, -extents.x_bearing, ceil (mid - y) - (extents.height/2 + extents.y_bearing)+ .5);
cairo_show_text (c->cr, buf);
cairo_move_to (c->cr, c->width-extents.width+extents.x_bearing, ceil (mid - y) - (extents.height/2 + extents.y_bearing)+ .5);
cairo_show_text (c->cr, buf);
} while (1);
cairo_restore (c->cr);
}
static void
add_slower_faster_guide (struct chart *c)
{
cairo_text_extents_t extents;
cairo_save (c->cr);
cairo_set_font_size (c->cr, 3 * FONT_SIZE / 2);
cairo_text_extents (c->cr, "FASTER", &extents);
cairo_set_source_rgba (c->cr, 0, .75, 0, .5);
cairo_move_to (c->cr,
c->width/4. - extents.width/2. + extents.x_bearing,
1 - extents.y_bearing);
cairo_show_text (c->cr, "FASTER");
cairo_move_to (c->cr,
3*c->width/4. - extents.width/2. + extents.x_bearing,
1 - extents.y_bearing);
cairo_show_text (c->cr, "FASTER");
cairo_text_extents (c->cr, "SLOWER", &extents);
cairo_set_source_rgba (c->cr, .75, 0, 0, .5);
cairo_move_to (c->cr,
c->width/4. - extents.width/2. + extents.x_bearing,
c->height - 1);
cairo_show_text (c->cr, "SLOWER");
cairo_move_to (c->cr,
3*c->width/4. - extents.width/2. + extents.x_bearing,
c->height - 1);
cairo_show_text (c->cr, "SLOWER");
cairo_restore (c->cr);
}
static void
cairo_perf_reports_compare (struct chart *chart, cairo_bool_t print)
{
test_report_t **tests, *min_test;
double test_time, best_time;
int num_test = 0;
int seen_non_null;
int i;
tests = xmalloc (chart->num_reports * sizeof (test_report_t *));
for (i = 0; i < chart->num_reports; i++)
tests[i] = chart->reports[i].tests;
if (print) {
if (chart->use_html) {
printf ("<table style=\"text-align:right\" cellspacing=\"4\">\n");
printf ("<tr><td></td>");
for (i = 0; i < chart->num_reports; i++) {
printf ("<td>%s</td>", chart->names[i] ? chart->names[i] : "");
}
printf ("</tr>\n");
}
}
while (1) {
/* We expect iterations values of 0 when multiple raw reports
* for the same test have been condensed into the stats of the
* first. So we just skip these later reports that have no
* stats. */
seen_non_null = 0;
for (i = 0; i < chart->num_reports; i++) {
while (tests[i]->name && tests[i]->stats.iterations == 0)
tests[i]++;
if (tests[i]->name)
seen_non_null++;
}
if (! seen_non_null)
break;
/* Find the minimum of all current tests, (we have to do this
* in case some reports don't have a particular test). */
for (i = 0; i < chart->num_reports; i++) {
if (tests[i]->name) {
min_test = tests[i];
break;
}
}
for (++i; i < chart->num_reports; i++) {
if (tests[i]->name && test_report_cmp_name (tests[i], min_test) < 0)
min_test = tests[i];
}
add_label (chart, num_test, min_test->name);
if (print) {
if (chart->use_html) {
printf ("<tr><td>%s</td>", min_test->name);
} else {
if (min_test->size) {
printf ("%16s, size %4d:\n",
min_test->name,
min_test->size);
} else {
printf ("%26s:",
min_test->name);
}
}
}
test_time = 0;
best_time = HUGE_VAL;
for (i = 0; i < chart->num_reports; i++) {
test_report_t *initial = tests[i];
double report_time = HUGE_VAL;
while (tests[i]->name &&
test_report_cmp_name (tests[i], min_test) == 0)
{
double time = tests[i]->stats.min_ticks;
if (time < report_time) {
time /= tests[i]->stats.ticks_per_ms;
if (time < report_time)
report_time = time;
}
tests[i]++;
}
if (test_time == 0 && report_time != HUGE_VAL)
test_time = report_time;
if (report_time < best_time)
best_time = report_time;
tests[i] = initial;
}
for (i = 0; i < chart->num_reports; i++) {
double report_time = HUGE_VAL;
while (tests[i]->name &&
test_report_cmp_name (tests[i], min_test) == 0)
{
double time = tests[i]->stats.min_ticks;
if (time > 0) {
time /= tests[i]->stats.ticks_per_ms;
if (time < report_time)
report_time = time;
}
tests[i]++;
}
if (print) {
if (chart->use_html) {
if (report_time < HUGE_VAL) {
if (report_time / best_time < 1.01) {
printf ("<td><strong>%.1f</strong></td>", report_time/1000);
} else {
printf ("<td>%.1f</td>", report_time/1000);
}
} else {
printf ("<td></td>");
}
} else {
if (report_time < HUGE_VAL)
printf (" %6.1f", report_time/1000);
else
printf (" ---");
}
}
if (report_time < HUGE_VAL) {
if (chart->relative) {
add_chart (chart, num_test, i,
to_factor (test_time / report_time));
} else {
add_chart (chart, num_test, i, report_time/1000);
}
}
}
if (print) {
if (chart->use_html) {
printf ("</tr>\n");
} else {
printf ("\n");
}
}
num_test++;
}
free (tests);
if (print) {
if (chart->use_html)
printf ("</table>\n");
printf ("\n");
for (i = 0; i < chart->num_reports; i++) {
if (chart->names[i]) {
printf ("[%s] %s\n",
chart->names[i], chart->reports[i].configuration);
} else {
printf ("[%d] %s\n",
i, chart->reports[i].configuration);
}
}
}
}
static void
add_legend (struct chart *chart)
{
cairo_text_extents_t extents;
const char *str;
int i, x, y;
cairo_set_font_size (chart->cr, FONT_SIZE);
x = PAD;
y = chart->height + PAD;
for (i = chart->relative; i < chart->num_reports; i++) {
str = chart->names[i] ?
chart->names[i] : chart->reports[i].configuration;
set_report_color (chart, i);
cairo_rectangle (chart->cr, x, y + 6, 8, 8);
cairo_fill (chart->cr);
cairo_set_source_rgb (chart->cr, 1, 1, 1);
cairo_move_to (chart->cr, x + 10, y + FONT_SIZE + PAD / 2.);
cairo_text_extents (chart->cr, str, &extents);
cairo_show_text (chart->cr, str);
x += 10 + 2 * PAD + ceil (extents.width);
}
if (chart->relative) {
char buf[80];
str = chart->names[0] ?
chart->names[0] : chart->reports[0].configuration;
sprintf (buf, "(relative to %s)", str);
cairo_text_extents (chart->cr, buf, &extents);
cairo_set_source_rgb (chart->cr, 1, 1, 1);
cairo_move_to (chart->cr,
chart->width - 1 - extents.width,
y + FONT_SIZE + PAD / 2.);
cairo_show_text (chart->cr, buf);
}
}
int
main (int argc, const char *argv[])
{
cairo_surface_t *surface;
struct chart chart;
test_report_t *t;
int i;
chart.use_html = 0;
chart.width = 480;
chart.height = 300;
chart.reports = xcalloc (argc-1, sizeof (cairo_perf_report_t));
chart.names = xcalloc (argc-1, sizeof (cairo_perf_report_t));
chart.num_reports = 0;
for (i = 1; i < argc; i++) {
if (strcmp (argv[i], "--html") == 0) {
chart.use_html = 1;
} else if (strncmp (argv[i], "--width=", 8) == 0) {
chart.width = atoi (argv[i] + 8);
} else if (strncmp (argv[i], "--height=", 9) == 0) {
chart.height = atoi (argv[i] + 9);
} else if (strcmp (argv[i], "--name") == 0) {
if (i + 1 < argc)
chart.names[chart.num_reports] = argv[++i];
} else if (strncmp (argv[i], "--name=", 7) == 0) {
chart.names[chart.num_reports] = argv[i] + 7;
} else {
cairo_perf_report_load (&chart.reports[chart.num_reports++],
argv[i],
test_report_cmp_name);
}
}
for (chart.relative = 0; chart.relative <= 1; chart.relative++) {
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
chart.width,
chart.height + (FONT_SIZE + PAD) + 2*PAD);
chart.cr = cairo_create (surface);
cairo_surface_destroy (surface);
find_ranges (&chart);
for (i = 0; i < chart.num_tests; i++)
test_background (&chart, i);
if (chart.relative) {
add_relative_lines (&chart);
add_slower_faster_guide (&chart);
} else
add_absolute_lines (&chart);
cairo_perf_reports_compare (&chart, !chart.relative);
add_base_line (&chart);
add_legend (&chart);
cairo_surface_write_to_png (cairo_get_target (chart.cr),
chart.relative ?
"cairo-perf-chart-relative.png" :
"cairo-perf-chart-absolute.png");
cairo_destroy (chart.cr);
}
/* Pointless memory cleanup, (would be a great place for talloc) */
for (i = 0; i < chart.num_reports; i++) {
for (t = chart.reports[i].tests; t->name; t++) {
free (t->samples);
free (t->backend);
free (t->name);
}
free (chart.reports[i].tests);
free (chart.reports[i].configuration);
}
free (chart.names);
free (chart.reports);
return 0;
}

View file

@ -223,14 +223,20 @@ run_cairo_perf_if_not_cached() {
git_setup
# Build cairo-perf-diff-files if not available
if [ ! -e $CAIRO_DIR/perf/cairo-perf-diff-files ]; then
echo "Building cairo-perf-diff-files"
if [ "x$OS" = "xWindows_NT" ]; then
make -f Makefile.win32 -C $CAIRO_DIR/perf/ cairo-perf-diff-files CFG=debug
else
make -C $CAIRO_DIR/perf/ cairo-perf-diff-files
fi
if [ -e ./cairo-perf-diff-files ]; then
bindir="."
else
bindir=$CAIRO_DIR/perf
# Build cairo-perf-diff-files if not available
if [ ! -e $bindir/cairo-perf-diff-files ]; then
echo "Building cairo-perf-diff-files"
if [ "x$OS" = "xWindows_NT" ]; then
make -f Makefile.win32 -C $bindir cairo-perf-diff-files CFG=debug
else
make -C $bindir cairo-perf-diff-files
fi
fi
fi
if [ ! -e $old ]; then
@ -244,8 +250,8 @@ if [ ! -e $new ]; then
fi
if [ -z "$html_output" ]; then
$CAIRO_DIR/perf/cairo-perf-diff-files $old $new
$bindir/cairo-perf-diff-files $old $new
else
$CAIRO_DIR/perf/cairo-perf-diff-files $old $new |
$bindir/cairo-perf-diff-files $old $new |
$CAIRO_DIR/perf/make-html.py > $html_output
fi

View file

@ -55,10 +55,6 @@
#include <fontconfig/fontconfig.h>
#endif
#ifdef HAVE_SCHED_H
#include <sched.h>
#endif
#define CAIRO_PERF_ITERATIONS_DEFAULT 15
#define CAIRO_PERF_LOW_STD_DEV 0.05
#define CAIRO_PERF_MIN_STD_DEV_COUNT 3
@ -116,6 +112,9 @@ target_is_measurable (const cairo_boilerplate_target_t *target)
#endif
#if CAIRO_HAS_DRM_SURFACE
case CAIRO_SURFACE_TYPE_DRM:
#endif
#if CAIRO_HAS_SKIA_SURFACE
case CAIRO_SURFACE_TYPE_SKIA:
#endif
return TRUE;
case CAIRO_SURFACE_TYPE_PDF:
@ -128,14 +127,21 @@ target_is_measurable (const cairo_boilerplate_target_t *target)
cairo_bool_t
cairo_perf_can_run (cairo_perf_t *perf,
const char *name)
const char *name,
cairo_bool_t *is_explicit)
{
unsigned int i;
char *copy, *dot;
cairo_bool_t ret;
if (perf->exact_names)
if (is_explicit)
*is_explicit = FALSE;
if (perf->exact_names) {
if (is_explicit)
*is_explicit = TRUE;
return TRUE;
}
if (perf->num_names == 0 && perf->num_exclude_names == 0)
return TRUE;
@ -148,8 +154,11 @@ cairo_perf_can_run (cairo_perf_t *perf,
if (perf->num_names) {
ret = TRUE;
for (i = 0; i < perf->num_names; i++)
if (strstr (copy, perf->names[i]))
if (strstr (copy, perf->names[i])) {
if (is_explicit)
*is_explicit = strcmp (copy, perf->names[i]) == 0;
goto check_exclude;
}
ret = FALSE;
goto done;
@ -159,8 +168,11 @@ check_exclude:
if (perf->num_exclude_names) {
ret = FALSE;
for (i = 0; i < perf->num_exclude_names; i++)
if (strstr (copy, perf->exclude_names[i]))
if (strstr (copy, perf->exclude_names[i])) {
if (is_explicit)
*is_explicit = strcmp (copy, perf->exclude_names[i]) == 0;
goto done;
}
ret = TRUE;
goto done;
@ -319,8 +331,8 @@ execute (cairo_perf_t *perf,
name);
fprintf (perf->summary,
"%#8.3f %#8.3f %#6.2f%% %4d/%d",
stats.min_ticks / (double) cairo_perf_ticks_per_second (),
stats.median_ticks / (double) cairo_perf_ticks_per_second (),
(double) stats.min_ticks / cairo_perf_ticks_per_second (),
(double) stats.median_ticks / cairo_perf_ticks_per_second (),
stats.std_dev * 100.0,
stats.iterations, i+1);
fflush (perf->summary);
@ -339,8 +351,8 @@ execute (cairo_perf_t *perf,
}
fprintf (perf->summary,
"%#8.3f %#8.3f %#6.2f%% %4d/%d\n",
stats.min_ticks / (double) cairo_perf_ticks_per_second (),
stats.median_ticks / (double) cairo_perf_ticks_per_second (),
(double) stats.min_ticks / cairo_perf_ticks_per_second (),
(double) stats.median_ticks / cairo_perf_ticks_per_second (),
stats.std_dev * 100.0,
stats.iterations, i);
fflush (perf->summary);
@ -544,37 +556,6 @@ parse_options (cairo_perf_t *perf, int argc, char *argv[])
}
}
static int
check_cpu_affinity (void)
{
#ifdef HAVE_SCHED_GETAFFINITY
cpu_set_t affinity;
int i, cpu_count;
if (sched_getaffinity (0, sizeof (affinity), &affinity)) {
perror ("sched_getaffinity");
return -1;
}
for (i = 0, cpu_count = 0; i < CPU_SETSIZE; ++i) {
if (CPU_ISSET (i, &affinity))
++cpu_count;
}
if (cpu_count > 1) {
fputs ("WARNING: cairo-perf has not been bound to a single CPU.\n",
stderr);
return -1;
}
return 0;
#else
fputs ("WARNING: Cannot check CPU affinity for this platform.\n",
stderr);
return -1;
#endif
}
static void
cairo_perf_fini (cairo_perf_t *perf)
{
@ -631,6 +612,11 @@ cairo_perf_trace (cairo_perf_t *perf,
if (target->cleanup)
target->cleanup (closure);
cairo_debug_reset_static_data ();
#if HAVE_FCFINI
FcFini ();
#endif
}
static void
@ -653,11 +639,17 @@ cairo_perf_trace_dir (cairo_perf_t *perf,
DIR *dir;
struct dirent *de;
int num_traces = 0;
cairo_bool_t force;
cairo_bool_t is_explicit;
dir = opendir (dirname);
if (dir == NULL)
return 0;
force = FALSE;
if (cairo_perf_can_run (perf, dirname, &is_explicit))
force = is_explicit;
while ((de = readdir (dir)) != NULL) {
char *trace;
struct stat st;
@ -681,7 +673,7 @@ cairo_perf_trace_dir (cairo_perf_t *perf,
goto next;
num_traces++;
if (! cairo_perf_can_run (perf, de->d_name))
if (!force && ! cairo_perf_can_run (perf, de->d_name, NULL))
goto next;
cairo_perf_trace (perf, target, trace);
@ -705,18 +697,6 @@ main (int argc, char *argv[])
parse_options (&perf, argc, argv);
if (! perf.list_only && check_cpu_affinity ()) {
fputs ("NOTICE: cairo-perf and the X server should be bound to CPUs (either the same\n"
"or separate) on SMP systems. Not doing so causes random results when the X\n"
"server is moved to or from cairo-perf's CPU during the benchmarks:\n"
"\n"
" $ sudo taskset -cp 0 $(pidof X)\n"
" $ taskset -cp 1 $$\n"
"\n"
"See taskset(1) for information about changing CPU affinity.\n\n",
stderr);
}
signal (SIGINT, interrupt);
if (getenv ("CAIRO_TRACE_DIR") != NULL)

View file

@ -106,6 +106,9 @@ target_is_measurable (const cairo_boilerplate_target_t *target)
#endif
#if CAIRO_HAS_DRM_SURFACE
case CAIRO_SURFACE_TYPE_DRM:
#endif
#if CAIRO_HAS_SKIA_SURFACE
case CAIRO_SURFACE_TYPE_SKIA:
#endif
return TRUE;
@ -153,16 +156,24 @@ cairo_perf_has_similar (cairo_perf_t *perf)
cairo_bool_t
cairo_perf_can_run (cairo_perf_t *perf,
const char *name)
const char *name,
cairo_bool_t *is_explicit)
{
unsigned int i;
if (is_explicit)
*is_explicit = FALSE;
if (perf->num_names == 0)
return TRUE;
for (i = 0; i < perf->num_names; i++)
if (strstr (name, perf->names[i]))
for (i = 0; i < perf->num_names; i++) {
if (strstr (name, perf->names[i])) {
if (is_explicit)
*is_explicit = FALSE;
return TRUE;
}
}
return FALSE;
}

View file

@ -98,7 +98,8 @@ typedef cairo_perf_ticks_t
cairo_bool_t
cairo_perf_can_run (cairo_perf_t *perf,
const char *name);
const char *name,
cairo_bool_t *is_explicit);
void
cairo_perf_run (cairo_perf_t *perf,

View file

@ -83,7 +83,7 @@ composite_checker (cairo_perf_t *perf,
{
cairo_surface_t *image;
if (! cairo_perf_can_run (perf, "composite-checker"))
if (! cairo_perf_can_run (perf, "composite-checker", NULL))
return;
/* Create the checker pattern. We don't actually need to draw

View file

@ -72,6 +72,7 @@ path (cairo_t *cr, int step, int dir, int iterations)
int i;
switch (dir) {
default:
case 0: dx = step; dy = 0; break;
case 1: dx = -step; dy = 0; break;
case 2: dx = 0; dy = step; break;
@ -202,12 +203,47 @@ do_dragon_solid (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
static cairo_perf_ticks_t
do_dragon_solid_aligned_clip (cairo_t *cr, int width, int height, int loops)
{
cairo_reset_clip (cr);
cairo_rectangle (cr, 10, 10, width/2 + 10, height/2 + 10);
cairo_rectangle (cr, width/2-20, height/2-20, width/2 + 10, height/2 + 10);
cairo_clip (cr);
return do_dragon_solid (cr, width, height, loops);
}
static cairo_perf_ticks_t
do_dragon_solid_unaligned_clip (cairo_t *cr, int width, int height, int loops)
{
cairo_reset_clip (cr);
cairo_rectangle (cr, 10.5, 10.5, width/2 + 10, height/2 + 10);
cairo_rectangle (cr, width/2-20, height/2-20, width/2 + 9.5, height/2 + 9.5);
cairo_clip (cr);
return do_dragon_solid (cr, width, height, loops);
}
static cairo_perf_ticks_t
do_dragon_solid_circle_clip (cairo_t *cr, int width, int height, int loops)
{
cairo_reset_clip (cr);
cairo_arc (cr, width/2., height/2., MIN (width, height)/2. - 10, 0, 2 * M_PI);
cairo_clip (cr);
return do_dragon_solid (cr, width, height, loops);
}
void
dragon (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "dragon"))
if (! cairo_perf_can_run (perf, "dragon", NULL))
return;
cairo_perf_run (perf, "dragon-solid", do_dragon_solid);
cairo_perf_run (perf, "dragon-solid-aligned-clip", do_dragon_solid_aligned_clip);
cairo_perf_run (perf, "dragon-solid-unaligned-clip", do_dragon_solid_unaligned_clip);
cairo_perf_run (perf, "dragon-solid-circle-clip", do_dragon_solid_circle_clip);
cairo_perf_run (perf, "dragon", do_dragon);
}

View file

@ -110,7 +110,7 @@ do_fill_eo_noaa (cairo_t *cr, int width, int height, int loops)
void
fill (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "fill"))
if (! cairo_perf_can_run (perf, "fill", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "fill", do_fill);

View file

@ -92,7 +92,7 @@ out:
void
glyphs (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "glyphs"))
if (! cairo_perf_can_run (perf, "glyphs", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "glyphs", do_glyphs);

View file

@ -61,6 +61,7 @@ draw_random (cairo_t *cr, cairo_fill_rule_t fill_rule,
cairo_set_fill_rule (cr, fill_rule);
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_new_path (cr);
cairo_move_to (cr, 0, 0);
for (i = 0; i < NUM_SEGMENTS; i++)
cairo_line_to (cr, x[i], y[i]);
@ -98,6 +99,7 @@ draw_random_curve (cairo_t *cr, cairo_fill_rule_t fill_rule,
cairo_set_fill_rule (cr, fill_rule);
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_new_path (cr);
cairo_move_to (cr, 0, 0);
for (i = 0; i < NUM_SEGMENTS; i++) {
cairo_curve_to (cr,
@ -144,7 +146,7 @@ random_curve_nz (cairo_t *cr, int width, int height, int loops)
void
intersections (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "intersections"))
if (! cairo_perf_can_run (perf, "intersections", NULL))
return;
cairo_perf_run (perf, "intersections-nz-fill", random_nz);

View file

@ -64,7 +64,7 @@ do_long_dashed_lines (cairo_t *cr, int width, int height, int loops)
void
long_dashed_lines (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "long-dashed-lines"))
if (! cairo_perf_can_run (perf, "long-dashed-lines", NULL))
return;
cairo_perf_run (perf, "long-dashed-lines", do_long_dashed_lines);

View file

@ -135,7 +135,7 @@ long_lines_cropped_once (cairo_t *cr, int width, int height, int loops)
void
long_lines (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "long-lines"))
if (! cairo_perf_can_run (perf, "long-lines", NULL))
return;
cairo_perf_run (perf, "long-lines-uncropped", long_lines_uncropped);

View file

@ -275,7 +275,7 @@ do_mask_radial (cairo_t *cr, int width, int height, int loops)
void
mask (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "mask"))
if (! cairo_perf_can_run (perf, "mask", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "mask-solid",

View file

@ -163,7 +163,7 @@ mosaic_tessellate_curves (cairo_t *cr, int width, int height, int loops)
void
mosaic (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "mosaic"))
if (! cairo_perf_can_run (perf, "mosaic", NULL))
return;
cairo_perf_run (perf, "mosaic-fill-curves", mosaic_fill_curves);

View file

@ -41,7 +41,7 @@ do_paint_with_alpha (cairo_t *cr, int width, int height, int loops)
void
paint_with_alpha (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "paint-with-alpha"))
if (! cairo_perf_can_run (perf, "paint-with-alpha", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "paint-with-alpha",

View file

@ -41,7 +41,7 @@ do_paint (cairo_t *cr, int width, int height, int loops)
void
paint (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "paint"))
if (! cairo_perf_can_run (perf, "paint", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "paint", do_paint);

View file

@ -84,7 +84,7 @@ pattern_create_radial (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
int i;
if (! cairo_perf_can_run (perf, "pattern-create-radial"))
if (! cairo_perf_can_run (perf, "pattern-create-radial", NULL))
return;
srand (time (0));

View file

@ -84,8 +84,8 @@ do_pythagoras_tree (cairo_t *cr, int width, int height, int loops)
void
pythagoras_tree (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "pythagoras-tree"))
if (! cairo_perf_can_run (perf, "pythagoras-tree", NULL))
return;
cairo_perf_run (perf, "pythagoras_tree", do_pythagoras_tree);
cairo_perf_run (perf, "pythagoras-tree", do_pythagoras_tree);
}

View file

@ -100,7 +100,7 @@ rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
int i;
if (! cairo_perf_can_run (perf, "rectangles"))
if (! cairo_perf_can_run (perf, "rectangles", NULL))
return;
srand (8478232);

View file

@ -124,7 +124,7 @@ rounded_rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
int i;
if (! cairo_perf_can_run (perf, "rounded-rectangles"))
if (! cairo_perf_can_run (perf, "rounded-rectangles", NULL))
return;
srand (8478232);

View file

@ -89,6 +89,7 @@ draw_spiral (cairo_t *cr,
cairo_set_fill_rule (cr, fill_rule);
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_new_path (cr);
cairo_move_to (cr, x[0], y[0]);
for (i = 1; i < n; i++) {
cairo_line_to (cr, x[i], y[i]);
@ -105,6 +106,97 @@ draw_spiral (cairo_t *cr,
return cairo_perf_timer_elapsed ();
}
static cairo_perf_ticks_t
draw_spiral_box (cairo_t *cr,
cairo_fill_rule_t fill_rule,
align_t align,
int width, int height, int loops)
{
const int step = 3;
int side = (width < height ? width : height) - 2;
cairo_save (cr);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_paint (cr);
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_set_fill_rule (cr, fill_rule);
cairo_translate (cr, 1, 1);
if (align == NONALIGN)
cairo_translate (cr, 0.1415926, 0.7182818);
cairo_new_path (cr);
while (side >= step) {
cairo_rectangle (cr, 0, 0, side, side);
cairo_translate (cr, step, step);
side -= 2*step;
}
cairo_perf_timer_start ();
while (loops--)
cairo_fill_preserve (cr);
cairo_perf_timer_stop ();
cairo_restore (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_perf_ticks_t
draw_spiral_stroke (cairo_t *cr,
align_t align,
int width, int height, int loops)
{
const int step = 3;
int side = width < height ? width : height;
cairo_save (cr);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_paint (cr);
cairo_translate (cr, 1, 1);
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_set_line_width (cr, 4.);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
cairo_new_path (cr);
switch (align) {
case PIXALIGN: cairo_move_to (cr, 0,0); break;
case NONALIGN: cairo_move_to (cr, 0.1415926, 0.7182818); break;
}
while (side >= step) {
cairo_rel_line_to (cr, 0, side);
side -= step;
if (side <= 0)
break;
cairo_rel_line_to (cr, side, 0);
side -= step;
if (side <= 0)
break;
cairo_rel_line_to (cr, 0, -side);
side -= step;
if (side <= 0)
break;
cairo_rel_line_to (cr, -side, 0);
side -= step;
if (side <= 0)
break;
}
cairo_perf_timer_start ();
while (loops--)
cairo_stroke_preserve (cr);
cairo_perf_timer_stop ();
cairo_restore (cr);
return cairo_perf_timer_elapsed ();
}
static cairo_perf_ticks_t
draw_spiral_eo_pa_re (cairo_t *cr, int width, int height, int loops)
{
@ -185,12 +277,65 @@ draw_spiral_nz_na_di (cairo_t *cr, int width, int height, int loops)
width, height, loops);
}
static cairo_perf_ticks_t
draw_spiral_nz_pa_box (cairo_t *cr, int width, int height, int loops)
{
return draw_spiral_box (cr,
CAIRO_FILL_RULE_WINDING, PIXALIGN,
width, height, loops);
}
static cairo_perf_ticks_t
draw_spiral_nz_na_box (cairo_t *cr, int width, int height, int loops)
{
return draw_spiral_box (cr,
CAIRO_FILL_RULE_WINDING, NONALIGN,
width, height, loops);
}
static cairo_perf_ticks_t
draw_spiral_eo_pa_box (cairo_t *cr, int width, int height, int loops)
{
return draw_spiral_box (cr,
CAIRO_FILL_RULE_EVEN_ODD, PIXALIGN,
width, height, loops);
}
static cairo_perf_ticks_t
draw_spiral_eo_na_box (cairo_t *cr, int width, int height, int loops)
{
return draw_spiral_box (cr,
CAIRO_FILL_RULE_EVEN_ODD, NONALIGN,
width, height, loops);
}
static cairo_perf_ticks_t
draw_spiral_stroke_pa (cairo_t *cr, int width, int height, int loops)
{
return draw_spiral_stroke (cr,
PIXALIGN,
width, height, loops);
}
static cairo_perf_ticks_t
draw_spiral_stroke_na (cairo_t *cr, int width, int height, int loops)
{
return draw_spiral_stroke (cr,
NONALIGN,
width, height, loops);
}
void
spiral (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "spiral"))
if (! cairo_perf_can_run (perf, "spiral", NULL))
return;
cairo_perf_run (perf, "spiral-box-nonalign-evenodd-fill", draw_spiral_eo_na_box);
cairo_perf_run (perf, "spiral-box-nonalign-nonzero-fill", draw_spiral_nz_na_box);
cairo_perf_run (perf, "spiral-box-pixalign-evenodd-fill", draw_spiral_eo_pa_box);
cairo_perf_run (perf, "spiral-box-pixalign-nonzero-fill", draw_spiral_nz_pa_box);
cairo_perf_run (perf, "spiral-diag-nonalign-evenodd-fill", draw_spiral_eo_na_di);
cairo_perf_run (perf, "spiral-diag-nonalign-nonzero-fill", draw_spiral_nz_na_di);
cairo_perf_run (perf, "spiral-diag-pixalign-evenodd-fill", draw_spiral_eo_pa_di);
@ -199,4 +344,6 @@ spiral (cairo_perf_t *perf, cairo_t *cr, int width, int height)
cairo_perf_run (perf, "spiral-rect-nonalign-nonzero-fill", draw_spiral_nz_na_re);
cairo_perf_run (perf, "spiral-rect-pixalign-evenodd-fill", draw_spiral_eo_pa_re);
cairo_perf_run (perf, "spiral-rect-pixalign-nonzero-fill", draw_spiral_nz_pa_re);
cairo_perf_run (perf, "spiral-nonalign-stroke", draw_spiral_stroke_na);
cairo_perf_run (perf, "spiral-pixalign-stroke", draw_spiral_stroke_pa);
}

View file

@ -89,7 +89,7 @@ do_strokes (cairo_t *cr, int width, int height, int loops)
void
stroke (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "stroke"))
if (! cairo_perf_can_run (perf, "stroke", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "stroke", do_stroke);

View file

@ -58,7 +58,7 @@ subimage_copy (cairo_perf_t *perf, cairo_t *cr, int width, int height)
cairo_surface_t *image;
cairo_t *cr2;
if (! cairo_perf_can_run (perf, "subimage-copy"))
if (! cairo_perf_can_run (perf, "subimage-copy", NULL))
return;
cairo_set_source_rgb (cr, 0, 0, 1); /* blue */

View file

@ -144,7 +144,7 @@ tessellate_256 (cairo_t *cr, int width, int height, int loops)
void
tessellate (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "tessellate"))
if (! cairo_perf_can_run (perf, "tessellate", NULL))
return;
cairo_perf_run (perf, "tessellate-16", tessellate_16);

View file

@ -59,7 +59,7 @@ do_text (cairo_t *cr, int width, int height, int loops)
void
text (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "text"))
if (! cairo_perf_can_run (perf, "text", NULL))
return;
cairo_perf_cover_sources_and_operators (perf, "text", do_text);

View file

@ -49,7 +49,7 @@ twin (cairo_perf_t *perf,
int width,
int height)
{
if (! cairo_perf_can_run (perf, "twin"))
if (! cairo_perf_can_run (perf, "twin", NULL))
return;
cairo_perf_run (perf, "twin", do_twin);

View file

@ -34,6 +34,8 @@ do_unaligned_clip (cairo_t *cr, int width, int height, int loops)
cairo_perf_timer_start ();
while (loops--) {
cairo_save (cr);
/* First a triangular clip that obviously isn't along device-pixel
* boundaries. */
cairo_move_to (cr, 50, 50);
@ -51,7 +53,7 @@ do_unaligned_clip (cairo_t *cr, int width, int height, int loops)
/* And paint something to force the clip to be evaluated. */
cairo_paint (cr);
cairo_reset_clip (cr);
cairo_restore (cr);
}
cairo_perf_timer_stop ();
@ -61,7 +63,7 @@ do_unaligned_clip (cairo_t *cr, int width, int height, int loops)
void
unaligned_clip (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "unaligned-clip"))
if (! cairo_perf_can_run (perf, "unaligned-clip", NULL))
return;
cairo_perf_run (perf, "unaligned-clip", do_unaligned_clip);

View file

@ -97,6 +97,8 @@ do_world_map (cairo_t *cr, int width, int height, int loops)
break;
e++;
}
cairo_new_path (cr);
}
cairo_perf_timer_stop ();
@ -107,7 +109,7 @@ do_world_map (cairo_t *cr, int width, int height, int loops)
void
world_map (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "world-map"))
if (! cairo_perf_can_run (perf, "world-map", NULL))
return;
cairo_perf_run (perf, "world-map", do_world_map);

View file

@ -87,7 +87,7 @@ zrusin_another_fill (cairo_t *cr, int width, int height, int loops)
void
zrusin (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
if (! cairo_perf_can_run (perf, "zrusin"))
if (! cairo_perf_can_run (perf, "zrusin", NULL))
return;
cairo_perf_run (perf, "zrusin-another-tessellate", zrusin_another_tessellate);

View file

@ -84,12 +84,9 @@ TESTS += check-link$(EXEEXT)
endif
EXTRA_DIST += $(TESTS_SH) check-has-hidden-symbols.c
check_PROGRAMS += check-link check-skiplist
check_PROGRAMS += check-link
check_link_LDADD = libcairo.la
check_skiplist_SOURCES = cairo-skiplist.c
check_skiplist_CPPFLAGS = -DMAIN $(AM_CPPFLAGS)
check: headers-standalone
PREPROCESS_ARGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS)
@ -99,5 +96,7 @@ COMPILE_ARGS = $(PREPROCESS_ARGS) $(AM_CFLAGS) $(CFLAGS)
# cairo has been compiled with symbol hiding.
.c.i: $(cairoinclude_HEADERS) $(nodist_cairoinclude_HEADERS) cairoint.h $(top_builddir)/config.h
$(CPP) $(PREPROCESS_ARGS) $< -o $@
.c.s: $(cairoinclude_HEADERS) $(nodist_cairoinclude_HEADERS) cairoint.h $(top_builddir)/config.h
$(CC) $(COMPILE_ARGS) $< -S -o $@
include $(srcdir)/Makefile.am.analysis

View file

@ -82,12 +82,13 @@ cairo_private = \
cairo-region-private.h \
cairo-rtree-private.h \
cairo-scaled-font-private.h \
cairo-skiplist-private.h \
cairo-slope-private.h \
cairo-spans-private.h \
cairo-surface-fallback-private.h \
cairo-surface-private.h \
cairo-surface-clipper-private.h \
cairo-surface-wrapper-private.h \
cairo-tee-surface-private.h \
cairo-types-private.h \
cairo-user-font-private.h \
cairo-wideint-private.h \
@ -98,8 +99,11 @@ cairo_sources = \
cairo-arc.c \
cairo-array.c \
cairo-atomic.c \
cairo-base64-stream.c \
cairo-base85-stream.c \
cairo-bentley-ottmann.c \
cairo-bentley-ottmann-rectangular.c \
cairo-bentley-ottmann-rectilinear.c \
cairo.c \
cairo-cache.c \
cairo-clip.c \
@ -136,7 +140,6 @@ cairo_sources = \
cairo-region.c \
cairo-rtree.c \
cairo-scaled-font.c \
cairo-skiplist.c \
cairo-slope.c \
cairo-spans.c \
cairo-spline.c \
@ -145,10 +148,11 @@ cairo_sources = \
cairo-surface-fallback.c \
cairo-surface-clipper.c \
cairo-surface-wrapper.c \
cairo-tor-scan-converter.c \
cairo-system.c \
cairo-traps.c \
cairo-tee-surface.c \
cairo-tor-scan-converter.c \
cairo-toy-font-face.c \
cairo-traps.c \
cairo-unicode.c \
cairo-user-font.c \
cairo-version.c \
@ -187,9 +191,14 @@ cairo_ps_headers = cairo-ps.h
cairo_ps_private = cairo-ps-surface-private.h
cairo_ps_sources = cairo-ps-surface.c
cairo_deflate_stream_sources = cairo-deflate-stream.c
cairo_pdf_headers = cairo-pdf.h
cairo_pdf_private = cairo-pdf-surface-private.h
cairo_pdf_sources = cairo-pdf-surface.c cairo-deflate-stream.c
cairo_pdf_sources = cairo-pdf-surface.c
if CAIRO_HAS_PDF_SURFACE
req_cairo_deflate_stream_sources = $(cairo_deflate_stream_sources)
endif
cairo_svg_headers = cairo-svg.h
cairo_svg_private = cairo-svg-surface-private.h
@ -253,6 +262,9 @@ cairo_win32_sources = cairo-win32-surface.c cairo-win32-printing-surface.c
cairo_win32_font_sources = cairo-win32-font.c
cairo_skia_headers =
cairo_skia_sources = cairo-skia-surface.cpp
cairo_os2_headers = cairo-os2.h
cairo_os2_private = cairo-os2-private.h
cairo_os2_sources = cairo-os2-surface.c
@ -291,5 +303,15 @@ cairo_gallium_sources = drm/cairo-drm-gallium-surface.c
cairo_script_headers = cairo-script.h
cairo_script_sources = cairo-script-surface.c
cairo_xml_headers = cairo-xml.h
cairo_xml_sources = cairo-xml-surface.c
if CAIRO_HAS_XML_SURFACE
req_cairo_deflate_stream_sources = $(cairo_deflate_stream_sources)
endif
cairo_vg_headers = cairo-vg.h
cairo_vg_sources = cairo-vg-surface.c
cairo_sources += \
$(req_cairo_deflate_stream_sources) \
$(NULL)

View file

@ -147,6 +147,20 @@ ifeq ($(CAIRO_HAS_WIN32_FONT),1)
enabled_cairo_pkgconf += cairo-win32-font.pc
endif
unsupported_cairo_headers += $(cairo_skia_headers)
all_cairo_headers += $(cairo_skia_headers)
all_cairo_private += $(cairo_skia_private)
all_cairo_sources += $(cairo_skia_sources)
ifeq ($(CAIRO_HAS_SKIA_SURFACE),1)
enabled_cairo_headers += $(cairo_skia_headers)
enabled_cairo_private += $(cairo_skia_private)
enabled_cairo_sources += $(cairo_skia_sources)
endif
all_cairo_pkgconf += cairo-skia.pc
ifeq ($(CAIRO_HAS_SKIA_SURFACE),1)
enabled_cairo_pkgconf += cairo-skia.pc
endif
unsupported_cairo_headers += $(cairo_os2_headers)
all_cairo_headers += $(cairo_os2_headers)
all_cairo_private += $(cairo_os2_private)
@ -422,6 +436,28 @@ enabled_cairo_headers += $(cairo_meta_headers)
enabled_cairo_private += $(cairo_meta_private)
enabled_cairo_sources += $(cairo_meta_sources)
supported_cairo_headers += $(cairo_tee_headers)
all_cairo_headers += $(cairo_tee_headers)
all_cairo_private += $(cairo_tee_private)
all_cairo_sources += $(cairo_tee_sources)
enabled_cairo_headers += $(cairo_tee_headers)
enabled_cairo_private += $(cairo_tee_private)
enabled_cairo_sources += $(cairo_tee_sources)
supported_cairo_headers += $(cairo_xml_headers)
all_cairo_headers += $(cairo_xml_headers)
all_cairo_private += $(cairo_xml_private)
all_cairo_sources += $(cairo_xml_sources)
ifeq ($(CAIRO_HAS_XML_SURFACE),1)
enabled_cairo_headers += $(cairo_xml_headers)
enabled_cairo_private += $(cairo_xml_private)
enabled_cairo_sources += $(cairo_xml_sources)
endif
all_cairo_pkgconf += cairo-xml.pc
ifeq ($(CAIRO_HAS_XML_SURFACE),1)
enabled_cairo_pkgconf += cairo-xml.pc
endif
supported_cairo_headers += $(cairo_user_headers)
all_cairo_headers += $(cairo_user_headers)
all_cairo_private += $(cairo_user_private)

View file

@ -116,7 +116,7 @@ _arc_segments_needed (double angle,
major_axis = _cairo_matrix_transformed_circle_major_axis (ctm, radius);
max_angle = _arc_max_angle_for_tolerance_normalized (tolerance / major_axis);
return (int) ceil (angle / max_angle);
return ceil (fabs (angle) / max_angle);
}
/* We want to draw a single spline approximating a circular arc radius

143
src/cairo-base64-stream.c Normal file
View file

@ -0,0 +1,143 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005-2007 Emmanuel Pacaud <emmanuel.pacaud@free.fr>
* Copyright © 2009 Chris Wilson
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
*
* Author(s):
* Kristian Høgsberg <krh@redhat.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-output-stream-private.h"
typedef struct _cairo_base64_stream {
cairo_output_stream_t base;
cairo_output_stream_t *output;
unsigned int in_mem;
unsigned int trailing;
unsigned char src[3];
} cairo_base64_stream_t;
static char const base64_table[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static cairo_status_t
_cairo_base64_stream_write (cairo_output_stream_t *base,
const unsigned char *data,
unsigned int length)
{
cairo_base64_stream_t * stream = (cairo_base64_stream_t *) base;
unsigned char *src = stream->src;
unsigned int i;
if (stream->in_mem + length < 3) {
for (i = 0; i < length; i++) {
src[i + stream->in_mem] = *data++;
}
stream->in_mem += length;
return CAIRO_STATUS_SUCCESS;
}
do {
unsigned char dst[4];
for (i = stream->in_mem; i < 3; i++) {
src[i] = *data++;
length--;
}
stream->in_mem = 0;
dst[0] = base64_table[src[0] >> 2];
dst[1] = base64_table[(src[0] & 0x03) << 4 | src[1] >> 4];
dst[2] = base64_table[(src[1] & 0x0f) << 2 | src[2] >> 6];
dst[3] = base64_table[src[2] & 0xfc >> 2];
/* Special case for the last missing bits */
switch (stream->trailing) {
case 2:
dst[2] = '=';
case 1:
dst[3] = '=';
default:
break;
}
_cairo_output_stream_write (stream->output, dst, 4);
} while (length >= 3);
for (i = 0; i < length; i++) {
src[i] = *data++;
}
stream->in_mem = length;
return _cairo_output_stream_get_status (stream->output);
}
static cairo_status_t
_cairo_base64_stream_close (cairo_output_stream_t *base)
{
cairo_base64_stream_t *stream = (cairo_base64_stream_t *) base;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (stream->in_mem > 0) {
memset (stream->src + stream->in_mem, 0, 3 - stream->in_mem);
stream->trailing = 3 - stream->in_mem;
stream->in_mem = 3;
status = _cairo_base64_stream_write (base, NULL, 0);
}
return status;
}
cairo_output_stream_t *
_cairo_base64_stream_create (cairo_output_stream_t *output)
{
cairo_base64_stream_t *stream;
if (output->status)
return _cairo_output_stream_create_in_error (output->status);
stream = malloc (sizeof (cairo_base64_stream_t));
if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
_cairo_base64_stream_write,
NULL,
_cairo_base64_stream_close);
stream->output = output;
stream->in_mem = 0;
stream->trailing = 0;
return &stream->base;
}

View file

@ -102,9 +102,6 @@ _cairo_base85_stream_close (cairo_output_stream_t *base)
_cairo_output_stream_write (stream->output, five_tuple, stream->pending + 1);
}
/* Mark end of base85 data */
_cairo_output_stream_printf (stream->output, "~>");
return _cairo_output_stream_get_status (stream->output);
}

View file

@ -0,0 +1,733 @@
/*
* Copyright © 2004 Carl Worth
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2009 Chris Wilson
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Carl Worth
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
/* Provide definitions for standalone compilation */
#include "cairoint.h"
#include "cairo-combsort-private.h"
#include "cairo-list-private.h"
typedef struct _cairo_bo_rectangle cairo_bo_rectangle_t;
typedef struct _cairo_bo_edge cairo_bo_edge_t;
/* A deferred trapezoid of an edge */
typedef struct _cairo_bo_trap {
cairo_bo_edge_t *right;
int32_t top;
} cairo_bo_trap_t;
struct _cairo_bo_edge {
int x;
int dir;
cairo_bo_trap_t deferred_trap;
cairo_list_t link;
};
struct _cairo_bo_rectangle {
cairo_bo_edge_t left, right;
int top, bottom;
};
/* the parent is always given by index/2 */
#define PQ_PARENT_INDEX(i) ((i) >> 1)
#define PQ_FIRST_ENTRY 1
/* left and right children are index * 2 and (index * 2) +1 respectively */
#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
typedef struct _pqueue {
int size, max_size;
cairo_bo_rectangle_t **elements;
cairo_bo_rectangle_t *elements_embedded[1024];
} pqueue_t;
typedef struct _cairo_bo_sweep_line {
cairo_bo_rectangle_t **rectangles;
pqueue_t stop;
cairo_list_t sweep;
cairo_list_t *current_left, *current_right;
int32_t current_y;
int32_t last_y;
} cairo_bo_sweep_line_t;
#define DEBUG_TRAPS 0
#if DEBUG_TRAPS
static void
dump_traps (cairo_traps_t *traps, const char *filename)
{
FILE *file;
int n;
if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
return;
file = fopen (filename, "a");
if (file != NULL) {
for (n = 0; n < traps->num_traps; n++) {
fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n",
traps->traps[n].top,
traps->traps[n].bottom,
traps->traps[n].left.p1.x,
traps->traps[n].left.p1.y,
traps->traps[n].left.p2.x,
traps->traps[n].left.p2.y,
traps->traps[n].right.p1.x,
traps->traps[n].right.p1.y,
traps->traps[n].right.p2.x,
traps->traps[n].right.p2.y);
}
fprintf (file, "\n");
fclose (file);
}
}
#else
#define dump_traps(traps, filename)
#endif
static inline int
cairo_bo_rectangle_compare_start (const cairo_bo_rectangle_t *a,
const cairo_bo_rectangle_t *b)
{
return a->top - b->top;
}
static inline int
_cairo_bo_rectangle_compare_stop (const cairo_bo_rectangle_t *a,
const cairo_bo_rectangle_t *b)
{
return a->bottom - b->bottom;
}
static inline void
_pqueue_init (pqueue_t *pq)
{
pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
pq->size = 0;
pq->elements = pq->elements_embedded;
pq->elements[PQ_FIRST_ENTRY] = NULL;
}
static inline void
_pqueue_fini (pqueue_t *pq)
{
if (pq->elements != pq->elements_embedded)
free (pq->elements);
}
static cairo_status_t
_pqueue_grow (pqueue_t *pq)
{
cairo_bo_rectangle_t **new_elements;
pq->max_size *= 2;
if (pq->elements == pq->elements_embedded) {
new_elements = _cairo_malloc_ab (pq->max_size,
sizeof (cairo_bo_rectangle_t *));
if (unlikely (new_elements == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (new_elements, pq->elements_embedded,
sizeof (pq->elements_embedded));
} else {
new_elements = _cairo_realloc_ab (pq->elements,
pq->max_size,
sizeof (cairo_bo_rectangle_t *));
if (unlikely (new_elements == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
pq->elements = new_elements;
return CAIRO_STATUS_SUCCESS;
}
static inline cairo_status_t
_pqueue_push (pqueue_t *pq, cairo_bo_rectangle_t *rectangle)
{
cairo_bo_rectangle_t **elements;
int i, parent;
if (unlikely (pq->size + 1 == pq->max_size)) {
cairo_status_t status;
status = _pqueue_grow (pq);
if (unlikely (status))
return status;
}
elements = pq->elements;
for (i = ++pq->size;
i != PQ_FIRST_ENTRY &&
_cairo_bo_rectangle_compare_stop (rectangle,
elements[parent = PQ_PARENT_INDEX (i)]) < 0;
i = parent)
{
elements[i] = elements[parent];
}
elements[i] = rectangle;
return CAIRO_STATUS_SUCCESS;
}
static inline void
_pqueue_pop (pqueue_t *pq)
{
cairo_bo_rectangle_t **elements = pq->elements;
cairo_bo_rectangle_t *tail;
int child, i;
tail = elements[pq->size--];
if (pq->size == 0) {
elements[PQ_FIRST_ENTRY] = NULL;
return;
}
for (i = PQ_FIRST_ENTRY;
(child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
i = child)
{
if (child != pq->size &&
_cairo_bo_rectangle_compare_stop (elements[child+1],
elements[child]) < 0)
{
child++;
}
if (_cairo_bo_rectangle_compare_stop (elements[child], tail) >= 0)
break;
elements[i] = elements[child];
}
elements[i] = tail;
}
static inline cairo_bo_rectangle_t *
_cairo_bo_rectangle_pop_start (cairo_bo_sweep_line_t *sweep_line)
{
return *sweep_line->rectangles++;
}
static inline cairo_bo_rectangle_t *
_cairo_bo_rectangle_peek_stop (cairo_bo_sweep_line_t *sweep_line)
{
return sweep_line->stop.elements[PQ_FIRST_ENTRY];
}
CAIRO_COMBSORT_DECLARE (_cairo_bo_rectangle_sort,
cairo_bo_rectangle_t *,
cairo_bo_rectangle_compare_start)
static void
_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_rectangle_t **rectangles,
int num_rectangles)
{
_cairo_bo_rectangle_sort (rectangles, num_rectangles);
rectangles[num_rectangles] = NULL;
sweep_line->rectangles = rectangles;
cairo_list_init (&sweep_line->sweep);
sweep_line->current_left = &sweep_line->sweep;
sweep_line->current_right = &sweep_line->sweep;
sweep_line->current_y = INT32_MIN;
sweep_line->last_y = INT32_MIN;
_pqueue_init (&sweep_line->stop);
}
static void
_cairo_bo_sweep_line_fini (cairo_bo_sweep_line_t *sweep_line)
{
_pqueue_fini (&sweep_line->stop);
}
static inline cairo_bo_edge_t *
link_to_edge (cairo_list_t *elt)
{
return cairo_container_of (elt, cairo_bo_edge_t, link);
}
static cairo_status_t
_cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
int32_t bot,
cairo_traps_t *traps)
{
cairo_bo_trap_t *trap = &left->deferred_trap;
/* Only emit (trivial) non-degenerate trapezoids with positive height. */
if (likely (trap->top < bot)) {
cairo_line_t _left = {
{ left->x, trap->top },
{ left->x, bot },
}, _right = {
{ trap->right->x, trap->top },
{ trap->right->x, bot },
};
_cairo_traps_add_trap (traps, trap->top, bot, &_left, &_right);
}
trap->right = NULL;
return _cairo_traps_status (traps);
}
/* Start a new trapezoid at the given top y coordinate, whose edges
* are `edge' and `edge->next'. If `edge' already has a trapezoid,
* then either add it to the traps in `traps', if the trapezoid's
* right edge differs from `edge->next', or do nothing if the new
* trapezoid would be a continuation of the existing one. */
static inline cairo_status_t
_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
cairo_bo_edge_t *right,
int top,
cairo_traps_t *traps)
{
cairo_status_t status;
if (left->deferred_trap.right == right)
return CAIRO_STATUS_SUCCESS;
if (left->deferred_trap.right != NULL) {
if (right != NULL && left->deferred_trap.right->x == right->x) {
/* continuation on right, so just swap edges */
left->deferred_trap.right = right;
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_bo_edge_end_trap (left, top, traps);
if (unlikely (status))
return status;
}
if (right != NULL && left->x != right->x) {
left->deferred_trap.top = top;
left->deferred_trap.right = right;
}
return CAIRO_STATUS_SUCCESS;
}
static inline cairo_status_t
_active_edges_to_traps (cairo_bo_sweep_line_t *sweep,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
int top = sweep->current_y;
cairo_list_t *pos = &sweep->sweep;
cairo_status_t status;
if (sweep->last_y == sweep->current_y)
return CAIRO_STATUS_SUCCESS;
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
do {
cairo_bo_edge_t *left, *right;
int in_out;
pos = pos->next;
if (pos == &sweep->sweep)
break;
left = link_to_edge (pos);
in_out = left->dir;
/* Check if there is a co-linear edge with an existing trap */
if (left->deferred_trap.right == NULL) {
right = link_to_edge (pos->next);
while (unlikely (right->x == left->x)) {
if (right->deferred_trap.right != NULL) {
/* continuation on left */
left->deferred_trap = right->deferred_trap;
right->deferred_trap.right = NULL;
break;
}
right = link_to_edge (right->link.next);
}
}
/* Greedily search for the closing edge, so that we generate the
* maximal span width with the minimal number of trapezoids.
*/
right = link_to_edge (left->link.next);
do {
/* End all subsumed traps */
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, traps);
if (unlikely (status))
return status;
}
in_out += right->dir;
if (in_out == 0) {
/* skip co-linear edges */
if (likely (right->link.next == &sweep->sweep ||
right->x != link_to_edge (right->link.next)->x))
{
break;
}
}
right = link_to_edge (right->link.next);
} while (TRUE);
status = _cairo_bo_edge_start_or_continue_trap (left, right,
top, traps);
if (unlikely (status))
return status;
pos = &right->link;
} while (TRUE);
} else {
cairo_bo_edge_t *left, *right;
do {
int in_out = 0;
pos = pos->next;
if (pos == &sweep->sweep)
break;
left = link_to_edge (pos);
pos = pos->next;
do {
right = link_to_edge (pos);
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, traps);
if (unlikely (status))
return status;
}
if ((in_out++ & 1) == 0) {
cairo_list_t *next;
cairo_bool_t skip = FALSE;
/* skip co-linear edges */
next = pos->next;
if (next != &sweep->sweep)
skip = right->x == link_to_edge (next)->x;
if (! skip)
break;
}
pos = pos->next;
} while (TRUE);
right = pos == &sweep->sweep ? NULL : link_to_edge (pos);
status = _cairo_bo_edge_start_or_continue_trap (left, right,
top, traps);
if (unlikely (status))
return status;
} while (right != NULL);
}
sweep->last_y = sweep->current_y;
return CAIRO_STATUS_SUCCESS;
}
static inline cairo_status_t
_cairo_bo_sweep_line_delete_edge (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge,
cairo_traps_t *traps)
{
if (edge->deferred_trap.right != NULL) {
cairo_bo_edge_t *next = link_to_edge (edge->link.next);
if (&next->link != &sweep_line->sweep && next->x == edge->x) {
next->deferred_trap = edge->deferred_trap;
} else {
cairo_status_t status;
status = _cairo_bo_edge_end_trap (edge,
sweep_line->current_y,
traps);
if (unlikely (status))
return status;
}
}
if (sweep_line->current_left == &edge->link)
sweep_line->current_left = edge->link.prev;
if (sweep_line->current_right == &edge->link)
sweep_line->current_right = edge->link.next;
cairo_list_del (&edge->link);
return CAIRO_STATUS_SUCCESS;
}
static inline cairo_status_t
_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_rectangle_t *rectangle,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_status_t status;
if (rectangle->bottom != sweep_line->current_y) {
status = _active_edges_to_traps (sweep_line, fill_rule, traps);
if (unlikely (status))
return status;
sweep_line->current_y = rectangle->bottom;
}
status = _cairo_bo_sweep_line_delete_edge (sweep_line,
&rectangle->left,
traps);
if (unlikely (status))
return status;
status = _cairo_bo_sweep_line_delete_edge (sweep_line,
&rectangle->right,
traps);
if (unlikely (status))
return status;
_pqueue_pop (&sweep_line->stop);
return CAIRO_STATUS_SUCCESS;
}
static cairo_bool_t
validate_sweep_line (cairo_bo_sweep_line_t *sweep_line)
{
int32_t last_x = INT32_MIN;
cairo_bo_edge_t *edge;
cairo_list_foreach_entry (edge, cairo_bo_edge_t, &sweep_line->sweep, link) {
if (edge->x < last_x)
return FALSE;
last_x = edge->x;
}
return TRUE;
}
static inline cairo_status_t
_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_rectangle_t *rectangle,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_list_t *pos;
cairo_status_t status;
if (rectangle->top != sweep_line->current_y) {
cairo_bo_rectangle_t *stop;
stop = _cairo_bo_rectangle_peek_stop (sweep_line);
while (stop != NULL && stop->bottom < rectangle->top) {
status = _cairo_bo_sweep_line_delete (sweep_line, stop,
fill_rule, traps);
if (unlikely (status))
return status;
stop = _cairo_bo_rectangle_peek_stop (sweep_line);
}
status = _active_edges_to_traps (sweep_line, fill_rule, traps);
if (unlikely (status))
return status;
sweep_line->current_y = rectangle->top;
}
/* right edge */
pos = sweep_line->current_right;
if (pos != &sweep_line->sweep) {
int cmp;
cmp = link_to_edge (pos)->x - rectangle->right.x;
if (cmp < 0) {
while (pos->next != &sweep_line->sweep &&
link_to_edge (pos->next)->x - rectangle->right.x < 0)
{
pos = pos->next;
}
} else if (cmp > 0) {
do {
pos = pos->prev;
} while (pos != &sweep_line->sweep &&
link_to_edge (pos)->x - rectangle->right.x > 0);
}
cairo_list_add (&rectangle->right.link, pos);
} else {
cairo_list_add_tail (&rectangle->right.link, pos);
}
sweep_line->current_right = &rectangle->right.link;
assert (validate_sweep_line (sweep_line));
/* left edge */
pos = sweep_line->current_left;
if (pos != &sweep_line->sweep) {
int cmp;
if (link_to_edge (pos)->x >= rectangle->right.x) {
pos = rectangle->right.link.prev;
if (pos == &sweep_line->sweep)
goto left_done;
}
cmp = link_to_edge (pos)->x - rectangle->left.x;
if (cmp < 0) {
while (pos->next != &sweep_line->sweep &&
link_to_edge (pos->next)->x - rectangle->left.x < 0)
{
pos = pos->next;
}
} else if (cmp > 0) {
do {
pos = pos->prev;
} while (pos != &sweep_line->sweep &&
link_to_edge (pos)->x - rectangle->left.x > 0);
}
}
left_done:
cairo_list_add (&rectangle->left.link, pos);
sweep_line->current_left = &rectangle->left.link;
assert (validate_sweep_line (sweep_line));
return _pqueue_push (&sweep_line->stop, rectangle);
}
static cairo_status_t
_cairo_bentley_ottmann_tessellate_rectangular (cairo_bo_rectangle_t **rectangles,
int num_rectangles,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_bo_sweep_line_t sweep_line;
cairo_bo_rectangle_t *rectangle;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
_cairo_bo_sweep_line_init (&sweep_line, rectangles, num_rectangles);
while ((rectangle = _cairo_bo_rectangle_pop_start (&sweep_line)) != NULL) {
status = _cairo_bo_sweep_line_insert (&sweep_line, rectangle,
fill_rule, traps);
if (unlikely (status))
goto BAIL;
}
while ((rectangle = _cairo_bo_rectangle_peek_stop (&sweep_line)) != NULL) {
status = _cairo_bo_sweep_line_delete (&sweep_line, rectangle,
fill_rule, traps);
if (unlikely (status))
goto BAIL;
}
BAIL:
_cairo_bo_sweep_line_fini (&sweep_line);
return status;
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule)
{
cairo_bo_rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_rectangle_t)];
cairo_bo_rectangle_t *rectangles;
cairo_bo_rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1];
cairo_bo_rectangle_t **rectangles_ptrs;
cairo_status_t status;
int i;
if (unlikely (traps->num_traps == 0))
return CAIRO_STATUS_SUCCESS;
assert (traps->is_rectangular);
dump_traps (traps, "bo-rects-traps-in.txt");
rectangles = stack_rectangles;
rectangles_ptrs = stack_rectangles_ptrs;
if (traps->num_traps > ARRAY_LENGTH (stack_rectangles)) {
rectangles = _cairo_malloc_ab_plus_c (traps->num_traps,
sizeof (cairo_bo_rectangle_t) +
sizeof (cairo_bo_rectangle_t *),
sizeof (cairo_bo_rectangle_t *));
if (unlikely (rectangles == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
rectangles_ptrs = (cairo_bo_rectangle_t **) (rectangles + traps->num_traps);
}
for (i = 0; i < traps->num_traps; i++) {
if (traps->traps[i].left.p1.x < traps->traps[i].right.p1.x) {
rectangles[i].left.x = traps->traps[i].left.p1.x;
rectangles[i].left.dir = 1;
rectangles[i].right.x = traps->traps[i].right.p1.x;
rectangles[i].right.dir = -1;
} else {
rectangles[i].right.x = traps->traps[i].left.p1.x;
rectangles[i].right.dir = 1;
rectangles[i].left.x = traps->traps[i].right.p1.x;
rectangles[i].left.dir = -1;
}
rectangles[i].left.deferred_trap.right = NULL;
cairo_list_init (&rectangles[i].left.link);
rectangles[i].right.deferred_trap.right = NULL;
cairo_list_init (&rectangles[i].right.link);
rectangles[i].top = traps->traps[i].top;
rectangles[i].bottom = traps->traps[i].bottom;
rectangles_ptrs[i] = &rectangles[i];
}
_cairo_traps_clear (traps);
status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs, i,
fill_rule,
traps);
traps->is_rectilinear = TRUE;
traps->is_rectangular = TRUE;
if (rectangles != stack_rectangles)
free (rectangles);
dump_traps (traps, "bo-rects-traps-out.txt");
return status;
}

View file

@ -0,0 +1,582 @@
/*
* Copyright © 2004 Carl Worth
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2008 Chris Wilson
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Carl Worth
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
/* Provide definitions for standalone compilation */
#include "cairoint.h"
#include "cairo-combsort-private.h"
typedef struct _cairo_bo_edge cairo_bo_edge_t;
typedef struct _cairo_bo_trap cairo_bo_trap_t;
/* A deferred trapezoid of an edge */
struct _cairo_bo_trap {
cairo_bo_edge_t *right;
int32_t top;
};
struct _cairo_bo_edge {
cairo_edge_t edge;
cairo_bo_edge_t *prev;
cairo_bo_edge_t *next;
cairo_bo_trap_t deferred_trap;
};
typedef enum {
CAIRO_BO_EVENT_TYPE_START,
CAIRO_BO_EVENT_TYPE_STOP
} cairo_bo_event_type_t;
typedef struct _cairo_bo_event {
cairo_bo_event_type_t type;
cairo_point_t point;
cairo_bo_edge_t *edge;
} cairo_bo_event_t;
typedef struct _cairo_bo_sweep_line {
cairo_bo_event_t **events;
cairo_bo_edge_t *head;
cairo_bo_edge_t *stopped;
int32_t current_y;
cairo_bo_edge_t *current_edge;
} cairo_bo_sweep_line_t;
static inline int
_cairo_point_compare (const cairo_point_t *a,
const cairo_point_t *b)
{
int cmp;
cmp = a->y - b->y;
if (likely (cmp))
return cmp;
return a->x - b->x;
}
static inline int
_cairo_bo_edge_compare (const cairo_bo_edge_t *a,
const cairo_bo_edge_t *b)
{
int cmp;
cmp = a->edge.line.p1.x - b->edge.line.p1.x;
if (likely (cmp))
return cmp;
return b->edge.bottom - a->edge.bottom;
}
static inline int
cairo_bo_event_compare (const cairo_bo_event_t *a,
const cairo_bo_event_t *b)
{
int cmp;
cmp = _cairo_point_compare (&a->point, &b->point);
if (likely (cmp))
return cmp;
cmp = a->type - b->type;
if (cmp)
return cmp;
return a - b;
}
static inline cairo_bo_event_t *
_cairo_bo_event_dequeue (cairo_bo_sweep_line_t *sweep_line)
{
return *sweep_line->events++;
}
CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort,
cairo_bo_event_t *,
cairo_bo_event_compare)
static void
_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_event_t **events,
int num_events)
{
_cairo_bo_event_queue_sort (events, num_events);
events[num_events] = NULL;
sweep_line->events = events;
sweep_line->head = NULL;
sweep_line->current_y = INT32_MIN;
sweep_line->current_edge = NULL;
}
static void
_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge)
{
if (sweep_line->current_edge != NULL) {
cairo_bo_edge_t *prev, *next;
int cmp;
cmp = _cairo_bo_edge_compare (sweep_line->current_edge, edge);
if (cmp < 0) {
prev = sweep_line->current_edge;
next = prev->next;
while (next != NULL && _cairo_bo_edge_compare (next, edge) < 0)
prev = next, next = prev->next;
prev->next = edge;
edge->prev = prev;
edge->next = next;
if (next != NULL)
next->prev = edge;
} else if (cmp > 0) {
next = sweep_line->current_edge;
prev = next->prev;
while (prev != NULL && _cairo_bo_edge_compare (prev, edge) > 0)
next = prev, prev = next->prev;
next->prev = edge;
edge->next = next;
edge->prev = prev;
if (prev != NULL)
prev->next = edge;
else
sweep_line->head = edge;
} else {
prev = sweep_line->current_edge;
edge->prev = prev;
edge->next = prev->next;
if (prev->next != NULL)
prev->next->prev = edge;
prev->next = edge;
}
} else {
sweep_line->head = edge;
}
sweep_line->current_edge = edge;
}
static void
_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge)
{
if (edge->prev != NULL)
edge->prev->next = edge->next;
else
sweep_line->head = edge->next;
if (edge->next != NULL)
edge->next->prev = edge->prev;
if (sweep_line->current_edge == edge)
sweep_line->current_edge = edge->prev ? edge->prev : edge->next;
}
static inline cairo_bool_t
edges_collinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
{
return a->edge.line.p1.x == b->edge.line.p1.x;
}
static cairo_status_t
_cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
int32_t bot,
cairo_traps_t *traps)
{
cairo_bo_trap_t *trap = &left->deferred_trap;
/* Only emit (trivial) non-degenerate trapezoids with positive height. */
if (likely (trap->top < bot)) {
_cairo_traps_add_trap (traps,
trap->top, bot,
&left->edge.line, &trap->right->edge.line);
}
trap->right = NULL;
return _cairo_traps_status (traps);
}
/* Start a new trapezoid at the given top y coordinate, whose edges
* are `edge' and `edge->next'. If `edge' already has a trapezoid,
* then either add it to the traps in `traps', if the trapezoid's
* right edge differs from `edge->next', or do nothing if the new
* trapezoid would be a continuation of the existing one. */
static inline cairo_status_t
_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
cairo_bo_edge_t *right,
int top,
cairo_traps_t *traps)
{
cairo_status_t status;
if (left->deferred_trap.right == right)
return CAIRO_STATUS_SUCCESS;
if (left->deferred_trap.right != NULL) {
if (right != NULL && edges_collinear (left->deferred_trap.right, right))
{
/* continuation on right, so just swap edges */
left->deferred_trap.right = right;
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_bo_edge_end_trap (left, top, traps);
if (unlikely (status))
return status;
}
if (right != NULL && ! edges_collinear (left, right)) {
left->deferred_trap.top = top;
left->deferred_trap.right = right;
}
return CAIRO_STATUS_SUCCESS;
}
static inline cairo_status_t
_active_edges_to_traps (cairo_bo_edge_t *left,
int32_t top,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_bo_edge_t *right;
cairo_status_t status;
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
while (left != NULL) {
int in_out;
/* Greedily search for the closing edge, so that we generate the
* maximal span width with the minimal number of trapezoids.
*/
in_out = left->edge.dir;
/* Check if there is a co-linear edge with an existing trap */
right = left->next;
if (left->deferred_trap.right == NULL) {
while (right != NULL && right->deferred_trap.right == NULL)
right = right->next;
if (right != NULL && edges_collinear (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) {
/* skip co-linear edges */
if (right->next == NULL ||
! edges_collinear (right, right->next))
{
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;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (right, top, traps);
if (unlikely (status))
return status;
}
if ((in_out++ & 1) == 0) {
cairo_bo_edge_t *next;
cairo_bool_t skip = FALSE;
/* skip co-linear edges */
next = right->next;
if (next != NULL)
skip = edges_collinear (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;
}
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events,
int num_events,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_bo_sweep_line_t sweep_line;
cairo_bo_event_t *event;
cairo_status_t status;
_cairo_bo_sweep_line_init (&sweep_line, start_events, num_events);
while ((event = _cairo_bo_event_dequeue (&sweep_line))) {
if (event->point.y != sweep_line.current_y) {
status = _active_edges_to_traps (sweep_line.head,
sweep_line.current_y,
fill_rule, traps);
if (unlikely (status))
return status;
sweep_line.current_y = event->point.y;
}
switch (event->type) {
case CAIRO_BO_EVENT_TYPE_START:
_cairo_bo_sweep_line_insert (&sweep_line, event->edge);
break;
case CAIRO_BO_EVENT_TYPE_STOP:
_cairo_bo_sweep_line_delete (&sweep_line, event->edge);
if (event->edge->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (event->edge,
sweep_line.current_y,
traps);
if (unlikely (status))
return status;
}
break;
}
}
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, traps);
if (events != stack_events)
free (events);
traps->is_rectilinear = TRUE;
return status;
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule)
{
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;
cairo_status_t status;
int i, j, k;
if (unlikely (traps->num_traps == 0))
return CAIRO_STATUS_SUCCESS;
assert (traps->is_rectilinear);
i = 4 * traps->num_traps;
events = stack_events;
event_ptrs = stack_event_ptrs;
edges = stack_edges;
if (i > ARRAY_LENGTH (stack_events)) {
events = _cairo_malloc_ab_plus_c (i,
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 + i);
edges = (cairo_bo_edge_t *) (event_ptrs + i + 1);
}
for (i = j = k = 0; i < traps->num_traps; i++) {
edges[k].edge.top = traps->traps[i].top;
edges[k].edge.bottom = traps->traps[i].bottom;
edges[k].edge.line = traps->traps[i].left;
edges[k].edge.dir = 1;
edges[k].deferred_trap.right = NULL;
edges[k].prev = NULL;
edges[k].next = NULL;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = traps->traps[i].top;
events[j].point.x = traps->traps[i].left.p1.x;
events[j].edge = &edges[k];
j++;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = traps->traps[i].bottom;
events[j].point.x = traps->traps[i].left.p1.x;
events[j].edge = &edges[k];
j++;
k++;
edges[k].edge.top = traps->traps[i].top;
edges[k].edge.bottom = traps->traps[i].bottom;
edges[k].edge.line = traps->traps[i].right;
edges[k].edge.dir = -1;
edges[k].deferred_trap.right = NULL;
edges[k].prev = NULL;
edges[k].next = NULL;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_START;
events[j].point.y = traps->traps[i].top;
events[j].point.x = traps->traps[i].right.p1.x;
events[j].edge = &edges[k];
j++;
event_ptrs[j] = &events[j];
events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
events[j].point.y = traps->traps[i].bottom;
events[j].point.x = traps->traps[i].right.p1.x;
events[j].edge = &edges[k];
j++;
k++;
}
_cairo_traps_clear (traps);
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
fill_rule,
traps);
traps->is_rectilinear = TRUE;
if (events != stack_events)
free (events);
return status;
}

File diff suppressed because it is too large Load diff

View file

@ -79,7 +79,7 @@ cairo_private cairo_status_t
_cairo_clip_init_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rect);
cairo_private void
cairo_private_no_warn cairo_clip_t *
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other);
cairo_private cairo_status_t
@ -90,6 +90,12 @@ _cairo_clip_init_copy_transformed (cairo_clip_t *clip,
cairo_private void
_cairo_clip_reset (cairo_clip_t *clip);
#define _cairo_clip_fini(clip) _cairo_clip_reset (clip)
cairo_private cairo_status_t
_cairo_clip_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rectangle);
cairo_private cairo_status_t
_cairo_clip_clip (cairo_clip_t *clip,
const cairo_path_fixed_t *path,
@ -107,10 +113,20 @@ _cairo_clip_get_extents (const cairo_clip_t *clip);
cairo_private cairo_surface_t *
_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *dst);
cairo_private cairo_status_t
_cairo_clip_combine_with_surface (cairo_clip_t *clip,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents);
cairo_private cairo_int_status_t
_cairo_clip_get_region (cairo_clip_t *clip,
cairo_region_t **region);
cairo_private cairo_int_status_t
_cairo_clip_get_boxes (cairo_clip_t *clip,
cairo_box_t **boxes,
int *count);
cairo_private void
_cairo_clip_translate (cairo_clip_t *clip,
cairo_fixed_t tx,

File diff suppressed because it is too large Load diff

View file

@ -56,7 +56,7 @@ NAME (TYPE *base, unsigned int nmemb) \
int swapped; \
do { \
gap = _cairo_combsort_newgap (gap); \
swapped = 0; \
swapped = gap > 1; \
for (i = 0; i < nmemb-gap ; i++) { \
j = i + gap; \
if (CMP (base[i], base[j]) > 0 ) { \
@ -67,5 +67,5 @@ NAME (TYPE *base, unsigned int nmemb) \
swapped = 1; \
} \
} \
} while (gap > 1 || swapped); \
} while (swapped); \
}

View file

@ -165,3 +165,70 @@ _cairo_image_surface_write_to_ppm (cairo_image_surface_t *isurf, const char *fn)
fprintf (stderr, "Wrote %s\n", fn);
}
#endif
static cairo_status_t
_print_move_to (void *closure,
const cairo_point_t *point)
{
fprintf (closure,
" %f %f m",
_cairo_fixed_to_double (point->x),
_cairo_fixed_to_double (point->y));
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_print_line_to (void *closure,
const cairo_point_t *point)
{
fprintf (closure,
" %f %f l",
_cairo_fixed_to_double (point->x),
_cairo_fixed_to_double (point->y));
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_print_curve_to (void *closure,
const cairo_point_t *p1,
const cairo_point_t *p2,
const cairo_point_t *p3)
{
fprintf (closure,
" %f %f %f %f %f %f c",
_cairo_fixed_to_double (p1->x),
_cairo_fixed_to_double (p1->y),
_cairo_fixed_to_double (p2->x),
_cairo_fixed_to_double (p2->y),
_cairo_fixed_to_double (p3->x),
_cairo_fixed_to_double (p3->y));
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_print_close (void *closure)
{
fprintf (closure, " h");
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path)
{
cairo_status_t status;
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_print_move_to,
_print_line_to,
_print_curve_to,
_print_close,
stream);
assert (status == CAIRO_STATUS_SUCCESS);
printf ("\n");
}

View file

@ -226,15 +226,61 @@ _cairo_fixed_mul (cairo_fixed_t a, cairo_fixed_t b)
return _cairo_int64_to_int32(_cairo_int64_rsl (temp, CAIRO_FIXED_FRAC_BITS));
}
/* computes a * b / c */
/* computes round (a * b / c) */
static inline cairo_fixed_t
_cairo_fixed_mul_div (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
{
cairo_int64_t ab = _cairo_int32x32_64_mul (a, b);
cairo_int64_t c64 = _cairo_int32_to_int64 (c);
cairo_int64_t quo = _cairo_int64_divrem (ab, c64).quo;
return _cairo_int64_to_int32 (_cairo_int64_divrem (ab, c64).quo);
}
return _cairo_int64_to_int32(quo);
/* computes floor (a * b / c) */
static inline cairo_fixed_t
_cairo_fixed_mul_div_floor (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
{
return _cairo_int64_32_div (_cairo_int32x32_64_mul (a, b), c);
}
static inline cairo_fixed_t
_cairo_edge_compute_intersection_y_for_x (const cairo_point_t *p1,
const cairo_point_t *p2,
cairo_fixed_t x)
{
cairo_fixed_t y, dx;
if (x == p1->x)
return p1->y;
if (x == p2->x)
return p2->y;
y = p1->y;
dx = p2->x - p1->x;
if (dx != 0)
y += _cairo_fixed_mul_div_floor (x - p1->x, p2->y - p1->y, dx);
return y;
}
static inline cairo_fixed_t
_cairo_edge_compute_intersection_x_for_y (const cairo_point_t *p1,
const cairo_point_t *p2,
cairo_fixed_t y)
{
cairo_fixed_t x, dy;
if (y == p1->y)
return p1->x;
if (y == p2->y)
return p2->x;
x = p1->x;
dy = p2->y - p1->y;
if (dy != 0)
x += _cairo_fixed_mul_div_floor (y - p1->y, p2->x - p1->x, dy);
return x;
}
#else

View file

@ -67,4 +67,9 @@ typedef int32_t cairo_fixed_t;
/* An unsigned type of the same size as #cairo_fixed_t */
typedef uint32_t cairo_fixed_unsigned_t;
typedef struct _cairo_point {
cairo_fixed_t x;
cairo_fixed_t y;
} cairo_point_t;
#endif /* CAIRO_FIXED_TYPE_PRIVATE_H */

View file

@ -44,11 +44,19 @@ typedef struct _cairo_freelist {
unsigned nodesize;
} cairo_freelist_t;
typedef struct _cairo_freelist_pool cairo_freelist_pool_t;
struct _cairo_freelist_pool {
cairo_freelist_pool_t *next;
unsigned size, rem;
uint8_t *data;
};
typedef struct _cairo_freepool {
cairo_freelist_node_t *first_free_node;
cairo_freelist_node_t *pools;
cairo_freelist_pool_t *pools;
unsigned nodesize;
char embedded_pool[1000];
cairo_freelist_pool_t embedded_pool;
uint8_t embedded_data[1000];
} cairo_freepool_t;
@ -91,6 +99,23 @@ _cairo_freepool_fini (cairo_freepool_t *freepool);
cairo_private void *
_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool);
static inline void *
_cairo_freepool_alloc_from_pool (cairo_freepool_t *freepool)
{
cairo_freelist_pool_t *pool;
uint8_t *ptr;
pool = freepool->pools;
if (unlikely (freepool->nodesize > pool->rem))
return _cairo_freepool_alloc_from_new_pool (freepool);
ptr = pool->data;
pool->data += freepool->nodesize;
pool->rem -= freepool->nodesize;
VG (VALGRIND_MAKE_MEM_UNDEFINED (ptr, freepool->nodesize));
return ptr;
}
static inline void *
_cairo_freepool_alloc (cairo_freepool_t *freepool)
{
@ -98,7 +123,7 @@ _cairo_freepool_alloc (cairo_freepool_t *freepool)
node = freepool->first_free_node;
if (unlikely (node == NULL))
return _cairo_freepool_alloc_from_new_pool (freepool);
return _cairo_freepool_alloc_from_pool (freepool);
VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
freepool->first_free_node = node->next;

View file

@ -87,39 +87,27 @@ _cairo_freelist_free (cairo_freelist_t *freelist, void *voidnode)
void
_cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize)
{
int poolsize;
char *ptr;
freepool->first_free_node = NULL;
freepool->pools = NULL;
freepool->pools = &freepool->embedded_pool;
freepool->nodesize = nodesize;
poolsize = sizeof (freepool->embedded_pool);
ptr = freepool->embedded_pool + poolsize - freepool->nodesize;
freepool->embedded_pool.next = NULL;
freepool->embedded_pool.size = sizeof (freepool->embedded_data);
freepool->embedded_pool.rem = sizeof (freepool->embedded_data);
freepool->embedded_pool.data = freepool->embedded_data;
poolsize /= freepool->nodesize;
while (poolsize--) {
cairo_freelist_node_t *node = (cairo_freelist_node_t *) ptr;
ptr -= freepool->nodesize;
node->next = freepool->first_free_node;
freepool->first_free_node = node;
VG (VALGRIND_MAKE_MEM_NOACCESS (node, freepool->nodesize));
}
VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data,
sizeof (freepool->embedded_data)));
}
void
_cairo_freepool_fini (cairo_freepool_t *freepool)
{
cairo_freelist_node_t *node = freepool->pools;
while (node != NULL) {
cairo_freelist_node_t *next;
VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
next = node->next;
free (node);
node = next;
cairo_freelist_pool_t *pool = freepool->pools;
while (pool != &freepool->embedded_pool) {
cairo_freelist_pool_t *next = pool->next;
free (pool);
pool = next;
}
VG (VALGRIND_MAKE_MEM_NOACCESS (freepool, sizeof (freepool)));
}
@ -127,31 +115,26 @@ _cairo_freepool_fini (cairo_freepool_t *freepool)
void *
_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool)
{
cairo_freelist_node_t *node;
char *ptr;
cairo_freelist_pool_t *pool;
int poolsize;
poolsize = (128 * freepool->nodesize + 8191) & -8192;
node = malloc (poolsize);
if (node == NULL)
return node;
if (freepool->pools != &freepool->embedded_pool)
poolsize = 2 * freepool->pools->size;
else
poolsize = (128 * freepool->nodesize + 8191) & -8192;
pool = malloc (sizeof (cairo_freelist_pool_t) + poolsize);
if (unlikely (pool == NULL))
return pool;
node->next = freepool->pools;
freepool->pools = node;
pool->next = freepool->pools;
freepool->pools = pool;
ptr = (char *) node + poolsize - freepool->nodesize;
pool->size = poolsize;
pool->rem = poolsize - freepool->nodesize;
pool->data = (uint8_t *) (pool + 1) + freepool->nodesize;
poolsize -= sizeof (cairo_freelist_node_t);
poolsize /= freepool->nodesize;
VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, poolsize));
VG (VALGRIND_MAKE_MEM_UNDEFINED (pool->data, freepool->nodesize));
while (--poolsize) {
node = (cairo_freelist_node_t *) ptr;
ptr -= freepool->nodesize;
node->next = freepool->first_free_node;
freepool->first_free_node = node;
VG (VALGRIND_MAKE_MEM_NOACCESS (node, freepool->nodesize));
}
return ptr;
return pool + 1;
}

View file

@ -2234,12 +2234,6 @@ _cairo_ft_font_face_destroy (void *abstract_face)
{
cairo_ft_font_face_t *font_face = abstract_face;
cairo_ft_font_face_t *tmp_face = NULL;
cairo_ft_font_face_t *last_face = NULL;
if (font_face == NULL)
return;
/* When destroying a face created by cairo_ft_font_face_create_for_ft_face,
* we have a special "zombie" state for the face when the unscaled font
* is still alive but there are no other references to a font face with
@ -2270,6 +2264,9 @@ _cairo_ft_font_face_destroy (void *abstract_face)
}
if (font_face->unscaled) {
cairo_ft_font_face_t *tmp_face = NULL;
cairo_ft_font_face_t *last_face = NULL;
/* Remove face from linked list */
for (tmp_face = font_face->unscaled->faces;
tmp_face;
@ -2334,12 +2331,15 @@ _cairo_ft_font_face_get_implementation (void *abstract_face,
return cairo_font_face_reference (resolved);
cairo_font_face_destroy (resolved);
font_face->resolved_font_face = NULL;
}
resolved = _cairo_ft_resolve_pattern (font_face->pattern,
font_matrix,
ctm,
options);
if (unlikely (resolved->status))
return resolved;
font_face->resolved_font_face = cairo_font_face_reference (resolved);
font_face->resolved_config = FcConfigGetCurrent ();

View file

@ -42,8 +42,6 @@
slim_hidden_proto (cairo_gl_context_reference);
slim_hidden_proto (cairo_gl_context_destroy);
#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
#define BIAS .375
static inline float
@ -367,7 +365,7 @@ _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op)
};
GLenum src_factor, dst_factor;
assert (op < ARRAY_SIZE (blend_factors));
assert (op < ARRAY_LENGTH (blend_factors));
src_factor = blend_factors[op].src;
dst_factor = blend_factors[op].dst;
@ -666,28 +664,10 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t *surface,
cairo_rectangle_int_t *rect_out)
{
cairo_image_surface_t *image;
cairo_rectangle_int_t extents;
GLenum err;
char *temp_data;
int y;
unsigned int cpp;
GLenum format, type;
cairo_format_t cairo_format;
extents.x = 0;
extents.y = 0;
extents.width = surface->width;
extents.height = surface->height;
if (interest != NULL) {
if (! _cairo_rectangle_intersect (&extents, interest)) {
*image_out = NULL;
return CAIRO_STATUS_SUCCESS;
}
}
if (rect_out != NULL)
*rect_out = extents;
unsigned int cpp;
/* Want to use a switch statement here but the compiler gets whiny. */
if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
@ -706,14 +686,14 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t *surface,
type = GL_UNSIGNED_BYTE;
cpp = 1;
} else {
fprintf (stderr, "get_image fallback: %d\n", surface->base.content);
ASSERT_NOT_REACHED;
return CAIRO_INT_STATUS_UNSUPPORTED;
}
image = (cairo_image_surface_t*)
cairo_image_surface_create (cairo_format,
extents.width, extents.height);
if (image->base.status)
interest->width, interest->height);
if (unlikely (image->base.status))
return image->base.status;
/* This is inefficient, as we'd rather just read the thing without making
@ -722,30 +702,18 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t *surface,
*/
_cairo_gl_set_destination (surface);
/* Read the data to a temporary as GL gives us bottom-to-top data
* screen-wise, and we want top-to-bottom.
*/
temp_data = malloc (extents.width * extents.height * cpp);
if (temp_data == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
glPixelStorei (GL_PACK_ALIGNMENT, 1);
glReadPixels (extents.x, extents.y,
extents.width, extents.height,
format, type, temp_data);
for (y = 0; y < extents.height; y++) {
memcpy ((char *) image->data + y * image->stride,
temp_data + y * extents.width * cpp,
extents.width * cpp);
}
free (temp_data);
*image_out = image;
glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp);
glReadPixels (interest->x, interest->y,
interest->width, interest->height,
format, type, image->data);
while ((err = glGetError ()))
fprintf (stderr, "GL error 0x%08x\n", (int) err);
*image_out = image;
if (rect_out != NULL)
*rect_out = *interest;
return CAIRO_STATUS_SUCCESS;
}
@ -1512,6 +1480,23 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
cairo_surface_pattern_t traps_pattern;
cairo_int_status_t status;
if (! _cairo_gl_operator_is_supported (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (_cairo_surface_check_span_renderer (op,pattern,&dst->base, antialias)) {
status =
_cairo_surface_composite_trapezoids_as_polygon (&dst->base,
op, pattern,
antialias,
src_x, src_y,
dst_x, dst_y,
width, height,
traps, num_traps,
clip_region);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
}
status = _cairo_gl_get_traps_pattern (dst,
dst_x, dst_y, width, height,
traps, num_traps, antialias,
@ -1841,8 +1826,7 @@ static cairo_bool_t
_cairo_gl_surface_check_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *abstract_dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects)
cairo_antialias_t antialias)
{
if (! _cairo_gl_operator_is_supported (op))
return FALSE;
@ -1855,7 +1839,6 @@ _cairo_gl_surface_check_span_renderer (cairo_operator_t op,
(void) pattern;
(void) abstract_dst;
(void) antialias;
(void) rects;
}
static cairo_span_renderer_t *

View file

@ -817,13 +817,71 @@ _cairo_gstate_path_extents (cairo_gstate_t *gstate,
*y2 = py2;
}
static void
_cairo_gstate_copy_pattern (cairo_pattern_t *pattern,
const cairo_pattern_t *original)
{
/* First check if the we can replace the original with a much simpler
* pattern. For example, gradients that are uniform or just have a single
* stop can be replace with a solid.
*/
switch (original->type) {
case CAIRO_PATTERN_TYPE_SOLID:
case CAIRO_PATTERN_TYPE_SURFACE:
break;
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
{
cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) original;
/* fast path for gradients with less than 2 color stops */
if (src->n_stops < 2) {
if (src->n_stops) {
_cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
&src->stops->color,
CAIRO_CONTENT_COLOR_ALPHA);
} else {
_cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
CAIRO_COLOR_TRANSPARENT,
CAIRO_CONTENT_ALPHA);
}
return;
} else {
unsigned int i;
/* Is the gradient a uniform colour?
* Happens more often than you would believe.
*/
for (i = 1; i < src->n_stops; i++) {
if (! _cairo_color_equal (&src->stops[0].color,
&src->stops[i].color))
{
break;
}
}
if (i == src->n_stops) {
_cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
&src->stops->color,
CAIRO_CONTENT_COLOR_ALPHA);
return;
}
}
}
}
_cairo_pattern_init_static_copy (pattern, original);
}
static void
_cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
cairo_pattern_t *pattern,
cairo_pattern_t *original,
cairo_matrix_t *ctm_inverse)
const cairo_pattern_t *original,
const cairo_matrix_t *ctm_inverse)
{
_cairo_pattern_init_static_copy (pattern, original);
_cairo_gstate_copy_pattern (pattern, original);
/* apply device_transform first so that it is transformed by ctm_inverse */
if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
@ -860,20 +918,28 @@ _cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate,
&gstate->ctm_inverse);
}
#define _gstate_get_clip(g) ((g)->clip.path ? &(g)->clip : NULL)
/* We need to take a copy of the clip so that the lower layers may modify it
* by, perhaps, intersecting it with the operation extents and other paths.
*/
#define _gstate_get_clip(G, C) _cairo_clip_init_copy ((C), &(G)->clip)
static cairo_bool_t
_clipped (const cairo_gstate_t *gstate)
_clipped (cairo_gstate_t *gstate)
{
cairo_rectangle_int_t extents;
if (gstate->clip.all_clipped)
return TRUE;
/* XXX consider applying a surface clip? */
if (gstate->clip.path == NULL)
return FALSE;
if (_cairo_surface_get_extents (gstate->target, &extents)) {
if (extents.width == 0 || extents.height == 0)
return TRUE;
if (! _cairo_rectangle_intersect (&extents,
&gstate->clip.path->extents))
{
@ -881,13 +947,16 @@ _clipped (const cairo_gstate_t *gstate)
}
}
return FALSE;
/* perform a simple query to exclude trivial all-clipped cases */
return _cairo_clip_get_region (&gstate->clip, NULL) == CAIRO_INT_STATUS_NOTHING_TO_DO;
}
cairo_status_t
_cairo_gstate_paint (cairo_gstate_t *gstate)
{
cairo_pattern_union_t pattern;
cairo_clip_t clip;
cairo_status_t status;
if (unlikely (gstate->source->status))
return gstate->source->status;
@ -897,10 +966,13 @@ _cairo_gstate_paint (cairo_gstate_t *gstate)
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
return _cairo_surface_paint (gstate->target,
gstate->op,
&pattern.base,
_gstate_get_clip (gstate));
status = _cairo_surface_paint (gstate->target,
gstate->op,
&pattern.base,
_gstate_get_clip (gstate, &clip));
_cairo_clip_fini (&clip);
return status;
}
cairo_status_t
@ -908,6 +980,8 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
cairo_pattern_t *mask)
{
cairo_pattern_union_t source_pattern, mask_pattern;
cairo_clip_t clip;
cairo_status_t status;
if (unlikely (mask->status))
return mask->status;
@ -918,20 +992,52 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
if (_cairo_pattern_is_opaque (mask))
return _cairo_gstate_paint (gstate);
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
_cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
return _cairo_surface_mask (gstate->target,
gstate->op,
&source_pattern.base,
&mask_pattern.base,
_gstate_get_clip (gstate));
/* XXX: This optimization assumes that there is no color
* information in mask, so this will need to change if we
* support RENDER-style 4-channel masks.
*/
if (source_pattern.type == CAIRO_PATTERN_TYPE_SOLID &&
mask_pattern.type == CAIRO_PATTERN_TYPE_SOLID)
{
cairo_color_t combined;
combined = source_pattern.solid.color;
_cairo_color_multiply_alpha (&combined, mask_pattern.solid.color.alpha);
_cairo_pattern_init_solid (&source_pattern.solid, &combined,
source_pattern.solid.content |
mask_pattern.solid.content);
status = _cairo_surface_paint (gstate->target,
gstate->op,
&source_pattern.base,
_gstate_get_clip (gstate, &clip));
}
else
{
status = _cairo_surface_mask (gstate->target,
gstate->op,
&source_pattern.base,
&mask_pattern.base,
_gstate_get_clip (gstate, &clip));
}
_cairo_clip_fini (&clip);
return status;
}
cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_pattern_union_t source_pattern;
cairo_clip_t clip;
cairo_status_t status;
if (unlikely (gstate->source->status))
return gstate->source->status;
@ -944,16 +1050,19 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
return _cairo_surface_stroke (gstate->target,
gstate->op,
&source_pattern.base,
path,
&gstate->stroke_style,
&gstate->ctm,
&gstate->ctm_inverse,
gstate->tolerance,
gstate->antialias,
_gstate_get_clip (gstate));
status = _cairo_surface_stroke (gstate->target,
gstate->op,
&source_pattern.base,
path,
&gstate->stroke_style,
&gstate->ctm,
&gstate->ctm_inverse,
gstate->tolerance,
gstate->antialias,
_gstate_get_clip (gstate, &clip));
_cairo_clip_fini (&clip);
return status;
}
cairo_status_t
@ -995,7 +1104,7 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate,
limit.p2.y = limit.p1.y + 2;
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, &limit);
_cairo_traps_limit (&traps, &limit, 1);
status = _cairo_path_fixed_stroke_to_traps (path,
&gstate->stroke_style,
@ -1018,6 +1127,8 @@ cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_pattern_union_t pattern;
cairo_clip_t clip;
cairo_status_t status;
if (unlikely (gstate->source->status))
return gstate->source->status;
@ -1032,22 +1143,26 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
_cairo_pattern_init_solid (&pattern.solid,
CAIRO_COLOR_TRANSPARENT,
CAIRO_CONTENT_COLOR_ALPHA);
return _cairo_surface_paint (gstate->target,
CAIRO_OPERATOR_CLEAR,
&pattern.base,
_gstate_get_clip (gstate));
status = _cairo_surface_paint (gstate->target,
CAIRO_OPERATOR_CLEAR,
&pattern.base,
_gstate_get_clip (gstate, &clip));
} else {
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
status = _cairo_surface_fill (gstate->target,
gstate->op,
&pattern.base,
path,
gstate->fill_rule,
gstate->tolerance,
gstate->antialias,
_gstate_get_clip (gstate, &clip));
}
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
_cairo_clip_fini (&clip);
return _cairo_surface_fill (gstate->target,
gstate->op,
&pattern.base,
path,
gstate->fill_rule,
gstate->tolerance,
gstate->antialias,
_gstate_get_clip (gstate));
return status;
}
cairo_bool_t
@ -1184,7 +1299,7 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
&gstate->ctm_inverse,
gstate->tolerance,
&traps);
if (status == CAIRO_STATUS_SUCCESS) {
if (likely (status == CAIRO_STATUS_SUCCESS)) {
_cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
x1, y1, x2, y2);
}
@ -1203,13 +1318,25 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate,
cairo_status_t status;
cairo_traps_t traps;
if (path->is_empty_fill) {
if (x1)
*x1 = 0.0;
if (y1)
*y1 = 0.0;
if (x2)
*x2 = 0.0;
if (y2)
*y2 = 0.0;
return CAIRO_STATUS_SUCCESS;
}
_cairo_traps_init (&traps);
status = _cairo_path_fixed_fill_to_traps (path,
gstate->fill_rule,
gstate->tolerance,
&traps);
if (status == CAIRO_STATUS_SUCCESS) {
if (likely (status == CAIRO_STATUS_SUCCESS)) {
_cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
x1, y1, x2, y2);
}
@ -1630,6 +1757,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
cairo_text_cluster_t *transformed_clusters;
cairo_status_t status;
cairo_clip_t clip;
if (unlikely (gstate->source->status))
return gstate->source->status;
@ -1699,7 +1827,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
transformed_clusters, num_clusters,
cluster_flags,
gstate->scaled_font,
_gstate_get_clip (gstate));
_gstate_get_clip (gstate, &clip));
}
else
{
@ -1719,12 +1847,14 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
CAIRO_FILL_RULE_WINDING,
gstate->tolerance,
gstate->scaled_font->options.antialias,
_gstate_get_clip (gstate));
_gstate_get_clip (gstate, &clip));
}
_cairo_path_fixed_fini (&path);
}
_cairo_clip_fini (&clip);
CLEANUP_GLYPHS:
if (transformed_glyphs != stack_transformed_glyphs)
cairo_glyph_free (transformed_glyphs);

View file

@ -191,9 +191,6 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal)
void
_cairo_hash_table_destroy (cairo_hash_table_t *hash_table)
{
if (hash_table == NULL)
return;
/* The hash table must be empty. Otherwise, halt. */
assert (hash_table->live_entries == 0);
/* No iterators can be running. Otherwise, halt. */
@ -525,9 +522,6 @@ _cairo_hash_table_foreach (cairo_hash_table_t *hash_table,
unsigned long i;
cairo_hash_entry_t *entry;
if (hash_table == NULL)
return;
/* Mark the table for iteration */
++hash_table->iterating;
for (i = 0; i < hash_table->arrangement->size; i++) {

View file

@ -36,6 +36,8 @@
#include "cairoint.h"
#include "cairo-slope-private.h"
typedef struct cairo_hull {
cairo_point_t point;
cairo_slope_t slope;

View file

@ -1483,15 +1483,13 @@ static cairo_bool_t
_cairo_image_surface_check_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *abstract_dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects)
cairo_antialias_t antialias)
{
return TRUE;
(void) op;
(void) pattern;
(void) abstract_dst;
(void) antialias;
(void) rects;
}
static cairo_span_renderer_t *

View file

@ -371,37 +371,39 @@ _cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double min_x, max_x;
double min_y, max_y;
if (_cairo_matrix_is_identity (matrix)) {
if (is_tight)
*is_tight = TRUE;
return;
}
if (matrix->xy == 0. && matrix->yx == 0.) {
/* non-rotation/skew matrix, just map the two extreme points */
quad_x[0] = *x1;
quad_y[0] = *y1;
cairo_matrix_transform_distance (matrix, &quad_x[0], &quad_y[0]);
quad_x[1] = *x2;
quad_y[1] = *y2;
cairo_matrix_transform_distance (matrix, &quad_x[1], &quad_y[1]);
if (quad_x[0] < quad_x[1]) {
*x1 = quad_x[0] + matrix->x0;
*x2 = quad_x[1] + matrix->x0;
} else {
*x1 = quad_x[1] + matrix->x0;
*x2 = quad_x[0] + matrix->x0;
if (matrix->xx != 1.) {
quad_x[0] = *x1 * matrix->xx;
quad_x[1] = *x2 * matrix->xx;
if (quad_x[0] < quad_x[1]) {
*x1 = quad_x[0];
*x2 = quad_x[1];
} else {
*x1 = quad_x[1];
*x2 = quad_x[0];
}
}
if (matrix->x0 != 0.) {
*x1 += matrix->x0;
*x2 += matrix->x0;
}
if (quad_y[0] < quad_y[1]) {
*y1 = quad_y[0] + matrix->y0;
*y2 = quad_y[1] + matrix->y0;
} else {
*y1 = quad_y[1] + matrix->y0;
*y2 = quad_y[0] + matrix->y0;
if (matrix->yy != 1.) {
quad_y[0] = *y1 * matrix->yy;
quad_y[1] = *y2 * matrix->yy;
if (quad_y[0] < quad_y[1]) {
*y1 = quad_y[0];
*y2 = quad_y[1];
} else {
*y1 = quad_y[1];
*y2 = quad_y[0];
}
}
if (matrix->y0 != 0.) {
*y1 += matrix->y0;
*y2 += matrix->y0;
}
if (is_tight)
@ -688,16 +690,9 @@ _cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
return FALSE;
}
/* By pixel exact here, we mean a matrix that is composed only of
* 90 degree rotations, flips, and integer translations and produces a 1:1
* mapping between source and destination pixels. If we transform an image
* with a pixel-exact matrix, filtering is not useful.
*/
cairo_private cairo_bool_t
_cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix)
cairo_bool_t
_cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix)
{
cairo_fixed_t x0_fixed, y0_fixed;
if (matrix->xy == 0.0 && matrix->yx == 0.0) {
if (! (matrix->xx == 1.0 || matrix->xx == -1.0))
return FALSE;
@ -711,6 +706,22 @@ _cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix)
} else
return FALSE;
return TRUE;
}
/* By pixel exact here, we mean a matrix that is composed only of
* 90 degree rotations, flips, and integer translations and produces a 1:1
* mapping between source and destination pixels. If we transform an image
* with a pixel-exact matrix, filtering is not useful.
*/
cairo_bool_t
_cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix)
{
cairo_fixed_t x0_fixed, y0_fixed;
if (! _cairo_matrix_has_unity_scale (matrix))
return FALSE;
x0_fixed = _cairo_fixed_from_double (matrix->x0);
y0_fixed = _cairo_fixed_from_double (matrix->y0);

View file

@ -257,6 +257,8 @@ _cairo_meta_surface_acquire_source_image (void *abstract_surface,
image = _cairo_image_surface_create_with_content (surface->content,
surface->extents.width,
surface->extents.height);
if (unlikely (image->status))
return image->status;
cairo_surface_set_device_offset (image,
-surface->extents.x,

View file

@ -184,6 +184,10 @@ _cairo_null_stream_create (void);
cairo_private cairo_output_stream_t *
_cairo_base85_stream_create (cairo_output_stream_t *output);
/* cairo-base64-stream.c */
cairo_private cairo_output_stream_t *
_cairo_base64_stream_create (cairo_output_stream_t *output);
/* cairo-deflate-stream.c */
cairo_private cairo_output_stream_t *
_cairo_deflate_stream_create (cairo_output_stream_t *output);

View file

@ -51,13 +51,6 @@ _cairo_path_bounder_init (cairo_path_bounder_t *bounder)
bounder->has_point = FALSE;
}
static void
_cairo_path_bounder_fini (cairo_path_bounder_t *bounder)
{
bounder->has_initial_point = FALSE;
bounder->has_point = FALSE;
}
static void
_cairo_path_bounder_add_point (cairo_path_bounder_t *bounder,
const cairo_point_t *point)
@ -79,7 +72,6 @@ _cairo_path_bounder_add_point (cairo_path_bounder_t *bounder,
bounder->extents.p1.y = point->y;
bounder->extents.p2.x = point->x;
bounder->extents.p2.y = point->y;
bounder->has_point = TRUE;
}
}
@ -195,8 +187,6 @@ _cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path,
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
_cairo_path_bounder_fini (&bounder);
}
/* A slightly better approximation than above - we actually decompose the
@ -225,8 +215,6 @@ _cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path,
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
_cairo_path_bounder_fini (&bounder);
}
void
@ -253,8 +241,6 @@ _cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
_cairo_path_bounder_fini (&bounder);
}
/* Adjusts the fill extents (above) by the device-space pen. */
@ -287,13 +273,24 @@ _cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
bounder.extents.p1.y -= _cairo_fixed_from_double (dy);
bounder.extents.p2.y += _cairo_fixed_from_double (dy);
_cairo_box_round_to_rectangle (&bounder.extents, extents);
} else if (bounder.has_initial_point) {
double dx, dy;
/* accommodate capping of degenerate paths */
_cairo_stroke_style_max_distance_from_path (style, ctm, &dx, &dy);
bounder.extents.p1.x = bounder.current_point.x - _cairo_fixed_from_double (dx);
bounder.extents.p2.x = bounder.current_point.x + _cairo_fixed_from_double (dx);
bounder.extents.p1.y = bounder.current_point.y - _cairo_fixed_from_double (dy);
bounder.extents.p2.y = bounder.current_point.y + _cairo_fixed_from_double (dy);
_cairo_box_round_to_rectangle (&bounder.extents, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
_cairo_path_bounder_fini (&bounder);
}
cairo_status_t
@ -354,6 +351,4 @@ _cairo_path_fixed_bounds (const cairo_path_fixed_t *path,
*x2 = 0.0;
*y2 = 0.0;
}
_cairo_path_bounder_fini (&bounder);
}

View file

@ -36,32 +36,25 @@
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
#include "cairo-region-private.h"
typedef struct cairo_filler {
double tolerance;
cairo_traps_t *traps;
cairo_point_t current_point;
cairo_polygon_t polygon;
cairo_polygon_t *polygon;
} cairo_filler_t;
static void
_cairo_filler_init (cairo_filler_t *filler, double tolerance, cairo_traps_t *traps)
_cairo_filler_init (cairo_filler_t *filler,
double tolerance,
cairo_polygon_t *polygon)
{
filler->tolerance = tolerance;
filler->traps = traps;
filler->current_point.x = 0;
filler->current_point.y = 0;
_cairo_polygon_init (&filler->polygon);
filler->polygon = polygon;
}
static void
_cairo_filler_fini (cairo_filler_t *filler)
{
_cairo_polygon_fini (&filler->polygon);
}
static cairo_status_t
@ -69,14 +62,10 @@ _cairo_filler_move_to (void *closure,
const cairo_point_t *point)
{
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
cairo_polygon_t *polygon = filler->polygon;
_cairo_polygon_close (polygon);
_cairo_polygon_move_to (polygon, point);
filler->current_point = *point;
return _cairo_polygon_status (&filler->polygon);
return _cairo_polygon_move_to (polygon, point);
}
static cairo_status_t
@ -84,13 +73,7 @@ _cairo_filler_line_to (void *closure,
const cairo_point_t *point)
{
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
_cairo_polygon_line_to (polygon, point);
filler->current_point = *point;
return _cairo_polygon_status (&filler->polygon);
return _cairo_polygon_line_to (filler->polygon, point);
}
static cairo_status_t
@ -103,11 +86,10 @@ _cairo_filler_curve_to (void *closure,
cairo_spline_t spline;
if (! _cairo_spline_init (&spline,
_cairo_filler_line_to,
filler,
&filler->current_point, b, c, d))
_cairo_filler_line_to, filler,
&filler->polygon->current_point, b, c, d))
{
return CAIRO_STATUS_SUCCESS;
return _cairo_filler_line_to (closure, d);
}
return _cairo_spline_decompose (&spline, filler->tolerance);
@ -117,36 +99,18 @@ static cairo_status_t
_cairo_filler_close_path (void *closure)
{
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
_cairo_polygon_close (polygon);
return _cairo_polygon_status (polygon);
return _cairo_polygon_close (filler->polygon);
}
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps);
cairo_status_t
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_traps_t *traps)
_cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
double tolerance,
cairo_polygon_t *polygon)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t filler;
cairo_status_t status;
traps->maybe_region = path->maybe_fill_region;
/* Before we do anything else, we use a special-case filler for
* a device-axis aligned rectangle if possible. */
status = _cairo_path_fixed_fill_rectangle (path, fill_rule, traps);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
_cairo_filler_init (&filler, tolerance, traps);
_cairo_filler_init (&filler, tolerance, polygon);
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
@ -156,70 +120,155 @@ _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
_cairo_filler_close_path,
&filler);
if (unlikely (status))
goto BAIL;
return status;
_cairo_polygon_close (&filler.polygon);
status = _cairo_polygon_status (&filler.polygon);
if (unlikely (status))
goto BAIL;
status = _cairo_bentley_ottmann_tessellate_polygon (filler.traps,
&filler.polygon,
fill_rule);
if (unlikely (status))
goto BAIL;
BAIL:
_cairo_polygon_close (polygon);
status = _cairo_polygon_status (polygon);
_cairo_filler_fini (&filler);
return status;
}
cairo_status_t
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_traps_t *traps)
{
cairo_polygon_t polygon;
cairo_status_t status;
if (path->is_empty_fill)
return CAIRO_STATUS_SUCCESS;
_cairo_polygon_init (&polygon);
_cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
status = _cairo_path_fixed_fill_to_polygon (path,
tolerance,
&polygon);
if (unlikely (status || polygon.num_edges == 0))
goto CLEANUP;
if (path->is_rectilinear) {
status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (traps,
&polygon,
fill_rule);
} else {
status = _cairo_bentley_ottmann_tessellate_polygon (traps,
&polygon,
fill_rule);
}
CLEANUP:
_cairo_polygon_fini (&polygon);
return status;
}
static cairo_region_t *
_cairo_path_fixed_fill_rectilinear_tessellate_to_region (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
const cairo_rectangle_int_t *extents)
{
cairo_box_t box;
cairo_polygon_t polygon;
cairo_traps_t traps;
cairo_status_t status;
cairo_region_t *region;
/* first try to bypass fill-to-polygon */
_cairo_traps_init (&traps);
status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
fill_rule,
&traps);
if (_cairo_status_is_error (status))
goto CLEANUP_TRAPS;
if (status == CAIRO_STATUS_SUCCESS) {
status = _cairo_traps_extract_region (&traps, &region);
goto CLEANUP_TRAPS;
}
/* path is not rectangular, try extracting clipped rectilinear edges */
_cairo_polygon_init (&polygon);
if (extents != NULL) {
_cairo_box_from_rectangle (&box, extents);
_cairo_polygon_limit (&polygon, &box, 1);
}
/* tolerance will be ignored as the path is rectilinear */
status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
if (unlikely (status))
goto CLEANUP_POLYGON;
if (polygon.num_edges == 0) {
region = cairo_region_create ();
} else {
status =
_cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
&polygon,
fill_rule);
if (likely (status == CAIRO_STATUS_SUCCESS))
status = _cairo_traps_extract_region (&traps, &region);
}
CLEANUP_POLYGON:
_cairo_polygon_fini (&polygon);
CLEANUP_TRAPS:
_cairo_traps_fini (&traps);
if (unlikely (status)) { /* XXX _cairo_region_create_in_error() */
region = cairo_region_create ();
if (likely (region->status) == CAIRO_STATUS_SUCCESS)
region->status = status;
}
return region;
}
/* This special-case filler supports only a path that describes a
* device-axis aligned rectangle. It exists to avoid the overhead of
* the general tessellator when drawing very common rectangles.
*
* If the path described anything but a device-axis aligned rectangle,
* this function will return %CAIRO_INT_STATUS_UNSUPPORTED.
* this function will abort.
*/
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
cairo_region_t *
_cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
const cairo_rectangle_int_t *extents)
{
cairo_rectangle_int_t rectangle_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
cairo_box_t box;
cairo_region_t *region = NULL;
if (! path->is_rectilinear)
return CAIRO_INT_STATUS_UNSUPPORTED;
assert (path->maybe_fill_region);
assert (! path->is_empty_fill);
if (_cairo_path_fixed_is_box (path, &box)) {
if (box.p1.x > box.p2.x) {
cairo_fixed_t t;
t = box.p1.x;
box.p1.x = box.p2.x;
box.p2.x = t;
}
if (box.p1.y > box.p2.y) {
cairo_fixed_t t;
t = box.p1.y;
box.p1.y = box.p2.y;
box.p2.y = t;
}
return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
rectangle_stack[0].x = _cairo_fixed_integer_part (box.p1.x);
rectangle_stack[0].y = _cairo_fixed_integer_part (box.p1.y);
rectangle_stack[0].width = _cairo_fixed_integer_part (box.p2.x) -
rectangle_stack[0].x;
rectangle_stack[0].height = _cairo_fixed_integer_part (box.p2.y) -
rectangle_stack[0].y;
if (! _cairo_rectangle_intersect (&rectangle_stack[0], extents))
region = cairo_region_create ();
else
region = cairo_region_create_rectangle (&rectangle_stack[0]);
} else if (fill_rule == CAIRO_FILL_RULE_WINDING) {
cairo_rectangle_int_t *rects = rectangle_stack;
cairo_path_fixed_iter_t iter;
int last_cw = -1;
int size = ARRAY_LENGTH (rectangle_stack);
int count = 0;
/* Support a series of rectangles as can be expected to describe a
* GdkRegion clip region during exposes.
*/
_cairo_path_fixed_iter_init (&iter, path);
while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
cairo_status_t status;
int cw = 0;
if (box.p1.x > box.p2.x) {
@ -242,23 +291,104 @@ _cairo_path_fixed_fill_rectangle (const cairo_path_fixed_t *path,
cw = ! cw;
}
if (last_cw < 0) {
if (last_cw < 0)
last_cw = cw;
} else if (last_cw != cw) {
_cairo_traps_clear (traps);
return CAIRO_INT_STATUS_UNSUPPORTED;
else if (last_cw != cw)
goto TESSELLATE;
if (count == size) {
cairo_rectangle_int_t *new_rects;
size *= 4;
if (rects == rectangle_stack) {
new_rects = _cairo_malloc_ab (size,
sizeof (cairo_rectangle_int_t));
if (unlikely (new_rects == NULL)) {
/* XXX _cairo_region_nil */
break;
}
memcpy (new_rects, rects, sizeof (rectangle_stack));
} else {
new_rects = _cairo_realloc_ab (rects, size,
sizeof (cairo_rectangle_int_t));
if (unlikely (new_rects == NULL)) {
/* XXX _cairo_region_nil */
break;
}
}
rects = new_rects;
}
rects[count].x = _cairo_fixed_integer_part (box.p1.x);
rects[count].y = _cairo_fixed_integer_part (box.p1.y);
rects[count].width = _cairo_fixed_integer_part (box.p2.x) - rects[count].x;
rects[count].height = _cairo_fixed_integer_part (box.p2.y) - rects[count].y;
if (_cairo_rectangle_intersect (&rects[count], extents))
count++;
}
if (_cairo_path_fixed_iter_at_end (&iter))
region = cairo_region_create_rectangles (rects, count);
TESSELLATE:
if (rects != rectangle_stack)
free (rects);
}
if (region == NULL) {
/* Hmm, complex polygon */
region = _cairo_path_fixed_fill_rectilinear_tessellate_to_region (path,
fill_rule,
extents);
}
return region;
}
cairo_int_status_t
_cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_box_t box;
cairo_status_t status;
traps->is_rectilinear = TRUE;
traps->is_rectangular = TRUE;
if (_cairo_path_fixed_is_box (path, &box)) {
return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
} else {
cairo_path_fixed_iter_t iter;
_cairo_path_fixed_iter_init (&iter, path);
while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
if (box.p1.y > box.p2.y) {
cairo_fixed_t t;
t = box.p1.y;
box.p1.y = box.p2.y;
box.p2.y = t;
t = box.p1.x;
box.p1.x = box.p2.x;
box.p2.x = t;
}
status = _cairo_traps_tessellate_rectangle (traps,
&box.p1, &box.p2);
if (unlikely (status))
if (unlikely (status)) {
_cairo_traps_clear (traps);
return status;
}
}
if (_cairo_path_fixed_iter_at_end (&iter))
return CAIRO_STATUS_SUCCESS;
return _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, fill_rule);
_cairo_traps_clear (traps);
return CAIRO_INT_STATUS_UNSUPPORTED;
}
return CAIRO_INT_STATUS_UNSUPPORTED;
}

View file

@ -135,6 +135,20 @@ _cairo_path_fixed_fill_is_empty (const cairo_path_fixed_t *path)
return path->is_empty_fill;
}
static inline cairo_bool_t
_cairo_path_fixed_is_rectilinear_fill (const cairo_path_fixed_t *path)
{
if (! path->is_rectilinear)
return FALSE;
if (! path->has_current_point)
return TRUE;
/* check whether the implicit close preserves the rectilinear property */
return path->current_point.x == path->last_move_point.x ||
path->current_point.y == path->last_move_point.y;
}
static inline cairo_bool_t
_cairo_path_fixed_maybe_fill_region (const cairo_path_fixed_t *path)
{

View file

@ -39,6 +39,7 @@
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
#include "cairo-slope-private.h"
static cairo_status_t
_cairo_path_fixed_add (cairo_path_fixed_t *path,
@ -389,7 +390,7 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path,
if (path->has_current_point && path->is_rectilinear) {
/* a move-to is first an implicit close */
path->is_rectilinear = path->current_point.x == path->last_move_point.x ||
path->current_point.y == path->last_move_point.y;
path->current_point.y == path->last_move_point.y;
path->maybe_fill_region &= path->is_rectilinear;
}
if (path->maybe_fill_region) {
@ -449,23 +450,32 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
* then just change its end-point rather than adding a new op.
*/
if (_cairo_path_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
cairo_path_buf_t *buf;
cairo_point_t *p;
cairo_slope_t prev, self;
buf = cairo_path_tail (path);
if (likely (buf->num_points >= 2)) {
p = &buf->points[buf->num_points-2];
} else {
cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
if (x == path->current_point.x &&
y == path->current_point.y)
{
return CAIRO_STATUS_SUCCESS;
}
_cairo_slope_init (&prev, p, &path->current_point);
_cairo_slope_init (&self, &path->current_point, &point);
if (_cairo_slope_equal (&prev, &self)) {
buf->points[buf->num_points - 1] = point;
status = CAIRO_STATUS_SUCCESS;
goto DONE;
else
{
cairo_path_buf_t *buf;
cairo_point_t *p;
cairo_slope_t prev, self;
buf = cairo_path_tail (path);
if (likely (buf->num_points >= 2)) {
p = &buf->points[buf->num_points-2];
} else {
cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
}
_cairo_slope_init (&prev, p, &path->current_point);
_cairo_slope_init (&self, &path->current_point, &point);
if (_cairo_slope_equal (&prev, &self)) {
buf->points[buf->num_points - 1] = point;
path->current_point = point;
return CAIRO_STATUS_SUCCESS;
}
}
}
@ -483,11 +493,9 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
path->is_empty_fill = path->current_point.x == x &&
path->current_point.y == y;
}
}
DONE:
path->current_point = point;
path->has_current_point = TRUE;
path->current_point = point;
}
return status;
}
@ -566,6 +574,28 @@ _cairo_path_fixed_close_path (cairo_path_fixed_t *path)
if (! path->has_current_point)
return CAIRO_STATUS_SUCCESS;
/* If the previous op was also a LINE_TO back to the start, discard it */
if (_cairo_path_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
if (path->current_point.x == path->last_move_point.x &&
path->current_point.y == path->last_move_point.y)
{
cairo_path_buf_t *buf;
cairo_point_t *p;
buf = cairo_path_tail (path);
if (likely (buf->num_points >= 2)) {
p = &buf->points[buf->num_points-2];
} else {
cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
}
path->current_point = *p;
buf->num_ops--;
buf->num_points--;
}
}
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
if (unlikely (status))
return status;
@ -1070,6 +1100,28 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
&flattener);
}
static inline void
_canonical_box (cairo_box_t *box,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
if (p1->x <= p2->x) {
box->p1.x = p1->x;
box->p2.x = p2->x;
} else {
box->p1.x = p2->x;
box->p2.x = p1->x;
}
if (p1->y <= p2->y) {
box->p1.y = p1->y;
box->p2.y = p2->y;
} else {
box->p1.y = p2->y;
box->p2.y = p1->y;
}
}
/*
* Check whether the given path contains a single rectangle.
*/
@ -1083,7 +1135,7 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
return FALSE;
/* Do we have the right number of ops? */
if (buf->num_ops != 5 && buf->num_ops != 6)
if (buf->num_ops < 4 || buf->num_ops > 6)
return FALSE;
/* Check whether the ops are those that would be used for a rectangle */
@ -1095,22 +1147,25 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
return FALSE;
}
/* Now, there are choices. The rectangle might end with a LINE_TO
* (to the original point), but this isn't required. If it
* doesn't, then it must end with a CLOSE_PATH. */
if (buf->op[4] == CAIRO_PATH_OP_LINE_TO) {
if (buf->points[4].x != buf->points[0].x ||
buf->points[4].y != buf->points[0].y)
/* we accept an implicit close for filled paths */
if (buf->num_ops > 4) {
/* Now, there are choices. The rectangle might end with a LINE_TO
* (to the original point), but this isn't required. If it
* doesn't, then it must end with a CLOSE_PATH. */
if (buf->op[4] == CAIRO_PATH_OP_LINE_TO) {
if (buf->points[4].x != buf->points[0].x ||
buf->points[4].y != buf->points[0].y)
return FALSE;
} else if (buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH) {
return FALSE;
} else if (buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH) {
return FALSE;
}
}
if (buf->num_ops == 6) {
/* A trailing CLOSE_PATH or MOVE_TO is ok */
if (buf->op[5] != CAIRO_PATH_OP_MOVE_TO &&
buf->op[5] != CAIRO_PATH_OP_CLOSE_PATH)
return FALSE;
if (buf->num_ops == 6) {
/* A trailing CLOSE_PATH or MOVE_TO is ok */
if (buf->op[5] != CAIRO_PATH_OP_MOVE_TO &&
buf->op[5] != CAIRO_PATH_OP_CLOSE_PATH)
return FALSE;
}
}
/* Ok, we may have a box, if the points line up */
@ -1119,8 +1174,7 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
buf->points[2].y == buf->points[3].y &&
buf->points[3].x == buf->points[0].x)
{
box->p1 = buf->points[0];
box->p2 = buf->points[2];
_canonical_box (box, &buf->points[0], &buf->points[2]);
return TRUE;
}
@ -1129,8 +1183,7 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
buf->points[2].x == buf->points[3].x &&
buf->points[3].y == buf->points[0].y)
{
box->p1 = buf->points[0];
box->p2 = buf->points[2];
_canonical_box (box, &buf->points[0], &buf->points[2]);
return TRUE;
}
@ -1267,8 +1320,8 @@ _cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter,
points[2].x == points[3].x &&
points[3].y == points[0].y)
{
box->p1 = points[0];
box->p2 = points[2];
box->p1 = points[1];
box->p2 = points[3];
*_iter = iter;
return TRUE;
}

File diff suppressed because it is too large Load diff

View file

@ -2116,7 +2116,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
sampled_area.y += ty;
if ( _cairo_surface_get_extents (surface, &extents)) {
if (attr->extend != CAIRO_EXTEND_REPEAT) {
if (attr->extend == CAIRO_EXTEND_NONE) {
/* Never acquire a larger area than the source itself */
is_empty = _cairo_rectangle_intersect (&extents, &sampled_area);
} else {
@ -2586,9 +2586,14 @@ _cairo_pattern_hash (const cairo_pattern_t *pattern)
return 0;
hash = _cairo_hash_bytes (hash, &pattern->type, sizeof (pattern->type));
hash = _cairo_hash_bytes (hash, &pattern->matrix, sizeof (pattern->matrix));
hash = _cairo_hash_bytes (hash, &pattern->filter, sizeof (pattern->filter));
hash = _cairo_hash_bytes (hash, &pattern->extend, sizeof (pattern->extend));
if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
hash = _cairo_hash_bytes (hash,
&pattern->matrix, sizeof (pattern->matrix));
hash = _cairo_hash_bytes (hash,
&pattern->filter, sizeof (pattern->filter));
hash = _cairo_hash_bytes (hash,
&pattern->extend, sizeof (pattern->extend));
}
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
@ -2745,14 +2750,16 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
if (a->type != b->type)
return FALSE;
if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t)))
return FALSE;
if (a->type != CAIRO_PATTERN_TYPE_SOLID) {
if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t)))
return FALSE;
if (a->filter != b->filter)
return FALSE;
if (a->filter != b->filter)
return FALSE;
if (a->extend != b->extend)
return FALSE;
if (a->extend != b->extend)
return FALSE;
}
switch (a->type) {
case CAIRO_PATTERN_TYPE_SOLID:

View file

@ -250,7 +250,7 @@ _path_covers_bbox (cairo_pdf_surface_t *surface,
{
cairo_box_t box;
return _cairo_path_fixed_is_rectangle (path, &box) &&
return _cairo_path_fixed_is_box (path, &box) &&
box.p1.x <= 0 &&
box.p1.y <= 0 &&
box.p2.x >= _cairo_fixed_from_double (surface->width) &&
@ -1963,8 +1963,6 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
#undef IMAGE_DICTIONARY
if (image_res == NULL)
*image_res = surface->pdf_stream.self;
_cairo_output_stream_write (surface->output, rgb, rgb_size);
status = _cairo_pdf_surface_close_stream (surface);
@ -2950,9 +2948,9 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
dx = fabs (x2 - x1);
dy = fabs (y2 - y1);
if (dx > 1e-6)
x_rep = (int) ceil (surface->width/dx);
x_rep = ceil (surface->width/dx);
if (dy > 1e-6)
y_rep = (int) ceil (surface->height/dy);
y_rep = ceil (surface->height/dy);
repeat_end = MAX (x_rep, y_rep);
repeat_begin = -repeat_end;
@ -3445,8 +3443,8 @@ _cairo_pdf_surface_get_extents (void *abstract_surface,
* mention the arbitrary limitation of width to a short(!). We
* may need to come up with a better interface for get_size.
*/
rectangle->width = (int) ceil (surface->width);
rectangle->height = (int) ceil (surface->height);
rectangle->width = ceil (surface->width);
rectangle->height = ceil (surface->height);
return TRUE;
}

View file

@ -38,6 +38,8 @@
#include "cairoint.h"
#include "cairo-slope-private.h"
static int
_cairo_pen_vertices_needed (double tolerance,
double radius,
@ -393,194 +395,3 @@ _cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen,
return i;
}
static int
_cairo_pen_stroke_spline_add_convolved_point (cairo_pen_stroke_spline_t *stroker,
const cairo_point_t *last_point,
const cairo_slope_t *slope,
cairo_point_t *last_hull_point,
int active,
int step)
{
do {
cairo_point_t hull_point;
hull_point.x = last_point->x + stroker->pen.vertices[active].point.x;
hull_point.y = last_point->y + stroker->pen.vertices[active].point.y;
_cairo_polygon_add_edge (&stroker->polygon,
last_hull_point, &hull_point,
step);
*last_hull_point = hull_point;
/* The strict inequalities here ensure that if a spline slope
* compares identically with either of the slopes of the
* active vertex, then it remains the active vertex. This is
* very important since otherwise we can trigger an infinite
* loop in the case of a degenerate pen, (a line), where
* neither vertex considers itself active for the slope---one
* will consider it as equal and reject, and the other will
* consider it unequal and reject. This is due to the inherent
* ambiguity when comparing slopes that differ by exactly
* pi. */
if (_cairo_slope_compare (slope,
&stroker->pen.vertices[active].slope_ccw) > 0)
{
if (++active == stroker->pen.num_vertices)
active = 0;
}
else if (_cairo_slope_compare (slope,
&stroker->pen.vertices[active].slope_cw) < 0)
{
if (--active == -1)
active = stroker->pen.num_vertices - 1;
}
else
{
return active;
}
} while (TRUE);
}
/* Compute outline of a given spline using the pen.
* The trapezoids needed to fill that outline will be added to traps
*/
cairo_status_t
_cairo_pen_stroke_spline (cairo_pen_stroke_spline_t *stroker,
double tolerance,
cairo_traps_t *traps)
{
cairo_status_t status;
cairo_slope_t slope;
/* If the line width is so small that the pen is reduced to a
single point, then we have nothing to do. */
if (stroker->pen.num_vertices <= 1)
return CAIRO_STATUS_SUCCESS;
/* open the polygon */
slope = stroker->spline.initial_slope;
stroker->forward_vertex =
_cairo_pen_find_active_cw_vertex_index (&stroker->pen, &slope);
stroker->forward_hull_point.x = stroker->last_point.x +
stroker->pen.vertices[stroker->forward_vertex].point.x;
stroker->forward_hull_point.y = stroker->last_point.y +
stroker->pen.vertices[stroker->forward_vertex].point.y;
slope.dx = -slope.dx;
slope.dy = -slope.dy;
stroker->backward_vertex =
_cairo_pen_find_active_cw_vertex_index (&stroker->pen, &slope);
stroker->backward_hull_point.x = stroker->last_point.x +
stroker->pen.vertices[stroker->backward_vertex].point.x;
stroker->backward_hull_point.y = stroker->last_point.y +
stroker->pen.vertices[stroker->backward_vertex].point.y;
_cairo_polygon_add_edge (&stroker->polygon,
&stroker->backward_hull_point,
&stroker->forward_hull_point,
1);
status = _cairo_spline_decompose (&stroker->spline, tolerance);
if (unlikely (status))
return status;
/* close the polygon */
slope = stroker->spline.final_slope;
_cairo_pen_stroke_spline_add_convolved_point (stroker,
&stroker->last_point,
&slope,
&stroker->forward_hull_point,
stroker->forward_vertex,
1);
slope.dx = -slope.dx;
slope.dy = -slope.dy;
_cairo_pen_stroke_spline_add_convolved_point (stroker,
&stroker->last_point,
&slope,
&stroker->backward_hull_point,
stroker->backward_vertex,
-1);
_cairo_polygon_add_edge (&stroker->polygon,
&stroker->forward_hull_point,
&stroker->backward_hull_point,
1);
status = _cairo_polygon_status (&stroker->polygon);
if (unlikely (status))
return status;
status = _cairo_bentley_ottmann_tessellate_polygon (traps,
&stroker->polygon,
CAIRO_FILL_RULE_WINDING);
return status;
}
static cairo_status_t
_cairo_pen_stroke_spline_add_point (void *closure,
const cairo_point_t *point)
{
cairo_pen_stroke_spline_t *stroker = closure;
cairo_slope_t slope;
_cairo_slope_init (&slope, &stroker->last_point, point);
stroker->forward_vertex =
_cairo_pen_stroke_spline_add_convolved_point (stroker,
&stroker->last_point,
&slope,
&stroker->forward_hull_point,
stroker->forward_vertex,
1);
slope.dx = -slope.dx;
slope.dy = -slope.dy;
stroker->backward_vertex =
_cairo_pen_stroke_spline_add_convolved_point (stroker,
&stroker->last_point,
&slope,
&stroker->backward_hull_point,
stroker->backward_vertex,
-1);
stroker->last_point = *point;
return CAIRO_STATUS_SUCCESS;
}
cairo_int_status_t
_cairo_pen_stroke_spline_init (cairo_pen_stroke_spline_t *stroker,
const cairo_pen_t *pen,
const cairo_point_t *a,
const cairo_point_t *b,
const cairo_point_t *c,
const cairo_point_t *d)
{
cairo_int_status_t status;
if (! _cairo_spline_init (&stroker->spline,
_cairo_pen_stroke_spline_add_point,
stroker,
a, b, c, d))
{
return CAIRO_INT_STATUS_DEGENERATE;
}
status = _cairo_pen_init_copy (&stroker->pen, pen);
if (unlikely (status))
return status;
_cairo_polygon_init (&stroker->polygon);
stroker->last_point = *a;
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_pen_stroke_spline_fini (cairo_pen_stroke_spline_t *stroker)
{
_cairo_polygon_fini (&stroker->polygon);
_cairo_pen_fini (&stroker->pen);
}

View file

@ -36,6 +36,8 @@
#include "cairoint.h"
#include "cairo-slope-private.h"
void
_cairo_polygon_init (cairo_polygon_t *polygon)
{
@ -49,6 +51,20 @@ _cairo_polygon_init (cairo_polygon_t *polygon)
polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded);
polygon->has_current_point = FALSE;
polygon->has_current_edge = FALSE;
polygon->num_limits = 0;
polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX;
polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN;
}
void
_cairo_polygon_limit (cairo_polygon_t *polygon,
const cairo_box_t *limits,
int num_limits)
{
polygon->limits = limits;
polygon->num_limits = num_limits;
}
void
@ -93,17 +109,16 @@ _cairo_polygon_grow (cairo_polygon_t *polygon)
return TRUE;
}
void
_cairo_polygon_add_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2,
int dir)
static void
_add_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2,
int top, int bottom,
int dir)
{
cairo_edge_t *edge;
/* drop horizontal edges */
if (p1->y == p2->y)
return;
assert (top < bottom);
if (polygon->num_edges == polygon->edges_size) {
if (! _cairo_polygon_grow (polygon))
@ -111,47 +126,350 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon,
}
edge = &polygon->edges[polygon->num_edges++];
if (p1->y < p2->y) {
edge->edge.p1 = *p1;
edge->edge.p2 = *p2;
edge->dir = dir;
} else {
edge->edge.p1 = *p2;
edge->edge.p2 = *p1;
edge->dir = -dir;
edge->line.p1 = *p1;
edge->line.p2 = *p2;
edge->top = top;
edge->bottom = bottom;
edge->dir = dir;
if (top < polygon->extents.p1.y)
polygon->extents.p1.y = top;
if (bottom > polygon->extents.p2.y)
polygon->extents.p2.y = bottom;
if (p1->x < polygon->extents.p1.x || p1->x > polygon->extents.p2.x) {
cairo_fixed_t x = p1->x;
if (top != p1->y)
x = _cairo_edge_compute_intersection_x_for_y (p1, p2, top);
if (x < polygon->extents.p1.x)
polygon->extents.p1.x = x;
if (x > polygon->extents.p2.x)
polygon->extents.p2.x = x;
}
if (p2->x < polygon->extents.p1.x || p2->x > polygon->extents.p2.x) {
cairo_fixed_t x = p2->x;
if (bottom != p2->y)
x = _cairo_edge_compute_intersection_x_for_y (p1, p2, bottom);
if (x < polygon->extents.p1.x)
polygon->extents.p1.x = x;
if (x > polygon->extents.p2.x)
polygon->extents.p2.x = x;
}
}
void
static void
_add_clipped_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2,
const int top, const int bottom,
const int dir)
{
cairo_point_t p[2];
int top_y, bot_y;
int n;
for (n = 0; n < polygon->num_limits; n++) {
const cairo_box_t *limits = &polygon->limits[n];
if (top >= limits->p2.y)
continue;
if (bottom <= limits->p1.y)
continue;
if (p1->x <= limits->p1.x && p2->x <= limits->p1.x)
{
p[0].x = limits->p1.x;
p[0].y = limits->p1.y;
top_y = top;
if (top_y < p[0].y)
top_y = p[0].y;
p[1].x = limits->p1.x;
p[1].y = limits->p2.y;
bot_y = bottom;
if (bot_y > p[1].y)
bot_y = p[1].y;
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
}
else if (p1->x >= limits->p2.x && p2->x >= limits->p2.x)
{
p[0].x = limits->p2.x;
p[0].y = limits->p1.y;
top_y = top;
if (top_y < p[0].y)
top_y = p[0].y;
p[1].x = limits->p2.x;
p[1].y = limits->p2.y;
bot_y = bottom;
if (bot_y > p[1].y)
bot_y = p[1].y;
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
}
else if (p1->x >= limits->p1.x && p2->x >= limits->p1.x &&
p1->x <= limits->p2.x && p2->x <= limits->p2.x)
{
top_y = top;
if (top_y < limits->p1.y)
top_y = limits->p1.y;
bot_y = bottom;
if (bot_y > limits->p2.y)
bot_y = limits->p2.y;
_add_edge (polygon, p1, p2, top_y, bot_y, dir);
}
else
{
int left_y, right_y;
int p1_y, p2_y;
left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
limits->p1.x);
right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
limits->p2.x);
if (left_y == right_y) /* horizontal within bounds */
return;
p1_y = top;
p2_y = bottom;
if (left_y < right_y) {
if (p1->x < limits->p1.x && left_y > limits->p1.y) {
p[0].x = limits->p1.x;
p[0].y = limits->p1.y;
top_y = p1_y;
if (top_y < p[0].y)
top_y = p[0].y;
p[1].x = limits->p1.x;
p[1].y = limits->p2.y;
bot_y = left_y;
if (bot_y > p[1].y)
bot_y = p[1].y;
if (bot_y > top_y)
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
p1_y = bot_y;
}
if (p2->x > limits->p2.x && right_y < limits->p2.y) {
p[0].x = limits->p2.x;
p[0].y = limits->p1.y;
top_y = right_y;
if (top_y < p[0].y)
top_y = p[0].y;
p[1].x = limits->p2.x;
p[1].y = limits->p2.y;
bot_y = p2_y;
if (bot_y > p[1].y)
bot_y = p[1].y;
if (bot_y > top_y)
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
p2_y = top_y;
}
} else {
if (p1->x > limits->p2.x && right_y > limits->p1.y) {
p[0].x = limits->p2.x;
p[0].y = limits->p1.y;
top_y = p1_y;
if (top_y < p[0].y)
top_y = p[0].y;
p[1].x = limits->p2.x;
p[1].y = limits->p2.y;
bot_y = right_y;
if (bot_y > p[1].y)
bot_y = p[1].y;
if (bot_y > top_y)
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
p1_y = bot_y;
}
if (p2->x < limits->p1.x && left_y < limits->p2.y) {
p[0].x = limits->p1.x;
p[0].y = limits->p1.y;
top_y = left_y;
if (top_y < p[0].y)
top_y = p[0].y;
p[1].x = limits->p1.x;
p[1].y = limits->p2.y;
bot_y = p2_y;
if (bot_y > p[1].y)
bot_y = p[1].y;
if (bot_y > top_y)
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
p2_y = top_y;
}
}
if (p1_y < limits->p1.y)
p1_y = limits->p1.y;
if (p2_y > limits->p2.y)
p2_y = limits->p2.y;
if (p2_y > p1_y)
_add_edge (polygon, p1, p2, p1_y, p2_y, dir);
}
}
}
static void
_cairo_polygon_add_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
int dir;
/* drop horizontal edges */
if (p1->y == p2->y)
return;
if (p1->y < p2->y) {
dir = 1;
} else {
const cairo_point_t *t;
t = p1, p1 = p2, p2 = t;
dir = -1;
}
if (polygon->num_limits) {
if (p2->y <= polygon->limits[0].p1.y)
return;
if (p1->y >= polygon->limits[polygon->num_limits-1].p2.y)
return;
_add_clipped_edge (polygon, p1, p2, p1->y, p2->y, dir);
} else
_add_edge (polygon, p1, p2, p1->y, p2->y, dir);
}
cairo_status_t
_cairo_polygon_add_external_edge (void *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
_cairo_polygon_add_edge (polygon, p1, p2);
return _cairo_polygon_status (polygon);
}
cairo_status_t
_cairo_polygon_add_line (cairo_polygon_t *polygon,
const cairo_line_t *line,
int top, int bottom,
int dir)
{
/* drop horizontal edges */
if (line->p1.y == line->p2.y)
return CAIRO_STATUS_SUCCESS;
if (bottom <= top)
return CAIRO_STATUS_SUCCESS;
if (polygon->num_limits) {
if (line->p2.y <= polygon->limits[0].p1.y)
return CAIRO_STATUS_SUCCESS;
if (line->p1.y >= polygon->limits[polygon->num_limits-1].p2.y)
return CAIRO_STATUS_SUCCESS;
_add_clipped_edge (polygon, &line->p1, &line->p2, top, bottom, dir);
} else
_add_edge (polygon, &line->p1, &line->p2, top, bottom, dir);
return polygon->status;
}
/* flattened path operations */
cairo_status_t
_cairo_polygon_move_to (cairo_polygon_t *polygon,
const cairo_point_t *point)
{
if (! polygon->has_current_point)
if (polygon->has_current_edge) {
_cairo_polygon_add_edge (polygon,
&polygon->last_point,
&polygon->current_point);
polygon->has_current_edge = FALSE;
}
if (! polygon->has_current_point) {
polygon->first_point = *point;
polygon->has_current_point = TRUE;
}
polygon->current_point = *point;
polygon->has_current_point = TRUE;
return polygon->status;
}
void
cairo_status_t
_cairo_polygon_line_to (cairo_polygon_t *polygon,
const cairo_point_t *point)
{
if (polygon->has_current_point)
_cairo_polygon_add_edge (polygon, &polygon->current_point, point, 1);
/* squash collinear edges */
if (polygon->has_current_edge) {
if (polygon->current_point.x != point->x ||
polygon->current_point.y != point->y)
{
cairo_slope_t this;
_cairo_polygon_move_to (polygon, point);
_cairo_slope_init (&this, &polygon->current_point, point);
if (_cairo_slope_equal (&polygon->current_edge, &this)) {
polygon->current_point = *point;
return CAIRO_STATUS_SUCCESS;
}
_cairo_polygon_add_edge (polygon,
&polygon->last_point,
&polygon->current_point);
polygon->last_point = polygon->current_point;
polygon->current_edge = this;
}
} else if (polygon->has_current_point) {
if (polygon->current_point.x != point->x ||
polygon->current_point.y != point->y)
{
polygon->last_point = polygon->current_point;
_cairo_slope_init (&polygon->current_edge,
&polygon->last_point,
point);
polygon->has_current_edge = TRUE;
}
} else {
polygon->first_point = *point;
polygon->has_current_point = TRUE;
}
polygon->current_point = *point;
return polygon->status;
}
void
cairo_status_t
_cairo_polygon_close (cairo_polygon_t *polygon)
{
if (polygon->has_current_point) {
_cairo_polygon_add_edge (polygon,
&polygon->current_point,
&polygon->first_point,
1);
cairo_status_t status;
if (polygon->has_current_point) {
status = _cairo_polygon_line_to (polygon, &polygon->first_point);
polygon->has_current_point = FALSE;
}
if (polygon->has_current_edge) {
_cairo_polygon_add_edge (polygon,
&polygon->last_point,
&polygon->current_point);
polygon->has_current_edge = FALSE;
}
return polygon->status;
}

View file

@ -714,7 +714,7 @@ _path_covers_bbox (cairo_ps_surface_t *surface,
{
cairo_box_t box;
if (_cairo_path_fixed_is_rectangle (path, &box)) {
if (_cairo_path_fixed_is_box (path, &box)) {
cairo_rectangle_int_t rect;
_cairo_box_round_to_rectangle (&box, &rect);
@ -1919,10 +1919,14 @@ _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
_cairo_output_stream_write (base85_stream, data, length);
status = _cairo_output_stream_destroy (base85_stream);
/* Mark end of base85 data */
_cairo_output_stream_printf (string_array_stream, "~>");
status2 = _cairo_output_stream_destroy (string_array_stream);
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
return status;
}
@ -2972,9 +2976,9 @@ _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface,
dx = fabs (x2 - x1);
dy = fabs (y2 - y1);
if (dx > 1e-6)
x_rep = (int) ceil (surface->width/dx);
x_rep = ceil (surface->width/dx);
if (dy > 1e-6)
y_rep = (int) ceil (surface->height/dy);
y_rep = ceil (surface->height/dy);
repeat_end = MAX (x_rep, y_rep);
repeat_begin = -repeat_end;
@ -3214,8 +3218,8 @@ _cairo_ps_surface_get_extents (void *abstract_surface,
* mention the aribitray limitation of width to a short(!). We
* may need to come up with a better interface for get_extents.
*/
rectangle->width = (int) ceil (surface->width);
rectangle->height = (int) ceil (surface->height);
rectangle->width = ceil (surface->width);
rectangle->height = ceil (surface->height);
return TRUE;
}
@ -3497,15 +3501,15 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface,
int x1, y1, x2, y2;
if (surface->eps) {
x1 = (int) floor (_cairo_fixed_to_double (bbox->p1.x));
y1 = (int) floor (surface->height - _cairo_fixed_to_double (bbox->p2.y));
x2 = (int) ceil (_cairo_fixed_to_double (bbox->p2.x));
y2 = (int) ceil (surface->height - _cairo_fixed_to_double (bbox->p1.y));
x1 = floor (_cairo_fixed_to_double (bbox->p1.x));
y1 = floor (surface->height - _cairo_fixed_to_double (bbox->p2.y));
x2 = ceil (_cairo_fixed_to_double (bbox->p2.x));
y2 = ceil (surface->height - _cairo_fixed_to_double (bbox->p1.y));
} else {
x1 = 0;
y1 = 0;
x2 = (int) ceil (surface->width);
y2 = (int) ceil (surface->height);
x2 = ceil (surface->width);
y2 = ceil (surface->height);
}
surface->page_bbox.x = x1;

View file

@ -323,7 +323,7 @@ _qmatrix_from_cairo_matrix (const cairo_matrix_t& m)
/** Path conversion **/
typedef struct _qpainter_path_transform {
QPainterPath *path;
QPainterPath path;
cairo_matrix_t *ctm_inverse;
} qpainter_path_data;
@ -331,14 +331,14 @@ typedef struct _qpainter_path_transform {
static cairo_status_t
_cairo_path_to_qpainterpath_move_to (void *closure, const cairo_point_t *point)
{
qpainter_path_data *pdata = (qpainter_path_data *)closure;
qpainter_path_data *pdata = static_cast <qpainter_path_data *> (closure);
double x = _cairo_fixed_to_double (point->x);
double y = _cairo_fixed_to_double (point->y);
if (pdata->ctm_inverse)
cairo_matrix_transform_point (pdata->ctm_inverse, &x, &y);
pdata->path->moveTo(x, y);
pdata->path.moveTo(x, y);
return CAIRO_STATUS_SUCCESS;
}
@ -346,19 +346,14 @@ _cairo_path_to_qpainterpath_move_to (void *closure, const cairo_point_t *point)
static cairo_status_t
_cairo_path_to_qpainterpath_line_to (void *closure, const cairo_point_t *point)
{
qpainter_path_data *pdata = (qpainter_path_data *)closure;
qpainter_path_data *pdata = static_cast <qpainter_path_data *> (closure);
double x = _cairo_fixed_to_double (point->x);
double y = _cairo_fixed_to_double (point->y);
if (pdata->ctm_inverse)
cairo_matrix_transform_point (pdata->ctm_inverse, &x, &y);
pdata->path->lineTo(x, y);
if (pdata->path->isEmpty())
pdata->path->moveTo(x, y);
else
pdata->path->lineTo(x, y);
pdata->path.lineTo(x, y);
return CAIRO_STATUS_SUCCESS;
}
@ -366,7 +361,7 @@ _cairo_path_to_qpainterpath_line_to (void *closure, const cairo_point_t *point)
static cairo_status_t
_cairo_path_to_qpainterpath_curve_to (void *closure, const cairo_point_t *p0, const cairo_point_t *p1, const cairo_point_t *p2)
{
qpainter_path_data *pdata = (qpainter_path_data *)closure;
qpainter_path_data *pdata = static_cast <qpainter_path_data *> (closure);
double x0 = _cairo_fixed_to_double (p0->x);
double y0 = _cairo_fixed_to_double (p0->y);
double x1 = _cairo_fixed_to_double (p1->x);
@ -380,7 +375,7 @@ _cairo_path_to_qpainterpath_curve_to (void *closure, const cairo_point_t *p0, co
cairo_matrix_transform_point (pdata->ctm_inverse, &x2, &y2);
}
pdata->path->cubicTo (x0, y0, x1, y1, x2, y2);
pdata->path.cubicTo (x0, y0, x1, y1, x2, y2);
return CAIRO_STATUS_SUCCESS;
}
@ -388,42 +383,48 @@ _cairo_path_to_qpainterpath_curve_to (void *closure, const cairo_point_t *p0, co
static cairo_status_t
_cairo_path_to_qpainterpath_close_path (void *closure)
{
qpainter_path_data *pdata = (qpainter_path_data *)closure;
qpainter_path_data *pdata = static_cast <qpainter_path_data *> (closure);
pdata->path->closeSubpath();
pdata->path.closeSubpath();
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_quartz_cairo_path_to_qpainterpath (cairo_path_fixed_t *path,
QPainterPath *qpath,
cairo_fill_rule_t fill_rule,
cairo_matrix_t *ctm_inverse = NULL)
static inline QPainterPath
path_to_qt (cairo_path_fixed_t *path,
cairo_matrix_t *ctm_inverse = NULL)
{
qpainter_path_data pdata = { qpath, ctm_inverse };
qpainter_path_data data;
cairo_status_t status;
qpath->setFillRule (fill_rule == CAIRO_FILL_RULE_WINDING ?
if (ctm_inverse && _cairo_matrix_is_identity (ctm_inverse))
ctm_inverse = NULL;
data.ctm_inverse = ctm_inverse;
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_path_to_qpainterpath_move_to,
_cairo_path_to_qpainterpath_line_to,
_cairo_path_to_qpainterpath_curve_to,
_cairo_path_to_qpainterpath_close_path,
&data);
assert (status == CAIRO_STATUS_SUCCESS);
return data.path;
}
static inline QPainterPath
path_to_qt (cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_matrix_t *ctm_inverse = NULL)
{
QPainterPath qpath = path_to_qt (path, ctm_inverse);
qpath.setFillRule (fill_rule == CAIRO_FILL_RULE_WINDING ?
Qt::WindingFill :
Qt::OddEvenFill);
return _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_path_to_qpainterpath_move_to,
_cairo_path_to_qpainterpath_line_to,
_cairo_path_to_qpainterpath_curve_to,
_cairo_path_to_qpainterpath_close_path,
&pdata);
}
static cairo_status_t
_cairo_quartz_cairo_path_to_qpainterpath (cairo_path_fixed_t *path,
QPainterPath *qpath,
cairo_matrix_t *ctm_inverse)
{
return _cairo_quartz_cairo_path_to_qpainterpath (path, qpath,
CAIRO_FILL_RULE_WINDING,
ctm_inverse);
return qpath;
}
/**
@ -722,17 +723,8 @@ _cairo_qt_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
qs->p->save ();
}
} else {
QPainterPath qpath;
cairo_status_t status;
// XXX Antialiasing is ignored
status = _cairo_quartz_cairo_path_to_qpainterpath (path,
&qpath,
fill_rule);
if (unlikely (status))
return status;
qs->p->setClipPath (qpath, Qt::IntersectClip);
qs->p->setClipPath (path_to_qt (path, fill_rule), Qt::IntersectClip);
}
return CAIRO_STATUS_SUCCESS;
@ -1042,6 +1034,7 @@ struct PatternToBrushConverter {
QBrush mBrush;
private:
cairo_surface_t *mAcquiredImageParent;
cairo_image_surface_t *mAcquiredImage;
void *mAcquiredImageExtra;
@ -1322,14 +1315,8 @@ _cairo_qt_surface_fill (void *abstract_surface,
if (! _cairo_qt_fast_fill (qs, source,
path, fill_rule, tolerance, antialias))
{
QPainterPath qpath;
cairo_status_t status;
status = _cairo_quartz_cairo_path_to_qpainterpath (path, &qpath, fill_rule);
assert (status == CAIRO_STATUS_SUCCESS);
PatternToBrushConverter brush(source);
qs->p->fillPath (qpath, brush);
qs->p->fillPath (path_to_qt (path, fill_rule), brush);
}
if (qs->supports_porter_duff)
@ -1364,14 +1351,6 @@ _cairo_qt_surface_stroke (void *abstract_surface,
if (unlikely (int_status))
return int_status;
QPainterPath qpath;
cairo_status_t status;
if (_cairo_matrix_is_identity (ctm_inverse))
ctm_inverse = NULL;
status = _cairo_quartz_cairo_path_to_qpainterpath (path, &qpath,
ctm_inverse);
assert (status == CAIRO_STATUS_SUCCESS);
QMatrix savedMatrix = qs->p->worldMatrix();
@ -1387,7 +1366,7 @@ _cairo_qt_surface_stroke (void *abstract_surface,
PatternToPenConverter pen(source, style);
qs->p->setPen(pen);
qs->p->drawPath(qpath);
qs->p->drawPath(path_to_qt (path, ctm_inverse));
qs->p->setPen(Qt::black);
qs->p->setWorldMatrix (savedMatrix, false);

View file

@ -71,6 +71,29 @@ _cairo_box_from_rectangle (cairo_box_t *box,
box->p2.y = _cairo_fixed_from_int (rect->y + rect->height);
}
void
_cairo_boxes_get_extents (const cairo_box_t *boxes,
int num_boxes,
cairo_box_t *extents)
{
int n;
assert (num_boxes > 0);
*extents = *boxes;
for (n = 1; n < num_boxes; n++) {
if (boxes[n].p1.x < extents->p1.x)
extents->p1.x = boxes[n].p1.x;
if (boxes[n].p2.x > extents->p2.x)
extents->p2.x = boxes[n].p2.x;
if (boxes[n].p1.y < extents->p1.y)
extents->p1.y = boxes[n].p1.y;
if (boxes[n].p2.y > extents->p2.y)
extents->p2.y = boxes[n].p2.y;
}
}
/* XXX We currently have a confusing mix of boxes and rectangles as
* exemplified by this function. A #cairo_box_t is a rectangular area
* represented by the coordinates of the upper left and lower right

View file

@ -60,11 +60,6 @@ cairo_private void
_cairo_region_init_rectangle (cairo_region_t *region,
const cairo_rectangle_int_t *rectangle);
cairo_private cairo_status_t
_cairo_region_init_rectangles (cairo_region_t *region,
const cairo_rectangle_int_t *rects,
int count);
cairo_private void
_cairo_region_fini (cairo_region_t *region);

View file

@ -144,23 +144,28 @@ cairo_region_create (void)
}
slim_hidden_def (cairo_region_create);
cairo_status_t
_cairo_region_init_rectangles (cairo_region_t *region,
const cairo_rectangle_int_t *rects,
int count)
cairo_region_t *
cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
int count)
{
pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
pixman_box32_t *pboxes = stack_pboxes;
cairo_status_t status;
cairo_region_t *region;
int i;
status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
region = _cairo_malloc (sizeof (cairo_region_t));
if (unlikely (region == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_region_t *) &_cairo_region_nil;
}
if (count > ARRAY_LENGTH (stack_pboxes)) {
pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
if (unlikely (pboxes == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (unlikely (pboxes == NULL)) {
free (region);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_region_t *) &_cairo_region_nil;
}
}
for (i = 0; i < count; i++) {
@ -170,35 +175,19 @@ _cairo_region_init_rectangles (cairo_region_t *region,
pboxes[i].y2 = rects[i].y + rects[i].height;
}
if (! pixman_region32_init_rects (&region->rgn, pboxes, count))
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
i = pixman_region32_init_rects (&region->rgn, pboxes, count);
if (pboxes != stack_pboxes)
free (pboxes);
return region->status = status;
}
cairo_region_t *
cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
int count)
{
cairo_region_t *region;
cairo_status_t status;
region = _cairo_malloc (sizeof (cairo_region_t));
if (unlikely (region == NULL)) {
if (unlikely (i == 0)) {
free (region);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_region_t *) &_cairo_region_nil;
}
status = _cairo_region_init_rectangles (region, rects, count);
if (unlikely (status)) {
cairo_region_destroy (region);
return (cairo_region_t *) &_cairo_region_nil;
}
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
region->status = CAIRO_STATUS_SUCCESS;
return region;
}
slim_hidden_def (cairo_region_create_rectangles);
@ -437,7 +426,7 @@ slim_hidden_def (cairo_region_status);
* Since: 1.10
**/
cairo_status_t
cairo_region_subtract (cairo_region_t *dst, cairo_region_t *other)
cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other)
{
if (dst->status)
return dst->status;
@ -445,8 +434,12 @@ cairo_region_subtract (cairo_region_t *dst, cairo_region_t *other)
if (other->status)
return _cairo_region_set_error (dst, other->status);
if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, &other->rgn))
if (! pixman_region32_subtract (&dst->rgn,
&dst->rgn,
CONST_CAST &other->rgn))
{
return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
}
return CAIRO_STATUS_SUCCESS;
}

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