mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-04 21:08:10 +02:00
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:
commit
19ebf83b67
353 changed files with 18884 additions and 4693 deletions
18
NEWS
18
NEWS
|
|
@ -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)
|
||||
===========================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
52
boilerplate/cairo-boilerplate-skia.c
Normal file
52
boilerplate/cairo-boilerplate-skia.c
Normal 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)
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
46
configure.ac
46
configure.ac
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
751
perf/cairo-perf-chart.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
149
perf/spiral.c
149
perf/spiral.c
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
143
src/cairo-base64-stream.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
733
src/cairo-bentley-ottmann-rectangular.c
Normal file
733
src/cairo-bentley-ottmann-rectangular.c
Normal 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;
|
||||
}
|
||||
582
src/cairo-bentley-ottmann-rectilinear.c
Normal file
582
src/cairo-bentley-ottmann-rectilinear.c
Normal 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
|
|
@ -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,
|
||||
|
|
|
|||
844
src/cairo-clip.c
844
src/cairo-clip.c
File diff suppressed because it is too large
Load diff
|
|
@ -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); \
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@
|
|||
|
||||
#include "cairoint.h"
|
||||
|
||||
#include "cairo-slope-private.h"
|
||||
|
||||
typedef struct cairo_hull {
|
||||
cairo_point_t point;
|
||||
cairo_slope_t slope;
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, ®ion);
|
||||
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, ®ion);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
193
src/cairo-pen.c
193
src/cairo-pen.c
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 (®ion->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 (®ion->rgn, pboxes, count))
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
i = pixman_region32_init_rects (®ion->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 (®ion->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
Loading…
Add table
Reference in a new issue