diff options
author | mh0310.choi <mh0310.choi@samsung.com> | 2015-07-28 10:46:57 +0900 |
---|---|---|
committer | mh0310.choi <mh0310.choi@samsung.com> | 2015-07-28 13:08:12 +0900 |
commit | 5e67a6f721eaedda61300baf0799199c7771ebd0 (patch) | |
tree | 6cd50b52498aab50e79b966cdccc2a137db316d9 /src | |
parent | d3aeffba37161d2b76b29c4ea13369bd67a47a8e (diff) | |
download | cairo-5e67a6f721eaedda61300baf0799199c7771ebd0.tar.gz cairo-5e67a6f721eaedda61300baf0799199c7771ebd0.tar.bz2 cairo-5e67a6f721eaedda61300baf0799199c7771ebd0.zip |
Cairo version Upgrade for Tizen3.0submit/tizen_tv/20150728.091927submit/tizen_mobile/20150728.091912submit/tizen_common/20150728.091859accepted/tizen/tv/20150729.011254accepted/tizen/mobile/20150729.011230
- from 1.12.14 to 1.14.2
Change-Id: I3b62d212041b337bbb926d579f9ce74f42a45c3b
Diffstat (limited to 'src')
396 files changed, 7571 insertions, 5985 deletions
diff --git a/src/.gitignore b/src/.gitignore index fd53c8649..534263a15 100755..100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -31,3 +31,7 @@ check-has-hidden-symbols.i check-link check-skiplist headers-standalone +!cairo.pc.in +!cairo-uninstalled.pc.in +!cairo-features.pc.in +!cairo-features-uninstalled.pc.in diff --git a/src/Makefile.am b/src/Makefile.am index acf0a8281..acf0a8281 100755..100644 --- a/src/Makefile.am +++ b/src/Makefile.am diff --git a/src/Makefile.am.analysis b/src/Makefile.am.analysis index fab4cf7a5..fab4cf7a5 100755..100644 --- a/src/Makefile.am.analysis +++ b/src/Makefile.am.analysis diff --git a/src/Makefile.sources b/src/Makefile.sources index 0c9bfbe54..558065cbe 100755..100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -86,6 +86,8 @@ cairo_private = \ cairo-image-info-private.h \ cairo-image-surface-inline.h \ cairo-image-surface-private.h \ + cairo-line-inline.h \ + cairo-line-private.h \ cairo-list-inline.h \ cairo-list-private.h \ cairo-malloc-private.h \ @@ -101,6 +103,7 @@ cairo_private = \ cairo-path-private.h \ cairo-pattern-inline.h \ cairo-pattern-private.h \ + cairo-pixman-private.h \ cairo-private.h \ cairo-recording-surface-inline.h \ cairo-recording-surface-private.h \ @@ -130,11 +133,11 @@ cairo_private = \ cairo-time-private.h \ cairo-types-private.h \ cairo-traps-private.h \ + cairo-convex-fill-private.h \ cairo-tristrip-private.h \ cairo-user-font-private.h \ cairo-wideint-private.h \ cairo-wideint-type-private.h \ - cairo-thread-local-private.h \ $(NULL) cairo_sources = \ cairo-analysis-surface.c \ @@ -182,6 +185,7 @@ cairo_sources = \ cairo-image-info.c \ cairo-image-source.c \ cairo-image-surface.c \ + cairo-line.c \ cairo-lzw.c \ cairo-matrix.c \ cairo-mask-compositor.c \ @@ -198,6 +202,7 @@ cairo_sources = \ cairo-path.c \ cairo-path-fill.c \ cairo-path-fixed.c \ + cairo-convex-fill.c \ cairo-path-in-fill.c \ cairo-path-stroke.c \ cairo-path-stroke-boxes.c \ @@ -268,6 +273,7 @@ cairo_sources += $(_cairo_font_subset_sources) cairo_egl_sources = cairo_glx_sources = cairo_wgl_sources = +cairo_cgl_sources = _cairo_pdf_operators_private = cairo-pdf-operators-private.h cairo-pdf-shading-private.h _cairo_pdf_operators_sources = cairo-pdf-operators.c cairo-pdf-shading.c @@ -342,6 +348,7 @@ cairo_xcb_sources = \ cairo-xcb-surface.c \ cairo-xcb-surface-core.c \ cairo-xcb-surface-render.c \ + cairo-xcb-resources.c \ $(NULL) cairo_qt_headers = cairo-qt.h @@ -418,6 +425,9 @@ cairo_glesv3_headers = $(cairo_gl_headers) cairo_glesv3_private = $(cairo_gl_private) cairo_glesv3_sources = $(cairo_gl_sources) +cairo_evasgl_headers = +cairo_evasgl_private = +cairo_evasgl_sources = if CAIRO_HAS_EVASGL_SURFACE if CAIRO_HAS_GL_SURFACE cairo_evasgl_headers = @@ -440,10 +450,6 @@ cairo_evasgl_sources = $(cairo_gl_sources) endif endif endif -else -cairo_evasgl_headers = -cairo_evasgl_private = -cairo_evasgl_sources = endif cairo_egl_sources += cairo-egl-context.c @@ -451,6 +457,7 @@ cairo_glx_sources += cairo-glx-context.c cairo_wgl_sources += cairo-wgl-context.c cairo_evasgl_headers += cairo-evas-gl.h cairo_evasgl_sources += cairo-evas-gl-context.c +cairo_cgl_sources += cairo-cgl-context.c cairo_directfb_headers = cairo-directfb.h cairo_directfb_sources = cairo-directfb-surface.c @@ -511,11 +518,3 @@ cairo_cogl_sources = cairo-cogl-surface.c \ cairo-cogl-gradient.c \ cairo-cogl-context.c \ cairo-cogl-utils.c - -cairo_tg_headers = cairo-tg.h -cairo_tg_private = cairo-tg-private.h \ - cairo-tg-allocator-private.h \ - cairo-tg-journal-private.h \ - cairo-tg-composite-extents-private.h -cairo_tg_sources = cairo-tg-surface.c \ - cairo-tg-journal.c diff --git a/src/Makefile.win32 b/src/Makefile.win32 index 864791f37..864791f37 100755..100644 --- a/src/Makefile.win32 +++ b/src/Makefile.win32 diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features index 268117094..fe7627c9c 100755..100644 --- a/src/Makefile.win32.features +++ b/src/Makefile.win32.features @@ -21,24 +21,6 @@ enabled_cairo_sources = $(cairo_sources) all_cairo_pkgconf = cairo.pc enabled_cairo_pkgconf = cairo.pc -all_cairo_private += $(cairo_tls_private) $(cairo_tls_headers) -all_cairo_cxx_sources += $(cairo_tls_cxx_sources) -all_cairo_sources += $(cairo_tls_sources) -ifeq ($(CAIRO_HAS_TLS),1) -enabled_cairo_private += $(cairo_tls_private) $(cairo_tls_headers) -enabled_cairo_cxx_sources += $(cairo_tls_cxx_sources) -enabled_cairo_sources += $(cairo_tls_sources) -endif - -all_cairo_private += $(cairo_pthread_setspecific_private) $(cairo_pthread_setspecific_headers) -all_cairo_cxx_sources += $(cairo_pthread_setspecific_cxx_sources) -all_cairo_sources += $(cairo_pthread_setspecific_sources) -ifeq ($(CAIRO_HAS_PTHREAD_SETSPECIFIC),1) -enabled_cairo_private += $(cairo_pthread_setspecific_private) $(cairo_pthread_setspecific_headers) -enabled_cairo_cxx_sources += $(cairo_pthread_setspecific_cxx_sources) -enabled_cairo_sources += $(cairo_pthread_setspecific_sources) -endif - supported_cairo_headers += $(cairo_xlib_headers) all_cairo_headers += $(cairo_xlib_headers) all_cairo_private += $(cairo_xlib_private) @@ -407,22 +389,6 @@ ifeq ($(CAIRO_HAS_DIRECTFB_SURFACE),1) enabled_cairo_pkgconf += cairo-directfb.pc endif -unsupported_cairo_headers += $(cairo_tg_headers) -all_cairo_headers += $(cairo_tg_headers) -all_cairo_private += $(cairo_tg_private) -all_cairo_cxx_sources += $(cairo_tg_cxx_sources) -all_cairo_sources += $(cairo_tg_sources) -ifeq ($(CAIRO_HAS_TG_SURFACE),1) -enabled_cairo_headers += $(cairo_tg_headers) -enabled_cairo_private += $(cairo_tg_private) -enabled_cairo_cxx_sources += $(cairo_tg_cxx_sources) -enabled_cairo_sources += $(cairo_tg_sources) -endif -all_cairo_pkgconf += cairo-tg.pc -ifeq ($(CAIRO_HAS_TG_SURFACE),1) -enabled_cairo_pkgconf += cairo-tg.pc -endif - unsupported_cairo_headers += $(cairo_vg_headers) all_cairo_headers += $(cairo_vg_headers) all_cairo_private += $(cairo_vg_private) @@ -471,6 +437,22 @@ ifeq ($(CAIRO_HAS_GLX_FUNCTIONS),1) enabled_cairo_pkgconf += cairo-glx.pc endif +supported_cairo_headers += $(cairo_cgl_headers) +all_cairo_headers += $(cairo_cgl_headers) +all_cairo_private += $(cairo_cgl_private) +all_cairo_cxx_sources += $(cairo_cgl_cxx_sources) +all_cairo_sources += $(cairo_cgl_sources) +ifeq ($(CAIRO_HAS_CGL_FUNCTIONS),1) +enabled_cairo_headers += $(cairo_cgl_headers) +enabled_cairo_private += $(cairo_cgl_private) +enabled_cairo_cxx_sources += $(cairo_cgl_cxx_sources) +enabled_cairo_sources += $(cairo_cgl_sources) +endif +all_cairo_pkgconf += cairo-cgl.pc +ifeq ($(CAIRO_HAS_CGL_FUNCTIONS),1) +enabled_cairo_pkgconf += cairo-cgl.pc +endif + supported_cairo_headers += $(cairo_wgl_headers) all_cairo_headers += $(cairo_wgl_headers) all_cairo_private += $(cairo_wgl_private) @@ -674,15 +656,6 @@ enabled_cairo_private += $(cairo_user_private) enabled_cairo_cxx_sources += $(cairo_user_cxx_sources) enabled_cairo_sources += $(cairo_user_sources) -all_cairo_private += $(cairo_openmp_private) $(cairo_openmp_headers) -all_cairo_cxx_sources += $(cairo_openmp_cxx_sources) -all_cairo_sources += $(cairo_openmp_sources) -ifeq ($(CAIRO_HAS_OPENMP),1) -enabled_cairo_private += $(cairo_openmp_private) $(cairo_openmp_headers) -enabled_cairo_cxx_sources += $(cairo_openmp_cxx_sources) -enabled_cairo_sources += $(cairo_openmp_sources) -endif - all_cairo_private += $(cairo_pthread_private) $(cairo_pthread_headers) all_cairo_cxx_sources += $(cairo_pthread_cxx_sources) all_cairo_sources += $(cairo_pthread_sources) diff --git a/src/README b/src/README index 03e4455ea..03e4455ea 100755..100644 --- a/src/README +++ b/src/README diff --git a/src/cairo-analysis-surface-private.h b/src/cairo-analysis-surface-private.h index 1e054c209..1e054c209 100755..100644 --- a/src/cairo-analysis-surface-private.h +++ b/src/cairo-analysis-surface-private.h diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index 6717f7369..6717f7369 100755..100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c diff --git a/src/cairo-arc-private.h b/src/cairo-arc-private.h index a22c01ac9..a22c01ac9 100755..100644 --- a/src/cairo-arc-private.h +++ b/src/cairo-arc-private.h diff --git a/src/cairo-arc.c b/src/cairo-arc.c index 5cbd11238..390397bae 100755..100644 --- a/src/cairo-arc.c +++ b/src/cairo-arc.c @@ -236,6 +236,10 @@ _cairo_arc_in_direction (cairo_t *cr, step = -step; } + cairo_line_to (cr, + xc + radius * cos (angle_min), + yc + radius * sin (angle_min)); + for (i = 0; i < segments; i++, angle_min += step) { _cairo_arc_segment (cr, xc, yc, radius, angle_min, angle_min + step); diff --git a/src/cairo-array-private.h b/src/cairo-array-private.h index 35b29e5fc..35b29e5fc 100755..100644 --- a/src/cairo-array-private.h +++ b/src/cairo-array-private.h diff --git a/src/cairo-array.c b/src/cairo-array.c index e37bb9980..e37bb9980 100755..100644 --- a/src/cairo-array.c +++ b/src/cairo-array.c diff --git a/src/cairo-atomic-private.h b/src/cairo-atomic-private.h index 327fed1d9..327fed1d9 100755..100644 --- a/src/cairo-atomic-private.h +++ b/src/cairo-atomic-private.h diff --git a/src/cairo-atomic.c b/src/cairo-atomic.c index 909cfea49..909cfea49 100755..100644 --- a/src/cairo-atomic.c +++ b/src/cairo-atomic.c diff --git a/src/cairo-backend-private.h b/src/cairo-backend-private.h index cc5d5f313..8129fa22c 100755..100644 --- a/src/cairo-backend-private.h +++ b/src/cairo-backend-private.h @@ -116,6 +116,7 @@ struct _cairo_backend { cairo_status_t (*arc) (void *cr, double xc, double yc, double radius, double angle1, double angle2, cairo_bool_t forward); cairo_status_t (*rectangle) (void *cr, double x, double y, double width, double height); + cairo_status_t (*rounded_rectangle) (void *cr, double x, double y, double width, double height, double r_top_left, double r_top_right, double r_bottom_left, double r_bottom_right); void (*path_extents) (void *cr, double *x1, double *y1, double *x2, double *y2); cairo_bool_t (*has_current_point) (void *cr); diff --git a/src/cairo-base64-stream.c b/src/cairo-base64-stream.c index 636431372..636431372 100755..100644 --- a/src/cairo-base64-stream.c +++ b/src/cairo-base64-stream.c diff --git a/src/cairo-base85-stream.c b/src/cairo-base85-stream.c index f81affb49..f81affb49 100755..100644 --- a/src/cairo-base85-stream.c +++ b/src/cairo-base85-stream.c diff --git a/src/cairo-bentley-ottmann-rectangular.c b/src/cairo-bentley-ottmann-rectangular.c index 5541bdc3a..5541bdc3a 100755..100644 --- a/src/cairo-bentley-ottmann-rectangular.c +++ b/src/cairo-bentley-ottmann-rectangular.c diff --git a/src/cairo-bentley-ottmann-rectilinear.c b/src/cairo-bentley-ottmann-rectilinear.c index 7c0be69b7..7c0be69b7 100755..100644 --- a/src/cairo-bentley-ottmann-rectilinear.c +++ b/src/cairo-bentley-ottmann-rectilinear.c diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c index 7259add0c..3f6f02422 100755..100644 --- a/src/cairo-bentley-ottmann.c +++ b/src/cairo-bentley-ottmann.c @@ -38,9 +38,10 @@ /* Provide definitions for standalone compilation */ #include "cairoint.h" +#include "cairo-combsort-inline.h" #include "cairo-error-private.h" #include "cairo-freelist-private.h" -#include "cairo-combsort-inline.h" +#include "cairo-line-inline.h" #include "cairo-traps-private.h" #define DEBUG_PRINT_STATE 0 @@ -307,156 +308,6 @@ _slope_compare (const cairo_bo_edge_t *a, } } -/* - * We need to compare the x-coordinates of a pair of lines for a particular y, - * without loss of precision. - * - * The x-coordinate along an edge for a given y is: - * X = A_x + (Y - A_y) * A_dx / A_dy - * - * So the inequality we wish to test is: - * A_x + (Y - A_y) * A_dx / A_dy ∘ B_x + (Y - B_y) * B_dx / B_dy, - * where ∘ is our inequality operator. - * - * By construction, we know that A_dy and B_dy (and (Y - A_y), (Y - B_y)) are - * all positive, so we can rearrange it thus without causing a sign change: - * A_dy * B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx * A_dy - * - (Y - A_y) * A_dx * B_dy - * - * Given the assumption that all the deltas fit within 32 bits, we can compute - * this comparison directly using 128 bit arithmetic. For certain, but common, - * input we can reduce this down to a single 32 bit compare by inspecting the - * deltas. - * - * (And put the burden of the work on developing fast 128 bit ops, which are - * required throughout the tessellator.) - * - * See the similar discussion for _slope_compare(). - */ -static int -edges_compare_x_for_y_general (const cairo_bo_edge_t *a, - const cairo_bo_edge_t *b, - int32_t y) -{ - /* XXX: We're assuming here that dx and dy will still fit in 32 - * bits. That's not true in general as there could be overflow. We - * should prevent that before the tessellation algorithm - * begins. - */ - int32_t dx; - int32_t adx, ady; - int32_t bdx, bdy; - enum { - HAVE_NONE = 0x0, - HAVE_DX = 0x1, - HAVE_ADX = 0x2, - HAVE_DX_ADX = HAVE_DX | HAVE_ADX, - HAVE_BDX = 0x4, - HAVE_DX_BDX = HAVE_DX | HAVE_BDX, - HAVE_ADX_BDX = HAVE_ADX | HAVE_BDX, - HAVE_ALL = HAVE_DX | HAVE_ADX | HAVE_BDX - } have_dx_adx_bdx = HAVE_ALL; - - /* don't bother solving for abscissa if the edges' bounding boxes - * can be used to order them. */ - { - int32_t amin, amax; - int32_t bmin, bmax; - if (a->edge.line.p1.x < a->edge.line.p2.x) { - amin = a->edge.line.p1.x; - amax = a->edge.line.p2.x; - } else { - amin = a->edge.line.p2.x; - amax = a->edge.line.p1.x; - } - if (b->edge.line.p1.x < b->edge.line.p2.x) { - bmin = b->edge.line.p1.x; - bmax = b->edge.line.p2.x; - } else { - bmin = b->edge.line.p2.x; - bmax = b->edge.line.p1.x; - } - if (amax < bmin) return -1; - if (amin > bmax) return +1; - } - - ady = a->edge.line.p2.y - a->edge.line.p1.y; - adx = a->edge.line.p2.x - a->edge.line.p1.x; - if (adx == 0) - have_dx_adx_bdx &= ~HAVE_ADX; - - bdy = b->edge.line.p2.y - b->edge.line.p1.y; - bdx = b->edge.line.p2.x - b->edge.line.p1.x; - if (bdx == 0) - have_dx_adx_bdx &= ~HAVE_BDX; - - dx = a->edge.line.p1.x - b->edge.line.p1.x; - if (dx == 0) - have_dx_adx_bdx &= ~HAVE_DX; - -#define L _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (ady, bdy), dx) -#define A _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (adx, bdy), y - a->edge.line.p1.y) -#define B _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (bdx, ady), y - b->edge.line.p1.y) - switch (have_dx_adx_bdx) { - default: - case HAVE_NONE: - return 0; - case HAVE_DX: - /* A_dy * B_dy * (A_x - B_x) ∘ 0 */ - return dx; /* ady * bdy is positive definite */ - case HAVE_ADX: - /* 0 ∘ - (Y - A_y) * A_dx * B_dy */ - return adx; /* bdy * (y - a->top.y) is positive definite */ - case HAVE_BDX: - /* 0 ∘ (Y - B_y) * B_dx * A_dy */ - return -bdx; /* ady * (y - b->top.y) is positive definite */ - case HAVE_ADX_BDX: - /* 0 ∘ (Y - B_y) * B_dx * A_dy - (Y - A_y) * A_dx * B_dy */ - if ((adx ^ bdx) < 0) { - return adx; - } else if (a->edge.line.p1.y == b->edge.line.p1.y) { /* common origin */ - cairo_int64_t adx_bdy, bdx_ady; - - /* ∴ A_dx * B_dy ∘ B_dx * A_dy */ - - adx_bdy = _cairo_int32x32_64_mul (adx, bdy); - bdx_ady = _cairo_int32x32_64_mul (bdx, ady); - - return _cairo_int64_cmp (adx_bdy, bdx_ady); - } else - return _cairo_int128_cmp (A, B); - case HAVE_DX_ADX: - /* A_dy * (A_x - B_x) ∘ - (Y - A_y) * A_dx */ - if ((-adx ^ dx) < 0) { - return dx; - } else { - cairo_int64_t ady_dx, dy_adx; - - ady_dx = _cairo_int32x32_64_mul (ady, dx); - dy_adx = _cairo_int32x32_64_mul (a->edge.line.p1.y - y, adx); - - return _cairo_int64_cmp (ady_dx, dy_adx); - } - case HAVE_DX_BDX: - /* B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx */ - if ((bdx ^ dx) < 0) { - return dx; - } else { - cairo_int64_t bdy_dx, dy_bdx; - - bdy_dx = _cairo_int32x32_64_mul (bdy, dx); - dy_bdx = _cairo_int32x32_64_mul (y - b->edge.line.p1.y, bdx); - - return _cairo_int64_cmp (bdy_dx, dy_bdx); - } - case HAVE_ALL: - /* XXX try comparing (a->edge.line.p2.x - b->edge.line.p2.x) et al */ - return _cairo_int128_cmp (L, _cairo_int128_sub (B, A)); - } -#undef B -#undef A -#undef L -} /* * We need to compare the x-coordinate of a line for a particular y wrt to a @@ -510,58 +361,6 @@ edge_compare_for_y_against_x (const cairo_bo_edge_t *a, return _cairo_int64_cmp (L, R); } -static int -edges_compare_x_for_y (const cairo_bo_edge_t *a, - const cairo_bo_edge_t *b, - int32_t y) -{ - /* If the sweep-line is currently on an end-point of a line, - * then we know its precise x value (and considering that we often need to - * compare events at end-points, this happens frequently enough to warrant - * special casing). - */ - enum { - HAVE_NEITHER = 0x0, - HAVE_AX = 0x1, - HAVE_BX = 0x2, - HAVE_BOTH = HAVE_AX | HAVE_BX - } have_ax_bx = HAVE_BOTH; - int32_t ax, bx; - - if (y == a->edge.line.p1.y) - ax = a->edge.line.p1.x; - else if (y == a->edge.line.p2.y) - ax = a->edge.line.p2.x; - else - have_ax_bx &= ~HAVE_AX; - - if (y == b->edge.line.p1.y) - bx = b->edge.line.p1.x; - else if (y == b->edge.line.p2.y) - bx = b->edge.line.p2.x; - else - have_ax_bx &= ~HAVE_BX; - - switch (have_ax_bx) { - default: - case HAVE_NEITHER: - return edges_compare_x_for_y_general (a, b, y); - case HAVE_AX: - return -edge_compare_for_y_against_x (b, y, ax); - case HAVE_BX: - return edge_compare_for_y_against_x (a, y, bx); - case HAVE_BOTH: - return ax - bx; - } -} - -static inline int -_line_equal (const cairo_line_t *a, const cairo_line_t *b) -{ - return a->p1.x == b->p1.x && a->p1.y == b->p1.y && - a->p2.x == b->p2.x && a->p2.y == b->p2.y; -} - static inline int _cairo_bo_sweep_line_compare_edges (const cairo_bo_sweep_line_t *sweep_line, const cairo_bo_edge_t *a, @@ -569,28 +368,11 @@ _cairo_bo_sweep_line_compare_edges (const cairo_bo_sweep_line_t *sweep_line, { int cmp; - /* compare the edges if not identical */ - if (! _line_equal (&a->edge.line, &b->edge.line)) { - if (MAX (a->edge.line.p1.x, a->edge.line.p2.x) < - MIN (b->edge.line.p1.x, b->edge.line.p2.x)) - return -1; - else if (MIN (a->edge.line.p1.x, a->edge.line.p2.x) > - MAX (b->edge.line.p1.x, b->edge.line.p2.x)) - return 1; - - cmp = edges_compare_x_for_y (a, b, sweep_line->current_y); - if (cmp) - return cmp; - - /* The two edges intersect exactly at y, so fall back on slope - * comparison. We know that this compare_edges function will be - * called only when starting a new edge, (not when stopping an - * edge), so we don't have to worry about conditionally inverting - * the sense of _slope_compare. */ - cmp = _slope_compare (a, b); - if (cmp) + cmp = cairo_lines_compare_at_y (&a->edge.line, + &b->edge.line, + sweep_line->current_y); + if (cmp) return cmp; - } /* We've got two collinear edges now. */ return b->edge.bottom - a->edge.bottom; @@ -1090,7 +872,7 @@ _cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_ MIN (right->edge.line.p1.x, right->edge.line.p2.x)) return CAIRO_STATUS_SUCCESS; - if (_line_equal (&left->edge.line, &right->edge.line)) + if (cairo_lines_equal (&left->edge.line, &right->edge.line)) return CAIRO_STATUS_SUCCESS; /* The names "left" and "right" here are correct descriptions of @@ -1691,7 +1473,7 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps, cairo_bo_event_t **event_ptrs; cairo_bo_start_event_t *stack_event_y[64]; cairo_bo_start_event_t **event_y = NULL; - int i, num_events, y, ymin = 0, ymax = 0; + int i, num_events, y, ymin, ymax; cairo_status_t status; num_events = polygon->num_edges; diff --git a/src/cairo-beos-surface.cpp b/src/cairo-beos-surface.cpp index c97641685..c97641685 100755..100644 --- a/src/cairo-beos-surface.cpp +++ b/src/cairo-beos-surface.cpp diff --git a/src/cairo-beos.h b/src/cairo-beos.h index fdb89a6c4..fdb89a6c4 100755..100644 --- a/src/cairo-beos.h +++ b/src/cairo-beos.h diff --git a/src/cairo-botor-scan-converter.c b/src/cairo-botor-scan-converter.c index 515305bf2..515305bf2 100755..100644 --- a/src/cairo-botor-scan-converter.c +++ b/src/cairo-botor-scan-converter.c diff --git a/src/cairo-box-inline.h b/src/cairo-box-inline.h index d6b994127..d6b994127 100755..100644 --- a/src/cairo-box-inline.h +++ b/src/cairo-box-inline.h diff --git a/src/cairo-boxes-intersect.c b/src/cairo-boxes-intersect.c index 96ae66334..96ae66334 100755..100644 --- a/src/cairo-boxes-intersect.c +++ b/src/cairo-boxes-intersect.c diff --git a/src/cairo-boxes-private.h b/src/cairo-boxes-private.h index d1f9dfcd1..d1f9dfcd1 100755..100644 --- a/src/cairo-boxes-private.h +++ b/src/cairo-boxes-private.h diff --git a/src/cairo-boxes.c b/src/cairo-boxes.c index 63b68ddfb..63b68ddfb 100755..100644 --- a/src/cairo-boxes.c +++ b/src/cairo-boxes.c diff --git a/src/cairo-cache-private.h b/src/cairo-cache-private.h index 76b556194..24b6d0b20 100755..100644 --- a/src/cairo-cache-private.h +++ b/src/cairo-cache-private.h @@ -43,7 +43,7 @@ #include "cairo-types-private.h" /** - * cairo_cache_entry_t: + * _cairo_cache_entry: * * A #cairo_cache_entry_t contains both a key and a value for * #cairo_cache_t. User-derived types for #cairo_cache_entry_t must diff --git a/src/cairo-cache.c b/src/cairo-cache.c index 5c4e4caa3..5c4e4caa3 100755..100644 --- a/src/cairo-cache.c +++ b/src/cairo-cache.c diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c index 6e60568e6..da49e8e1e 100755..100644 --- a/src/cairo-cff-subset.c +++ b/src/cairo-cff-subset.c @@ -295,7 +295,6 @@ decode_nibble (int n, char *buf) static unsigned char * decode_real (unsigned char *p, double *real) { - struct lconv *locale_data; const char *decimal_point; int decimal_point_len; int n; @@ -305,8 +304,7 @@ decode_real (unsigned char *p, double *real) char *buf = buffer; char *buf_end = buffer + sizeof (buffer); - locale_data = localeconv (); - decimal_point = locale_data->decimal_point; + decimal_point = cairo_get_locale_decimal_point (); decimal_point_len = strlen (decimal_point); assert (decimal_point_len != 0); @@ -435,7 +433,7 @@ cff_index_read (cairo_array_t *index, unsigned char **ptr, unsigned char *end_pt p = *ptr; if (p + 2 > end_ptr) return CAIRO_INT_STATUS_UNSUPPORTED; - count = be16_to_cpu( *((uint16_t *)p) ); + count = get_unaligned_be16 (p); p += 2; if (count > 0) { offset_size = *p++; @@ -905,6 +903,8 @@ cairo_cff_font_read_name (cairo_cff_font_t *font) memcpy (font->ps_name, p, len); font->ps_name[len] = 0; + + status = _cairo_escape_ps_name (&font->ps_name); } cff_index_fini (&index); @@ -990,14 +990,14 @@ cairo_cff_font_read_fdselect (cairo_cff_font_t *font, unsigned char *p) for (i = 0; i < font->num_glyphs; i++) font->fdselect[i] = *p++; } else if (type == 3) { - num_ranges = be16_to_cpu( *((uint16_t *)p) ); + num_ranges = get_unaligned_be16 (p); p += 2; for (i = 0; i < num_ranges; i++) { - first = be16_to_cpu( *((uint16_t *)p) ); + first = get_unaligned_be16 (p); p += 2; fd = *p++; - last = be16_to_cpu( *((uint16_t *)p) ); + last = get_unaligned_be16 (p); for (j = first; j < last; j++) font->fdselect[j] = fd; } @@ -1058,13 +1058,13 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr) goto fail; } - font->fd_default_width = calloc (sizeof (int), font->num_fontdicts); + font->fd_default_width = calloc (font->num_fontdicts, sizeof (double)); if (unlikely (font->fd_default_width == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail; } - font->fd_nominal_width = calloc (sizeof (int), font->num_fontdicts); + font->fd_nominal_width = calloc (font->num_fontdicts, sizeof (double)); if (unlikely (font->fd_nominal_width == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail; @@ -1757,7 +1757,7 @@ cairo_cff_font_get_gid_for_cid (cairo_cff_font_t *font, unsigned long cid, unsi p = font->charset + 1; g = 1; while (g <= (unsigned)font->num_glyphs && p < font->data_end) { - c = be16_to_cpu( *((uint16_t *)p) ); + c = get_unaligned_be16 (p); if (c == cid) { *gid = g; return CAIRO_STATUS_SUCCESS; @@ -1772,7 +1772,7 @@ cairo_cff_font_get_gid_for_cid (cairo_cff_font_t *font, unsigned long cid, unsi first_gid = 1; p = font->charset + 1; while (first_gid <= (unsigned)font->num_glyphs && p + 2 < font->data_end) { - first_cid = be16_to_cpu( *((uint16_t *)p) ); + first_cid = get_unaligned_be16 (p); num_left = p[2]; if (cid >= first_cid && cid <= first_cid + num_left) { *gid = first_gid + cid - first_cid; @@ -1788,8 +1788,8 @@ cairo_cff_font_get_gid_for_cid (cairo_cff_font_t *font, unsigned long cid, unsi first_gid = 1; p = font->charset + 1; while (first_gid <= (unsigned)font->num_glyphs && p + 3 < font->data_end) { - first_cid = be16_to_cpu( *((uint16_t *)p) ); - num_left = be16_to_cpu( *((uint16_t *)(p+2)) ); + first_cid = get_unaligned_be16 (p); + num_left = get_unaligned_be16 (p+2); if (cid >= first_cid && cid <= first_cid + num_left) { *gid = first_gid + cid - first_cid; return CAIRO_STATUS_SUCCESS; @@ -2366,7 +2366,7 @@ cairo_cff_font_write_cid_fontdict (cairo_cff_font_t *font) unsigned int i; cairo_int_status_t status; unsigned int offset_array; - uint32_t *offset_array_ptr; + unsigned char *offset_array_ptr; int offset_base; uint16_t count; uint8_t offset_size = 4; @@ -2387,7 +2387,7 @@ cairo_cff_font_write_cid_fontdict (cairo_cff_font_t *font) if (unlikely (status)) return status; offset_base = _cairo_array_num_elements (&font->output) - 1; - *offset_array_ptr = cpu_to_be32(1); + put_unaligned_be32(1, offset_array_ptr); offset_array += sizeof(uint32_t); for (i = 0; i < font->num_subset_fontdicts; i++) { status = cff_dict_write (font->fd_dict[font->fd_subset_map[i]], @@ -2395,8 +2395,9 @@ cairo_cff_font_write_cid_fontdict (cairo_cff_font_t *font) if (unlikely (status)) return status; - offset_array_ptr = (uint32_t *) _cairo_array_index (&font->output, offset_array); - *offset_array_ptr = cpu_to_be32(_cairo_array_num_elements (&font->output) - offset_base); + offset_array_ptr = _cairo_array_index (&font->output, offset_array); + put_unaligned_be32 (_cairo_array_num_elements (&font->output) - offset_base, + offset_array_ptr); offset_array += sizeof(uint32_t); } @@ -2647,7 +2648,7 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font) unsigned int i; tt_hhea_t hhea; int num_hmetrics; - unsigned char buf[10]; + uint16_t short_entry; int glyph_index; cairo_int_status_t status; @@ -2667,7 +2668,8 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font) status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, TT_TAG_hmtx, glyph_index * long_entry_size, - buf, &short_entry_size); + (unsigned char *) &short_entry, + &short_entry_size); if (unlikely (status)) return status; } @@ -2676,11 +2678,12 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font) status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, TT_TAG_hmtx, (num_hmetrics - 1) * long_entry_size, - buf, &short_entry_size); + (unsigned char *) &short_entry, + &short_entry_size); if (unlikely (status)) return status; } - font->widths[i] = be16_to_cpu (*((int16_t*)buf)); + font->widths[i] = be16_to_cpu (short_entry); } return CAIRO_STATUS_SUCCESS; diff --git a/src/cairo-cgl-context.c b/src/cairo-cgl-context.c new file mode 100644 index 000000000..6f5e557f4 --- /dev/null +++ b/src/cairo-cgl-context.c @@ -0,0 +1,224 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Eric Anholt + * Copyright © 2009 Chris Wilson + * Copyright © 2005 Red Hat, Inc + * Copyright © 2015 Samsung Research America, Inc. - Silicon Valley + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl Worth <cworth@cworth.org> + * Chris Wilson <chris@chris-wilson.co.uk> + * Henry Songn <hsong@sisa.samsung.com> + */ + +#include "cairoint.h" + +#include "cairo-gl-private.h" + +#include "cairo-error-private.h" + +#include <dlfcn.h> + +typedef struct _cairo_cgl_context { + cairo_gl_context_t base; + + CGLContextObj context; + CGLContextObj prev_context; +} cairo_cgl_context_t; + +typedef struct _cairo_cgl_surface { + cairo_gl_surface_t base; + + CGLContextObj context; +} cairo_cgl_surface_t; + +static void * +_cgl_query_current_state (cairo_cgl_context_t * ctx) +{ + ctx->prev_context = CGLGetCurrentContext (); +} + +static void +_cgl_acquire (void *abstract_ctx) +{ + cairo_cgl_context_t *ctx = abstract_ctx; + _cgl_query_current_state (ctx); + + if (ctx->prev_context == ctx->context) + return; + + _cairo_gl_context_reset (&ctx->base); + + CGLLockContext (ctx->context); + CGLSetCurrentContext (ctx->context); +} + +static void +_cgl_make_current (void *abstract_ctx, cairo_gl_surface_t *abstract_surface) +{ + cairo_cgl_context_t *ctx = abstract_ctx; + cairo_cgl_surface_t *surface = (cairo_cgl_surface_t *) abstract_surface; + + /* Set the window as the target of our context. */ + if (ctx->context != surface->context) { + CGLLockContext (surface->context); + CGLSetCurrentContext (surface->context); + } +} + +static void +_cgl_release (void *abstract_ctx) +{ + cairo_cgl_context_t *ctx = abstract_ctx; + + if (!ctx->base.thread_aware) + return; + + CGLSetCurrentContext (NULL); + CGLUnlockContext (ctx->context); +} + +static void +_cgl_swap_buffers (void *abstract_ctx, + cairo_gl_surface_t *abstract_surface) +{ + cairo_cgl_context_t *ctx = abstract_ctx; + cairo_cgl_surface_t *surface = (cairo_cgl_surface_t *)abstract_surface; + + /* is it possible to have different context? */ + if (ctx->context == surface->context) + CGLFlushDrawable (surface->context); +} + +static void +_cgl_destroy (void *abstract_ctx) +{ + cairo_cgl_context_t *ctx = abstract_ctx; + + CGLSetCurrentContext (NULL); + CGLReleaseContext (ctx->context); + CGLUnlockContext (ctx->context); +} + +static cairo_gl_generic_func_t +_cairo_cgl_get_proc_address (void *data, const char *name) +{ + return dlsym (RTLD_DEFAULT, name); +} + +cairo_device_t * +cairo_cgl_device_create (CGLContextObj context) +{ + cairo_cgl_context_t *ctx; + cairo_status_t status; + + ctx = calloc (1, sizeof (cairo_cgl_context_t)); + if (unlikely (ctx == NULL)) + return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY); + + ctx->context = CGLRetainContext (context); + + ctx->base.acquire = _cgl_acquire; + ctx->base.release = _cgl_release; + ctx->base.make_current = _cgl_make_current; + ctx->base.swap_buffers = _cgl_swap_buffers; + ctx->base.destroy = _cgl_destroy; + + _cgl_query_current_state (ctx); + if (ctx->context != ctx->prev_context) { + CGLLockContext (ctx->context); + CGLSetCurrentContext (ctx->context); + } + + status = _cairo_gl_dispatch_init (&ctx->base.dispatch, + (cairo_gl_get_proc_addr_func_t) _cairo_cgl_get_proc_address, + NULL); + + if (unlikely (status)) { + ctx->base.release (ctx); + CGLReleaseContext (ctx->context); + free (ctx); + return _cairo_gl_context_create_in_error (status); + } + + status = _cairo_gl_context_init (&ctx->base); + if (unlikely (status)) { + ctx->base.release (ctx); + CGLReleaseContext (ctx->context); + free (ctx); + return _cairo_gl_context_create_in_error (status); + } + + ctx->base.release (ctx); + + return &ctx->base.base; +} + +CGLContextObj +cairo_cgl_device_get_context (cairo_device_t *device) +{ + cairo_cgl_context_t *ctx; + + if (device->backend->type != CAIRO_DEVICE_TYPE_GL) { + _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + return NULL; + } + + ctx = (cairo_cgl_context_t *) device; + + return ctx->context; +} + +cairo_surface_t * +cairo_gl_surface_create_for_cgl (cairo_device_t *device, + int width, + int height) +{ + cairo_cgl_surface_t *surface; + + if (unlikely (device->status)) + return _cairo_surface_create_in_error (device->status); + + if (device->backend->type != CAIRO_DEVICE_TYPE_GL) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + + if (width <= 0 || height <= 0) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + + surface = calloc (1, sizeof (cairo_cgl_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_gl_surface_init (device, &surface->base, + CAIRO_CONTENT_COLOR_ALPHA, width, height); + surface->context = ((cairo_cgl_context_t *) device)->context; + + return &surface->base.base; +} diff --git a/src/cairo-clip-boxes.c b/src/cairo-clip-boxes.c index eae0919af..0501fa273 100755..100644 --- a/src/cairo-clip-boxes.c +++ b/src/cairo-clip-boxes.c @@ -173,7 +173,7 @@ _cairo_clip_intersect_rectangle_box (cairo_clip_t *clip, clip->extents = *r; } else { if (! _cairo_rectangle_intersect (&clip->extents, r)) - clip = _cairo_clip_set_all_clipped (clip); + return _cairo_clip_set_all_clipped (clip); } if (clip->path == NULL) clip->is_region = _cairo_box_is_pixel_aligned (box); @@ -258,6 +258,9 @@ _cairo_clip_intersect_box (cairo_clip_t *clip, { cairo_rectangle_int_t r; + if (_cairo_clip_is_all_clipped (clip)) + return clip; + _cairo_box_round_to_rectangle (box, &r); if (r.width == 0 || r.height == 0) return _cairo_clip_set_all_clipped (clip); @@ -315,10 +318,12 @@ _cairo_clip_intersect_boxes (cairo_clip_t *clip, _cairo_boxes_extents (boxes, &limits); _cairo_box_round_to_rectangle (&limits, &extents); - if (clip->path == NULL) + if (clip->path == NULL) { clip->extents = extents; - else if (! _cairo_rectangle_intersect (&clip->extents, &extents)) + } else if (! _cairo_rectangle_intersect (&clip->extents, &extents)) { clip = _cairo_clip_set_all_clipped (clip); + goto out; + } if (clip->region) { cairo_region_destroy (clip->region); diff --git a/src/cairo-clip-inline.h b/src/cairo-clip-inline.h index a9f232692..a9f232692 100755..100644 --- a/src/cairo-clip-inline.h +++ b/src/cairo-clip-inline.h diff --git a/src/cairo-clip-polygon.c b/src/cairo-clip-polygon.c index f40faefba..f40faefba 100755..100644 --- a/src/cairo-clip-polygon.c +++ b/src/cairo-clip-polygon.c diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h index c2ed66419..c2ed66419 100755..100644 --- a/src/cairo-clip-private.h +++ b/src/cairo-clip-private.h diff --git a/src/cairo-clip-region.c b/src/cairo-clip-region.c index e3f4891e3..e3f4891e3 100755..100644 --- a/src/cairo-clip-region.c +++ b/src/cairo-clip-region.c diff --git a/src/cairo-clip-surface.c b/src/cairo-clip-surface.c index f1c13a4ae..a92379eba 100755..100644 --- a/src/cairo-clip-surface.c +++ b/src/cairo-clip-surface.c @@ -134,11 +134,11 @@ _cairo_clip_get_surface (const cairo_clip_t *clip, cairo_path_fixed_t path; int i; - surface = _cairo_surface_create_similar_solid (target, - CAIRO_CONTENT_ALPHA, - clip->extents.width, - clip->extents.height, - CAIRO_COLOR_TRANSPARENT); + surface = _cairo_surface_create_scratch (target, + CAIRO_CONTENT_ALPHA, + clip->extents.width, + clip->extents.height, + CAIRO_COLOR_TRANSPARENT); if (unlikely (surface->status)) return surface; @@ -164,11 +164,11 @@ _cairo_clip_get_surface (const cairo_clip_t *clip, return _cairo_surface_create_in_error (status); } } else { - surface = _cairo_surface_create_similar_solid (target, - CAIRO_CONTENT_ALPHA, - clip->extents.width, - clip->extents.height, - CAIRO_COLOR_WHITE); + surface = _cairo_surface_create_scratch (target, + CAIRO_CONTENT_ALPHA, + clip->extents.width, + clip->extents.height, + CAIRO_COLOR_WHITE); if (unlikely (surface->status)) return surface; } diff --git a/src/cairo-clip-tor-scan-converter.c b/src/cairo-clip-tor-scan-converter.c index e32a5a9d9..e32a5a9d9 100755..100644 --- a/src/cairo-clip-tor-scan-converter.c +++ b/src/cairo-clip-tor-scan-converter.c diff --git a/src/cairo-clip.c b/src/cairo-clip.c index dcafaf229..dcafaf229 100755..100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c diff --git a/src/cairo-cogl-context-private.h b/src/cairo-cogl-context-private.h index 0a7185ef1..0a7185ef1 100755..100644 --- a/src/cairo-cogl-context-private.h +++ b/src/cairo-cogl-context-private.h diff --git a/src/cairo-cogl-context.c b/src/cairo-cogl-context.c index 0116b0a5a..0116b0a5a 100755..100644 --- a/src/cairo-cogl-context.c +++ b/src/cairo-cogl-context.c diff --git a/src/cairo-cogl-gradient-private.h b/src/cairo-cogl-gradient-private.h index fa684d2c6..fa684d2c6 100755..100644 --- a/src/cairo-cogl-gradient-private.h +++ b/src/cairo-cogl-gradient-private.h diff --git a/src/cairo-cogl-gradient.c b/src/cairo-cogl-gradient.c index f8c800416..f8c800416 100755..100644 --- a/src/cairo-cogl-gradient.c +++ b/src/cairo-cogl-gradient.c diff --git a/src/cairo-cogl-private.h b/src/cairo-cogl-private.h index 13fe5a8dc..13fe5a8dc 100755..100644 --- a/src/cairo-cogl-private.h +++ b/src/cairo-cogl-private.h diff --git a/src/cairo-cogl-surface.c b/src/cairo-cogl-surface.c index 27c3676de..c57fd7f43 100755..100644 --- a/src/cairo-cogl-surface.c +++ b/src/cairo-cogl-surface.c @@ -143,7 +143,7 @@ typedef struct _cairo_cogl_path_fill_meta { * and translations but not for different scales. * * one idea is to track the diagonal lenghts of a unit rectangle - * transformed through the original ctm use to tesselate the geometry + * transformed through the original ctm use to tessellate the geometry * so we can check what the lengths are for any new ctm to know if * this geometry is compatible. */ @@ -167,7 +167,7 @@ typedef struct _cairo_cogl_path_stroke_meta { * and translations but not for different scales. * * one idea is to track the diagonal lenghts of a unit rectangle - * transformed through the original ctm use to tesselate the geometry + * transformed through the original ctm use to tessellate the geometry * so we can check what the lengths are for any new ctm to know if * this geometry is compatible. */ @@ -805,7 +805,7 @@ _cairo_cogl_journal_flush (cairo_cogl_surface_t *surface) _cairo_path_fixed_approximate_clip_extents (&path->path, &extents); /* TODO - maintain a fifo of the last 10 used clips with cached - * primitives to see if we can avoid tesselating the path and + * primitives to see if we can avoid tessellating the path and * uploading the vertices... */ #if 0 @@ -2789,7 +2789,7 @@ cairo_cogl_device_create (CoglContext *cogl_context) ERROR: g_free (dev); - return NULL; + return _cairo_device_create_in_error (CAIRO_STATUS_DEVICE_ERROR); } slim_hidden_def (cairo_cogl_device_create); diff --git a/src/cairo-cogl-utils-private.h b/src/cairo-cogl-utils-private.h index ee77f3034..ee77f3034 100755..100644 --- a/src/cairo-cogl-utils-private.h +++ b/src/cairo-cogl-utils-private.h diff --git a/src/cairo-cogl-utils.c b/src/cairo-cogl-utils.c index 4f02aaa52..4f02aaa52 100755..100644 --- a/src/cairo-cogl-utils.c +++ b/src/cairo-cogl-utils.c diff --git a/src/cairo-cogl.h b/src/cairo-cogl.h index f270d74d3..f270d74d3 100755..100644 --- a/src/cairo-cogl.h +++ b/src/cairo-cogl.h diff --git a/src/cairo-color.c b/src/cairo-color.c index 9c852559e..c2a11a177 100755..100644 --- a/src/cairo-color.c +++ b/src/cairo-color.c @@ -78,18 +78,13 @@ _cairo_stock_color (cairo_stock_t stock) } /* Convert a double in [0.0, 1.0] to an integer in [0, 65535] - * The conversion is designed to divide the input range into 65536 - * equally-sized regions. This is achieved by multiplying by 65536 and - * then special-casing the result of an input value of 1.0 so that it - * maps to 65535 instead of 65536. + * The conversion is designed to choose the integer i such that + * i / 65535.0 is as close as possible to the input value. */ uint16_t _cairo_color_double_to_short (double d) { - uint32_t i; - i = (uint32_t) (d * 65536); - i -= (i >> 16); - return i; + return d * 65535.0 + 0.5; } static void diff --git a/src/cairo-combsort-inline.h b/src/cairo-combsort-inline.h index d359faeb5..d359faeb5 100755..100644 --- a/src/cairo-combsort-inline.h +++ b/src/cairo-combsort-inline.h diff --git a/src/cairo-compiler-private.h b/src/cairo-compiler-private.h index f3e971ebb..216e71b4e 100755..100644 --- a/src/cairo-compiler-private.h +++ b/src/cairo-compiler-private.h @@ -221,16 +221,14 @@ be needed for GCC but it seems fine for now. */ #define CAIRO_ENSURE_UNIQUE \ do { \ - char func[] = __FUNCTION__; \ char file[] = __FILE__; \ __asm { \ __asm jmp __internal_skip_line_no \ - __asm _emit (__LINE__ & 0xff) \ - __asm _emit ((__LINE__>>8) & 0xff) \ - __asm _emit ((__LINE__>>16) & 0xff) \ - __asm _emit ((__LINE__>>24) & 0xff) \ - __asm lea eax, func \ - __asm lea eax, file \ + __asm _emit (__COUNTER__ & 0xff) \ + __asm _emit ((__COUNTER__>>8) & 0xff) \ + __asm _emit ((__COUNTER__>>16) & 0xff)\ + __asm _emit ((__COUNTER__>>24) & 0xff)\ + __asm lea eax, dword ptr file \ __asm __internal_skip_line_no: \ }; \ } while (0) diff --git a/src/cairo-composite-rectangles-private.h b/src/cairo-composite-rectangles-private.h index 108137427..108137427 100755..100644 --- a/src/cairo-composite-rectangles-private.h +++ b/src/cairo-composite-rectangles-private.h diff --git a/src/cairo-composite-rectangles.c b/src/cairo-composite-rectangles.c index f288bb785..2f0013fa7 100755..100644 --- a/src/cairo-composite-rectangles.c +++ b/src/cairo-composite-rectangles.c @@ -61,7 +61,7 @@ _cairo_composite_rectangles_check_lazy_init (cairo_composite_rectangles_t *exten if (type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; - cairo_surface_t *pattern_surface = surface_pattern->surface; + cairo_surface_t *pattern_surface = pattern_surface = surface_pattern->surface; /* XXX: both source and target are GL surface */ if (cairo_surface_get_type (pattern_surface) == CAIRO_SURFACE_TYPE_GL && @@ -87,7 +87,7 @@ _cairo_composite_reduce_pattern (const cairo_pattern_t *src, if (dst->base.type == CAIRO_PATTERN_TYPE_SOLID) return; - dst->base.filter = _cairo_pattern_analyze_filter (&dst->base, NULL), + dst->base.filter = _cairo_pattern_analyze_filter (&dst->base); tx = ty = 0; if (_cairo_matrix_is_pixman_translation (&dst->base.matrix, @@ -244,6 +244,13 @@ _cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents, _cairo_clip_get_extents (extents->clip))) return CAIRO_INT_STATUS_NOTHING_TO_DO; + if (! _cairo_rectangle_intersect (&extents->bounded, + _cairo_clip_get_extents (extents->clip)) && + extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) + { + return CAIRO_INT_STATUS_NOTHING_TO_DO; + } + if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) _cairo_pattern_sampled_area (&extents->source_pattern.base, &extents->bounded, diff --git a/src/cairo-compositor-private.h b/src/cairo-compositor-private.h index 3a461bf06..d4230b1bc 100755..100644 --- a/src/cairo-compositor-private.h +++ b/src/cairo-compositor-private.h @@ -242,18 +242,18 @@ struct cairo_traps_compositor { int dst_y, unsigned int width, unsigned int height); - cairo_int_status_t - (*lerp_color_glyph) (void *_dst, - cairo_surface_t *abstract_src, - cairo_surface_t *abstract_mask, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height); + cairo_int_status_t + (*lerp_color_glyph) (void *_dst, + cairo_surface_t *abstract_src, + cairo_surface_t *abstract_mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height); cairo_int_status_t (*composite_boxes) (void *surface, diff --git a/src/cairo-compositor.c b/src/cairo-compositor.c index 0c4d34cc0..0c4d34cc0 100755..100644 --- a/src/cairo-compositor.c +++ b/src/cairo-compositor.c diff --git a/src/cairo-contour-inline.h b/src/cairo-contour-inline.h index 7972c1ac5..7972c1ac5 100755..100644 --- a/src/cairo-contour-inline.h +++ b/src/cairo-contour-inline.h diff --git a/src/cairo-contour-private.h b/src/cairo-contour-private.h index 1dfc46f3a..1dfc46f3a 100755..100644 --- a/src/cairo-contour-private.h +++ b/src/cairo-contour-private.h diff --git a/src/cairo-contour.c b/src/cairo-contour.c index d356f4f65..9ad75bdbf 100755..100644 --- a/src/cairo-contour.c +++ b/src/cairo-contour.c @@ -332,7 +332,6 @@ _cairo_contour_simplify (cairo_contour_t *contour, double tolerance) } /* stage2: polygon simplification using Douglas-Peucker */ - simplified = FALSE; do { last = &contour->chain.points[0]; iter_init (&furthest, contour); diff --git a/src/cairo-convex-fill-private.h b/src/cairo-convex-fill-private.h new file mode 100644 index 000000000..ba76045b3 --- /dev/null +++ b/src/cairo-convex-fill-private.h @@ -0,0 +1,112 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2014 Samsung Research America, Silicon Valley + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Srikanth Chevalam<chevalam.s@samsung.com> + * Suyambulingam Rathinasamy<suyambu.rm@samsung.com> + * Henry Song <henry.song@samsung.com> + */ +#ifndef __CAIRO_CONVEX_FILL_H_ +#define __CAIRO_CONVEX_FILL_H_ + +#include "cairo-box-inline.h" +#include "cairo-list-inline.h" +#include "cairo-stroke-dash-private.h" +#include "cairo-slope-private.h" + +#define NUM_SPLINE_CALLS 64 + +typedef struct cairo_convex_fill_closure { + cairo_status_t (*add_triangle_fan) (void *closure, + const cairo_point_t *points, + int npoints); + double tolerance; + cairo_point_t current_point; + cairo_point_t start_point; + void *closure; + unsigned int pcount; + unsigned int capacity; + cairo_bool_t midp_added; + cairo_point_t embedded_points[NUM_SPLINE_CALLS]; + cairo_point_t *convex_points; +} cairo_convex_fill_closure_t; + +typedef cairo_warn cairo_status_t +(*cairo_convex_fill_closure_add_triangle_fan) (void *closure, + const cairo_point_t *points, + int npoints); + +cairo_status_t +_cairo_convex_fill_spline_to (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent); + + +cairo_status_t +_cairo_convex_fill_curve_to (void *closure, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d); + +cairo_status_t +_cairo_convex_fill_move_to (void *closure, + const cairo_point_t *point); + +cairo_status_t +_cairo_path_fixed_fill_to_convex (cairo_convex_fill_closure_add_triangle_fan add_triangle_fan, + const cairo_path_fixed_t *path, + cairo_path_fixed_move_to_func_t *move_to, + cairo_path_fixed_line_to_func_t *line_to, + cairo_path_fixed_curve_to_func_t *curve_to, + cairo_path_fixed_close_path_func_t *close_path, + void *closure); + + +cairo_status_t +_cairo_path_fixed_convex_fill_interpret (const cairo_path_fixed_t *path, + cairo_path_fixed_move_to_func_t *move_to, + cairo_path_fixed_line_to_func_t *line_to, + cairo_path_fixed_curve_to_func_t *curve_to, + cairo_path_fixed_close_path_func_t *close_path, + void *closure); + +cairo_status_t +_cairo_convex_fill_line_to (void *closure, + const cairo_point_t *point); + +cairo_status_t +_cairo_convex_fill_close_path (void *closure); + +cairo_status_t +_add_triangle (void *closure, + const cairo_point_t triangle[3]); + +#endif diff --git a/src/cairo-convex-fill.c b/src/cairo-convex-fill.c new file mode 100644 index 000000000..e5fefe315 --- /dev/null +++ b/src/cairo-convex-fill.c @@ -0,0 +1,219 @@ +/* cairo - a vector graphics library with display and print output +* +* Copyright © 2014 Samsung Research America, Silicon Valley +* +* This library is free software; you can redistribute it and/or +* modify it either under the terms of the GNU Lesser General Public +* License version 2.1 as published by the Free Software Foundation +* (the "LGPL") or, at your option, under the terms of the Mozilla +* Public License Version 1.1 (the "MPL"). If you do not alter this +* notice, a recipient may use your version of this file under either +* the MPL or the LGPL. +* +* You should have received a copy of the LGPL along with this library +* in the file COPYING-LGPL-2.1; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA +* You should have received a copy of the MPL along with this library +* in the file COPYING-MPL-1.1 +* +* The contents of this file are subject to the Mozilla Public License +* Version 1.1 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY +* OF ANY KIND, either express or implied. See the LGPL or the MPL for +* the specific language governing rights and limitations. +* +* The Original Code is the cairo graphics library. +* +* The Initial Developer of the Original Code is Red Hat, Inc. +* +* Contributor(s): +* Srikanth Chevalam<chevalam.s@samsung.com> +* Suyambulingam Rathinasamy<suyambu.rm@samsung.com> +* Henry Song <henry.song@samsung.com> +*/ + +#include "cairo-convex-fill-private.h" +#include <sys/time.h> + +cairo_status_t +_add_triangle (void *closure, + const cairo_point_t* triangle) +{ + cairo_convex_fill_closure_t *filler = closure; + int required_space = 1; + if (! filler->midp_added) + required_space = 2; + + if(filler->capacity < filler->pcount + required_space) { + filler->capacity += NUM_SPLINE_CALLS; + if (filler->convex_points == filler->embedded_points) { + filler->convex_points = _cairo_malloc_ab (filler->capacity, sizeof(cairo_point_t)); + memcpy (filler->convex_points, filler->embedded_points, sizeof(cairo_point_t) * NUM_SPLINE_CALLS); + } + else + filler->convex_points = _cairo_realloc_ab (filler->convex_points, filler->capacity, sizeof (cairo_point_t)); + } + + if (! filler->midp_added) { + filler->convex_points[filler->pcount++] = filler->start_point; + filler->midp_added = TRUE; + } + filler->convex_points[filler->pcount++] = *triangle; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_convex_fill_spline_to (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent) +{ + cairo_convex_fill_closure_t *filler = closure; + if (filler->current_point.x == point->x && + filler->current_point.y == point->y) + return CAIRO_STATUS_SUCCESS; + + if ((filler->current_point.x != point->x || + filler->current_point.y != point->y)) + _add_triangle (filler, point); + + filler->current_point = *point; + return CAIRO_STATUS_SUCCESS; +} + + +cairo_status_t +_cairo_convex_fill_move_to (void *closure, + const cairo_point_t *point) +{ + cairo_convex_fill_closure_t *path = closure; + path->current_point = *point; + path->start_point = path->current_point; + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_convex_fill_line_to (void *closure, + const cairo_point_t *point) +{ + cairo_convex_fill_closure_t *filler = closure; + + _add_triangle(filler, point); + + filler->current_point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_convex_fill_close_path (void *closure) +{ + cairo_convex_fill_closure_t *filler = closure; + _cairo_convex_fill_line_to (closure, &filler->start_point); + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_path_fixed_fill_to_convex (cairo_convex_fill_closure_add_triangle_fan add_triangle_fan, + const cairo_path_fixed_t *path, + cairo_path_fixed_move_to_func_t *move_to, + cairo_path_fixed_line_to_func_t *line_to, + cairo_path_fixed_curve_to_func_t *curve_to, + cairo_path_fixed_close_path_func_t *close_path, + void *closure) +{ + cairo_convex_fill_closure_t *filler = closure ; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + filler->current_point = path->current_point; + filler->start_point = filler->current_point; + filler->add_triangle_fan = add_triangle_fan; + filler->pcount = 0 ; + filler->capacity = NUM_SPLINE_CALLS; + filler->convex_points = filler->embedded_points; + //filler->convex_points = _cairo_malloc_ab (filler->capacity, sizeof(cairo_point_t)); + status = _cairo_path_fixed_convex_fill_interpret (path, + move_to, + line_to, + curve_to, + close_path, + filler); + return status; +} + +cairo_status_t +_cairo_convex_fill_curve_to (void *closure, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + cairo_convex_fill_closure_t *filler = closure; + cairo_spline_t spline; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + if (! _cairo_spline_init (&spline, + (cairo_spline_add_point_func_t) _cairo_convex_fill_spline_to, + filler, + &filler->current_point, b, c, d)) + return _cairo_convex_fill_line_to (closure, d); + + status = _cairo_spline_decompose (&spline, filler->tolerance); + + if (unlikely (status)) + return status; + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_path_fixed_convex_fill_interpret (const cairo_path_fixed_t *path, + cairo_path_fixed_move_to_func_t *move_to, + cairo_path_fixed_line_to_func_t *line_to, + cairo_path_fixed_curve_to_func_t *curve_to, + cairo_path_fixed_close_path_func_t *close_path, + void *closure) +{ + const cairo_path_buf_t *buf; + cairo_status_t status; + cairo_convex_fill_closure_t *filler = closure; + + cairo_path_foreach_buf_start (buf, path) { + const cairo_point_t *points = buf->points; + unsigned int i; + + for (i = 0; i < buf->num_ops; i++) { + switch (buf->op[i]) { + case CAIRO_PATH_OP_MOVE_TO: + status = (*move_to) (closure, &points[0]); + points += 1; + break; + case CAIRO_PATH_OP_LINE_TO: + status = (*line_to) (closure, &points[0]); + points += 1; + break; + case CAIRO_PATH_OP_CURVE_TO: + status = (*curve_to) (closure, &points[0], &points[1], &points[2]); + points += 3; + break; + default: + ASSERT_NOT_REACHED; + case CAIRO_PATH_OP_CLOSE_PATH: + status = (*close_path) (closure); + break; + } + + if (unlikely (status)) + return status; + } + } cairo_path_foreach_buf_end (buf, path); + + if (filler->pcount) { + filler->add_triangle_fan (filler->closure, + filler->convex_points, + filler->pcount); + } + if (filler->convex_points != filler->embedded_points) + free (filler->convex_points); + + return status; +} diff --git a/src/cairo-damage-private.h b/src/cairo-damage-private.h index 97b177e86..97b177e86 100755..100644 --- a/src/cairo-damage-private.h +++ b/src/cairo-damage-private.h diff --git a/src/cairo-damage.c b/src/cairo-damage.c index 63191fee9..63191fee9 100755..100644 --- a/src/cairo-damage.c +++ b/src/cairo-damage.c diff --git a/src/cairo-debug.c b/src/cairo-debug.c index 33d46aa3f..33d46aa3f 100755..100644 --- a/src/cairo-debug.c +++ b/src/cairo-debug.c diff --git a/src/cairo-default-context-private.h b/src/cairo-default-context-private.h index fd159b496..fd159b496 100755..100644 --- a/src/cairo-default-context-private.h +++ b/src/cairo-default-context-private.h diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c index b7a38d2f0..4b63d53be 100755..100644 --- a/src/cairo-default-context.c +++ b/src/cairo-default-context.c @@ -139,7 +139,6 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content) cairo_surface_t *group_surface; cairo_clip_t *clip; cairo_status_t status; - clip = _cairo_gstate_get_clip (cr->gstate); if (_cairo_clip_is_all_clipped (clip)) { group_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); @@ -153,6 +152,11 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content) parent_surface = _cairo_gstate_get_target (cr->gstate); + if (unlikely (parent_surface->status)) + return parent_surface->status; + if (unlikely (parent_surface->finished)) + return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + /* Get the extents that we'll use in creating our new group surface */ bounded = _cairo_surface_get_extents (parent_surface, &extents); if (clip) @@ -165,11 +169,11 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content) group_surface = cairo_recording_surface_create (content, NULL); extents.x = extents.y = 0; } else { - group_surface = _cairo_surface_create_similar_solid (parent_surface, - content, - extents.width, - extents.height, - CAIRO_COLOR_TRANSPARENT); + group_surface = _cairo_surface_create_scratch (parent_surface, + content, + extents.width, + extents.height, + CAIRO_COLOR_TRANSPARENT); } status = group_surface->status; if (unlikely (status)) @@ -184,6 +188,10 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content) parent_surface->device_transform.x0 - extents.x, parent_surface->device_transform.y0 - extents.y); + cairo_surface_set_device_scale (group_surface, + parent_surface->device_transform.xx, + parent_surface->device_transform.yy); + /* If we have a current path, we need to adjust it to compensate for * the device offset just applied. */ _cairo_path_fixed_translate (cr->path, @@ -209,7 +217,8 @@ _cairo_default_context_pop_group (void *abstract_cr) cairo_default_context_t *cr = abstract_cr; cairo_surface_t *group_surface; cairo_pattern_t *group_pattern; - cairo_matrix_t group_matrix, device_transform_matrix; + cairo_surface_t *parent_surface; + cairo_matrix_t group_matrix; cairo_status_t status; /* Verify that we are at the right nesting level */ @@ -223,29 +232,21 @@ _cairo_default_context_pop_group (void *abstract_cr) status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist); assert (status == CAIRO_STATUS_SUCCESS); + parent_surface = _cairo_gstate_get_target (cr->gstate); + group_pattern = cairo_pattern_create_for_surface (group_surface); status = group_pattern->status; if (unlikely (status)) goto done; _cairo_gstate_get_matrix (cr->gstate, &group_matrix); - /* Transform by group_matrix centered around device_transform so that when - * we call _cairo_gstate_copy_transformed_pattern the result is a pattern - * with a matrix equivalent to the device_transform of group_surface. */ - if (_cairo_surface_has_device_transform (group_surface)) { - cairo_pattern_set_matrix (group_pattern, &group_surface->device_transform); - _cairo_pattern_transform (group_pattern, &group_matrix); - _cairo_pattern_transform (group_pattern, &group_surface->device_transform_inverse); - } else { - cairo_pattern_set_matrix (group_pattern, &group_matrix); - } + cairo_pattern_set_matrix (group_pattern, &group_matrix); /* If we have a current path, we need to adjust it to compensate for * the device offset just removed. */ - cairo_matrix_multiply (&device_transform_matrix, - &_cairo_gstate_get_target (cr->gstate)->device_transform, - &group_surface->device_transform_inverse); - _cairo_path_fixed_transform (cr->path, &device_transform_matrix); + _cairo_path_fixed_translate (cr->path, + _cairo_fixed_from_int (parent_surface->device_transform.x0 - group_surface->device_transform.x0), + _cairo_fixed_from_int (parent_surface->device_transform.y0 - group_surface->device_transform.y0)); done: cairo_surface_destroy (group_surface); @@ -267,7 +268,7 @@ _current_source_matches_solid (const cairo_pattern_t *pattern, double red, double green, double blue, - double alpha) + double alpha) { cairo_color_t color; @@ -299,11 +300,8 @@ _cairo_default_context_set_source_rgba (void *abstract_cr, double red, double gr _cairo_default_context_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black); pattern = cairo_pattern_create_rgba (red, green, blue, alpha); - if (unlikely (pattern->status)) { - status = pattern->status; - cairo_pattern_destroy (pattern); - return pattern->status; - } + if (unlikely (pattern->status)) + return pattern->status; status = _cairo_default_context_set_source (cr, pattern); cairo_pattern_destroy (pattern); @@ -326,11 +324,8 @@ _cairo_default_context_set_source_surface (void *abstract_cr, _cairo_default_context_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black); pattern = cairo_pattern_create_for_surface (surface); - if (unlikely (pattern->status)) { - status = pattern->status; - cairo_pattern_destroy (pattern); - return status; - } + if (unlikely (pattern->status)) + return pattern->status; cairo_matrix_init_translate (&matrix, -x, -y); cairo_pattern_set_matrix (pattern, &matrix); @@ -711,7 +706,6 @@ _cairo_default_context_line_to (void *abstract_cr, double x, double y) { cairo_default_context_t *cr = abstract_cr; cairo_fixed_t x_fixed, y_fixed; - _cairo_gstate_user_to_backend (cr->gstate, &x, &y); x_fixed = _cairo_fixed_from_double (x); y_fixed = _cairo_fixed_from_double (y); @@ -729,7 +723,6 @@ _cairo_default_context_curve_to (void *abstract_cr, cairo_fixed_t x1_fixed, y1_fixed; cairo_fixed_t x2_fixed, y2_fixed; cairo_fixed_t x3_fixed, y3_fixed; - _cairo_gstate_user_to_backend (cr->gstate, &x1, &y1); _cairo_gstate_user_to_backend (cr->gstate, &x2, &y2); _cairo_gstate_user_to_backend (cr->gstate, &x3, &y3); @@ -758,13 +751,16 @@ _cairo_default_context_arc (void *abstract_cr, cairo_default_context_t *cr = abstract_cr; cairo_status_t status; + cairo_fixed_t x_fixed, y_fixed; + + cairo_bool_t path_empty = _cairo_path_fixed_is_empty (cr->path); + /* Do nothing, successfully, if radius is <= 0 */ if (radius <= 0.0) { - cairo_fixed_t x_fixed, y_fixed; - _cairo_gstate_user_to_backend (cr->gstate, &xc, &yc); x_fixed = _cairo_fixed_from_double (xc); y_fixed = _cairo_fixed_from_double (yc); + status = _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed); if (unlikely (status)) return status; @@ -788,6 +784,16 @@ _cairo_default_context_arc (void *abstract_cr, else _cairo_arc_path_negative (&cr->base, xc, yc, radius, angle1, angle2); + if (path_empty) { + x_fixed = _cairo_fixed_from_double (xc + radius * cos (angle1)); + y_fixed = _cairo_fixed_from_double (yc + radius * sin (angle1)); + cr->path->start_point.x = x_fixed; + cr->path->start_point.y = y_fixed; + cr->path->is_convex = TRUE; + } + else + cr->path->is_convex = FALSE; + return CAIRO_STATUS_SUCCESS; /* any error will have already been set on cr */ } @@ -885,6 +891,161 @@ _cairo_default_context_rectangle (void *abstract_cr, return _cairo_default_context_close_path (cr); } +static cairo_status_t +_cairo_default_context_rounded_rectangle_curve_to (void *abstract_cr, + double xc, double yc, + double radius, + double angle_a, + double angle_b) +{ + double sin_a, cos_a; + double sin_b, cos_b; + double h; + + sin_a = radius * sin (angle_a); + cos_a = radius * cos (angle_a); + sin_b = radius * sin (angle_b); + cos_b = radius * cos (angle_b); + h = 4.0/3.0 * tan ((angle_b - angle_a) / 4.0); + return _cairo_default_context_curve_to (abstract_cr, + xc + cos_a - h * sin_a, + yc + sin_a + h * cos_a, + xc + cos_b + h * sin_b, + yc + sin_b - h * cos_b, + xc + cos_b, yc + sin_b); +} + +static cairo_status_t +_cairo_default_context_rounded_rectangle (void *abstract_cr, + double x, double y, + double width, double height, + double r_top_left, double r_top_right, + double r_bottom_left, double r_bottom_right) +{ + cairo_default_context_t *cr = abstract_cr; + cairo_status_t status; + double temp_scale, scale = 1.0; + double length; + cairo_bool_t path_empty; + double x_start, y_start; + + if (width <= 0.0 || height <= 0.0) + return CAIRO_STATUS_SUCCESS; + + path_empty = _cairo_path_fixed_is_empty (cr->path); + + if (r_top_left <= 0.0) + r_top_left = 0.0; + if (r_top_right <= 0.0) + r_top_left = 0.0; + if (r_bottom_left < 0.0) + r_bottom_left = 0.0; + if (r_bottom_right <= 0.0) + r_bottom_right = 0.0; + + length = r_top_left + r_top_right; + if (length > width) { + temp_scale = width / length; + scale = temp_scale; + } + length = r_top_right + r_bottom_right; + if (length > height) { + temp_scale = height / length; + if (temp_scale < scale) + scale = temp_scale; + } + length = r_bottom_right + r_bottom_left; + if (length > width) { + temp_scale = width / length; + if (temp_scale < scale) + scale = temp_scale; + } + length = r_bottom_left + r_top_left; + if (length > height) { + temp_scale = height / length; + if (temp_scale < scale) + scale = temp_scale; + } + + if (scale != 0) { + r_top_left *= scale; + r_top_right *= scale; + r_bottom_left *= scale; + r_bottom_right *= scale; + } + + status = _cairo_default_context_move_to (cr, x, y + r_top_left); + if (unlikely (status)) + return status; + + status = _cairo_default_context_rounded_rectangle_curve_to (cr, + x + r_top_left, + y + r_top_left, + r_top_left, + M_PI, + 1.5 * M_PI); + if (unlikely (status)) + return status; + + status = _cairo_default_context_rel_line_to (cr, + width - r_top_left - r_top_right, + 0); + if (unlikely (status)) + return status; + + status = _cairo_default_context_rounded_rectangle_curve_to (cr, + x + width - r_top_right, + y + r_top_right, + r_top_right, + 1.5 *M_PI, + 2.0 * M_PI); + if (unlikely (status)) + return status; + + status = _cairo_default_context_rel_line_to (cr, 0, height - r_top_right - r_bottom_right); + if (unlikely (status)) + return status; + + status = _cairo_default_context_rounded_rectangle_curve_to (cr, + x + width - r_bottom_right, + y + height - r_bottom_right, + r_bottom_right, + 0, + 0.5 * M_PI); + if (unlikely (status)) + return status; + + status = _cairo_default_context_rel_line_to (cr, -width + r_bottom_right + r_bottom_left, 0); + if (unlikely (status)) + return status; + + status = _cairo_default_context_rounded_rectangle_curve_to (cr, + x + r_bottom_left, + y + height - r_bottom_left, + r_bottom_left, + 0.5 * M_PI, + M_PI); + if (unlikely (status)) + return status; + + status = _cairo_default_context_close_path (cr); + if (unlikely (status)) + return status; + + if (path_empty) { + x_start = x; + y_start = y + r_top_left; + _cairo_gstate_user_to_backend (cr->gstate, &x_start, &y_start); + cr->path->start_point.x = _cairo_fixed_from_double (x_start); + cr->path->start_point.y = _cairo_fixed_from_double (y_start); + cr->path->is_convex = TRUE; + } + else + cr->path->is_convex = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + static void _cairo_default_context_path_extents (void *abstract_cr, double *x1, @@ -950,8 +1111,12 @@ _cairo_default_context_append_path (void *abstract_cr, const cairo_path_t *path) { cairo_default_context_t *cr = abstract_cr; + cairo_bool_t can_apply_convex = _cairo_path_fixed_is_empty (cr->path); - return _cairo_path_append_to_context (path, &cr->base); + cairo_status_t status = _cairo_path_append_to_context (path, &cr->base); + if (can_apply_convex && path->is_convex) + cr->path->is_convex = path->is_convex; + return status; } static cairo_status_t @@ -1055,7 +1220,7 @@ _cairo_default_context_fill (void *abstract_cr) { cairo_default_context_t *cr = abstract_cr; cairo_status_t status; - + status = _cairo_gstate_fill (cr->gstate, cr->path); if (unlikely (status)) return status; @@ -1297,7 +1462,6 @@ _cairo_default_context_glyphs (void *abstract_cr, cairo_glyph_text_info_t *info) { cairo_default_context_t *cr = abstract_cr; - return _cairo_gstate_show_text_glyphs (cr->gstate, glyphs, num_glyphs, info); } @@ -1307,7 +1471,6 @@ _cairo_default_context_glyph_path (void *abstract_cr, int num_glyphs) { cairo_default_context_t *cr = abstract_cr; - return _cairo_gstate_glyph_path (cr->gstate, glyphs, num_glyphs, cr->path); @@ -1320,7 +1483,6 @@ _cairo_default_context_glyph_extents (void *abstract_cr, cairo_text_extents_t *extents) { cairo_default_context_t *cr = abstract_cr; - return _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs, extents); } @@ -1458,6 +1620,7 @@ static const cairo_backend_t _cairo_default_context_backend = { _cairo_default_context_close_path, _cairo_default_context_arc, _cairo_default_context_rectangle, + _cairo_default_context_rounded_rectangle, _cairo_default_context_path_extents, _cairo_default_context_has_current_point, _cairo_default_context_get_current_point, diff --git a/src/cairo-deflate-stream.c b/src/cairo-deflate-stream.c index ae23bda94..ae23bda94 100755..100644 --- a/src/cairo-deflate-stream.c +++ b/src/cairo-deflate-stream.c diff --git a/src/cairo-deprecated.h b/src/cairo-deprecated.h index 7a56aadbf..7a56aadbf 100755..100644 --- a/src/cairo-deprecated.h +++ b/src/cairo-deprecated.h diff --git a/src/cairo-device-private.h b/src/cairo-device-private.h index 1c687d2fe..1c687d2fe 100755..100644 --- a/src/cairo-device-private.h +++ b/src/cairo-device-private.h diff --git a/src/cairo-device.c b/src/cairo-device.c index e845912a3..b4d1f8422 100755..100644 --- a/src/cairo-device.c +++ b/src/cairo-device.c @@ -159,6 +159,7 @@ _cairo_device_create_in_error (cairo_status_t status) case CAIRO_STATUS_INVALID_CONTENT: case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION: case CAIRO_STATUS_DEVICE_FINISHED: + case CAIRO_STATUS_JBIG2_GLOBAL_MISSING: default: _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_device_t *) &_nil_device; @@ -345,7 +346,7 @@ cairo_device_destroy (cairo_device_t *device) while (! cairo_list_is_empty (&device->shadow_caches)) { cairo_shadow_cache_t *shadow; - shadow = cairo_list_first_entry (&device->shadow_caches, + shadow = cairo_list_first_entry (&device->shadow_caches, cairo_shadow_cache_t, link); diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c index 16e367af8..5ac64ba98 100755..100644 --- a/src/cairo-directfb-surface.c +++ b/src/cairo-directfb-surface.c @@ -197,7 +197,7 @@ _cairo_dfb_surface_map_to_image (void *abstract_surface, _cairo_image_surface_init (&surface->image, image, surface->image.pixman_format); } - return _cairo_surface_map_to_image (&surface->image.base, extents); + return _cairo_image_surface_map_to_image (&surface->image.base, extents); } static cairo_int_status_t @@ -205,7 +205,7 @@ _cairo_dfb_surface_unmap_image (void *abstract_surface, cairo_image_surface_t *image) { cairo_dfb_surface_t *surface = abstract_surface; - return _cairo_surface_unmap_image (&surface->image.base, image); + return _cairo_image_surface_unmap_image (&surface->image.base, image); } static cairo_status_t diff --git a/src/cairo-directfb.h b/src/cairo-directfb.h index e3d818c66..e3d818c66 100755..100644 --- a/src/cairo-directfb.h +++ b/src/cairo-directfb.h diff --git a/src/cairo-drm.h b/src/cairo-drm.h index 907610dcd..907610dcd 100755..100644 --- a/src/cairo-drm.h +++ b/src/cairo-drm.h diff --git a/src/cairo-egl-context.c b/src/cairo-egl-context.c index fa52a04ba..5b67d4b3c 100755..100644 --- a/src/cairo-egl-context.c +++ b/src/cairo-egl-context.c @@ -93,7 +93,6 @@ typedef struct _cairo_egl_context { EGLSurface dummy_surface; EGLSurface current_surface; - EGLDisplay previous_display; EGLContext previous_context; EGLSurface previous_surface; } cairo_egl_context_t; @@ -110,8 +109,7 @@ _context_acquisition_changed_egl_state (cairo_egl_context_t *ctx, EGLSurface current_surface) { return ctx->previous_context != ctx->context || - ctx->previous_surface != current_surface || - ctx->previous_display != ctx->display; + ctx->previous_surface != current_surface; } static EGLSurface @@ -128,19 +126,8 @@ _egl_get_current_surface (cairo_egl_context_t *ctx) static void _egl_query_current_state (cairo_egl_context_t *ctx) { - ctx->previous_surface = eglGetCurrentSurface (EGL_DRAW); ctx->previous_context = eglGetCurrentContext (); - ctx->previous_display = eglGetCurrentDisplay (); - - /* If any of the values were none, assume they are all none. Not all - drivers seem well behaved when it comes to using these values across - multiple threads. */ - if (ctx->previous_surface == EGL_NO_SURFACE || - ctx->previous_context == EGL_NO_CONTEXT || ctx->previous_display == EGL_NO_DISPLAY) { - ctx->previous_surface = EGL_NO_SURFACE; - ctx->previous_context = EGL_NO_CONTEXT; - ctx->previous_display = EGL_NO_DISPLAY; - } + ctx->previous_surface = eglGetCurrentSurface (EGL_DRAW); } static void @@ -272,7 +259,7 @@ _cairo_egl_get_proc_address (void *data, const char *name) }; for (i = 0; func_map[i].name; i++) { - if (! strncmp (func_map[i].name, name, strlen(name))) + if (! strcmp (func_map[i].name, name)) return func_map[i].func; } @@ -352,6 +339,12 @@ cairo_egl_device_create (EGLDisplay dpy, EGLContext egl) return _cairo_gl_context_create_in_error (status); } + /* Tune the default VBO size to reduce overhead on embedded devices. + * This smaller size means that flushing needs to be done more often, + * but it is less demanding of scarce memory on embedded devices. + */ + ctx->base.vbo_size = 16*1024; + eglMakeCurrent (dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); ctx->current_surface = EGL_NO_SURFACE; diff --git a/src/cairo-error-inline.h b/src/cairo-error-inline.h index 9126c5e61..9126c5e61 100755..100644 --- a/src/cairo-error-inline.h +++ b/src/cairo-error-inline.h diff --git a/src/cairo-error-private.h b/src/cairo-error-private.h index ea9c2ea31..178078ad6 100755..100644 --- a/src/cairo-error-private.h +++ b/src/cairo-error-private.h @@ -46,10 +46,13 @@ CAIRO_BEGIN_DECLS -/* Sure wish C had a real enum type so that this would be distinct +/* _cairo_int_status: internal status + * + * Sure wish C had a real enum type so that this would be distinct * from #cairo_status_t. Oh well, without that, I'll use this bogus 100 * offset. We want to keep it fit in int8_t as the compiler may choose - * that for #cairo_status_t */ + * that for #cairo_status_t + */ enum _cairo_int_status { CAIRO_INT_STATUS_SUCCESS = 0, @@ -90,6 +93,7 @@ enum _cairo_int_status { CAIRO_INT_STATUS_DEVICE_ERROR, CAIRO_INT_STATUS_INVALID_MESH_CONSTRUCTION, CAIRO_INT_STATUS_DEVICE_FINISHED, + CAIRO_INT_STATUS_JBIG2_GLOBAL_MISSING, CAIRO_INT_STATUS_LAST_STATUS, diff --git a/src/cairo-error.c b/src/cairo-error.c index 1b9bd76be..1b9bd76be 100755..100644 --- a/src/cairo-error.c +++ b/src/cairo-error.c diff --git a/src/cairo-evas-gl-context.c b/src/cairo-evas-gl-context.c index 3f256cbc2..3cd4e0e0b 100755..100644 --- a/src/cairo-evas-gl-context.c +++ b/src/cairo-evas-gl-context.c @@ -180,7 +180,7 @@ _cairo_evas_gl_get_proc_addr (void *data, const char *name) } return evas_gl_proc_address_get (gl, name); -} +} static cairo_bool_t _context_acquisition_changed_evas_gl_state (cairo_evas_gl_context_t *ctx, @@ -204,8 +204,8 @@ _evas_gl_get_current_surface (cairo_evas_gl_context_t *ctx) static void _evas_gl_query_current_state (cairo_evas_gl_context_t *ctx) { - ctx->queried_context = evas_gl_current_context_get (ctx->evas_gl); - ctx->current_surface = evas_gl_current_surface_get (ctx->evas_gl); + ctx->queried_context = evas_gl_current_context_get (ctx->evas_gl); + ctx->current_surface = evas_gl_current_surface_get (ctx->evas_gl); } static void @@ -394,13 +394,13 @@ cairo_gl_surface_create_for_evas_gl (cairo_device_t *device, static cairo_bool_t is_evas_gl_device (cairo_device_t *device) { - return (device->backend != NULL && + return (device->backend != NULL && device->backend->type == CAIRO_DEVICE_TYPE_GL); } static cairo_evas_gl_context_t *to_evas_gl_context (cairo_device_t *device) { - return (cairo_evas_gl_context_t *) device; + return (cairo_evas_gl_context_t *) device; } cairo_public Evas_GL * @@ -412,7 +412,7 @@ cairo_evas_gl_device_get_gl (cairo_device_t *device) return NULL; } - if (! is_evas_gl_device (device)) { + if (! is_evas_gl_device (device)) { _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); return NULL; } diff --git a/src/cairo-fallback-compositor.c b/src/cairo-fallback-compositor.c index 3f6199fe2..3f6199fe2 100755..100644 --- a/src/cairo-fallback-compositor.c +++ b/src/cairo-fallback-compositor.c diff --git a/src/cairo-features-uninstalled.pc.in b/src/cairo-features-uninstalled.pc.in index b9cd9d3ad..b9cd9d3ad 100755..100644 --- a/src/cairo-features-uninstalled.pc.in +++ b/src/cairo-features-uninstalled.pc.in diff --git a/src/cairo-features.pc.in b/src/cairo-features.pc.in index 9a4b657c8..9a4b657c8 100755..100644 --- a/src/cairo-features.pc.in +++ b/src/cairo-features.pc.in diff --git a/src/cairo-filters-private.h b/src/cairo-filters-private.h index 89b7037d6..89b7037d6 100755..100644 --- a/src/cairo-filters-private.h +++ b/src/cairo-filters-private.h diff --git a/src/cairo-filters.c b/src/cairo-filters.c index dfacda58b..dfacda58b 100755..100644 --- a/src/cairo-filters.c +++ b/src/cairo-filters.c diff --git a/src/cairo-fixed-private.h b/src/cairo-fixed-private.h index b6cc6be7d..9ff8f7503 100755..100644 --- a/src/cairo-fixed-private.h +++ b/src/cairo-fixed-private.h @@ -40,12 +40,13 @@ #include "cairo-fixed-type-private.h" #include "cairo-wideint-private.h" +#include "cairoint.h" /* Implementation */ #if (CAIRO_FIXED_BITS != 32) # error CAIRO_FIXED_BITS must be 32, and the type must be a 32-bit type. -# error To remove this limitation, you will have to fix the tesselator. +# error To remove this limitation, you will have to fix the tessellator. #endif #define CAIRO_FIXED_ONE ((cairo_fixed_t)(1 << CAIRO_FIXED_FRAC_BITS)) @@ -311,7 +312,7 @@ _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); } - +/* compute y from x so that (x,y), p1, and p2 are collinear */ static inline cairo_fixed_t _cairo_edge_compute_intersection_y_for_x (const cairo_point_t *p1, const cairo_point_t *p2, @@ -332,6 +333,7 @@ _cairo_edge_compute_intersection_y_for_x (const cairo_point_t *p1, return y; } +/* compute x from y so that (x,y), p1, and p2 are collinear */ static inline cairo_fixed_t _cairo_edge_compute_intersection_x_for_y (const cairo_point_t *p1, const cairo_point_t *p2, @@ -352,6 +354,40 @@ _cairo_edge_compute_intersection_x_for_y (const cairo_point_t *p1, return x; } +/* Intersect two segments based on the algorithm described at + * http://paulbourke.net/geometry/pointlineplane/. This implementation + * uses floating point math. */ +static inline cairo_bool_t +_slow_segment_intersection (const cairo_point_t *seg1_p1, + const cairo_point_t *seg1_p2, + const cairo_point_t *seg2_p1, + const cairo_point_t *seg2_p2, + cairo_point_t *intersection) +{ + double denominator, u_a, u_b; + double seg1_dx, seg1_dy, seg2_dx, seg2_dy, seg_start_dx, seg_start_dy; + + seg1_dx = _cairo_fixed_to_double (seg1_p2->x - seg1_p1->x); + seg1_dy = _cairo_fixed_to_double (seg1_p2->y - seg1_p1->y); + seg2_dx = _cairo_fixed_to_double (seg2_p2->x - seg2_p1->x); + seg2_dy = _cairo_fixed_to_double (seg2_p2->y - seg2_p1->y); + denominator = (seg2_dy * seg1_dx) - (seg2_dx * seg1_dy); + if (denominator == 0) + return FALSE; + + seg_start_dx = _cairo_fixed_to_double (seg1_p1->x - seg2_p1->x); + seg_start_dy = _cairo_fixed_to_double (seg1_p1->y - seg2_p1->y); + u_a = ((seg2_dx * seg_start_dy) - (seg2_dy * seg_start_dx)) / denominator; + u_b = ((seg1_dx * seg_start_dy) - (seg1_dy * seg_start_dx)) / denominator; + + if (u_a <= 0 || u_a >= 1 || u_b <= 0 || u_b >= 1) + return FALSE; + + intersection->x = seg1_p1->x + _cairo_fixed_from_double ((u_a * seg1_dx)); + intersection->y = seg1_p1->y + _cairo_fixed_from_double ((u_a * seg1_dy)); + return TRUE; +} + #else # error Please define multiplication and other operands for your fixed-point type size #endif diff --git a/src/cairo-fixed-type-private.h b/src/cairo-fixed-type-private.h index 2bbd5f786..e9f26f615 100755..100644 --- a/src/cairo-fixed-type-private.h +++ b/src/cairo-fixed-type-private.h @@ -50,7 +50,7 @@ typedef cairo_int128_t cairo_fixed_64_64_t; typedef cairo_int128_t cairo_fixed_96_32_t; /* Eventually, we should allow changing this, but I think - * there are some assumptions in the tesselator about the + * there are some assumptions in the tessellator about the * size of a fixed type. For now, it must be 32. */ #define CAIRO_FIXED_BITS 32 diff --git a/src/cairo-fixed.c b/src/cairo-fixed.c index 03e055923..03e055923 100755..100644 --- a/src/cairo-fixed.c +++ b/src/cairo-fixed.c diff --git a/src/cairo-font-face-twin-data.c b/src/cairo-font-face-twin-data.c index ff09cb2be..ff09cb2be 100755..100644 --- a/src/cairo-font-face-twin-data.c +++ b/src/cairo-font-face-twin-data.c diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c index 22f87394a..22f87394a 100755..100644 --- a/src/cairo-font-face-twin.c +++ b/src/cairo-font-face-twin.c diff --git a/src/cairo-font-face.c b/src/cairo-font-face.c index b93bd8caa..3bcd2a1e6 100755..100644 --- a/src/cairo-font-face.c +++ b/src/cairo-font-face.c @@ -115,7 +115,7 @@ cairo_font_face_t * cairo_font_face_reference (cairo_font_face_t *font_face) { if (font_face == NULL || - CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count)) + CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count)) return font_face; /* We would normally assert that we have a reference here but we @@ -128,6 +128,28 @@ cairo_font_face_reference (cairo_font_face_t *font_face) } slim_hidden_def (cairo_font_face_reference); +static inline cairo_bool_t +__put(cairo_reference_count_t *v) +{ + int c, old; + + c = CAIRO_REFERENCE_COUNT_GET_VALUE(v); + while (c != 1 && (old = _cairo_atomic_int_cmpxchg_return_old(&v->ref_count, c, c - 1)) != c) + c = old; + + return c != 1; +} + +cairo_bool_t +_cairo_font_face_destroy (void *abstract_face) +{ +#if 0 /* Nothing needs to be done, we can just drop the last reference */ + cairo_font_face_t *font_face = abstract_face; + return _cairo_reference_count_dec_and_test (&font_face->ref_count); +#endif + return TRUE; +} + /** * cairo_font_face_destroy: * @font_face: a #cairo_font_face_t @@ -142,22 +164,19 @@ void cairo_font_face_destroy (cairo_font_face_t *font_face) { if (font_face == NULL || - CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count)) + CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count)) return; assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count)); - if (! _cairo_reference_count_dec_and_test (&font_face->ref_count)) - return; - - if (font_face->backend->destroy) - font_face->backend->destroy (font_face); - /* We allow resurrection to deal with some memory management for the * FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t * need to effectively mutually reference each other */ - if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count)) + if (__put (&font_face->ref_count)) + return; + + if (! font_face->backend->destroy (font_face)) return; _cairo_user_data_array_fini (&font_face->user_data); @@ -201,7 +220,7 @@ unsigned int cairo_font_face_get_reference_count (cairo_font_face_t *font_face) { if (font_face == NULL || - CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count)) + CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count)) return 0; return CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->ref_count); @@ -309,10 +328,11 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font) assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count)); - if (! _cairo_reference_count_dec_and_test (&unscaled_font->ref_count)) + if (__put (&unscaled_font->ref_count)) return; - unscaled_font->backend->destroy (unscaled_font); + if (! unscaled_font->backend->destroy (unscaled_font)) + return; free (unscaled_font); } diff --git a/src/cairo-font-options.c b/src/cairo-font-options.c index 7b26853ad..d8883a5b5 100755..100644 --- a/src/cairo-font-options.c +++ b/src/cairo-font-options.c @@ -73,7 +73,7 @@ _cairo_font_options_init_default (cairo_font_options_t *options) options->hint_style = CAIRO_HINT_STYLE_DEFAULT; options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT; options->round_glyph_positions = CAIRO_ROUND_GLYPH_POS_DEFAULT; - options->color = CAIRO_FONT_COLOR_DEFAULT; + options->color = CAIRO_FONT_COLOR_DEFAULT; } void @@ -86,7 +86,7 @@ _cairo_font_options_init_copy (cairo_font_options_t *options, options->hint_style = other->hint_style; options->hint_metrics = other->hint_metrics; options->round_glyph_positions = other->round_glyph_positions; - options->color = other->color; + options->color = other->color; } /** @@ -228,7 +228,7 @@ cairo_font_options_merge (cairo_font_options_t *options, options->hint_metrics = other->hint_metrics; if (other->round_glyph_positions != CAIRO_ROUND_GLYPH_POS_DEFAULT) options->round_glyph_positions = other->round_glyph_positions; - if (other->color != CAIRO_FONT_COLOR_DEFAULT) + if (other->color != CAIRO_FONT_COLOR_DEFAULT) options->color = other->color; } slim_hidden_def (cairo_font_options_merge); @@ -264,7 +264,7 @@ cairo_font_options_equal (const cairo_font_options_t *options, options->hint_style == other->hint_style && options->hint_metrics == other->hint_metrics && options->round_glyph_positions == other->round_glyph_positions && - options->color == other->color); + options->color == other->color); } slim_hidden_def (cairo_font_options_equal); @@ -293,7 +293,7 @@ cairo_font_options_hash (const cairo_font_options_t *options) (options->lcd_filter << 8) | (options->hint_style << 12) | (options->hint_metrics << 16) | - (options->color << 20)); + (options->color << 20)); } slim_hidden_def (cairo_font_options_hash); @@ -539,22 +539,23 @@ cairo_font_options_get_hint_metrics (const cairo_font_options_t *options) return options->hint_metrics; } + void cairo_font_options_set_font_color (cairo_font_options_t *options, - cairo_font_color_t font_color) + cairo_font_color_t font_color) { - if (cairo_font_options_status (options)) + if (cairo_font_options_status (options)) return; - options->color = font_color; + options->color = font_color; } slim_hidden_def (cairo_font_options_set_font_color); cairo_font_color_t cairo_font_options_get_font_color (const cairo_font_options_t *options) { - if (cairo_font_options_status ((cairo_font_options_t *) options)) + if (cairo_font_options_status ((cairo_font_options_t *) options)) return CAIRO_FONT_COLOR_DEFAULT; - return options->color; + return options->color; } diff --git a/src/cairo-fontconfig-private.h b/src/cairo-fontconfig-private.h index ea873abe7..ea873abe7 100755..100644 --- a/src/cairo-fontconfig-private.h +++ b/src/cairo-fontconfig-private.h diff --git a/src/cairo-freed-pool-private.h b/src/cairo-freed-pool-private.h index 0ec6de3d1..0ec6de3d1 100755..100644 --- a/src/cairo-freed-pool-private.h +++ b/src/cairo-freed-pool-private.h diff --git a/src/cairo-freed-pool.c b/src/cairo-freed-pool.c index cfdc8e96b..cfdc8e96b 100755..100644 --- a/src/cairo-freed-pool.c +++ b/src/cairo-freed-pool.c diff --git a/src/cairo-freelist-private.h b/src/cairo-freelist-private.h index 8fe6516f3..8fe6516f3 100755..100644 --- a/src/cairo-freelist-private.h +++ b/src/cairo-freelist-private.h diff --git a/src/cairo-freelist-type-private.h b/src/cairo-freelist-type-private.h index 4dd056461..4dd056461 100755..100644 --- a/src/cairo-freelist-type-private.h +++ b/src/cairo-freelist-type-private.h diff --git a/src/cairo-freelist.c b/src/cairo-freelist.c index d596eab81..d596eab81 100755..100644 --- a/src/cairo-freelist.c +++ b/src/cairo-freelist.c diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 43df78e0b..868ccc2c8 100755..100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -45,6 +45,7 @@ #include "cairo-image-surface-private.h" #include "cairo-ft-private.h" #include "cairo-pattern-private.h" +#include "cairo-pixman-private.h" #include <float.h> @@ -54,11 +55,11 @@ #include FT_FREETYPE_H #include FT_OUTLINE_H #include FT_IMAGE_H +#include FT_BITMAP_H #include FT_TRUETYPE_TABLES_H #include FT_XFREE86_H #if HAVE_FT_GLYPHSLOT_EMBOLDEN #include FT_SYNTHESIS_H -#define USE_FT_OUTLINE_EMBOLDEN 1 #endif #if HAVE_FT_LIBRARY_SETLCDFILTER @@ -587,23 +588,20 @@ _cairo_ft_unscaled_font_create_from_face (FT_Face face, return _cairo_ft_unscaled_font_create_internal (TRUE, NULL, 0, face, out); } -static void +static cairo_bool_t _cairo_ft_unscaled_font_destroy (void *abstract_font) { cairo_ft_unscaled_font_t *unscaled = abstract_font; cairo_ft_unscaled_font_map_t *font_map; - if (unscaled == NULL) - return; - font_map = _cairo_ft_unscaled_font_map_lock (); /* All created objects must have been mapped in the font map. */ assert (font_map != NULL); - if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled->base.ref_count)) { + if (! _cairo_reference_count_dec_and_test (&unscaled->base.ref_count)) { /* somebody recreated the font whilst we waited for the lock */ _cairo_ft_unscaled_font_map_unlock (); - return; + return FALSE; } _cairo_hash_table_remove (font_map->hash_table, @@ -625,6 +623,7 @@ _cairo_ft_unscaled_font_destroy (void *abstract_font) _cairo_ft_unscaled_font_map_unlock (); _cairo_ft_unscaled_font_fini (unscaled); + return TRUE; } static cairo_bool_t @@ -740,19 +739,26 @@ _compute_transform (cairo_ft_font_transform_t *sf, if (unscaled && (unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) == 0) { double min_distance = DBL_MAX; + cairo_bool_t magnify = TRUE; int i; - int best_i = 0; double best_x_size = 0; double best_y_size = 0; for (i = 0; i < unscaled->face->num_fixed_sizes; i++) { - double x_size = unscaled->face->available_sizes[i].y_ppem / 64.; + double x_size = unscaled->face->available_sizes[i].x_ppem / 64.; double y_size = unscaled->face->available_sizes[i].y_ppem / 64.; - double distance = fabs (y_size - y_scale); + double distance = y_size - y_scale; + + /* + * distance is positive if current strike is larger than desired + * size, and negative if smaller. + * + * We like to prefer down-scaling to upscaling. + */ - if (distance <= min_distance) { - min_distance = distance; - best_i = i; + if ((magnify && distance >= 0) || fabs (distance) <= min_distance) { + magnify = distance < 0; + min_distance = fabs (distance); best_x_size = x_size; best_y_size = y_size; } @@ -1114,15 +1120,17 @@ _fill_xrender_bitmap(FT_Bitmap *target, */ static cairo_status_t _get_bitmap_surface (FT_Bitmap *bitmap, + FT_Library library, cairo_bool_t own_buffer, cairo_font_options_t *font_options, cairo_image_surface_t **surface) { - int width, height, stride; + unsigned int width, height; unsigned char *data; int format = CAIRO_FORMAT_A8; + int stride; cairo_image_surface_t *image; - cairo_bool_t component_alpha = TRUE; + cairo_bool_t component_alpha = TRUE; width = bitmap->width; height = bitmap->rows; @@ -1179,8 +1187,18 @@ _get_bitmap_surface (FT_Bitmap *bitmap, case FT_PIXEL_MODE_LCD: case FT_PIXEL_MODE_LCD_V: case FT_PIXEL_MODE_GRAY: - if (font_options->antialias != CAIRO_ANTIALIAS_SUBPIXEL) { + if (font_options->antialias != CAIRO_ANTIALIAS_SUBPIXEL || + bitmap->pixel_mode == FT_PIXEL_MODE_GRAY) + { stride = bitmap->pitch; + + /* We don't support stride not multiple of 4. */ + if (stride & 3) + { + assert (!own_buffer); + goto convert; + } + if (own_buffer) { data = bitmap->buffer; } else { @@ -1193,49 +1211,91 @@ _get_bitmap_surface (FT_Bitmap *bitmap, format = CAIRO_FORMAT_A8; } else { - /* color glyph is rendered as bitmap, does not come from - * _fill_xrender_bitmap */ - if (! own_buffer) { - stride = bitmap->pitch; - data = _cairo_malloc_ab (height, stride); - if (!data) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - memcpy (data, bitmap->buffer, stride * height); - format = CAIRO_FORMAT_A8; - } else { - /* if we get there, the data from the source bitmap - * really comes from _fill_xrender_bitmap, and is - * made of 32-bit ARGB or ABGR values */ - assert (own_buffer != 0); - assert (bitmap->pixel_mode != FT_PIXEL_MODE_GRAY); - - data = bitmap->buffer; - stride = bitmap->pitch; - format = CAIRO_FORMAT_ARGB32; - } - } - break; - // color font - /* - case FT_PIXEL_MODE_BGRA: + /* color glyph is rendered as bitmap, does not come from + * _fill_xrender_bitmap */ + if (! own_buffer) { stride = bitmap->pitch; - if (own_buffer) { - data = bitmap->buffer; - } else { - data = _cairo_malloc_ab (height, stride); - if (!data) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - memcpy (data, bitmap->buffer, stride * height); - } + data = _cairo_malloc_ab (height, stride); + if (!data) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (data, bitmap->buffer, stride * height); + format = CAIRO_FORMAT_A8; + } else { + /* if we get there, the data from the source bitmap + * really comes from _fill_xrender_bitmap, and is + * made of 32-bit ARGB or ABGR values */ + assert (own_buffer != 0); + assert (bitmap->pixel_mode != FT_PIXEL_MODE_GRAY); + data = bitmap->buffer; + stride = bitmap->pitch; format = CAIRO_FORMAT_ARGB32; - component_alpha = FALSE; + } + } break; - */ + // color font + #if 0 // TODO(suyambu.rm) Build error for Tizen 3.0 + case FT_PIXEL_MODE_BGRA: + stride = bitmap->pitch; + + if (own_buffer) { + data = bitmap->buffer; + } else { + data = _cairo_malloc_ab (height, stride); + if (!data) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (data, bitmap->buffer, stride * height); + } + + format = CAIRO_FORMAT_ARGB32; + component_alpha = FALSE; + break; + #endif case FT_PIXEL_MODE_GRAY2: case FT_PIXEL_MODE_GRAY4: + convert: + if (!own_buffer && library) + { + /* This is pretty much the only case that we can get in here. */ + /* Convert to 8bit grayscale. */ + + FT_Bitmap tmp; + FT_Int align; + + format = CAIRO_FORMAT_A8; + + align = cairo_format_stride_for_width (format, bitmap->width); + + FT_Bitmap_New( &tmp ); + + if (FT_Bitmap_Convert( library, bitmap, &tmp, align )) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + FT_Bitmap_Done( library, bitmap ); + *bitmap = tmp; + + stride = bitmap->pitch; + data = _cairo_malloc_ab (height, stride); + if (!data) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (bitmap->num_grays != 256) + { + unsigned int x, y; + unsigned int mul = 255 / (bitmap->num_grays - 1); + FT_Byte *p = bitmap->buffer; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + p[x] *= mul; + p += bitmap->pitch; + } + } + + memcpy (data, bitmap->buffer, stride * height); + break; + } /* These could be triggered by very rare types of TrueType fonts */ default: if (own_buffer) @@ -1429,7 +1489,7 @@ _render_glyph_outline (FT_Face face, /* Note: * _get_bitmap_surface will free bitmap.buffer if there is an error */ - status = _get_bitmap_surface (&bitmap, TRUE, font_options, surface); + status = _get_bitmap_surface (&bitmap, NULL, TRUE, font_options, surface); if (unlikely (status)) return status; @@ -1470,6 +1530,7 @@ _render_glyph_bitmap (FT_Face face, return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _get_bitmap_surface (&glyphslot->bitmap, + glyphslot->library, FALSE, font_options, surface); if (unlikely (status)) @@ -1511,7 +1572,7 @@ _transform_glyph_bitmap (cairo_matrix_t * shape, * the "shape" portion of the font transform */ original_to_transformed = *shape; - + cairo_surface_get_device_offset (&(*surface)->base, &origin_x, &origin_y); orig_width = (*surface)->width; orig_height = (*surface)->height; @@ -2193,10 +2254,23 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, vertical_layout = TRUE; } - #ifdef FT_LOAD_COLOR - /*Color-glyph support */ - load_flags |= FT_LOAD_COLOR; - #endif +#ifdef FT_LOAD_COLOR + /* Color-glyph support: + * + * This flags needs plumbing through fontconfig (does it?), and + * maybe we should cache color and grayscale bitmaps separately + * such that users of the font (ie. the surface) can choose which + * version to use based on target content type. + * + * Moreover, none of our backends and compositors currently support + * color glyphs. As such, this is currently disabled. + */ + /* load_flags |= FT_LOAD_COLOR; */ + + /* Color-glyph support */ + if (scaled_font->ft_options.base.color == CAIRO_FONT_COLOR_DEFAULT) + load_flags |= FT_LOAD_COLOR; +#endif error = FT_Load_Glyph (face, _cairo_scaled_glyph_index(scaled_glyph), @@ -2215,22 +2289,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, */ #if HAVE_FT_GLYPHSLOT_EMBOLDEN if (scaled_font->ft_options.synth_flags & CAIRO_FT_SYNTHESIZE_BOLD) -#if USE_FT_OUTLINE_EMBOLDEN - { - /*UX team request us to use 64 instead 34*/ - FT_Pos xstr; - if(face && face->size) - xstr = FT_MulFix(face->units_per_EM, face->size->metrics.y_scale) / 64; - else - goto FAIL; - if(face->glyph) - FT_Outline_Embolden(&face->glyph->outline, xstr); - else - goto FAIL; - } -#else FT_GlyphSlot_Embolden (glyph); -#endif // USE_FT_OUTLINE_EMBOLDEN #endif #if HAVE_FT_GLYPHSLOT_OBLIQUE @@ -2384,22 +2443,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, } #if HAVE_FT_GLYPHSLOT_EMBOLDEN if (scaled_font->ft_options.synth_flags & CAIRO_FT_SYNTHESIZE_BOLD) -#if USE_FT_OUTLINE_EMBOLDEN - { - /*UX team request us to use 64 instead 34*/ - FT_Pos xstr; - if(face && face->size) - xstr = FT_MulFix(face->units_per_EM, face->size->metrics.y_scale) / 64; - else - goto FAIL; - if(face->glyph) - FT_Outline_Embolden(&face->glyph->outline, xstr); - else - goto FAIL; - } -#else - FT_GlyphSlot_Embolden (glyph); -#endif // USE_FT_OUTLINE_EMBOLDEN + FT_GlyphSlot_Embolden (glyph); #endif #if HAVE_FT_GLYPHSLOT_OBLIQUE if (scaled_font->ft_options.synth_flags & CAIRO_FT_SYNTHESIZE_OBLIQUE) @@ -2752,7 +2796,7 @@ _cairo_ft_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, } #endif -static void +static cairo_bool_t _cairo_ft_font_face_destroy (void *abstract_face) { cairo_ft_font_face_t *font_face = abstract_face; @@ -2778,12 +2822,10 @@ _cairo_ft_font_face_destroy (void *abstract_face) font_face->unscaled->faces == font_face && CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->unscaled->base.ref_count) > 1) { - cairo_font_face_reference (&font_face->base); - _cairo_unscaled_font_destroy (&font_face->unscaled->base); font_face->unscaled = NULL; - return; + return FALSE; } if (font_face->unscaled) { @@ -2815,6 +2857,8 @@ _cairo_ft_font_face_destroy (void *abstract_face) cairo_font_face_destroy (font_face->resolved_font_face); } #endif + + return TRUE; } static cairo_font_face_t * diff --git a/src/cairo-ft-private.h b/src/cairo-ft-private.h index 392151866..0dc811472 100755..100644 --- a/src/cairo-ft-private.h +++ b/src/cairo-ft-private.h @@ -37,8 +37,8 @@ #ifndef CAIRO_FT_PRIVATE_H #define CAIRO_FT_PRIVATE_H -#include "cairo-ft.h" #include "cairoint.h" +#include "cairo-ft.h" #if CAIRO_HAS_FT_FONT diff --git a/src/cairo-ft.h b/src/cairo-ft.h index 29c43c965..29c43c965 100755..100644 --- a/src/cairo-ft.h +++ b/src/cairo-ft.h diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c index c9f7782d1..57d7ddf31 100755..100644 --- a/src/cairo-gl-composite.c +++ b/src/cairo-gl-composite.c @@ -76,7 +76,7 @@ _cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup, _cairo_gl_operand_copy (&setup->src, source); if (source->type == CAIRO_GL_OPERAND_TEXTURE || source->type == CAIRO_GL_OPERAND_GAUSSIAN) - status = _cairo_gl_surface_resolve_multisampling (source->texture.surface); + status = _cairo_gl_surface_resolve_multisampling (source->texture.surface); } void @@ -96,7 +96,7 @@ _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup, { _cairo_gl_operand_destroy (&setup->mask); if (pattern == NULL) - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; return _cairo_gl_operand_init (&setup->mask, pattern, setup->dst, sample, extents, use_texgen, FALSE); @@ -112,7 +112,7 @@ _cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup, _cairo_gl_operand_copy (&setup->mask, mask); if (mask->type == CAIRO_GL_OPERAND_TEXTURE || mask->type == CAIRO_GL_OPERAND_GAUSSIAN) - status = _cairo_gl_surface_resolve_multisampling (mask->texture.surface); + status = _cairo_gl_surface_resolve_multisampling (mask->texture.surface); } } @@ -146,7 +146,7 @@ static void _cairo_gl_composite_bind_to_shader (cairo_gl_context_t *ctx, cairo_gl_composite_t *setup) { - _cairo_gl_shader_bind_matrix4f(ctx, CAIRO_GL_UNIFORM_PROJECTION_MATRIX, + _cairo_gl_shader_bind_matrix4f(ctx, ctx->current_shader->mvp_location, ctx->modelviewprojection_matrix); _cairo_gl_operand_bind_to_shader (ctx, &setup->src, CAIRO_GL_TEX_SOURCE); _cairo_gl_operand_bind_to_shader (ctx, &setup->mask, CAIRO_GL_TEX_MASK); @@ -259,7 +259,7 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx, if (operand->constant.encode_as_attribute) { dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4, GL_FLOAT, GL_FALSE, ctx->vertex_size, - ctx->vb + vertex_offset); + ctx->vbo ? (GLvoid *)vertex_offset : (GLvoid *)(ctx->vb + vertex_offset)); dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX); } break; @@ -278,7 +278,7 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx, if (! operand->texture.texgen) { dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2, GL_FLOAT, GL_FALSE, ctx->vertex_size, - ctx->vb + offset); + ctx->vbo ? (GLvoid *)offset : (GLvoid *)(ctx->vb + offset)); dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit); offset += 2 * sizeof (GLfloat); } @@ -287,12 +287,12 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx, dispatch->VertexAttribPointer (CAIRO_GL_START_COORD0_ATTRIB_INDEX + tex_unit, 2, GL_FLOAT, GL_FALSE, ctx->vertex_size, - ctx->vb + offset); + ctx->vbo ? (GLvoid *)offset : (GLvoid *)(ctx->vb + offset)); dispatch->EnableVertexAttribArray (CAIRO_GL_START_COORD0_ATTRIB_INDEX + tex_unit); dispatch->VertexAttribPointer (CAIRO_GL_STOP_COORD0_ATTRIB_INDEX + tex_unit, 2, GL_FLOAT, GL_FALSE, ctx->vertex_size, - ctx->vb + offset + 2 * sizeof (float)); + ctx->vbo ? (GLvoid *)(offset + 2 * sizeof (float)) : (GLvoid *)(ctx->vb + offset + 2 * sizeof (float))); dispatch->EnableVertexAttribArray (CAIRO_GL_STOP_COORD0_ATTRIB_INDEX + tex_unit); } break; @@ -312,7 +312,7 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx, if (! operand->gradient.texgen) { dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2, GL_FLOAT, GL_FALSE, ctx->vertex_size, - ctx->vb + vertex_offset); + ctx->vbo ? (GLvoid *)vertex_offset : (GLvoid *)(ctx->vb + vertex_offset)); dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit); } break; @@ -341,7 +341,7 @@ _cairo_gl_context_setup_spans (cairo_gl_context_t *ctx, dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4, GL_UNSIGNED_BYTE, GL_TRUE, vertex_size, - ctx->vb + vertex_offset); + ctx->vbo ? (GLvoid *)vertex_offset : (GLvoid *)(ctx->vb + vertex_offset)); dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX); ctx->spans = TRUE; } @@ -617,7 +617,7 @@ _cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx, if (_cairo_gl_context_is_flushed (ctx)) { ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2, GL_FLOAT, GL_FALSE, size_per_vertex, - ctx->vb); + ctx->vbo ? 0 : ctx->vb); ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX); } @@ -655,17 +655,18 @@ _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup, _enable_stencil_buffer (ctx); _enable_scissor_buffer (ctx); + + /* We only want to clear the part of the stencil buffer + * that we are about to use. It also does not hurt to + * scissor around the painted clip. */ _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (clip)); if (clip_is_equal) goto activate_stencil_buffer_and_return; - /* Clear the stencil buffer, but only the areas that we are - * going to be drawing to. */ - if (old_clip) { - _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer); - } - + if (old_clip) { + _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer); + } setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip); ctx->dispatch.ClearStencil (0); @@ -783,6 +784,7 @@ _cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup, ctx->pre_shader = NULL; return status; } + if (ctx->current_shader != shader) _cairo_gl_composite_flush (ctx); @@ -842,10 +844,12 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup, setup->dst->content_cleared = FALSE; _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample); + if (ctx->states_cache.blend_enabled == FALSE) { ctx->dispatch.Enable (GL_BLEND); ctx->states_cache.blend_enabled = TRUE; } + status = _cairo_gl_set_operands_and_operator (setup, ctx); if (unlikely (status)) goto FAIL; @@ -869,18 +873,24 @@ _cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx) cairo_array_t* indices = &ctx->tristrip_indices; const unsigned short *indices_array = _cairo_array_index_const (indices, 0); + if (ctx->ibo) { + ctx->dispatch.BufferSubData (GL_ELEMENT_ARRAY_BUFFER, 0, + _cairo_array_num_elements (indices) * sizeof (unsigned short), + (GLvoid *) indices_array); + } + if (ctx->pre_shader) { cairo_gl_shader_t *prev_shader = ctx->current_shader; _cairo_gl_set_shader (ctx, ctx->pre_shader); _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE); - ctx->dispatch.DrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array); + ctx->dispatch.DrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, ctx->ibo ? 0 : indices_array); _cairo_gl_set_shader (ctx, prev_shader); _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE); } - ctx->dispatch.DrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array); + ctx->dispatch.DrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, ctx->ibo ? 0 :indices_array); _cairo_array_truncate (indices, 0); } @@ -894,18 +904,24 @@ _cairo_gl_composite_draw_line (cairo_gl_context_t *ctx) if (ctx->draw_mode == CAIRO_GL_LINES) type = GL_LINES; + if (ctx->ibo) { + ctx->dispatch.BufferSubData (GL_ELEMENT_ARRAY_BUFFER, 0, + _cairo_array_num_elements (indices) * sizeof (unsigned short), + (GLvoid *) indices_array); + } + if (ctx->pre_shader) { cairo_gl_shader_t *prev_shader = ctx->current_shader; _cairo_gl_set_shader (ctx, ctx->pre_shader); _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE); - ctx->dispatch.DrawElements (type, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array); + ctx->dispatch.DrawElements (type, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, ctx->ibo ? 0 : indices_array); _cairo_gl_set_shader (ctx, prev_shader); _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE); } - ctx->dispatch.DrawElements (type, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array); + ctx->dispatch.DrawElements (type, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, ctx->ibo ? 0 : indices_array); _cairo_array_truncate (indices, 0); } @@ -954,6 +970,11 @@ _cairo_gl_composite_draw_triangles_with_clip_region (cairo_gl_context_t *ctx, static void _cairo_gl_composite_unmap_vertex_buffer (cairo_gl_context_t *ctx) { + if (ctx->vbo) { + ctx->dispatch.BufferSubData (GL_ARRAY_BUFFER, 0, + ctx->vb_offset, + (const GLvoid *)ctx->vb); + } ctx->vb_offset = 0; } @@ -966,7 +987,11 @@ _cairo_gl_composite_flush (cairo_gl_context_t *ctx) if (_cairo_gl_context_is_flushed (ctx)) return; + /* ensure we are binding to vbo and ibo */ + _cairo_gl_ensure_drawbuffers (ctx); + count = ctx->vb_offset / ctx->vertex_size; + _cairo_gl_composite_unmap_vertex_buffer (ctx); if (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS) { @@ -996,7 +1021,8 @@ _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx, ctx->primitive_type = primitive_type; } - if (ctx->vb_offset + n_vertices * ctx->vertex_size > CAIRO_GL_VBO_SIZE) + assert(ctx->vbo_size > 0); + if (ctx->vb_offset + n_vertices * ctx->vertex_size > ctx->vbo_size) _cairo_gl_composite_flush (ctx); } @@ -1141,17 +1167,17 @@ _cairo_gl_composite_emit_solid_span (cairo_gl_context_t *ctx, v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset]; - v[15 + 20*src_use_atlas + 20*mask_use_atlas] = + v[15 + 20*src_use_atlas + 20*mask_use_atlas] = v[ 6 + 8*src_use_atlas + 8*mask_use_atlas] = v[ 0 ] = x1; v[10 + 12*src_use_atlas + 12*mask_use_atlas] = v[ 4 + 4*src_use_atlas + 4*mask_use_atlas] = v[ 1 ] = y1; v[12 + 16*src_use_atlas + 16*mask_use_atlas] = - v[ 9 + 12*src_use_atlas + 12*mask_use_atlas] = + v[ 9 + 12*src_use_atlas + 12*mask_use_atlas] = v[ 3 + 4*src_use_atlas + 4*mask_use_atlas] = x2; - v[16 + 20*src_use_atlas + 20*mask_use_atlas] = - v[13 + 16*src_use_atlas + 16*mask_use_atlas] = + v[16 + 20*src_use_atlas + 20*mask_use_atlas] = + v[13 + 16*src_use_atlas + 16*mask_use_atlas] = v[ 7 + 8*src_use_atlas + 8*mask_use_atlas] = y2; fi.bytes[0] = 0; @@ -1159,77 +1185,77 @@ _cairo_gl_composite_emit_solid_span (cairo_gl_context_t *ctx, fi.bytes[2] = 0; fi.bytes[3] = alpha; v[17 + 24*src_use_atlas + 24*mask_use_atlas] = - v[14 + 20*src_use_atlas + 20*mask_use_atlas] = - v[11 + 16*src_use_atlas + 16*mask_use_atlas] = - v[ 8 + 12*src_use_atlas + 12*mask_use_atlas] = - v[ 5 + 8*src_use_atlas + 8*mask_use_atlas] = + v[14 + 20*src_use_atlas + 20*mask_use_atlas] = + v[11 + 16*src_use_atlas + 16*mask_use_atlas] = + v[ 8 + 12*src_use_atlas + 12*mask_use_atlas] = + v[ 5 + 8*src_use_atlas + 8*mask_use_atlas] = v[ 2 + 4*src_use_atlas + 4*mask_use_atlas ] = fi.f; if (src_use_atlas) { v[ 2 ] = - v[ 5 + 4*src_use_atlas + 4*mask_use_atlas] = - v[ 8 + 8*src_use_atlas + 8*mask_use_atlas] = + v[ 5 + 4*src_use_atlas + 4*mask_use_atlas] = + v[ 8 + 8*src_use_atlas + 8*mask_use_atlas] = v[11 + 12*src_use_atlas + 12*mask_use_atlas] = v[14 + 16*src_use_atlas + 16*mask_use_atlas] = - v[17 + 20*src_use_atlas + 20*mask_use_atlas] = + v[17 + 20*src_use_atlas + 20*mask_use_atlas] = ctx->operands[CAIRO_GL_TEX_SOURCE].texture.p1.x; v[ 3 ] = - v[ 6 + 4*src_use_atlas + 4*mask_use_atlas] = - v[ 9 + 8*src_use_atlas + 8*mask_use_atlas] = + v[ 6 + 4*src_use_atlas + 4*mask_use_atlas] = + v[ 9 + 8*src_use_atlas + 8*mask_use_atlas] = v[12 + 12*src_use_atlas + 12*mask_use_atlas] = v[15 + 16*src_use_atlas + 16*mask_use_atlas] = - v[18 + 20*src_use_atlas + 20*mask_use_atlas] = + v[18 + 20*src_use_atlas + 20*mask_use_atlas] = ctx->operands[CAIRO_GL_TEX_SOURCE].texture.p1.y; - + v[ 4 ] = - v[ 7 + 4*src_use_atlas + 4*mask_use_atlas] = - v[10 + 8*src_use_atlas + 8*mask_use_atlas] = + v[ 7 + 4*src_use_atlas + 4*mask_use_atlas] = + v[10 + 8*src_use_atlas + 8*mask_use_atlas] = v[13 + 12*src_use_atlas + 12*mask_use_atlas] = v[16 + 16*src_use_atlas + 16*mask_use_atlas] = - v[19 + 20*src_use_atlas + 20*mask_use_atlas] = + v[19 + 20*src_use_atlas + 20*mask_use_atlas] = ctx->operands[CAIRO_GL_TEX_SOURCE].texture.p2.x; v[ 5 ] = - v[ 8 + 4*src_use_atlas + 4*mask_use_atlas] = - v[11 + 8*src_use_atlas + 8*mask_use_atlas] = + v[ 8 + 4*src_use_atlas + 4*mask_use_atlas] = + v[11 + 8*src_use_atlas + 8*mask_use_atlas] = v[14 + 12*src_use_atlas + 12*mask_use_atlas] = v[17 + 16*src_use_atlas + 16*mask_use_atlas] = - v[20 + 20*src_use_atlas + 20*mask_use_atlas] = + v[20 + 20*src_use_atlas + 20*mask_use_atlas] = ctx->operands[CAIRO_GL_TEX_SOURCE].texture.p2.y; } if (mask_use_atlas) { v[ 2 + 4*src_use_atlas ] = - v[ 5 + 8*src_use_atlas + 4*mask_use_atlas] = - v[ 8 + 12*src_use_atlas + 8*mask_use_atlas] = + v[ 5 + 8*src_use_atlas + 4*mask_use_atlas] = + v[ 8 + 12*src_use_atlas + 8*mask_use_atlas] = v[11 + 16*src_use_atlas + 12*mask_use_atlas] = v[14 + 20*src_use_atlas + 16*mask_use_atlas] = - v[17 + 24*src_use_atlas + 20*mask_use_atlas] = + v[17 + 24*src_use_atlas + 20*mask_use_atlas] = ctx->operands[CAIRO_GL_TEX_MASK].texture.p1.x; v[ 3 + 4*src_use_atlas ] = - v[ 6 + 4*src_use_atlas + 4*mask_use_atlas] = - v[ 9 + 8*src_use_atlas + 8*mask_use_atlas] = + v[ 6 + 4*src_use_atlas + 4*mask_use_atlas] = + v[ 9 + 8*src_use_atlas + 8*mask_use_atlas] = v[12 + 12*src_use_atlas + 12*mask_use_atlas] = v[15 + 16*src_use_atlas + 16*mask_use_atlas] = - v[18 + 20*src_use_atlas + 20*mask_use_atlas] = + v[18 + 20*src_use_atlas + 20*mask_use_atlas] = ctx->operands[CAIRO_GL_TEX_MASK].texture.p1.y; - + v[ 4 + 4*src_use_atlas ] = - v[ 7 + 4*src_use_atlas + 4*mask_use_atlas] = - v[10 + 8*src_use_atlas + 8*mask_use_atlas] = + v[ 7 + 4*src_use_atlas + 4*mask_use_atlas] = + v[10 + 8*src_use_atlas + 8*mask_use_atlas] = v[13 + 12*src_use_atlas + 12*mask_use_atlas] = v[16 + 16*src_use_atlas + 16*mask_use_atlas] = - v[19 + 20*src_use_atlas + 20*mask_use_atlas] = + v[19 + 20*src_use_atlas + 20*mask_use_atlas] = ctx->operands[CAIRO_GL_TEX_MASK].texture.p2.x; v[ 5 + 4*src_use_atlas ] = - v[ 8 + 4*src_use_atlas + 4*mask_use_atlas] = - v[11 + 8*src_use_atlas + 8*mask_use_atlas] = + v[ 8 + 4*src_use_atlas + 4*mask_use_atlas] = + v[11 + 8*src_use_atlas + 8*mask_use_atlas] = v[14 + 12*src_use_atlas + 12*mask_use_atlas] = v[17 + 16*src_use_atlas + 16*mask_use_atlas] = - v[20 + 20*src_use_atlas + 20*mask_use_atlas] = + v[20 + 20*src_use_atlas + 20*mask_use_atlas] = ctx->operands[CAIRO_GL_TEX_MASK].texture.p2.y; } @@ -1309,17 +1335,17 @@ _cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx, static inline void _cairo_gl_composite_emit_color_glyph_vertex (cairo_gl_context_t *ctx, - GLfloat x, GLfloat y, - GLfloat glyph_x, GLfloat glyph_y) + GLfloat x, GLfloat y, + GLfloat glyph_x, GLfloat glyph_y) { - GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset]; + GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset]; - *vb++ = x; - *vb++ = y; - *vb++ = glyph_x; - *vb++ = glyph_y; + *vb++ = x; + *vb++ = y; + *vb++ = glyph_x; + *vb++ = glyph_y; - ctx->vb_offset += ctx->vertex_size; + ctx->vb_offset += ctx->vertex_size; } static void @@ -1348,26 +1374,26 @@ _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx, static void _cairo_gl_composite_emit_color_glyph (cairo_gl_context_t *ctx, - GLfloat x1, GLfloat y1, - GLfloat x2, GLfloat y2, - GLfloat glyph_x1, GLfloat glyph_y1, - GLfloat glyph_x2, GLfloat glyph_y2) + GLfloat x1, GLfloat y1, + GLfloat x2, GLfloat y2, + GLfloat glyph_x1, GLfloat glyph_y1, + GLfloat glyph_x2, GLfloat glyph_y2) { - if (ctx->draw_mode != CAIRO_GL_VERTEX) { + if (ctx->draw_mode != CAIRO_GL_VERTEX) { _cairo_gl_composite_flush (ctx); ctx->draw_mode = CAIRO_GL_VERTEX; - } + } - _cairo_gl_composite_prepare_buffer (ctx, 6, - CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES); + _cairo_gl_composite_prepare_buffer (ctx, 6, + CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES); - _cairo_gl_composite_emit_color_glyph_vertex (ctx, x1, y1, glyph_x1, glyph_y1); - _cairo_gl_composite_emit_color_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1); - _cairo_gl_composite_emit_color_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2); + _cairo_gl_composite_emit_color_glyph_vertex (ctx, x1, y1, glyph_x1, glyph_y1); + _cairo_gl_composite_emit_color_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1); + _cairo_gl_composite_emit_color_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2); - _cairo_gl_composite_emit_color_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1); - _cairo_gl_composite_emit_color_glyph_vertex (ctx, x2, y2, glyph_x2, glyph_y2); - _cairo_gl_composite_emit_color_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2); + _cairo_gl_composite_emit_color_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1); + _cairo_gl_composite_emit_color_glyph_vertex (ctx, x2, y2, glyph_x2, glyph_y2); + _cairo_gl_composite_emit_color_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2); } static void @@ -1400,13 +1426,12 @@ _cairo_gl_composite_emit_solid_glyph (cairo_gl_context_t *ctx, cairo_gl_emit_glyph_t _cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx, - const cairo_bool_t is_color_glyph) + const cairo_bool_t is_color_glyph) { - - if ( is_color_glyph) { + if ( is_color_glyph) { /* color glyph ignore all source and mask */ return _cairo_gl_composite_emit_color_glyph; - } + } switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) { default: diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c index a22ac63bb..dbb6f162f 100755..100644 --- a/src/cairo-gl-device.c +++ b/src/cairo-gl-device.c @@ -215,6 +215,15 @@ _gl_destroy (void *device) cairo_region_destroy (ctx->clip_region); free (ctx->vb); + if (ctx->vao) { + ctx->dispatch.DeleteVertexArrays (1, &ctx->vao); + } + if (ctx->vbo) { + ctx->dispatch.DeleteBuffers (1, &ctx->vbo); + } + if (ctx->ibo) { + ctx->dispatch.DeleteBuffers (1, &ctx->ibo); + } ctx->destroy (ctx); @@ -269,6 +278,11 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) cairo_bool_t is_gles = (gl_flavor == CAIRO_GL_FLAVOR_ES2 || gl_flavor == CAIRO_GL_FLAVOR_ES3); + if (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 30) && + gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) + ctx->is_gl33 = TRUE; + else + ctx->is_gl33 = FALSE; _cairo_device_init (&ctx->base, &_cairo_gl_device_backend); /* XXX The choice of compositor should be made automatically at runtime. @@ -293,7 +307,8 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) /* Check for required extensions */ if (is_desktop) { - if (_cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_texture_non_power_of_two")) { + if (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) || + _cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_texture_non_power_of_two")) { ctx->tex_target = GL_TEXTURE_2D; ctx->has_npot_repeat = TRUE; } else if (_cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_texture_rectangle")) { @@ -326,7 +341,9 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) _cairo_gl_has_extension (&ctx->dispatch, "GL_MESA_pack_invert"); ctx->has_packed_depth_stencil = - (is_desktop && _cairo_gl_has_extension (&ctx->dispatch, "GL_EXT_packed_depth_stencil")) || + (is_desktop && + (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) || + _cairo_gl_has_extension (&ctx->dispatch, "GL_EXT_packed_depth_stencil"))) || (is_gles && _cairo_gl_has_extension (&ctx->dispatch, "GL_OES_packed_depth_stencil")); ctx->num_samples = 1; @@ -336,51 +353,51 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) if (is_desktop && ctx->has_packed_depth_stencil && (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) || _cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_framebuffer_object") || - (_cairo_gl_has_extension (&ctx->dispatch, "GL_EXT_framebuffer_blit") && - _cairo_gl_has_extension (&ctx->dispatch, "GL_EXT_framebuffer_multisample")))) { - ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples); + (_cairo_gl_has_extension (&ctx->dispatch, "GL_EXT_framebuffer_blit") && + _cairo_gl_has_extension (&ctx->dispatch, "GL_EXT_framebuffer_multisample")))) { + ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples); } #endif #if (CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE) && GL_MAX_SAMPLES_EXT if (is_gles && ctx->has_packed_depth_stencil && _cairo_gl_has_extension (&ctx->dispatch, "GL_EXT_multisampled_render_to_texture")) { - ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples); - ctx->msaa_type = CAIRO_GL_EXT_MULTISAMPLE_TO_TEXTURE; + ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples); + ctx->msaa_type = CAIRO_GL_EXT_MULTISAMPLE_TO_TEXTURE; } #endif #if (CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE) && GL_MAX_SAMPLES_IMG if (ctx->msaa_type == CAIRO_GL_NONE_MULTISAMPLE_TO_TEXTURE && - is_gles && - ctx->has_packed_depth_stencil && + is_gles && + ctx->has_packed_depth_stencil && _cairo_gl_has_extension (&ctx->dispatch, "GL_IMG_multisampled_render_to_texture")) { - ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES_IMG, &ctx->num_samples); - ctx->msaa_type = CAIRO_GL_IMG_MULTISAMPLE_TO_TEXTURE; + ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES_IMG, &ctx->num_samples); + ctx->msaa_type = CAIRO_GL_IMG_MULTISAMPLE_TO_TEXTURE; } #endif #if (CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE) && GL_MAX_SAMPLES_ANGLE if (ctx->msaa_type == CAIRO_GL_NONE_MULTISAMPLE_TO_TEXTURE && - is_gles && - ctx->has_packed_depth_stencil && + is_gles && + ctx->has_packed_depth_stencil && _cairo_gl_has_extension (&ctx->dispatch, "GL_ANGLE_framebuffer_blit") && - _cairo_gl_has_extension (&ctx->dispatch, "GL_ANGLE_framebuffer_multisample")) { - ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES_ANGLE, &ctx->num_samples); + _cairo_gl_has_extension (&ctx->dispatch, "GL_ANGLE_framebuffer_multisample")) { + ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES_ANGLE, &ctx->num_samples); ctx->has_angle_multisampling = TRUE; } #endif #if CAIRO_HAS_GLESV3_SURFACE || CAIRO_HAS_EVASGL_SURFACE if (ctx->msaa_type == CAIRO_GL_NONE_MULTISAMPLE_TO_TEXTURE && - is_gles && ctx->has_packed_depth_stencil) { - ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES, &ctx->num_samples); - /* this is work around for evasgl. At this moment, if - we still get samples == 1, it means gles2 does not have any + is_gles && ctx->has_packed_depth_stencil) { + ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES, &ctx->num_samples); + /* this is work around for evasgl. At this moment, if + we still get samples == 1, it means gles2 does not have any support for extensions we have supported - */ - if (gl_flavor == CAIRO_GL_FLAVOR_ES2) - ctx->num_samples = 1; + */ + if (gl_flavor == CAIRO_GL_FLAVOR_ES2) + ctx->num_samples = 1; } #endif @@ -410,18 +427,45 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) if (unlikely (status)) return status; - ctx->vb = malloc (CAIRO_GL_VBO_SIZE); + ctx->vbo_size = _cairo_gl_get_vbo_size(); + + if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP && + gl_version > CAIRO_GL_VERSION_ENCODE (3, 0)) { + ctx->dispatch.GenVertexArrays (1, &ctx->vao); + ctx->dispatch.BindVertexArray (ctx->vao); + + ctx->dispatch.GenBuffers (1, &ctx->vbo); + ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo); + ctx->dispatch.BufferData (GL_ARRAY_BUFFER, ctx->vbo_size, + NULL, GL_DYNAMIC_DRAW); + + ctx->dispatch.GenBuffers (1, &ctx->ibo); + ctx->dispatch.BindBuffer (GL_ELEMENT_ARRAY_BUFFER, ctx->ibo); + ctx->dispatch.BufferData (GL_ELEMENT_ARRAY_BUFFER, + ctx->vbo_size * 2, + NULL, GL_DYNAMIC_DRAW); + ctx->states_cache.bound_vao = ctx->vao; + ctx->states_cache.bound_vbo = ctx->vbo; + ctx->states_cache.bound_ibo = ctx->ibo; + } else { + ctx->vbo = 0; + ctx->vao = 0; + ctx->ibo = 0; + } + + ctx->vb = malloc (ctx->vbo_size); + if (unlikely (ctx->vb == NULL)) { - _cairo_cache_fini (&ctx->gradients); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + _cairo_cache_fini (&ctx->gradients); + ctx->dispatch.DeleteVertexArrays (1, &ctx->vao); + ctx->dispatch.DeleteBuffers (1, &ctx->vbo); + ctx->dispatch.DeleteBuffers (1, &ctx->ibo); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); } ctx->primitive_type = CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES; _cairo_array_init (&ctx->tristrip_indices, sizeof (unsigned short)); - /* PBO for any sort of texture upload */ - dispatch->GenBuffers (1, &ctx->texture_load_pbo); - ctx->max_framebuffer_size = 0; ctx->dispatch.GetIntegerv (GL_MAX_RENDERBUFFER_SIZE, &ctx->max_framebuffer_size); ctx->max_texture_size = 0; @@ -655,7 +699,9 @@ _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx, ctx->dispatch.ClearColor (0, 0, 0, 0); // reset cached clear colors memset (&ctx->states_cache.clear_red, 0, sizeof (GLclampf) * 4); + ctx->dispatch.Clear (GL_COLOR_BUFFER_BIT); + } static cairo_bool_t @@ -666,7 +712,7 @@ _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx, if (surface->msaa_depth_stencil) return TRUE; - _cairo_gl_ensure_multisampling (ctx, surface); + //_cairo_gl_ensure_framebuffer (ctx, surface); dispatch->GenRenderbuffers (1, &surface->msaa_depth_stencil); dispatch->BindRenderbuffer (GL_RENDERBUFFER, @@ -805,8 +851,6 @@ bind_multisample_framebuffer (cairo_gl_context_t *ctx, GLbitfield mask; if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) { - stencil_test_enabled = ctx->states_cache.stencil_test_enabled; - scissor_test_enabled = ctx->states_cache.scissor_test_enabled; has_stencil_cache = surface->clip_on_stencil_buffer ? TRUE : FALSE; mask = GL_COLOR_BUFFER_BIT; @@ -832,34 +876,37 @@ bind_multisample_framebuffer (cairo_gl_context_t *ctx, #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_SURFACE /* we must disable scissor and stencil test */ if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) { - _disable_stencil_buffer (ctx); - _disable_scissor_buffer (ctx); + stencil_test_enabled = ctx->states_cache.stencil_test_enabled; + scissor_test_enabled = ctx->states_cache.scissor_test_enabled; + _disable_stencil_buffer (ctx); + _disable_scissor_buffer (ctx); ctx->dispatch.Enable (GL_MULTISAMPLE); - if (has_stencil_cache) - mask |= GL_STENCIL_BUFFER_BIT; - - /* The last time we drew to the surface, we were not using multisampling, - so we need to blit from the non-multisampling framebuffer into the - multisampling framebuffer. */ - ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->msaa_fb); - ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->fb); - ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height, - 0, 0, surface->width, surface->height, - mask, GL_NEAREST); - surface->content_synced = TRUE; + if (has_stencil_cache) + mask |= GL_STENCIL_BUFFER_BIT; + + /* The last time we drew to the surface, we were not using multisampling, + so we need to blit from the non-multisampling framebuffer into the + multisampling framebuffer. */ + ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->msaa_fb); + ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->fb); + ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height, + 0, 0, surface->width, surface->height, + mask, GL_NEAREST); + surface->content_synced = TRUE; } #endif + ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb); #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_SURFACE if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) { - /* re-enable stencil and scissor test */ - if (scissor_test_enabled) - _enable_scissor_buffer (ctx); - if (stencil_test_enabled) - _enable_stencil_buffer (ctx); + /* re-enable stencil and scissor test */ + if (stencil_test_enabled) + _enable_stencil_buffer (ctx); + if (scissor_test_enabled) + _enable_scissor_buffer (ctx); } #endif } @@ -869,14 +916,14 @@ bind_singlesample_framebuffer (cairo_gl_context_t *ctx, cairo_gl_surface_t *surface) { cairo_bool_t has_stencil_cache = surface->clip_on_stencil_buffer ? TRUE : FALSE; - cairo_bool_t stencil_test_enabled = ctx->states_cache.stencil_test_enabled; - cairo_bool_t scissor_test_enabled = ctx->states_cache.scissor_test_enabled; + cairo_bool_t stencil_test_enabled; + cairo_bool_t scissor_test_enabled; GLbitfield mask = GL_COLOR_BUFFER_BIT; if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 && ! ctx->has_angle_multisampling) return; - + _cairo_gl_ensure_framebuffer (ctx, surface); if (! surface->msaa_active) { @@ -890,9 +937,11 @@ bind_singlesample_framebuffer (cairo_gl_context_t *ctx, _cairo_gl_composite_flush (ctx); - /* we must disable scissor and stencil test */ - _disable_stencil_buffer (ctx); + stencil_test_enabled = ctx->states_cache.stencil_test_enabled; + scissor_test_enabled = ctx->states_cache.scissor_test_enabled; + _disable_stencil_buffer (ctx); _disable_scissor_buffer (ctx); + #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_FLAVOR if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) ctx->dispatch.Disable (GL_MULTISAMPLE); @@ -906,12 +955,12 @@ bind_singlesample_framebuffer (cairo_gl_context_t *ctx, non-multisampling framebuffer. */ #if CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) { - ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER_ANGLE, surface->fb); - ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER_ANGLE, surface->msaa_fb); + ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER_ANGLE, surface->fb); + ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER_ANGLE, surface->msaa_fb); } #if CAIRO_HAS_EVASGL_SURFACE else { - ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->fb); + ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->fb); ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->msaa_fb); } #endif @@ -925,11 +974,12 @@ bind_singlesample_framebuffer (cairo_gl_context_t *ctx, ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb); surface->content_synced = TRUE; + /* re-enable stencil and scissor test */ - if (scissor_test_enabled) - _enable_scissor_buffer (ctx); if (stencil_test_enabled) _enable_stencil_buffer (ctx); + if (scissor_test_enabled) + _enable_scissor_buffer (ctx); } void @@ -1018,8 +1068,8 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx, if (! _cairo_gl_surface_is_texture (surface)) { #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_SURFACE if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP && - ctx->dispatch.DrawBuffer && - ctx->dispatch.ReadBuffer) { + ctx->dispatch.DrawBuffer && + ctx->dispatch.ReadBuffer) { ctx->dispatch.DrawBuffer (GL_BACK_LEFT); ctx->dispatch.ReadBuffer (GL_BACK_LEFT); } @@ -1046,22 +1096,11 @@ void cairo_gl_device_set_thread_aware (cairo_device_t *device, cairo_bool_t thread_aware) { - if ((! device)||(cairo_device_status(device)!= CAIRO_STATUS_SUCCESS)) { - fprintf (stderr, "cairo_gl_device_set_thread_aware(): cairo_device is NULL or not available\n"); - _cairo_error_throw (CAIRO_STATUS_DEVICE_ERROR); - return; - } if (device->backend->type != CAIRO_DEVICE_TYPE_GL) { _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); return; } - if(thread_aware == 0 || thread_aware == 1){ - ((cairo_gl_context_t *) device)->thread_aware = thread_aware; - } - else{ - _cairo_device_set_error (device, CAIRO_STATUS_INVALID_STATUS); - return; - } + ((cairo_gl_context_t *) device)->thread_aware = thread_aware; } void _cairo_gl_context_reset (cairo_gl_context_t *ctx) @@ -1085,8 +1124,12 @@ void _cairo_gl_context_reset (cairo_gl_context_t *ctx) ctx->states_cache.depth_mask = FALSE; - /* FIXME: this is hack to fix mali driver*/ - ctx->dispatch.Disable (GL_DITHER); + /* FIXME: this is hack to fix mali driver */ + ctx->dispatch.Disable (GL_DITHER); + + ctx->current_shader = NULL; - ctx->current_shader = NULL; + ctx->states_cache.bound_vbo = 0; + ctx->states_cache.bound_vao = 0; + ctx->states_cache.bound_ibo = 0; } diff --git a/src/cairo-gl-dispatch-private.h b/src/cairo-gl-dispatch-private.h index 5996ebdc7..5d4144f03 100755..100644 --- a/src/cairo-gl-dispatch-private.h +++ b/src/cairo-gl-dispatch-private.h @@ -78,6 +78,7 @@ cairo_private cairo_gl_dispatch_entry_t dispatch_core_entries[] = { DISPATCH_ENTRY_CORE (ClearStencil), DISPATCH_ENTRY_CORE (ColorMask), DISPATCH_ENTRY_CORE (DeleteTextures), + DISPATCH_ENTRY_CORE (DepthMask), DISPATCH_ENTRY_CORE (Disable), DISPATCH_ENTRY_CORE (DrawArrays), DISPATCH_ENTRY_CORE (DrawElements), @@ -89,6 +90,7 @@ cairo_private cairo_gl_dispatch_entry_t dispatch_core_entries[] = { DISPATCH_ENTRY_CORE (GetFloatv), DISPATCH_ENTRY_CORE (GetIntegerv), DISPATCH_ENTRY_CORE (GetString), + DISPATCH_ENTRY_CORE (GetStringi), DISPATCH_ENTRY_CORE (PixelStorei), DISPATCH_ENTRY_CORE (ReadPixels), DISPATCH_ENTRY_CORE (Scissor), @@ -102,17 +104,21 @@ cairo_private cairo_gl_dispatch_entry_t dispatch_core_entries[] = { DISPATCH_ENTRY_CORE (DrawBuffer), DISPATCH_ENTRY_CORE (ReadBuffer), #endif - DISPATCH_ENTRY_CORE (DepthMask), DISPATCH_ENTRY_CORE (Viewport), DISPATCH_ENTRY_LAST }; cairo_private cairo_gl_dispatch_entry_t dispatch_buffers_entries[] = { DISPATCH_ENTRY_ARB (GenBuffers), + DISPATCH_ENTRY_ARB (DeleteBuffers), DISPATCH_ENTRY_ARB (BindBuffer), DISPATCH_ENTRY_ARB (BufferData), + DISPATCH_ENTRY_ARB (BufferSubData), DISPATCH_ENTRY_ARB_OES (MapBuffer), DISPATCH_ENTRY_ARB_OES (UnmapBuffer), + DISPATCH_ENTRY_ARB (GenVertexArrays), + DISPATCH_ENTRY_ARB (DeleteVertexArrays), + DISPATCH_ENTRY_ARB (BindVertexArray), DISPATCH_ENTRY_LAST }; diff --git a/src/cairo-gl-dispatch.c b/src/cairo-gl-dispatch.c index aaa234661..c38fe8cad 100755..100644 --- a/src/cairo-gl-dispatch.c +++ b/src/cairo-gl-dispatch.c @@ -111,7 +111,7 @@ _cairo_gl_dispatch_init_entries (cairo_gl_dispatch_t *dispatch, static cairo_status_t _cairo_gl_dispatch_init_buffers (cairo_gl_dispatch_t *dispatch, cairo_gl_get_proc_addr_func_t get_proc_addr, - void *data, + void *data, int gl_version, cairo_gl_flavor_t gl_flavor) { cairo_gl_dispatch_name_t dispatch_name; diff --git a/src/cairo-gl-ext-def-private.h b/src/cairo-gl-ext-def-private.h index a261947be..9c11a9691 100755..100644 --- a/src/cairo-gl-ext-def-private.h +++ b/src/cairo-gl-ext-def-private.h @@ -140,4 +140,12 @@ #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 #endif +#ifndef GL_NUM_EXTENSIONS +#define GL_NUM_EXTENSIONS 0x821D +#endif + +#ifndef GL_VERTEX_ARRAY_BINDING +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#endif + #endif /* CAIRO_GL_EXT_DEF_PRIVATE_H */ diff --git a/src/cairo-gl-filters.c b/src/cairo-gl-filters.c index 7ddc4a246..612e599d5 100755..100644 --- a/src/cairo-gl-filters.c +++ b/src/cairo-gl-filters.c @@ -165,14 +165,12 @@ gaussian_filter_stage_1 (cairo_bool_t x_axis, if (is_opaque) _cairo_gl_shader_bind_float (ctx_out, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_ALPHA, CAIRO_GL_TEX_SOURCE), - 1.0); + ctx_out->current_shader->alpha_location[CAIRO_GL_TEX_SOURCE], + 1.0); else _cairo_gl_shader_bind_float (ctx_out, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_ALPHA, CAIRO_GL_TEX_SOURCE), - 0.0); + ctx_out->current_shader->alpha_location[CAIRO_GL_TEX_SOURCE], + 0.0); rect.x = 0; rect.y = 0; @@ -212,7 +210,7 @@ gaussian_filter_stage_2 (cairo_bool_t y_axis, col = original_pattern->base.x_radius * 2 + 1; memset (&stage_2_src->operand.texture.coef[0], 0, sizeof (float) * row); - compute_y_coef_to_float (original_pattern->base.convolution_matrix, + compute_y_coef_to_float (original_pattern->base.convolution_matrix, row, col, &stage_2_src->operand.texture.coef[2]); stage_2_src->operand.texture.y_radius = original_pattern->base.y_radius; stage_2_src->operand.texture.x_radius = 1; diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c index 8e5892e6e..b28eef3bc 100755..100644 --- a/src/cairo-gl-glyphs.c +++ b/src/cairo-gl-glyphs.c @@ -178,8 +178,8 @@ _cairo_gl_glyph_cache_lock (cairo_gl_glyph_cache_t *cache, static cairo_status_t cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx, cairo_format_t format, - cairo_bool_t has_component_alpha, - cairo_gl_glyph_cache_t **cache_out) + cairo_bool_t has_component_alpha, + cairo_gl_glyph_cache_t **cache_out) { cairo_gl_glyph_cache_t *cache; cairo_content_t content; @@ -189,13 +189,12 @@ cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx, case CAIRO_FORMAT_RGB16_565: case CAIRO_FORMAT_ARGB32: case CAIRO_FORMAT_RGB24: - if (has_component_alpha) { - cache = &ctx->glyph_cache[0]; - } else { - cache = &ctx->glyph_cache[2]; - } + if (has_component_alpha) { + cache = &ctx->glyph_cache[0]; + } else { + cache = &ctx->glyph_cache[2]; + } content = CAIRO_CONTENT_COLOR_ALPHA; - break; break; case CAIRO_FORMAT_A8: case CAIRO_FORMAT_A1: @@ -275,7 +274,7 @@ render_glyphs (cairo_gl_surface_t *dst, cairo_format_t last_format = CAIRO_FORMAT_INVALID; cairo_gl_glyph_cache_t *cache = NULL; cairo_gl_context_t *ctx; - cairo_gl_emit_glyph_t emit; + cairo_gl_emit_glyph_t emit = NULL; cairo_gl_composite_t setup; cairo_int_status_t status; int i = 0; @@ -325,34 +324,35 @@ render_glyphs (cairo_gl_surface_t *dst, { continue; } + if (! *has_component_alpha) - *has_component_alpha = pixman_image_get_component_alpha (scaled_glyph->surface->pixman_image); + *has_component_alpha = pixman_image_get_component_alpha (scaled_glyph->surface->pixman_image); /* color glyph has ARGB32 format and dst mask surface is ALPHA */ if (scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32 && - dst->base.content == CAIRO_CONTENT_ALPHA && - *has_component_alpha == FALSE) - return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; + dst->base.content == CAIRO_CONTENT_ALPHA && + *has_component_alpha == FALSE) + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; if (scaled_glyph->surface->format != last_format) { status = cairo_gl_context_get_glyph_cache (ctx, scaled_glyph->surface->format, - *has_component_alpha, + *has_component_alpha, &cache); if (unlikely (status)) goto FINISH; last_format = scaled_glyph->surface->format; - if (! *has_component_alpha && + if (! *has_component_alpha && cache->surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) { /* we have color glyph */ _cairo_gl_composite_set_source_operand (&setup, &cache->surface->operand); *is_color_glyph = TRUE; - } else { + } else { _cairo_gl_composite_set_mask_operand (&setup, &cache->surface->operand); *is_color_glyph = FALSE; - } + } /* XXX Shoot me. */ if (dst->msaa_active) @@ -407,6 +407,7 @@ render_glyphs (cairo_gl_surface_t *dst, goto FINISH; } glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph); + assert (emit); emit (ctx, x1, y1, x2, y2, glyph->p1.x, glyph->p1.y, @@ -433,7 +434,7 @@ render_glyphs_via_mask (cairo_gl_surface_t *dst, cairo_status_t status; cairo_bool_t has_component_alpha; cairo_gl_context_t *ctx; - cairo_bool_t is_color_glyph; + cairo_bool_t is_color_glyph; int width = info->extents.width; int height = info->extents.height; @@ -505,27 +506,27 @@ render_glyphs_via_mask (cairo_gl_surface_t *dst, clip_extents.height = info->extents.height; clip = _cairo_clip_intersect_rectangle (clip, &clip_extents); - if(is_color_glyph) { - if(op == CAIRO_OPERATOR_SOURCE) { - /* do dest_out then add*/ - status = _cairo_surface_paint (&dst->base, - CAIRO_OPERATOR_DEST_OUT, - &mask_pattern.base, - clip); - status = _cairo_surface_paint (&dst->base, - CAIRO_OPERATOR_ADD, - &mask_pattern.base, clip); - } else { - status = _cairo_surface_paint (&dst->base,op, - &mask_pattern.base, - clip); - } - } + if (is_color_glyph) { + if (op == CAIRO_OPERATOR_SOURCE) { + /* do dest_out then add */ + status = _cairo_surface_paint (&dst->base, + CAIRO_OPERATOR_DEST_OUT, + &mask_pattern.base, + clip); + status = _cairo_surface_paint (&dst->base, + CAIRO_OPERATOR_ADD, + &mask_pattern.base, clip); + } else { + status = _cairo_surface_paint (&dst->base, op, + &mask_pattern.base, + clip); + } + } else - status = _cairo_surface_mask (&dst->base, op, - &source_pattern.base, - &mask_pattern.base, - clip); + status = _cairo_surface_mask (&dst->base, op, + &source_pattern.base, + &mask_pattern.base, + clip); _cairo_clip_destroy (clip); @@ -567,7 +568,7 @@ _cairo_gl_composite_glyphs_with_clip (void *_dst, { cairo_gl_surface_t *dst = _dst; cairo_bool_t has_component_alpha; - cairo_bool_t is_color_glyph; + cairo_bool_t is_color_glyph; TRACE ((stderr, "%s\n", __FUNCTION__)); diff --git a/src/cairo-gl-gradient-private.h b/src/cairo-gl-gradient-private.h index 024549e5d..d66f3dc3b 100755..100644 --- a/src/cairo-gl-gradient-private.h +++ b/src/cairo-gl-gradient-private.h @@ -3,6 +3,7 @@ * Copyright © 2009 Eric Anholt * Copyright © 2009 Chris Wilson * Copyright © 2005,2010 Red Hat, Inc + * Copyright © 2011,2015 Samsung Research America, Inc - Silicon Valley * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -36,6 +37,7 @@ * Carl Worth <cworth@cworth.org> * Chris Wilson <chris@chris-wilson.co.uk> * Eric Anholt <eric@anholt.net> + * Henry Songt <hsong@sisa.samsung.com> */ #ifndef CAIRO_GL_GRADIENT_PRIVATE_H @@ -51,21 +53,26 @@ #include "cairo-gl.h" -#if 0 #if CAIRO_HAS_EVASGL_SURFACE -#include <Evas_GL.h> + #include <Evas_GL.h> #else - #if CAIRO_HAS_GL_SURFACE - #include <GL/gl.h> - #include <GL/glext.h> - #elif CAIRO_HAS_GLESV2_SURFACE - #include <GLES2/gl2.h> - #include <GLES2/gl2ext.h> - #elif CAIRO_HAS_GLESV3_SURFACE - #include <GLES3/gl3.h> - #include <GLES3/gl3ext.h> - #endif -#endif + #if CAIRO_HAS_GL_SURFACE + #if CAIRO_HAS_CGL_FUNCTIONS + #include <OpenGL/gl.h> + #include <OpenGL/glext.h> + #else + #include <GL/gl.h> + #include <GL/glext.h> + #endif + #elif CAIRO_HAS_GLESV2_SURFACE + #include <GLES2/gl2.h> + #include <GLES2/gl2ext.h> + #elif CAIRO_HAS_GLESV3_SURFACE + #include <GLES3/gl3.h> + #include <GLES3/gl3ext.h> + #elif CAIRO_HAS_EVASGL_SURFACE + #include <Evas_GL.h> + #endif #endif #define CAIRO_GL_GRADIENT_CACHE_SIZE 4096 @@ -77,7 +84,7 @@ typedef struct _cairo_gl_gradient { cairo_cache_entry_t cache_entry; cairo_reference_count_t ref_count; cairo_device_t *device; /* NB: we don't hold a reference */ - unsigned int tex; + GLuint tex; unsigned int n_stops; const cairo_gradient_stop_t *stops; cairo_gradient_stop_t stops_embedded[1]; diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c index ddf869ead..2f8c725b6 100755..100644 --- a/src/cairo-gl-gradient.c +++ b/src/cairo-gl-gradient.c @@ -290,7 +290,7 @@ _cairo_gl_gradient_create (cairo_gl_context_t *ctx, ctx->dispatch.TexImage2D (ctx->tex_target, 0, internal_format, tex_width, 1, 0, - GL_BGRA, GL_UNSIGNED_BYTE, data); + GL_BGRA, GL_UNSIGNED_BYTE, data); free (data); diff --git a/src/cairo-gl-hairline-stroke.c b/src/cairo-gl-hairline-stroke.c index 9ff59e502..7ce75d7c7 100755..100644 --- a/src/cairo-gl-hairline-stroke.c +++ b/src/cairo-gl-hairline-stroke.c @@ -46,6 +46,8 @@ _add_cap (cairo_gl_hairline_closure_t *hairline, cairo_bool_t lead_cap, cairo_point_t *outp) { + // Do we really need cap? +/* double dx, dy; if (hairline->cap_style == CAIRO_LINE_CAP_BUTT) @@ -57,7 +59,7 @@ _add_cap (cairo_gl_hairline_closure_t *hairline, cairo_matrix_transform_distance (hairline->ctm, &dx, &dy); outp->x += _cairo_fixed_from_double (dx); outp->y += _cairo_fixed_from_double (dy); - +*/ return TRUE; } @@ -121,20 +123,21 @@ _cairo_gl_hairline_style_is_hairline (const cairo_stroke_style_t *style, x = fabs (x - 1.0); y = fabs (y - 1.0); + // do not consider line join return style->line_width == 1.0 && - (style->line_join != CAIRO_LINE_JOIN_MITER || - style->miter_limit <= 10.0) && (x <= SCALE_TOLERANCE && y <= SCALE_TOLERANCE); } static cairo_status_t _path_add_first_and_last_cap (cairo_gl_hairline_closure_t *hairline) { + // Do we really need caps and join for single point line? +/* cairo_point_t p[2]; cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_bool_t needs_to_cap; - /* check last point */ + // check last point if (hairline->initialized) { if (! hairline->line_last_capped) { p[0] = hairline->line_last_point; @@ -166,7 +169,7 @@ _path_add_first_and_last_cap (cairo_gl_hairline_closure_t *hairline) } } } - +*/ return CAIRO_STATUS_SUCCESS; } diff --git a/src/cairo-gl-info.c b/src/cairo-gl-info.c index 33dc0cc56..fffea58b1 100755..100644 --- a/src/cairo-gl-info.c +++ b/src/cairo-gl-info.c @@ -32,6 +32,29 @@ #include "cairoint.h" #include "cairo-gl-private.h" +#include <errno.h> +int _cairo_glsl_get_version (cairo_gl_dispatch_t *dispatch) +{ + int major, minor; + const char *version = (const char *) dispatch->GetString (GL_SHADING_LANGUAGE_VERSION); + const char *dot = version == NULL ? NULL : strchr (version, '.'); + const char *major_start = dot; + + /* Sanity check */ + if (dot == NULL || dot == version || *(dot + 1) == '\0') { + major = 0; + minor = 0; + } else { + /* Find the start of the major version in the string */ + while (major_start > version && *major_start != ' ') + --major_start; + major = strtol (major_start, NULL, 10); + minor = strtol (dot + 1, NULL, 10); + } + + return CAIRO_GL_VERSION_ENCODE (major, minor); +} + int _cairo_gl_get_version (cairo_gl_dispatch_t *dispatch) { int major, minor; @@ -78,21 +101,54 @@ _cairo_gl_get_flavor (cairo_gl_dispatch_t *dispatch) return flavor; } +unsigned long +_cairo_gl_get_vbo_size (void) +{ + unsigned long vbo_size; + + const char *env = getenv ("CAIRO_GL_VBO_SIZE"); + if (env == NULL) { + vbo_size = CAIRO_GL_VBO_SIZE_DEFAULT; + } else { + errno = 0; + vbo_size = strtol (env, NULL, 10); + assert (errno == 0); + assert (vbo_size > 0); + } + + return vbo_size; +} + cairo_bool_t _cairo_gl_has_extension (cairo_gl_dispatch_t *dispatch, const char *ext) { - const char *extensions = (const char *) dispatch->GetString (GL_EXTENSIONS); - size_t len = strlen (ext); - const char *ext_ptr = extensions; + int version = _cairo_gl_get_version (dispatch); + if (version >= CAIRO_GL_VERSION_ENCODE (3, 0)) { + GLuint max_num_extensions; + int i; + dispatch->GetIntegerv (GL_NUM_EXTENSIONS, &max_num_extensions); - if (unlikely (ext_ptr == NULL)) - return 0; + for (i = 0; i < max_num_extensions; i++) { + const char *extension = (const char *) dispatch->GetStringi (GL_EXTENSIONS, i); + if (strstr (extension, ext) == 0) + return TRUE; + } + return FALSE; + } else { + const char *extensions = (const char *) dispatch->GetString (GL_EXTENSIONS); + size_t len = strlen (ext); + const char *ext_ptr = extensions; + - while ((ext_ptr = strstr (ext_ptr, ext)) != NULL) { - if (ext_ptr[len] == ' ' || ext_ptr[len] == '\0') - break; - ext_ptr += len; - } + if (unlikely (ext_ptr == NULL)) + return 0; + + while ((ext_ptr = strstr (ext_ptr, ext)) != NULL) { + if (ext_ptr[len] == ' ' || ext_ptr[len] == '\0') + break; + ext_ptr += len; + } - return (ext_ptr != NULL); + return (ext_ptr != NULL); + } } diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c index 7ce5c7a4b..99d8cc01a 100755..100644 --- a/src/cairo-gl-msaa-compositor.c +++ b/src/cairo-gl-msaa-compositor.c @@ -47,6 +47,7 @@ #include "cairo-gl-private.h" #include "cairo-path-private.h" #include "cairo-traps-private.h" +#include "cairo-convex-fill-private.h" static cairo_bool_t can_use_msaa_compositor (cairo_gl_surface_t *surface, @@ -151,8 +152,8 @@ _draw_traps (cairo_gl_context_t *ctx, static cairo_int_status_t _draw_int_rect (cairo_gl_context_t *ctx, - cairo_gl_composite_t *setup, - cairo_rectangle_int_t *rect) + cairo_gl_composite_t *setup, + cairo_rectangle_int_t *rect) { int quad[8]; @@ -536,10 +537,12 @@ _cairo_gl_msaa_compositor_mask_source_operator (const cairo_compositor_t *compos status = _draw_int_rect (ctx, &setup, &composite->bounded); else status = _draw_traps (ctx, &setup, &traps); + if (unlikely (status)) + goto finish; /* Now draw the second pass. */ status = _cairo_gl_composite_set_operator (&setup, CAIRO_OPERATOR_ADD, - FALSE /* assume_component_alpha */); + FALSE /* assume_component_alpha */); if (unlikely (status)) goto finish; status = _cairo_gl_composite_set_source (&setup, @@ -716,7 +719,7 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor, if (clip) { cairo_clip_t *clip_copy = _cairo_clip_copy (clip); - + clip_copy = _cairo_clip_intersect_rectangle (clip_copy, &rect); status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, clip_copy); @@ -769,6 +772,59 @@ _stroke_shaper_add_triangle_fan (void *closure, } static cairo_status_t +_fill_add_triangle_fan (void *closure, + const cairo_point_t *points, + int npoints) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + int n = npoints - 1, idx = 1; + cairo_bool_t done = FALSE; + struct _tristrip_composite_info *info = closure; + cairo_point_t triangle[3], quad[4]; + cairo_point_t midp = points[0]; + + if (n <= 1) + return status; + else if (n <= 2) { + triangle[0] = midp; + triangle[1] = points[idx]; + triangle[2] = points[++idx]; + return _cairo_gl_composite_emit_triangle_as_tristrip (info->ctx, &info->setup, triangle); + } + else { + quad[0] = midp; + quad[1] = points[idx]; + quad[2] = points[++idx]; + quad[3] = points[++idx]; + n -= 3; + status = _cairo_gl_composite_emit_quad_as_tristrip (info->ctx, &info->setup, quad); + } + + while (! done) { + if (n == 0) + break; + if (n == 1) { + triangle[0] = midp; + triangle[1] = points[idx]; + triangle[2] = points[++idx]; + status = _cairo_gl_composite_emit_triangle_as_tristrip (info->ctx, &info->setup, triangle); + break; + } + else { + quad[0] = midp; + quad[1] = points[idx]; + quad[2] = points[++idx]; + quad[3] = points[++idx]; + n -= 2; + status = _cairo_gl_composite_emit_quad_as_tristrip (info->ctx, &info->setup, quad); + if (unlikely (status)) + break; + } + } + return status; +} + +static cairo_status_t _stroke_shaper_add_quad (void *closure, const cairo_point_t quad[4]) { @@ -918,9 +974,9 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor, if (stroke_extents.width != 0 && stroke_extents.height != 0) { - if ((stroke_extents.width / stroke_extents.height > 10 && + if ((stroke_extents.width / stroke_extents.height > 10 && stroke_extents.height < 10) || - (stroke_extents.height / stroke_extents.width > 10 && + (stroke_extents.height / stroke_extents.width > 10 && stroke_extents.width < 10)) { return CAIRO_INT_STATUS_UNSUPPORTED; } @@ -981,14 +1037,23 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor, if (_cairo_gl_hairline_style_is_hairline (style, ctm)) { cairo_gl_hairline_closure_t closure; + /* prevent overlapping is very expensive, we should avoid it + at all cost. In case of hairline, the overlapping occurs + on a single pixel and is almost indistinguishable. To + trade-off quality vs performance, for hairline, we disable + overlapping + */ + /* if (! (_is_continuous_arc (path, style) || - _is_continuous_single_line (path, style))) { + _is_continuous_single_line (path, style) || + path->is_convex)) { status = _prevent_overlapping_strokes (info.ctx, &info.setup, composite, path, style, ctm); if (unlikely (status)) goto finish; } + */ closure.ctx = info.ctx; @@ -1045,7 +1110,6 @@ _draw_simple_quad_path (cairo_gl_context_t *ctx, cairo_point_t triangle[3]; cairo_int_status_t status; const cairo_point_t *points; - points = cairo_path_head (path)->points; triangle[0] = points[0]; @@ -1076,6 +1140,7 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, cairo_traps_t traps; cairo_bool_t draw_path_with_traps; cairo_rectangle_int_t fill_extents; + struct _tristrip_composite_info info; if (! can_use_msaa_compositor (dst, antialias)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1084,9 +1149,9 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, _cairo_path_fixed_approximate_fill_extents (path, &fill_extents); if (fill_extents.width != 0 && fill_extents.height != 0) { - if ((fill_extents.width / fill_extents.height > 10 && + if ((fill_extents.width / fill_extents.height > 10 && fill_extents.height < 10) || - (fill_extents.height / fill_extents.width > 10 && + (fill_extents.height / fill_extents.width > 10 && fill_extents.width < 10)) { return CAIRO_INT_STATUS_UNSUPPORTED; } @@ -1122,13 +1187,6 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path); - if (draw_path_with_traps) { - _cairo_traps_init (&traps); - status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); - if (unlikely (status)) - goto cleanup_traps; - } - status = _cairo_gl_composite_init (&setup, composite->op, dst, @@ -1147,15 +1205,44 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, _cairo_gl_msaa_compositor_set_clip (composite, &setup); if (antialias != CAIRO_ANTIALIAS_NONE) _cairo_gl_composite_set_multisample (&setup); - + status = _cairo_gl_composite_begin (&setup, &ctx); if (unlikely (status)) goto cleanup_setup; - if (! draw_path_with_traps) + if(path->is_convex) { + + cairo_convex_fill_closure_t filler; + filler.tolerance = tolerance; + info.ctx = ctx; + info.setup = setup; + filler.closure = &info; + filler.midp_added = FALSE; + status = _cairo_path_fixed_fill_to_convex((*_fill_add_triangle_fan), + path, + _cairo_convex_fill_move_to, + _cairo_convex_fill_line_to, + _cairo_convex_fill_curve_to, + _cairo_convex_fill_close_path, + &filler); + if (unlikely (status)) + goto cleanup_setup; + + } + else if (draw_path_with_traps) { + _cairo_traps_init (&traps); + status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); + if (unlikely (status)) + goto cleanup_traps; + } + + if (!path->is_convex && ! draw_path_with_traps) status = _draw_simple_quad_path (ctx, &setup, path); else - status = _draw_traps (ctx, &setup, &traps); + { + if(!path->is_convex) + status = _draw_traps (ctx, &setup, &traps); + } if (unlikely (status)) goto cleanup_setup; @@ -1168,7 +1255,7 @@ cleanup_setup: status = _cairo_gl_context_release (ctx, status); cleanup_traps: - if (draw_path_with_traps) + if (draw_path_with_traps && !path->is_convex) _cairo_traps_fini (&traps); return status; @@ -1215,7 +1302,13 @@ _cairo_gl_msaa_compositor_glyphs (const cairo_compositor_t *compositor, return _paint_back_unbounded_surface (compositor, composite, surface); } - +/* + if (scaled_font->options.antialias != CAIRO_ANTIALIAS_NONE) { + status = _blit_texture_to_renderbuffer (dst); + if (unlikely (status)) + return status; + } +*/ src = _cairo_gl_pattern_to_source (&dst->base, composite->original_source_pattern, FALSE, @@ -1253,6 +1346,7 @@ _cairo_gl_msaa_compositor_glyphs (const cairo_compositor_t *compositor, dst->content_synced = FALSE; finish: + if (src) cairo_surface_destroy (src); return status; @@ -1264,7 +1358,6 @@ _cairo_gl_msaa_compositor_init (cairo_compositor_t *compositor, { compositor->delegate = delegate; compositor->lazy_init = TRUE; - compositor->paint = _cairo_gl_msaa_compositor_paint; compositor->mask = _cairo_gl_msaa_compositor_mask; compositor->fill = _cairo_gl_msaa_compositor_fill; diff --git a/src/cairo-gl-operand.c b/src/cairo-gl-operand.c index 8c21e6985..2bbd99b74 100755..100644 --- a/src/cairo-gl-operand.c +++ b/src/cairo-gl-operand.c @@ -119,7 +119,7 @@ _cairo_gl_copy_texture (cairo_gl_surface_t *surface, /* paint image to dst */ _cairo_pattern_init_for_surface (&pattern, &image->base); - cairo_matrix_init_translate (&pattern.base.matrix, + cairo_matrix_init_translate (&pattern.base.matrix, -dst_x + src_x, -dst_y + src_y); rect.x = dst_x; @@ -231,7 +231,7 @@ _cairo_gl_image_cache_replace_image (cairo_gl_image_t *image_node, { cairo_int_status_t status; /* Paint image to cache. */ - status = _cairo_gl_copy_texture (dst, cache_surface, + status = _cairo_gl_copy_texture (dst, cache_surface, image, image_node->node.x, image_node->node.y, 0, 0, @@ -256,7 +256,7 @@ _cairo_gl_image_cache_add_image (cairo_gl_context_t *ctx, if (! image->base.device || (image->width >= IMAGE_CACHE_MAX_SIZE || - image->height >= IMAGE_CACHE_MAX_SIZE)) + image->height >= IMAGE_CACHE_MAX_SIZE)) return CAIRO_INT_STATUS_UNSUPPORTED; else if (! _cairo_gl_surface_is_texture (image)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -350,7 +350,7 @@ _cairo_gl_image_cache_add_image (cairo_gl_context_t *ctx, status = _cairo_gl_copy_texture (dst, ctx->image_cache->surface, image, node->x, node->y, 0, 0, - image->width, image->height, + image->width, image->height, FALSE, &ctx); if (unlikely (status)) return status; @@ -528,7 +528,7 @@ _cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand, operand->texture.texgen = use_texgen; - if (blur_surface == surface && + if (blur_surface == surface && surface->needs_to_cache && surface->base.device) { status = _cairo_gl_context_acquire (dst->base.device, &ctx); @@ -562,11 +562,10 @@ _cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand, operand->texture.p2.x = (double) blur_extents.width / (double) blur_surface->width; operand->texture.p2.y = (double) blur_extents.height / (double) blur_surface->height; - operand->texture.p1.x += 0.5 / blur_surface->width; - operand->texture.p1.y += 0.5 / blur_surface->height; - operand->texture.p2.x -= 0.5 / blur_surface->width; - operand->texture.p2.y -= 0.5 / blur_surface->height; - + operand->texture.p1.x += 0.5 / blur_surface->width; + operand->texture.p1.y += 0.5 / blur_surface->height; + operand->texture.p2.x -= 0.5 / blur_surface->width; + operand->texture.p2.y -= 0.5 / blur_surface->height; operand->texture.surface = blur_surface; operand->texture.owns_surface = NULL; @@ -597,19 +596,18 @@ _cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand, operand->texture.p2.x = image_node->p2.x; operand->texture.p2.y = image_node->p2.y; - operand->texture.p1.x += 0.5 / ctx->image_cache->surface->width; - operand->texture.p1.y += 0.5 / ctx->image_cache->surface->height; - operand->texture.p2.x -= 0.5 / ctx->image_cache->surface->width; - operand->texture.p2.y -= 0.5 / ctx->image_cache->surface->height; - + operand->texture.p1.x += 0.5 / ctx->image_cache->surface->width; + operand->texture.p1.y += 0.5 / ctx->image_cache->surface->height; + operand->texture.p2.x -= 0.5 / ctx->image_cache->surface->width; + operand->texture.p2.y -= 0.5 / ctx->image_cache->surface->height; cairo_matrix_multiply (&attributes->matrix, &matrix, &ctx->image_cache->surface->operand.texture.attributes.matrix); } + cairo_surface_destroy (&blur_surface->base); status = CAIRO_STATUS_SUCCESS; - cairo_surface_destroy (&blur_surface->base); if (ctx_acquired) return _cairo_gl_context_release (ctx, status); @@ -674,8 +672,8 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand, operand->texture.texgen = use_texgen; - if (surface->base.device && - blur_surface == surface && + if (surface->base.device && + blur_surface == surface && surface->needs_to_cache) { status = _cairo_gl_context_acquire (dst->base.device, &ctx); if (status == CAIRO_INT_STATUS_SUCCESS) { @@ -703,11 +701,10 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand, operand->texture.p2.x = (double) blur_extents.width / (double) blur_surface->width; operand->texture.p2.y = (double) blur_extents.height / (double) blur_surface->height; - operand->texture.p1.x += 0.5 / blur_surface->width; - operand->texture.p1.y += 0.5 / blur_surface->height; - operand->texture.p2.x -= 0.5 / blur_surface->width; - operand->texture.p2.y -= 0.5 / blur_surface->height; - + operand->texture.p1.x += 0.5 / blur_surface->width; + operand->texture.p1.y += 0.5 / blur_surface->height; + operand->texture.p2.x -= 0.5 / blur_surface->width; + operand->texture.p2.y -= 0.5 / blur_surface->height; operand->texture.surface = blur_surface; operand->texture.owns_surface = NULL; @@ -733,11 +730,10 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand, operand->texture.p2.x = image_node->p2.x; operand->texture.p2.y = image_node->p2.y; - operand->texture.p1.x += 0.5 / ctx->image_cache->surface->width; - operand->texture.p1.y += 0.5 / ctx->image_cache->surface->height; - operand->texture.p2.x -= 0.5 / ctx->image_cache->surface->width; - operand->texture.p2.y -= 0.5 / ctx->image_cache->surface->height; - + operand->texture.p1.x += 0.5 / ctx->image_cache->surface->width; + operand->texture.p1.y += 0.5 / ctx->image_cache->surface->height; + operand->texture.p2.x -= 0.5 / ctx->image_cache->surface->width; + operand->texture.p2.y -= 0.5 / ctx->image_cache->surface->height; operand->texture.surface = ctx->image_cache->surface; operand->texture.owns_surface = NULL; @@ -749,9 +745,9 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand, &ctx->image_cache->surface->operand.texture.attributes.matrix); } - cairo_surface_destroy (&blur_surface->base); status = CAIRO_STATUS_SUCCESS; + cairo_surface_destroy (&blur_surface->base); if (ctx_acquired) return _cairo_gl_context_release (ctx, status); @@ -825,7 +821,7 @@ _cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand, operand->texture.attributes.matrix.x0 -= extents->x * operand->texture.attributes.matrix.xx; operand->texture.attributes.matrix.y0 -= extents->y * operand->texture.attributes.matrix.yy; - if (_cairo_gl_surface_is_texture (dst) && + if (_cairo_gl_surface_is_texture (dst) && dst->width <= IMAGE_CACHE_MAX_SIZE && dst->height <= IMAGE_CACHE_MAX_SIZE && ! dst->force_no_cache) @@ -1128,7 +1124,7 @@ _cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand) cairo_bool_t _cairo_gl_operand_get_use_atlas (cairo_gl_operand_t *operand) { - if (operand->type != CAIRO_GL_OPERAND_TEXTURE && + if (operand->type != CAIRO_GL_OPERAND_TEXTURE && operand->type != CAIRO_GL_OPERAND_GAUSSIAN) return FALSE; @@ -1201,30 +1197,27 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx, return; _cairo_gl_shader_bind_vec4 (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_CONSTANT, tex_unit), - operand->constant.color[0], - operand->constant.color[1], - operand->constant.color[2], - operand->constant.color[3]); - return; + ctx->current_shader->constant_location[tex_unit], + operand->constant.color[0], + operand->constant.color[1], + operand->constant.color[2], + operand->constant.color[3]); + return; + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: _cairo_gl_shader_bind_float (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_A, tex_unit), + ctx->current_shader->a_location[tex_unit], operand->gradient.a); /* fall through */ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: - _cairo_gl_shader_bind_vec3 (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_CIRCLE_D, tex_unit), + _cairo_gl_shader_bind_vec3 (ctx, + ctx->current_shader->circle_d_location[tex_unit], operand->gradient.circle_d.center.x, operand->gradient.circle_d.center.y, operand->gradient.circle_d.radius); _cairo_gl_shader_bind_float (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_RADIUS_0, tex_unit), + ctx->current_shader->radius_0_location[tex_unit], operand->gradient.radius_0); /* fall through */ case CAIRO_GL_OPERAND_LINEAR_GRADIENT: @@ -1252,8 +1245,7 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx, } if (operand->type != CAIRO_GL_OPERAND_GAUSSIAN) _cairo_gl_shader_bind_vec2 (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_TEXDIMS, tex_unit), + ctx->current_shader->texdims_location[tex_unit], width, height); } @@ -1266,60 +1258,52 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx, float y_axis = 0.0; float temp_width; float near_zero = 0.00001; + _cairo_gl_shader_bind_float (ctx, + ctx->current_shader->blur_x_axis_location[tex_unit], + x_axis); + + _cairo_gl_shader_bind_float (ctx, + ctx->current_shader->blur_y_axis_location[tex_unit], + y_axis); - _cairo_gl_shader_bind_float (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_BLUR_X_AXIS, tex_unit), - x_axis); - _cairo_gl_shader_bind_float (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_BLUR_Y_AXIS, tex_unit), - y_axis); _cairo_gl_shader_bind_int (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_BLUR_RADIUS, tex_unit), - operand->texture.x_radius); + ctx->current_shader->blur_radius_location[tex_unit], + operand->texture.x_radius); temp_width = cairo_gl_surface_get_width (&operand->texture.surface->base); temp_width = (temp_width == 0) ? near_zero : temp_width; _cairo_gl_shader_bind_float (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_BLUR_STEP, tex_unit), - 1.0 / temp_width); + ctx->current_shader->blur_step_location[tex_unit], + 1.0 / temp_width); _cairo_gl_shader_bind_float_array (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_BLURS, tex_unit), - operand->texture.x_radius * 2 + 1, - &operand->texture.coef[0]); + ctx->current_shader->blurs_location [tex_unit], + operand->texture.x_radius * 2 + 1, + operand->texture.coef); } else if (operand->type == CAIRO_GL_OPERAND_GAUSSIAN && operand->pass == 2) { float x_axis = 0.0; float y_axis = 1.0; + _cairo_gl_shader_bind_float (ctx, + ctx->current_shader->blur_x_axis_location[tex_unit], + x_axis); + + _cairo_gl_shader_bind_float (ctx, + ctx->current_shader->blur_y_axis_location[tex_unit], + y_axis); - _cairo_gl_shader_bind_float (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_BLUR_X_AXIS, tex_unit), - x_axis); - _cairo_gl_shader_bind_float (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_BLUR_Y_AXIS, tex_unit), - y_axis); _cairo_gl_shader_bind_int (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_BLUR_RADIUS, tex_unit), - operand->texture.y_radius); + ctx->current_shader->blur_radius_location[tex_unit], + operand->texture.y_radius); - _cairo_gl_shader_bind_float (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_BLUR_STEP, tex_unit), - 1.0 / cairo_gl_surface_get_height (&operand->texture.surface->base)); + _cairo_gl_shader_bind_float (ctx, + ctx->current_shader->blur_step_location[tex_unit], + 1.0 / cairo_gl_surface_get_height (&operand->texture.surface->base)); _cairo_gl_shader_bind_float_array (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_BLURS, tex_unit), + ctx->current_shader->blurs_location[tex_unit], operand->texture.y_radius * 2 + 1, &operand->texture.coef[0]); } @@ -1332,12 +1316,10 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx, if (operand->gradient.texgen) texgen = &operand->gradient.m; } - if (texgen) { - _cairo_gl_shader_bind_matrix (ctx, - _cairo_gl_shader_uniform_for_texunit ( - CAIRO_GL_UNIFORM_TEXGEN, tex_unit), - texgen); + _cairo_gl_shader_bind_matrix(ctx, + ctx->current_shader->texgen_location[tex_unit], + texgen); } } diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index c46a3e8cc..ad08abd9f 100755..100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -4,6 +4,7 @@ * Copyright © 2009 Chris Wilson * Copyright © 2005,2010 Red Hat, Inc * Copyright © 2011 Linaro Limited + * Copyright © 2011,2015 Samsung Research America, Inc - Silicon Valley * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -39,6 +40,7 @@ * Eric Anholt <eric@anholt.net> * T. Zachary Laine <whatwasthataddress@gmail.com> * Alexandros Frantzis <alexandros.frantzis@linaro.org> + * Henry Song <hsong@sisa.samsung.com> */ #ifndef CAIRO_GL_PRIVATE_H @@ -62,11 +64,16 @@ #include <assert.h> #if CAIRO_HAS_EVASGL_SURFACE -#include <Evas_GL.h> + #include <Evas_GL.h> #else #if CAIRO_HAS_GL_SURFACE + #if CAIRO_HAS_CGL_FUNCTIONS + #include <OpenGL/gl.h> + #include <OpenGL/glext.h> + #else #include <GL/gl.h> #include <GL/glext.h> + #endif #elif CAIRO_HAS_GLESV2_SURFACE #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> @@ -76,7 +83,6 @@ #endif #endif - #include "cairo-gl-ext-def-private.h" #define DEBUG_GL 0 @@ -104,8 +110,9 @@ /* VBO size that we allocate, smaller size means we gotta flush more often, * but larger means hogging more memory and can cause trouble for drivers - * (especially on embedded devices). */ -#define CAIRO_GL_VBO_SIZE (16*1024) + * (especially on embedded devices). Use the CAIRO_GL_VBO_SIZE environment + * variable to set this to a different size. */ +#define CAIRO_GL_VBO_SIZE_DEFAULT (1024*1024) #define MIN_IMAGE_CACHE_WIDTH 512 #define MIN_IMAGE_CACHE_HEIGHT 512 @@ -142,7 +149,7 @@ typedef enum cairo_gl_flavor { CAIRO_GL_FLAVOR_ES3 = 3 } cairo_gl_flavor_t; -/* The order here is sensitive because of the logic of +/* The order here is sensitive because of the logic of *_cairo_gl_shader_uniform_for_texunit. */ typedef enum cairo_gl_uniform_t { CAIRO_GL_UNIFORM_TEXDIMS, /* "source_texdims" */ @@ -310,7 +317,19 @@ typedef enum cairo_gl_tex { typedef struct cairo_gl_shader { GLuint fragment_shader; GLuint program; - GLint uniforms[CAIRO_GL_UNIFORM_MAX]; + GLint mvp_location; + GLint constant_location[2]; + GLint a_location[2]; + GLint circle_d_location[2]; + GLint radius_0_location[2]; + GLint texdims_location[2]; + GLint texgen_location[2]; + GLint blur_radius_location[2]; + GLint blurs_location[2]; + GLint blur_step_location[2]; + GLint blur_x_axis_location[2]; + GLint blur_y_axis_location[2]; + GLint alpha_location[2]; } cairo_gl_shader_t; typedef struct _cairo_gl_image_cache { @@ -406,7 +425,7 @@ typedef struct _cairo_gl_dispatch { void (*ClearStencil) (GLint s); void (*ColorMask) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); void (*DeleteTextures) (GLsizei n, const GLuint *textures); - void (*DepthMask)(GLboolean flag); + void (*DepthMask) (GLboolean flag); void (*Disable) (GLenum cap); void (*DrawArrays) (GLenum mode, GLint first, GLsizei count); void (*DrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); @@ -418,6 +437,7 @@ typedef struct _cairo_gl_dispatch { void (*GetFloatv) (GLenum pname, GLfloat *data); void (*GetIntegerv) (GLenum pname, GLint *data); const GLubyte *(*GetString) (GLenum pname); + const GLubyte *(*GetStringi) (GLenum pname, GLuint i); void (*PixelStorei) (GLenum pname, GLint param); void (*ReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *data); @@ -442,11 +462,17 @@ typedef struct _cairo_gl_dispatch { /* Buffers */ void (*GenBuffers) (GLsizei n, GLuint *buffers); + void (*DeleteBuffers) (GLsizei n, const GLuint *buffers); void (*BindBuffer) (GLenum target, GLuint buffer); void (*BufferData) (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage); + void (*BufferSubData) (GLenum target, GLintptr offset, + GLsizeiptr size, const GLvoid *data); GLvoid *(*MapBuffer) (GLenum target, GLenum access); GLboolean (*UnmapBuffer) (GLenum target); + void (*GenVertexArrays) (GLsizei n, GLuint *arrays); + void (*BindVertexArray) (GLuint array); + void (*DeleteVertexArrays) (GLsizei n, const GLuint *arrays); /* Shaders */ GLuint (*CreateShader) (GLenum type); @@ -540,6 +566,9 @@ typedef struct _cairo_gl_states { cairo_bool_t scissor_test_enabled; cairo_bool_t stencil_test_enabled; + GLuint bound_vbo; + GLuint bound_vao; + GLuint bound_ibo; } cairo_gl_states_t; struct _cairo_gl_context { @@ -547,7 +576,6 @@ struct _cairo_gl_context { const cairo_compositor_t *compositor; - GLuint texture_load_pbo; GLint max_framebuffer_size; GLint max_texture_size; GLint max_textures; @@ -556,6 +584,9 @@ struct _cairo_gl_context { GLint num_samples; cairo_bool_t supports_msaa; char *vb; + GLuint vbo; + GLuint vao; + GLuint ibo; cairo_bool_t has_shader_support; @@ -565,9 +596,9 @@ struct _cairo_gl_context { cairo_cache_t gradients; - /* cache[0] for gray font, cache[1] for rgba component alpha - * cache[2] for color glyph */ - cairo_gl_glyph_cache_t glyph_cache[3]; + /* cache[0] for gray font, cache[1] for rgba component alpha + * cache[2] for color glyph */ + cairo_gl_glyph_cache_t glyph_cache[3]; cairo_list_t fonts; cairo_gl_surface_t *current_target; @@ -578,6 +609,7 @@ struct _cairo_gl_context { cairo_gl_operand_t operands[2]; cairo_bool_t spans; + unsigned int vbo_size; unsigned int vb_offset; unsigned int vertex_size; cairo_region_t *clip_region; @@ -593,6 +625,7 @@ struct _cairo_gl_context { cairo_bool_t has_packed_depth_stencil; cairo_bool_t has_npot_repeat; cairo_bool_t can_read_bgra; + cairo_bool_t is_gl33; cairo_bool_t thread_aware; @@ -755,7 +788,7 @@ _cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx); cairo_private cairo_gl_emit_glyph_t _cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx, - const cairo_bool_t is_color_glyph); + const cairo_bool_t is_color_glyph); cairo_private void _cairo_gl_context_activate (cairo_gl_context_t *ctx, @@ -804,6 +837,45 @@ _enable_scissor_buffer (cairo_gl_context_t *ctx) } } +static cairo_always_inline void +_cairo_gl_ensure_drawbuffers (cairo_gl_context_t *ctx) +{ + GLint vbo, ibo, vao; + + if ((ctx->vao != 0 && + (ctx->vao != ctx->states_cache.bound_vao))) { + ctx->dispatch.GetIntegerv (GL_VERTEX_ARRAY_BINDING, &vao); + if (vao != ctx->states_cache.bound_vao) { + ctx->dispatch.BindVertexArray (ctx->vao); + ctx->states_cache.bound_vao = ctx->vao; + + ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo); + ctx->states_cache.bound_vbo = ctx->vbo; + + ctx->dispatch.BindBuffer (GL_ELEMENT_ARRAY_BUFFER, ctx->ibo); + ctx->states_cache.bound_ibo = ctx->ibo; + } + } + + if ((ctx->vbo != 0 && + (ctx->vbo != ctx->states_cache.bound_vbo))) { + ctx->dispatch.GetIntegerv (GL_ARRAY_BUFFER_BINDING, &vbo); + if (vbo != (GLint) ctx->states_cache.bound_vbo) { + ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo); + } + ctx->states_cache.bound_vbo = ctx->vbo; + } + + if ((ctx->ibo != 0 && + (ctx->ibo != ctx->states_cache.bound_ibo))) { + ctx->dispatch.GetIntegerv (GL_ELEMENT_ARRAY_BUFFER_BINDING, &ibo); + if (ibo != (GLint) ctx->states_cache.bound_ibo) { + ctx->dispatch.BindBuffer (GL_ELEMENT_ARRAY_BUFFER, ctx->ibo); + } + ctx->states_cache.bound_ibo = ctx->ibo; + } +} + cairo_private cairo_status_t _cairo_gl_composite_init (cairo_gl_composite_t *setup, cairo_operator_t op, @@ -886,6 +958,12 @@ _cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t *ctx, const cairo_point_t triangle[3]); cairo_private cairo_int_status_t +_cairo_gl_composite_emit_triangle_fan (cairo_gl_context_t *ctx, + cairo_gl_composite_t *setup, + const cairo_point_t *fan, + int count); + +cairo_private cairo_int_status_t _cairo_gl_composite_emit_point_as_tristrip_line (cairo_gl_context_t *ctx, const cairo_point_t point[2], cairo_bool_t start_point); @@ -944,49 +1022,49 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx, cairo_private cairo_gl_uniform_t _cairo_gl_shader_uniform_for_texunit (cairo_gl_uniform_t uniform, - cairo_gl_tex_t tex_unit); + cairo_gl_tex_t tex_unit); cairo_private void _cairo_gl_shader_bind_float (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, float value); cairo_private void _cairo_gl_shader_bind_float_array (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, int num, float *values); cairo_private void _cairo_gl_shader_bind_int (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, int value); cairo_private void _cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, float value0, float value1); cairo_private void _cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, float value0, float value1, float value2); cairo_private void _cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, float value0, float value1, float value2, float value3); cairo_private void _cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, const cairo_matrix_t* m); cairo_private void _cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, GLfloat* gl_m); cairo_private void @@ -999,9 +1077,15 @@ _cairo_gl_shader_fini (cairo_gl_context_t *ctx, cairo_gl_shader_t *shader); cairo_private int _cairo_gl_get_version (cairo_gl_dispatch_t *dispatch); +cairo_private int +_cairo_glsl_get_version (cairo_gl_dispatch_t *dispatch); + cairo_private cairo_gl_flavor_t _cairo_gl_get_flavor (cairo_gl_dispatch_t *dispatch); +cairo_private unsigned long +_cairo_gl_get_vbo_size (void); + cairo_private cairo_bool_t _cairo_gl_has_extension (cairo_gl_dispatch_t *dispatch, const char *ext); diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c index 0f8073ba6..7d7b669a8 100755..100644 --- a/src/cairo-gl-shaders.c +++ b/src/cairo-gl-shaders.c @@ -44,50 +44,40 @@ #include "cairo-error-private.h" #include "cairo-output-stream-private.h" -static GLint -_cairo_gl_shader_get_uniform_location (cairo_gl_context_t *ctx, - cairo_gl_shader_t *shader, - cairo_gl_uniform_t uniform) +enum { + CAIRO_GLSL_VERSION_UNKNOWN, + CAIRO_GLSL_VERSION_330, + CAIRO_GLSL_VERSION_NON_330 +}; + +static int needs_glsl330 = CAIRO_GLSL_VERSION_UNKNOWN; +/*static const char[] glsl330_frag_out = "fsColorOut"; +static const char[] non_glsl330_frag_out = "gl_FragColor"; +static const char[] glsl330_in_attrib = "in"; +static const char[] non_glsl330_in_attrib = "attribute"; +static const char[] glsl330_out_attrib = "varying"; +static const char[] non_glsl330_out_attrib = "out"; +static const char[] glsl330 = "#version 330"; +*/ +static cairo_bool_t _cairo_needs_glsl330 (cairo_gl_context_t *ctx) { - /* This should be kept in sync with the enum - * definition in cairo-gl-private.h. */ - const char *names[CAIRO_GL_UNIFORM_MAX] = { - "source_texdims", - "source_texgen", - "source_constant", - "source_sampler", - "source_a", - "source_circle_d", - "source_radius_0", - "source_blur_radius", - "source_blurs", - "source_blur_step", - "source_blur_x_axis", - "source_blur_y_axis", - "source_alpha", - "mask_texdims", - "mask_texgen", - "mask_constant", - "mask_sampler", - "mask_a", - "mask_circle_d", - "mask_radius_0", - "mask_blur_radius", - "mask_blurs", - "mask_blur_step", - "mask_blur_x_axis", - "mask_blur_y_axis", - "mask_alpha", - "ModelViewProjectionMatrix" - }; - - if (shader->uniforms[uniform] != -1) - return shader->uniforms[uniform]; + int version; + cairo_gl_flavor_t flavor; + + if (needs_glsl330 == CAIRO_GLSL_VERSION_UNKNOWN) { + version = _cairo_glsl_get_version (&ctx->dispatch); + flavor = _cairo_gl_get_flavor (&ctx->dispatch); + + if ((flavor == CAIRO_GL_FLAVOR_DESKTOP && + version >= CAIRO_GL_VERSION_ENCODE (3, 30)) || + (flavor == CAIRO_GL_FLAVOR_ES3 && + version >= CAIRO_GL_VERSION_ENCODE (3, 1))) + needs_glsl330 = CAIRO_GLSL_VERSION_330; + else + needs_glsl330 = CAIRO_GLSL_VERSION_NON_330; + } - shader->uniforms[uniform] = - ctx->dispatch.GetUniformLocation (shader->program, - names[uniform]); - return shader->uniforms[uniform]; + return needs_glsl330 == CAIRO_GLSL_VERSION_330; } cairo_gl_uniform_t @@ -212,12 +202,8 @@ _cairo_gl_shader_cache_destroy (void *data) static void _cairo_gl_shader_init (cairo_gl_shader_t *shader) { - int i; shader->fragment_shader = 0; shader->program = 0; - - for (i = 0; i < CAIRO_GL_UNIFORM_MAX; i++) - shader->uniforms[i] = -1; } cairo_status_t @@ -232,8 +218,23 @@ _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx) "{\n" " gl_FragColor = color;\n" "}\n"; + + static const char *glsl330_fill_fs_source = + "#version 330\n" + "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n" + "uniform vec4 color;\n" + "out vec4 fsColorOut;\n" + "void main()\n" + "{\n" + " fsColorOut = color;\n" + "}\n"; + cairo_status_t status; + _cairo_needs_glsl330 (ctx); + if (_cairo_gl_get_version (&ctx->dispatch) >= CAIRO_GL_VERSION_ENCODE (2, 0) || (_cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_shader_objects") && _cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_fragment_shader") && @@ -258,7 +259,17 @@ _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx) return status; _cairo_gl_shader_init (&ctx->fill_rectangles_shader); - status = _cairo_gl_shader_compile_and_link (ctx, + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) + status = _cairo_gl_shader_compile_and_link (ctx, + &ctx->fill_rectangles_shader, + CAIRO_GL_VAR_NONE, + CAIRO_GL_VAR_NONE, + FALSE, + glsl330_fill_fs_source, + CAIRO_EXTEND_NONE, CAIRO_EXTEND_NONE, + FALSE, FALSE); + else + status = _cairo_gl_shader_compile_and_link (ctx, &ctx->fill_rectangles_shader, CAIRO_GL_VAR_NONE, CAIRO_GL_VAR_NONE, @@ -334,32 +345,63 @@ cairo_gl_shader_emit_variable (cairo_output_stream_t *stream, case CAIRO_GL_VAR_NONE: break; case CAIRO_GL_VAR_TEXCOORDS: - _cairo_output_stream_printf (stream, + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) { + _cairo_output_stream_printf (stream, + "in vec4 MultiTexCoord%d;\n" + "out vec2 %s_texcoords;\n", + name, + operand_names[name]); + if (use_atlas) + _cairo_output_stream_printf (stream, + "out vec2 %s_start_coords;\n" + "out vec2 %s_stop_coords;\n", + operand_names[name], operand_names[name]); + } else { + _cairo_output_stream_printf (stream, "attribute vec4 MultiTexCoord%d;\n" "varying vec2 %s_texcoords;\n", name, operand_names[name]); - if (use_atlas) - _cairo_output_stream_printf (stream, + if (use_atlas) + _cairo_output_stream_printf (stream, "varying vec2 %s_start_coords;\n" "varying vec2 %s_stop_coords;\n", operand_names[name], operand_names[name]); + } break; case CAIRO_GL_VAR_TEXGEN: - _cairo_output_stream_printf (stream, + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) { + _cairo_output_stream_printf (stream, + "uniform mat3 %s_texgen;\n" + "out vec2 %s_texcoords;\n", + operand_names[name], + operand_names[name]); + /*if (use_atlas) + _cairo_output_stream_printf (stream, + "out vec2 %s_start_coords;\n" + "out vec2 %s_stop_coords;\n", + operand_names[name], operand_names[name]); + */ + } else { + _cairo_output_stream_printf (stream, "uniform mat3 %s_texgen;\n" "varying vec2 %s_texcoords;\n", operand_names[name], operand_names[name]); - /*if (use_atlas) - _cairo_output_stream_printf (stream, + /*if (use_atlas) + _cairo_output_stream_printf (stream, "varying vec2 %s_start_coords;\n" "varying vec2 %s_stop_coords;\n", operand_names[name], operand_names[name]); -*/ + */ + } break; case CAIRO_GL_VAR_COLOR: - _cairo_output_stream_printf (stream, + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) + _cairo_output_stream_printf (stream, + "out vec4 fragment_color;\n"); + else + _cairo_output_stream_printf (stream, "varying vec4 fragment_color;\n"); break; } @@ -395,7 +437,10 @@ cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream, static void cairo_gl_shader_dcl_coverage (cairo_output_stream_t *stream) { - _cairo_output_stream_printf (stream, "varying float coverage;\n"); + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) + _cairo_output_stream_printf (stream, "out float coverage;\n"); + else + _cairo_output_stream_printf (stream, "varying float coverage;\n"); } static void @@ -422,10 +467,16 @@ cairo_gl_shader_emit_varying (cairo_output_stream_t *stream, { const char *namestr = operand_names[name]; - _cairo_output_stream_printf (stream, - "varying vec2 %s_start_coords;\n" - "varying vec2 %s_stop_coords;\n", - namestr, namestr); + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) + _cairo_output_stream_printf (stream, + "out vec2 %s_start_coords;\n" + "out vec2 %s_stop_coords;\n", + namestr, namestr); + else + _cairo_output_stream_printf (stream, + "varying vec2 %s_start_coords;\n" + "varying vec2 %s_stop_coords;\n", + namestr, namestr); } static cairo_status_t @@ -442,6 +493,11 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src, unsigned long length; cairo_status_t status; + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) + _cairo_output_stream_printf (stream, "#version 330\n"); + + _cairo_output_stream_printf (stream, "#ifdef GL_ES\nprecision mediump float;\n#endif\n"); + cairo_gl_shader_emit_variable (stream, src, CAIRO_GL_TEX_SOURCE, src_use_atlas); cairo_gl_shader_emit_variable (stream, mask, CAIRO_GL_TEX_MASK, mask_use_atlas); if (use_coverage) @@ -453,7 +509,20 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src, if (mask_use_atlas && mask == CAIRO_GL_VAR_TEXGEN) cairo_gl_shader_emit_varying (stream, CAIRO_GL_TEX_MASK); - _cairo_output_stream_printf (stream, + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) { + _cairo_output_stream_printf (stream, + "in vec4 Vertex;\n" + "in vec4 Color;\n" + "in vec2 StartCoords0;\n" + "in vec2 StartCoords1;\n" + "in vec2 StopCoords0;\n" + "in vec2 StopCoords1;\n" + "uniform mat4 ModelViewProjectionMatrix;\n" + "void main()\n" + "{\n" + " gl_Position = ModelViewProjectionMatrix * Vertex;\n"); + } else { + _cairo_output_stream_printf (stream, "attribute vec4 Vertex;\n" "attribute vec4 Color;\n" "attribute vec2 StartCoords0;\n" @@ -464,6 +533,7 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src, "void main()\n" "{\n" " gl_Position = ModelViewProjectionMatrix * Vertex;\n"); + } cairo_gl_shader_emit_vertex (stream, src, CAIRO_GL_TEX_SOURCE); cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_TEX_MASK); @@ -479,10 +549,8 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src, "}\n\0", 3); status = _cairo_memory_stream_destroy (stream, &source, &length); - if (unlikely (status)) { - free (source); - return status; - } + if (unlikely (status)) + return status; *out = (char *) source; return CAIRO_STATUS_SUCCESS; @@ -512,6 +580,7 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, cairo_gl_tex_t name) { const char *namestr = operand_names[name]; + const char *textstr = (needs_glsl330 == CAIRO_GLSL_VERSION_330) ? "" : "2D"; const char *rectstr = (ctx->tex_target == GL_TEXTURE_RECTANGLE ? "Rect" : ""); cairo_bool_t use_atlas = _cairo_gl_operand_get_use_atlas (op); @@ -521,7 +590,7 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, ASSERT_NOT_REACHED; break; case CAIRO_GL_OPERAND_NONE: - _cairo_output_stream_printf (stream, + _cairo_output_stream_printf (stream, "vec4 get_%s()\n" "{\n" " return vec4 (0, 0, 0, 1);\n" @@ -530,13 +599,22 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, break; case CAIRO_GL_OPERAND_CONSTANT: if (op->constant.encode_as_attribute) { - _cairo_output_stream_printf (stream, - "varying vec4 fragment_color;\n" - "vec4 get_%s()\n" - "{\n" - " return fragment_color;\n" - "}\n", - namestr); + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) + _cairo_output_stream_printf (stream, + "in vec4 fragment_color;\n" + "vec4 get_%s()\n" + "{\n" + " return fragment_color;\n" + "}\n", + namestr); + else + _cairo_output_stream_printf (stream, + "varying vec4 fragment_color;\n" + "vec4 get_%s()\n" + "{\n" + " return fragment_color;\n" + "}\n", + namestr); } else { _cairo_output_stream_printf (stream, "uniform vec4 %s_constant;\n" @@ -546,23 +624,41 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, "}\n", namestr, namestr, namestr); } - break; + break; case CAIRO_GL_OPERAND_TEXTURE: case CAIRO_GL_OPERAND_GAUSSIAN: - if (! use_atlas) { - _cairo_output_stream_printf (stream, - "uniform sampler2D%s %s_sampler;\n" - "uniform vec2 %s_texdims;\n" - "varying vec2 %s_texcoords;\n", - rectstr, namestr, namestr, namestr); + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) { + if (! use_atlas) { + _cairo_output_stream_printf (stream, + "uniform sampler2D%s %s_sampler;\n" + "uniform vec2 %s_texdims;\n" + "in vec2 %s_texcoords;\n", + rectstr, namestr, namestr, namestr); + } else { + _cairo_output_stream_printf (stream, + "uniform sampler2D%s %s_sampler;\n" + "uniform vec2 %s_texdims;\n" + "in vec2 %s_texcoords;\n" + "in vec2 %s_start_coords;\n" + "in vec2 %s_stop_coords;\n", + rectstr, namestr, namestr, namestr, namestr, namestr); + } } else { - _cairo_output_stream_printf (stream, - "uniform sampler2D%s %s_sampler;\n" - "uniform vec2 %s_texdims;\n" - "varying vec2 %s_texcoords;\n" - "varying vec2 %s_start_coords;\n" - "varying vec2 %s_stop_coords;\n", - rectstr, namestr, namestr, namestr, namestr, namestr); + if (! use_atlas) { + _cairo_output_stream_printf (stream, + "uniform sampler2D%s %s_sampler;\n" + "uniform vec2 %s_texdims;\n" + "varying vec2 %s_texcoords;\n", + rectstr, namestr, namestr, namestr); + } else { + _cairo_output_stream_printf (stream, + "uniform sampler2D%s %s_sampler;\n" + "uniform vec2 %s_texdims;\n" + "varying vec2 %s_texcoords;\n" + "varying vec2 %s_start_coords;\n" + "varying vec2 %s_stop_coords;\n", + rectstr, namestr, namestr, namestr, namestr, namestr); + } } if (op->type != CAIRO_GL_OPERAND_TEXTURE) { @@ -582,17 +678,17 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, namestr); if (op->type == CAIRO_GL_OPERAND_TEXTURE) { - if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 || + if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 || ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) && _cairo_gl_shader_needs_border_fade (op)) { if (! use_atlas) { _cairo_output_stream_printf (stream, " vec2 border_fade = %s_border_fade (%s_texcoords, %s_texdims);\n" - " vec4 texel = texture2D%s (%s_sampler, %s_texcoords);\n" + " vec4 texel = texture%s%s (%s_sampler, %s_texcoords);\n" " return texel * border_fade.x * border_fade.y;\n" "}\n", - namestr, namestr, namestr, rectstr, namestr, namestr); + namestr, namestr, namestr, textstr, rectstr, namestr, namestr); } else { _cairo_output_stream_printf (stream, @@ -600,25 +696,24 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, " vec2 co = %s_wrap (%s_texcoords, %s_start_coords, %s_stop_coords);\n" " if (co.x == -1.0 && co.y == -1.0)\n" " return vec4(0.0, 0.0, 0.0, 0.0);\n" - " vec4 texel = texture2D%s (%s_sampler, co);\n" + " vec4 texel = texture%s%s (%s_sampler, %s_wrap (%s_texcoords, %s_start_coords, %s_stop_coords));\n" " return texel * border_fade.x * border_fade.y;\n" "}\n", - namestr, namestr, namestr, namestr, - namestr, namestr, namestr, rectstr, namestr); + namestr, namestr, namestr, namestr, namestr, namestr, namestr, textstr, rectstr, namestr, namestr, namestr, namestr, namestr); } } else { if (! use_atlas) { _cairo_output_stream_printf (stream, - " return texture2D%s (%s_sampler, %s_wrap (%s_texcoords));\n" + " return texture%s%s (%s_sampler, %s_wrap (%s_texcoords));\n" "}\n", - rectstr, namestr, namestr, namestr); + textstr, rectstr, namestr, namestr, namestr); } else { _cairo_output_stream_printf (stream, - " return texture2D%s (%s_sampler, %s_wrap (%s_texcoords, %s_start_coords, %s_stop_coords));\n" + " return texture%s%s (%s_sampler, %s_wrap (%s_texcoords, %s_start_coords, %s_stop_coords));\n" "}\n", - rectstr, namestr, namestr, namestr, namestr, namestr); + textstr, rectstr, namestr, namestr, namestr, namestr, namestr); } } } @@ -631,7 +726,7 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, " vec2 wrapped_coords = %s_wrap (%s_texcoords, %s_start_coords, %s_stop_coords);\n" " if (wrapped_coords == vec2 (-1.0, -1.0))\n" " return texel;\n" - " texel += texture2D%s (%s_sampler, wrapped_coords);\n" + " texel += texture%s%s (%s_sampler, wrapped_coords);\n" " texel = texel * %s_blurs[%s_blur_radius];\n" " for (i = -%s_blur_radius; i <= %s_blur_radius; i++) {\n" " if (i == 0)\n" @@ -642,160 +737,255 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, " if (wrapped_coords == vec2 (-1.0, -1.0))\n" " texel += vec4 (0.0, 0.0, 0.0, alpha) * %s_blurs[i+%s_blur_radius];\n" " else\n" - " texel += texture2D%s (%s_sampler, wrapped_coords) * %s_blurs[i+%s_blur_radius];\n" + " texel += texture%s%s (%s_sampler, wrapped_coords) * %s_blurs[i+%s_blur_radius];\n" " }\n" " return texel;\n" "}\n", namestr, namestr, namestr, namestr, namestr, - rectstr, namestr, namestr, namestr, + textstr, rectstr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, - rectstr, namestr, namestr, namestr); + textstr, rectstr, namestr, namestr, namestr); } break; case CAIRO_GL_OPERAND_LINEAR_GRADIENT: - _cairo_output_stream_printf (stream, - "varying vec2 %s_texcoords;\n" - "uniform vec2 %s_texdims;\n" - "uniform sampler2D%s %s_sampler;\n" - "\n" - "vec4 get_%s()\n" - "{\n", - namestr, namestr, rectstr, namestr, namestr); - if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 || + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) { + _cairo_output_stream_printf (stream, + "in vec2 %s_texcoords;\n" + "uniform vec2 %s_texdims;\n" + "uniform sampler2D%s %s_sampler;\n" + "\n" + "vec4 get_%s()\n" + "{\n", + namestr, namestr, rectstr, namestr, namestr); + } + else { + _cairo_output_stream_printf (stream, + "varying vec2 %s_texcoords;\n" + "uniform vec2 %s_texdims;\n" + "uniform sampler2D%s %s_sampler;\n" + "\n" + "vec4 get_%s()\n" + "{\n", + namestr, namestr, rectstr, namestr, namestr); + } + + if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 || ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) && _cairo_gl_shader_needs_border_fade (op)) { _cairo_output_stream_printf (stream, " float border_fade = %s_border_fade (%s_texcoords.x, %s_texdims.x);\n" - " vec4 texel = texture2D%s (%s_sampler, vec2 (%s_texcoords.x, 0.5));\n" + " vec4 texel = texture%s%s (%s_sampler, vec2 (%s_texcoords.x, 0.5));\n" " return texel * border_fade;\n" "}\n", - namestr, namestr, namestr, rectstr, namestr, namestr); + namestr, namestr, namestr, textstr, rectstr, namestr, namestr); } else { _cairo_output_stream_printf (stream, - " return texture2D%s (%s_sampler, %s_wrap (vec2 (%s_texcoords.x, 0.5)));\n" + " return texture%s%s (%s_sampler, %s_wrap (vec2 (%s_texcoords.x, 0.5)));\n" "}\n", - rectstr, namestr, namestr, namestr); + textstr, rectstr, namestr, namestr, namestr); } break; case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: - _cairo_output_stream_printf (stream, - "varying vec2 %s_texcoords;\n" - "uniform vec2 %s_texdims;\n" - "uniform sampler2D%s %s_sampler;\n" - "uniform vec3 %s_circle_d;\n" - "uniform float %s_radius_0;\n" - "\n" - "vec4 get_%s()\n" - "{\n" - " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n" - " \n" - " float B = dot (pos, %s_circle_d);\n" - " float C = dot (pos, vec3 (pos.xy, -pos.z));\n" - " \n" - " float t = 0.5 * C / B;\n" - " float is_valid = step (-%s_radius_0, t * %s_circle_d.z);\n", - namestr, namestr, rectstr, namestr, namestr, namestr, namestr, - namestr, namestr, namestr, namestr, namestr); - if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 || + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) { + _cairo_output_stream_printf (stream, + "in vec2 %s_texcoords;\n" + "uniform vec2 %s_texdims;\n" + "uniform sampler2D%s %s_sampler;\n" + "uniform vec3 %s_circle_d;\n" + "uniform float %s_radius_0;\n" + "\n" + "vec4 get_%s()\n" + "{\n" + " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n" + " \n" + " float B = dot (pos, %s_circle_d);\n" + " float C = dot (pos, vec3 (pos.xy, -pos.z));\n" + " \n" + " float t = 0.5 * C / B;\n" + " float is_valid = step (-%s_radius_0, t * %s_circle_d.z);\n", + namestr, namestr, rectstr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr, namestr); + } else { + _cairo_output_stream_printf (stream, + "varying vec2 %s_texcoords;\n" + "uniform vec2 %s_texdims;\n" + "uniform sampler2D%s %s_sampler;\n" + "uniform vec3 %s_circle_d;\n" + "uniform float %s_radius_0;\n" + "\n" + "vec4 get_%s()\n" + "{\n" + " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n" + " \n" + " float B = dot (pos, %s_circle_d);\n" + " float C = dot (pos, vec3 (pos.xy, -pos.z));\n" + " \n" + " float t = 0.5 * C / B;\n" + " float is_valid = step (-%s_radius_0, t * %s_circle_d.z);\n", + namestr, namestr, rectstr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr, namestr); + } + + if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 || ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) && _cairo_gl_shader_needs_border_fade (op)) { _cairo_output_stream_printf (stream, " float border_fade = %s_border_fade (t, %s_texdims.x);\n" - " vec4 texel = texture2D%s (%s_sampler, vec2 (t, 0.5));\n" + " vec4 texel = texture%s%s (%s_sampler, vec2 (t, 0.5));\n" " return mix (vec4 (0.0), texel * border_fade, is_valid);\n" "}\n", - namestr, namestr, rectstr, namestr); + namestr, namestr, textstr, rectstr, namestr); } else { _cairo_output_stream_printf (stream, - " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2 (t, 0.5)));\n" + " vec4 texel = texture%s%s (%s_sampler, %s_wrap (vec2 (t, 0.5)));\n" " return mix (vec4 (0.0), texel, is_valid);\n" "}\n", - rectstr, namestr, namestr); + textstr, rectstr, namestr, namestr); } break; case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: - _cairo_output_stream_printf (stream, - "varying vec2 %s_texcoords;\n" - "uniform vec2 %s_texdims;\n" - "uniform sampler2D%s %s_sampler;\n" - "uniform vec3 %s_circle_d;\n" - "uniform float %s_a;\n" - "uniform float %s_radius_0;\n" - "\n" - "vec4 get_%s()\n" - "{\n" - " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n" - " \n" - " float B = dot (pos, %s_circle_d);\n" - " float C = dot (pos, vec3 (pos.xy, -pos.z));\n" - " \n" - " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n" - " float sqrtdet = sqrt (abs (det));\n" - " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n" - " \n" - " vec2 is_valid = step (vec2 (0.0), t) * step (t, vec2(1.0));\n" - " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n" - " \n" - " float upper_t = mix (t.y, t.x, is_valid.x);\n", - namestr, namestr, rectstr, namestr, namestr, namestr, namestr, - namestr, namestr, namestr, namestr, namestr, namestr); - if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 || + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) { + _cairo_output_stream_printf (stream, + "in vec2 %s_texcoords;\n" + "uniform vec2 %s_texdims;\n" + "uniform sampler2D%s %s_sampler;\n" + "uniform vec3 %s_circle_d;\n" + "uniform float %s_a;\n" + "uniform float %s_radius_0;\n" + "\n" + "vec4 get_%s()\n" + "{\n" + " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n" + " \n" + " float B = dot (pos, %s_circle_d);\n" + " float C = dot (pos, vec3 (pos.xy, -pos.z));\n" + " \n" + " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n" + " float sqrtdet = sqrt (abs (det));\n" + " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n" + " \n" + " vec2 is_valid = step (vec2 (0.0), t) * step (t, vec2(1.0));\n" + " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n" + " \n" + " float upper_t = mix (t.y, t.x, is_valid.x);\n", + namestr, namestr, rectstr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr, namestr, namestr); + } else { + _cairo_output_stream_printf (stream, + "varying vec2 %s_texcoords;\n" + "uniform vec2 %s_texdims;\n" + "uniform sampler2D%s %s_sampler;\n" + "uniform vec3 %s_circle_d;\n" + "uniform float %s_a;\n" + "uniform float %s_radius_0;\n" + "\n" + "vec4 get_%s()\n" + "{\n" + " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n" + " \n" + " float B = dot (pos, %s_circle_d);\n" + " float C = dot (pos, vec3 (pos.xy, -pos.z));\n" + " \n" + " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n" + " float sqrtdet = sqrt (abs (det));\n" + " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n" + " \n" + " vec2 is_valid = step (vec2 (0.0), t) * step (t, vec2(1.0));\n" + " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n" + " \n" + " float upper_t = mix (t.y, t.x, is_valid.x);\n", + namestr, namestr, rectstr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr, namestr, namestr); + } + + if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 || ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) && _cairo_gl_shader_needs_border_fade (op)) { _cairo_output_stream_printf (stream, " float border_fade = %s_border_fade (upper_t, %s_texdims.x);\n" - " vec4 texel = texture2D%s (%s_sampler, vec2 (upper_t, 0.5));\n" + " vec4 texel = texture%s%s (%s_sampler, vec2 (upper_t, 0.5));\n" " return mix (vec4 (0.0), texel * border_fade, has_color);\n" "}\n", - namestr, namestr, rectstr, namestr); + namestr, namestr, textstr, rectstr, namestr); } else { _cairo_output_stream_printf (stream, - " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n" + " vec4 texel = texture%s%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n" " return mix (vec4 (0.0), texel, has_color);\n" "}\n", - rectstr, namestr, namestr); + textstr, rectstr, namestr, namestr); } break; case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: - _cairo_output_stream_printf (stream, - "varying vec2 %s_texcoords;\n" - "uniform sampler2D%s %s_sampler;\n" - "uniform vec3 %s_circle_d;\n" - "uniform float %s_a;\n" - "uniform float %s_radius_0;\n" - "\n" - "vec4 get_%s()\n" - "{\n" - " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n" - " \n" - " float B = dot (pos, %s_circle_d);\n" - " float C = dot (pos, vec3 (pos.xy, -pos.z));\n" - " \n" - " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n" - " float sqrtdet = sqrt (abs (det));\n" - " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n" - " \n" - " vec2 is_valid = step (vec2 (-%s_radius_0), t * %s_circle_d.z);\n" - " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n" - " \n" - " float upper_t = mix (t.y, t.x, is_valid.x);\n" - " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n" - " return mix (vec4 (0.0), texel, has_color);\n" - "}\n", - namestr, rectstr, namestr, namestr, namestr, namestr, - namestr, namestr, namestr, namestr, namestr, - namestr, namestr, namestr, rectstr, namestr, namestr); + if (needs_glsl330 == CAIRO_GLSL_VERSION_330) { + _cairo_output_stream_printf (stream, + "in vec2 %s_texcoords;\n" + "uniform sampler2D%s %s_sampler;\n" + "uniform vec3 %s_circle_d;\n" + "uniform float %s_a;\n" + "uniform float %s_radius_0;\n" + "\n" + "vec4 get_%s()\n" + "{\n" + " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n" + " \n" + " float B = dot (pos, %s_circle_d);\n" + " float C = dot (pos, vec3 (pos.xy, -pos.z));\n" + " \n" + " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n" + " float sqrtdet = sqrt (abs (det));\n" + " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n" + " \n" + " vec2 is_valid = step (vec2 (-%s_radius_0), t * %s_circle_d.z);\n" + " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n" + " \n" + " float upper_t = mix (t.y, t.x, is_valid.x);\n" + " vec4 texel = texture%s%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n" + " return mix (vec4 (0.0), texel, has_color);\n" + "}\n", + namestr, rectstr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, textstr, rectstr, namestr, namestr); + } else { + _cairo_output_stream_printf (stream, + "varying vec2 %s_texcoords;\n" + "uniform sampler2D%s %s_sampler;\n" + "uniform vec3 %s_circle_d;\n" + "uniform float %s_a;\n" + "uniform float %s_radius_0;\n" + "\n" + "vec4 get_%s()\n" + "{\n" + " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n" + " \n" + " float B = dot (pos, %s_circle_d);\n" + " float C = dot (pos, vec3 (pos.xy, -pos.z));\n" + " \n" + " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n" + " float sqrtdet = sqrt (abs (det));\n" + " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n" + " \n" + " vec2 is_valid = step (vec2 (-%s_radius_0), t * %s_circle_d.z);\n" + " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n" + " \n" + " float upper_t = mix (t.y, t.x, is_valid.x);\n" + " vec4 texel = texture%s%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n" + " return mix (vec4 (0.0), texel, has_color);\n" + "}\n", + namestr, rectstr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, textstr, rectstr, namestr, namestr); + } break; } } @@ -962,21 +1152,13 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx, cairo_status_t status; const char *coverage_str; - // dy5.kim: Use highp only for gradients to handle the following test case - // http://w3c-test.org/html/tests/approved/canvas/2d.gradient.radial.touch1.html - if (src->type == CAIRO_GL_OPERAND_LINEAR_GRADIENT || - src->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0 || - src->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE || - src->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT) - _cairo_output_stream_printf (stream, - "#ifdef GL_ES\n" - "precision highp float;\n" - "#endif\n"); - else - _cairo_output_stream_printf (stream, - "#ifdef GL_ES\n" - "precision mediump float;\n" - "#endif\n"); + if (_cairo_needs_glsl330 (ctx)) + _cairo_output_stream_printf (stream, "#version 330\n"); + + _cairo_output_stream_printf (stream, + "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n"); _cairo_gl_shader_emit_wrap (ctx, stream, src, CAIRO_GL_TEX_SOURCE); _cairo_gl_shader_emit_wrap (ctx, stream, mask, CAIRO_GL_TEX_MASK); @@ -994,10 +1176,17 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx, coverage_str = ""; if (use_coverage) { - _cairo_output_stream_printf (stream, "varying float coverage;\n"); + if (_cairo_needs_glsl330 (ctx)) { + _cairo_output_stream_printf (stream, "in float coverage;\n"); + } else { + _cairo_output_stream_printf (stream, "varying float coverage;\n"); + } coverage_str = " * coverage"; } + if (_cairo_needs_glsl330 (ctx)) + _cairo_output_stream_printf (stream, "out vec4 fsColorOut;\n"); + _cairo_output_stream_printf (stream, "void main()\n" "{\n"); @@ -1006,19 +1195,34 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx, default: ASSERT_NOT_REACHED; case CAIRO_GL_SHADER_IN_NORMAL: - _cairo_output_stream_printf (stream, - " gl_FragColor = get_source() * get_mask().a%s;\n", - coverage_str); + if (_cairo_needs_glsl330 (ctx)) + _cairo_output_stream_printf (stream, + " fsColorOut = get_source() * get_mask().a%s;\n", + coverage_str); + else + _cairo_output_stream_printf (stream, + " gl_FragColor = get_source() * get_mask().a%s;\n", + coverage_str); break; case CAIRO_GL_SHADER_IN_CA_SOURCE: - _cairo_output_stream_printf (stream, - " gl_FragColor = get_source() * get_mask()%s;\n", - coverage_str); + if (_cairo_needs_glsl330 (ctx)) + _cairo_output_stream_printf (stream, + " fsColorOut = get_source() * get_mask()%s;\n", + coverage_str); + else + _cairo_output_stream_printf (stream, + " gl_FragColor = get_source() * get_mask()%s;\n", + coverage_str); break; case CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA: - _cairo_output_stream_printf (stream, - " gl_FragColor = get_source().a * get_mask()%s;\n", - coverage_str); + if (_cairo_needs_glsl330 (ctx)) + _cairo_output_stream_printf (stream, + " fsColorOut = get_source().a * get_mask()%s;\n", + coverage_str); + else + _cairo_output_stream_printf (stream, + " gl_FragColor = get_source().a * get_mask()%s;\n", + coverage_str); break; } @@ -1026,10 +1230,8 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx, "}\n\0", 3); status = _cairo_memory_stream_destroy (stream, &source, &length); - if (unlikely (status)) { - free (source); + if (unlikely (status)) return status; - } *out = (char *) source; return CAIRO_STATUS_SUCCESS; @@ -1133,6 +1335,22 @@ link_shader_program (cairo_gl_context_t *ctx, ASSERT_NOT_REACHED; } +static GLint +_cairo_gl_get_op_uniform_location(cairo_gl_context_t *ctx, + cairo_gl_shader_t *shader, + cairo_gl_tex_t tex_unit, + const char *suffix) +{ + cairo_gl_dispatch_t *dispatch = &ctx->dispatch; + char uniform_name[100]; + const char *unit_name[2] = { "source", "mask" }; + + snprintf (uniform_name, sizeof (uniform_name), "%s_%s", + unit_name[tex_unit], suffix); + + return dispatch->GetUniformLocation (shader->program, uniform_name); +} + static cairo_status_t _cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx, cairo_gl_shader_t *shader, @@ -1145,8 +1363,12 @@ _cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx, cairo_bool_t src_use_atlas, cairo_bool_t mask_use_atlas) { + cairo_gl_dispatch_t *dispatch = &ctx->dispatch; unsigned int vertex_shader; cairo_status_t status; + int i; + + _cairo_needs_glsl330 (ctx); assert (shader->program == 0); @@ -1167,12 +1389,14 @@ _cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx, use_coverage, CAIRO_GL_VAR_NONE, &source); - if (unlikely (status)) - goto FAILURE; + if (unlikely (status)) + goto FAILURE; + + printf ("\n\n======= vertex source ========\n%s\n\n", source); compile_shader (ctx, &ctx->vertex_shaders[vertex_shader], GL_VERTEX_SHADER, source); - free (source); + free (source); } compile_shader (ctx, &shader->fragment_shader, @@ -1182,6 +1406,37 @@ _cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx, ctx->vertex_shaders[vertex_shader], shader->fragment_shader); + shader->mvp_location = + dispatch->GetUniformLocation (shader->program, + "ModelViewProjectionMatrix"); + + for (i = 0; i < 2; i++) { + shader->constant_location[i] = + _cairo_gl_get_op_uniform_location (ctx, shader, i, "constant"); + shader->a_location[i] = + _cairo_gl_get_op_uniform_location (ctx, shader, i, "a"); + shader->circle_d_location[i] = + _cairo_gl_get_op_uniform_location (ctx, shader, i, "circle_d"); + shader->radius_0_location[i] = + _cairo_gl_get_op_uniform_location (ctx, shader, i, "radius_0"); + shader->texdims_location[i] = + _cairo_gl_get_op_uniform_location (ctx, shader, i, "texdims"); + shader->texgen_location[i] = + _cairo_gl_get_op_uniform_location (ctx, shader, i, "texgen"); + shader->blur_radius_location[i] = + _cairo_gl_get_op_uniform_location (ctx, shader, i, "blur_radius"); + shader->blurs_location[i] = + _cairo_gl_get_op_uniform_location (ctx, shader, i, "blurs"); + shader->blur_step_location[i] = + _cairo_gl_get_op_uniform_location (ctx, shader, i, "blur_step"); + shader->blur_x_axis_location[i] = + _cairo_gl_get_op_uniform_location (ctx, shader, i, "blur_x_axis"); + shader->blur_y_axis_location[i] = + _cairo_gl_get_op_uniform_location (ctx, shader, i, "blur_y_axis"); + shader->alpha_location[i] = + _cairo_gl_get_op_uniform_location (ctx, shader, i, "alpha"); + } + return CAIRO_STATUS_SUCCESS; FAILURE: @@ -1211,14 +1466,12 @@ _cairo_gl_shader_set_samplers (cairo_gl_context_t *ctx, dispatch->GetIntegerv (GL_CURRENT_PROGRAM, &saved_program); dispatch->UseProgram (shader->program); - location = _cairo_gl_shader_get_uniform_location (ctx, shader, - CAIRO_GL_UNIFORM_SAMPLER); + location = dispatch->GetUniformLocation (shader->program, "source_sampler"); if (location != -1) { dispatch->Uniform1i (location, CAIRO_GL_TEX_SOURCE); } - location = _cairo_gl_shader_get_uniform_location (ctx, shader, - CAIRO_GL_UNIFORM_MASK_SAMPLER); + location = dispatch->GetUniformLocation (shader->program, "mask_sampler"); if (location != -1) { dispatch->Uniform1i (location, CAIRO_GL_TEX_MASK); } @@ -1228,96 +1481,74 @@ _cairo_gl_shader_set_samplers (cairo_gl_context_t *ctx, void _cairo_gl_shader_bind_float (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, float value) { cairo_gl_dispatch_t *dispatch = &ctx->dispatch; - GLint location = _cairo_gl_shader_get_uniform_location (ctx, - ctx->current_shader, - uniform); assert (location != -1); dispatch->Uniform1f (location, value); } void _cairo_gl_shader_bind_int (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, int value) { cairo_gl_dispatch_t *dispatch = &ctx->dispatch; - GLint location = _cairo_gl_shader_get_uniform_location (ctx, - ctx->current_shader, - uniform); assert (location != -1); dispatch->Uniform1i (location, value); } void _cairo_gl_shader_bind_float_array (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, int num, float *values) { cairo_gl_dispatch_t *dispatch = &ctx->dispatch; - GLint location = _cairo_gl_shader_get_uniform_location (ctx, - ctx->current_shader, - uniform); assert (location != -1); dispatch->Uniform1fv (location, num, values); } void _cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, float value0, float value1) { cairo_gl_dispatch_t *dispatch = &ctx->dispatch; - GLint location = _cairo_gl_shader_get_uniform_location (ctx, - ctx->current_shader, - uniform); assert (location != -1); dispatch->Uniform2f (location, value0, value1); } void _cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, float value0, float value1, float value2) { cairo_gl_dispatch_t *dispatch = &ctx->dispatch; - GLint location = _cairo_gl_shader_get_uniform_location (ctx, - ctx->current_shader, - uniform); assert (location != -1); dispatch->Uniform3f (location, value0, value1, value2); } void _cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, float value0, float value1, float value2, float value3) { cairo_gl_dispatch_t *dispatch = &ctx->dispatch; - GLint location = _cairo_gl_shader_get_uniform_location (ctx, - ctx->current_shader, - uniform); assert (location != -1); dispatch->Uniform4f (location, value0, value1, value2, value3); } void _cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, + GLint location, const cairo_matrix_t* m) { cairo_gl_dispatch_t *dispatch = &ctx->dispatch; - GLint location = _cairo_gl_shader_get_uniform_location (ctx, - ctx->current_shader, - uniform); - float gl_m[9] = { m->xx, m->yx, 0, m->xy, m->yy, 0, @@ -1329,13 +1560,9 @@ _cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx, void _cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx, - cairo_gl_uniform_t uniform, - GLfloat* gl_m) + GLint location, GLfloat* gl_m) { cairo_gl_dispatch_t *dispatch = &ctx->dispatch; - GLint location = _cairo_gl_shader_get_uniform_location (ctx, - ctx->current_shader, - uniform); assert (location != -1); dispatch->UniformMatrix4fv (location, 1, GL_FALSE, gl_m); } @@ -1411,6 +1638,8 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx, if (unlikely (status)) return status; + printf ("\n\n======= fragment source ========\n%s\n\n", fs_source); + entry = malloc (sizeof (cairo_shader_cache_entry_t)); if (unlikely (entry == NULL)) { free (fs_source); diff --git a/src/cairo-gl-source.c b/src/cairo-gl-source.c index 53c3ed35a..53c3ed35a 100755..100644 --- a/src/cairo-gl-source.c +++ b/src/cairo-gl-source.c diff --git a/src/cairo-gl-spans-compositor.c b/src/cairo-gl-spans-compositor.c index 724ae6661..df337404e 100755..100644 --- a/src/cairo-gl-spans-compositor.c +++ b/src/cairo-gl-spans-compositor.c @@ -299,9 +299,6 @@ draw_image_boxes (void *_dst, struct _cairo_boxes_chunk *chunk; int i; - if (_cairo_gl_surface_is_texture (dst)) - return CAIRO_INT_STATUS_UNSUPPORTED; - for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { for (i = 0; i < chunk->count; i++) { cairo_box_t *b = &chunk->base[i]; diff --git a/src/cairo-gl-surface-legacy.c b/src/cairo-gl-surface-legacy.c index 92b27c905..92b27c905 100755..100644 --- a/src/cairo-gl-surface-legacy.c +++ b/src/cairo-gl-surface-legacy.c diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c index ac19a13ad..665ab244a 100755..100644 --- a/src/cairo-gl-surface.c +++ b/src/cairo-gl-surface.c @@ -76,7 +76,7 @@ _cairo_gl_surface_shadow_surface (void *surface, return NULL; shadow_surface = ctx->shadow_scratch_surfaces[0]; - + if (shadow_surface) { shadow_width = shadow_surface->width; shadow_height = shadow_surface->height; @@ -258,7 +258,7 @@ _cairo_gl_surface_glyph_shadow_surface (void *surface, shadow_surface = ctx->shadow_scratch_surfaces[1]; else shadow_surface = ctx->shadow_scratch_surfaces[2]; - + if (shadow_surface) { shadow_width = shadow_surface->width; shadow_height = shadow_surface->height; @@ -273,7 +273,7 @@ _cairo_gl_surface_glyph_shadow_surface (void *surface, if (! shadow_surface) { shadow_surface = (cairo_gl_surface_t *) _cairo_gl_surface_create_scratch (ctx, - CAIRO_CONTENT_COLOR_ALPHA, + CAIRO_CONTENT_COLOR_ALPHA, width, height); if (unlikely (shadow_surface->base.status)) { cairo_surface_destroy (&shadow_surface->base); @@ -309,10 +309,10 @@ _cairo_gl_surface_glyph_shadow_mask_surface (void *surface, return NULL; mask_surface = ctx->shadow_masks[index + 2]; - + if (mask_surface) { if (mask_surface->width != width || - mask_surface->height != height) { + mask_surface->height != height) { cairo_surface_destroy (&mask_surface->base); mask_surface = NULL; ctx->shadow_masks[index + 2] = NULL; @@ -542,6 +542,9 @@ _cairo_gl_get_image_format_and_type_gl (pixman_format_code_t pixman_format, *type = GL_UNSIGNED_BYTE; return TRUE; +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,27,2) + case PIXMAN_a8r8g8b8_sRGB: +#endif case PIXMAN_a2b10g10r10: case PIXMAN_x2b10g10r10: case PIXMAN_a4r4g4b4: @@ -690,17 +693,32 @@ _cairo_gl_surface_init (cairo_device_t *device, _cairo_gl_surface_embedded_operand_init (surface); } +static cairo_bool_t +_cairo_gl_surface_size_valid_for_context (cairo_gl_context_t *ctx, + int width, int height) +{ + return width > 0 && height > 0 && + width <= ctx->max_framebuffer_size && + height <= ctx->max_framebuffer_size; +} + +static cairo_bool_t +_cairo_gl_surface_size_valid (cairo_gl_surface_t *surface, + int width, int height) +{ + cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device; + return _cairo_gl_surface_size_valid_for_context (ctx, width, height); +} + static cairo_surface_t * _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t *ctx, cairo_content_t content, GLuint tex, int width, - int height, - cairo_bool_t set_tex_param) + int height) { cairo_gl_surface_t *surface; - assert (width <= ctx->max_framebuffer_size && height <= ctx->max_framebuffer_size); surface = calloc (1, sizeof (cairo_gl_surface_t)); if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); @@ -713,12 +731,10 @@ _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t *ctx, surface->supports_stencil = TRUE; /* Create the texture used to store the surface's data. */ - if (!set_tex_param) { _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP); ctx->dispatch.BindTexture (ctx->tex_target, surface->tex); ctx->dispatch.TexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); ctx->dispatch.TexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } return &surface->base; } @@ -737,7 +753,7 @@ _create_scratch_internal (cairo_gl_context_t *ctx, ctx->dispatch.GenTextures (1, &tex); surface = (cairo_gl_surface_t *) _cairo_gl_surface_create_scratch_for_texture (ctx, content, - tex, width, height, FALSE); + tex, width, height); if (unlikely (surface->base.status)) return &surface->base; @@ -753,7 +769,7 @@ _create_scratch_internal (cairo_gl_context_t *ctx, default: ASSERT_NOT_REACHED; case CAIRO_CONTENT_COLOR_ALPHA: - if (ctx->can_read_bgra) + if(ctx->can_read_bgra) format = GL_BGRA; else format = GL_RGBA; @@ -762,7 +778,7 @@ _create_scratch_internal (cairo_gl_context_t *ctx, /* When using GL_ALPHA, compositing doesn't work properly, but for * caching surfaces, we are just uploading pixel data, so it isn't * an issue. */ - if (for_caching) + if (for_caching && !ctx->is_gl33) format = GL_ALPHA; else format = GL_RGBA; @@ -776,7 +792,7 @@ _create_scratch_internal (cairo_gl_context_t *ctx, * specified. So, we have to store RGBA, and fill the alpha * channel with 1 when blending. */ - if (ctx->can_read_bgra) + if(ctx->can_read_bgra) format = GL_BGRA; else format = GL_RGBA; @@ -785,7 +801,7 @@ _create_scratch_internal (cairo_gl_context_t *ctx, ctx->dispatch.TexImage2D (ctx->tex_target, 0, format, width, height, 0, - format, GL_UNSIGNED_BYTE, NULL); + format, GL_UNSIGNED_BYTE, NULL); return &surface->base; } @@ -861,15 +877,14 @@ _cairo_gl_surface_clear (cairo_gl_surface_t *surface, } /* optimize for mobile gl driver with deferred rendering */ - if (surface->clip_on_stencil_buffer || - ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) + if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) ctx->dispatch.Clear (GL_COLOR_BUFFER_BIT); else { - if (surface->clip_on_stencil_buffer) { - _cairo_clip_destroy(surface->clip_on_stencil_buffer); - surface->clip_on_stencil_buffer = NULL; - } - ctx->dispatch.Clear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (surface->clip_on_stencil_buffer) { + _cairo_clip_destroy (surface->clip_on_stencil_buffer); + surface->clip_on_stencil_buffer = NULL; + } + ctx->dispatch.Clear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } if (a == 0) @@ -931,6 +946,11 @@ cairo_gl_surface_create (cairo_device_t *abstract_device, if (unlikely (status)) return _cairo_surface_create_in_error (status); + if (! _cairo_gl_surface_size_valid_for_context (ctx, width, height)) { + status = _cairo_gl_context_release (ctx, status); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + } + surface = (cairo_gl_surface_t *) _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height); if (unlikely (surface->base.status)) { @@ -1003,9 +1023,14 @@ cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device, if (unlikely (status)) return _cairo_surface_create_in_error (status); + if (! _cairo_gl_surface_size_valid_for_context (ctx, width, height)) { + status = _cairo_gl_context_release (ctx, status); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + } + surface = (cairo_gl_surface_t *) _cairo_gl_surface_create_scratch_for_texture (ctx, content, - tex, width, height, TRUE); + tex, width, height); status = _cairo_gl_context_release (ctx, status); return &surface->base; @@ -1090,7 +1115,6 @@ cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface) status = _cairo_gl_context_acquire (surface->base.device, &ctx); if (unlikely (status)) return; - /* And in any case we should flush any pending operations. */ _cairo_gl_composite_flush (ctx); @@ -1099,7 +1123,7 @@ cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface) ctx->swap_buffers (ctx, surface); - /* according to khronos specs on egl 1.4, stencil buffer is + /* according to khronos specs on egl 1.4, stencil buffer is * not preserved after eglSwapBuffers */ if (surface->clip_on_stencil_buffer) { _cairo_clip_destroy (surface->clip_on_stencil_buffer); @@ -1112,16 +1136,6 @@ cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface) } } -static cairo_bool_t -_cairo_gl_surface_size_valid (cairo_gl_surface_t *surface, - int width, int height) -{ - cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device; - return width > 0 && height > 0 && - width <= ctx->max_framebuffer_size && - height <= ctx->max_framebuffer_size; -} - static cairo_surface_t * _cairo_gl_surface_create_similar (void *abstract_surface, cairo_content_t content, @@ -1214,8 +1228,10 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, pixman_format = _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8; if (src->base.content != CAIRO_CONTENT_ALPHA) { - if (src->pixman_format != pixman_format) - require_conversion = TRUE; + if (src->pixman_format != pixman_format) { + if (!ctx->can_read_bgra) + require_conversion = TRUE; + } } else if (dst->base.content != CAIRO_CONTENT_ALPHA) require_conversion = TRUE; @@ -1227,6 +1243,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, } if (require_conversion) { + src->base.is_clear = FALSE; rgba_clone = (cairo_image_surface_t *) _cairo_image_surface_create_with_pixman_format (NULL, pixman_format, @@ -1246,7 +1263,32 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, src = rgba_clone; } - } + } else if (ctx->is_gl33 && src->base.content == CAIRO_CONTENT_ALPHA) { + /* use RGBA for ALPHA */ + pixman_format_code_t pixman_format; + cairo_surface_pattern_t pattern; + src->base.is_clear = FALSE; + pixman_format = _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8; + + rgba_clone = (cairo_image_surface_t *) + _cairo_image_surface_create_with_pixman_format (NULL, + pixman_format, + src->width, + src->height, + 0); + if (unlikely (rgba_clone->base.status)) + goto FAIL; + + _cairo_pattern_init_for_surface (&pattern, &src->base); + status = _cairo_surface_paint (&rgba_clone->base, + CAIRO_OPERATOR_SOURCE, + &pattern.base, NULL); + _cairo_pattern_fini (&pattern.base); + if (unlikely (status)) + goto FAIL; + + src = rgba_clone; + } if (! _cairo_gl_get_image_format_and_type (ctx->gl_flavor, src->pixman_format, @@ -1311,6 +1353,9 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, } else { + /* When cpp != 4, setting GL_UNPACK_ALIGNMENT to cpp + causes many failures in cairo tests with respect to + GLESV2 */ ctx->dispatch.PixelStorei (GL_UNPACK_ALIGNMENT, 4); if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP || ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) @@ -1320,18 +1365,18 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, /* we must resolve the renderbuffer to texture before we upload image */ status = _cairo_gl_surface_resolve_multisampling (dst); - if (unlikely (status)) { - free (data_start_gles2); - goto FAIL; - } + if (unlikely (status)) { + free (data_start_gles2); + goto FAIL; + } _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP); ctx->dispatch.BindTexture (ctx->tex_target, dst->tex); ctx->dispatch.TexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); ctx->dispatch.TexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); ctx->dispatch.TexSubImage2D (ctx->tex_target, 0, - dst_x, dst_y, width, height, - format, type, data_start); + dst_x, dst_y, width, height, + format, type, data_start); free (data_start_gles2); @@ -1498,8 +1543,8 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, return NULL; } - if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES2 || - _cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES3) { + /*if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES2 || + _cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES3)*/ { /* If only RGBA is supported, we must download data in a compatible * format. This means that pixman will convert the data on the CPU when * interacting with other image surfaces. For ALPHA, GLES2 does not @@ -1538,11 +1583,11 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, /* If the original surface has not been modified or * is clear, we can avoid downloading data. */ - if (surface->base.is_clear || surface->base.serial == 0) { +/* if (surface->base.is_clear || surface->base.serial == 0) { status = _cairo_gl_context_release (ctx, status); return image; } - +*/ /* This is inefficient, as we'd rather just read the thing without making * it the destination. But then, this is the fallback path, so let's not * fall back instead. @@ -1554,10 +1599,11 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, flipped = ! _cairo_gl_surface_is_texture (surface); mesa_invert = flipped && ctx->has_mesa_pack_invert; - ctx->dispatch.PixelStorei (GL_PACK_ALIGNMENT, 4); + ctx->dispatch.PixelStorei (GL_PACK_ALIGNMENT, cpp); if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP || ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) ctx->dispatch.PixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp); + if (mesa_invert) ctx->dispatch.PixelStorei (GL_PACK_INVERT_MESA, 1); @@ -1566,8 +1612,9 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, y = surface->height - extents->y - extents->height; ctx->dispatch.ReadPixels (extents->x, y, - extents->width, extents->height, - format, type, image->data); + extents->width, extents->height, + format, type, image->data); + if (mesa_invert) ctx->dispatch.PixelStorei (GL_PACK_INVERT_MESA, 0); @@ -1707,9 +1754,10 @@ _cairo_gl_surface_flush (void *abstract_surface, unsigned flags) _cairo_gl_composite_flush (ctx); status = _cairo_gl_surface_resolve_multisampling (surface); - +#if 0 if (ctx->msaa_type != CAIRO_GL_NONE_MULTISAMPLE_TO_TEXTURE) - ctx->dispatch.Flush (); + ctx->dispatch.Flush (); +#endif return _cairo_gl_context_release (ctx, status); } @@ -1772,7 +1820,7 @@ _cairo_gl_surface_paint (void *surface, &source->shadow); ctx->source_scratch_in_use = FALSE; if (unlikely (status)) { - cairo_device_release (dst->base.device); + cairo_device_release (dst->base.device); return status; } @@ -1781,13 +1829,12 @@ _cairo_gl_surface_paint (void *surface, dst->content_changed = TRUE; dst->content_synced = FALSE; } - + ctx->source_scratch_in_use = FALSE; cairo_device_release (dst->base.device); return status; } -#if 0 // Currently glClear does not get flushed to GPU so do not use this fast path for the time being /* simplify the common case of clearing the surface */ if (clip == NULL) { if (op == CAIRO_OPERATOR_CLEAR) { @@ -1800,11 +1847,10 @@ _cairo_gl_surface_paint (void *surface, (op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_opaque_solid (source)))) { status = _cairo_gl_surface_clear (surface, &((cairo_solid_pattern_t *) source)->color); - cairo_device_release (dst->base.device); + cairo_device_release (dst->base.device); return status; } } -#endif status = _cairo_compositor_paint (get_compositor (surface), surface, op, source, clip); @@ -1812,7 +1858,7 @@ _cairo_gl_surface_paint (void *surface, dst->content_changed = TRUE; dst->content_synced = FALSE; } - + ctx->source_scratch_in_use = FALSE; cairo_device_release (dst->base.device); return status; @@ -1837,7 +1883,7 @@ _cairo_gl_surface_mask (void *surface, &source->shadow); ctx->source_scratch_in_use = FALSE; if (unlikely (status)) { - cairo_device_release (dst->base.device); + cairo_device_release (dst->base.device); return status; } @@ -1845,8 +1891,8 @@ _cairo_gl_surface_mask (void *surface, if (status == CAIRO_INT_STATUS_SUCCESS) { dst->content_changed = TRUE; dst->content_synced = FALSE; - } - + } + ctx->source_scratch_in_use = FALSE; cairo_device_release (dst->base.device); return status; @@ -1857,7 +1903,7 @@ _cairo_gl_surface_mask (void *surface, if (status == CAIRO_INT_STATUS_SUCCESS) { dst->content_changed = TRUE; dst->content_synced = FALSE; - + ctx->source_scratch_in_use = FALSE; cairo_device_release (dst->base.device); return status; @@ -2016,7 +2062,6 @@ _cairo_gl_surface_fill (void *surface, ctx->source_scratch_in_use = FALSE; cairo_device_release (dst->base.device); - return status; } diff --git a/src/cairo-gl-traps-compositor.c b/src/cairo-gl-traps-compositor.c index 022a37d77..4e95e9a57 100755..100644 --- a/src/cairo-gl-traps-compositor.c +++ b/src/cairo-gl-traps-compositor.c @@ -84,9 +84,6 @@ draw_image_boxes (void *_dst, struct _cairo_boxes_chunk *chunk; int i; - if (_cairo_gl_surface_is_texture (dst)) - return CAIRO_INT_STATUS_UNSUPPORTED; - for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { for (i = 0; i < chunk->count; i++) { cairo_box_t *b = &chunk->base[i]; @@ -268,7 +265,6 @@ lerp (void *dst, 0, 0, dst_x, dst_y, width, height); - if (unlikely (status)) return status; @@ -284,27 +280,26 @@ lerp (void *dst, } static cairo_int_status_t -lerp_color_glyph (void *dst, - cairo_surface_t *src, - cairo_surface_t *mask, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height) +lerp_color_glyph (void *dst, + cairo_surface_t *src, + cairo_surface_t *mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) { - cairo_int_status_t status; + cairo_int_status_t status; - /*we could avoid some repetition... */ + /* we could avoid some repetition... */ status = composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, src, mask_x, mask_y, 0, 0, dst_x, dst_y, width, height); - if (unlikely (status)) return status; @@ -351,44 +346,12 @@ traps_to_operand (void *_dst, return status; } - /* GLES2 only supports RGB/RGBA when uploading */ -#if 0 - if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2) { - cairo_surface_pattern_t pattern; - cairo_surface_t *rgba_image; - - /* XXX perform this fixup inside _cairo_gl_draw_image() */ - - rgba_image = - _cairo_image_surface_create_with_pixman_format (NULL, - _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8, - extents->width, - extents->height, - 0); - if (unlikely (rgba_image->status)) { - cairo_surface_destroy (image); - return rgba_image->status; - } - - _cairo_pattern_init_for_surface (&pattern, image); - status = _cairo_surface_paint (rgba_image, CAIRO_OPERATOR_SOURCE, - &pattern.base, NULL); - _cairo_pattern_fini (&pattern.base); - - cairo_surface_destroy (image); - image = rgba_image; - - if (unlikely (status)) { - cairo_surface_destroy (image); - return status; - } - } -#endif - - mask = _cairo_surface_create_similar_scratch (_dst, - CAIRO_CONTENT_COLOR_ALPHA, - extents->width, - extents->height); + mask = _cairo_surface_create_scratch (_dst, + CAIRO_CONTENT_COLOR_ALPHA, + extents->width, + extents->height, + NULL); + if (unlikely (mask->status)) { cairo_surface_destroy (image); return mask->status; @@ -419,7 +382,7 @@ traps_to_operand (void *_dst, if (unlikely (status)) goto error; - operand->texture.owns_surface = mask; + operand->texture.owns_surface = (cairo_gl_surface_t *)mask; return CAIRO_STATUS_SUCCESS; error: @@ -442,42 +405,42 @@ composite_traps (void *_dst, cairo_gl_composite_t setup; cairo_gl_context_t *ctx; cairo_int_status_t status; - cairo_surface_t *src = (cairo_surface_t *) abstract_src; - cairo_surface_t *dst = (cairo_surface_t *) _dst; - cairo_surface_t *new_surface = NULL; - cairo_surface_t *new_src = (cairo_surface_t *) abstract_src; - int new_src_x, new_src_y; - cairo_surface_pattern_t new_surface_pattern; - - if (dst == src) { - new_surface = _cairo_surface_create_similar_scratch (src, - src->content, - extents->width, - extents->height); - status = new_surface->status; - if (unlikely (status)) { - cairo_surface_destroy (new_surface); - return status; - } + cairo_surface_t *src = (cairo_surface_t *) abstract_src; + cairo_surface_t *dst = (cairo_surface_t *) _dst; + cairo_surface_t *new_surface = NULL; + cairo_surface_t *new_src = (cairo_surface_t *) abstract_src; + int new_src_x, new_src_y; + cairo_surface_pattern_t new_surface_pattern; + + if (dst == src) { + new_surface = _cairo_surface_create_similar_scratch (src, + src->content, + extents->width, + extents->height); + status = new_surface->status; + if (unlikely (status)) { + cairo_surface_destroy (new_surface); + return status; + } _cairo_pattern_init_for_surface (&new_surface_pattern, src); new_surface_pattern.base.extend = CAIRO_EXTEND_NONE; new_surface_pattern.base.filter = CAIRO_FILTER_NEAREST; status = _cairo_surface_paint (new_surface, CAIRO_OPERATOR_SOURCE, - &new_surface_pattern.base, NULL); + &new_surface_pattern.base, NULL); if (unlikely (status)) { - _cairo_pattern_fini (&new_surface_pattern.base); - cairo_surface_destroy (new_surface); - return status; - } + _cairo_pattern_fini (&new_surface_pattern.base); + cairo_surface_destroy (new_surface); + return status; + } new_src = _cairo_gl_pattern_to_source (dst, - &new_surface_pattern.base, - FALSE, - extents, extents, - &new_src_x, &new_src_y); - } + &new_surface_pattern.base, + FALSE, + extents, extents, + &new_src_x, &new_src_y); + } status = _cairo_gl_composite_init (&setup, op, _dst, FALSE); if (unlikely (status)) @@ -485,9 +448,8 @@ composite_traps (void *_dst, _cairo_gl_composite_set_source_operand (&setup, source_to_operand (new_src)); - - if (src == new_src) - _cairo_gl_operand_translate (&setup.src, -src_x-dst_x, -src_y-dst_y); + if (src == new_src) + _cairo_gl_operand_translate (&setup.src, -src_x-dst_x, -src_y-dst_y); status = traps_to_operand (_dst, extents, antialias, traps, &setup.mask, dst_x, dst_y); if (unlikely (status)) goto FAIL; @@ -506,12 +468,12 @@ composite_traps (void *_dst, FAIL: _cairo_gl_composite_fini (&setup); - if (new_src != src) { - cairo_surface_destroy (new_src); - cairo_surface_destroy (new_surface); - _cairo_pattern_fini (&new_surface_pattern.base); - } - + if (new_src != src) { + cairo_surface_destroy (new_src); + cairo_surface_destroy (new_surface); + _cairo_pattern_fini (&new_surface_pattern.base); + } + return status; } @@ -542,10 +504,11 @@ tristrip_to_surface (void *_dst, return (cairo_gl_surface_t *)image; } - mask = _cairo_surface_create_similar_scratch (_dst, - CAIRO_CONTENT_COLOR_ALPHA, - extents->width, - extents->height); + mask = _cairo_surface_create_scratch (_dst, + CAIRO_CONTENT_COLOR_ALPHA, + extents->width, + extents->height, + NULL); if (unlikely (mask->status)) { cairo_surface_destroy (image); return (cairo_gl_surface_t *)mask; @@ -648,8 +611,8 @@ _cairo_gl_traps_compositor_get (void) compositor.check_composite = check_composite; compositor.composite = composite; compositor.lerp = lerp; - //FIXME: - compositor.lerp_color_glyph = lerp_color_glyph; + // FIXME: + compositor.lerp_color_glyph = lerp_color_glyph; //compositor.check_composite_boxes = check_composite_boxes; compositor.composite_boxes = composite_boxes; //compositor.check_composite_traps = check_composite_traps; diff --git a/src/cairo-gl.h b/src/cairo-gl.h index 69738a265..85a0ac69e 100755..100644 --- a/src/cairo-gl.h +++ b/src/cairo-gl.h @@ -130,6 +130,21 @@ cairo_gl_surface_create_for_dc (cairo_device_t *device, int height); #endif +#if CAIRO_HAS_CGL_FUNCTIONS +#include <OpenGL/OpenGL.h> + +cairo_public cairo_device_t * +cairo_cgl_device_create (CGLContextObj ctx); + +cairo_public cairo_surface_t * +cairo_gl_surface_create_for_cgl (cairo_device_t *device, + int width, + int height); + +cairo_public CGLContextObj +cairo_cgl_device_get_context (cairo_device_t *device); +#endif + #if CAIRO_HAS_EGL_FUNCTIONS #include <EGL/egl.h> diff --git a/src/cairo-glx-context.c b/src/cairo-glx-context.c index b4d706007..59e939292 100755..100644 --- a/src/cairo-glx-context.c +++ b/src/cairo-glx-context.c @@ -55,6 +55,7 @@ typedef struct _cairo_glx_context { GLXDrawable current_drawable; GLXContext previous_context; + GLXDrawable previous_drawable; cairo_bool_t has_multithread_makecurrent; } cairo_glx_context_t; @@ -68,7 +69,8 @@ typedef struct _cairo_glx_surface { static cairo_bool_t _context_acquisition_changed_glx_state (cairo_glx_context_t *ctx) { - return ctx->previous_context != ctx->context; + return ctx->previous_context != ctx->context || + ctx->previous_drawable != ctx->current_drawable; } static GLXDrawable @@ -86,6 +88,7 @@ static void * _glx_query_current_state (cairo_glx_context_t * ctx) { ctx->previous_context = glXGetCurrentContext (); + ctx->previous_drawable = glXGetCurrentDrawable (); } static void @@ -252,7 +255,7 @@ _cairo_glx_get_proc_address (void *data, const char *name) return func_map[i].func; } - return glXGetProcAddress (name); + return glXGetProcAddress (name); } cairo_device_t * diff --git a/src/cairo-gstate-private.h b/src/cairo-gstate-private.h index 92d3bb3c3..92d3bb3c3 100755..100644 --- a/src/cairo-gstate-private.h +++ b/src/cairo-gstate-private.h diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 84b47fe9a..c747b3fa8 100755..100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -975,7 +975,7 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate, surface = surface_pattern->surface; if (_cairo_surface_has_device_transform (surface)) - _cairo_pattern_transform (pattern, &surface->device_transform); + _cairo_pattern_pretransform (pattern, &surface->device_transform); } if (! _cairo_matrix_is_identity (ctm_inverse)) @@ -1087,7 +1087,7 @@ _cairo_gstate_paint (cairo_gstate_t *gstate) op = _reduce_op (gstate); /* do not use static pattern */ if (op == CAIRO_OPERATOR_CLEAR) { - if (! _cairo_gstate_has_shadow (gstate)) + if (! _cairo_gstate_has_shadow (gstate)) pattern = &_cairo_pattern_clear.base; else { pattern = cairo_pattern_create_rgba (0, 0, 0, 0); @@ -1219,6 +1219,8 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) cairo_stroke_style_t style; double dash[2]; cairo_status_t status; + cairo_matrix_t aggregate_transform; + cairo_matrix_t aggregate_transform_inverse; status = _cairo_gstate_get_pattern_status (gstate->source); if (unlikely (status)) @@ -1239,8 +1241,15 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) assert (gstate->opacity == 1.0); + cairo_matrix_multiply (&aggregate_transform, + &gstate->ctm, + &gstate->target->device_transform); + cairo_matrix_multiply (&aggregate_transform_inverse, + &gstate->target->device_transform_inverse, + &gstate->ctm_inverse); + memcpy (&style, &gstate->stroke_style, sizeof (gstate->stroke_style)); - if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance)) { + if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &aggregate_transform, gstate->tolerance)) { style.dash = dash; _cairo_stroke_style_dash_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance, &style.dash_offset, @@ -1259,8 +1268,8 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) &source_pattern.base, path, &style, - &gstate->ctm, - &gstate->ctm_inverse, + &aggregate_transform, + &aggregate_transform_inverse, gstate->tolerance, gstate->antialias, gstate->clip); @@ -1364,7 +1373,7 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) op = _reduce_op (gstate); /* FIXME: I don't like this */ if (op == CAIRO_OPERATOR_CLEAR) { - if (_cairo_gstate_has_shadow (gstate)) + if (_cairo_gstate_has_shadow (gstate)) pattern = &_cairo_pattern_clear.base; else { pattern = cairo_pattern_create_rgba (0, 0, 0, 0); @@ -1553,19 +1562,19 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate, } if (status == CAIRO_INT_STATUS_UNSUPPORTED) { - cairo_traps_t traps; - - _cairo_traps_init (&traps); - status = _cairo_path_fixed_stroke_polygon_to_traps (path, - &gstate->stroke_style, - &gstate->ctm, - &gstate->ctm_inverse, - gstate->tolerance, - &traps); - empty = traps.num_traps == 0; + cairo_polygon_t polygon; + + _cairo_polygon_init (&polygon, NULL, 0); + status = _cairo_path_fixed_stroke_to_polygon (path, + &gstate->stroke_style, + &gstate->ctm, + &gstate->ctm_inverse, + gstate->tolerance, + &polygon); + empty = polygon.num_edges == 0; if (! empty) - _cairo_traps_extents (&traps, &extents); - _cairo_traps_fini (&traps); + extents = polygon.extents; + _cairo_polygon_fini (&polygon); } if (! empty) { _cairo_gstate_extents_to_user_rectangle (gstate, &extents, @@ -1924,6 +1933,7 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate) cairo_status_t status; cairo_font_options_t options; cairo_scaled_font_t *scaled_font; + cairo_matrix_t font_ctm; if (gstate->scaled_font != NULL) return gstate->scaled_font->status; @@ -1935,9 +1945,13 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate) cairo_surface_get_font_options (gstate->target, &options); cairo_font_options_merge (&options, &gstate->font_options); + cairo_matrix_multiply (&font_ctm, + &gstate->ctm, + &gstate->target->device_transform); + scaled_font = cairo_scaled_font_create (gstate->font_face, &gstate->font_matrix, - &gstate->ctm, + &font_ctm, &options); status = cairo_scaled_font_status (scaled_font); @@ -2094,6 +2108,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, if (cairo_surface_has_show_text_glyphs (gstate->target) || _cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240) { + if (info != NULL) { status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern, info->utf8, info->utf8_len, diff --git a/src/cairo-hash-private.h b/src/cairo-hash-private.h index 30e51ffe6..30e51ffe6 100755..100644 --- a/src/cairo-hash-private.h +++ b/src/cairo-hash-private.h diff --git a/src/cairo-hash.c b/src/cairo-hash.c index 928c74b8b..928c74b8b 100755..100644 --- a/src/cairo-hash.c +++ b/src/cairo-hash.c diff --git a/src/cairo-hull.c b/src/cairo-hull.c index c65593327..c65593327 100755..100644 --- a/src/cairo-hull.c +++ b/src/cairo-hull.c diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c index a732f2a3a..18a44fb8c 100755..100644 --- a/src/cairo-image-compositor.c +++ b/src/cairo-image-compositor.c @@ -52,9 +52,7 @@ #include "cairo-traps-private.h" #include "cairo-tristrip-private.h" -#if CAIRO_HAS_TG_SURFACE -#include "cairo-thread-local-private.h" -#endif +#include "cairo-pixman-private.h" static pixman_image_t * to_pixman_image (cairo_surface_t *s) @@ -260,9 +258,9 @@ _pixman_operator (cairo_operator_t op) } static cairo_bool_t -fill_reduces_to_source (cairo_operator_t op, - const cairo_color_t *color, - cairo_image_surface_t *dst) +__fill_reduces_to_source (cairo_operator_t op, + const cairo_color_t *color, + const cairo_image_surface_t *dst) { if (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_CLEAR) return TRUE; @@ -274,6 +272,19 @@ fill_reduces_to_source (cairo_operator_t op, return FALSE; } +static cairo_bool_t +fill_reduces_to_source (cairo_operator_t op, + const cairo_color_t *color, + const cairo_image_surface_t *dst, + uint32_t *pixel) +{ + if (__fill_reduces_to_source (op, color, dst)) { + return color_to_pixel (color, dst->pixman_format, pixel); + } + + return FALSE; +} + static cairo_int_status_t fill_rectangles (void *_dst, cairo_operator_t op, @@ -287,9 +298,7 @@ fill_rectangles (void *_dst, TRACE ((stderr, "%s\n", __FUNCTION__)); - if (fill_reduces_to_source (op, color, dst) && - color_to_pixel (color, dst->pixman_format, &pixel)) - { + if (fill_reduces_to_source (op, color, dst, &pixel)) { for (i = 0; i < num_rects; i++) { pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t), PIXMAN_FORMAT_BPP (dst->pixman_format), @@ -297,12 +306,10 @@ fill_rectangles (void *_dst, rects[i].width, rects[i].height, pixel); } - } - else - { + } else { pixman_image_t *src = _pixman_image_for_color (color); - if (src == NULL) - return CAIRO_STATUS_NULL_POINTER; + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); op = _pixman_operator (op); for (i = 0; i < num_rects; i++) { @@ -333,9 +340,7 @@ fill_boxes (void *_dst, TRACE ((stderr, "%s x %d\n", __FUNCTION__, boxes->num_boxes)); - if (fill_reduces_to_source (op, color, dst) && - color_to_pixel (color, dst->pixman_format, &pixel)) - { + if (fill_reduces_to_source (op, color, dst, &pixel)) { for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { for (i = 0; i < chunk->count; i++) { int x = _cairo_fixed_integer_part (chunk->base[i].p1.x); @@ -352,8 +357,8 @@ fill_boxes (void *_dst, else { pixman_image_t *src = _pixman_image_for_color (color); - if (src == NULL) - return CAIRO_STATUS_NULL_POINTER; + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); op = _pixman_operator (op); for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { @@ -472,49 +477,49 @@ lerp (void *_dst, } static cairo_int_status_t -lerp_color_glyph (void *_dst, - cairo_surface_t *abstract_src, - cairo_surface_t *abstract_mask, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height) -{ - cairo_image_surface_t *dst = _dst; - cairo_image_source_t *src = (cairo_image_source_t *)abstract_src; - cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask; - - TRACE ((stderr, "%s\n", __FUNCTION__)); - - /* Punch the clip out of the destination */ - TRACE ((stderr, "%s - OUT_REVERSE (mask=%d/%p, dst=%d/%p)\n", - __FUNCTION__, - mask->base.unique_id, mask->pixman_image, - dst->base.unique_id, dst->pixman_image)); - pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, - mask->pixman_image, src->pixman_image, dst->pixman_image, - mask_x, mask_y, - 0, 0, - dst_x, dst_y, - width, height); - - /* Now add the two results together */ - TRACE ((stderr, "%s - ADD (src=%d/%p, mask=%d/%p, dst=%d/%p)\n", - __FUNCTION__, - src->base.unique_id, src->pixman_image, - mask->base.unique_id, mask->pixman_image, - dst->base.unique_id, dst->pixman_image)); - pixman_image_composite32 (PIXMAN_OP_ADD, - src->pixman_image, mask->pixman_image, dst->pixman_image, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); - return CAIRO_STATUS_SUCCESS; +lerp_color_glyph (void *_dst, + cairo_surface_t *abstract_src, + cairo_surface_t *abstract_mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_image_surface_t *dst = _dst; + cairo_image_source_t *src = (cairo_image_source_t *)abstract_src; + cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + /* Punch the clip out of the destination */ + TRACE ((stderr, "%s - OUT_REVERSE (mask=%d/%p, dst=%d/%p)\n", + __FUNCTION__, + mask->base.unique_id, mask->pixman_image, + dst->base.unique_id, dst->pixman_image)); + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + mask->pixman_image, src->pixman_image, dst->pixman_image, + mask_x, mask_y, + 0, 0, + dst_x, dst_y, + width, height); + + /* Now add the two results together */ + TRACE ((stderr, "%s - ADD (src=%d/%p, mask=%d/%p, dst=%d/%p)\n", + __FUNCTION__, + src->base.unique_id, src->pixman_image, + mask->base.unique_id, mask->pixman_image, + dst->base.unique_id, dst->pixman_image)); + pixman_image_composite32 (PIXMAN_OP_ADD, + src->pixman_image, mask->pixman_image, dst->pixman_image, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t @@ -552,9 +557,8 @@ composite_boxes (void *_dst, op = PIXMAN_OP_LERP_CLEAR; #else free_src = src = _pixman_image_for_color (CAIRO_COLOR_WHITE); - if (src == NULL) - return CAIRO_STATUS_NULL_POINTER; - + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); op = PIXMAN_OP_OUT_REVERSE; #endif } else if (op == CAIRO_OPERATOR_SOURCE) { @@ -691,11 +695,18 @@ composite_traps (void *_dst, { cairo_image_surface_t *dst = (cairo_image_surface_t *) _dst; cairo_image_source_t *src = (cairo_image_source_t *) abstract_src; + cairo_int_status_t status; pixman_image_t *mask; pixman_format_code_t format; TRACE ((stderr, "%s\n", __FUNCTION__)); + /* pixman doesn't eliminate self-intersecting trapezoids/edges */ + status = _cairo_bentley_ottmann_tessellate_traps (traps, + CAIRO_FILL_RULE_WINDING); + if (status != CAIRO_INT_STATUS_SUCCESS) + return status; + /* Special case adding trapezoids onto a mask surface; we want to avoid * creating an intermediate temporary mask unnecessarily. * @@ -731,6 +742,7 @@ composite_traps (void *_dst, return CAIRO_STATUS_SUCCESS; } +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,22,0) static void set_point (pixman_point_fixed_t *p, cairo_point_t *c) { @@ -779,6 +791,31 @@ composite_tristrip (void *_dst, if (strip->num_points < 3) return CAIRO_STATUS_SUCCESS; + if (1) { /* pixman doesn't eliminate self-intersecting triangles/edges */ + cairo_int_status_t status; + cairo_traps_t traps; + int n; + + _cairo_traps_init (&traps); + for (n = 0; n < strip->num_points; n++) { + cairo_point_t p[4]; + + p[0] = strip->points[0]; + p[1] = strip->points[1]; + p[2] = strip->points[2]; + p[3] = strip->points[0]; + + _cairo_traps_tessellate_convex_quad (&traps, p); + } + status = composite_traps (_dst, op, abstract_src, + src_x, src_y, + dst_x, dst_y, + extents, antialias, &traps); + _cairo_traps_fini (&traps); + + return status; + } + format = antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8; if (dst->pixman_format == format && (abstract_src == NULL || @@ -806,6 +843,7 @@ composite_tristrip (void *_dst, return CAIRO_STATUS_SUCCESS; } +#endif static cairo_int_status_t check_composite_glyphs (const cairo_composite_rectangles_t *extents, @@ -817,51 +855,30 @@ check_composite_glyphs (const cairo_composite_rectangles_t *extents, } #if 0 && HAS_PIXMAN_GLYPHS -#if CAIRO_HAS_TG_SURFACE -CAIRO_DEFINE_THREAD_LOCAL (pixman_glyph_cache_t *, per_thread_glyph_cache); -#else static pixman_glyph_cache_t *global_glyph_cache; -#endif static inline pixman_glyph_cache_t * get_glyph_cache (void) { - pixman_glyph_cache_t **glyph_cache = NULL; + if (!global_glyph_cache) + global_glyph_cache = pixman_glyph_cache_create (); -#if CAIRO_HAS_TG_SURFACE - glyph_cache = CAIRO_GET_THREAD_LOCAL (per_thread_glyph_cache); -#else - glyph_cache = &global_glyph_cache; -#endif - - if (! (*glyph_cache)) - *glyph_cache = pixman_glyph_cache_create (); - - return *glyph_cache; + return global_glyph_cache; } void _cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph) { - pixman_glyph_cache_t *glyph_cache = NULL; - -#if CAIRO_HAS_TG_SURFACE - glyph_cache = *CAIRO_GET_THREAD_LOCAL (per_thread_glyph_cache); -#else - glyph_cache = global_glyph_cache; CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex); -#endif - if (glyph_cache) { + if (global_glyph_cache) { pixman_glyph_cache_remove ( - glyph_cache, scaled_font, + global_glyph_cache, scaled_font, (void *)_cairo_scaled_glyph_index (scaled_glyph)); } -#if ! CAIRO_HAS_TG_SURFACE CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex); -#endif } static cairo_int_status_t @@ -883,9 +900,7 @@ composite_glyphs (void *_dst, TRACE ((stderr, "%s\n", __FUNCTION__)); -#if ! CAIRO_HAS_TG_SURFACE CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex); -#endif glyph_cache = get_glyph_cache(); if (unlikely (glyph_cache == NULL)) { @@ -913,43 +928,23 @@ composite_glyphs (void *_dst, cairo_scaled_glyph_t *scaled_glyph; cairo_image_surface_t *glyph_surface; -#if ! CAIRO_HAS_TG_SURFACE /* This call can actually end up recursing, so we have to * drop the mutex around it. */ CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex); -#else - _cairo_scaled_font_freeze_cache (info->font); - CAIRO_MUTEX_LOCK (_cairo_tg_scaled_glyph_mutex); -#endif - status = _cairo_scaled_glyph_lookup (info->font, index, CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); - -#if ! CAIRO_HAS_TG_SURFACE CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex); -#endif - if (unlikely (status)) { -#if CAIRO_HAS_TG_SURFACE - CAIRO_MUTEX_UNLOCK (_cairo_tg_scaled_glyph_mutex); - _cairo_scaled_font_thaw_cache (info->font); -#endif + if (unlikely (status)) goto out_thaw; - } glyph_surface = scaled_glyph->surface; glyph = pixman_glyph_cache_insert (glyph_cache, info->font, (void *)index, glyph_surface->base.device_transform.x0, glyph_surface->base.device_transform.y0, glyph_surface->pixman_image); - -#if CAIRO_HAS_TG_SURFACE - CAIRO_MUTEX_UNLOCK (_cairo_tg_scaled_glyph_mutex); - _cairo_scaled_font_thaw_cache (info->font); -#endif - if (unlikely (!glyph)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto out_thaw; @@ -992,10 +987,7 @@ out_thaw: free(pglyphs); out_unlock: -#if ! CAIRO_HAS_TG_SURFACE CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex); -#endif - return status; } #else @@ -1015,7 +1007,7 @@ composite_one_glyph (void *_dst, int dst_y, cairo_composite_glyphs_info_t *info) { - cairo_image_surface_t *dst_surface = (cairo_image_surface_t *)_dst; + cairo_image_surface_t *dst_surface = (cairo_image_surface_t *)_dst; cairo_image_surface_t *glyph_surface; cairo_scaled_glyph_t *scaled_glyph; cairo_status_t status; @@ -1035,11 +1027,11 @@ composite_one_glyph (void *_dst, if (glyph_surface->width == 0 || glyph_surface->height == 0) return CAIRO_INT_STATUS_NOTHING_TO_DO; - if (glyph_surface->format == CAIRO_FORMAT_ARGB32 && - dst_surface->format != CAIRO_FORMAT_ARGB32) { + if (glyph_surface->format == CAIRO_FORMAT_ARGB32 && + dst_surface->format != CAIRO_FORMAT_ARGB32) { /* FIXME: color glyph */ return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; - } + } /* round glyph locations to the nearest pixel */ /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ @@ -1048,28 +1040,27 @@ composite_one_glyph (void *_dst, y = _cairo_lround (info->glyphs[0].y - glyph_surface->base.device_transform.y0); - - if (glyph_surface->format != CAIRO_FORMAT_ARGB32 || - pixman_image_get_component_alpha (glyph_surface->pixman_image)) - pixman_image_composite32 (_pixman_operator (op), - ((cairo_image_source_t *)_src)->pixman_image, - glyph_surface->pixman_image, - to_pixman_image (_dst), - x + src_x, y + src_y, - 0, 0, - x - dst_x, y - dst_y, - glyph_surface->width, - glyph_surface->height); - else /* color glyph */ - pixman_image_composite32 (_pixman_operator (op), - glyph_surface->pixman_image, - NULL, - to_pixman_image (_dst), - 0, 0, - x + src_x, y + src_y, - x - dst_x, y - dst_y, - glyph_surface->width, - glyph_surface->height); + if (glyph_surface->format != CAIRO_FORMAT_ARGB32 || + pixman_image_get_component_alpha (glyph_surface->pixman_image)) + pixman_image_composite32 (_pixman_operator (op), + ((cairo_image_source_t *)_src)->pixman_image, + glyph_surface->pixman_image, + to_pixman_image (_dst), + x + src_x, y + src_y, + 0, 0, + x - dst_x, y - dst_y, + glyph_surface->width, + glyph_surface->height); + else /* color glyph */ + pixman_image_composite32 (_pixman_operator (op), + glyph_surface->pixman_image, + NULL, + to_pixman_image (_dst), + 0, 0, + x + src_x, y + src_y, + x - dst_x, y - dst_y, + glyph_surface->width, + glyph_surface->height); return CAIRO_INT_STATUS_SUCCESS; } @@ -1092,7 +1083,7 @@ composite_glyphs_via_mask (void *_dst, pixman_format_code_t format; cairo_status_t status; int i; - cairo_bool_t component_alpha = FALSE; + cairo_bool_t component_alpha = FALSE; TRACE ((stderr, "%s\n", __FUNCTION__)); @@ -1167,7 +1158,7 @@ composite_glyphs_via_mask (void *_dst, glyph_surface = scaled_glyph->surface; if (! component_alpha) - component_alpha = pixman_image_get_component_alpha (glyph_surface->pixman_image); + component_alpha = pixman_image_get_component_alpha (glyph_surface->pixman_image); if (glyph_surface->width && glyph_surface->height) { if (glyph_surface->base.content & CAIRO_CONTENT_COLOR && format == PIXMAN_a8) { @@ -1225,22 +1216,22 @@ composite_glyphs_via_mask (void *_dst, if (format == PIXMAN_a8r8g8b8 && component_alpha) pixman_image_set_component_alpha (mask, TRUE); - if (format != PIXMAN_a8r8g8b8 || component_alpha) - pixman_image_composite32 (_pixman_operator (op), - ((cairo_image_source_t *)_src)->pixman_image, - mask, - to_pixman_image (_dst), - info->extents.x + src_x, info->extents.y + src_y, - 0, 0, - info->extents.x - dst_x, info->extents.y - dst_y, - info->extents.width, info->extents.height); - else /* color glyph */ - pixman_image_composite32 (_pixman_operator (op), mask, NULL, - to_pixman_image (_dst), - 0, 0, - info->extents.x + src_x, info->extents.y + src_y, - info->extents.x - dst_x, info->extents.y - dst_y, - info->extents.width, info->extents.height); + if (format != PIXMAN_a8r8g8b8 || component_alpha) + pixman_image_composite32 (_pixman_operator (op), + ((cairo_image_source_t *)_src)->pixman_image, + mask, + to_pixman_image (_dst), + info->extents.x + src_x, info->extents.y + src_y, + 0, 0, + info->extents.x - dst_x, info->extents.y - dst_y, + info->extents.width, info->extents.height); + else /* color glyph */ + pixman_image_composite32 (_pixman_operator (op), mask, NULL, + to_pixman_image (_dst), + 0, 0, + info->extents.x + src_x, info->extents.y + src_y, + info->extents.x - dst_x, info->extents.y - dst_y, + info->extents.width, info->extents.height); pixman_image_unref (mask); pixman_image_unref (white); @@ -1261,24 +1252,17 @@ composite_glyphs (void *_dst, pixman_image_t *dst, *src; cairo_status_t status; int i; - cairo_image_surface_t *dst_surface = (cairo_image_surface_t *)_dst; + cairo_image_surface_t *dst_surface = (cairo_image_surface_t *)_dst; TRACE ((stderr, "%s\n", __FUNCTION__)); -#if CAIRO_HAS_TG_SURFACE - _cairo_scaled_font_freeze_cache (info->font); - CAIRO_MUTEX_LOCK (_cairo_tg_scaled_glyph_mutex); -#endif + /* XXX */ + if (0 && info->num_glyphs == 1) + return composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info); - if (0 && info->num_glyphs == 1) { - status = composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info); - goto out_thaw; - } - - if (0 && info->use_mask) { - status = composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info); - goto out_thaw; - } + /* XXX */ + if (info->use_mask) + return composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info); op = _pixman_operator (op); dst = to_pixman_image (_dst); @@ -1310,9 +1294,9 @@ composite_glyphs (void *_dst, glyph_surface = scaled_glyph->surface; if (glyph_surface->format == CAIRO_FORMAT_ARGB32 && - dst_surface->format != CAIRO_FORMAT_ARGB32) { - /* FIXME: color glyph */ - return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; + dst_surface->format != CAIRO_FORMAT_ARGB32) { + /* FIXME: color glyph */ + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; } if (glyph_surface->width && glyph_surface->height) { @@ -1323,30 +1307,24 @@ composite_glyphs (void *_dst, y = _cairo_lround (info->glyphs[i].y - glyph_surface->base.device_transform.y0); - if (glyph_surface->format != CAIRO_FORMAT_ARGB32 || + if (glyph_surface->format != CAIRO_FORMAT_ARGB32 || pixman_image_get_component_alpha (glyph_surface->pixman_image)) - pixman_image_composite32 (op, src, glyph_surface->pixman_image, dst, - x + src_x, y + src_y, - 0, 0, - x - dst_x, y - dst_y, - glyph_surface->width, - glyph_surface->height); - else /* Color glyph. */ - pixman_image_composite32 (op, glyph_surface->pixman_image, NULL, dst, - 0, 0, - x + src_x, y + src_y, - x - dst_x, y - dst_y, - glyph_surface->width, - glyph_surface->height); - } + pixman_image_composite32 (op, src, glyph_surface->pixman_image, dst, + x + src_x, y + src_y, + 0, 0, + x - dst_x, y - dst_y, + glyph_surface->width, + glyph_surface->height); + else /* Color glyph. */ + pixman_image_composite32 (op, glyph_surface->pixman_image, NULL, dst, + 0, 0, + x + src_x, y + src_y, + x - dst_x, y - dst_y, + glyph_surface->width, + glyph_surface->height); + } } -out_thaw: -#if CAIRO_HAS_TG_SURFACE - _cairo_scaled_font_thaw_cache (info->font); - CAIRO_MUTEX_UNLOCK (_cairo_tg_scaled_glyph_mutex); -#endif - return status; } #endif @@ -1381,7 +1359,9 @@ _cairo_image_traps_compositor_get (void) //compositor.check_composite_traps = check_composite_traps; compositor.composite_traps = composite_traps; //compositor.check_composite_tristrip = check_composite_traps; +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,22,0) compositor.composite_tristrip = composite_tristrip; +#endif compositor.check_composite_glyphs = check_composite_glyphs; compositor.composite_glyphs = composite_glyphs; } @@ -1404,9 +1384,10 @@ _cairo_image_mask_compositor_get (void) compositor.draw_image_boxes = draw_image_boxes; compositor.fill_rectangles = fill_rectangles; compositor.fill_boxes = fill_boxes; - //compositor.check_composite = check_composite; + compositor.check_composite = check_composite; compositor.composite = composite; //compositor.lerp = lerp; + //compositor.lerp_color_glyph = lerp_color_glyph; //compositor.check_composite_boxes = check_composite_boxes; compositor.composite_boxes = composite_boxes; compositor.check_composite_glyphs = check_composite_glyphs; @@ -1714,7 +1695,7 @@ typedef struct _cairo_image_span_renderer { } mask; } u; uint8_t _buf[0]; -#define SZ_BUF (sizeof (cairo_abstract_span_renderer_t) - sizeof (cairo_image_span_renderer_t)) +#define SZ_BUF (int)(sizeof (cairo_abstract_span_renderer_t) - sizeof (cairo_image_span_renderer_t)) } cairo_image_span_renderer_t; COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t)); @@ -2184,8 +2165,7 @@ mono_renderer_init (cairo_image_span_renderer_t *r, if (composite->op == CAIRO_OPERATOR_CLEAR) color = CAIRO_COLOR_TRANSPARENT; - if (fill_reduces_to_source (composite->op, color, dst) && - color_to_pixel (color, dst->pixman_format, &r->u.fill.pixel)) { + if (fill_reduces_to_source (composite->op, color, dst, &r->u.fill.pixel)) { /* Use plain C for the fill operations as the span length is * typically small, too small to payback the startup overheads of * using SSE2 etc. @@ -2366,10 +2346,10 @@ _fill_xrgb32_lerp_opaque_spans (void *abstract_renderer, int y, int h, spans[0].x, y, len, 1, r->u.fill.pixel); } else { uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4); - while (len--) + while (len-- > 0) *d++ = r->u.fill.pixel; } - } else while (len--) { + } else while (len-- > 0) { *d = lerp8x4 (r->u.fill.pixel, a, *d); d++; } @@ -2943,8 +2923,7 @@ inplace_renderer_init (cairo_image_span_renderer_t *r, if (composite->op == CAIRO_OPERATOR_CLEAR) color = CAIRO_COLOR_TRANSPARENT; - if (fill_reduces_to_source (composite->op, color, dst) && - color_to_pixel (color, dst->pixman_format, &r->u.fill.pixel)) { + if (fill_reduces_to_source (composite->op, color, dst, &r->u.fill.pixel)) { /* Use plain C for the fill operations as the span length is * typically small, too small to payback the startup overheads of * using SSE2 etc. @@ -3181,7 +3160,7 @@ span_renderer_init (cairo_abstract_span_renderer_t *_r, r->u.mask.extents = composite->unbounded; r->u.mask.stride = (r->u.mask.extents.width + 3) & ~3; - if (r->u.mask.extents.height * r->u.mask.stride > (int)sizeof (r->_buf)) { + if (r->u.mask.extents.height * r->u.mask.stride > SZ_BUF) { r->mask = pixman_image_create_bits (PIXMAN_a8, r->u.mask.extents.width, r->u.mask.extents.height, @@ -3217,12 +3196,11 @@ span_renderer_fini (cairo_abstract_span_renderer_t *_r, TRACE ((stderr, "%s\n", __FUNCTION__)); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { - if (r->base.finish) + if (r->base.finish) r->base.finish (r); } - if (likely (status == CAIRO_INT_STATUS_SUCCESS && r->bpp == 0)) { - const cairo_composite_rectangles_t *composite = r->composite; + const cairo_composite_rectangles_t *composite = r->composite; pixman_image_composite32 (r->op, r->src, r->mask, to_pixman_image (composite->surface), diff --git a/src/cairo-image-filters-private.h b/src/cairo-image-filters-private.h index a9e47f0b3..2761c7b29 100755..100644 --- a/src/cairo-image-filters-private.h +++ b/src/cairo-image-filters-private.h @@ -49,8 +49,8 @@ #define MAX_BLUR_SIZE 256 -cairo_private cairo_surface_t * -_cairo_image_gaussian_filter (cairo_surface_t *src, +cairo_private cairo_surface_t * +_cairo_image_gaussian_filter (cairo_surface_t *src, const cairo_pattern_t *pattern); #endif /* CAIRO_IMAGE_FILTERS_PRIVATE_H */ diff --git a/src/cairo-image-filters.c b/src/cairo-image-filters.c index 1f0531ef2..1216b7931 100755..100644 --- a/src/cairo-image-filters.c +++ b/src/cairo-image-filters.c @@ -106,7 +106,7 @@ _pixman_image_create_convolution_params (double *params, return pixman_params; } -cairo_surface_t * +cairo_surface_t * _cairo_image_gaussian_filter (cairo_surface_t *src, const cairo_pattern_t *pattern) { int row, col; @@ -139,10 +139,10 @@ _cairo_image_gaussian_filter (cairo_surface_t *src, const cairo_pattern_t *patt row = pattern->y_radius * 2 + 1; col = pattern->x_radius * 2 + 1; - width = src_width / pattern->shrink_factor_x; - height = src_height / pattern->shrink_factor_y; + width = src_width / pattern->shrink_factor_x; + height = src_height / pattern->shrink_factor_y; stride = width * (src_image->stride / src_width); - + clone_image = (cairo_image_surface_t *) cairo_image_surface_create (src_image->format, src_width, src_height); @@ -152,7 +152,7 @@ _cairo_image_gaussian_filter (cairo_surface_t *src, const cairo_pattern_t *patt clone_image = (cairo_image_surface_t *)cairo_surface_reference (src); goto DONE; } - + /* XXX: we must always create a clone because we need to modify * it transformation, no copy data */ temp_image = pixman_image_create_bits (src_image->pixman_format, @@ -165,7 +165,7 @@ _cairo_image_gaussian_filter (cairo_surface_t *src, const cairo_pattern_t *patt clone_image = (cairo_image_surface_t *)cairo_surface_reference (src); goto DONE; } - + /* create scratch images */ for (i = 0; i < 2; i++) { scratch_images[i] = pixman_image_create_bits (src_image->pixman_format, @@ -183,7 +183,7 @@ _cairo_image_gaussian_filter (cairo_surface_t *src, const cairo_pattern_t *patt if (width != src_width || height != src_height) { pixman_image_set_filter (temp_image, PIXMAN_FILTER_NEAREST, NULL, 0); /* set up transform matrix */ - cairo_matrix_init_scale (&matrix, + cairo_matrix_init_scale (&matrix, (double) src_width / (double) width, (double) src_height / (double) height); status = _cairo_matrix_to_pixman_matrix_offset (&matrix, @@ -264,7 +264,7 @@ _cairo_image_gaussian_filter (cairo_surface_t *src, const cairo_pattern_t *patt /* paint scratch_surfaces[0] to clone */ /* set up transform matrix */ - cairo_matrix_init_scale (&matrix, + cairo_matrix_init_scale (&matrix, (double) width / (double) src_width, (double) height / (double) src_height); status = _cairo_matrix_to_pixman_matrix_offset (&matrix, diff --git a/src/cairo-image-info-private.h b/src/cairo-image-info-private.h index 0d9ef8498..e64928e40 100755..100644 --- a/src/cairo-image-info-private.h +++ b/src/cairo-image-info-private.h @@ -60,4 +60,9 @@ _cairo_image_info_get_png_info (cairo_image_info_t *info, const unsigned char *data, unsigned long length); +cairo_private cairo_int_status_t +_cairo_image_info_get_jbig2_info (cairo_image_info_t *info, + const unsigned char *data, + unsigned long length); + #endif /* CAIRO_IMAGE_INFO_PRIVATE_H */ diff --git a/src/cairo-image-info.c b/src/cairo-image-info.c index 4489698e8..26e7ae5af 100755..100644 --- a/src/cairo-image-info.c +++ b/src/cairo-image-info.c @@ -1,3 +1,4 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ /* cairo - a vector graphics library with display and print output * * Copyright © 2008 Adrian Johnson @@ -38,12 +39,6 @@ #include "cairo-error-private.h" #include "cairo-image-info-private.h" -static uint32_t -_get_be32 (const unsigned char *p) -{ - return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; -} - /* JPEG (image/jpeg) * * http://www.w3.org/Graphics/JPEG/itu-t81.pdf @@ -169,7 +164,7 @@ static const unsigned char _jpx_signature[] = { static const unsigned char * _jpx_next_box (const unsigned char *p) { - return p + _get_be32 (p); + return p + get_unaligned_be32 (p); } static const unsigned char * @@ -184,8 +179,8 @@ _jpx_match_box (const unsigned char *p, const unsigned char *end, uint32_t type) uint32_t length; if (p + 8 < end) { - length = _get_be32 (p); - if (_get_be32 (p + 4) == type && p + length < end) + length = get_unaligned_be32 (p); + if (get_unaligned_be32 (p + 4) == type && p + length < end) return TRUE; } @@ -207,8 +202,8 @@ _jpx_find_box (const unsigned char *p, const unsigned char *end, uint32_t type) static void _jpx_extract_info (const unsigned char *p, cairo_image_info_t *info) { - info->height = _get_be32 (p); - info->width = _get_be32 (p + 4); + info->height = get_unaligned_be32 (p); + info->width = get_unaligned_be32 (p + 4); info->num_components = (p[8] << 8) + p[9]; info->bits_per_component = p[10]; } @@ -280,13 +275,147 @@ _cairo_image_info_get_png_info (cairo_image_info_t *info, return CAIRO_INT_STATUS_UNSUPPORTED; p += 4; - if (_get_be32 (p) != PNG_IHDR) + if (get_unaligned_be32 (p) != PNG_IHDR) return CAIRO_INT_STATUS_UNSUPPORTED; p += 4; - info->width = _get_be32 (p); + info->width = get_unaligned_be32 (p); p += 4; - info->height = _get_be32 (p); + info->height = get_unaligned_be32 (p); return CAIRO_STATUS_SUCCESS; } + +static const unsigned char * +_jbig2_find_data_end (const unsigned char *p, + const unsigned char *end, + int type) +{ + unsigned char end_seq[2]; + int mmr; + + /* Segments of type "Immediate generic region" may have an + * unspecified data length. The JBIG2 specification specifies the + * method to find the end of the data for these segments. */ + if (type == 36 || type == 38 || type == 39) { + if (p + 18 < end) { + mmr = p[17] & 0x01; + if (mmr) { + /* MMR encoding ends with 0x00, 0x00 */ + end_seq[0] = 0x00; + end_seq[1] = 0x00; + } else { + /* Template encoding ends with 0xff, 0xac */ + end_seq[0] = 0xff; + end_seq[1] = 0xac; + } + p += 18; + while (p < end) { + if (p[0] == end_seq[0] && p[1] == end_seq[1]) { + /* Skip the 2 terminating bytes and the 4 byte row count that follows. */ + p += 6; + if (p < end) + return p; + } + p++; + } + } + } + + return NULL; +} + +static const unsigned char * +_jbig2_get_next_segment (const unsigned char *p, + const unsigned char *end, + int *type, + const unsigned char **data, + unsigned long *data_len) +{ + unsigned long seg_num; + cairo_bool_t big_page_size; + int num_segs; + int ref_seg_bytes; + int referred_size; + + if (p + 6 >= end) + return NULL; + + seg_num = get_unaligned_be32 (p); + *type = p[4] & 0x3f; + big_page_size = (p[4] & 0x40) != 0; + p += 5; + + num_segs = p[0] >> 5; + if (num_segs == 7) { + num_segs = get_unaligned_be32 (p) & 0x1fffffff; + ref_seg_bytes = 4 + ((num_segs + 1)/8); + } else { + ref_seg_bytes = 1; + } + p += ref_seg_bytes; + + if (seg_num <= 256) + referred_size = 1; + else if (seg_num <= 65536) + referred_size = 2; + else + referred_size = 4; + + p += num_segs * referred_size; + p += big_page_size ? 4 : 1; + if (p + 4 >= end) + return NULL; + + *data_len = get_unaligned_be32 (p); + p += 4; + *data = p; + + if (*data_len == 0xffffffff) { + /* if data length is -1 we have to scan through the data to find the end */ + p = _jbig2_find_data_end (*data, end, *type); + if (!p || p >= end) + return NULL; + + *data_len = p - *data; + } else { + p += *data_len; + } + + if (p < end) + return p; + else + return NULL; +} + +static void +_jbig2_extract_info (cairo_image_info_t *info, const unsigned char *p) +{ + info->width = get_unaligned_be32 (p); + info->height = get_unaligned_be32 (p + 4); + info->num_components = 1; + info->bits_per_component = 1; +} + +cairo_int_status_t +_cairo_image_info_get_jbig2_info (cairo_image_info_t *info, + const unsigned char *data, + unsigned long length) +{ + const unsigned char *p = data; + const unsigned char *end = data + length; + int seg_type; + const unsigned char *seg_data; + unsigned long seg_data_len; + + while (p && p < end) { + p = _jbig2_get_next_segment (p, end, &seg_type, &seg_data, &seg_data_len); + if (p && seg_type == 48 && seg_data_len > 8) { + /* page information segment */ + _jbig2_extract_info (info, seg_data); + return CAIRO_STATUS_SUCCESS; + } + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} diff --git a/src/cairo-image-mask-compositor.c b/src/cairo-image-mask-compositor.c index 33fd6dd87..bb990dd65 100755..100644 --- a/src/cairo-image-mask-compositor.c +++ b/src/cairo-image-mask-compositor.c @@ -48,6 +48,8 @@ #include "cairo-compositor-private.h" #include "cairo-region-private.h" +#error This file isn't included in any Makefile + static cairo_int_status_t acquire (void *abstract_dst) { @@ -398,6 +400,7 @@ _cairo_image_mask_compositor_get (void) compositor.draw_image = draw_image; compositor.fill_rectangles = fill_rectangles; compositor.fill_boxes = fill_boxes; +#error check_composite must never be NULL, because it gets called without a NULL pointer check //compositor.check_composite = check_composite; compositor.composite = composite; //compositor.check_composite_boxes = check_composite_boxes; diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c index e02ebe5e0..25cdf9373 100755..100644 --- a/src/cairo-image-source.c +++ b/src/cairo-image-source.c @@ -56,10 +56,6 @@ #include "cairo-surface-subsurface-private.h" #include "cairo-image-filters-private.h" -#if CAIRO_HAS_TG_SURFACE -#include "cairo-tg-private.h" -#endif - #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */ #if CAIRO_NO_MUTEX @@ -444,51 +440,6 @@ _defer_free_cleanup (pixman_image_t *pixman_image, cairo_surface_destroy (closure); } -typedef struct _cairo_image_buffer -{ - cairo_format_t format; - unsigned char *data; - int width; - int height; - int stride; - pixman_image_t *pixman_image; - pixman_format_code_t pixman_format; -} cairo_image_buffer_t; - -static inline void -_get_image_buffer (cairo_surface_t *surface, cairo_image_buffer_t *image_buffer) -{ - if (surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE) - { - cairo_image_surface_t *image = (cairo_image_surface_t *)surface; - - image_buffer->format = image->format; - image_buffer->data = image->data; - image_buffer->width = image->width; - image_buffer->height = image->height; - image_buffer->stride = image->stride; - image_buffer->pixman_image = image->pixman_image; - image_buffer->pixman_format = image->pixman_format; - } -#if CAIRO_HAS_TG_SURFACE - else if (surface->backend->type == CAIRO_SURFACE_TYPE_TG) - { - cairo_tg_surface_t *tg = (cairo_tg_surface_t *)surface; - - image_buffer->format = tg->format; - image_buffer->data = tg->data; - image_buffer->width = tg->width; - image_buffer->height = tg->height; - image_buffer->stride = tg->stride; - image_buffer->pixman_image = ((cairo_image_surface_t *)(tg->image_surface))->pixman_image; - image_buffer->pixman_format = ((cairo_image_surface_t *)(tg->image_surface))->pixman_format; - - /* flush the journal to make the memory image_buffer up-to-date. */ - cairo_surface_flush (surface); - } -#endif -} - static uint16_t expand_channel (uint16_t v, uint32_t bits) { @@ -502,25 +453,25 @@ expand_channel (uint16_t v, uint32_t bits) } static pixman_image_t * -_pixel_to_solid (const cairo_image_buffer_t *image_buffer, int x, int y) +_pixel_to_solid (cairo_image_surface_t *image, int x, int y) { uint32_t pixel; pixman_color_t color; TRACE ((stderr, "%s\n", __FUNCTION__)); - switch (image_buffer->format) { + switch (image->format) { default: case CAIRO_FORMAT_INVALID: ASSERT_NOT_REACHED; return NULL; case CAIRO_FORMAT_A1: - pixel = *(uint8_t *) (image_buffer->data + y * image_buffer->stride + x/8); + pixel = *(uint8_t *) (image->data + y * image->stride + x/8); return pixel & (1 << (x&7)) ? _pixman_black_image () : _pixman_transparent_image (); case CAIRO_FORMAT_A8: - color.alpha = *(uint8_t *) (image_buffer->data + y * image_buffer->stride + x); + color.alpha = *(uint8_t *) (image->data + y * image->stride + x); color.alpha |= color.alpha << 8; if (color.alpha == 0) return _pixman_transparent_image (); @@ -531,7 +482,7 @@ _pixel_to_solid (const cairo_image_buffer_t *image_buffer, int x, int y) return pixman_image_create_solid_fill (&color); case CAIRO_FORMAT_RGB16_565: - pixel = *(uint16_t *) (image_buffer->data + y * image_buffer->stride + 2 * x); + pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x); if (pixel == 0) return _pixman_black_image (); if (pixel == 0xffff) @@ -544,7 +495,7 @@ _pixel_to_solid (const cairo_image_buffer_t *image_buffer, int x, int y) return pixman_image_create_solid_fill (&color); case CAIRO_FORMAT_RGB30: - pixel = *(uint32_t *) (image_buffer->data + y * image_buffer->stride + 4 * x); + pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x); pixel &= 0x3fffffff; /* ignore alpha bits */ if (pixel == 0) return _pixman_black_image (); @@ -560,8 +511,8 @@ _pixel_to_solid (const cairo_image_buffer_t *image_buffer, int x, int y) case CAIRO_FORMAT_ARGB32: case CAIRO_FORMAT_RGB24: - pixel = *(uint32_t *) (image_buffer->data + y * image_buffer->stride + 4 * x); - color.alpha = image_buffer->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff; + pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x); + color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff; if (color.alpha == 0) return _pixman_transparent_image (); if (pixel == 0xffffffff) @@ -576,6 +527,368 @@ _pixel_to_solid (const cairo_image_buffer_t *image_buffer, int x, int y) } } +/* ========================================================================== */ + +/* Index into filter table */ +typedef enum +{ + KERNEL_IMPULSE, + KERNEL_BOX, + KERNEL_LINEAR, + KERNEL_MITCHELL, + KERNEL_NOTCH, + KERNEL_CATMULL_ROM, + KERNEL_LANCZOS3, + KERNEL_LANCZOS3_STRETCHED, + KERNEL_TENT +} kernel_t; + +/* Produce contribution of a filter of size r for pixel centered on x. + For a typical low-pass function this evaluates the function at x/r. + If the frequency is higher than 1/2, such as when r is less than 1, + this may need to integrate several samples, see cubic for examples. +*/ +typedef double (* kernel_func_t) (double x, double r); + +/* Return maximum number of pixels that will be non-zero. Except for + impluse this is the maximum of 2 and the width of the non-zero part + of the filter rounded up to the next integer. +*/ +typedef int (* kernel_width_func_t) (double r); + +/* Table of filters */ +typedef struct +{ + kernel_t kernel; + kernel_func_t func; + kernel_width_func_t width; +} filter_info_t; + +/* PIXMAN_KERNEL_IMPULSE: Returns pixel nearest the center. This + matches PIXMAN_FILTER_NEAREST. This is useful if you wish to + combine the result of nearest in one direction with another filter + in the other. +*/ + +static double +impulse_kernel (double x, double r) +{ + return 1; +} + +static int +impulse_width (double r) +{ + return 1; +} + +/* PIXMAN_KERNEL_BOX: Intersection of a box of width r with square + pixels. This is the smallest possible filter such that the output + image contains an equal contribution from all the input + pixels. Lots of software uses this. The function is a trapazoid of + width r+1, not a box. + + When r == 1.0, PIXMAN_KERNEL_BOX, PIXMAN_KERNEL_LINEAR, and + PIXMAN_KERNEL_TENT all produce the same filter, allowing + them to be exchanged at this point. +*/ + +static double +box_kernel (double x, double r) +{ + return MAX (0.0, MIN (MIN (r, 1.0), + MIN ((r + 1) / 2 - x, (r + 1) / 2 + x))); +} + +static int +box_width (double r) +{ + return r < 1.0 ? 2 : ceil(r + 1); +} + +/* PIXMAN_KERNEL_LINEAR: Weighted sum of the two pixels nearest the + center, or a triangle of width 2. This matches + PIXMAN_FILTER_BILINEAR. This is useful if you wish to combine the + result of bilinear in one direction with another filter in the + other. This is not a good filter if r > 1. You may actually want + PIXMAN_FILTER_TENT. + + When r == 1.0, PIXMAN_KERNEL_BOX, PIXMAN_KERNEL_LINEAR, and + PIXMAN_KERNEL_TENT all produce the same filter, allowing + them to be exchanged at this point. +*/ + +static double +linear_kernel (double x, double r) +{ + return MAX (1.0 - fabs(x), 0.0); +} + +static int +linear_width (double r) +{ + return 2; +} + +/* Cubic functions described in the Mitchell-Netravali paper. + http://mentallandscape.com/Papers_siggraph88.pdf. This describes + all possible cubic functions that can be used for sampling. +*/ + +static double +general_cubic (double x, double r, double B, double C) +{ + double ax; + if (r < 1.0) + return + general_cubic(x * 2 - .5, r * 2, B, C) + + general_cubic(x * 2 + .5, r * 2, B, C); + + ax = fabs (x / r); + + if (ax < 1) + { + return (((12 - 9 * B - 6 * C) * ax + + (-18 + 12 * B + 6 * C)) * ax * ax + + (6 - 2 * B)) / 6; + } + else if (ax < 2) + { + return ((((-B - 6 * C) * ax + + (6 * B + 30 * C)) * ax + + (-12 * B - 48 * C)) * ax + + (8 * B + 24 * C)) / 6; + } + else + { + return 0.0; + } +} + +static int +cubic_width (double r) +{ + return MAX (2, ceil (r * 4)); +} + +/* PIXMAN_KERNEL_CATMULL_ROM: Catmull-Rom interpolation. Often called + "cubic interpolation", "b-spline", or just "cubic" by other + software. This filter has negative values so it can produce ringing + and output pixels outside the range of input pixels. This is very + close to lanczos2 so there is no reason to supply that as well. +*/ + +static double +cubic_kernel (double x, double r) +{ + return general_cubic (x, r, 0.0, 0.5); +} + +/* PIXMAN_KERNEL_MITCHELL: Cubic recommended by the Mitchell-Netravali + paper. This has negative values and because the values at +/-1 are + not zero it does not interpolate the pixels, meaning it will change + an image even if there is no translation. +*/ + +static double +mitchell_kernel (double x, double r) +{ + return general_cubic (x, r, 1/3.0, 1/3.0); +} + +/* PIXMAN_KERNEL_NOTCH: Cubic recommended by the Mitchell-Netravali + paper to remove postaliasing artifacts. This does not remove + aliasing already present in the source image, though it may appear + to due to it's excessive blurriness. In any case this is more + useful than gaussian for image reconstruction. +*/ + +static double +notch_kernel (double x, double r) +{ + return general_cubic (x, r, 1.5, -0.25); +} + +/* PIXMAN_KERNEL_LANCZOS3: lanczos windowed sinc function from -3 to + +3. Very popular with high-end software though I think any + advantage over cubics is hidden by quantization and programming + mistakes. You will see LANCZOS5 or even 7 sometimes. +*/ + +static double +sinc (double x) +{ + return x ? sin (M_PI * x) / (M_PI * x) : 1.0; +} + +static double +lanczos (double x, double n) +{ + return fabs (x) < n ? sinc (x) * sinc (x * (1.0 / n)) : 0.0; +} + +static double +lanczos3_kernel (double x, double r) +{ + if (r < 1.0) + return + lanczos3_kernel (x * 2 - .5, r * 2) + + lanczos3_kernel (x * 2 + .5, r * 2); + else + return lanczos (x / r, 3.0); +} + +static int +lanczos3_width (double r) +{ + return MAX (2, ceil (r * 6)); +} + +/* PIXMAN_KERNEL_LANCZOS3_STRETCHED - The LANCZOS3 kernel widened by + 4/3. Recommended by Jim Blinn + http://graphics.cs.cmu.edu/nsp/course/15-462/Fall07/462/papers/jaggy.pdf +*/ + +static double +nice_kernel (double x, double r) +{ + return lanczos3_kernel (x, r * (4.0/3)); +} + +static int +nice_width (double r) +{ + return MAX (2.0, ceil (r * 8)); +} + +/* PIXMAN_KERNEL_TENT: Triangle of width 2r. Lots of software uses + this as a "better" filter, twice the size of a box but smaller than + a cubic. + + When r == 1.0, PIXMAN_KERNEL_BOX, PIXMAN_KERNEL_LINEAR, and + PIXMAN_KERNEL_TENT all produce the same filter, allowing + them to be exchanged at this point. +*/ + +static double +tent_kernel (double x, double r) +{ + if (r < 1.0) + return box_kernel(x, r); + else + return MAX (1.0 - fabs(x / r), 0.0); +} + +static int +tent_width (double r) +{ + return r < 1.0 ? 2 : ceil(2 * r); +} + + +static const filter_info_t filters[] = +{ + { KERNEL_IMPULSE, impulse_kernel, impulse_width }, + { KERNEL_BOX, box_kernel, box_width }, + { KERNEL_LINEAR, linear_kernel, linear_width }, + { KERNEL_MITCHELL, mitchell_kernel, cubic_width }, + { KERNEL_NOTCH, notch_kernel, cubic_width }, + { KERNEL_CATMULL_ROM, cubic_kernel, cubic_width }, + { KERNEL_LANCZOS3, lanczos3_kernel, lanczos3_width }, + { KERNEL_LANCZOS3_STRETCHED,nice_kernel, nice_width }, + { KERNEL_TENT, tent_kernel, tent_width } +}; + +/* Fills in one dimension of the filter array */ +static void get_filter(kernel_t filter, double r, + int width, int subsample, + pixman_fixed_t* out) +{ + int i; + pixman_fixed_t *p = out; + int n_phases = 1 << subsample; + double step = 1.0 / n_phases; + kernel_func_t func = filters[filter].func; + + /* special-case the impulse filter: */ + if (width <= 1) + { + for (i = 0; i < n_phases; ++i) + *p++ = pixman_fixed_1; + return; + } + + for (i = 0; i < n_phases; ++i) + { + double frac = (i + .5) * step; + /* Center of left-most pixel: */ + double x1 = ceil (frac - width / 2.0 - 0.5) - frac + 0.5; + double total = 0; + pixman_fixed_t new_total = 0; + int j; + + for (j = 0; j < width; ++j) + { + double v = func(x1 + j, r); + total += v; + p[j] = pixman_double_to_fixed (v); + } + + /* Normalize */ + total = 1 / total; + for (j = 0; j < width; ++j) + new_total += (p[j] *= total); + + /* Put any error on center pixel */ + p[width / 2] += (pixman_fixed_1 - new_total); + + p += width; + } +} + + +/* Create the parameter list for a SEPARABLE_CONVOLUTION filter + * with the given kernels and scale parameters. + */ +static pixman_fixed_t * +create_separable_convolution (int *n_values, + kernel_t xfilter, + double sx, + kernel_t yfilter, + double sy) +{ + int xwidth, xsubsample, ywidth, ysubsample, size_x, size_y; + pixman_fixed_t *params; + + xwidth = filters[xfilter].width(sx); + xsubsample = 0; + if (xwidth > 1) + while (sx * (1 << xsubsample) <= 128.0) xsubsample++; + size_x = (1 << xsubsample) * xwidth; + + ywidth = filters[yfilter].width(sy); + ysubsample = 0; + if (ywidth > 1) + while (sy * (1 << ysubsample) <= 128.0) ysubsample++; + size_y = (1 << ysubsample) * ywidth; + + *n_values = 4 + size_x + size_y; + params = malloc (*n_values * sizeof (pixman_fixed_t)); + if (!params) return 0; + + params[0] = pixman_int_to_fixed (xwidth); + params[1] = pixman_int_to_fixed (ywidth); + params[2] = pixman_int_to_fixed (xsubsample); + params[3] = pixman_int_to_fixed (ysubsample); + + get_filter(xfilter, sx, xwidth, xsubsample, params + 4); + get_filter(yfilter, sy, ywidth, ysubsample, params + 4 + size_x); + + return params; +} + +/* ========================================================================== */ + static cairo_bool_t _pixman_image_set_properties (pixman_image_t *pixman_image, const cairo_pattern_t *pattern, @@ -605,16 +918,58 @@ _pixman_image_set_properties (pixman_image_t *pixman_image, else { pixman_filter_t pixman_filter; + kernel_t kernel; + double dx, dy; + + /* Compute scale factors from the pattern matrix. These scale + * factors are from user to pattern space, and as such they + * are greater than 1.0 for downscaling and less than 1.0 for + * upscaling. The factors are the size of an axis-aligned + * rectangle with the same area as the parallelgram a 1x1 + * square transforms to. + */ + dx = hypot (pattern->matrix.xx, pattern->matrix.xy); + dy = hypot (pattern->matrix.yx, pattern->matrix.yy); + + /* Clip at maximum pixman_fixed number. Besides making it + * passable to pixman, this avoids errors from inf and nan. + */ + if (! (dx < 0x7FFF)) dx = 0x7FFF; + if (! (dy < 0x7FFF)) dy = 0x7FFF; switch (pattern->filter) { case CAIRO_FILTER_FAST: pixman_filter = PIXMAN_FILTER_FAST; break; case CAIRO_FILTER_GOOD: - pixman_filter = PIXMAN_FILTER_GOOD; + pixman_filter = PIXMAN_FILTER_SEPARABLE_CONVOLUTION; + kernel = KERNEL_BOX; + /* Clip the filter size to prevent extreme slowness. This + value could be raised if 2-pass filtering is done */ + if (dx > 16.0) dx = 16.0; + if (dy > 16.0) dy = 16.0; + /* Match the bilinear filter for scales > .75: */ + if (dx < 1.0/0.75) dx = 1.0; + if (dy < 1.0/0.75) dy = 1.0; break; case CAIRO_FILTER_BEST: - pixman_filter = PIXMAN_FILTER_BEST; + pixman_filter = PIXMAN_FILTER_SEPARABLE_CONVOLUTION; + kernel = KERNEL_CATMULL_ROM; /* LANCZOS3 is better but not much */ + /* Clip the filter size to prevent extreme slowness. This + value could be raised if 2-pass filtering is done */ + if (dx > 16.0) { dx = 16.0; kernel = KERNEL_BOX; } + /* blur up to 2x scale, then blend to square pixels for larger: */ + else if (dx < 1.0) { + if (dx < 1.0/128) dx = 1.0/127; + else if (dx < 0.5) dx = 1.0 / (1.0 / dx - 1.0); + else dx = 1.0; + } + if (dy > 16.0) { dy = 16.0; kernel = KERNEL_BOX; } + else if (dy < 1.0) { + if (dy < 1.0/128) dy = 1.0/127; + else if (dy < 0.5) dy = 1.0 / (1.0 / dy - 1.0); + else dy = 1.0; + } break; case CAIRO_FILTER_NEAREST: pixman_filter = PIXMAN_FILTER_NEAREST; @@ -632,7 +987,17 @@ _pixman_image_set_properties (pixman_image_t *pixman_image, pixman_filter = PIXMAN_FILTER_BEST; } - pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0); + if (pixman_filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION) { + int n_params; + pixman_fixed_t *params; + params = create_separable_convolution + (&n_params, kernel, dx, kernel, dy); + pixman_image_set_filter (pixman_image, pixman_filter, + params, n_params); + free (params); + } else { + pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0); + } } { @@ -835,7 +1200,7 @@ _pixman_image_for_recording (cairo_image_surface_t *dst, done: /* filter with gaussian */ blurred_surface = _cairo_image_gaussian_filter (clone, &pattern->base); - + pixman_image = pixman_image_ref (((cairo_image_surface_t *)blurred_surface)->pixman_image); cairo_surface_destroy (blurred_surface); cairo_surface_destroy (clone); @@ -854,16 +1219,6 @@ done: return pixman_image; } -static inline cairo_bool_t -_surface_type_is_image_buffer (cairo_surface_type_t type) -{ -#if CAIRO_HAS_TG_SURFACE - return type == CAIRO_SURFACE_TYPE_IMAGE || type == CAIRO_SURFACE_TYPE_TG; -#else - return type == CAIRO_SURFACE_TYPE_IMAGE; -#endif -} - static pixman_image_t * _pixman_image_for_surface (cairo_image_surface_t *dst, const cairo_surface_pattern_t *pattern, @@ -886,27 +1241,26 @@ _pixman_image_for_surface (cairo_image_surface_t *dst, is_mask, extents, sample, ix, iy); - if (_surface_type_is_image_buffer (pattern->surface->type) && + if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE && (! is_mask || ! pattern->base.has_component_alpha || (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0)) { cairo_surface_t *defer_free = NULL; cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface; - cairo_image_buffer_t image_buffer; + cairo_surface_type_t type; if (_cairo_surface_is_snapshot (&source->base)) { defer_free = _cairo_surface_snapshot_get_target (&source->base); source = (cairo_image_surface_t *) defer_free; } - if (_surface_type_is_image_buffer (source->base.backend->type)) { - _get_image_buffer (source, &image_buffer); - + type = source->base.backend->type; + if (type == CAIRO_SURFACE_TYPE_IMAGE) { if (extend != CAIRO_EXTEND_NONE && sample->x >= 0 && sample->y >= 0 && - sample->x + sample->width <= image_buffer.width && - sample->y + sample->height <= image_buffer.height) + sample->x + sample->width <= source->width && + sample->y + sample->height <= source->height) { extend = CAIRO_EXTEND_NONE; } @@ -914,8 +1268,8 @@ _pixman_image_for_surface (cairo_image_surface_t *dst, if (sample->width == 1 && sample->height == 1) { if (sample->x < 0 || sample->y < 0 || - sample->x >= image_buffer.width || - sample->y >= image_buffer.height) + sample->x >= source->width || + sample->y >= source->height) { if (extend == CAIRO_EXTEND_NONE) { cairo_surface_destroy (defer_free); @@ -924,7 +1278,8 @@ _pixman_image_for_surface (cairo_image_surface_t *dst, } else { - pixman_image = _pixel_to_solid (&image_buffer, sample->x, sample->y); + pixman_image = _pixel_to_solid (source, + sample->x, sample->y); if (pixman_image) { cairo_surface_destroy (defer_free); return pixman_image; @@ -948,16 +1303,16 @@ _pixman_image_for_surface (cairo_image_surface_t *dst, return blurred_pixman_image; } else - return pixman_image_ref (image_buffer.pixman_image); + return pixman_image_ref (source->pixman_image); } #endif if (pattern->base.filter != CAIRO_FILTER_GAUSSIAN) { - pixman_image = pixman_image_create_bits (image_buffer.pixman_format, - image_buffer.width, - image_buffer.height, - (uint32_t *) image_buffer.data, - image_buffer.stride); + pixman_image = pixman_image_create_bits (source->pixman_format, + source->width, + source->height, + (uint32_t *) source->data, + source->stride); if (unlikely (pixman_image == NULL)) { cairo_surface_destroy (defer_free); if (blurred_surface) @@ -975,14 +1330,12 @@ _pixman_image_for_surface (cairo_image_surface_t *dst, } else blurred_surface = _cairo_image_gaussian_filter (&source->base, &pattern->base); - } else if (source->base.backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + } else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) { cairo_surface_subsurface_t *sub; cairo_bool_t is_contained = FALSE; sub = (cairo_surface_subsurface_t *) source; - source = sub->target; - - _get_image_buffer (source, &image_buffer); + source = (cairo_image_surface_t *) sub->target; if (sample->x >= 0 && sample->y >= 0 && @@ -994,7 +1347,7 @@ _pixman_image_for_surface (cairo_image_surface_t *dst, if (sample->width == 1 && sample->height == 1) { if (is_contained) { - pixman_image = _pixel_to_solid (&image_buffer, + pixman_image = _pixel_to_solid (source, sub->extents.x + sample->x, sub->extents.y + sample->y); if (pixman_image) @@ -1025,16 +1378,16 @@ _pixman_image_for_surface (cairo_image_surface_t *dst, /* Avoid sub-byte offsets, force a copy in that case. */ if (pattern->base.filter != CAIRO_FILTER_GAUSSIAN) { - if (PIXMAN_FORMAT_BPP (image_buffer.pixman_format) >= 8) { - if (is_contained) { - void *data = image_buffer.data - + sub->extents.x * PIXMAN_FORMAT_BPP(image_buffer.pixman_format)/8 - + sub->extents.y * image_buffer.stride; - pixman_image = pixman_image_create_bits (image_buffer.pixman_format, - sub->extents.width, - sub->extents.height, - data, - image_buffer.stride); + if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) { + if (is_contained) { + void *data = source->data + + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8 + + sub->extents.y * source->stride; + pixman_image = pixman_image_create_bits (source->pixman_format, + sub->extents.width, + sub->extents.height, + data, + source->stride); if (unlikely (pixman_image == NULL)) { if (blurred_surface) cairo_surface_destroy (blurred_surface); @@ -1087,7 +1440,7 @@ _pixman_image_for_surface (cairo_image_surface_t *dst, } else /* filter with gaussian */ - blurred_surface = _cairo_image_gaussian_filter (&image->base, &pattern->base); + blurred_surface = _cairo_image_gaussian_filter (&image->base, &pattern->base); cleanup = malloc (sizeof (*cleanup)); if (unlikely (cleanup == NULL)) { diff --git a/src/cairo-image-surface-inline.h b/src/cairo-image-surface-inline.h index 743d5fd3e..743d5fd3e 100755..100644 --- a/src/cairo-image-surface-inline.h +++ b/src/cairo-image-surface-inline.h diff --git a/src/cairo-image-surface-private.h b/src/cairo-image-surface-private.h index 8ca694c5e..8ca694c5e 100755..100644 --- a/src/cairo-image-surface-private.h +++ b/src/cairo-image-surface-private.h diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index b68f4a9e7..1948a1add 100755..100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -48,6 +48,7 @@ #include "cairo-image-surface-inline.h" #include "cairo-paginated-private.h" #include "cairo-pattern-private.h" +#include "cairo-pixman-private.h" #include "cairo-recording-surface-private.h" #include "cairo-region-private.h" #include "cairo-scaled-font-private.h" @@ -123,7 +124,7 @@ _cairo_image_shadow_caches_destroy (void) cairo_surface_destroy (shadow->surface); free (shadow); } - shadow_caches_size = 0; + shadow_caches_size = 0; } } @@ -222,7 +223,12 @@ _cairo_format_from_pixman_format (pixman_format_code_t pixman_format) return CAIRO_FORMAT_A1; case PIXMAN_r5g6b5: return CAIRO_FORMAT_RGB16_565; +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,22,0) case PIXMAN_r8g8b8a8: case PIXMAN_r8g8b8x8: +#endif +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,27,2) + case PIXMAN_a8r8g8b8_sRGB: +#endif case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: case PIXMAN_r8g8b8: case PIXMAN_b8g8r8: case PIXMAN_b5g6r5: case PIXMAN_a1r5g5b5: case PIXMAN_x1r5g5b5: case PIXMAN_a1b5g5r5: @@ -239,7 +245,9 @@ _cairo_format_from_pixman_format (pixman_format_code_t pixman_format) case PIXMAN_a2b10g10r10: case PIXMAN_x2b10g10r10: case PIXMAN_a2r10g10b10: +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,22,0) case PIXMAN_x14r6g6b6: +#endif default: return CAIRO_FORMAT_INVALID; } @@ -535,7 +543,7 @@ _cairo_image_surface_create_with_content (cairo_content_t content, * <informalexample><programlisting> * int stride; * unsigned char *data; - * #cairo_surface_t *surface; + * cairo_surface_t *surface; * * stride = cairo_format_stride_for_width (format, width); * data = malloc (stride * height); @@ -883,12 +891,12 @@ _cairo_image_surface_snapshot (void *abstract_surface) return &clone->base; image->pixman_image = NULL; + image->owns_data = FALSE; clone->transparency = image->transparency; clone->color = image->color; - clone->owns_data = image->owns_data; - image->owns_data = FALSE; + clone->owns_data = TRUE; return &clone->base; } @@ -964,8 +972,9 @@ _cairo_image_surface_finish (void *abstract_surface) } if (surface->parent) { - cairo_surface_destroy (surface->parent); + cairo_surface_t *parent = surface->parent; surface->parent = NULL; + cairo_surface_destroy (parent); } _cairo_image_shadow_caches_destroy (); @@ -1034,7 +1043,7 @@ _cairo_image_surface_paint (void *abstract_surface, const cairo_clip_t *clip) { cairo_image_surface_t *surface = abstract_surface; - cairo_int_status_t status; + cairo_int_status_t status; TRACE ((stderr, "%s (surface=%d)\n", __FUNCTION__, surface->base.unique_id)); @@ -1322,7 +1331,7 @@ _cairo_image_surface_shadow_surface (void *surface, else shadow_width = width; } - + if (height < MIN_IMAGE_SHADOW_SIZE) shadow_height = height; else if (has_blur) { diff --git a/src/cairo-line-inline.h b/src/cairo-line-inline.h new file mode 100644 index 000000000..71cc5e7eb --- /dev/null +++ b/src/cairo-line-inline.h @@ -0,0 +1,48 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2014 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + */ + +#ifndef CAIRO_LINE_INLINE_H +#define CAIRO_LINE_INLINE_H + +#include "cairo-types-private.h" +#include "cairo-compiler-private.h" +#include "cairo-fixed-private.h" +#include "cairo-line-private.h" + +static inline int +cairo_lines_equal (const cairo_line_t *a, const cairo_line_t *b) +{ + return (a->p1.x == b->p1.x && a->p1.y == b->p1.y && + a->p2.x == b->p2.x && a->p2.y == b->p2.y); +} + +#endif /* CAIRO_LINE_INLINE_H */ diff --git a/src/cairo-tg.h b/src/cairo-line-private.h index 97be60153..08bf4b358 100755..100644 --- a/src/cairo-tg.h +++ b/src/cairo-line-private.h @@ -1,5 +1,6 @@ -/* - * Copyright © 2012 SCore Corporation +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2014 Intel Corporation, Inc * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -24,47 +25,27 @@ * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. * - * Author: Taekyun Kim (podain77@gmail.com) + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * */ -#ifndef CAIRO_TG_H -#define CAIRO_TG_H +#ifndef CAIRO_LINE_PRIVATE_H +#define CAIRO_LINE_PRIVATE_H -#include "cairo.h" - -#if CAIRO_HAS_TG_SURFACE +#include "cairo-types-private.h" +#include "cairo-error-private.h" +#include "cairo-compiler-private.h" CAIRO_BEGIN_DECLS -cairo_public cairo_surface_t * -cairo_tg_surface_create (cairo_format_t format, - int width, - int height); - -cairo_public cairo_surface_t * -cairo_tg_surface_create_for_data (unsigned char *data, - cairo_format_t format, - int width, - int height, - int stride); - -cairo_public unsigned char * -cairo_tg_surface_get_data (cairo_surface_t *surface); - -cairo_public cairo_format_t -cairo_tg_surface_get_format (cairo_surface_t *surface); - -cairo_public int -cairo_tg_surface_get_width (cairo_surface_t *surface); - -cairo_public int -cairo_tg_surface_get_height (cairo_surface_t *surface); - -cairo_public int -cairo_tg_surface_get_stride (cairo_surface_t *surface); +cairo_private int +cairo_lines_compare_at_y(const cairo_line_t *a, + const cairo_line_t *b, + int y); CAIRO_END_DECLS -#endif /* CAIRO_HAS_TG_SURFACE */ - -#endif /* CAIRO_TG_H */ +#endif /* CAIRO_LINE_PRIVATE_H */ diff --git a/src/cairo-line.c b/src/cairo-line.c new file mode 100644 index 000000000..cb13927bd --- /dev/null +++ b/src/cairo-line.c @@ -0,0 +1,306 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* + * Copyright © 2004 Carl Worth + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2008 Chris Wilson + * Copyright © 2014 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Keith Packard + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#include "cairoint.h" + +#include "cairo-line-inline.h" +#include "cairo-slope-private.h" + +static int +line_compare_for_y_against_x (const cairo_line_t *a, + int32_t y, + int32_t x) +{ + int32_t adx, ady; + int32_t dx, dy; + cairo_int64_t L, R; + + if (x < a->p1.x && x < a->p2.x) + return 1; + if (x > a->p1.x && x > a->p2.x) + return -1; + + adx = a->p2.x - a->p1.x; + dx = x - a->p1.x; + + if (adx == 0) + return -dx; + if (dx == 0 || (adx ^ dx) < 0) + return adx; + + dy = y - a->p1.y; + ady = a->p2.y - a->p1.y; + + L = _cairo_int32x32_64_mul (dy, adx); + R = _cairo_int32x32_64_mul (dx, ady); + + return _cairo_int64_cmp (L, R); +} + +/* + * We need to compare the x-coordinates of a pair of lines for a particular y, + * without loss of precision. + * + * The x-coordinate along an edge for a given y is: + * X = A_x + (Y - A_y) * A_dx / A_dy + * + * So the inequality we wish to test is: + * A_x + (Y - A_y) * A_dx / A_dy ∘ B_x + (Y - B_y) * B_dx / B_dy, + * where ∘ is our inequality operator. + * + * By construction, we know that A_dy and B_dy (and (Y - A_y), (Y - B_y)) are + * all positive, so we can rearrange it thus without causing a sign change: + * A_dy * B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx * A_dy + * - (Y - A_y) * A_dx * B_dy + * + * Given the assumption that all the deltas fit within 32 bits, we can compute + * this comparison directly using 128 bit arithmetic. For certain, but common, + * input we can reduce this down to a single 32 bit compare by inspecting the + * deltas. + * + * (And put the burden of the work on developing fast 128 bit ops, which are + * required throughout the tessellator.) + * + * See the similar discussion for _slope_compare(). + */ +static int +lines_compare_x_for_y_general (const cairo_line_t *a, + const cairo_line_t *b, + int32_t y) +{ + /* XXX: We're assuming here that dx and dy will still fit in 32 + * bits. That's not true in general as there could be overflow. We + * should prevent that before the tessellation algorithm + * begins. + */ + int32_t dx; + int32_t adx, ady; + int32_t bdx, bdy; + enum { + HAVE_NONE = 0x0, + HAVE_DX = 0x1, + HAVE_ADX = 0x2, + HAVE_DX_ADX = HAVE_DX | HAVE_ADX, + HAVE_BDX = 0x4, + HAVE_DX_BDX = HAVE_DX | HAVE_BDX, + HAVE_ADX_BDX = HAVE_ADX | HAVE_BDX, + HAVE_ALL = HAVE_DX | HAVE_ADX | HAVE_BDX + } have_dx_adx_bdx = HAVE_ALL; + + ady = a->p2.y - a->p1.y; + adx = a->p2.x - a->p1.x; + if (adx == 0) + have_dx_adx_bdx &= ~HAVE_ADX; + + bdy = b->p2.y - b->p1.y; + bdx = b->p2.x - b->p1.x; + if (bdx == 0) + have_dx_adx_bdx &= ~HAVE_BDX; + + dx = a->p1.x - b->p1.x; + if (dx == 0) + have_dx_adx_bdx &= ~HAVE_DX; + +#define L _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (ady, bdy), dx) +#define A _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (adx, bdy), y - a->p1.y) +#define B _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (bdx, ady), y - b->p1.y) + switch (have_dx_adx_bdx) { + default: + case HAVE_NONE: + return 0; + case HAVE_DX: + /* A_dy * B_dy * (A_x - B_x) ∘ 0 */ + return dx; /* ady * bdy is positive definite */ + case HAVE_ADX: + /* 0 ∘ - (Y - A_y) * A_dx * B_dy */ + return adx; /* bdy * (y - a->top.y) is positive definite */ + case HAVE_BDX: + /* 0 ∘ (Y - B_y) * B_dx * A_dy */ + return -bdx; /* ady * (y - b->top.y) is positive definite */ + case HAVE_ADX_BDX: + /* 0 ∘ (Y - B_y) * B_dx * A_dy - (Y - A_y) * A_dx * B_dy */ + if ((adx ^ bdx) < 0) { + return adx; + } else if (a->p1.y == b->p1.y) { /* common origin */ + cairo_int64_t adx_bdy, bdx_ady; + + /* ∴ A_dx * B_dy ∘ B_dx * A_dy */ + + adx_bdy = _cairo_int32x32_64_mul (adx, bdy); + bdx_ady = _cairo_int32x32_64_mul (bdx, ady); + + return _cairo_int64_cmp (adx_bdy, bdx_ady); + } else + return _cairo_int128_cmp (A, B); + case HAVE_DX_ADX: + /* A_dy * (A_x - B_x) ∘ - (Y - A_y) * A_dx */ + if ((-adx ^ dx) < 0) { + return dx; + } else { + cairo_int64_t ady_dx, dy_adx; + + ady_dx = _cairo_int32x32_64_mul (ady, dx); + dy_adx = _cairo_int32x32_64_mul (a->p1.y - y, adx); + + return _cairo_int64_cmp (ady_dx, dy_adx); + } + case HAVE_DX_BDX: + /* B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx */ + if ((bdx ^ dx) < 0) { + return dx; + } else { + cairo_int64_t bdy_dx, dy_bdx; + + bdy_dx = _cairo_int32x32_64_mul (bdy, dx); + dy_bdx = _cairo_int32x32_64_mul (y - b->p1.y, bdx); + + return _cairo_int64_cmp (bdy_dx, dy_bdx); + } + case HAVE_ALL: + /* XXX try comparing (a->p2.x - b->p2.x) et al */ + return _cairo_int128_cmp (L, _cairo_int128_sub (B, A)); + } +#undef B +#undef A +#undef L +} + +static int +lines_compare_x_for_y (const cairo_line_t *a, + const cairo_line_t *b, + int32_t y) +{ + /* If the sweep-line is currently on an end-point of a line, + * then we know its precise x value (and considering that we often need to + * compare events at end-points, this happens frequently enough to warrant + * special casing). + */ + enum { + HAVE_NEITHER = 0x0, + HAVE_AX = 0x1, + HAVE_BX = 0x2, + HAVE_BOTH = HAVE_AX | HAVE_BX + } have_ax_bx = HAVE_BOTH; + int32_t ax, bx; + + if (y == a->p1.y) + ax = a->p1.x; + else if (y == a->p2.y) + ax = a->p2.x; + else + have_ax_bx &= ~HAVE_AX; + + if (y == b->p1.y) + bx = b->p1.x; + else if (y == b->p2.y) + bx = b->p2.x; + else + have_ax_bx &= ~HAVE_BX; + + switch (have_ax_bx) { + default: + case HAVE_NEITHER: + return lines_compare_x_for_y_general (a, b, y); + case HAVE_AX: + return -line_compare_for_y_against_x (b, y, ax); + case HAVE_BX: + return line_compare_for_y_against_x (a, y, bx); + case HAVE_BOTH: + return ax - bx; + } +} + +static int bbox_compare (const cairo_line_t *a, + const cairo_line_t *b) +{ + int32_t amin, amax; + int32_t bmin, bmax; + + if (a->p1.x < a->p2.x) { + amin = a->p1.x; + amax = a->p2.x; + } else { + amin = a->p2.x; + amax = a->p1.x; + } + + if (b->p1.x < b->p2.x) { + bmin = b->p1.x; + bmax = b->p2.x; + } else { + bmin = b->p2.x; + bmax = b->p1.x; + } + + if (amax < bmin) + return -1; + + if (amin > bmax) + return +1; + + return 0; +} + +int cairo_lines_compare_at_y (const cairo_line_t *a, + const cairo_line_t *b, + int y) +{ + cairo_slope_t sa, sb; + int ret; + + if (cairo_lines_equal (a, b)) + return 0; + + /* Don't bother solving for abscissa if the edges' bounding boxes + * can be used to order them. + */ + ret = bbox_compare (a, b); + if (ret) + return ret; + + ret = lines_compare_x_for_y (a, b, y); + if (ret) + return ret; + + _cairo_slope_init (&sa, &a->p1, &a->p2); + _cairo_slope_init (&sb, &b->p1, &b->p2); + + return _cairo_slope_compare (&sb, &sa); +} diff --git a/src/cairo-list-inline.h b/src/cairo-list-inline.h index d00f40e98..0955178d2 100755..100644 --- a/src/cairo-list-inline.h +++ b/src/cairo-list-inline.h @@ -145,9 +145,15 @@ __cairo_list_del (cairo_list_t *prev, cairo_list_t *next) } static inline void -cairo_list_del (cairo_list_t *entry) +_cairo_list_del (cairo_list_t *entry) { __cairo_list_del (entry->prev, entry->next); +} + +static inline void +cairo_list_del (cairo_list_t *entry) +{ + _cairo_list_del (entry); cairo_list_init (entry); } diff --git a/src/cairo-list-private.h b/src/cairo-list-private.h index 9f39b668f..9f39b668f 100755..100644 --- a/src/cairo-list-private.h +++ b/src/cairo-list-private.h diff --git a/src/cairo-lzw.c b/src/cairo-lzw.c index de7f99983..de7f99983 100755..100644 --- a/src/cairo-lzw.c +++ b/src/cairo-lzw.c diff --git a/src/cairo-malloc-private.h b/src/cairo-malloc-private.h index 1e2c67f8d..1e2c67f8d 100755..100644 --- a/src/cairo-malloc-private.h +++ b/src/cairo-malloc-private.h diff --git a/src/cairo-mask-compositor.c b/src/cairo-mask-compositor.c index 31d116119..80bf0f5e6 100755..100644 --- a/src/cairo-mask-compositor.c +++ b/src/cairo-mask-compositor.c @@ -163,9 +163,10 @@ create_composite_mask (const cairo_mask_compositor_t *compositor, struct blt_in info; int i; - surface = _cairo_surface_create_similar_scratch (dst, CAIRO_CONTENT_ALPHA, - extents->bounded.width, - extents->bounded.height); + surface = _cairo_surface_create_scratch (dst, CAIRO_CONTENT_ALPHA, + extents->bounded.width, + extents->bounded.height, + NULL); if (unlikely (surface->status)) return surface; @@ -346,9 +347,10 @@ clip_and_composite_combine (const cairo_mask_compositor_t *compositor, cairo_status_t status; int clip_x, clip_y; - tmp = _cairo_surface_create_similar_scratch (dst, dst->content, - extents->bounded.width, - extents->bounded.height); + tmp = _cairo_surface_create_scratch (dst, dst->content, + extents->bounded.width, + extents->bounded.height, + NULL); if (unlikely (tmp->status)) { status = tmp->status; goto cleanup; diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index ba975beae..ae498f515 100755..100644 --- a/src/cairo-matrix.c +++ b/src/cairo-matrix.c @@ -748,23 +748,32 @@ _cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix, return FALSE; } +#define SCALING_EPSILON _cairo_fixed_to_double(1) + +/* This only returns true if the matrix is 90 degree rotations or + * flips. It appears calling code is relying on this. It will return + * false for other rotations even if the scale is one. Approximations + * are allowed to handle matricies filled in using trig functions + * such as sin(M_PI_2). + */ cairo_bool_t _cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix) { - if (matrix->xy == 0.0 && matrix->yx == 0.0) { - if (! (matrix->xx == 1.0 || matrix->xx == -1.0)) - return FALSE; - if (! (matrix->yy == 1.0 || matrix->yy == -1.0)) - return FALSE; - } else if (matrix->xx == 0.0 && matrix->yy == 0.0) { - if (! (matrix->xy == 1.0 || matrix->xy == -1.0)) - return FALSE; - if (! (matrix->yx == 1.0 || matrix->yx == -1.0)) - return FALSE; - } else - return FALSE; - - return TRUE; + /* check that the determinant is near +/-1 */ + double det = _cairo_matrix_compute_determinant (matrix); + if (fabs (det * det - 1.0) < SCALING_EPSILON) { + /* check that one axis is close to zero */ + if (fabs (matrix->xy) < SCALING_EPSILON && + fabs (matrix->yx) < SCALING_EPSILON) + return TRUE; + if (fabs (matrix->xx) < SCALING_EPSILON && + fabs (matrix->yy) < SCALING_EPSILON) + return TRUE; + /* If rotations are allowed then it must instead test for + * orthogonality. This is xx*xy+yx*yy ~= 0. + */ + } + return FALSE; } /* By pixel exact here, we mean a matrix that is composed only of diff --git a/src/cairo-mempool-private.h b/src/cairo-mempool-private.h index a09f6ce51..a09f6ce51 100755..100644 --- a/src/cairo-mempool-private.h +++ b/src/cairo-mempool-private.h diff --git a/src/cairo-mempool.c b/src/cairo-mempool.c index 96e4a62b2..751ede320 100755..100644 --- a/src/cairo-mempool.c +++ b/src/cairo-mempool.c @@ -157,7 +157,8 @@ get_buddy (cairo_mempool_t *pool, size_t offset, int bits) { struct _cairo_memblock *block; - assert (offset + (1 << bits) <= pool->num_blocks); + if (offset + (1 << bits) >= pool->num_blocks) + return NULL; /* invalid */ if (BITTEST (pool, offset + (1 << bits) - 1)) return NULL; /* buddy is allocated */ diff --git a/src/cairo-mesh-pattern-rasterizer.c b/src/cairo-mesh-pattern-rasterizer.c index 5342b3d22..86cd16833 100755..100644 --- a/src/cairo-mesh-pattern-rasterizer.c +++ b/src/cairo-mesh-pattern-rasterizer.c @@ -697,9 +697,9 @@ rasterize_bezier_patch (unsigned char *data, int width, int height, int stride, cairo_point_double_t p[4][4], double col[4][4]) { double pv[4][2][4], cstart[4], cend[4], dcstart[4], dcend[4]; - int vsteps, v, i, k; + int v, i, k; - vsteps = 1 << vshift; + v = 1 << vshift; /* * pv[i][0] is the function (represented using forward @@ -724,11 +724,12 @@ rasterize_bezier_patch (unsigned char *data, int width, int height, int stride, for (i = 0; i < 4; ++i) { cstart[i] = col[0][i]; cend[i] = col[1][i]; - dcstart[i] = (col[2][i] - col[0][i]) / vsteps; - dcend[i] = (col[3][i] - col[1][i]) / vsteps; + dcstart[i] = (col[2][i] - col[0][i]) / v; + dcend[i] = (col[3][i] - col[1][i]) / v; } - for (v = 0; v <= vsteps; ++v) { + v++; + while (v--) { cairo_point_double_t nodes[4]; for (i = 0; i < 4; ++i) { nodes[i].x = pv[i][0][0]; diff --git a/src/cairo-misc.c b/src/cairo-misc.c index bb37e1a0a..df8a4efc9 100755..100644 --- a/src/cairo-misc.c +++ b/src/cairo-misc.c @@ -156,6 +156,8 @@ cairo_status_to_string (cairo_status_t status) return "invalid operation during mesh pattern construction"; case CAIRO_STATUS_DEVICE_FINISHED: return "the target device has been finished"; + case CAIRO_STATUS_JBIG2_GLOBAL_MISSING: + return "CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID used but no CAIRO_MIME_TYPE_JBIG2_GLOBAL data provided"; default: case CAIRO_STATUS_LAST_STATUS: return "<unknown error status>"; @@ -757,6 +759,24 @@ _cairo_half_from_float (float f) } } +#ifndef __BIONIC__ +# include <locale.h> + +const char * +cairo_get_locale_decimal_point (void) +{ + struct lconv *locale_data = localeconv (); + return locale_data->decimal_point; +} + +#else +/* Android's Bionic libc doesn't provide decimal_point */ +const char * +cairo_get_locale_decimal_point (void) +{ + return '.'; +} +#endif #ifdef _WIN32 diff --git a/src/cairo-mono-scan-converter.c b/src/cairo-mono-scan-converter.c index 2a9546cf8..2a9546cf8 100755..100644 --- a/src/cairo-mono-scan-converter.c +++ b/src/cairo-mono-scan-converter.c diff --git a/src/cairo-mutex-impl-private.h b/src/cairo-mutex-impl-private.h index 25223f3ea..25223f3ea 100755..100644 --- a/src/cairo-mutex-impl-private.h +++ b/src/cairo-mutex-impl-private.h diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h index d79a059ea..f46afadb0 100755..100644 --- a/src/cairo-mutex-list-private.h +++ b/src/cairo-mutex-list-private.h @@ -34,7 +34,6 @@ #ifndef CAIRO_FEATURES_H /* This block is to just make this header file standalone */ #define CAIRO_MUTEX_DECLARE(mutex) -#define CAIRO_RECURSIVE_MUTEX_DECLARE(mutex) #endif CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock) @@ -48,10 +47,6 @@ CAIRO_MUTEX_DECLARE (_cairo_scaled_glyph_page_cache_mutex) CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex) CAIRO_MUTEX_DECLARE (_cairo_glyph_cache_mutex) -#if CAIRO_HAS_TG_SURFACE -CAIRO_RECURSIVE_MUTEX_DECLARE(_cairo_tg_scaled_glyph_mutex) -#endif - #if CAIRO_HAS_FT_FONT CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex) #endif diff --git a/src/cairo-mutex-private.h b/src/cairo-mutex-private.h index 0b806c186..61a7160a0 100755..100644 --- a/src/cairo-mutex-private.h +++ b/src/cairo-mutex-private.h @@ -59,10 +59,8 @@ cairo_private void _cairo_mutex_finalize (void); /* Finally, extern the static mutexes and undef */ #define CAIRO_MUTEX_DECLARE(mutex) cairo_private extern cairo_mutex_t mutex; -#define CAIRO_RECURSIVE_MUTEX_DECLARE(mutex) cairo_private extern cairo_recursive_mutex_t mutex; #include "cairo-mutex-list-private.h" #undef CAIRO_MUTEX_DECLARE -#undef CAIRO_RECURSIVE_MUTEX_DECLARE CAIRO_END_DECLS diff --git a/src/cairo-mutex-type-private.h b/src/cairo-mutex-type-private.h index e8c493985..e8c493985 100755..100644 --- a/src/cairo-mutex-type-private.h +++ b/src/cairo-mutex-type-private.h diff --git a/src/cairo-mutex.c b/src/cairo-mutex.c index 41d5c73f4..0a31dced3 100755..100644 --- a/src/cairo-mutex.c +++ b/src/cairo-mutex.c @@ -36,11 +36,8 @@ #include "cairo-mutex-private.h" #define CAIRO_MUTEX_DECLARE(mutex) cairo_mutex_t mutex = CAIRO_MUTEX_NIL_INITIALIZER; -#define CAIRO_RECURSIVE_MUTEX_DECLARE(mutex) \ - cairo_recursive_mutex_t mutex = CAIRO_RECURSIVE_MUTEX_NIL_INITIALIZER; #include "cairo-mutex-list-private.h" #undef CAIRO_MUTEX_DECLARE -#undef CAIRO_RECURSIVE_MUTEX_DECLARE #if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER @@ -65,10 +62,8 @@ void _cairo_mutex_initialize (void) _cairo_mutex_initialized = TRUE; #define CAIRO_MUTEX_DECLARE(mutex) CAIRO_MUTEX_INIT (mutex); -#define CAIRO_RECURSIVE_MUTEX_DECLARE(mutex) CAIRO_RECURSIVE_MUTEX_INIT (mutex); #include "cairo-mutex-list-private.h" #undef CAIRO_MUTEX_DECLARE -#undef CAIRO_RECURSIVE_MUTEX_DECLARE } #endif @@ -81,9 +76,7 @@ void _cairo_mutex_finalize (void) _cairo_mutex_initialized = FALSE; #define CAIRO_MUTEX_DECLARE(mutex) CAIRO_MUTEX_FINI (mutex); -#define CAIRO_RECURSIVE_MUTEX_DECLARE(mutex) CAIRO_MUTEX_FINI (mutex); #include "cairo-mutex-list-private.h" #undef CAIRO_MUTEX_DECLARE -#undef CAIRO_RECURSIVE_MUTEX_DECLARE } #endif diff --git a/src/cairo-no-compositor.c b/src/cairo-no-compositor.c index 1602a12f6..1602a12f6 100755..100644 --- a/src/cairo-no-compositor.c +++ b/src/cairo-no-compositor.c diff --git a/src/cairo-observer.c b/src/cairo-observer.c index 36d6b93bd..36d6b93bd 100755..100644 --- a/src/cairo-observer.c +++ b/src/cairo-observer.c diff --git a/src/cairo-os2-private.h b/src/cairo-os2-private.h index 829dd3c8d..829dd3c8d 100755..100644 --- a/src/cairo-os2-private.h +++ b/src/cairo-os2-private.h diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c index 1ab50f977..1ab50f977 100755..100644 --- a/src/cairo-os2-surface.c +++ b/src/cairo-os2-surface.c diff --git a/src/cairo-os2.h b/src/cairo-os2.h index d23f2dec4..d23f2dec4 100755..100644 --- a/src/cairo-os2.h +++ b/src/cairo-os2.h diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h index edaabbe78..2542646b8 100755..100644 --- a/src/cairo-output-stream-private.h +++ b/src/cairo-output-stream-private.h @@ -135,6 +135,11 @@ _cairo_output_stream_printf (cairo_output_stream_t *stream, const char *fmt, ...) CAIRO_PRINTF_FORMAT (2, 3); +/* Print matrix element values with rounding of insignificant digits. */ +cairo_private void +_cairo_output_stream_print_matrix (cairo_output_stream_t *stream, + const cairo_matrix_t *matrix); + cairo_private long _cairo_output_stream_get_position (cairo_output_stream_t *stream); diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c index facc182f6..c29ea0e39 100755..100644 --- a/src/cairo-output-stream.c +++ b/src/cairo-output-stream.c @@ -43,7 +43,6 @@ #include "cairo-compiler-private.h" #include <stdio.h> -#include <locale.h> #include <errno.h> /* Numbers printed with %f are printed with this number of significant @@ -303,7 +302,6 @@ _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream, static void _cairo_dtostr (char *buffer, size_t size, double d, cairo_bool_t limited_precision) { - struct lconv *locale_data; const char *decimal_point; int decimal_point_len; char *p; @@ -314,8 +312,7 @@ _cairo_dtostr (char *buffer, size_t size, double d, cairo_bool_t limited_precisi if (d == 0.0) d = 0.0; - locale_data = localeconv (); - decimal_point = locale_data->decimal_point; + decimal_point = cairo_get_locale_decimal_point (); decimal_point_len = strlen (decimal_point); assert (decimal_point_len != 0); @@ -530,6 +527,45 @@ _cairo_output_stream_printf (cairo_output_stream_t *stream, va_end (ap); } +/* Matrix elements that are smaller than the value of the largest element * MATRIX_ROUNDING_TOLERANCE + * are rounded down to zero. */ +#define MATRIX_ROUNDING_TOLERANCE 1e-12 + +void +_cairo_output_stream_print_matrix (cairo_output_stream_t *stream, + const cairo_matrix_t *matrix) +{ + cairo_matrix_t m; + double s, e; + + m = *matrix; + s = fabs (m.xx); + if (fabs (m.xy) > s) + s = fabs (m.xy); + if (fabs (m.yx) > s) + s = fabs (m.yx); + if (fabs (m.yy) > s) + s = fabs (m.yy); + + e = s * MATRIX_ROUNDING_TOLERANCE; + if (fabs(m.xx) < e) + m.xx = 0; + if (fabs(m.xy) < e) + m.xy = 0; + if (fabs(m.yx) < e) + m.yx = 0; + if (fabs(m.yy) < e) + m.yy = 0; + if (fabs(m.x0) < e) + m.x0 = 0; + if (fabs(m.y0) < e) + m.y0 = 0; + + _cairo_output_stream_printf (stream, + "%f %f %f %f %f %f", + m.xx, m.yx, m.xy, m.yy, m.x0, m.y0); +} + long _cairo_output_stream_get_position (cairo_output_stream_t *stream) { diff --git a/src/cairo-paginated-private.h b/src/cairo-paginated-private.h index b827faba0..b827faba0 100755..100644 --- a/src/cairo-paginated-private.h +++ b/src/cairo-paginated-private.h diff --git a/src/cairo-paginated-surface-private.h b/src/cairo-paginated-surface-private.h index ebf4b3424..ebf4b3424 100755..100644 --- a/src/cairo-paginated-surface-private.h +++ b/src/cairo-paginated-surface-private.h diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c index b4580d77b..6d6d6dd1c 100755..100644 --- a/src/cairo-paginated-surface.c +++ b/src/cairo-paginated-surface.c @@ -309,7 +309,7 @@ _paint_fallback_image (cairo_paginated_surface_t *surface, image = _cairo_paginated_surface_create_image_surface (surface, ceil (width * x_scale), ceil (height * y_scale)); - _cairo_surface_set_device_scale (image, x_scale, y_scale); + cairo_surface_set_device_scale (image, x_scale, y_scale); /* set_device_offset just sets the x0/y0 components of the matrix; * so we have to do the scaling manually. */ cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale); diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c index 77f23c887..e8cf0e320 100755..100644 --- a/src/cairo-path-bounds.c +++ b/src/cairo-path-bounds.c @@ -221,7 +221,7 @@ _cairo_path_fixed_approximate_stroke_exact_extents (const cairo_path_fixed_t *pa box_extents.p1.y -= _cairo_fixed_from_double (dy); box_extents.p2.x += _cairo_fixed_from_double (dx); box_extents.p2.y += _cairo_fixed_from_double (dy); - + _cairo_box_to_doubles (&box_extents, &x1, &y1, &x2, &y2); extents->x = x1; diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c index b38c2a8d3..4000c9c58 100755..100644 --- a/src/cairo-path-fill.c +++ b/src/cairo-path-fill.c @@ -339,4 +339,3 @@ _cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path, antialias, boxes); } - diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h index cf7cd0836..adc3b532b 100755..100644 --- a/src/cairo-path-fixed-private.h +++ b/src/cairo-path-fixed-private.h @@ -101,6 +101,7 @@ typedef struct _cairo_path_buf_fixed { struct _cairo_path_fixed { cairo_point_t last_move_point; cairo_point_t current_point; + cairo_point_t start_point; unsigned int has_current_point : 1; unsigned int needs_move_to : 1; unsigned int has_extents : 1; @@ -113,6 +114,7 @@ struct _cairo_path_fixed { cairo_box_t extents; cairo_path_buf_fixed_t buf; + unsigned int is_convex : 1; }; cairo_private void diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index 2c198815d..5d57a61ec 100755..100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -86,6 +86,7 @@ _cairo_path_fixed_init (cairo_path_fixed_t *path) path->current_point.x = 0; path->current_point.y = 0; path->last_move_point = path->current_point; + path->start_point = path->current_point; path->has_current_point = FALSE; path->needs_move_to = TRUE; @@ -95,6 +96,7 @@ _cairo_path_fixed_init (cairo_path_fixed_t *path) path->fill_is_rectilinear = TRUE; path->fill_maybe_region = TRUE; path->fill_is_empty = TRUE; + path->is_convex = TRUE; path->extents.p1.x = path->extents.p1.y = 0; path->extents.p2.x = path->extents.p2.y = 0; @@ -132,6 +134,9 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path, path->buf.base.num_ops = other->buf.base.num_ops; path->buf.base.num_points = other->buf.base.num_points; + + path->is_convex = other->is_convex; + memcpy (path->buf.op, other->buf.base.op, other->buf.base.num_ops * sizeof (other->buf.op[0])); memcpy (path->buf.points, other->buf.points, @@ -408,6 +413,11 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path, path->current_point.y = y; path->last_move_point = path->current_point; + if (_cairo_path_fixed_is_empty (path)) + path->is_convex = TRUE; + else + path->is_convex = FALSE; + return CAIRO_STATUS_SUCCESS; } @@ -450,6 +460,11 @@ _cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path) path->needs_move_to = TRUE; } + if (_cairo_path_fixed_is_empty (path)) + path->is_convex = TRUE; + else + path->is_convex = FALSE; + path->has_current_point = FALSE; } @@ -548,6 +563,13 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path, _cairo_box_add_point (&path->extents, &point); + /* if line to point does not match start point, is_convex false */ + if (path->is_convex) { + if (path->start_point.x != x && + path->start_point.y != y) + path->is_convex = FALSE; + } + return _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1); } @@ -620,6 +642,8 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path, path->fill_maybe_region = FALSE; path->fill_is_empty = FALSE; + path->is_convex = FALSE; + return _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3); } @@ -847,6 +871,9 @@ _cairo_path_fixed_interpret (const cairo_path_fixed_t *path, } } cairo_path_foreach_buf_end (buf, path); + if (path->needs_move_to && path->has_current_point) + return (*move_to) (closure, &path->current_point); + return CAIRO_STATUS_SUCCESS; } @@ -965,8 +992,19 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path, path->extents.p1.x = _cairo_fixed_mul (scalex, path->extents.p1.x) + offx; path->extents.p2.x = _cairo_fixed_mul (scalex, path->extents.p2.x) + offx; + if (scalex < 0) { + cairo_fixed_t t = path->extents.p1.x; + path->extents.p1.x = path->extents.p2.x; + path->extents.p2.x = t; + } + path->extents.p1.y = _cairo_fixed_mul (scaley, path->extents.p1.y) + offy; path->extents.p2.y = _cairo_fixed_mul (scaley, path->extents.p2.y) + offy; + if (scaley < 0) { + cairo_fixed_t t = path->extents.p1.y; + path->extents.p1.y = path->extents.p2.y; + path->extents.p2.y = t; + } } void @@ -1289,7 +1327,7 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path, } /* Determine whether two lines A->B and C->D intersect based on the - * algorithm described here: http://paulbourke.net/geometry/lineline2d/ */ + * algorithm described here: http://paulbourke.net/geometry/pointlineplane/ */ static inline cairo_bool_t _lines_intersect_or_are_coincident (cairo_point_t a, cairo_point_t b, @@ -1297,6 +1335,7 @@ _lines_intersect_or_are_coincident (cairo_point_t a, cairo_point_t d) { cairo_int64_t numerator_a, numerator_b, denominator; + cairo_bool_t denominator_negative; denominator = _cairo_int64_sub (_cairo_int32x32_64_mul (d.y - c.y, b.x - a.x), _cairo_int32x32_64_mul (d.x - c.x, b.y - a.y)); @@ -1316,20 +1355,34 @@ _lines_intersect_or_are_coincident (cairo_point_t a, return FALSE; } - /* If either division would produce a number between 0 and 1, i.e. - * the numerator is smaller than the denominator and their signs are - * the same, then the lines intersect. */ - if (_cairo_int64_lt (numerator_a, denominator) && - ! (_cairo_int64_negative (numerator_a) ^ _cairo_int64_negative(denominator))) { - return TRUE; - } + /* The lines intersect if both quotients are between 0 and 1 (exclusive). */ - if (_cairo_int64_lt (numerator_b, denominator) && - ! (_cairo_int64_negative (numerator_b) ^ _cairo_int64_negative(denominator))) { - return TRUE; + /* We first test whether either quotient is a negative number. */ + denominator_negative = _cairo_int64_negative (denominator); + if (_cairo_int64_negative (numerator_a) ^ denominator_negative) + return FALSE; + if (_cairo_int64_negative (numerator_b) ^ denominator_negative) + return FALSE; + + /* A zero quotient indicates an "intersection" at an endpoint, which + * we aren't considering a true intersection. */ + if (_cairo_int64_is_zero (numerator_a) || _cairo_int64_is_zero (numerator_b)) + return FALSE; + + /* If the absolute value of the numerator is larger than or equal to the + * denominator the result of the division would be greater than or equal + * to one. */ + if (! denominator_negative) { + if (! _cairo_int64_lt (numerator_a, denominator) || + ! _cairo_int64_lt (numerator_b, denominator)) + return FALSE; + } else { + if (! _cairo_int64_lt (denominator, numerator_a) || + ! _cairo_int64_lt (denominator, numerator_b)) + return FALSE; } - return FALSE; + return TRUE; } cairo_bool_t @@ -1454,6 +1507,19 @@ _cairo_path_fixed_is_single_line (const cairo_path_fixed_t *path) } cairo_bool_t +_cairo_path_fixed_is_empty (const cairo_path_fixed_t *path) +{ + unsigned int i; + const cairo_path_buf_t *buf = cairo_path_head (path); + for (i = 0; i < buf->num_ops; i++) { + if (buf->op[i] != CAIRO_PATH_OP_MOVE_TO) + return FALSE; + } + + return TRUE; +} + +cairo_bool_t _cairo_path_fixed_is_single_arc (const cairo_path_fixed_t *path) { const cairo_path_buf_t *buf = cairo_path_head (path); diff --git a/src/cairo-path-in-fill.c b/src/cairo-path-in-fill.c index 1787fb1a3..1787fb1a3 100755..100644 --- a/src/cairo-path-in-fill.c +++ b/src/cairo-path-in-fill.c diff --git a/src/cairo-path-private.h b/src/cairo-path-private.h index 7b54317e2..7b54317e2 100755..100644 --- a/src/cairo-path-private.h +++ b/src/cairo-path-private.h diff --git a/src/cairo-path-stroke-boxes.c b/src/cairo-path-stroke-boxes.c index 7f25bf76c..7f25bf76c 100755..100644 --- a/src/cairo-path-stroke-boxes.c +++ b/src/cairo-path-stroke-boxes.c diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c index b62ddfb8f..83e40854e 100755..100644 --- a/src/cairo-path-stroke-polygon.c +++ b/src/cairo-path-stroke-polygon.c @@ -1083,7 +1083,6 @@ spline_to (void *closure, _cairo_contour_add_point (&stroker->path, point); #endif if ((tangent->dx | tangent->dy) == 0) { - const cairo_point_t *inpt, *outpt; struct stroke_contour *outer; cairo_point_t t; int clockwise; @@ -1101,12 +1100,8 @@ spline_to (void *closure, clockwise = join_is_clockwise (&stroker->current_face, &face); if (clockwise) { - inpt = &stroker->current_face.cw; - outpt = &face.cw; outer = &stroker->cw; } else { - inpt = &stroker->current_face.ccw; - outpt = &face.ccw; outer = &stroker->ccw; } @@ -1121,7 +1116,6 @@ spline_to (void *closure, if ((face.dev_slope.x * stroker->current_face.dev_slope.x + face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance) { - const cairo_point_t *inpt, *outpt; struct stroke_contour *outer; int clockwise = join_is_clockwise (&stroker->current_face, &face); @@ -1134,12 +1128,8 @@ spline_to (void *closure, contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw); if (clockwise) { - inpt = &stroker->current_face.cw; - outpt = &face.cw; outer = &stroker->cw; } else { - inpt = &stroker->current_face.ccw; - outpt = &face.ccw; outer = &stroker->ccw; } add_fan (stroker, diff --git a/src/cairo-path-stroke-traps.c b/src/cairo-path-stroke-traps.c index f95321491..03638961c 100755..100644 --- a/src/cairo-path-stroke-traps.c +++ b/src/cairo-path-stroke-traps.c @@ -249,9 +249,11 @@ join (struct stroker *stroker, in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance) { int start, stop; - cairo_point_t tri[3]; + cairo_point_t tri[3], edges[4]; cairo_pen_t *pen = &stroker->pen; + edges[0] = in->cw; + edges[1] = in->ccw; tri[0] = in->point; tri[1] = *inpt; if (clockwise) { @@ -261,8 +263,13 @@ join (struct stroker *stroker, while (start != stop) { tri[2] = in->point; translate_point (&tri[2], &pen->vertices[start].point); - _cairo_traps_tessellate_triangle (stroker->traps, tri); + edges[2] = in->point; + edges[3] = tri[2]; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, + tri, edges); tri[1] = tri[2]; + edges[0] = edges[2]; + edges[1] = edges[3]; if (start-- == 0) start += pen->num_vertices; @@ -274,17 +281,30 @@ join (struct stroker *stroker, while (start != stop) { tri[2] = in->point; translate_point (&tri[2], &pen->vertices[start].point); - _cairo_traps_tessellate_triangle (stroker->traps, tri); + edges[2] = in->point; + edges[3] = tri[2]; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, + tri, edges); tri[1] = tri[2]; + edges[0] = edges[2]; + edges[1] = edges[3]; if (++start == pen->num_vertices) start = 0; } } tri[2] = *outpt; - _cairo_traps_tessellate_triangle (stroker->traps, tri); - break; + edges[2] = out->cw; + edges[3] = out->ccw; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, + tri, edges); + } else { + cairo_point_t t[] = { { in->point.x, in->point.y}, { inpt->x, inpt->y }, { outpt->x, outpt->y } }; + cairo_point_t e[] = { { in->cw.x, in->cw.y}, { in->ccw.x, in->ccw.y }, + { out->cw.x, out->cw.y}, { out->ccw.x, out->ccw.y } }; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, t, e); } + break; case CAIRO_LINE_JOIN_MITER: default: { @@ -442,12 +462,10 @@ join (struct stroker *stroker, } case CAIRO_LINE_JOIN_BEVEL: { - cairo_point_t tri[3]; - tri[0] = in->point; - tri[1] = *inpt; - tri[2] = *outpt; - - _cairo_traps_tessellate_triangle (stroker->traps, tri); + cairo_point_t t[] = { { in->point.x, in->point.y }, { inpt->x, inpt->y }, { outpt->x, outpt->y } }; + cairo_point_t e[] = { { in->cw.x, in->cw.y }, { in->ccw.x, in->ccw.y }, + { out->cw.x, out->cw.y }, { out->ccw.x, out->ccw.y } }; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, t, e); break; } } @@ -460,7 +478,7 @@ add_cap (struct stroker *stroker, cairo_stroke_face_t *f) case CAIRO_LINE_CAP_ROUND: { int start, stop; cairo_slope_t in_slope, out_slope; - cairo_point_t tri[3]; + cairo_point_t tri[3], edges[4]; cairo_pen_t *pen = &stroker->pen; in_slope = f->dev_vector; @@ -468,19 +486,29 @@ add_cap (struct stroker *stroker, cairo_stroke_face_t *f) out_slope.dy = -in_slope.dy; _cairo_pen_find_active_cw_vertices (pen, &in_slope, &out_slope, &start, &stop); + edges[0] = f->cw; + edges[1] = f->ccw; tri[0] = f->point; tri[1] = f->cw; while (start != stop) { tri[2] = f->point; translate_point (&tri[2], &pen->vertices[start].point); - _cairo_traps_tessellate_triangle (stroker->traps, tri); + edges[2] = f->point; + edges[3] = tri[2]; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, + tri, edges); tri[1] = tri[2]; + edges[0] = edges[2]; + edges[1] = edges[3]; if (++start == pen->num_vertices) start = 0; } tri[2] = f->ccw; - _cairo_traps_tessellate_triangle (stroker->traps, tri); + edges[2] = f->cw; + edges[3] = f->ccw; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, + tri, edges); break; } @@ -937,7 +965,6 @@ spline_to (void *closure, cairo_point_t rectangle[4]; compute_face (&stroker->current_face.point, tangent, stroker, &face); - join (stroker, &stroker->current_face, &face); rectangle[0] = face.cw; @@ -1024,7 +1051,7 @@ curve_to_dashed (void *closure, func = (cairo_spline_add_point_func_t)line_to_dashed; if (stroker->has_bounds && - ! _cairo_spline_intersects (&stroker->current_face.point, b, c, b, + ! _cairo_spline_intersects (&stroker->current_face.point, b, c, d, &stroker->line_bounds)) return func (closure, d, NULL); diff --git a/src/cairo-path-stroke-tristrip.c b/src/cairo-path-stroke-tristrip.c index 3c232986b..3c232986b 100755..100644 --- a/src/cairo-path-stroke-tristrip.c +++ b/src/cairo-path-stroke-tristrip.c diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c index 73c554bd8..5c260c915 100755..100644 --- a/src/cairo-path-stroke.c +++ b/src/cairo-path-stroke.c @@ -54,6 +54,7 @@ typedef struct cairo_stroker { const cairo_matrix_t *ctm_inverse; double half_line_width; double tolerance; + double spline_cusp_tolerance; double ctm_determinant; cairo_bool_t ctm_det_positive; @@ -177,6 +178,18 @@ _cairo_stroker_init (cairo_stroker_t *stroker, stroker->tolerance = tolerance; stroker->half_line_width = stroke_style->line_width / 2.0; + /* To test whether we need to join two segments of a spline using + * a round-join or a bevel-join, we can inspect the angle between the + * two segments. If the difference between the chord distance + * (half-line-width times the cosine of the bisection angle) and the + * half-line-width itself is greater than tolerance then we need to + * inject a point. + */ + stroker->spline_cusp_tolerance = 1 - tolerance / stroker->half_line_width; + stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance; + stroker->spline_cusp_tolerance *= 2; + stroker->spline_cusp_tolerance -= 1; + stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm); stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0; @@ -1052,39 +1065,61 @@ _cairo_stroker_spline_to (void *closure, slope_dy = _cairo_fixed_to_double (tangent->dy); if (! _compute_normalized_device_slope (&slope_dx, &slope_dy, - stroker->ctm_inverse, NULL)) + stroker->ctm_inverse, NULL)) return CAIRO_STATUS_SUCCESS; _compute_face (point, tangent, slope_dx, slope_dy, stroker, &new_face); - assert(stroker->has_current_face); - - if (_cairo_stroke_segment_intersect (&stroker->current_face.cw, - &stroker->current_face.ccw, - &new_face.cw, - &new_face.ccw, - &intersect_point)) { - points[0] = stroker->current_face.ccw; - points[1] = new_face.ccw; - points[2] = intersect_point; - stroker->add_triangle (stroker->closure, points); - - points[0] = stroker->current_face.cw; - points[1] = new_face.cw; - stroker->add_triangle (stroker->closure, points); + assert (stroker->has_current_face); + + if ((new_face.dev_slope.x * stroker->current_face.dev_slope.x + + new_face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance) { + + const cairo_point_t *inpt, *outpt; + int clockwise = _cairo_stroker_join_is_clockwise (&new_face, + &stroker->current_face); + + if (clockwise) { + inpt = &stroker->current_face.cw; + outpt = &new_face.cw; + } else { + inpt = &stroker->current_face.ccw; + outpt = &new_face.ccw; + } + + _tessellate_fan (stroker, + &stroker->current_face.dev_vector, + &new_face.dev_vector, + &stroker->current_face.point, + inpt, outpt, + clockwise); } - else { - points[0] = stroker->current_face.ccw; - points[1] = stroker->current_face.cw; - points[2] = new_face.cw; - stroker->add_triangle (stroker->closure, points); - - points[0] = stroker->current_face.ccw; - points[1] = new_face.cw; - points[2] = new_face.ccw; - stroker->add_triangle (stroker->closure, points); + + if (_slow_segment_intersection (&stroker->current_face.cw, + &stroker->current_face.ccw, + &new_face.cw, + &new_face.ccw, + &intersect_point)) { + points[0] = stroker->current_face.ccw; + points[1] = new_face.ccw; + points[2] = intersect_point; + stroker->add_triangle (stroker->closure, points); + + points[0] = stroker->current_face.cw; + points[1] = new_face.cw; + stroker->add_triangle (stroker->closure, points); + } else { + points[0] = stroker->current_face.ccw; + points[1] = stroker->current_face.cw; + points[2] = new_face.cw; + stroker->add_triangle (stroker->closure, points); + + points[0] = stroker->current_face.ccw; + points[1] = new_face.cw; + points[2] = new_face.ccw; + stroker->add_triangle (stroker->closure, points); } /* compute join */ diff --git a/src/cairo-path.c b/src/cairo-path.c index 43cd175a3..6ca06a74e 100755..100644 --- a/src/cairo-path.c +++ b/src/cairo-path.c @@ -342,7 +342,7 @@ _cairo_path_create_internal (cairo_path_fixed_t *path_fixed, path->data = NULL; path->status = CAIRO_STATUS_SUCCESS; } - + path->is_convex = path_fixed->is_convex; return path; } diff --git a/src/cairo-pattern-inline.h b/src/cairo-pattern-inline.h index 97e8ea034..97e8ea034 100755..100644 --- a/src/cairo-pattern-inline.h +++ b/src/cairo-pattern-inline.h diff --git a/src/cairo-pattern-private.h b/src/cairo-pattern-private.h index a0092b135..5914b45f6 100755..100644 --- a/src/cairo-pattern-private.h +++ b/src/cairo-pattern-private.h @@ -259,6 +259,10 @@ cairo_private void _cairo_pattern_transform (cairo_pattern_t *pattern, const cairo_matrix_t *ctm_inverse); +cairo_private void +_cairo_pattern_pretransform (cairo_pattern_t *pattern, + const cairo_matrix_t *ctm); + cairo_private cairo_bool_t _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern); @@ -307,7 +311,7 @@ _cairo_mesh_pattern_coord_box (const cairo_mesh_pattern_t *mesh, double *out_xmax, double *out_ymax); -cairo_private_no_warn cairo_filter_t +cairo_private void _cairo_pattern_sampled_area (const cairo_pattern_t *pattern, const cairo_rectangle_int_t *extents, cairo_rectangle_int_t *sample); @@ -350,6 +354,9 @@ cairo_private cairo_bool_t _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b); +cairo_private cairo_filter_t +_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern); + /* cairo-mesh-pattern-rasterizer.c */ cairo_private void @@ -380,7 +387,7 @@ _cairo_raster_source_pattern_init_copy (cairo_pattern_t *pattern, cairo_private void _cairo_raster_source_pattern_finish (cairo_pattern_t *abstract_pattern); -cairo_private cairo_status_t +cairo_private cairo_status_t _cairo_pattern_create_gaussian_matrix (cairo_pattern_t *pattern, double line_width); diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 4d6094ba2..c7d269caa 100755..100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -51,8 +51,8 @@ * @See_Also: #cairo_t, #cairo_surface_t * * #cairo_pattern_t is the paint with which cairo draws. - * The primary use of patterns is as the source for all cairo drawing - * operations, although they can also be used as masks, that is, as the + * The primary use of patterns is as the source for all cairo drawing + * operations, although they can also be used as masks, that is, as the * brush too. * * A cairo pattern is created by using one of the many constructors, @@ -2158,6 +2158,16 @@ cairo_pattern_get_extend (cairo_pattern_t *pattern) slim_hidden_def (cairo_pattern_get_extend); void +_cairo_pattern_pretransform (cairo_pattern_t *pattern, + const cairo_matrix_t *ctm) +{ + if (pattern->status) + return; + + cairo_matrix_multiply (&pattern->matrix, &pattern->matrix, ctm); +} + +void _cairo_pattern_transform (cairo_pattern_t *pattern, const cairo_matrix_t *ctm_inverse) { @@ -3358,111 +3368,180 @@ _cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern) return FALSE; } +/* + * Will given row of back-translation matrix work with bilinear scale? + * This is true for scales larger than 1. Also it was judged acceptable + * for scales larger than .75. And if there is integer translation + * then a scale of exactly .5 works. + */ +static int +use_bilinear(double x, double y, double t) +{ + /* This is the inverse matrix! */ + double h = x*x + y*y; + if (h < 1.0 / (0.75 * 0.75)) + return TRUE; /* scale > .75 */ + if ((h > 3.99 && h < 4.01) /* scale is 1/2 */ + && !_cairo_fixed_from_double(x*y) /* parallel to an axis */ + && _cairo_fixed_is_integer (_cairo_fixed_from_double (t))) + return TRUE; + return FALSE; +} + /** * _cairo_pattern_analyze_filter: * @pattern: surface pattern - * @pad_out: location to store necessary padding in the source image, or %NULL * Returns: the optimized #cairo_filter_t to use with @pattern. * - * Analyze the filter to determine how much extra needs to be sampled - * from the source image to account for the filter radius and whether - * we can optimize the filter to a simpler value. - * - * XXX: We don't actually have any way of querying the backend for - * the filter radius, so we just guess base on what we know that - * backends do currently (see bug #10508) + * Possibly optimize the filter to a simpler value depending on transformation **/ cairo_filter_t -_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern, - double *pad_out) +_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern) { - double pad; - cairo_filter_t optimized_filter; - switch (pattern->filter) { case CAIRO_FILTER_GOOD: case CAIRO_FILTER_BEST: case CAIRO_FILTER_BILINEAR: + case CAIRO_FILTER_FAST: /* If source pixels map 1:1 onto destination pixels, we do * not need to filter (and do not want to filter, since it * will cause blurriness) */ if (_cairo_matrix_is_pixel_exact (&pattern->matrix)) { - pad = 0.; - optimized_filter = CAIRO_FILTER_NEAREST; + return CAIRO_FILTER_NEAREST; } else { - /* 0.5 is enough for a bilinear filter. It's possible we - * should defensively use more for CAIRO_FILTER_BEST, but - * without a single example, it's hard to know how much - * more would be defensive... + /* Use BILINEAR for any scale greater than .75 instead + * of GOOD. For scales of 1 and larger this is identical, + * for the smaller sizes it was judged that the artifacts + * were not worse than the artifacts from a box filer. + * BILINEAR can also be used if the scale is exactly .5 + * and the translation in that direction is an integer. */ - pad = 0.5; - optimized_filter = pattern->filter; + if (pattern->filter == CAIRO_FILTER_GOOD && + use_bilinear (pattern->matrix.xx, pattern->matrix.xy, + pattern->matrix.x0) && + use_bilinear (pattern->matrix.yx, pattern->matrix.yy, + pattern->matrix.y0)) + return CAIRO_FILTER_BILINEAR; } break; - case CAIRO_FILTER_FAST: case CAIRO_FILTER_NEAREST: case CAIRO_FILTER_GAUSSIAN: default: - pad = 0.; - optimized_filter = pattern->filter; break; } - if (pad_out) - *pad_out = pad; + return pattern->filter; +} - return optimized_filter; +/** + * _cairo_hypot: + * Returns: value similar to hypot(@x,@y) + * + * May want to replace this with Manhattan distance (abs(x)+abs(y)) if + * hypot is too slow, as there is no need for accuracy here. + **/ +static inline double +_cairo_hypot(double x, double y) +{ + return hypot(x, y); } -cairo_filter_t +/** + * _cairo_pattern_sampled_area: + * + * Return region of @pattern that will be sampled to fill @extents, + * based on the transformation and filter. + * + * This does not include pixels that are mulitiplied by values very + * close to zero by the ends of filters. This is so that transforms + * that should be the identity or 90 degree rotations do not expand + * the source unexpectedly. + * + * XXX: We don't actually have any way of querying the backend for + * the filter radius, so we just guess base on what we know that + * backends do currently (see bug #10508) + **/ +void _cairo_pattern_sampled_area (const cairo_pattern_t *pattern, const cairo_rectangle_int_t *extents, cairo_rectangle_int_t *sample) { - cairo_filter_t filter; double x1, x2, y1, y2; - double pad; + double padx, pady; - filter = _cairo_pattern_analyze_filter (pattern, &pad); - if (pad == 0.0 && _cairo_matrix_is_identity (&pattern->matrix)) { + /* Assume filters are interpolating, which means identity + cannot change the image */ + if (_cairo_matrix_is_identity (&pattern->matrix)) { *sample = *extents; - return filter; + return; } - x1 = extents->x; - y1 = extents->y; - x2 = extents->x + (int) extents->width; - y2 = extents->y + (int) extents->height; - + /* Transform the centers of the corner pixels */ + x1 = extents->x + 0.5; + y1 = extents->y + 0.5; + x2 = x1 + (extents->width - 1); + y2 = y1 + (extents->height - 1); _cairo_matrix_transform_bounding_box (&pattern->matrix, &x1, &y1, &x2, &y2, NULL); - if (x1 > CAIRO_RECT_INT_MIN) - sample->x = floor (x1 - pad); - else - sample->x = CAIRO_RECT_INT_MIN; - if (y1 > CAIRO_RECT_INT_MIN) - sample->y = floor (y1 - pad); - else - sample->y = CAIRO_RECT_INT_MIN; + /* How far away from center will it actually sample? + * This is the distance from a transformed pixel center to the + * furthest sample of reasonable size. + */ + switch (pattern->filter) { + case CAIRO_FILTER_NEAREST: + case CAIRO_FILTER_FAST: + /* Correct value is zero, but when the sample is on an integer + * it is unknown if the backend will sample the pixel to the + * left or right. This value makes it include both possible pixels. + */ + padx = pady = 0.004; + break; + case CAIRO_FILTER_BILINEAR: + case CAIRO_FILTER_GAUSSIAN: + default: + /* Correct value is .5 */ + padx = pady = 0.495; + break; + case CAIRO_FILTER_GOOD: + /* Correct value is max(width,1)*.5 */ + padx = _cairo_hypot (pattern->matrix.xx, pattern->matrix.xy); + if (padx <= 1.0) padx = 0.495; + else if (padx >= 16.0) padx = 7.92; + else padx *= 0.495; + pady = _cairo_hypot (pattern->matrix.yx, pattern->matrix.yy); + if (pady <= 1.0) pady = 0.495; + else if (pady >= 16.0) pady = 7.92; + else pady *= 0.495; + break; + case CAIRO_FILTER_BEST: + /* Correct value is width*2 */ + padx = _cairo_hypot (pattern->matrix.xx, pattern->matrix.xy) * 1.98; + if (padx > 7.92) padx = 7.92; + pady = _cairo_hypot (pattern->matrix.yx, pattern->matrix.yy) * 1.98; + if (pady > 7.92) pady = 7.92; + break; + } - if (x2 < CAIRO_RECT_INT_MAX) - sample->width = ceil (x2 + pad); - else - sample->width = CAIRO_RECT_INT_MAX; + /* round furthest samples to edge of pixels */ + x1 = floor (x1 - padx); + if (x1 < CAIRO_RECT_INT_MIN) x1 = CAIRO_RECT_INT_MIN; + sample->x = x1; - if (y2 < CAIRO_RECT_INT_MAX) - sample->height = ceil (y2 + pad); - else - sample->height = CAIRO_RECT_INT_MAX; + y1 = floor (y1 - pady); + if (y1 < CAIRO_RECT_INT_MIN) y1 = CAIRO_RECT_INT_MIN; + sample->y = y1; - sample->width -= sample->x; - sample->height -= sample->y; + x2 = floor (x2 + padx) + 1.0; + if (x2 > CAIRO_RECT_INT_MAX) x2 = CAIRO_RECT_INT_MAX; + sample->width = x2 - x1; - return filter; + y2 = floor (y2 + pady) + 1.0; + if (y2 > CAIRO_RECT_INT_MAX) y2 = CAIRO_RECT_INT_MAX; + sample->height = y2 - y1; } /** @@ -3482,7 +3561,9 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, cairo_rectangle_int_t *extents) { double x1, y1, x2, y2; - cairo_status_t status; + int ix1, ix2, iy1, iy2; + cairo_bool_t round_x = FALSE; + cairo_bool_t round_y = FALSE; switch (pattern->type) { case CAIRO_PATTERN_TYPE_SOLID: @@ -3494,7 +3575,6 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, const cairo_surface_pattern_t *surface_pattern = (const cairo_surface_pattern_t *) pattern; cairo_surface_t *surface = surface_pattern->surface; - double pad; if (! _cairo_surface_get_extents (surface, &surface_extents)) goto UNBOUNDED; @@ -3505,14 +3585,12 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, if (pattern->extend != CAIRO_EXTEND_NONE) goto UNBOUNDED; - /* The filter can effectively enlarge the extents of the - * pattern, so extend as necessary. - */ - _cairo_pattern_analyze_filter (&surface_pattern->base, &pad); - x1 = surface_extents.x - pad; - y1 = surface_extents.y - pad; - x2 = surface_extents.x + (int) surface_extents.width + pad; - y2 = surface_extents.y + (int) surface_extents.height + pad; + x1 = surface_extents.x; + y1 = surface_extents.y; + x2 = surface_extents.x + (int) surface_extents.width; + y2 = surface_extents.y + (int) surface_extents.height; + + goto HANDLE_FILTER; } break; @@ -3520,7 +3598,6 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, { const cairo_raster_source_pattern_t *raster = (const cairo_raster_source_pattern_t *) pattern; - double pad; if (raster->extents.width == 0 || raster->extents.height == 0) goto EMPTY; @@ -3528,14 +3605,41 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, if (pattern->extend != CAIRO_EXTEND_NONE) goto UNBOUNDED; - /* The filter can effectively enlarge the extents of the - * pattern, so extend as necessary. - */ - _cairo_pattern_analyze_filter (pattern, &pad); - x1 = raster->extents.x - pad; - y1 = raster->extents.y - pad; - x2 = raster->extents.x + (int) raster->extents.width + pad; - y2 = raster->extents.y + (int) raster->extents.height + pad; + x1 = raster->extents.x; + y1 = raster->extents.y; + x2 = raster->extents.x + (int) raster->extents.width; + y2 = raster->extents.y + (int) raster->extents.height; + } + HANDLE_FILTER: + switch (pattern->filter) { + case CAIRO_FILTER_NEAREST: + case CAIRO_FILTER_FAST: + round_x = round_y = TRUE; + /* We don't know which way .5 will go, so fudge it slightly. */ + x1 -= 0.004; + y1 -= 0.004; + x2 += 0.004; + y2 += 0.004; + break; + case CAIRO_FILTER_BEST: + /* Assume best filter will produce nice antialiased edges */ + break; + case CAIRO_FILTER_BILINEAR: + case CAIRO_FILTER_GAUSSIAN: + case CAIRO_FILTER_GOOD: + default: + /* These filters can blur the edge out 1/2 pixel when scaling up */ + if (_cairo_hypot (pattern->matrix.xx, pattern->matrix.yx) < 1.0) { + x1 -= 0.5; + x2 += 0.5; + round_x = TRUE; + } + if (_cairo_hypot (pattern->matrix.xy, pattern->matrix.yy) < 1.0) { + y1 -= 0.5; + y2 += 0.5; + round_y = TRUE; + } + break; } break; @@ -3607,6 +3711,10 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, } else { goto UNBOUNDED; } + + /* The current linear renderer just point-samples in the middle + of the pixels, similar to the NEAREST filter: */ + round_x = round_y = TRUE; } break; @@ -3614,22 +3722,8 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, { const cairo_mesh_pattern_t *mesh = (const cairo_mesh_pattern_t *) pattern; - double padx, pady; - cairo_bool_t is_valid; - - is_valid = _cairo_mesh_pattern_coord_box (mesh, &x1, &y1, &x2, &y2); - if (!is_valid) + if (! _cairo_mesh_pattern_coord_box (mesh, &x1, &y1, &x2, &y2)) goto EMPTY; - - padx = pady = 1.; - cairo_matrix_transform_distance (&pattern->matrix, &padx, &pady); - padx = fabs (padx); - pady = fabs (pady); - - x1 -= padx; - y1 -= pady; - x2 += padx; - y2 += pady; } break; @@ -3642,6 +3736,7 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, y1 -= pattern->matrix.y0; y2 -= pattern->matrix.y0; } else { cairo_matrix_t imatrix; + cairo_status_t status; imatrix = pattern->matrix; status = cairo_matrix_invert (&imatrix); @@ -3653,22 +3748,34 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, NULL); } - x1 = floor (x1); + if (!round_x) { + x1 -= 0.5; + x2 += 0.5; + } if (x1 < CAIRO_RECT_INT_MIN) - x1 = CAIRO_RECT_INT_MIN; - y1 = floor (y1); - if (y1 < CAIRO_RECT_INT_MIN) - y1 = CAIRO_RECT_INT_MIN; - - x2 = ceil (x2); + ix1 = CAIRO_RECT_INT_MIN; + else + ix1 = _cairo_lround (x1); if (x2 > CAIRO_RECT_INT_MAX) - x2 = CAIRO_RECT_INT_MAX; - y2 = ceil (y2); + ix2 = CAIRO_RECT_INT_MAX; + else + ix2 = _cairo_lround (x2); + extents->x = ix1; extents->width = ix2 - ix1; + + if (!round_y) { + y1 -= 0.5; + y2 += 0.5; + } + if (y1 < CAIRO_RECT_INT_MIN) + iy1 = CAIRO_RECT_INT_MIN; + else + iy1 = _cairo_lround (y1); if (y2 > CAIRO_RECT_INT_MAX) - y2 = CAIRO_RECT_INT_MAX; + iy2 = CAIRO_RECT_INT_MAX; + else + iy2 = _cairo_lround (y2); + extents->y = iy1; extents->height = iy2 - iy1; - extents->x = x1; extents->width = x2 - x1; - extents->y = y1; extents->height = y2 - y1; return; UNBOUNDED: @@ -4251,7 +4358,7 @@ cairo_pattern_get_rgba (cairo_pattern_t *pattern, * cairo_pattern_get_surface: * @pattern: a #cairo_pattern_t * @surface: return value for surface of pattern, or %NULL - * + * * Gets the surface of a surface pattern. The reference returned in * @surface is owned by the pattern; the caller should call * cairo_surface_reference() if the surface is to be retained. @@ -4291,8 +4398,9 @@ cairo_pattern_get_surface (cairo_pattern_t *pattern, * @alpha: return value for alpha component of color, or %NULL * * Gets the color and offset information at the given @index for a - * gradient pattern. Values of @index are 0 to 1 less than the number - * returned by cairo_pattern_get_color_stop_count(). + * gradient pattern. Values of @index range from 0 to n-1 + * where n is the number returned + * by cairo_pattern_get_color_stop_count(). * * Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX * if @index is not valid for the given pattern. If the pattern is @@ -4502,7 +4610,7 @@ slim_hidden_def (cairo_mesh_pattern_get_patch_count); * Gets path defining the patch @patch_num for a mesh * pattern. * - * @patch_num can range 0 to 1 less than the number returned by + * @patch_num can range from 0 to n-1 where n is the number returned by * cairo_mesh_pattern_get_patch_count(). * * Return value: the path defining the patch, or a path with status @@ -4598,7 +4706,7 @@ slim_hidden_def (cairo_mesh_pattern_get_path); * Gets the color information in corner @corner_num of patch * @patch_num for a mesh pattern. * - * @patch_num can range 0 to 1 less than the number returned by + * @patch_num can range from 0 to n-1 where n is the number returned by * cairo_mesh_pattern_get_patch_count(). * * Valid values for @corner_num are from 0 to 3 and identify the @@ -4666,7 +4774,7 @@ slim_hidden_def (cairo_mesh_pattern_get_corner_color_rgba); * Gets the control point @point_num of patch @patch_num for a mesh * pattern. * - * @patch_num can range 0 to 1 less than the number returned by + * @patch_num can range from 0 to n-1 where n is the number returned by * cairo_mesh_pattern_get_patch_count(). * * Valid values for @point_num are from 0 to 3 and identify the @@ -4840,7 +4948,7 @@ _cairo_pattern_create_gaussian_matrix (cairo_pattern_t *pattern, break; x_sigma /= 2.0; - x_factor *= 2; + x_factor *= 2; width *= 0.5; test_line_width *= 0.5; } diff --git a/src/cairo-pdf-operators-private.h b/src/cairo-pdf-operators-private.h index 6e1ae1833..4314a042e 100755..100644 --- a/src/cairo-pdf-operators-private.h +++ b/src/cairo-pdf-operators-private.h @@ -53,9 +53,10 @@ */ #define PDF_GLYPH_BUFFER_SIZE 200 -typedef cairo_status_t (*cairo_pdf_operators_use_font_subset_t) (unsigned int font_id, - unsigned int subset_id, - void *closure); +typedef cairo_int_status_t +(*cairo_pdf_operators_use_font_subset_t) (unsigned int font_id, + unsigned int subset_id, + void *closure); typedef struct _cairo_pdf_glyph { unsigned int glyph_index; @@ -69,6 +70,7 @@ typedef struct _cairo_pdf_operators { cairo_scaled_font_subsets_t *font_subsets; cairo_pdf_operators_use_font_subset_t use_font_subset; void *use_font_subset_closure; + cairo_bool_t ps_output; /* output is for PostScript */ cairo_bool_t use_actual_text; cairo_bool_t in_text_object; /* inside BT/ET pair */ @@ -100,7 +102,8 @@ cairo_private void _cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators, cairo_output_stream_t *stream, cairo_matrix_t *cairo_to_pdf, - cairo_scaled_font_subsets_t *font_subsets); + cairo_scaled_font_subsets_t *font_subsets, + cairo_bool_t ps); cairo_private cairo_status_t _cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators); diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c index fceaf1cc4..dcee25f0c 100755..100644 --- a/src/cairo-pdf-operators.c +++ b/src/cairo-pdf-operators.c @@ -57,11 +57,13 @@ void _cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators, cairo_output_stream_t *stream, cairo_matrix_t *cairo_to_pdf, - cairo_scaled_font_subsets_t *font_subsets) + cairo_scaled_font_subsets_t *font_subsets, + cairo_bool_t ps) { pdf_operators->stream = stream; pdf_operators->cairo_to_pdf = *cairo_to_pdf; pdf_operators->font_subsets = font_subsets; + pdf_operators->ps_output = ps; pdf_operators->use_font_subset = NULL; pdf_operators->use_font_subset_closure = NULL; pdf_operators->in_text_object = FALSE; @@ -176,6 +178,7 @@ typedef struct _word_wrap_stream { cairo_output_stream_t base; cairo_output_stream_t *output; int max_column; + cairo_bool_t ps_output; int column; cairo_word_wrap_state_t state; cairo_bool_t in_escape; @@ -269,7 +272,7 @@ _word_wrap_stream_count_string_up_to (word_wrap_stream_t *stream, if (*s == '\\') { stream->in_escape = TRUE; stream->escape_digits = 0; - } else if (stream->column > stream->max_column) { + } else if (stream->ps_output && stream->column > stream->max_column) { newline = TRUE; break; } @@ -348,7 +351,7 @@ _word_wrap_stream_close (cairo_output_stream_t *base) } static cairo_output_stream_t * -_word_wrap_stream_create (cairo_output_stream_t *output, int max_column) +_word_wrap_stream_create (cairo_output_stream_t *output, cairo_bool_t ps, int max_column) { word_wrap_stream_t *stream; @@ -367,6 +370,7 @@ _word_wrap_stream_create (cairo_output_stream_t *output, int max_column) _word_wrap_stream_close); stream->output = output; stream->max_column = max_column; + stream->ps_output = ps; stream->column = 0; stream->state = WRAP_STATE_DELIMITER; stream->in_escape = FALSE; @@ -502,7 +506,7 @@ _cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators, pdf_path_info_t info; cairo_box_t box; - word_wrap = _word_wrap_stream_create (pdf_operators->stream, 72); + word_wrap = _word_wrap_stream_create (pdf_operators->stream, pdf_operators->ps_output, 72); status = _cairo_output_stream_get_status (word_wrap); if (unlikely (status)) return _cairo_output_stream_destroy (word_wrap); @@ -510,7 +514,9 @@ _cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators, info.output = word_wrap; info.path_transform = path_transform; info.line_cap = line_cap; - if (_cairo_path_fixed_is_rectangle (path, &box)) { + if (_cairo_path_fixed_is_rectangle (path, &box) && + ((path_transform->xx == 0 && path_transform->yy == 0) || + (path_transform->xy == 0 && path_transform->yx == 0))) { status = _cairo_pdf_path_rectangle (&info, &box); } else { status = _cairo_path_fixed_interpret (path, @@ -828,10 +834,9 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, return status; if (has_ctm) { - _cairo_output_stream_printf (pdf_operators->stream, - "q %f %f %f %f %f %f cm\n", - m.xx, m.yx, m.xy, m.yy, - m.x0, m.y0); + _cairo_output_stream_printf (pdf_operators->stream, "q "); + _cairo_output_stream_print_matrix (pdf_operators->stream, &m); + _cairo_output_stream_printf (pdf_operators->stream, " cm\n"); } else { path_transform = pdf_operators->cairo_to_pdf; } @@ -1050,7 +1055,7 @@ _cairo_pdf_operators_flush_glyphs (cairo_pdf_operators_t *pdf_operators) if (pdf_operators->num_glyphs == 0) return CAIRO_STATUS_SUCCESS; - word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, 72); + word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, pdf_operators->ps_output, 72); status = _cairo_output_stream_get_status (word_wrap_stream); if (unlikely (status)) return _cairo_output_stream_destroy (word_wrap_stream); @@ -1120,14 +1125,8 @@ _cairo_pdf_operators_set_text_matrix (cairo_pdf_operators_t *pdf_operators, pdf_operators->cur_x = 0; pdf_operators->cur_y = 0; pdf_operators->glyph_buf_x_pos = 0; - _cairo_output_stream_printf (pdf_operators->stream, - "%f %f %f %f %f %f Tm\n", - pdf_operators->text_matrix.xx, - pdf_operators->text_matrix.yx, - pdf_operators->text_matrix.xy, - pdf_operators->text_matrix.yy, - pdf_operators->text_matrix.x0, - pdf_operators->text_matrix.y0); + _cairo_output_stream_print_matrix (pdf_operators->stream, &pdf_operators->text_matrix); + _cairo_output_stream_printf (pdf_operators->stream, " Tm\n"); pdf_operators->cairo_to_pdftext = *matrix; status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext); @@ -1416,7 +1415,11 @@ _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators, return status; } - cur_glyph = glyphs; + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + cur_glyph = glyphs + num_glyphs - 1; + else + cur_glyph = glyphs; + /* XXX * If no glyphs, we should put *something* here for the text to be selectable. */ for (i = 0; i < num_glyphs; i++) { diff --git a/src/cairo-pdf-shading-private.h b/src/cairo-pdf-shading-private.h index 0ca8cb7d5..0ca8cb7d5 100755..100644 --- a/src/cairo-pdf-shading-private.h +++ b/src/cairo-pdf-shading-private.h diff --git a/src/cairo-pdf-shading.c b/src/cairo-pdf-shading.c index 6a2fe3615..6a2fe3615 100755..100644 --- a/src/cairo-pdf-shading.c +++ b/src/cairo-pdf-shading.c diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h index d9f65d800..618ca4ede 100755..100644 --- a/src/cairo-pdf-surface-private.h +++ b/src/cairo-pdf-surface-private.h @@ -70,9 +70,12 @@ typedef struct _cairo_pdf_source_surface_entry { unsigned int id; unsigned char *unique_id; unsigned long unique_id_length; + cairo_operator_t operator; cairo_bool_t interpolate; cairo_bool_t stencil_mask; + cairo_bool_t smask; cairo_pdf_resource_t surface_res; + cairo_pdf_resource_t smask_res; int width; int height; cairo_rectangle_int_t extents; @@ -92,6 +95,7 @@ typedef struct _cairo_pdf_pattern { cairo_pattern_t *pattern; cairo_pdf_resource_t pattern_res; cairo_pdf_resource_t gstate_res; + cairo_operator_t operator; cairo_bool_t is_shading; } cairo_pdf_pattern_t; @@ -127,6 +131,13 @@ typedef struct _cairo_pdf_smask_group { cairo_scaled_font_t *scaled_font; } cairo_pdf_smask_group_t; +typedef struct _cairo_pdf_jbig2_global { + unsigned char *id; + unsigned long id_length; + cairo_pdf_resource_t res; + cairo_bool_t emitted; +} cairo_pdf_jbig2_global_t; + typedef struct _cairo_pdf_surface cairo_pdf_surface_t; struct _cairo_pdf_surface { @@ -149,6 +160,7 @@ struct _cairo_pdf_surface { cairo_hash_table_t *all_surfaces; cairo_array_t smask_groups; cairo_array_t knockout_group; + cairo_array_t jbig2_global; cairo_scaled_font_subsets_t *font_subsets; cairo_array_t fonts; diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index a0bf1c1d5..552e4bf4f 100755..100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -130,6 +130,23 @@ * * The PDF surface is used to render cairo graphics to Adobe * PDF files and is a multi-page vector surface backend. + * + * The following mime types are supported: %CAIRO_MIME_TYPE_JPEG, + * %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_UNIQUE_ID, + * %CAIRO_MIME_TYPE_JBIG2, %CAIRO_MIME_TYPE_JBIG2_GLOBAL, + * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID. + * + * JBIG2 data in PDF must be in the embedded format as descibed in + * ISO/IEC 11544. Image specific JBIG2 data must be in + * %CAIRO_MIME_TYPE_JBIG2. Any global segments in the JBIG2 data + * (segments with page association field set to 0) must be in + * %CAIRO_MIME_TYPE_JBIG2_GLOBAL. The global data may be shared by + * multiple images. All images sharing the same global data must set + * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID to a unique identifer. At least + * one of the images must provide the global data using + * %CAIRO_MIME_TYPE_JBIG2_GLOBAL. The global data will only be + * embedded once but shared by all JBIG2 images with the same + * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID. **/ static cairo_bool_t @@ -164,6 +181,9 @@ static const char *_cairo_pdf_supported_mime_types[] = CAIRO_MIME_TYPE_JPEG, CAIRO_MIME_TYPE_JP2, CAIRO_MIME_TYPE_UNIQUE_ID, + CAIRO_MIME_TYPE_JBIG2, + CAIRO_MIME_TYPE_JBIG2_GLOBAL, + CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID, NULL }; @@ -198,7 +218,7 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface); static void _cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group); -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_add_font (unsigned int font_id, unsigned int subset_id, void *closure); @@ -206,16 +226,16 @@ _cairo_pdf_surface_add_font (unsigned int font_id, static void _cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res); -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface, cairo_pdf_resource_t *resource, cairo_bool_t compressed, const char *fmt, ...) CAIRO_PRINTF_FORMAT(4, 5); -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface); -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface); static void @@ -230,10 +250,10 @@ _cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface); static long _cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface); -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface); -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface); static cairo_bool_t @@ -246,7 +266,7 @@ static cairo_pdf_resource_t _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface) { cairo_pdf_resource_t resource; - cairo_status_t status; + cairo_int_status_t status; cairo_pdf_object_t object; object.offset = _cairo_output_stream_get_position (surface->output); @@ -365,6 +385,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, _cairo_array_init (&surface->page_patterns, sizeof (cairo_pdf_pattern_t)); _cairo_array_init (&surface->page_surfaces, sizeof (cairo_pdf_source_surface_t)); + _cairo_array_init (&surface->jbig2_global, sizeof (cairo_pdf_jbig2_global_t)); surface->all_surfaces = _cairo_hash_table_create (_cairo_pdf_source_surface_equal); if (unlikely (surface->all_surfaces == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -410,7 +431,8 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, _cairo_pdf_operators_init (&surface->pdf_operators, surface->output, &surface->cairo_to_pdf, - surface->font_subsets); + surface->font_subsets, + FALSE); _cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators, _cairo_pdf_surface_add_font, surface); @@ -769,14 +791,14 @@ _cairo_pdf_surface_add_operator (cairo_pdf_surface_t *surface, res->operators[op] = TRUE; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface, double alpha, int *index) { int num_alphas, i; double other; - cairo_status_t status; + cairo_int_status_t status; cairo_pdf_group_resources_t *res = &surface->resources; num_alphas = _cairo_array_num_elements (&res->alphas); @@ -797,21 +819,21 @@ _cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface, return CAIRO_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_add_smask (cairo_pdf_surface_t *surface, cairo_pdf_resource_t smask) { return _cairo_array_append (&(surface->resources.smasks), &smask); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_add_pattern (cairo_pdf_surface_t *surface, cairo_pdf_resource_t pattern) { return _cairo_array_append (&(surface->resources.patterns), &pattern); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_add_shading (cairo_pdf_surface_t *surface, cairo_pdf_resource_t shading) { @@ -819,14 +841,14 @@ _cairo_pdf_surface_add_shading (cairo_pdf_surface_t *surface, } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_add_xobject (cairo_pdf_surface_t *surface, cairo_pdf_resource_t xobject) { return _cairo_array_append (&(surface->resources.xobjects), &xobject); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_add_font (unsigned int font_id, unsigned int subset_id, void *closure) @@ -834,7 +856,7 @@ _cairo_pdf_surface_add_font (unsigned int font_id, cairo_pdf_surface_t *surface = closure; cairo_pdf_font_t font; int num_fonts, i; - cairo_status_t status; + cairo_int_status_t status; cairo_pdf_group_resources_t *res = &surface->resources; num_fonts = _cairo_array_num_elements (&res->fonts); @@ -1093,7 +1115,7 @@ _cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group) free (group); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_add_smask_group (cairo_pdf_surface_t *surface, cairo_pdf_smask_group_t *group) { @@ -1187,6 +1209,20 @@ _cairo_pdf_surface_release_source_image_from_pattern (cairo_pdf_surface_t } static cairo_int_status_t +_get_jbig2_image_info (cairo_surface_t *source, + cairo_image_info_t *info, + const unsigned char **mime_data, + unsigned long *mime_data_length) +{ + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JBIG2, + mime_data, mime_data_length); + if (*mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return _cairo_image_info_get_jbig2_info (info, *mime_data, *mime_data_length); +} + +static cairo_int_status_t _get_jpx_image_info (cairo_surface_t *source, cairo_image_info_t *info, const unsigned char **mime_data, @@ -1263,6 +1299,15 @@ _get_source_surface_size (cairo_surface_t *source, extents->x = 0; extents->y = 0; + status = _get_jbig2_image_info (source, &info, &mime_data, &mime_data_length); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { + *width = info.width; + *height = info.height; + extents->width = info.width; + extents->height = info.height; + return status; + } + status = _get_jpx_image_info (source, &info, &mime_data, &mime_data_length); if (status != CAIRO_INT_STATUS_UNSUPPORTED) { *width = info.width; @@ -1295,9 +1340,12 @@ _get_source_surface_size (cairo_surface_t *source, * @surface: the pdf surface * @source_surface: A #cairo_surface_t to use as the source surface * @source_pattern: A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source + * @op: the operator used to composite this source * @filter: filter type of the source pattern * @stencil_mask: if true, the surface will be written to the PDF as an /ImageMask + * @smask: if true, only the alpha channel will be written (images only) * @extents: extents of the operation that is using this source + * @smask_res: if not NULL, the image written will specify this resource as the smask for the image (images only) * @surface_res: return PDF resource number of the surface * @width: returns width of surface * @height: returns height of surface @@ -1315,13 +1363,16 @@ _get_source_surface_size (cairo_surface_t *source, * Only one of @source_pattern or @source_surface is to be * specified. Set the other to NULL. **/ -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface, cairo_surface_t *source_surface, const cairo_pattern_t *source_pattern, + cairo_operator_t op, cairo_filter_t filter, cairo_bool_t stencil_mask, + cairo_bool_t smask, const cairo_rectangle_int_t *extents, + cairo_pdf_resource_t *smask_res, cairo_pdf_resource_t *surface_res, int *width, int *height, @@ -1332,9 +1383,9 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface, cairo_pdf_source_surface_t src_surface; cairo_pdf_source_surface_entry_t surface_key; cairo_pdf_source_surface_entry_t *surface_entry; - cairo_status_t status; + cairo_int_status_t status; cairo_bool_t interpolate; - unsigned char *unique_id; + unsigned char *unique_id = NULL; unsigned long unique_id_length = 0; cairo_image_surface_t *image; void *image_extra; @@ -1419,13 +1470,19 @@ release_source: } surface_entry->id = surface_key.id; + surface_entry->operator = op; surface_entry->interpolate = interpolate; surface_entry->stencil_mask = stencil_mask; + surface_entry->smask = smask; surface_entry->unique_id_length = unique_id_length; surface_entry->unique_id = unique_id; surface_entry->width = *width; surface_entry->height = *height; surface_entry->extents = *source_extents; + if (smask_res) + surface_entry->smask_res = *smask_res; + else + surface_entry->smask_res.id = 0; _cairo_pdf_source_surface_init_key (surface_entry); src_surface.hash_entry = surface_entry; @@ -1476,24 +1533,26 @@ fail1: return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_add_pdf_pattern_or_shading (cairo_pdf_surface_t *surface, const cairo_pattern_t *pattern, + cairo_operator_t op, const cairo_rectangle_int_t *extents, cairo_bool_t is_shading, cairo_pdf_resource_t *pattern_res, cairo_pdf_resource_t *gstate_res) { cairo_pdf_pattern_t pdf_pattern; - cairo_status_t status; + cairo_int_status_t status; pdf_pattern.is_shading = is_shading; + pdf_pattern.operator = op; /* Solid colors are emitted into the content stream */ if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { pattern_res->id = 0; gstate_res->id = 0; - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } status = _cairo_pattern_create_copy (&pdf_pattern.pattern, pattern); @@ -1545,7 +1604,7 @@ _cairo_pdf_surface_add_pdf_pattern_or_shading (cairo_pdf_surface_t *surface, return status; } - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } /* Get BBox in PDF coordinates from extents in cairo coordinates */ @@ -1560,37 +1619,41 @@ _get_bbox_from_extents (double surface_height, bbox->p2.y = surface_height - extents->y; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_add_pdf_shading (cairo_pdf_surface_t *surface, const cairo_pattern_t *pattern, + cairo_operator_t op, const cairo_rectangle_int_t *extents, cairo_pdf_resource_t *shading_res, cairo_pdf_resource_t *gstate_res) { return _cairo_pdf_surface_add_pdf_pattern_or_shading (surface, pattern, + op, extents, TRUE, shading_res, gstate_res); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface, const cairo_pattern_t *pattern, + cairo_operator_t op, const cairo_rectangle_int_t *extents, cairo_pdf_resource_t *pattern_res, cairo_pdf_resource_t *gstate_res) { return _cairo_pdf_surface_add_pdf_pattern_or_shading (surface, pattern, + op, extents, FALSE, pattern_res, gstate_res); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface, cairo_pdf_resource_t *resource, cairo_bool_t compressed, @@ -1659,22 +1722,22 @@ _cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface, return _cairo_output_stream_get_status (surface->output); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface) { - cairo_status_t status; + cairo_int_status_t status; long length; if (! surface->pdf_stream.active) - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; status = _cairo_pdf_operators_flush (&surface->pdf_operators); if (surface->pdf_stream.compressed) { - cairo_status_t status2; + cairo_int_status_t status2; status2 = _cairo_output_stream_destroy (surface->output); - if (likely (status == CAIRO_STATUS_SUCCESS)) + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = status2; surface->output = surface->pdf_stream.old_output; @@ -1700,7 +1763,7 @@ _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface) surface->pdf_stream.active = FALSE; - if (likely (status == CAIRO_STATUS_SUCCESS)) + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = _cairo_output_stream_get_status (surface->output); return status; @@ -1755,12 +1818,12 @@ _cairo_pdf_surface_write_memory_stream (cairo_pdf_surface_t *surface, "endobj\n"); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface, const cairo_box_double_t *bbox, cairo_pdf_resource_t *resource) { - cairo_status_t status; + cairo_int_status_t status; assert (surface->pdf_stream.active == FALSE); assert (surface->group_stream.active == FALSE); @@ -1798,11 +1861,11 @@ _cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface, return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t *surface, const cairo_box_double_t *bbox) { - cairo_status_t status; + cairo_int_status_t status; status = _cairo_pdf_surface_open_group (surface, bbox, NULL); if (unlikely (status)) @@ -1810,14 +1873,14 @@ _cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t *surface, surface->group_stream.is_knockout = TRUE; - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface, cairo_pdf_resource_t *group) { - cairo_status_t status = CAIRO_STATUS_SUCCESS, status2; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS, status2; assert (surface->pdf_stream.active == FALSE); assert (surface->group_stream.active == TRUE); @@ -1846,7 +1909,7 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface, *group = surface->group_stream.resource; status2 = _cairo_output_stream_destroy (surface->group_stream.mem_stream); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) status = status2; surface->group_stream.mem_stream = NULL; @@ -1855,13 +1918,14 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface, return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface, const cairo_box_double_t *bbox, cairo_pdf_resource_t *resource, - cairo_bool_t is_form) + cairo_bool_t is_form, + cairo_bool_t is_group) { - cairo_status_t status; + cairo_int_status_t status; assert (surface->pdf_stream.active == FALSE); assert (surface->group_stream.active == FALSE); @@ -1873,25 +1937,41 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface, if (is_form) { assert (bbox != NULL); - status = - _cairo_pdf_surface_open_stream (surface, - resource, - surface->compress_content, - " /Type /XObject\n" - " /Subtype /Form\n" - " /BBox [ %f %f %f %f ]\n" - " /Group <<\n" - " /Type /Group\n" - " /S /Transparency\n" - " /I true\n" - " /CS /DeviceRGB\n" - " >>\n" - " /Resources %d 0 R\n", - bbox->p1.x, - bbox->p1.y, - bbox->p2.x, - bbox->p2.y, - surface->content_resources.id); + if (is_group) { + status = + _cairo_pdf_surface_open_stream (surface, + resource, + surface->compress_content, + " /Type /XObject\n" + " /Subtype /Form\n" + " /BBox [ %f %f %f %f ]\n" + " /Group <<\n" + " /Type /Group\n" + " /S /Transparency\n" + " /I true\n" + " /CS /DeviceRGB\n" + " >>\n" + " /Resources %d 0 R\n", + bbox->p1.x, + bbox->p1.y, + bbox->p2.x, + bbox->p2.y, + surface->content_resources.id); + } else { + status = + _cairo_pdf_surface_open_stream (surface, + resource, + surface->compress_content, + " /Type /XObject\n" + " /Subtype /Form\n" + " /BBox [ %f %f %f %f ]\n" + " /Resources %d 0 R\n", + bbox->p1.x, + bbox->p1.y, + bbox->p2.x, + bbox->p2.y, + surface->content_resources.id); + } } else { status = _cairo_pdf_surface_open_stream (surface, @@ -1909,10 +1989,10 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface, return _cairo_output_stream_get_status (surface->output); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface) { - cairo_status_t status; + cairo_int_status_t status; assert (surface->pdf_stream.active == TRUE); assert (surface->group_stream.active == FALSE); @@ -1956,6 +2036,8 @@ _cairo_pdf_surface_finish (void *abstract_surface) long offset; cairo_pdf_resource_t info, catalog; cairo_status_t status, status2; + int size, i; + cairo_pdf_jbig2_global_t *global; status = surface->base.status; if (status == CAIRO_STATUS_SUCCESS) @@ -2045,6 +2127,17 @@ _cairo_pdf_surface_finish (void *abstract_surface) surface->font_subsets = NULL; } + size = _cairo_array_num_elements (&surface->jbig2_global); + for (i = 0; i < size; i++) { + global = (cairo_pdf_jbig2_global_t *) _cairo_array_index (&surface->jbig2_global, i); + free(global->id); + if (!global->emitted) + return _cairo_error (CAIRO_STATUS_JBIG2_GLOBAL_MISSING); + } + _cairo_array_fini (&surface->jbig2_global); + + _cairo_array_truncate (&surface->page_surfaces, 0); + _cairo_surface_clipper_reset (&surface->clipper); return status; @@ -2085,7 +2178,7 @@ static cairo_int_status_t _cairo_pdf_surface_has_fallback_images (void *abstract_surface, cairo_bool_t has_fallbacks) { - cairo_status_t status; + cairo_int_status_t status; cairo_pdf_surface_t *surface = abstract_surface; cairo_box_double_t bbox; @@ -2094,7 +2187,7 @@ _cairo_pdf_surface_has_fallback_images (void *abstract_surface, bbox.p1.y = 0; bbox.p2.x = surface->width; bbox.p2.y = surface->height; - status = _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, has_fallbacks); + status = _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, has_fallbacks, has_fallbacks); if (unlikely (status)) return status; @@ -2107,7 +2200,7 @@ _cairo_pdf_surface_supports_fine_grained_fallbacks (void *abstract_surface) return TRUE; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surface, const cairo_pattern_t *source, const cairo_rectangle_int_t *extents, @@ -2144,7 +2237,7 @@ _cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surfa h = image->height; if (_cairo_fixed_integer_ceil(box.p1.x) < 0 || _cairo_fixed_integer_ceil(box.p1.y) < 0 || - _cairo_fixed_integer_floor(box.p2.y) > w || + _cairo_fixed_integer_floor(box.p2.x) > w || _cairo_fixed_integer_floor(box.p2.y) > h) { pad_image = _cairo_image_surface_create_with_content (image->base.content, @@ -2169,9 +2262,12 @@ _cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surfa status = _cairo_pdf_surface_add_source_surface (surface, pad_image, NULL, + FALSE, source->filter, FALSE, + FALSE, extents, + NULL, surface_res, width, height, @@ -2202,24 +2298,16 @@ BAIL: return status; } -/* Emit alpha channel from the image into the given data, providing - * an id that can be used to reference the resulting SMask object. - * - * In the case that the alpha channel happens to be all opaque, then - * no SMask object will be emitted and *id_ret will be set to 0. - * - * When stencil_mask is TRUE, stream_res is an an input specifying the - * resource to use. When stencil_mask is FALSE, a new resource will be - * created and returned in stream_res. +/* Emit alpha channel from the image into stream_res. */ -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, cairo_image_surface_t *image, cairo_bool_t stencil_mask, - const char *interpolate, + cairo_bool_t interpolate, cairo_pdf_resource_t *stream_res) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; char *alpha; unsigned long alpha_size; uint32_t *pixel32; @@ -2229,6 +2317,7 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, /* This is the only image format we support, which simplifies things. */ assert (image->format == CAIRO_FORMAT_ARGB32 || + image->format == CAIRO_FORMAT_RGB24 || image->format == CAIRO_FORMAT_A8 || image->format == CAIRO_FORMAT_A1 ); @@ -2237,11 +2326,10 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, assert (transparency == CAIRO_IMAGE_IS_OPAQUE || transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA); } else { - if (transparency == CAIRO_IMAGE_IS_OPAQUE) - return status; + assert (transparency != CAIRO_IMAGE_IS_OPAQUE); } - if (transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA) { + if (transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA || transparency == CAIRO_IMAGE_IS_OPAQUE) { alpha_size = (image->width + 7) / 8 * image->height; alpha = _cairo_malloc_ab ((image->width+7) / 8, image->height); } else { @@ -2256,7 +2344,10 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, i = 0; for (y = 0; y < image->height; y++) { - if (image->format == CAIRO_FORMAT_A1) { + if (transparency == CAIRO_IMAGE_IS_OPAQUE) { + for (x = 0; x < (image->width + 7) / 8; x++) + alpha[i++] = 0xff; + } else if (image->format == CAIRO_FORMAT_A1) { pixel8 = (uint8_t *) (image->data + y * image->stride); for (x = 0; x < (image->width + 7) / 8; x++, pixel8++) { @@ -2308,11 +2399,11 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, " /Interpolate %s\n" " /BitsPerComponent 1\n" " /Decode [1 0]\n", - image->width, image->height, interpolate); + image->width, image->height, + interpolate ? "true" : "false"); } else { - stream_res->id = 0; status = _cairo_pdf_surface_open_stream (surface, - NULL, + stream_res, TRUE, " /Type /XObject\n" " /Subtype /Image\n" @@ -2321,15 +2412,13 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, " /ColorSpace /DeviceGray\n" " /Interpolate %s\n" " /BitsPerComponent %d\n", - image->width, image->height, interpolate, + image->width, image->height, + interpolate ? "true" : "false", transparency == CAIRO_IMAGE_HAS_ALPHA ? 8 : 1); } if (unlikely (status)) goto CLEANUP_ALPHA; - if (!stencil_mask) - *stream_res = surface->pdf_stream.self; - _cairo_output_stream_write (surface->output, alpha, alpha_size); status = _cairo_pdf_surface_close_stream (surface); @@ -2339,25 +2428,33 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, return status; } -/* Emit image data into the given surface, providing a resource that - * can be used to reference the data in image_ret. */ -static cairo_status_t -_cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface, - cairo_image_surface_t *image_surf, - cairo_pdf_resource_t *image_res, - cairo_filter_t filter, - cairo_bool_t stencil_mask) +/** + * _cairo_pdf_surface_emit_image: + * @surface: the pdf surface + * @image_surf: The image to write + * @surface_entry: Contains image resource, smask resource, interpolate and stencil mask parameters. + * + * Emit an image stream using the @image_res resource and write out + * the image data from @image_surf. If @smask_res is not null, @smask_res will + * be specified as the smask for the image. Otherwise emit the an smask if + * the image is requires one. + **/ +static cairo_int_status_t +_cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface, + cairo_image_surface_t *image_surf, + cairo_pdf_source_surface_entry_t *surface_entry) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; char *data; unsigned long data_size; uint32_t *pixel; int i, x, y, bit; cairo_pdf_resource_t smask = {0}; /* squelch bogus compiler warning */ cairo_bool_t need_smask; - const char *interpolate = "true"; cairo_image_color_t color; cairo_image_surface_t *image; + cairo_image_transparency_t transparency; + char smask_buf[30]; image = image_surf; if (image->format != CAIRO_FORMAT_RGB24 && @@ -2386,26 +2483,19 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface, goto CLEANUP; } - switch (filter) { - case CAIRO_FILTER_GOOD: - case CAIRO_FILTER_BEST: - case CAIRO_FILTER_BILINEAR: - interpolate = "true"; - break; - case CAIRO_FILTER_FAST: - case CAIRO_FILTER_NEAREST: - case CAIRO_FILTER_GAUSSIAN: - interpolate = "false"; - break; + if (surface_entry->smask || surface_entry->stencil_mask) { + return _cairo_pdf_surface_emit_smask (surface, image, + surface_entry->stencil_mask, + surface_entry->interpolate, + &surface_entry->surface_res); } - if (stencil_mask) - return _cairo_pdf_surface_emit_smask (surface, image, stencil_mask, interpolate, image_res); - color = _cairo_image_analyze_color (image); switch (color) { - case CAIRO_IMAGE_IS_COLOR: + default: case CAIRO_IMAGE_UNKNOWN_COLOR: + ASSERT_NOT_REACHED; + case CAIRO_IMAGE_IS_COLOR: data_size = image->height * image->width * 3; data = _cairo_malloc_abc (image->width, image->height, 3); break; @@ -2484,46 +2574,53 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface, i++; } - need_smask = FALSE; - if (image->format == CAIRO_FORMAT_ARGB32 || - image->format == CAIRO_FORMAT_A8 || - image->format == CAIRO_FORMAT_A1) { - status = _cairo_pdf_surface_emit_smask (surface, image, FALSE, interpolate, &smask); - if (unlikely (status)) - goto CLEANUP_RGB; + if (surface_entry->smask_res.id != 0) { + need_smask = TRUE; + smask = surface_entry->smask_res; + } else { + need_smask = FALSE; + if (image->format == CAIRO_FORMAT_ARGB32 || + image->format == CAIRO_FORMAT_A8 || + image->format == CAIRO_FORMAT_A1) + { + transparency = _cairo_image_analyze_transparency (image); + if (transparency != CAIRO_IMAGE_IS_OPAQUE) { + need_smask = TRUE; + smask = _cairo_pdf_surface_new_object (surface); + if (smask.id == 0) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_RGB; + } - if (smask.id) - need_smask = TRUE; + status = _cairo_pdf_surface_emit_smask (surface, image, FALSE, surface_entry->interpolate, &smask); + if (unlikely (status)) + goto CLEANUP_RGB; + } + } } -#define IMAGE_DICTIONARY " /Type /XObject\n" \ - " /Subtype /Image\n" \ - " /Width %d\n" \ - " /Height %d\n" \ - " /ColorSpace %s\n" \ - " /Interpolate %s\n" \ - " /BitsPerComponent %d\n" - if (need_smask) - status = _cairo_pdf_surface_open_stream (surface, - image_res, - TRUE, - IMAGE_DICTIONARY - " /SMask %d 0 R\n", - image->width, image->height, - color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray", - interpolate, - color == CAIRO_IMAGE_IS_MONOCHROME? 1 : 8, - smask.id); + snprintf(smask_buf, sizeof(smask_buf), " /SMask %d 0 R\n", smask.id); else - status = _cairo_pdf_surface_open_stream (surface, - image_res, - TRUE, - IMAGE_DICTIONARY, - image->width, image->height, - color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray", - interpolate, - color == CAIRO_IMAGE_IS_MONOCHROME? 1 : 8); + smask_buf[0] = 0; + + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + TRUE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /Width %d\n" + " /Height %d\n" + " /ColorSpace %s\n" + " /Interpolate %s\n" + " /BitsPerComponent %d\n" + "%s", + image->width, + image->height, + color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray", + surface_entry->interpolate ? "true" : "false", + color == CAIRO_IMAGE_IS_MONOCHROME? 1 : 8, + smask_buf); if (unlikely (status)) goto CLEANUP_RGB; @@ -2542,14 +2639,165 @@ CLEANUP: } static cairo_int_status_t -_cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface, - cairo_surface_t *source, - cairo_pdf_resource_t res) +_cairo_pdf_surface_lookup_jbig2_global (cairo_pdf_surface_t *surface, + const unsigned char *global_id, + unsigned long global_id_length, + cairo_pdf_jbig2_global_t **entry) { - cairo_status_t status; + cairo_pdf_jbig2_global_t global; + int size, i; + cairo_int_status_t status; + + size = _cairo_array_num_elements (&surface->jbig2_global); + for (i = 0; i < size; i++) { + *entry = (cairo_pdf_jbig2_global_t *) _cairo_array_index (&surface->jbig2_global, i); + if ((*entry)->id && global_id && (*entry)->id_length == global_id_length + && memcmp((*entry)->id, global_id, global_id_length) == 0) { + return CAIRO_STATUS_SUCCESS; + } + } + + global.id = malloc(global_id_length); + if (unlikely (global.id == NULL)) { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + memcpy (global.id, global_id, global_id_length); + global.id_length = global_id_length; + global.res = _cairo_pdf_surface_new_object (surface); + if (global.res.id == 0) { + free(global.id); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + global.emitted = FALSE; + status = _cairo_array_append (&surface->jbig2_global, &global); + if (unlikely(status)) + return status; + + size = _cairo_array_num_elements (&surface->jbig2_global); + *entry = (cairo_pdf_jbig2_global_t *) _cairo_array_index (&surface->jbig2_global, size - 1); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_jbig2_image (cairo_pdf_surface_t *surface, + cairo_surface_t *source, + cairo_pdf_source_surface_entry_t *surface_entry) +{ + cairo_int_status_t status; const unsigned char *mime_data; unsigned long mime_data_length; cairo_image_info_t info; + const unsigned char *global_id; + unsigned long global_id_length; + const unsigned char *global_data; + unsigned long global_data_length; + cairo_pdf_jbig2_global_t *global_entry = NULL; /* hide compiler warning */ + char smask_buf[30]; + char decode_parms_buf[100]; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JBIG2, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_jbig2_info (&info, mime_data, mime_data_length); + if (status) + return status; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID, + &global_id, &global_id_length); + if (global_id && global_id_length > 0) { + status = _cairo_pdf_surface_lookup_jbig2_global (surface, global_id, global_id_length, &global_entry); + if (unlikely(status)) + return status; + + if (!global_entry->emitted) { + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JBIG2_GLOBAL, + &global_data, &global_data_length); + if (global_data) { + status = _cairo_pdf_surface_open_stream (surface, &global_entry->res, FALSE, NULL); + if (unlikely(status)) + return status; + + _cairo_output_stream_write (surface->output, global_data, global_data_length); + status = _cairo_pdf_surface_close_stream (surface); + if (unlikely(status)) + return status; + + global_entry->emitted = TRUE; + } + } + + snprintf(decode_parms_buf, sizeof(decode_parms_buf), + " /DecodeParms << /JBIG2Globals %d 0 R >>\n", global_entry->res.id); + } else { + decode_parms_buf[0] = 0; + } + + if (surface_entry->smask_res.id) + snprintf(smask_buf, sizeof(smask_buf), " /SMask %d 0 R\n", surface_entry->smask_res.id); + else + smask_buf[0] = 0; + + if (surface_entry->stencil_mask) { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /ImageMask true\n" + " /Width %d\n" + " /Height %d\n" + " /Interpolate %s\n" + " /BitsPerComponent 1\n" + " /Decode [1 0]\n" + " /Filter /JPXDecode\n" + "%s", + info.width, + info.height, + surface_entry->interpolate ? "true" : "false", + decode_parms_buf); + } else { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /Width %d\n" + " /Height %d\n" + " /ColorSpace /DeviceGray\n" + " /BitsPerComponent 1\n" + " /Interpolate %s\n" + "%s" + " /Filter /JBIG2Decode\n" + "%s", + info.width, + info.height, + surface_entry->interpolate ? "true" : "false", + smask_buf, + decode_parms_buf); + } + if (unlikely(status)) + return status; + + _cairo_output_stream_write (surface->output, mime_data, mime_data_length); + status = _cairo_pdf_surface_close_stream (surface); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface, + cairo_surface_t *source, + cairo_pdf_source_surface_entry_t *surface_entry) +{ + cairo_int_status_t status; + const unsigned char *mime_data; + unsigned long mime_data_length; + cairo_image_info_t info; + char smask_buf[30]; if (surface->pdf_version < CAIRO_PDF_VERSION_1_5) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -2563,16 +2811,49 @@ _cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface, if (status) return status; - status = _cairo_pdf_surface_open_stream (surface, - &res, - FALSE, - " /Type /XObject\n" - " /Subtype /Image\n" - " /Width %d\n" - " /Height %d\n" - " /Filter /JPXDecode\n", - info.width, - info.height); + if ((surface_entry->smask || surface_entry->stencil_mask) && info.num_components != 1) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if ((surface_entry->stencil_mask) && info.bits_per_component != 1) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (surface_entry->smask_res.id) + snprintf(smask_buf, sizeof(smask_buf), " /SMask %d 0 R\n", surface_entry->smask_res.id); + else + smask_buf[0] = 0; + + if (surface_entry->stencil_mask) { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /ImageMask true\n" + " /Width %d\n" + " /Height %d\n" + " /Interpolate %s\n" + " /BitsPerComponent 1\n" + " /Decode [1 0]\n" + " /Filter /JPXDecode\n", + info.width, + info.height, + surface_entry->interpolate ? "true" : "false"); + } else { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /Width %d\n" + " /Height %d\n" + " /Interpolate %s\n" + "%s" + " /Filter /JPXDecode\n", + info.width, + info.height, + surface_entry->interpolate ? "true" : "false", + smask_buf); + } if (status) return status; @@ -2583,15 +2864,16 @@ _cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface, } static cairo_int_status_t -_cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, - cairo_surface_t *source, - cairo_pdf_resource_t res) +_cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, + cairo_surface_t *source, + cairo_pdf_source_surface_entry_t *surface_entry) { - cairo_status_t status; + cairo_int_status_t status; const unsigned char *mime_data; unsigned long mime_data_length; cairo_image_info_t info; const char *colorspace; + char smask_buf[30]; cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG, &mime_data, &mime_data_length); @@ -2604,6 +2886,12 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, if (unlikely (status)) return status; + if ((surface_entry->smask || surface_entry->stencil_mask) && info.num_components != 1) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if ((surface_entry->stencil_mask) && info.bits_per_component != 1) + return CAIRO_INT_STATUS_UNSUPPORTED; + switch (info.num_components) { case 1: colorspace = "/DeviceGray"; @@ -2618,20 +2906,47 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, return CAIRO_INT_STATUS_UNSUPPORTED; } - status = _cairo_pdf_surface_open_stream (surface, - &res, - FALSE, - " /Type /XObject\n" - " /Subtype /Image\n" - " /Width %d\n" - " /Height %d\n" - " /ColorSpace %s\n" - " /BitsPerComponent %d\n" - " /Filter /DCTDecode\n", - info.width, - info.height, - colorspace, - info.bits_per_component); + if (surface_entry->smask_res.id) + snprintf(smask_buf, sizeof(smask_buf), " /SMask %d 0 R\n", surface_entry->smask_res.id); + else + smask_buf[0] = 0; + + if (surface_entry->stencil_mask) { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /ImageMask true\n" + " /Width %d\n" + " /Height %d\n" + " /Interpolate %s\n" + " /BitsPerComponent 1\n" + " /Decode [1 0]\n" + " /Filter /DCTDecode\n", + info.width, + info.height, + surface_entry->interpolate ? "true" : "false"); + } else { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /Width %d\n" + " /Height %d\n" + " /ColorSpace %s\n" + " /Interpolate %s\n" + " /BitsPerComponent %d\n" + "%s" + " /Filter /DCTDecode\n", + info.width, + info.height, + colorspace, + surface_entry->interpolate ? "true" : "false", + info.bits_per_component, + smask_buf); + } if (unlikely (status)) return status; @@ -2641,7 +2956,7 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface, cairo_pdf_source_surface_t *source) { @@ -2650,6 +2965,20 @@ _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface, cairo_int_status_t status; if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { + status = _cairo_pdf_surface_emit_jbig2_image (surface, source->surface, source->hash_entry); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_pdf_surface_emit_jpx_image (surface, source->surface, source->hash_entry); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_pdf_surface_emit_jpeg_image (surface, source->surface, source->hash_entry); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { status = _cairo_surface_acquire_source_image (source->surface, &image, &image_extra); } else { status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source->raster_pattern, @@ -2658,22 +2987,10 @@ _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface, if (unlikely (status)) return status; - if (!source->hash_entry->stencil_mask) { - status = _cairo_pdf_surface_emit_jpx_image (surface, &image->base, source->hash_entry->surface_res); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - goto release_source; + status = _cairo_pdf_surface_emit_image (surface, + image, + source->hash_entry); - status = _cairo_pdf_surface_emit_jpeg_image (surface, &image->base, source->hash_entry->surface_res); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - goto release_source; - } - - status = _cairo_pdf_surface_emit_image (surface, image, - &source->hash_entry->surface_res, - source->hash_entry->interpolate, - source->hash_entry->stencil_mask); - -release_source: if (source->type == CAIRO_PATTERN_TYPE_SURFACE) _cairo_surface_release_source_image (source->surface, image, image_extra); else @@ -2683,7 +3000,7 @@ release_source: return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface, cairo_pdf_source_surface_t *pdf_source) { @@ -2699,6 +3016,8 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface, int width; int height; cairo_bool_t is_subsurface; + cairo_bool_t transparency_group; + cairo_recording_surface_t *recording; assert (pdf_source->type == CAIRO_PATTERN_TYPE_SURFACE); extents = &pdf_source->hash_entry->extents; @@ -2718,6 +3037,9 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface, is_subsurface = TRUE; } + assert (source->type == CAIRO_SURFACE_TYPE_RECORDING); + recording = (cairo_recording_surface_t *) source; + old_width = surface->width; old_height = surface->height; old_paginated_mode = surface->paginated_mode; @@ -2734,7 +3056,16 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface, surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER; _cairo_pdf_group_resources_clear (&surface->resources); _get_bbox_from_extents (height, extents, &bbox); - status = _cairo_pdf_surface_open_content_stream (surface, &bbox, &pdf_source->hash_entry->surface_res, TRUE); + + /* We can optimize away the transparency group allowing the viewer + * to replay the group in place when all operators are OVER and the + * recording contains only opaque and/or clear alpha. + */ + transparency_group = !(pdf_source->hash_entry->operator == CAIRO_OPERATOR_OVER && + _cairo_recording_surface_has_only_bilevel_alpha (recording) && + _cairo_recording_surface_has_only_op_over (recording)); + status = _cairo_pdf_surface_open_content_stream (surface, &bbox, &pdf_source->hash_entry->surface_res, + TRUE, transparency_group); if (unlikely (status)) goto err; @@ -2772,7 +3103,7 @@ err: return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_surface (cairo_pdf_surface_t *surface, cairo_pdf_source_surface_t *src_surface) { @@ -2783,12 +3114,12 @@ _cairo_pdf_surface_emit_surface (cairo_pdf_surface_t *surface, return _cairo_pdf_surface_emit_image_surface (surface, src_surface); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern_t *pdf_pattern) { cairo_pattern_t *pattern = pdf_pattern->pattern; - cairo_status_t status; + cairo_int_status_t status; cairo_pdf_resource_t pattern_resource = {0}; cairo_matrix_t cairo_p2d, pdf_p2d; cairo_extend_t extend = cairo_pattern_get_extend (pattern); @@ -2818,9 +3149,12 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, status = _cairo_pdf_surface_add_source_surface (surface, NULL, pattern, + pdf_pattern->operator, pattern->filter, FALSE, + FALSE, &pdf_pattern->extents, + NULL, &pattern_resource, &pattern_width, &pattern_height, @@ -2911,7 +3245,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, cairo_p2d = pattern->matrix; status = cairo_matrix_invert (&cairo_p2d); /* cairo_pattern_set_matrix ensures the matrix is invertible */ - assert (status == CAIRO_STATUS_SUCCESS); + assert (status == CAIRO_INT_STATUS_SUCCESS); cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &surface->cairo_to_pdf); cairo_matrix_translate (&pdf_p2d, -x_offset, -y_offset); @@ -2989,7 +3323,7 @@ typedef struct _cairo_pdf_color_stop { cairo_pdf_resource_t resource; } cairo_pdf_color_stop_t; -static cairo_status_t +static cairo_int_status_t cairo_pdf_surface_emit_rgb_linear_function (cairo_pdf_surface_t *surface, cairo_pdf_color_stop_t *stop1, cairo_pdf_color_stop_t *stop2, @@ -2998,7 +3332,7 @@ cairo_pdf_surface_emit_rgb_linear_function (cairo_pdf_surface_t *surface, int num_elems, i; cairo_pdf_rgb_linear_function_t elem; cairo_pdf_resource_t res; - cairo_status_t status; + cairo_int_status_t status; num_elems = _cairo_array_num_elements (&surface->rgb_linear_functions); for (i = 0; i < num_elems; i++) { @@ -3042,7 +3376,7 @@ cairo_pdf_surface_emit_rgb_linear_function (cairo_pdf_surface_t *surface, return status; } -static cairo_status_t +static cairo_int_status_t cairo_pdf_surface_emit_alpha_linear_function (cairo_pdf_surface_t *surface, cairo_pdf_color_stop_t *stop1, cairo_pdf_color_stop_t *stop2, @@ -3051,7 +3385,7 @@ cairo_pdf_surface_emit_alpha_linear_function (cairo_pdf_surface_t *surface, int num_elems, i; cairo_pdf_alpha_linear_function_t elem; cairo_pdf_resource_t res; - cairo_status_t status; + cairo_int_status_t status; num_elems = _cairo_array_num_elements (&surface->alpha_linear_functions); for (i = 0; i < num_elems; i++) { @@ -3091,7 +3425,7 @@ cairo_pdf_surface_emit_alpha_linear_function (cairo_pdf_surface_t *surface, return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_stitched_colorgradient (cairo_pdf_surface_t *surface, unsigned int n_stops, cairo_pdf_color_stop_t *stops, @@ -3100,7 +3434,7 @@ _cairo_pdf_surface_emit_stitched_colorgradient (cairo_pdf_surface_t *surface, { cairo_pdf_resource_t res; unsigned int i; - cairo_status_t status; + cairo_int_status_t status; /* emit linear gradients between pairs of subsequent stops... */ for (i = 0; i < n_stops-1; i++) { @@ -3182,7 +3516,7 @@ calc_gradient_color (cairo_pdf_color_stop_t *new_stop, #define COLOR_STOP_EPSILON 1e-6 -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern, cairo_pdf_resource_t *color_function, @@ -3192,7 +3526,7 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, unsigned int n_stops; unsigned int i; cairo_bool_t emit_alpha = FALSE; - cairo_status_t status; + cairo_int_status_t status; color_function->id = 0; alpha_function->id = 0; @@ -3326,7 +3660,7 @@ BAIL: return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_repeating_function (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern, cairo_pdf_resource_t *function, @@ -3387,14 +3721,14 @@ _cairo_pdf_surface_emit_repeating_function (cairo_pdf_surface_t *surface, return _cairo_output_stream_get_status (surface->output); } -static cairo_status_t +static cairo_int_status_t cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t *surface, cairo_pdf_pattern_t *pdf_pattern, cairo_pdf_resource_t gstate_resource, cairo_pdf_resource_t gradient_mask) { cairo_pdf_resource_t smask_resource; - cairo_status_t status; + cairo_int_status_t status; char buf[100]; double x1, y1, x2, y2; @@ -3531,11 +3865,11 @@ _cairo_pdf_surface_output_gradient (cairo_pdf_surface_t *surface, _cairo_output_stream_printf (surface->output, "<< /Type /Pattern\n" " /PatternType 2\n" - " /Matrix [ %f %f %f %f %f %f ]\n" - " /Shading\n", - pat_to_pdf->xx, pat_to_pdf->yx, - pat_to_pdf->xy, pat_to_pdf->yy, - pat_to_pdf->x0, pat_to_pdf->y0); + " /Matrix [ "); + _cairo_output_stream_print_matrix (surface->output, pat_to_pdf); + _cairo_output_stream_printf (surface->output, + " ]\n" + " /Shading\n"); } if (pdf_pattern->pattern->type == CAIRO_PATTERN_TYPE_LINEAR) { @@ -3577,12 +3911,14 @@ _cairo_pdf_surface_output_gradient (cairo_pdf_surface_t *surface, if (!pdf_pattern->is_shading) { _cairo_output_stream_printf (surface->output, - ">>\n" - "endobj\n"); + ">>\n"); } + + _cairo_output_stream_printf (surface->output, + "endobj\n"); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_gradient (cairo_pdf_surface_t *surface, cairo_pdf_pattern_t *pdf_pattern) { @@ -3591,7 +3927,7 @@ _cairo_pdf_surface_emit_gradient (cairo_pdf_surface_t *surface, cairo_matrix_t pat_to_pdf; cairo_circle_double_t start, end; double domain[2]; - cairo_status_t status; + cairo_int_status_t status; assert (pattern->n_stops != 0); @@ -3605,7 +3941,7 @@ _cairo_pdf_surface_emit_gradient (cairo_pdf_surface_t *surface, pat_to_pdf = pattern->base.matrix; status = cairo_matrix_invert (&pat_to_pdf); /* cairo_pattern_set_matrix ensures the matrix is invertible */ - assert (status == CAIRO_STATUS_SUCCESS); + assert (status == CAIRO_INT_STATUS_SUCCESS); cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf); if (pattern->base.extend == CAIRO_EXTEND_REPEAT || @@ -3728,12 +4064,12 @@ _cairo_pdf_surface_emit_gradient (cairo_pdf_surface_t *surface, return _cairo_output_stream_get_status (surface->output); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_mesh_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern_t *pdf_pattern) { cairo_matrix_t pat_to_pdf; - cairo_status_t status; + cairo_int_status_t status; cairo_pattern_t *pattern = pdf_pattern->pattern; cairo_pdf_shading_t shading; int i; @@ -3742,7 +4078,7 @@ _cairo_pdf_surface_emit_mesh_pattern (cairo_pdf_surface_t *surface, pat_to_pdf = pattern->matrix; status = cairo_matrix_invert (&pat_to_pdf); /* cairo_pattern_set_matrix ensures the matrix is invertible */ - assert (status == CAIRO_STATUS_SUCCESS); + assert (status == CAIRO_INT_STATUS_SUCCESS); cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf); @@ -3791,14 +4127,14 @@ _cairo_pdf_surface_emit_mesh_pattern (cairo_pdf_surface_t *surface, "%d 0 obj\n" "<< /Type /Pattern\n" " /PatternType 2\n" - " /Matrix [ %f %f %f %f %f %f ]\n" + " /Matrix [ ", + pdf_pattern->pattern_res.id); + _cairo_output_stream_print_matrix (surface->output, &pat_to_pdf); + _cairo_output_stream_printf (surface->output, + " ]\n" " /Shading %d 0 R\n" ">>\n" "endobj\n", - pdf_pattern->pattern_res.id, - pat_to_pdf.xx, pat_to_pdf.yx, - pat_to_pdf.xy, pat_to_pdf.yy, - pat_to_pdf.x0, pat_to_pdf.y0, res.id); if (pdf_pattern->gstate_res.id != 0) { @@ -3852,14 +4188,14 @@ _cairo_pdf_surface_emit_mesh_pattern (cairo_pdf_surface_t *surface, "%d 0 obj\n" "<< /Type /Pattern\n" " /PatternType 2\n" - " /Matrix [ %f %f %f %f %f %f ]\n" + " /Matrix [ ", + mask_resource.id); + _cairo_output_stream_print_matrix (surface->output, &pat_to_pdf); + _cairo_output_stream_printf (surface->output, + " ]\n" " /Shading %d 0 R\n" ">>\n" "endobj\n", - mask_resource.id, - pat_to_pdf.xx, pat_to_pdf.yx, - pat_to_pdf.xy, pat_to_pdf.yy, - pat_to_pdf.x0, pat_to_pdf.y0, res.id); status = cairo_pdf_surface_emit_transparency_group (surface, @@ -3873,11 +4209,11 @@ _cairo_pdf_surface_emit_mesh_pattern (cairo_pdf_surface_t *surface, return _cairo_output_stream_get_status (surface->output); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern_t *pdf_pattern) { double old_width, old_height; - cairo_status_t status; + cairo_int_status_t status; old_width = surface->width; old_height = surface->height; @@ -3918,16 +4254,18 @@ _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface, + cairo_operator_t op, const cairo_pattern_t *source, const cairo_rectangle_int_t *extents, + cairo_pdf_resource_t *smask_res, cairo_bool_t stencil_mask) { cairo_pdf_resource_t surface_res; int width, height; cairo_matrix_t cairo_p2d, pdf_p2d; - cairo_status_t status; + cairo_int_status_t status; int alpha; cairo_rectangle_int_t extents2; double x_offset; @@ -3949,9 +4287,12 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface, status = _cairo_pdf_surface_add_source_surface (surface, NULL, source, + op, source->filter, stencil_mask, + FALSE, extents, + smask_res, &surface_res, &width, &height, @@ -3965,7 +4306,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface, cairo_p2d = source->matrix; status = cairo_matrix_invert (&cairo_p2d); /* cairo_pattern_set_matrix ensures the matrix is invertible */ - assert (status == CAIRO_STATUS_SUCCESS); + assert (status == CAIRO_INT_STATUS_SUCCESS); pdf_p2d = surface->cairo_to_pdf; cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d); @@ -3983,11 +4324,8 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface, return status; if (! _cairo_matrix_is_identity (&pdf_p2d)) { - _cairo_output_stream_printf (surface->output, - "%f %f %f %f %f %f cm\n", - pdf_p2d.xx, pdf_p2d.yx, - pdf_p2d.xy, pdf_p2d.yy, - pdf_p2d.x0, pdf_p2d.y0); + _cairo_output_stream_print_matrix (surface->output, &pdf_p2d); + _cairo_output_stream_printf (surface->output, " cm\n"); } status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha); @@ -4008,28 +4346,29 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface, return _cairo_pdf_surface_add_xobject (surface, surface_res); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_paint_gradient (cairo_pdf_surface_t *surface, + cairo_operator_t op, const cairo_pattern_t *source, const cairo_rectangle_int_t *extents) { cairo_pdf_resource_t shading_res, gstate_res; cairo_matrix_t pat_to_pdf; - cairo_status_t status; + cairo_int_status_t status; int alpha; status = _cairo_pdf_surface_add_pdf_shading (surface, source, - extents, + op, extents, &shading_res, &gstate_res); if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; if (unlikely (status)) return status; pat_to_pdf = source->matrix; status = cairo_matrix_invert (&pat_to_pdf); /* cairo_pattern_set_matrix ensures the matrix is invertible */ - assert (status == CAIRO_STATUS_SUCCESS); + assert (status == CAIRO_INT_STATUS_SUCCESS); cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf); status = _cairo_pdf_operators_flush (&surface->pdf_operators); @@ -4037,11 +4376,8 @@ _cairo_pdf_surface_paint_gradient (cairo_pdf_surface_t *surface, return status; if (! _cairo_matrix_is_identity (&pat_to_pdf)) { - _cairo_output_stream_printf (surface->output, - "%f %f %f %f %f %f cm\n", - pat_to_pdf.xx, pat_to_pdf.yx, - pat_to_pdf.xy, pat_to_pdf.yy, - pat_to_pdf.x0, pat_to_pdf.y0); + _cairo_output_stream_print_matrix (surface->output, &pat_to_pdf); + _cairo_output_stream_printf (surface->output, " cm\n"); } status = _cairo_pdf_surface_add_shading (surface, shading_res); @@ -4071,8 +4407,9 @@ _cairo_pdf_surface_paint_gradient (cairo_pdf_surface_t *surface, return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t *surface, + cairo_operator_t op, const cairo_pattern_t *source, const cairo_rectangle_int_t *extents, cairo_bool_t mask) @@ -4081,13 +4418,16 @@ _cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t *surface, case CAIRO_PATTERN_TYPE_SURFACE: case CAIRO_PATTERN_TYPE_RASTER_SOURCE: return _cairo_pdf_surface_paint_surface_pattern (surface, + op, source, extents, + NULL, mask); case CAIRO_PATTERN_TYPE_LINEAR: case CAIRO_PATTERN_TYPE_RADIAL: case CAIRO_PATTERN_TYPE_MESH: return _cairo_pdf_surface_paint_gradient (surface, + op, source, extents); @@ -4123,11 +4463,11 @@ _can_paint_pattern (const cairo_pattern_t *pattern) } } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface, cairo_operator_t op) { - cairo_status_t status; + cairo_int_status_t status; if (op == surface->current_operator) return CAIRO_STATUS_SUCCESS; @@ -4144,13 +4484,13 @@ _cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface, return CAIRO_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface, const cairo_pattern_t *pattern, cairo_pdf_resource_t pattern_res, cairo_bool_t is_stroke) { - cairo_status_t status; + cairo_int_status_t status; int alpha; const cairo_color_t *solid_color = NULL; @@ -4366,14 +4706,14 @@ _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface) "endobj\n"); } -static cairo_status_t +static cairo_int_status_t _utf8_to_pdf_string (const char *utf8, char **str_out) { int i; int len; cairo_bool_t ascii; char *str; - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; ascii = TRUE; len = strlen (utf8); @@ -4421,13 +4761,13 @@ _utf8_to_pdf_string (const char *utf8, char **str_out) return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_unicode_for_glyph (cairo_pdf_surface_t *surface, const char *utf8) { uint16_t *utf16 = NULL; int utf16_len = 0; - cairo_status_t status; + cairo_int_status_t status; int i; if (utf8 && *utf8) { @@ -4651,7 +4991,7 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface, #define PDF_UNITS_PER_EM 1000 -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface, cairo_scaled_font_subset_t *font_subset, cairo_cff_subset_t *subset) @@ -4660,7 +5000,7 @@ _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface, cairo_pdf_resource_t subset_resource, to_unicode_stream; cairo_pdf_font_t font; unsigned int i, last_glyph; - cairo_status_t status; + cairo_int_status_t status; char tag[10]; _create_font_subset_tag (font_subset, subset->ps_name, tag); @@ -4690,7 +5030,7 @@ _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface, status = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset, &to_unicode_stream); - if (_cairo_status_is_error (status)) + if (_cairo_int_status_is_error (status)) return status; descriptor = _cairo_pdf_surface_new_object (surface); @@ -4848,11 +5188,11 @@ _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface, return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface, cairo_scaled_font_subset_t *font_subset) { - cairo_status_t status; + cairo_int_status_t status; cairo_cff_subset_t subset; char name[64]; @@ -4869,11 +5209,11 @@ _cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface, return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_cff_fallback_font (cairo_pdf_surface_t *surface, cairo_scaled_font_subset_t *font_subset) { - cairo_status_t status; + cairo_int_status_t status; cairo_cff_subset_t subset; char name[64]; @@ -4895,14 +5235,14 @@ _cairo_pdf_surface_emit_cff_fallback_font (cairo_pdf_surface_t *surface, return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface, cairo_scaled_font_subset_t *font_subset, cairo_type1_subset_t *subset) { cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream; cairo_pdf_font_t font; - cairo_status_t status; + cairo_int_status_t status; unsigned long length; unsigned int i, last_glyph; char tag[10]; @@ -4937,7 +5277,7 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface, status = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset, &to_unicode_stream); - if (_cairo_status_is_error (status)) + if (_cairo_int_status_is_error (status)) return status; last_glyph = font_subset->num_glyphs - 1; @@ -5037,11 +5377,11 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface, return _cairo_array_append (&surface->fonts, &font); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_type1_font_subset (cairo_pdf_surface_t *surface, cairo_scaled_font_subset_t *font_subset) { - cairo_status_t status; + cairo_int_status_t status; cairo_type1_subset_t subset; char name[64]; @@ -5061,11 +5401,11 @@ _cairo_pdf_surface_emit_type1_font_subset (cairo_pdf_surface_t *surface, return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_type1_fallback_font (cairo_pdf_surface_t *surface, cairo_scaled_font_subset_t *font_subset) { - cairo_status_t status; + cairo_int_status_t status; cairo_type1_subset_t subset; char name[64]; @@ -5085,13 +5425,13 @@ _cairo_pdf_surface_emit_type1_fallback_font (cairo_pdf_surface_t *surface, return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, cairo_scaled_font_subset_t *font_subset) { cairo_pdf_resource_t stream, descriptor, cidfont_dict; cairo_pdf_resource_t subset_resource, to_unicode_stream; - cairo_status_t status; + cairo_int_status_t status; cairo_pdf_font_t font; cairo_truetype_subset_t subset; unsigned int i, last_glyph; @@ -5131,7 +5471,7 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, status = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset, &to_unicode_stream); - if (_cairo_status_is_error (status)) { + if (_cairo_int_status_is_error (status)) { _cairo_truetype_subset_fini (&subset); return status; } @@ -5298,7 +5638,7 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_emit_imagemask (cairo_image_surface_t *image, cairo_output_stream_t *stream) { @@ -5343,8 +5683,8 @@ _cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_su void *closure) { cairo_pdf_surface_t *surface = closure; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - cairo_status_t status2; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + cairo_int_status_t status2; unsigned int i; cairo_surface_t *type3_surface; cairo_output_stream_t *null_stream; @@ -5353,7 +5693,8 @@ _cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_su type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font, null_stream, _cairo_pdf_emit_imagemask, - surface->font_subsets); + surface->font_subsets, + FALSE); if (unlikely (type3_surface->status)) { status2 = _cairo_output_stream_destroy (null_stream); status = type3_surface->status; @@ -5374,7 +5715,7 @@ _cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_su cairo_surface_destroy (type3_surface); status2 = _cairo_output_stream_destroy (null_stream); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) status = status2; return status; @@ -5384,7 +5725,7 @@ static cairo_int_status_t _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, cairo_scaled_font_subset_t *font_subset) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_pdf_resource_t *glyphs, encoding, char_procs, subset_resource, to_unicode_stream; cairo_pdf_font_t font; double *widths; @@ -5416,7 +5757,8 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font, NULL, _cairo_pdf_emit_imagemask, - surface->font_subsets); + surface->font_subsets, + FALSE); if (unlikely (type3_surface->status)) { free (glyphs); free (widths); @@ -5515,7 +5857,7 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, status = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset, &to_unicode_stream); - if (_cairo_status_is_error (status)) { + if (_cairo_int_status_is_error (status)) { free (widths); return status; } @@ -5613,10 +5955,10 @@ _cairo_pdf_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_sub return CAIRO_INT_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface) { - cairo_status_t status; + cairo_int_status_t status; status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets, _cairo_pdf_surface_analyze_user_font_subset, @@ -5698,7 +6040,7 @@ _cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface) return offset; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, cairo_pdf_smask_group_t *group) { @@ -5706,7 +6048,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, cairo_pdf_resource_t smask; cairo_pdf_smask_group_t *smask_group; cairo_pdf_resource_t pattern_res, gstate_res; - cairo_status_t status; + cairo_int_status_t status; cairo_box_double_t bbox; /* Create mask group */ @@ -5718,6 +6060,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, if (_can_paint_pattern (group->mask)) { _cairo_output_stream_printf (surface->output, "q\n"); status = _cairo_pdf_surface_paint_pattern (surface, + CAIRO_OPERATOR_OVER, group->mask, &group->extents, FALSE); @@ -5728,7 +6071,9 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, } else { pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, NULL, + status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, + CAIRO_OPERATOR_OVER, + NULL, &pattern_res, &gstate_res); if (unlikely (status)) return status; @@ -5791,6 +6136,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, if (_can_paint_pattern (group->source)) { _cairo_output_stream_printf (surface->output, "q\n"); status = _cairo_pdf_surface_paint_pattern (surface, + CAIRO_OPERATOR_OVER, group->source, &group->extents, FALSE); @@ -5801,7 +6147,9 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, } else { pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, NULL, + status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, + CAIRO_OPERATOR_OVER, + NULL, &pattern_res, &gstate_res); if (unlikely (status)) return status; @@ -5886,12 +6234,12 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, return _cairo_output_stream_get_status (surface->output); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface, cairo_pdf_smask_group_t *group) { double old_width, old_height; - cairo_status_t status; + cairo_int_status_t status; cairo_box_double_t bbox; old_width = surface->width; @@ -5965,14 +6313,14 @@ RESTORE_SIZE: return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface) { cairo_pdf_pattern_t pattern; cairo_pdf_smask_group_t *group; cairo_pdf_source_surface_t src_surface; unsigned int pattern_index, group_index, surface_index; - cairo_status_t status; + cairo_int_status_t status; /* Writing out PDF_MASK groups will cause additional smask groups * to be appended to surface->smask_groups. Additional patterns @@ -6013,11 +6361,11 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface return CAIRO_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface) { cairo_pdf_resource_t page, knockout, res; - cairo_status_t status; + cairo_int_status_t status; unsigned int i, len; _cairo_pdf_group_resources_clear (&surface->resources); @@ -6056,7 +6404,7 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface) return status; _cairo_pdf_group_resources_clear (&surface->resources); - status = _cairo_pdf_surface_open_content_stream (surface, NULL, NULL, FALSE); + status = _cairo_pdf_surface_open_content_stream (surface, NULL, NULL, FALSE, FALSE); if (unlikely (status)) return status; @@ -6329,7 +6677,7 @@ static cairo_int_status_t _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface) { cairo_box_double_t bbox; - cairo_status_t status; + cairo_int_status_t status; status = _cairo_pdf_surface_close_content_stream (surface); if (unlikely (status)) @@ -6344,17 +6692,194 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface) bbox.p1.y = 0; bbox.p2.x = surface->width; bbox.p2.y = surface->height; - return _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, TRUE); + return _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, TRUE, TRUE); +} + +/* If source is an opaque image and mask is an image and both images + * have the same bounding box we can emit them as a image/smask pair. + */ +static cairo_int_status_t +_cairo_pdf_surface_emit_combined_smask (cairo_pdf_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_rectangle_int_t *extents) +{ + cairo_int_status_t status; + cairo_image_surface_t *image; + void *image_extra; + cairo_image_transparency_t transparency; + cairo_pdf_resource_t smask_res; + int src_width, src_height; + int mask_width, mask_height; + double src_x_offset, src_y_offset; + double mask_x_offset, mask_y_offset; + double src_x1, src_y1, src_x2, src_y2; + double mask_x1, mask_y1, mask_x2, mask_y2; + cairo_matrix_t p2u; + double src_radius, mask_radius, e; + cairo_rectangle_int_t extents2; + cairo_bool_t need_smask; + + /* Check that source and mask are images */ + + if (!((source->type == CAIRO_PATTERN_TYPE_SURFACE || source->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) && + (mask->type == CAIRO_PATTERN_TYPE_SURFACE || mask->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (source->type == CAIRO_PATTERN_TYPE_SURFACE && + ((cairo_surface_pattern_t *) source)->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (mask->type == CAIRO_PATTERN_TYPE_SURFACE && + ((cairo_surface_pattern_t *) mask)->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (source->extend != CAIRO_EXTEND_NONE || mask->extend != CAIRO_EXTEND_NONE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Check that source is opaque and get image sizes */ + + status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source, + &image, &image_extra); + if (unlikely (status)) + return status; + + if (image->base.status) + return image->base.status; + + src_width = image->width; + src_height = image->height; + if (source->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { + cairo_surface_get_device_offset (&image->base, &src_x_offset, &src_y_offset); + } else { + src_x_offset = 0; + src_y_offset = 0; + } + + transparency = _cairo_image_analyze_transparency (image); + _cairo_pdf_surface_release_source_image_from_pattern (surface, source, image, image_extra); + + if (transparency != CAIRO_IMAGE_IS_OPAQUE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, mask, + &image, &image_extra); + if (unlikely (status)) + return status; + + if (image->base.status) + return image->base.status; + + mask_width = image->width; + mask_height = image->height; + if (mask->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { + cairo_surface_get_device_offset (&image->base, &mask_x_offset, &mask_y_offset); + } else { + mask_x_offset = 0; + mask_y_offset = 0; + } + + transparency = _cairo_image_analyze_transparency (image); + need_smask = transparency != CAIRO_IMAGE_IS_OPAQUE; + + _cairo_pdf_surface_release_source_image_from_pattern (surface, mask, image, image_extra); + + /* Check that both images have the same extents with a tolerance + * of half the smallest source pixel. */ + + p2u = source->matrix; + status = cairo_matrix_invert (&p2u); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_INT_STATUS_SUCCESS); + src_x1 = 0; + src_y1 = 0; + src_x2 = src_width; + src_y2 = src_height; + cairo_matrix_transform_point (&p2u, &src_x1, &src_y1); + cairo_matrix_transform_point (&p2u, &src_x2, &src_y2); + src_radius = _cairo_matrix_transformed_circle_major_axis (&p2u, 0.5); + + p2u = mask->matrix; + status = cairo_matrix_invert (&p2u); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_INT_STATUS_SUCCESS); + mask_x1 = 0; + mask_y1 = 0; + mask_x2 = mask_width; + mask_y2 = mask_height; + cairo_matrix_transform_point (&p2u, &mask_x1, &mask_y1); + cairo_matrix_transform_point (&p2u, &mask_x2, &mask_y2); + mask_radius = _cairo_matrix_transformed_circle_major_axis (&p2u, 0.5); + + if (src_radius < mask_radius) + e = src_radius; + else + e = mask_radius; + + if (fabs(src_x1 - mask_x1) > e || + fabs(src_x2 - mask_x2) > e || + fabs(src_y1 - mask_y1) > e || + fabs(src_y2 - mask_y2) > e) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Check both images have same device offset */ + if (fabs(src_x_offset - mask_x_offset) > e || + fabs(src_y_offset - mask_y_offset) > e) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (need_smask) { + status = _cairo_pdf_surface_add_source_surface (surface, + NULL, + mask, + op, + source->filter, + FALSE, + TRUE, + extents, + NULL, + &smask_res, + &mask_width, + &mask_height, + &mask_x_offset, + &mask_y_offset, + &extents2); + if (unlikely (status)) + return status; + } + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, "q\n"); + status = _cairo_pdf_surface_paint_surface_pattern (surface, op, source, extents, + need_smask ? &smask_res : NULL, + FALSE); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, "Q\n"); + + status = _cairo_output_stream_get_status (surface->output); + + + return status; } /* A PDF stencil mask is an A1 mask used with the current color */ static cairo_int_status_t _cairo_pdf_surface_emit_stencil_mask (cairo_pdf_surface_t *surface, + cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, const cairo_rectangle_int_t *extents) { - cairo_status_t status; + cairo_int_status_t status; cairo_image_surface_t *image; void *image_extra; cairo_image_transparency_t transparency; @@ -6396,7 +6921,7 @@ _cairo_pdf_surface_emit_stencil_mask (cairo_pdf_surface_t *surface, return status; _cairo_output_stream_printf (surface->output, "q\n"); - status = _cairo_pdf_surface_paint_surface_pattern (surface, mask, NULL, TRUE); + status = _cairo_pdf_surface_paint_surface_pattern (surface, op, mask, extents, NULL, TRUE); if (unlikely (status)) return status; @@ -6472,6 +6997,7 @@ _cairo_pdf_surface_paint (void *abstract_surface, if (_can_paint_pattern (source)) { _cairo_output_stream_printf (surface->output, "q\n"); status = _cairo_pdf_surface_paint_pattern (surface, + op, source, &extents.bounded, FALSE); @@ -6485,7 +7011,7 @@ _cairo_pdf_surface_paint (void *abstract_surface, pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op, &extents.bounded, &pattern_res, &gstate_res); if (unlikely (status)) @@ -6567,7 +7093,7 @@ _cairo_pdf_surface_mask (void *abstract_surface, return status; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { - cairo_status_t source_status, mask_status; + cairo_int_status_t source_status, mask_status; status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded); if (_cairo_int_status_is_error (status)) @@ -6625,8 +7151,13 @@ _cairo_pdf_surface_mask (void *abstract_surface, if (unlikely (status)) goto cleanup; + /* Check if we can combine source and mask into a smask image */ + status = _cairo_pdf_surface_emit_combined_smask (surface, op, source, mask, &extents.bounded); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + goto cleanup; + /* Check if we can use a stencil mask */ - status = _cairo_pdf_surface_emit_stencil_mask (surface, source, mask, &extents.bounded); + status = _cairo_pdf_surface_emit_stencil_mask (surface, op, source, mask, &extents.bounded); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto cleanup; @@ -6743,7 +7274,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface, pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op, &extents.bounded, &pattern_res, &gstate_res); if (unlikely (status)) @@ -6896,6 +7427,7 @@ _cairo_pdf_surface_fill (void *abstract_surface, goto cleanup; status = _cairo_pdf_surface_paint_pattern (surface, + op, source, &extents.bounded, FALSE); @@ -6909,7 +7441,7 @@ _cairo_pdf_surface_fill (void *abstract_surface, pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op, &extents.bounded, &pattern_res, &gstate_res); if (unlikely (status)) @@ -7084,6 +7616,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, fill_pattern_res.id = 0; gstate_res.id = 0; status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source, + fill_op, &extents.bounded, &fill_pattern_res, &gstate_res); @@ -7096,6 +7629,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, gstate_res.id = 0; status = _cairo_pdf_surface_add_pdf_pattern (surface, stroke_source, + stroke_op, &extents.bounded, &stroke_pattern_res, &gstate_res); @@ -7187,7 +7721,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op, &extents.bounded, &pattern_res, &gstate_res); if (unlikely (status)) diff --git a/src/cairo-pdf.h b/src/cairo-pdf.h index 1bc8524f2..1bc8524f2 100755..100644 --- a/src/cairo-pdf.h +++ b/src/cairo-pdf.h diff --git a/src/cairo-pen.c b/src/cairo-pen.c index 61be0e829..61be0e829 100755..100644 --- a/src/cairo-pen.c +++ b/src/cairo-pen.c diff --git a/src/cairo-tg-private.h b/src/cairo-pixman-private.h index 6e2464ea4..d705025c8 100755..100644 --- a/src/cairo-tg-private.h +++ b/src/cairo-pixman-private.h @@ -1,5 +1,7 @@ -/* - * Copyright © 2012 SCore Corporation +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright ©2013 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -24,34 +26,26 @@ * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. * - * Author: Taekyun Kim (podain77@gmail.com) + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> */ -#ifndef CAIRO_TG_PRIVATE_H -#define CAIRO_TG_PRIVATE_H +#ifndef CAIRO_PIXMAN_PRIVATE_H +#define CAIRO_PIXMAN_PRIVATE_H -#include "cairo-default-context-private.h" -#include "cairo-surface-private.h" -#include "cairo-tg-journal-private.h" -#include <pixman.h> +#include "cairo-pixman-private.h" /* keep make check happy */ -#define CAIRO_TG_NUM_MAX_TILES 8 - -typedef struct _cairo_tg_surface -{ - cairo_surface_t base; - - cairo_format_t format; - pixman_format_code_t pixman_format; - unsigned char *data; - int width; - int height; - int stride; - int bpp; +#include <pixman.h> - cairo_surface_t *image_surface; - cairo_surface_t *tile_surfaces[CAIRO_TG_NUM_MAX_TILES]; - cairo_tg_journal_t journal; -} cairo_tg_surface_t; +#if PIXMAN_VERSION < PIXMAN_VERSION_ENCODE(0,22,0) +#define pixman_image_composite32 pixman_image_composite +#define pixman_image_get_component_alpha(i) 0 +#define pixman_image_set_component_alpha(i, x) do { } while (0) +#endif -#endif /* CAIRO_TG_PRIVATE_H */ +#endif diff --git a/src/cairo-png.c b/src/cairo-png.c index e74a4a8bc..068617d58 100755..100644 --- a/src/cairo-png.c +++ b/src/cairo-png.c @@ -149,13 +149,13 @@ static void png_simple_warning_callback (png_structp png, png_const_charp error_msg) { - cairo_status_t *error = png_get_error_ptr (png); - - /* default to the most likely error */ - if (*error == CAIRO_STATUS_SUCCESS) - *error = _cairo_error (CAIRO_STATUS_NO_MEMORY); - - /* png does not expect to abort and will try to tidy up after a warning */ + /* png does not expect to abort and will try to tidy up and continue + * loading the image after a warning. So we also want to return the + * (incorrect?) surface. + * + * We use our own warning callback to squelch any attempts by libpng + * to write to stderr as we may not be in control of that output. + */ } diff --git a/src/cairo-polygon-intersect.c b/src/cairo-polygon-intersect.c index 2cd73d2e5..2cd73d2e5 100755..100644 --- a/src/cairo-polygon-intersect.c +++ b/src/cairo-polygon-intersect.c diff --git a/src/cairo-polygon-reduce.c b/src/cairo-polygon-reduce.c index ea457fe4e..ea457fe4e 100755..100644 --- a/src/cairo-polygon-reduce.c +++ b/src/cairo-polygon-reduce.c diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c index b0424f6e7..b0424f6e7 100755..100644 --- a/src/cairo-polygon.c +++ b/src/cairo-polygon.c diff --git a/src/cairo-private.h b/src/cairo-private.h index 9f4f55b7c..9f4f55b7c 100755..100644 --- a/src/cairo-private.h +++ b/src/cairo-private.h diff --git a/src/cairo-ps-surface-private.h b/src/cairo-ps-surface-private.h index 1d5d27d49..1d5d27d49 100755..100644 --- a/src/cairo-ps-surface-private.h +++ b/src/cairo-ps-surface-private.h diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 01df6090b..4fc15f632 100755..100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -340,14 +340,48 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface) "/rg { setrgbcolor } bind def\n" "/d1 { setcachedevice } bind def\n"); + if (!surface->eps) { + _cairo_output_stream_printf (surface->final_stream, + "/cairo_set_page_size {\n" + " %% Change paper size, but only if different from previous paper size otherwise\n" + " %% duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size\n" + " %% so we use the same when checking if the size changes.\n" + " /setpagedevice where {\n" + " pop currentpagedevice\n" + " /PageSize known {\n" + " 2 copy\n" + " currentpagedevice /PageSize get aload pop\n" + " exch 4 1 roll\n" + " sub abs 5 gt\n" + " 3 1 roll\n" + " sub abs 5 gt\n" + " or\n" + " } {\n" + " true\n" + " } ifelse\n" + " {\n" + " 2 array astore\n" + " 2 dict begin\n" + " /PageSize exch def\n" + " /ImagingBBox null def\n" + " currentdict end\n" + " setpagedevice\n" + " } {\n" + " pop pop\n" + " } ifelse\n" + " } {\n" + " pop\n" + " } ifelse\n" + "} def\n"); + } + _cairo_output_stream_printf (surface->final_stream, "%%%%EndProlog\n"); + _cairo_output_stream_printf (surface->final_stream, + "%%%%BeginSetup\n"); num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments); if (num_comments) { - _cairo_output_stream_printf (surface->final_stream, - "%%%%BeginSetup\n"); - comments = _cairo_array_index (&surface->dsc_setup_comments, 0); for (i = 0; i < num_comments; i++) { _cairo_output_stream_printf (surface->final_stream, @@ -355,9 +389,6 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface) free (comments[i]); comments[i] = NULL; } - - _cairo_output_stream_printf (surface->final_stream, - "%%%%EndSetup\n"); } } @@ -385,8 +416,13 @@ _cairo_ps_surface_emit_type1_font_subset (cairo_ps_surface_t *surface, "%% _cairo_ps_surface_emit_type1_font_subset\n"); #endif + _cairo_output_stream_printf (surface->final_stream, + "%%%%BeginResource: font %s\n", + subset.base_font); length = subset.header_length + subset.data_length + subset.trailer_length; _cairo_output_stream_write (surface->final_stream, subset.data, length); + _cairo_output_stream_printf (surface->final_stream, + "%%%%EndResource\n"); _cairo_type1_subset_fini (&subset); @@ -409,15 +445,18 @@ _cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t *surface, if (unlikely (status)) return status; - /* FIXME: Figure out document structure convention for fonts */ - #if DEBUG_PS _cairo_output_stream_printf (surface->final_stream, "%% _cairo_ps_surface_emit_type1_font_fallback\n"); #endif + _cairo_output_stream_printf (surface->final_stream, + "%%%%BeginResource: font %s\n", + subset.base_font); length = subset.header_length + subset.data_length + subset.trailer_length; _cairo_output_stream_write (surface->final_stream, subset.data, length); + _cairo_output_stream_printf (surface->final_stream, + "%%%%EndResource\n"); _cairo_type1_fallback_fini (&subset); @@ -446,6 +485,9 @@ _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface, #endif _cairo_output_stream_printf (surface->final_stream, + "%%%%BeginResource: font %s\n", + subset.ps_name); + _cairo_output_stream_printf (surface->final_stream, "11 dict begin\n" "/FontType 42 def\n" "/FontName /%s def\n" @@ -527,13 +569,15 @@ _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface, "/f-%d-%d currentdict end definefont pop\n", font_subset->font_id, font_subset->subset_id); - + _cairo_output_stream_printf (surface->final_stream, + "%%%%EndResource\n"); _cairo_truetype_subset_fini (&subset); + return CAIRO_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _cairo_ps_emit_imagemask (cairo_image_surface_t *image, cairo_output_stream_t *stream) { @@ -587,7 +631,8 @@ _cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_sub type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font, NULL, _cairo_ps_emit_imagemask, - surface->font_subsets); + surface->font_subsets, + TRUE); for (i = 0; i < font_subset->num_glyphs; i++) { status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface, @@ -624,6 +669,8 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface, #endif _cairo_output_stream_printf (surface->final_stream, + "%%%%BeginResource: font\n"); + _cairo_output_stream_printf (surface->final_stream, "8 dict begin\n" "/FontType 3 def\n" "/FontMatrix [1 0 0 1 0 0] def\n" @@ -633,7 +680,8 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface, type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font, NULL, _cairo_ps_emit_imagemask, - surface->font_subsets); + surface->font_subsets, + TRUE); status = type3_surface->status; if (unlikely (status)) { cairo_surface_destroy (type3_surface); @@ -705,6 +753,8 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface, - _cairo_fixed_to_double (font_bbox.p1.y), font_subset->font_id, font_subset->subset_id); + _cairo_output_stream_printf (surface->final_stream, + "%%%%EndResource\n"); return CAIRO_STATUS_SUCCESS; } @@ -1025,7 +1075,8 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, _cairo_pdf_operators_init (&surface->pdf_operators, surface->stream, &surface->cairo_to_ps, - surface->font_subsets); + surface->font_subsets, + TRUE); surface->num_pages = 0; cairo_list_init (&surface->document_media); @@ -1568,6 +1619,9 @@ _cairo_ps_surface_finish (void *abstract_surface) if (unlikely (status)) goto CLEANUP; + _cairo_output_stream_printf (surface->final_stream, + "%%%%EndSetup\n"); + status = _cairo_ps_surface_emit_body (surface); if (unlikely (status)) goto CLEANUP; @@ -2738,11 +2792,9 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface, } _cairo_output_stream_printf (surface->stream, - " /Interpolate %s def\n" " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n" "end\n" "%s\n", - interpolate, ps_image->height, stencil_mask ? "imagemask" : "image"); } @@ -3113,6 +3165,16 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface, { cairo_int_status_t status; + if (source_pattern->type == CAIRO_PATTERN_TYPE_SURFACE && + source_pattern->extend != CAIRO_EXTEND_PAD) + { + cairo_surface_t *surf = ((cairo_surface_pattern_t *) source_pattern)->surface; + + status = _cairo_ps_surface_emit_jpeg_image (surface, surf, width, height); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + if (source_surface->type == CAIRO_SURFACE_TYPE_RECORDING) { if (source_surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source_surface; @@ -3122,12 +3184,6 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface, } } else { cairo_image_surface_t *image = (cairo_image_surface_t *) source_surface; - if (source_pattern->extend != CAIRO_EXTEND_PAD) { - status = _cairo_ps_surface_emit_jpeg_image (surface, source_surface, - width, height); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; - } status = _cairo_ps_surface_emit_image (surface, image, op, source_pattern->filter, stencil_mask); @@ -3267,11 +3323,9 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface, cairo_matrix_scale (&ps_p2d, 1.0, -1.0); if (! _cairo_matrix_is_identity (&ps_p2d)) { - _cairo_output_stream_printf (surface->stream, - "[ %f %f %f %f %f %f ] concat\n", - ps_p2d.xx, ps_p2d.yx, - ps_p2d.xy, ps_p2d.yy, - ps_p2d.x0, ps_p2d.y0); + _cairo_output_stream_printf (surface->stream, "[ "); + _cairo_output_stream_print_matrix (surface->stream, &ps_p2d); + _cairo_output_stream_printf (surface->stream, " ] concat\n"); } status = _cairo_ps_surface_emit_surface (surface, @@ -3419,7 +3473,7 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, _cairo_output_stream_printf (surface->stream, " /BBox [0 0 %d %d]\n" " /PaintProc {\n" - " CairoPattern\n" + " pop CairoPattern\n" " [-1 0 0 1 %d 0] concat CairoPattern\n" " [ 1 0 0 -1 0 %d] concat CairoPattern\n" " [-1 0 0 1 %d 0] concat CairoPattern\n" @@ -3440,7 +3494,7 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, pattern_width, pattern_height); } _cairo_output_stream_printf (surface->stream, - " /PaintProc { CairoPattern }\n"); + " /PaintProc { pop CairoPattern }\n"); } _cairo_output_stream_printf (surface->stream, @@ -3458,12 +3512,10 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, cairo_matrix_translate (&ps_p2d, 0.0, pattern_height); cairo_matrix_scale (&ps_p2d, 1.0, -1.0); + _cairo_output_stream_printf (surface->stream, "[ "); + _cairo_output_stream_print_matrix (surface->stream, &ps_p2d); _cairo_output_stream_printf (surface->stream, - "[ %f %f %f %f %f %f ]\n", - ps_p2d.xx, ps_p2d.yx, - ps_p2d.xy, ps_p2d.yy, - ps_p2d.x0, ps_p2d.y0); - _cairo_output_stream_printf (surface->stream, + " ]\n" "makepattern setpattern\n"); release_source: @@ -3837,11 +3889,10 @@ _cairo_ps_surface_emit_gradient (cairo_ps_surface_t *surface, if (is_ps_pattern) { _cairo_output_stream_printf (surface->stream, ">>\n" - "[ %f %f %f %f %f %f ]\n" - "makepattern setpattern\n", - pat_to_ps.xx, pat_to_ps.yx, - pat_to_ps.xy, pat_to_ps.yy, - pat_to_ps.x0, pat_to_ps.y0); + "[ "); + _cairo_output_stream_print_matrix (surface->stream, &pat_to_ps); + _cairo_output_stream_printf (surface->stream, " ]\n" + "makepattern setpattern\n"); } else { _cairo_output_stream_printf (surface->stream, "shfill\n"); @@ -3919,11 +3970,10 @@ _cairo_ps_surface_emit_mesh_pattern (cairo_ps_surface_t *surface, if (is_ps_pattern) { _cairo_output_stream_printf (surface->stream, ">>\n" - "[ %f %f %f %f %f %f ]\n", - pat_to_ps.xx, pat_to_ps.yx, - pat_to_ps.xy, pat_to_ps.yy, - pat_to_ps.x0, pat_to_ps.y0); + "[ \n"); + _cairo_output_stream_print_matrix (surface->stream, &pat_to_ps); _cairo_output_stream_printf (surface->stream, + " ]\n" "makepattern\n" "setpattern\n"); } else { @@ -4022,11 +4072,9 @@ _cairo_ps_surface_paint_gradient (cairo_ps_surface_t *surface, cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps); if (! _cairo_matrix_is_identity (&pat_to_ps)) { - _cairo_output_stream_printf (surface->stream, - "[%f %f %f %f %f %f] concat\n", - pat_to_ps.xx, pat_to_ps.yx, - pat_to_ps.xy, pat_to_ps.yy, - pat_to_ps.x0, pat_to_ps.y0); + _cairo_output_stream_printf (surface->stream, "["); + _cairo_output_stream_print_matrix (surface->stream, &pat_to_ps); + _cairo_output_stream_printf (surface->stream, "] concat\n"); } if (source->type == CAIRO_PATTERN_TYPE_MESH) { @@ -4578,6 +4626,13 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface, x1, y1, x2, y2); } + if (!surface->eps) { + _cairo_output_stream_printf (surface->stream, + "%f %f cairo_set_page_size\n", + ceil(surface->width), + ceil(surface->height)); + } + _cairo_output_stream_printf (surface->stream, "%%%%EndPageSetup\n" "q %d %d %d %d rectclip q\n", diff --git a/src/cairo-ps.h b/src/cairo-ps.h index 33d0e0d94..33d0e0d94 100755..100644 --- a/src/cairo-ps.h +++ b/src/cairo-ps.h diff --git a/src/cairo-qt-surface.cpp b/src/cairo-qt-surface.cpp index ce05dba7e..7ddad77df 100755..100644 --- a/src/cairo-qt-surface.cpp +++ b/src/cairo-qt-surface.cpp @@ -306,6 +306,8 @@ _qimage_format_from_cairo_format (cairo_format_t fmt) #else return QImage::Format_MonoLSB; #endif + case CAIRO_FORMAT_RGB30: + return QImage::Format_Mono; } return QImage::Format_Mono; @@ -386,7 +388,7 @@ _cairo_path_to_qpainterpath_close_path (void *closure) return CAIRO_STATUS_SUCCESS; } -static inline QPainterPath +static QPainterPath path_to_qt (const cairo_path_fixed_t *path, const cairo_matrix_t *ctm_inverse = NULL) { @@ -849,7 +851,8 @@ _cairo_qt_surface_set_clip (cairo_qt_surface_t *qs, */ struct PatternToBrushConverter { - PatternToBrushConverter (const cairo_pattern_t *pattern) : + PatternToBrushConverter (const cairo_pattern_t *pattern) + __attribute__ ((noinline)) : mAcquiredImageParent(0), mAcquiredImage(0), mAcquiredImageExtra(0) @@ -1048,7 +1051,7 @@ struct PatternToBrushConverter { } } - ~PatternToBrushConverter () { + ~PatternToBrushConverter () __attribute__ ((noinline)){ if (mAcquiredImageParent) _cairo_surface_release_source_image (mAcquiredImageParent, mAcquiredImage, mAcquiredImageExtra); } @@ -1657,13 +1660,30 @@ cairo_qt_surface_create_with_qpixmap (cairo_content_t content, return &qs->base; } +/** + * _cairo_surface_is_qt: + * @surface: a #cairo_surface_t + * + * Checks if a surface is a #cairo_qt_surface_t + * + * Return value: True if the surface is an qt surface + **/ +static inline cairo_bool_t +_cairo_surface_is_qt (cairo_surface_t *surface) +{ + return surface->backend == &cairo_qt_surface_backend; +} + QPainter * cairo_qt_surface_get_qpainter (cairo_surface_t *surface) { cairo_qt_surface_t *qs = (cairo_qt_surface_t*) surface; - if (surface->type != CAIRO_SURFACE_TYPE_QT) + /* Throw an error for a non-qt surface */ + if (! _cairo_surface_is_qt (surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return NULL; + } return qs->p; } @@ -1673,8 +1693,11 @@ cairo_qt_surface_get_qimage (cairo_surface_t *surface) { cairo_qt_surface_t *qs = (cairo_qt_surface_t*) surface; - if (surface->type != CAIRO_SURFACE_TYPE_QT) + /* Throw an error for a non-qt surface */ + if (! _cairo_surface_is_qt (surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return NULL; + } return qs->image; } @@ -1684,8 +1707,10 @@ cairo_qt_surface_get_image (cairo_surface_t *surface) { cairo_qt_surface_t *qs = (cairo_qt_surface_t*) surface; - if (surface->type != CAIRO_SURFACE_TYPE_QT) - return NULL; + /* Throw an error for a non-qt surface */ + if (! _cairo_surface_is_qt (surface)) { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + } return qs->image_equiv; } diff --git a/src/cairo-qt.h b/src/cairo-qt.h index c20bbb18d..c20bbb18d 100755..100644 --- a/src/cairo-qt.h +++ b/src/cairo-qt.h diff --git a/src/cairo-quartz-filters.c b/src/cairo-quartz-filters.c index 804cddfde..aafceaf68 100755..100644 --- a/src/cairo-quartz-filters.c +++ b/src/cairo-quartz-filters.c @@ -363,7 +363,7 @@ _cairo_quartz_gaussian_filter (const cairo_pattern_t *src, if (! image_ctx) { free (kernel); *out_image = NULL; - return CAIRO_INT_STATUS_NO_MEMORY; + return CAIRO_INT_STATUS_NO_MEMORY; } #else image_provider = CGImageGetDataProvider (resized_image); diff --git a/src/cairo-quartz-font.c b/src/cairo-quartz-font.c index a9bbbdc7a..02f34267b 100755..100644 --- a/src/cairo-quartz-font.c +++ b/src/cairo-quartz-font.c @@ -81,9 +81,6 @@ static void (*CGFontGetGlyphsForUnicharsPtr) (CGFontRef, const UniChar[], const static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL; static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL; -/* Not public in the least bit */ -static CGPathRef (*CGFontGetGlyphPathPtr) (CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph) = NULL; - /* CGFontGetHMetrics isn't public, but the other functions are public/present in 10.5 */ typedef struct { int ascent; @@ -127,7 +124,6 @@ quartz_font_ensure_symbols(void) /* These have the same name in 10.4 and 10.5 */ CGFontGetUnitsPerEmPtr = dlsym(RTLD_DEFAULT, "CGFontGetUnitsPerEm"); CGFontGetGlyphAdvancesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphAdvances"); - CGFontGetGlyphPathPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphPath"); CGFontGetHMetricsPtr = dlsym(RTLD_DEFAULT, "CGFontGetHMetrics"); CGFontGetAscentPtr = dlsym(RTLD_DEFAULT, "CGFontGetAscent"); @@ -144,7 +140,6 @@ quartz_font_ensure_symbols(void) CGFontGetGlyphsForUnicharsPtr && CGFontGetUnitsPerEmPtr && CGFontGetGlyphAdvancesPtr && - CGFontGetGlyphPathPtr && (CGFontGetHMetricsPtr || (CGFontGetAscentPtr && CGFontGetDescentPtr && CGFontGetLeadingPtr))) _cairo_quartz_font_symbols_present = TRUE; @@ -241,12 +236,13 @@ _cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, return CAIRO_STATUS_SUCCESS; } -static void +static cairo_bool_t _cairo_quartz_font_face_destroy (void *abstract_face) { cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face; CGFontRelease (font_face->cgFont); + return TRUE; } static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend; @@ -549,6 +545,7 @@ _cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font, CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph); CGAffineTransform textMatrix; CGPathRef glyphPath; + CTFontRef ctFont; cairo_path_fixed_t *path; if (glyph == INVALID_GLYPH) { @@ -563,7 +560,9 @@ _cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font, -font->base.scale.yy, 0, 0); - glyphPath = CGFontGetGlyphPathPtr (font_face->cgFont, &textMatrix, 0, glyph); + ctFont = CTFontCreateWithGraphicsFont (font_face->cgFont, 0.0, NULL, NULL); + glyphPath = CTFontCreatePathForGlyph (ctFont, glyph, &textMatrix); + CFRelease (ctFont); if (!glyphPath) return CAIRO_INT_STATUS_UNSUPPORTED; diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c index 2715abd06..498a7b064 100755..100644 --- a/src/cairo-quartz-image-surface.c +++ b/src/cairo-quartz-image-surface.c @@ -378,8 +378,10 @@ cairo_quartz_image_surface_get_image (cairo_surface_t *asurface) { cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t*) asurface; - if (asurface->type != CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) - return NULL; + /* Throw an error for a non-quartz surface */ + if (! _cairo_surface_is_quartz (asurface)) { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + } return (cairo_surface_t*) surface->imageSurface; } diff --git a/src/cairo-quartz-image.h b/src/cairo-quartz-image.h index dae234dac..dae234dac 100755..100644 --- a/src/cairo-quartz-image.h +++ b/src/cairo-quartz-image.h diff --git a/src/cairo-quartz-private.h b/src/cairo-quartz-private.h index 58b97ac99..5e97392db 100755..100644 --- a/src/cairo-quartz-private.h +++ b/src/cairo-quartz-private.h @@ -83,6 +83,9 @@ typedef struct cairo_quartz_image_surface { cairo_private cairo_bool_t _cairo_quartz_verify_surface_size(int width, int height); +cairo_private cairo_bool_t +_cairo_surface_is_quartz (const cairo_surface_t *surface); + cairo_private CGImageRef CairoQuartzCreateCGImage (cairo_format_t format, unsigned int width, diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index 6d0a0c079..a27128150 100755..100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -257,9 +257,6 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext, unsigned int width, unsigned int height); -static cairo_bool_t -_cairo_surface_is_quartz (const cairo_surface_t *surface); - /* Load all extra symbols */ static void quartz_ensure_symbols (void) { @@ -1521,7 +1518,6 @@ _cairo_quartz_teardown_state (cairo_quartz_drawing_state_t *state, CGContextDrawLayerInRect (surface->cgContext, state->clipRect, state->layer); - CGContextRelease (state->cgDrawContext); CGLayerRelease (state->layer); } @@ -1805,7 +1801,7 @@ _cairo_quartz_cg_mask_with_surface (cairo_composite_rectangles_t *extents, cairo_matrix_t m = *mask_mat; _cairo_surface_get_extents (extents->surface, &dest_extents); - status = _cairo_surface_to_cgimage (&extents->mask_pattern.base, + status = _cairo_surface_to_cgimage (&extents->mask_pattern.base, mask_surf, &dest_extents, format, &m, extents->clip, &img); if (unlikely (status)) @@ -2791,7 +2787,15 @@ cairo_quartz_surface_get_cg_context (cairo_surface_t *surface) return NULL; } -static cairo_bool_t +/** + * _cairo_surface_is_quartz: + * @surface: a #cairo_surface_t + * + * Checks if a surface is a #cairo_quartz_surface_t + * + * Return value: True if the surface is an quartz surface + **/ +cairo_bool_t _cairo_surface_is_quartz (const cairo_surface_t *surface) { return surface->backend == &cairo_quartz_surface_backend; diff --git a/src/cairo-quartz.h b/src/cairo-quartz.h index 9be5f9ae5..9be5f9ae5 100755..100644 --- a/src/cairo-quartz.h +++ b/src/cairo-quartz.h diff --git a/src/cairo-raster-source-pattern.c b/src/cairo-raster-source-pattern.c index 2fd8bdb63..bcaa29dc9 100755..100644 --- a/src/cairo-raster-source-pattern.c +++ b/src/cairo-raster-source-pattern.c @@ -57,8 +57,6 @@ * Other callbacks are provided for when the pattern is copied temporarily * during rasterisation, or more permanently as a snapshot in order to keep * the pixel data available for printing. - * - * Since: 1.12 **/ cairo_surface_t * diff --git a/src/cairo-recording-surface-inline.h b/src/cairo-recording-surface-inline.h index 9002ccd69..9002ccd69 100755..100644 --- a/src/cairo-recording-surface-inline.h +++ b/src/cairo-recording-surface-inline.h diff --git a/src/cairo-recording-surface-private.h b/src/cairo-recording-surface-private.h index 0235b0f3f..456c63389 100755..100644 --- a/src/cairo-recording-surface-private.h +++ b/src/cairo-recording-surface-private.h @@ -133,9 +133,11 @@ typedef struct _cairo_recording_surface { cairo_bool_t unbounded; cairo_array_t commands; - int *indices; - int num_indices; + unsigned int *indices; + unsigned int num_indices; cairo_bool_t optimize_clears; + cairo_bool_t has_bilevel_alpha; + cairo_bool_t has_only_op_over; struct bbtree { cairo_box_t extents; @@ -184,4 +186,10 @@ _cairo_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface, cairo_box_t *bbox, const cairo_matrix_t *transform); +cairo_private cairo_bool_t +_cairo_recording_surface_has_only_bilevel_alpha (cairo_recording_surface_t *surface); + +cairo_private cairo_bool_t +_cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface); + #endif /* CAIRO_RECORDING_SURFACE_H */ diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c index 9e672df2c..ee9304746 100755..100644 --- a/src/cairo-recording-surface.c +++ b/src/cairo-recording-surface.c @@ -87,6 +87,7 @@ #include "cairo-error-private.h" #include "cairo-image-surface-private.h" #include "cairo-recording-surface-inline.h" +#include "cairo-surface-snapshot-inline.h" #include "cairo-surface-wrapper-private.h" #include "cairo-traps-private.h" @@ -257,7 +258,7 @@ static cairo_bool_t box_outside (const cairo_box_t *a, const cairo_box_t *b) static void bbtree_foreach_mark_visible (struct bbtree *bbt, const cairo_box_t *box, - int **indices) + unsigned int **indices) { cairo_command_header_t *chain; @@ -270,13 +271,13 @@ bbtree_foreach_mark_visible (struct bbtree *bbt, bbtree_foreach_mark_visible (bbt->right, box, indices); } -static inline int intcmp (const int a, const int b) +static inline int intcmp (const unsigned int a, const unsigned int b) { return a - b; } -CAIRO_COMBSORT_DECLARE (sort_indices, int, intcmp) +CAIRO_COMBSORT_DECLARE (sort_indices, unsigned int, intcmp) -static inline int sizecmp (int a, int b, cairo_command_header_t **elements) +static inline int sizecmp (unsigned int a, unsigned int b, cairo_command_header_t **elements) { const cairo_rectangle_int_t *r; @@ -288,7 +289,7 @@ static inline int sizecmp (int a, int b, cairo_command_header_t **elements) return b - a; } -CAIRO_COMBSORT_DECLARE_WITH_DATA (sort_commands, int, sizecmp) +CAIRO_COMBSORT_DECLARE_WITH_DATA (sort_commands, unsigned int, sizecmp) static void _cairo_recording_surface_destroy_bbtree (cairo_recording_surface_t *surface) @@ -323,9 +324,9 @@ _cairo_recording_surface_create_bbtree (cairo_recording_surface_t *surface) if (unlikely (elements == NULL)) return _cairo_error (CAIRO_STATUS_NULL_POINTER); + unsigned int *indices; cairo_status_t status; - int i, count; - int *indices; + unsigned int i, count; count = surface->commands.num_elements; if (count > surface->num_indices) { @@ -423,6 +424,8 @@ cairo_recording_surface_create (cairo_content_t content, surface->indices = NULL; surface->num_indices = 0; surface->optimize_clears = TRUE; + surface->has_bilevel_alpha = FALSE; + surface->has_only_op_over = FALSE; return &surface->base; } @@ -1589,9 +1592,12 @@ static int _cairo_recording_surface_get_visible_commands (cairo_recording_surface_t *surface, const cairo_rectangle_int_t *extents) { - int num_visible, *indices; + unsigned int num_visible, *indices; cairo_box_t box; + if (surface->commands.num_elements == 0) + return 0; + _cairo_box_from_rectangle (&box, extents); if (surface->bbtree.chain == INVALID_CHAIN) @@ -1606,6 +1612,68 @@ _cairo_recording_surface_get_visible_commands (cairo_recording_surface_t *surfac return num_visible; } +static void +_cairo_recording_surface_merge_source_attributes (cairo_recording_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source) +{ + if (op != CAIRO_OPERATOR_OVER) + surface->has_only_op_over = FALSE; + + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) source; + cairo_surface_t *surf = surf_pat->surface; + cairo_surface_t *free_me = NULL; + + if (_cairo_surface_is_snapshot (surf)) + free_me = surf = _cairo_surface_snapshot_get_target (surf); + + if (surf->type == CAIRO_SURFACE_TYPE_RECORDING) { + cairo_recording_surface_t *rec_surf = (cairo_recording_surface_t *) surf; + + if (! _cairo_recording_surface_has_only_bilevel_alpha (rec_surf)) + surface->has_bilevel_alpha = FALSE; + + if (! _cairo_recording_surface_has_only_op_over (rec_surf)) + surface->has_only_op_over = FALSE; + + } else if (surf->type == CAIRO_SURFACE_TYPE_IMAGE) { + cairo_image_surface_t *img_surf = (cairo_image_surface_t *) surf; + + if (_cairo_image_analyze_transparency (img_surf) == CAIRO_IMAGE_HAS_ALPHA) + surface->has_bilevel_alpha = FALSE; + + } else { + if (!_cairo_pattern_is_clear (source) && !_cairo_pattern_is_opaque (source, NULL)) + surface->has_bilevel_alpha = FALSE; + } + + cairo_surface_destroy (free_me); + return; + + } else if (source->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { + cairo_surface_t *image; + cairo_surface_t *raster; + + image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + raster = _cairo_raster_source_pattern_acquire (source, image, NULL); + cairo_surface_destroy (image); + if (raster) { + if (raster->type == CAIRO_SURFACE_TYPE_IMAGE) { + if (_cairo_image_analyze_transparency ((cairo_image_surface_t *)raster) == CAIRO_IMAGE_HAS_ALPHA) + surface->has_bilevel_alpha = FALSE; + } + + _cairo_raster_source_pattern_release (source, raster); + if (raster->type == CAIRO_SURFACE_TYPE_IMAGE) + return; + } + } + + if (!_cairo_pattern_is_clear (source) && !_cairo_pattern_is_opaque (source, NULL)) + surface->has_bilevel_alpha = FALSE; +} + static cairo_status_t _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, const cairo_rectangle_int_t *surface_extents, @@ -1624,7 +1692,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, cairo_rectangle_int_t extents; cairo_bool_t use_indices = FALSE; const cairo_rectangle_int_t *r; - int i, num_elements; + unsigned int i, num_elements; if (unlikely (surface->base.status)) return surface->base.status; @@ -1655,6 +1723,9 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, if (! _cairo_surface_wrapper_get_target_extents (&wrapper, &extents)) goto done; + surface->has_bilevel_alpha = TRUE; + surface->has_only_op_over = TRUE; + num_elements = surface->commands.num_elements; elements = _cairo_array_index (&surface->commands, 0); if (elements == NULL) { @@ -1665,7 +1736,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, if (extents.width < r->width || extents.height < r->height) { num_elements = _cairo_recording_surface_get_visible_commands (surface, &extents); - use_indices = TRUE; + use_indices = num_elements != surface->commands.num_elements; } for (i = 0; i < num_elements; i++) { @@ -1683,6 +1754,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, command->header.op, &command->paint.source.base, command->header.clip); + if (type == CAIRO_RECORDING_CREATE_REGIONS) { + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->paint.source.base); + } break; case CAIRO_COMMAND_MASK: @@ -1691,6 +1767,14 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, &command->mask.source.base, &command->mask.mask.base, command->header.clip); + if (type == CAIRO_RECORDING_CREATE_REGIONS) { + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->mask.source.base); + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->mask.mask.base); + } break; case CAIRO_COMMAND_STROKE: @@ -1704,6 +1788,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, command->stroke.tolerance, command->stroke.antialias, command->header.clip); + if (type == CAIRO_RECORDING_CREATE_REGIONS) { + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->stroke.source.base); + } break; case CAIRO_COMMAND_FILL: @@ -1745,6 +1834,14 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, stroke_command->stroke.tolerance, stroke_command->stroke.antialias, command->header.clip); + if (type == CAIRO_RECORDING_CREATE_REGIONS) { + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->fill.source.base); + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->stroke.source.base); + } i++; } } @@ -1757,6 +1854,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, command->fill.tolerance, command->fill.antialias, command->header.clip); + if (type == CAIRO_RECORDING_CREATE_REGIONS) { + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->fill.source.base); + } } break; @@ -1770,6 +1872,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, command->show_text_glyphs.cluster_flags, command->show_text_glyphs.scaled_font, command->header.clip); + if (type == CAIRO_RECORDING_CREATE_REGIONS) { + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->show_text_glyphs.source.base); + } break; default: @@ -2083,3 +2190,15 @@ cairo_recording_surface_get_extents (cairo_surface_t *surface, *extents = record->extents_pixels; return TRUE; } + +cairo_bool_t +_cairo_recording_surface_has_only_bilevel_alpha (cairo_recording_surface_t *surface) +{ + return surface->has_bilevel_alpha; +} + +cairo_bool_t +_cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface) +{ + return surface->has_only_op_over; +} diff --git a/src/cairo-rectangle.c b/src/cairo-rectangle.c index c8f90e671..c8f90e671 100755..100644 --- a/src/cairo-rectangle.c +++ b/src/cairo-rectangle.c diff --git a/src/cairo-rectangular-scan-converter.c b/src/cairo-rectangular-scan-converter.c index e353b34e8..e353b34e8 100755..100644 --- a/src/cairo-rectangular-scan-converter.c +++ b/src/cairo-rectangular-scan-converter.c diff --git a/src/cairo-reference-count-private.h b/src/cairo-reference-count-private.h index 75fdf3538..75fdf3538 100755..100644 --- a/src/cairo-reference-count-private.h +++ b/src/cairo-reference-count-private.h diff --git a/src/cairo-region-private.h b/src/cairo-region-private.h index 549e50878..549e50878 100755..100644 --- a/src/cairo-region-private.h +++ b/src/cairo-region-private.h diff --git a/src/cairo-region.c b/src/cairo-region.c index a51e2247f..ccfb2200e 100755..100644 --- a/src/cairo-region.c +++ b/src/cairo-region.c @@ -106,6 +106,7 @@ _cairo_region_create_in_error (cairo_status_t status) case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION: case CAIRO_STATUS_DEVICE_FINISHED: + case CAIRO_STATUS_JBIG2_GLOBAL_MISSING: default: _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_region_t *) &_cairo_region_nil; @@ -841,18 +842,6 @@ cairo_region_translate (cairo_region_t *region, slim_hidden_def (cairo_region_translate); /** - * cairo_region_overlap_t: - * @CAIRO_REGION_OVERLAP_IN: The contents are entirely inside the region. (Since 1.10) - * @CAIRO_REGION_OVERLAP_OUT: The contents are entirely outside the region. (Since 1.10) - * @CAIRO_REGION_OVERLAP_PART: The contents are partially inside and - * partially outside the region. (Since 1.10) - * - * Used as the return value for cairo_region_contains_rectangle(). - * - * Since: 1.10 - **/ - -/** * cairo_region_contains_rectangle: * @region: a #cairo_region_t * @rectangle: a #cairo_rectangle_int_t diff --git a/src/cairo-rtree-private.h b/src/cairo-rtree-private.h index 27806cab6..27806cab6 100755..100644 --- a/src/cairo-rtree-private.h +++ b/src/cairo-rtree-private.h diff --git a/src/cairo-rtree.c b/src/cairo-rtree.c index dbc040929..dbc040929 100755..100644 --- a/src/cairo-rtree.c +++ b/src/cairo-rtree.c diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h index da7b34698..da7b34698 100755..100644 --- a/src/cairo-scaled-font-private.h +++ b/src/cairo-scaled-font-private.h diff --git a/src/cairo-scaled-font-subsets-private.h b/src/cairo-scaled-font-subsets-private.h index dd1996258..866e63d7b 100755..100644 --- a/src/cairo-scaled-font-subsets-private.h +++ b/src/cairo-scaled-font-subsets-private.h @@ -715,6 +715,21 @@ _cairo_truetype_get_style (cairo_scaled_font_t *scaled_font, cairo_bool_t *bold, cairo_bool_t *italic); +/** + * _cairo_escape_ps_name: + * @ps_name: returns the PostScript name with all invalid characters escaped + * + * Ensure that PostSript name is a valid PDF/PostSript name object. + * In PDF names are treated as UTF8 and non ASCII bytes, ' ', + * and '#' are encoded as '#' followed by 2 hex digits that + * encode the byte. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful. Possible errors include + * %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_int_status_t +_cairo_escape_ps_name (char **ps_name); + #endif /* CAIRO_HAS_FONT_SUBSET */ #endif /* CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H */ diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c index e78e0c283..212176183 100755..100644 --- a/src/cairo-scaled-font-subsets.c +++ b/src/cairo-scaled-font-subsets.c @@ -1256,4 +1256,44 @@ CLEANUP_HASH: return status; } +cairo_int_status_t +_cairo_escape_ps_name (char **ps_name) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + /* Ensure PS name is a valid PDF/PS name object. In PDF names are + * treated as UTF8 and non ASCII bytes, ' ', and '#' are encoded + * as '#' followed by 2 hex digits that encode the byte. By also + * encoding the characters in the reserved string we ensure the + * name is also PS compatible. */ + if (*ps_name) { + static const char *reserved = "()<>[]{}/%#\\"; + char buf[128]; /* max name length is 127 bytes */ + char *src = *ps_name; + char *dst = buf; + + while (*src && dst < buf + 127) { + unsigned char c = *src; + if (c < 0x21 || c > 0x7e || strchr (reserved, c)) { + if (dst + 4 > buf + 127) + break; + + snprintf (dst, 4, "#%02X", c); + src++; + dst += 3; + } else { + *dst++ = *src++; + } + } + *dst = 0; + free (*ps_name); + *ps_name = strdup (buf); + if (*ps_name == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } + + return status; +} + #endif /* CAIRO_HAS_FONT_SUBSET */ diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index ea4435aff..660ff7ce0 100755..100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -2938,8 +2938,12 @@ _cairo_scaled_font_free_last_glyph (cairo_scaled_font_t *scaled_font, if (--page->num_glyphs == 0) { CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex); + /* Temporarily disconnect callback to avoid recursive locking */ + cairo_scaled_glyph_page_cache.entry_destroy = NULL; _cairo_cache_remove (&cairo_scaled_glyph_page_cache, &page->cache_entry); + _cairo_scaled_glyph_page_destroy (scaled_font, page); + cairo_scaled_glyph_page_cache.entry_destroy = _cairo_scaled_glyph_page_pluck; CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex); } } diff --git a/src/cairo-script-private.h b/src/cairo-script-private.h index 5b506f500..5b506f500 100755..100644 --- a/src/cairo-script-private.h +++ b/src/cairo-script-private.h diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c index 68c1528f6..68c1528f6 100755..100644 --- a/src/cairo-script-surface.c +++ b/src/cairo-script-surface.c diff --git a/src/cairo-script.h b/src/cairo-script.h index b5a8cf32d..b5a8cf32d 100755..100644 --- a/src/cairo-script.h +++ b/src/cairo-script.h diff --git a/src/cairo-shape-mask-compositor.c b/src/cairo-shape-mask-compositor.c index c2425b08c..3117267cc 100755..100644 --- a/src/cairo-shape-mask-compositor.c +++ b/src/cairo-shape-mask-compositor.c @@ -62,10 +62,11 @@ _cairo_shape_mask_compositor_stroke (const cairo_compositor_t *_compositor, return CAIRO_INT_STATUS_UNSUPPORTED; TRACE ((stderr, "%s\n", __FUNCTION__)); - mask = _cairo_surface_create_similar_scratch (extents->surface, - CAIRO_CONTENT_ALPHA, - extents->bounded.width, - extents->bounded.height); + mask = _cairo_surface_create_scratch (extents->surface, + CAIRO_CONTENT_ALPHA, + extents->bounded.width, + extents->bounded.height, + NULL); if (unlikely (mask->status)) return mask->status; @@ -156,10 +157,11 @@ _cairo_shape_mask_compositor_fill (const cairo_compositor_t *_compositor, if (! extents->is_bounded) return CAIRO_INT_STATUS_UNSUPPORTED; - mask = _cairo_surface_create_similar_scratch (extents->surface, - CAIRO_CONTENT_ALPHA, - extents->bounded.width, - extents->bounded.height); + mask = _cairo_surface_create_scratch (extents->surface, + CAIRO_CONTENT_ALPHA, + extents->bounded.width, + extents->bounded.height, + NULL); if (unlikely (mask->status)) return mask->status; @@ -248,10 +250,11 @@ _cairo_shape_mask_compositor_glyphs (const cairo_compositor_t *_compositor, return CAIRO_INT_STATUS_UNSUPPORTED; TRACE ((stderr, "%s\n", __FUNCTION__)); - mask = _cairo_surface_create_similar_scratch (extents->surface, - CAIRO_CONTENT_ALPHA, - extents->bounded.width, - extents->bounded.height); + mask = _cairo_surface_create_scratch (extents->surface, + CAIRO_CONTENT_ALPHA, + extents->bounded.width, + extents->bounded.height, + NULL); if (unlikely (mask->status)) return mask->status; diff --git a/src/cairo-skia-surface.cpp b/src/cairo-skia-surface.cpp index bf6b14a5e..0282c2b51 100755..100644 --- a/src/cairo-skia-surface.cpp +++ b/src/cairo-skia-surface.cpp @@ -51,6 +51,27 @@ #include <SkGradientShader.h> #include <SkDashPathEffect.h> +/** + * SECTION:cairo-skia + * @Title: Skia Surfaces + * @Short_Description: Rendering to Skia surfaces + * @See_Also: #cairo_surface_t + * + * Originally written by Vladimir Vukicevic to investigate using Skia for + * Mozilla, it provides a nice integration with a rather interesting code + * base. By hooking Skia underneath Cairo it allows us to directly compare + * code paths... which is interesting. + **/ + +/** + * CAIRO_HAS_SKIA_SURFACE: + * + * Defined if the Skia surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.10 + **/ + #if (CAIRO_FIXED_BITS == 32) && (CAIRO_FIXED_FRAC_BITS == 16) && defined(SK_SCALAR_IS_FIXED) # define CAIRO_FIXED_TO_SK_SCALAR(x) (x) #elif defined(SK_SCALAR_IS_FIXED) @@ -64,13 +85,20 @@ # define CAIRO_INT_STATUS_SUCCESS ((cairo_int_status_t) CAIRO_STATUS_SUCCESS) #endif -#define CAIRO_MAYBE_UNSUPPORTED CAIRO_INT_STATUS_UNSUPPORTED -//#define CAIRO_MAYBE_UNSUPPORTED _skia_unsupported () +#define DEBUG_SKIA 0 + +#if DEBUG_SKIA +#define UNSUPPORTED(reason) ({ \ + fprintf (stderr, \ + "cairo-skia : hit unsupported operation in %s(), line %d: %s\n", \ + __FUNCTION__, __LINE__, reason); \ + return CAIRO_INT_STATUS_UNSUPPORTED; \ +}) +#else +#define UNSUPPORTED(reason) ({ \ + return CAIRO_INT_STATUS_UNSUPPORTED; \ +})#endif -static cairo_int_status_t _skia_unsupported () { - printf ("unsupported!\n"); - return CAIRO_INT_STATUS_UNSUPPORTED; -} typedef struct cairo_skia_surface { cairo_surface_t base; @@ -542,8 +570,7 @@ _cairo_skia_surface_create_similar (void *asurface, if (! format_to_sk_config (_cairo_format_from_content (content), config, opaque)) { - _skia_unsupported (); - return NULL; + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); } return &_cairo_skia_surface_create_internal (config, opaque, @@ -781,7 +808,7 @@ _cairo_skia_surface_paint (void *asurface, shader = pattern_to_sk_shader (surface, source, &image, &image_extra); if (!bitmap && !shader) - return CAIRO_MAYBE_UNSUPPORTED; + return UNSUPPORTED("pattern to bitmap and shader conversion"); SkPaint paint; paint.setFilterBitmap (pattern_filter_to_sk (source)); @@ -838,7 +865,7 @@ _cairo_skia_surface_stroke (void *asurface, SkShader *shader = pattern_to_sk_shader (surface, source, &image, &image_extra); if (shader == NULL) - return CAIRO_MAYBE_UNSUPPORTED; + return UNSUPPORTED("pattern to shader conversion"); paint.setShader (shader); shader->unref (); @@ -941,7 +968,7 @@ _cairo_skia_surface_fill (void *asurface, SkShader *shader = pattern_to_sk_shader (surface, source, &image, &image_extra); if (shader == NULL) - return CAIRO_MAYBE_UNSUPPORTED; + return UNSUPPORTED("pattern to shader conversion"); paint.setShader (shader); shader->unref (); diff --git a/src/cairo-skia.h b/src/cairo-skia.h index 99b928656..99b928656 100755..100644 --- a/src/cairo-skia.h +++ b/src/cairo-skia.h diff --git a/src/cairo-slope-private.h b/src/cairo-slope-private.h index 6a58c9f45..6a58c9f45 100755..100644 --- a/src/cairo-slope-private.h +++ b/src/cairo-slope-private.h diff --git a/src/cairo-slope.c b/src/cairo-slope.c index cc5f30cb0..cc5f30cb0 100755..100644 --- a/src/cairo-slope.c +++ b/src/cairo-slope.c diff --git a/src/cairo-spans-compositor-private.h b/src/cairo-spans-compositor-private.h index 0babebd26..0babebd26 100755..100644 --- a/src/cairo-spans-compositor-private.h +++ b/src/cairo-spans-compositor-private.h diff --git a/src/cairo-spans-compositor.c b/src/cairo-spans-compositor.c index 8580da383..ef213b491 100755..100644 --- a/src/cairo-spans-compositor.c +++ b/src/cairo-spans-compositor.c @@ -95,11 +95,11 @@ get_clip_surface (const cairo_spans_compositor_t *compositor, assert (clip->path); - surface = _cairo_surface_create_similar_solid (dst, - CAIRO_CONTENT_ALPHA, - extents->width, - extents->height, - CAIRO_COLOR_TRANSPARENT); + surface = _cairo_surface_create_scratch (dst, + CAIRO_CONTENT_ALPHA, + extents->width, + extents->height, + CAIRO_COLOR_TRANSPARENT); _cairo_box_from_rectangle (&box, extents); _cairo_polygon_init (&polygon, &box, 1); @@ -588,20 +588,34 @@ composite_aligned_boxes (const cairo_spans_compositor_t *compositor, { cairo_clip_t *recording_clip; const cairo_pattern_t *source = &extents->source_pattern.base; + const cairo_matrix_t *m; + cairo_matrix_t matrix; /* XXX could also do tiling repeat modes... */ /* first clear the area about to be overwritten */ - if (! dst->is_clear) + if (! dst->is_clear) { status = compositor->fill_boxes (dst, CAIRO_OPERATOR_CLEAR, CAIRO_COLOR_TRANSPARENT, boxes); + if (unlikely (status)) + return status; + + dst->is_clear = TRUE; + } + + m = &source->matrix; + if (_cairo_surface_has_device_transform (dst)) { + cairo_matrix_multiply (&matrix, + &source->matrix, + &dst->device_transform); + m = &matrix; + } recording_clip = _cairo_clip_from_boxes (boxes); status = _cairo_recording_surface_replay_with_clip (unwrap_source (source), - &source->matrix, - dst, recording_clip); + m, dst, recording_clip); _cairo_clip_destroy (recording_clip); return status; diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h index c42b5afa7..b158f4d36 100755..100644 --- a/src/cairo-spans-private.h +++ b/src/cairo-spans-private.h @@ -53,7 +53,7 @@ struct _cairo_span_renderer { /* Render the spans on row y of the destination by whatever compositing * method is required. */ - cairo_warn cairo_status_t + cairo_status_t (*render_rows) (void *abstract_renderer, int y, int height, const cairo_half_open_span_t *coverages, diff --git a/src/cairo-spans.c b/src/cairo-spans.c index b8d41800e..182390c20 100755..100644 --- a/src/cairo-spans.c +++ b/src/cairo-spans.c @@ -127,6 +127,7 @@ _cairo_scan_converter_create_in_error (cairo_status_t status) case CAIRO_STATUS_DEVICE_ERROR: RETURN_NIL; case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION: RETURN_NIL; case CAIRO_STATUS_DEVICE_FINISHED: RETURN_NIL; + case CAIRO_STATUS_JBIG2_GLOBAL_MISSING: default: break; } @@ -239,6 +240,7 @@ _cairo_span_renderer_create_in_error (cairo_status_t status) case CAIRO_STATUS_DEVICE_ERROR: RETURN_NIL; case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION: RETURN_NIL; case CAIRO_STATUS_DEVICE_FINISHED: RETURN_NIL; + case CAIRO_STATUS_JBIG2_GLOBAL_MISSING: RETURN_NIL; default: break; } diff --git a/src/cairo-spline.c b/src/cairo-spline.c index 9ebb949c7..6341d71b3 100755..100644 --- a/src/cairo-spline.c +++ b/src/cairo-spline.c @@ -38,6 +38,7 @@ #include "cairo-box-inline.h" #include "cairo-slope-private.h" +#include "cairo-convex-fill-private.h" cairo_bool_t _cairo_spline_intersects (const cairo_point_t *a, diff --git a/src/cairo-stroke-dash-private.h b/src/cairo-stroke-dash-private.h index 75c000cd7..75c000cd7 100755..100644 --- a/src/cairo-stroke-dash-private.h +++ b/src/cairo-stroke-dash-private.h diff --git a/src/cairo-stroke-dash.c b/src/cairo-stroke-dash.c index 9494010f5..9494010f5 100755..100644 --- a/src/cairo-stroke-dash.c +++ b/src/cairo-stroke-dash.c diff --git a/src/cairo-stroke-style.c b/src/cairo-stroke-style.c index 51c9414c0..51c9414c0 100755..100644 --- a/src/cairo-stroke-style.c +++ b/src/cairo-stroke-style.c diff --git a/src/cairo-surface-backend-private.h b/src/cairo-surface-backend-private.h index be624dfbe..be624dfbe 100755..100644 --- a/src/cairo-surface-backend-private.h +++ b/src/cairo-surface-backend-private.h diff --git a/src/cairo-surface-clipper-private.h b/src/cairo-surface-clipper-private.h index e5b00af7c..e5b00af7c 100755..100644 --- a/src/cairo-surface-clipper-private.h +++ b/src/cairo-surface-clipper-private.h diff --git a/src/cairo-surface-clipper.c b/src/cairo-surface-clipper.c index 5309362c6..5309362c6 100755..100644 --- a/src/cairo-surface-clipper.c +++ b/src/cairo-surface-clipper.c diff --git a/src/cairo-surface-fallback-private.h b/src/cairo-surface-fallback-private.h index ecf7b0edf..ecf7b0edf 100755..100644 --- a/src/cairo-surface-fallback-private.h +++ b/src/cairo-surface-fallback-private.h diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c index a0af15969..a0af15969 100755..100644 --- a/src/cairo-surface-fallback.c +++ b/src/cairo-surface-fallback.c diff --git a/src/cairo-surface-inline.h b/src/cairo-surface-inline.h index 85fbc9192..85fbc9192 100755..100644 --- a/src/cairo-surface-inline.h +++ b/src/cairo-surface-inline.h diff --git a/src/cairo-surface-observer-inline.h b/src/cairo-surface-observer-inline.h index 07b94770d..07b94770d 100755..100644 --- a/src/cairo-surface-observer-inline.h +++ b/src/cairo-surface-observer-inline.h diff --git a/src/cairo-surface-observer-private.h b/src/cairo-surface-observer-private.h index 6ed0c18d1..6ed0c18d1 100755..100644 --- a/src/cairo-surface-observer-private.h +++ b/src/cairo-surface-observer-private.h diff --git a/src/cairo-surface-observer.c b/src/cairo-surface-observer.c index 8bbd6109c..ee65b72d1 100755..100644 --- a/src/cairo-surface-observer.c +++ b/src/cairo-surface-observer.c @@ -653,7 +653,7 @@ add_record (cairo_observation_t *log, } static void -sync (cairo_surface_t *target, int x, int y) +_cairo_surface_sync (cairo_surface_t *target, int x, int y) { cairo_rectangle_int_t extents; @@ -751,7 +751,7 @@ _cairo_surface_observer_paint (void *abstract_surface, if (unlikely (status)) return status; - sync (surface->target, x, y); + _cairo_surface_sync (surface->target, x, y); t = _cairo_time_get_delta (t); add_record_paint (&surface->log, surface->target, op, source, clip, t); @@ -837,7 +837,7 @@ _cairo_surface_observer_mask (void *abstract_surface, if (unlikely (status)) return status; - sync (surface->target, x, y); + _cairo_surface_sync (surface->target, x, y); t = _cairo_time_get_delta (t); add_record_mask (&surface->log, @@ -944,7 +944,7 @@ _cairo_surface_observer_fill (void *abstract_surface, if (unlikely (status)) return status; - sync (surface->target, x, y); + _cairo_surface_sync (surface->target, x, y); t = _cairo_time_get_delta (t); add_record_fill (&surface->log, @@ -1063,7 +1063,7 @@ _cairo_surface_observer_stroke (void *abstract_surface, if (unlikely (status)) return status; - sync (surface->target, x, y); + _cairo_surface_sync (surface->target, x, y); t = _cairo_time_get_delta (t); add_record_stroke (&surface->log, @@ -1183,7 +1183,7 @@ _cairo_surface_observer_glyphs (void *abstract_surface, if (unlikely (status)) return status; - sync (surface->target, x, y); + _cairo_surface_sync (surface->target, x, y); t = _cairo_time_get_delta (t); add_record_glyphs (&surface->log, @@ -1368,11 +1368,16 @@ static const cairo_surface_backend_t _cairo_surface_observer_backend = { /** * cairo_surface_create_observer: * @target: an existing surface for which the observer will watch + * @mode: sets the mode of operation (normal vs. record) * * Create a new surface that exists solely to watch another is doing. In * the process it will log operations and times, which are fast, which are * slow, which are frequent, etc. * + * The @mode parameter can be set to either CAIRO_SURFACE_OBSERVER_NORMAL + * or CAIRO_SURFACE_OBSERVER_RECORD_OPERATIONS, to control whether or not + * the internal observer should record operations. + * * Return value: a pointer to the newly allocated surface. The caller * owns the surface and should call cairo_surface_destroy() when done * with it. diff --git a/src/cairo-surface-offset-private.h b/src/cairo-surface-offset-private.h index 310ba5691..310ba5691 100755..100644 --- a/src/cairo-surface-offset-private.h +++ b/src/cairo-surface-offset-private.h diff --git a/src/cairo-surface-offset.c b/src/cairo-surface-offset.c index 98f57f298..98f57f298 100755..100644 --- a/src/cairo-surface-offset.c +++ b/src/cairo-surface-offset.c diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h index f20ab0739..f20ab0739 100755..100644 --- a/src/cairo-surface-private.h +++ b/src/cairo-surface-private.h diff --git a/src/cairo-surface-scale-translate-private.h b/src/cairo-surface-scale-translate-private.h index b13d3366d..b13d3366d 100755..100644 --- a/src/cairo-surface-scale-translate-private.h +++ b/src/cairo-surface-scale-translate-private.h diff --git a/src/cairo-surface-scale-translate.c b/src/cairo-surface-scale-translate.c index 1729b81ad..1729b81ad 100755..100644 --- a/src/cairo-surface-scale-translate.c +++ b/src/cairo-surface-scale-translate.c diff --git a/src/cairo-surface-shadow-private.h b/src/cairo-surface-shadow-private.h index 43c7e6d2a..43c7e6d2a 100755..100644 --- a/src/cairo-surface-shadow-private.h +++ b/src/cairo-surface-shadow-private.h diff --git a/src/cairo-surface-shadow.c b/src/cairo-surface-shadow.c index 5224bee40..921258ec3 100755..100644 --- a/src/cairo-surface-shadow.c +++ b/src/cairo-surface-shadow.c @@ -319,7 +319,8 @@ _cairo_ensure_shadow_surface (cairo_surface_t *target, content, width_out, height_out); - _cairo_surface_release_device_reference (shadow_surface); + if (shadow_surface->device) + _cairo_surface_release_device_reference (shadow_surface); } shadow_surface_extents->x = 0; @@ -407,13 +408,13 @@ _cairo_surface_shadow_paint (cairo_surface_t *target, &shadow_source.base, &shadow_extents, &bounded); - if (unlikely (status)) + if (unlikely (status)) goto FINISH; if (shadow_extents.width == 0 || shadow_extents.height == 0) goto FINISH; - x_offset = shadow_extents.x - x_blur; + x_offset = shadow_extents.x - x_blur; y_offset = shadow_extents.y - y_blur; cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale); @@ -678,13 +679,13 @@ _cairo_surface_shadow_mask (cairo_surface_t *target, &shadow_mask.base, &shadow_extents, &bounded); - if (unlikely (status)) + if (unlikely (status)) goto FINISH; if (shadow_extents.width == 0 || shadow_extents.height == 0) goto FINISH; - x_offset = shadow_extents.x - x_blur; + x_offset = shadow_extents.x - x_blur; y_offset = shadow_extents.y - y_blur; cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale); @@ -918,13 +919,13 @@ _cairo_surface_inset_shadow_stroke (cairo_surface_t *target, &shadow_ctm, &shadow_ctm_inverse, &shadow_extents); - if (unlikely (status)) + if (unlikely (status)) goto FINISH; if (shadow_extents.width == 0 || shadow_extents.height == 0) goto FINISH; - x_offset = shadow_extents.x - x_blur; + x_offset = shadow_extents.x - x_blur; y_offset = shadow_extents.y - y_blur; cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale); @@ -1205,13 +1206,13 @@ _cairo_surface_shadow_stroke (cairo_surface_t *target, &shadow_ctm, &shadow_ctm_inverse, &shadow_extents); - if (unlikely (status)) + if (unlikely (status)) goto FINISH; if (shadow_extents.width == 0 || shadow_extents.height == 0) goto FINISH; - x_offset = shadow_extents.x - x_blur; + x_offset = shadow_extents.x - x_blur; y_offset = shadow_extents.y - y_blur; cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale); @@ -1437,7 +1438,7 @@ _cairo_surface_inset_shadow_fill (cairo_surface_t *target, if (shadow_cache != NULL) { /* paint the shadow surface to target */ - color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red, + color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red, shadow_copy.color.green, shadow_copy.color.blue, 1.0); @@ -1455,13 +1456,13 @@ _cairo_surface_inset_shadow_fill (cairo_surface_t *target, &shadow_source.base, &shadow_path, &shadow_extents); - if (unlikely (status)) + if (unlikely (status)) goto FINISH; if (shadow_extents.width == 0 || shadow_extents.height == 0) goto FINISH; - x_offset = shadow_extents.x - x_blur; + x_offset = shadow_extents.x - x_blur; y_offset = shadow_extents.y - y_blur; cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale); @@ -1533,7 +1534,7 @@ _cairo_surface_inset_shadow_fill (cairo_surface_t *target, cache_surface = cairo_surface_create_similar (target, content, shadow_surface_extents.width, shadow_surface_extents.height); - if (unlikely (cache_surface->status)) + if (unlikely (cache_surface->status)) goto FINISH; if (device) @@ -1587,7 +1588,7 @@ _cairo_surface_inset_shadow_fill (cairo_surface_t *target, if (unlikely (status)) goto FINISH; - cairo_pattern_destroy (shadow_pattern); + cairo_pattern_destroy (shadow_pattern); size = shadow_surface_extents.width * shadow_surface_extents.height; _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list, @@ -1755,7 +1756,7 @@ _cairo_surface_shadow_fill (cairo_surface_t *target, if (shadow_cache != NULL) { /* paint the shadow surface to target */ - color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red, + color_pattern = cairo_pattern_create_rgba (shadow_copy.color.red, shadow_copy.color.green, shadow_copy.color.blue, 1.0); @@ -1773,13 +1774,13 @@ _cairo_surface_shadow_fill (cairo_surface_t *target, &shadow_source.base, &shadow_path, &shadow_extents); - if (unlikely (status)) + if (unlikely (status)) goto FINISH; if (shadow_extents.width == 0 || shadow_extents.height == 0) goto FINISH; - x_offset = shadow_extents.x - x_blur; + x_offset = shadow_extents.x - x_blur; y_offset = shadow_extents.y - y_blur; cairo_matrix_init_scale (&m, shadow_cache->scale, shadow_cache->scale); @@ -1843,7 +1844,7 @@ _cairo_surface_shadow_fill (cairo_surface_t *target, cache_surface = cairo_surface_create_similar (target, content, shadow_surface_extents.width, shadow_surface_extents.height); - if (unlikely (cache_surface->status)) + if (unlikely (cache_surface->status)) goto FINISH; if (device) @@ -1889,7 +1890,7 @@ _cairo_surface_shadow_fill (cairo_surface_t *target, if (unlikely (status)) goto FINISH; - cairo_pattern_destroy (shadow_pattern); + cairo_pattern_destroy (shadow_pattern); size = shadow_surface_extents.width * shadow_surface_extents.height; _cairo_shadow_cache_list_shrink_to_accomodate (&shadow_cache_list, @@ -2026,7 +2027,8 @@ _cairo_surface_inset_shadow_glyphs (cairo_surface_t *target, content, shadow_width, shadow_height); - _cairo_surface_release_device_reference (shadow_surface); + if (shadow_surface->device) + _cairo_surface_release_device_reference (shadow_surface); } if (! shadow_surface || unlikely (shadow_surface->status)) goto FINISH; @@ -2045,7 +2047,8 @@ _cairo_surface_inset_shadow_glyphs (cairo_surface_t *target, CAIRO_CONTENT_COLOR_ALPHA, shadow_surface_extents.width, shadow_surface_extents.height); - _cairo_surface_release_device_reference (mask_surface); + if (mask_surface->device) + _cairo_surface_release_device_reference (mask_surface); } if (! mask_surface || unlikely (mask_surface->status)) goto FINISH; @@ -2230,7 +2233,8 @@ _cairo_surface_shadow_glyphs (cairo_surface_t *target, content, shadow_width, shadow_height); - _cairo_surface_release_device_reference (shadow_surface); + if (shadow_surface->device) + _cairo_surface_release_device_reference (shadow_surface); } if (! shadow_surface || unlikely (shadow_surface->status)) goto FINISH; diff --git a/src/cairo-surface-snapshot-inline.h b/src/cairo-surface-snapshot-inline.h index bf89c772b..bf89c772b 100755..100644 --- a/src/cairo-surface-snapshot-inline.h +++ b/src/cairo-surface-snapshot-inline.h diff --git a/src/cairo-surface-snapshot-private.h b/src/cairo-surface-snapshot-private.h index 58bee7b49..58bee7b49 100755..100644 --- a/src/cairo-surface-snapshot-private.h +++ b/src/cairo-surface-snapshot-private.h diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c index 68bf9054e..68bf9054e 100755..100644 --- a/src/cairo-surface-snapshot.c +++ b/src/cairo-surface-snapshot.c diff --git a/src/cairo-surface-subsurface-inline.h b/src/cairo-surface-subsurface-inline.h index 0cd09e63e..0cd09e63e 100755..100644 --- a/src/cairo-surface-subsurface-inline.h +++ b/src/cairo-surface-subsurface-inline.h diff --git a/src/cairo-surface-subsurface-private.h b/src/cairo-surface-subsurface-private.h index 89c5cc01b..89c5cc01b 100755..100644 --- a/src/cairo-surface-subsurface-private.h +++ b/src/cairo-surface-subsurface-private.h diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c index 0b4915e7e..5c55ac12f 100755..100644 --- a/src/cairo-surface-subsurface.c +++ b/src/cairo-surface-subsurface.c @@ -354,10 +354,11 @@ _cairo_surface_subsurface_snapshot (void *abstract_surface) TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, surface->target->unique_id)); - clone = _cairo_surface_create_similar_scratch (surface->target, - surface->target->content, - surface->extents.width, - surface->extents.height); + clone = _cairo_surface_create_scratch (surface->target, + surface->target->content, + surface->extents.width, + surface->extents.height, + NULL); if (unlikely (clone->status)) return clone; @@ -468,7 +469,12 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target, if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - assert (_cairo_matrix_is_translation (&target->device_transform)); + x *= target->device_transform.xx; + y *= target->device_transform.yy; + + width *= target->device_transform.xx; + height *= target->device_transform.yy; + x += target->device_transform.x0; y += target->device_transform.y0; @@ -498,6 +504,10 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target, surface->snapshot = NULL; + cairo_surface_set_device_scale (&surface->base, + target->device_transform.xx, + target->device_transform.yy); + return &surface->base; } @@ -518,14 +528,16 @@ _cairo_surface_create_for_rectangle_int (cairo_surface_t *target, if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - assert (_cairo_matrix_is_translation (&target->device_transform)); - _cairo_surface_init (&surface->base, &_cairo_surface_subsurface_backend, NULL, /* device */ target->content); surface->extents = *extents; + surface->extents.x *= target->device_transform.xx; + surface->extents.y *= target->device_transform.yy; + surface->extents.width *= target->device_transform.xx; + surface->extents.height *= target->device_transform.yy; surface->extents.x += target->device_transform.x0; surface->extents.y += target->device_transform.y0; @@ -534,6 +546,10 @@ _cairo_surface_create_for_rectangle_int (cairo_surface_t *target, surface->snapshot = NULL; + cairo_surface_set_device_scale (&surface->base, + target->device_transform.xx, + target->device_transform.yy); + return &surface->base; } /* XXX observe mark-dirty */ diff --git a/src/cairo-surface-wrapper-private.h b/src/cairo-surface-wrapper-private.h index 6529ebc11..6529ebc11 100755..100644 --- a/src/cairo-surface-wrapper-private.h +++ b/src/cairo-surface-wrapper-private.h diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c index 578e8e2be..9236c8bf4 100755..100644 --- a/src/cairo-surface-wrapper.c +++ b/src/cairo-surface-wrapper.c @@ -437,12 +437,11 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, _cairo_surface_wrapper_get_transform (wrapper, &m); - if (! _cairo_matrix_is_translation (&wrapper->transform)) { + if (! _cairo_matrix_is_translation (&m)) { cairo_matrix_t ctm; - /* XXX No device-transform? A bug in the tangle of layers? */ _cairo_matrix_multiply (&ctm, - &wrapper->transform, + &m, &scaled_font->ctm); dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face, &scaled_font->font_matrix, @@ -514,8 +513,8 @@ _cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper, int width, int height) { - return _cairo_surface_create_similar_scratch (wrapper->target, - content, width, height); + return _cairo_surface_create_scratch (wrapper->target, + content, width, height, NULL); } cairo_bool_t diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 5c6969c8a..24ad24901 100755..100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -454,33 +454,6 @@ _cairo_surface_copy_similar_properties (cairo_surface_t *surface, other->y_fallback_resolution); } -cairo_surface_t * -_cairo_surface_create_similar_scratch (cairo_surface_t *other, - cairo_content_t content, - int width, - int height) -{ - cairo_surface_t *surface; - - if (unlikely (other->status)) - return _cairo_surface_create_in_error (other->status); - - surface = NULL; - if (other->backend->create_similar) - surface = other->backend->create_similar (other, content, width, height); - if (surface == NULL) - surface = cairo_surface_create_similar_image (other, - _cairo_format_from_content (content), - width, height); - - if (unlikely (surface->status)) - return surface; - - _cairo_surface_copy_similar_properties (surface, other); - - return surface; -} - /** * cairo_surface_create_similar: * @other: an existing surface used to select the backend of the new surface @@ -518,6 +491,8 @@ cairo_surface_create_similar (cairo_surface_t *other, int height) { cairo_surface_t *surface; + cairo_status_t status; + cairo_solid_pattern_t pattern; if (unlikely (other->status)) return _cairo_surface_create_in_error (other->status); @@ -529,9 +504,41 @@ cairo_surface_create_similar (cairo_surface_t *other, if (unlikely (! CAIRO_CONTENT_VALID (content))) return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT); - surface = _cairo_surface_create_similar_solid (other, - content, width, height, - CAIRO_COLOR_TRANSPARENT); + if (unlikely (other->status)) + return _cairo_surface_create_in_error (other->status); + + /* We inherit the device scale, so create a larger surface */ + width = width * other->device_transform.xx; + height = height * other->device_transform.yy; + + surface = NULL; + if (other->backend->create_similar) + surface = other->backend->create_similar (other, content, width, height); + if (surface == NULL) + surface = cairo_surface_create_similar_image (other, + _cairo_format_from_content (content), + width, height); + + if (unlikely (surface->status)) + return surface; + + _cairo_surface_copy_similar_properties (surface, other); + cairo_surface_set_device_scale (surface, + other->device_transform.xx, + other->device_transform.yy); + + if (unlikely (surface->status)) + return surface; + + _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_TRANSPARENT); + status = _cairo_surface_paint (surface, + CAIRO_OPERATOR_CLEAR, + &pattern.base, NULL); + if (unlikely (status)) { + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + } + assert (surface->is_clear); return surface; @@ -852,34 +859,78 @@ error: } cairo_surface_t * -_cairo_surface_create_similar_solid (cairo_surface_t *other, - cairo_content_t content, - int width, - int height, - const cairo_color_t *color) +_cairo_surface_create_scratch (cairo_surface_t *other, + cairo_content_t content, + int width, + int height, + const cairo_color_t *color) { - cairo_status_t status; cairo_surface_t *surface; + cairo_status_t status; cairo_solid_pattern_t pattern; - surface = _cairo_surface_create_similar_scratch (other, content, - width, height); + if (unlikely (other->status)) + return _cairo_surface_create_in_error (other->status); + + surface = NULL; + if (other->backend->create_similar) + surface = other->backend->create_similar (other, content, width, height); + if (surface == NULL) + surface = cairo_surface_create_similar_image (other, + _cairo_format_from_content (content), + width, height); + if (unlikely (surface->status)) return surface; - _cairo_pattern_init_solid (&pattern, color); - status = _cairo_surface_paint (surface, - color == CAIRO_COLOR_TRANSPARENT ? - CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE, - &pattern.base, NULL); - if (unlikely (status)) { - cairo_surface_destroy (surface); - surface = _cairo_surface_create_in_error (status); + _cairo_surface_copy_similar_properties (surface, other); + + if (unlikely (surface->status)) + return surface; + + if (color) { + _cairo_pattern_init_solid (&pattern, color); + status = _cairo_surface_paint (surface, + color == CAIRO_COLOR_TRANSPARENT ? + CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE, + &pattern.base, NULL); + if (unlikely (status)) { + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + } } return surface; } +cairo_surface_t * +_cairo_surface_create_similar_scratch (cairo_surface_t *other, + cairo_content_t content, + int width, + int height) +{ + cairo_surface_t *surface; + + if (unlikely (other->status)) + return _cairo_surface_create_in_error (other->status); + + surface = NULL; + if (other->backend->create_similar) + surface = other->backend->create_similar (other, content, width, height); + if (surface == NULL) + surface = cairo_surface_create_similar_image (other, + _cairo_format_from_content (content), + width, height); + + if (unlikely (surface->status)) + return surface; + + _cairo_surface_copy_similar_properties (surface, other); + + return surface; +} + + /** * cairo_surface_reference: * @surface: a #cairo_surface_t @@ -1200,6 +1251,31 @@ _cairo_mime_data_destroy (void *ptr) } /** + * CAIRO_MIME_TYPE_JBIG2: + * + * Joint Bi-level Image Experts Group image coding standard (ISO/IEC 11544). + * + * Since: 1.14 + **/ + +/** + * CAIRO_MIME_TYPE_JBIG2_GLOBAL: + * + * Joint Bi-level Image Experts Group image coding standard (ISO/IEC 11544) global segment. + * + * Since: 1.14 + **/ + +/** + * CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID: + * + * An unique identifier shared by a JBIG2 global segment and all JBIG2 images + * that depend on the global segment. + * + * Since: 1.14 + **/ + +/** * CAIRO_MIME_TYPE_JP2: * * The Joint Photographic Experts Group (JPEG) 2000 image coding standard (ISO/IEC 15444-1). @@ -1234,7 +1310,8 @@ _cairo_mime_data_destroy (void *ptr) /** * CAIRO_MIME_TYPE_UNIQUE_ID: * - * Unique identifier for a surface (cairo specific MIME type). + * Unique identifier for a surface (cairo specific MIME type). All surfaces with + * the same unique identifier will only be embedded once. * * Since: 1.12 **/ @@ -1262,13 +1339,24 @@ _cairo_mime_data_destroy (void *ptr) * * The recognized MIME types are the following: %CAIRO_MIME_TYPE_JPEG, * %CAIRO_MIME_TYPE_PNG, %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_URI, - * %CAIRO_MIME_TYPE_UNIQUE_ID. + * %CAIRO_MIME_TYPE_UNIQUE_ID, %CAIRO_MIME_TYPE_JBIG2, + * %CAIRO_MIME_TYPE_JBIG2_GLOBAL, %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID. * * See corresponding backend surface docs for details about which MIME * types it can handle. Caution: the associated MIME data will be * discarded if you draw on the surface afterwards. Use this function * with care. * + * Even if a backend supports a MIME type, that does not mean cairo + * will always be able to use the attached MIME data. For example, if + * the backend does not natively support the compositing operation used + * to apply the MIME data to the backend. In that case, the MIME data + * will be ignored. Therefore, to apply an image in all cases, it is best + * to create an image surface which contains the decoded image data and + * then attach the MIME data to that. This ensures the image will always + * be used while still allowing the MIME data to be used whenever + * possible. + * * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a * slot could not be allocated for the user data. * @@ -1346,6 +1434,13 @@ cairo_surface_supports_mime_type (cairo_surface_t *surface, { const char **types; + if (unlikely (surface->status)) + return FALSE; + if (unlikely (surface->finished)) { + _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } + if (surface->backend->get_supported_mime_types) { types = surface->backend->get_supported_mime_types (surface); if (types) { @@ -1617,26 +1712,28 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, slim_hidden_def (cairo_surface_mark_dirty_rectangle); /** - * _cairo_surface_set_device_scale: + * cairo_surface_set_device_scale: * @surface: a #cairo_surface_t - * @sx: a scale factor in the X direction - * @sy: a scale factor in the Y direction - * - * Private function for setting an extra scale factor to affect all - * drawing to a surface. This is used, for example, when replaying a - * recording surface to an image fallback intended for an eventual - * vector-oriented backend. Since the recording surface will record - * coordinates in one backend space, but the image fallback uses a - * different backend space, (differing by the fallback resolution - * scale factors), we need a scale factor correction. - * - * Caution: Not all places we use device transform correctly handle - * both a translate and a scale. An audit would be nice. + * @x_scale: a scale factor in the X direction + * @y_scale: a scale factor in the Y direction + * + * Sets a scale that is multiplied to the device coordinates determined + * by the CTM when drawing to @surface. One common use for this is to + * render to very high resolution display devices at a scale factor, so + * that code that assumes 1 pixel will be a certain size will still work. + * Setting a transformation via cairo_translate() isn't + * sufficient to do this, since functions like + * cairo_device_to_user() will expose the hidden scale. + * + * Note that the scale affects drawing to the surface as well as + * using the surface in a source pattern. + * + * Since: 1.14 **/ void -_cairo_surface_set_device_scale (cairo_surface_t *surface, - double sx, - double sy) +cairo_surface_set_device_scale (cairo_surface_t *surface, + double x_scale, + double y_scale) { cairo_status_t status; @@ -1656,8 +1753,8 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface, return; } - surface->device_transform.xx = sx; - surface->device_transform.yy = sy; + surface->device_transform.xx = x_scale; + surface->device_transform.yy = y_scale; surface->device_transform.xy = 0.0; surface->device_transform.yx = 0.0; @@ -1668,6 +1765,30 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface, _cairo_observers_notify (&surface->device_transform_observers, surface); } +slim_hidden_def (cairo_surface_set_device_scale); + +/** + * cairo_surface_get_device_scale: + * @surface: a #cairo_surface_t + * @x_scale: the scale in the X direction, in device units + * @y_scale: the scale in the Y direction, in device units + * + * This function returns the previous device offset set by + * cairo_surface_set_device_scale(). + * + * Since: 1.14 + **/ +void +cairo_surface_get_device_scale (cairo_surface_t *surface, + double *x_scale, + double *y_scale) +{ + if (x_scale) + *x_scale = surface->device_transform.xx; + if (y_scale) + *y_scale = surface->device_transform.yy; +} +slim_hidden_def (cairo_surface_get_device_scale); /** * cairo_surface_set_device_offset: @@ -2004,6 +2125,8 @@ _cairo_surface_paint (cairo_surface_t *surface, TRACE ((stderr, "%s\n", __FUNCTION__)); if (unlikely (surface->status)) return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; @@ -2040,6 +2163,8 @@ _cairo_surface_mask (cairo_surface_t *surface, TRACE ((stderr, "%s\n", __FUNCTION__)); if (unlikely (surface->status)) return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; @@ -2097,6 +2222,8 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, TRACE ((stderr, "%s\n", __FUNCTION__)); if (unlikely (surface->status)) return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; @@ -2177,6 +2304,8 @@ _cairo_surface_stroke (cairo_surface_t *surface, TRACE ((stderr, "%s\n", __FUNCTION__)); if (unlikely (surface->status)) return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; @@ -2220,6 +2349,8 @@ _cairo_surface_fill (cairo_surface_t *surface, TRACE ((stderr, "%s\n", __FUNCTION__)); if (unlikely (surface->status)) return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; @@ -2351,6 +2482,13 @@ _cairo_surface_get_extents (cairo_surface_t *surface, { cairo_bool_t bounded; + if (unlikely (surface->status)) + goto zero_extents; + if (unlikely (surface->finished)) { + _cairo_surface_set_error(surface, CAIRO_STATUS_SURFACE_FINISHED); + goto zero_extents; + } + bounded = FALSE; if (surface->backend->get_extents != NULL) bounded = surface->backend->get_extents (surface, extents); @@ -2359,6 +2497,11 @@ _cairo_surface_get_extents (cairo_surface_t *surface, _cairo_unbounded_rectangle_init (extents); return bounded; + +zero_extents: + extents->x = extents->y = 0; + extents->width = extents->height = 0; + return TRUE; } /** @@ -2430,11 +2573,12 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, const cairo_clip_t *clip) { cairo_int_status_t status; - cairo_scaled_font_t *dev_scaled_font = scaled_font; TRACE ((stderr, "%s\n", __FUNCTION__)); if (unlikely (surface->status)) return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); if (num_glyphs == 0 && utf8_len == 0) return CAIRO_STATUS_SUCCESS; @@ -2453,25 +2597,6 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, if (unlikely (status)) return status; - if (_cairo_surface_has_device_transform (surface) && - ! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL)) - { - cairo_font_options_t font_options; - cairo_matrix_t dev_ctm, font_matrix; - - cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix); - cairo_scaled_font_get_ctm (scaled_font, &dev_ctm); - cairo_matrix_multiply (&dev_ctm, &dev_ctm, &surface->device_transform); - cairo_scaled_font_get_font_options (scaled_font, &font_options); - dev_scaled_font = cairo_scaled_font_create (cairo_scaled_font_get_font_face (scaled_font), - &font_matrix, - &dev_ctm, - &font_options); - } - status = cairo_scaled_font_status (dev_scaled_font); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - status = CAIRO_INT_STATUS_UNSUPPORTED; /* The logic here is duplicated in _cairo_analysis_surface show_glyphs and @@ -2485,7 +2610,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags, - dev_scaled_font, + scaled_font, clip); } if (status == CAIRO_INT_STATUS_UNSUPPORTED && @@ -2494,7 +2619,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, status = surface->backend->show_glyphs (surface, op, source, glyphs, num_glyphs, - dev_scaled_font, + scaled_font, clip); } } else { @@ -2503,7 +2628,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, status = surface->backend->show_glyphs (surface, op, source, glyphs, num_glyphs, - dev_scaled_font, + scaled_font, clip); } else if (surface->backend->show_text_glyphs != NULL) { /* Intentionally only try show_text_glyphs method for show_glyphs @@ -2519,14 +2644,11 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags, - dev_scaled_font, + scaled_font, clip); } } - if (dev_scaled_font != scaled_font) - cairo_scaled_font_destroy (dev_scaled_font); - if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { surface->is_clear = FALSE; surface->serial++; @@ -2557,6 +2679,16 @@ _cairo_surface_set_resolution (cairo_surface_t *surface, surface->y_resolution = y_res; } +/** + * _cairo_surface_create_in_error: + * @status: the error status + * + * Return an appropriate static error surface for the error status. + * On error, surface creation functions should always return a surface + * created with _cairo_surface_create_in_error() instead of a new surface + * in an error state. This simplifies internal code as no refcounting has + * to be done. + **/ cairo_surface_t * _cairo_surface_create_in_error (cairo_status_t status) { @@ -2617,6 +2749,7 @@ _cairo_surface_create_in_error (cairo_status_t status) case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION: case CAIRO_STATUS_DEVICE_FINISHED: + case CAIRO_STATUS_JBIG2_GLOBAL_MISSING: default: _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_surface_t *) &_cairo_surface_nil; diff --git a/src/cairo-svg-surface-private.h b/src/cairo-svg-surface-private.h index ddbf464b1..ddbf464b1 100755..100644 --- a/src/cairo-svg-surface-private.h +++ b/src/cairo-svg-surface-private.h diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index e2d99499d..04bb7a093 100755..100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -56,6 +56,7 @@ #include "cairo-paginated-private.h" #include "cairo-scaled-font-subsets-private.h" #include "cairo-surface-clipper-private.h" +#include "cairo-surface-snapshot-inline.h" #include "cairo-svg-surface-private.h" /** @@ -810,7 +811,7 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document, _cairo_output_stream_printf (document->xml_node_glyphs, "<g"); _cairo_svg_surface_emit_transform (document->xml_node_glyphs, " transform", &image->base.device_transform_inverse, NULL); - _cairo_output_stream_printf (document->xml_node_glyphs, ">/n"); + _cairo_output_stream_printf (document->xml_node_glyphs, ">\n"); for (y = 0, row = image->data, rows = image->height; rows; row += image->stride, rows--, y++) { for (x = 0, byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) { @@ -1120,6 +1121,9 @@ _cairo_surface_base64_encode_jpeg (cairo_surface_t *surface, if (unlikely (status)) return status; + if (image_info.num_components == 4) + return CAIRO_INT_STATUS_UNSUPPORTED; + _cairo_output_stream_printf (output, "data:image/jpeg;base64,"); info.output = output; @@ -1493,6 +1497,17 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document, document, NULL); } +static cairo_recording_surface_t * +to_recording_surface (const cairo_surface_pattern_t *pattern) +{ + cairo_surface_t *surface = pattern->surface; + if (_cairo_surface_is_paginated (surface)) + surface = _cairo_paginated_surface_get_recording (surface); + if (_cairo_surface_is_snapshot (surface)) + surface = _cairo_surface_snapshot_get_target (surface); + return (cairo_recording_surface_t *) surface; +} + static cairo_status_t _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *output, cairo_svg_surface_t *surface, @@ -1512,7 +1527,7 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *outp /* cairo_pattern_set_matrix ensures the matrix is invertible */ assert (status == CAIRO_STATUS_SUCCESS); - recording_surface = (cairo_recording_surface_t *) pattern->surface; + recording_surface = to_recording_surface (pattern); status = _cairo_svg_surface_emit_recording_surface (document, recording_surface); if (unlikely (status)) return status; @@ -1559,7 +1574,7 @@ _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t *output, const char *extra_attributes) { - if (_cairo_surface_is_recording (pattern->surface)) { + if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { return _cairo_svg_surface_emit_composite_recording_pattern (output, surface, op, pattern, pattern_id, diff --git a/src/cairo-svg.h b/src/cairo-svg.h index 592c645f6..592c645f6 100755..100644 --- a/src/cairo-svg.h +++ b/src/cairo-svg.h diff --git a/src/cairo-tee-surface-private.h b/src/cairo-tee-surface-private.h index a83cfc959..a83cfc959 100755..100644 --- a/src/cairo-tee-surface-private.h +++ b/src/cairo-tee-surface-private.h diff --git a/src/cairo-tee-surface.c b/src/cairo-tee-surface.c index 294e5f162..294e5f162 100755..100644 --- a/src/cairo-tee-surface.c +++ b/src/cairo-tee-surface.c diff --git a/src/cairo-tee.h b/src/cairo-tee.h index 9125a3a4a..9125a3a4a 100755..100644 --- a/src/cairo-tee.h +++ b/src/cairo-tee.h diff --git a/src/cairo-tg-allocator-private.h b/src/cairo-tg-allocator-private.h deleted file mode 100755 index f62b2e211..000000000 --- a/src/cairo-tg-allocator-private.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef CAIRO_TG_ALLOCATOR_H -#define CAIRO_TG_ALLOCATOR_H - -#include "cairoint.h" - -typedef struct _cairo_tg_mem_chunk cairo_tg_mem_chunk_t; - -struct _cairo_tg_mem_chunk -{ - cairo_tg_mem_chunk_t *next; - uint8_t *buffer; - int chunk_size; - int remaining_size; -}; - -typedef struct _cairo_tg_mono_allocator -{ - cairo_tg_mem_chunk_t *chunk_head; - int chunk_size; -} cairo_tg_mono_allocator_t; - -static inline cairo_tg_mem_chunk_t * -_cairo_tg_mem_chunk_create (int chunk_size) -{ - cairo_tg_mem_chunk_t *chunk; - - chunk = (cairo_tg_mem_chunk_t *) malloc (sizeof (cairo_tg_mem_chunk_t) + chunk_size); - - if (chunk) - { - chunk->next = NULL; - chunk->buffer = (uint8_t *) chunk + sizeof (cairo_tg_mem_chunk_t); - chunk->chunk_size = chunk_size; - chunk->remaining_size = chunk_size; - } - - return chunk; -} - -static inline void -_cairo_tg_mem_chunk_destroy (cairo_tg_mem_chunk_t *chunk) -{ - free (chunk); -} - -static inline cairo_status_t -_cairo_tg_mono_allocator_init (cairo_tg_mono_allocator_t *allocator, int chunk_size) -{ - cairo_tg_mem_chunk_t *chunk; - - chunk = _cairo_tg_mem_chunk_create (chunk_size); - - if (! chunk) - return CAIRO_STATUS_NO_MEMORY; - - allocator->chunk_size = chunk_size; - allocator->chunk_head = chunk; - - return CAIRO_STATUS_SUCCESS; -} - -static inline void -_cairo_tg_mono_allocator_fini (cairo_tg_mono_allocator_t *allocator) -{ - cairo_tg_mem_chunk_t *chunk = allocator->chunk_head, *next; - - while (chunk != NULL) - { - next = chunk->next; - _cairo_tg_mem_chunk_destroy (chunk); - chunk = next; - } - - allocator->chunk_head = NULL; -} - -static inline void * -_cairo_tg_mono_allocator_alloc (cairo_tg_mono_allocator_t *allocator, int size) -{ - cairo_tg_mem_chunk_t *chunk = allocator->chunk_head; - int chunk_size; - - if (chunk && chunk->remaining_size >= size) - { - void *buffer = (void*)(chunk->buffer + chunk->chunk_size - chunk->remaining_size); - chunk->remaining_size -= size; - return buffer; - } - - chunk_size = MAX (allocator->chunk_size, size); - - chunk = _cairo_tg_mem_chunk_create (chunk_size); - - if (chunk == NULL) - return NULL; - - chunk->next = allocator->chunk_head; - chunk->buffer = (uint8_t *) chunk + sizeof (cairo_tg_mem_chunk_t); - chunk->chunk_size = chunk_size; - chunk->remaining_size = chunk_size - size; - - allocator->chunk_head = chunk; - - return (void *) chunk->buffer; -} - -static inline void -_cairo_tg_mono_allocator_reset (cairo_tg_mono_allocator_t *allocator) -{ - cairo_tg_mem_chunk_t *chunk = allocator->chunk_head, *next; - cairo_tg_mem_chunk_t *stock = NULL; - - while (chunk != NULL) - { - next = chunk->next; - - if (stock) - _cairo_tg_mem_chunk_destroy (chunk); - else - stock = chunk; - - chunk = next; - } - - if (stock) - { - stock->next = NULL; - stock->remaining_size = stock->chunk_size; - } - - allocator->chunk_head = stock; -} - -#endif /* CAIRO_TG_ALLOCATOR_H */ diff --git a/src/cairo-tg-composite-extents-private.h b/src/cairo-tg-composite-extents-private.h deleted file mode 100755 index 22de139bf..000000000 --- a/src/cairo-tg-composite-extents-private.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright © 2012 SCore Corporation - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - * Author: Taekyun Kim (podain77@gmail.com) - */ - -#ifndef CAIRO_TG_COMPOSITE_EXTENTS_PRIVATE_H -#define CAIRO_TG_COMPOSITE_EXTENTS_PRIVATE_H - -#include "cairoint.h" -#include "cairo-pattern-private.h" -#include "cairo-clip-private.h" -#include "cairo-surface-private.h" - -static inline void -_cairo_tg_approximate_paint_extents (cairo_rectangle_int_t *extents, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_clip_t *clip) -{ - *extents = * (_cairo_clip_get_extents (clip)); -} - -static inline void -_cairo_tg_approximate_mask_extents (cairo_rectangle_int_t *extents, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_pattern_t *mask, - const cairo_clip_t *clip) -{ - *extents = * (_cairo_clip_get_extents (clip)); -} - -static inline void -_cairo_tg_approximate_stroke_extents (cairo_rectangle_int_t *extents, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - const cairo_stroke_style_t *style, - const cairo_matrix_t *ctm, - const cairo_matrix_t *ctm_inverse, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_rectangle_int_t rect; - - *extents = * (_cairo_clip_get_extents (clip)); - - if (_cairo_operator_bounded_by_either (op)) - { - _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &rect); - _cairo_rectangle_intersect (extents, &rect); - } -} - -static inline void -_cairo_tg_approximate_fill_extents (cairo_rectangle_int_t *extents, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_rectangle_int_t rect; - - *extents = * (_cairo_clip_get_extents (clip)); - - if (_cairo_operator_bounded_by_either (op)) - { - _cairo_path_fixed_approximate_fill_extents (path, &rect); - _cairo_rectangle_intersect (extents, &rect); - } -} - -static inline void -_cairo_tg_approximate_glyphs_extents (cairo_rectangle_int_t *extents, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - const cairo_clip_t *clip) -{ - cairo_rectangle_int_t rect; - - *extents = * (_cairo_clip_get_extents (clip)); - - if (_cairo_operator_bounded_by_either (op)) - { - if (_cairo_scaled_font_glyph_approximate_extents (scaled_font, glyphs, num_glyphs, &rect)) - _cairo_rectangle_intersect (extents, &rect); - } -} - -#endif /* CAIRO_TG_COMPOSITE_EXTENTS_PRIVATE_H */ diff --git a/src/cairo-tg-journal-private.h b/src/cairo-tg-journal-private.h deleted file mode 100755 index 694f77cfd..000000000 --- a/src/cairo-tg-journal-private.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright © 2012 SCore Corporation - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - * Author: Taekyun Kim (podain77@gmail.com) - */ - -#ifndef CAIRO_TG_JOURNAL_PRIVATE_H -#define CAIRO_TG_JOURNAL_PRIVATE_H - -#include "cairoint.h" -#include "cairo-pattern-private.h" -#include "cairo-clip-private.h" -#include "cairo-surface-private.h" -#include "cairo-list-private.h" -#include "cairo-list-inline.h" -#include "cairo-tg-allocator-private.h" -#include "cairo-mutex-private.h" - -typedef enum -{ - CAIRO_TG_JOURNAL_ENTRY_PAINT, - CAIRO_TG_JOURNAL_ENTRY_MASK, - CAIRO_TG_JOURNAL_ENTRY_FILL, - CAIRO_TG_JOURNAL_ENTRY_STROKE, - CAIRO_TG_JOURNAL_ENTRY_GLYPHS, -} cairo_tg_journal_entry_type_t; - -typedef struct _cairo_tg_journal_entry cairo_tg_journal_entry_t; - -struct _cairo_tg_journal_entry -{ - cairo_list_t link; - cairo_tg_journal_entry_type_t type; - - cairo_rectangle_int_t extents; - - cairo_operator_t op; - cairo_pattern_union_t source; - cairo_clip_t *clip; -}; - -typedef struct _cairo_tg_journal_entry_paint -{ - cairo_tg_journal_entry_t base; -} cairo_tg_journal_entry_paint_t; - -typedef struct _cairo_tg_journal_entry_mask -{ - cairo_tg_journal_entry_t base; - - cairo_pattern_union_t mask; -} cairo_tg_journal_entry_mask_t; - -typedef struct _cairo_tg_journal_entry_stroke -{ - cairo_tg_journal_entry_t base; - - cairo_path_fixed_t path; - cairo_stroke_style_t style; - cairo_matrix_t ctm; - cairo_matrix_t ctm_inverse; - double tolerance; - cairo_antialias_t antialias; -} cairo_tg_journal_entry_stroke_t; - -typedef struct _cairo_tg_journal_entry_fill -{ - cairo_tg_journal_entry_t base; - - cairo_path_fixed_t path; - cairo_fill_rule_t fill_rule; - double tolerance; - cairo_antialias_t antialias; -} cairo_tg_journal_entry_fill_t; - -typedef struct _cairo_tg_journal_entry_glyphs -{ - cairo_tg_journal_entry_t base; - - cairo_glyph_t *glyphs; - int num_glyphs; - cairo_scaled_font_t *scaled_font; -} cairo_tg_journal_entry_glyphs_t; - -typedef struct _cairo_tg_journal -{ - cairo_rectangle_int_t extents; - cairo_list_t entry_list; - int num_entries; - cairo_tg_mono_allocator_t allocator; - cairo_mutex_t mutex; -} cairo_tg_journal_t; - -typedef struct _cairo_tg_journal_replay_funcs -{ - cairo_int_status_t - (*paint) (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_clip_t *clip); - - cairo_int_status_t - (*mask) (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_pattern_t *mask, - const cairo_clip_t *clip); - - cairo_int_status_t - (*stroke) (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - const cairo_stroke_style_t *style, - const cairo_matrix_t *ctm, - const cairo_matrix_t *ctm_inverse, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip); - - cairo_int_status_t - (*fill) (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip); - - cairo_int_status_t - (*glyphs) (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - const cairo_clip_t *clip); -} cairo_tg_journal_replay_funcs_t; - -cairo_int_status_t -_cairo_tg_journal_init (cairo_tg_journal_t *journal); - -void -_cairo_tg_journal_fini (cairo_tg_journal_t *journal); - -void -_cairo_tg_journal_lock (cairo_tg_journal_t *journal); - -void -_cairo_tg_journal_unlock (cairo_tg_journal_t *journal); - -cairo_int_status_t -_cairo_tg_journal_log_paint (cairo_tg_journal_t *journal, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_clip_t *clip); - -cairo_int_status_t -_cairo_tg_journal_log_mask (cairo_tg_journal_t *journal, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_pattern_t *mask, - const cairo_clip_t *clip); - -cairo_int_status_t -_cairo_tg_journal_log_stroke (cairo_tg_journal_t *journal, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - const cairo_stroke_style_t *style, - const cairo_matrix_t *ctm, - const cairo_matrix_t *ctm_inverse, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip); - -cairo_int_status_t -_cairo_tg_journal_log_fill (cairo_tg_journal_t *journal, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip); - -cairo_int_status_t -_cairo_tg_journal_log_glyphs (cairo_tg_journal_t *journal, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - const cairo_clip_t *clip); - -void -_cairo_tg_journal_clear (cairo_tg_journal_t *journal); - -cairo_int_status_t -_cairo_tg_journal_replay (const cairo_tg_journal_t *journal, - void *closure, - const cairo_rectangle_int_t *extents, - const cairo_tg_journal_replay_funcs_t *funcs); - -#endif /* CAIRO_TG_JOURNAL_PRIVATE_H */ diff --git a/src/cairo-tg-journal.c b/src/cairo-tg-journal.c deleted file mode 100755 index 1d3902134..000000000 --- a/src/cairo-tg-journal.c +++ /dev/null @@ -1,520 +0,0 @@ -/* - * Copyright © 2012 SCore Corporation - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - * Author: Taekyun Kim (podain77@gmail.com) - */ - -#include "cairo-tg.h" -#include "cairo-tg-private.h" -#include "cairo-tg-journal-private.h" -#include "cairo-tg-allocator-private.h" -#include "cairo-tg-composite-extents-private.h" - -static inline cairo_int_status_t -_cairo_tg_journal_pattern_snapshot (cairo_pattern_t *dst, - const cairo_pattern_t *src) -{ - return _cairo_pattern_init_snapshot (dst, src); -} - -/* Allocator for various types of journal entries. */ -static cairo_tg_journal_entry_t * -_cairo_tg_journal_entry_alloc (cairo_tg_mono_allocator_t *allocator, - cairo_tg_journal_entry_type_t type) -{ - cairo_tg_journal_entry_t *entry = NULL; - - switch (type) - { - case CAIRO_TG_JOURNAL_ENTRY_PAINT: - entry = _cairo_tg_mono_allocator_alloc (allocator, - sizeof (cairo_tg_journal_entry_paint_t)); - break; - case CAIRO_TG_JOURNAL_ENTRY_MASK: - entry = _cairo_tg_mono_allocator_alloc (allocator, - sizeof (cairo_tg_journal_entry_mask_t)); - break; - case CAIRO_TG_JOURNAL_ENTRY_STROKE: - entry = _cairo_tg_mono_allocator_alloc (allocator, - sizeof (cairo_tg_journal_entry_stroke_t)); - break; - case CAIRO_TG_JOURNAL_ENTRY_FILL: - entry = _cairo_tg_mono_allocator_alloc (allocator, - sizeof (cairo_tg_journal_entry_fill_t)); - break; - case CAIRO_TG_JOURNAL_ENTRY_GLYPHS: - entry = _cairo_tg_mono_allocator_alloc (allocator, - sizeof (cairo_tg_journal_entry_glyphs_t)); - break; - default: - ASSERT_NOT_REACHED; - return NULL; - } - - /* One should not change the type of an entry. - * It is determined at the moment of allocation. */ - entry->type = type; - - return entry; -} - -static void -_cairo_tg_journal_entry_fini (cairo_tg_journal_entry_t *entry) -{ - /* common part. */ - _cairo_pattern_fini (&entry->source.base); - - if (entry->clip) - _cairo_clip_destroy (entry->clip); - - /* For each entry types... */ - switch (entry->type) - { - case CAIRO_TG_JOURNAL_ENTRY_PAINT: - break; - case CAIRO_TG_JOURNAL_ENTRY_MASK: - { - cairo_tg_journal_entry_mask_t *entry_mask = - (cairo_tg_journal_entry_mask_t *) entry; - - _cairo_pattern_fini (&entry_mask->mask.base); - } - break; - case CAIRO_TG_JOURNAL_ENTRY_STROKE: - { - cairo_tg_journal_entry_stroke_t *entry_stroke = - (cairo_tg_journal_entry_stroke_t *) entry; - - _cairo_path_fixed_fini (&entry_stroke->path); - _cairo_stroke_style_fini (&entry_stroke->style); - } - break; - case CAIRO_TG_JOURNAL_ENTRY_FILL: - { - cairo_tg_journal_entry_fill_t *entry_fill = - (cairo_tg_journal_entry_fill_t *) entry; - - _cairo_path_fixed_fini (&entry_fill->path); - } - break; - case CAIRO_TG_JOURNAL_ENTRY_GLYPHS: - { - cairo_tg_journal_entry_glyphs_t *entry_glyphs = - (cairo_tg_journal_entry_glyphs_t *) entry; - - free (entry_glyphs->glyphs); - cairo_scaled_font_destroy (entry_glyphs->scaled_font); - } - break; - default: - ASSERT_NOT_REACHED; - } -} - -cairo_int_status_t -_cairo_tg_journal_init (cairo_tg_journal_t *journal) -{ - cairo_int_status_t status; - - CAIRO_MUTEX_INIT (journal->mutex); - journal->num_entries = 0; - cairo_list_init (&journal->entry_list); - journal->extents = _cairo_empty_rectangle; - - status = _cairo_tg_mono_allocator_init (&journal->allocator, 4096 - - sizeof (cairo_tg_mem_chunk_t)); - - return status; -} - -void -_cairo_tg_journal_fini (cairo_tg_journal_t *journal) -{ - cairo_tg_journal_entry_t *entry; - cairo_tg_journal_entry_t *next; - - CAIRO_MUTEX_FINI (journal->mutex); - cairo_list_foreach_entry_safe (entry, next, cairo_tg_journal_entry_t, - &journal->entry_list, link) - { - _cairo_tg_journal_entry_fini (entry); - } - - _cairo_tg_mono_allocator_fini (&journal->allocator); -} - -void -_cairo_tg_journal_lock (cairo_tg_journal_t *journal) -{ - CAIRO_MUTEX_LOCK (journal->mutex); -} - -void -_cairo_tg_journal_unlock (cairo_tg_journal_t *journal) -{ - CAIRO_MUTEX_UNLOCK (journal->mutex); -} - -cairo_int_status_t -_cairo_tg_journal_log_paint (cairo_tg_journal_t *journal, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_clip_t *clip) -{ - cairo_int_status_t status; - cairo_tg_journal_entry_paint_t *entry; - - entry = (cairo_tg_journal_entry_paint_t *) - _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_PAINT); - - if (unlikely (entry == NULL)) - return CAIRO_INT_STATUS_NO_MEMORY; - - status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source); - - if (unlikely (status)) - return status; - - entry->base.op = op; - entry->base.clip = _cairo_clip_copy (clip); - _cairo_tg_approximate_paint_extents (&entry->base.extents, op, source, clip); - _cairo_rectangle_union (&journal->extents, &entry->base.extents); - - cairo_list_add_tail (&entry->base.link, &journal->entry_list); - journal->num_entries++; - - return CAIRO_INT_STATUS_SUCCESS; -} - -cairo_int_status_t -_cairo_tg_journal_log_mask (cairo_tg_journal_t *journal, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_pattern_t *mask, - const cairo_clip_t *clip) -{ - cairo_int_status_t status; - cairo_tg_journal_entry_mask_t *entry; - - entry = (cairo_tg_journal_entry_mask_t *) - _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_MASK); - - if (unlikely (entry == NULL)) - return CAIRO_INT_STATUS_NO_MEMORY; - - status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source); - - if (unlikely (status)) - return status; - - status = _cairo_tg_journal_pattern_snapshot (&entry->mask.base, mask); - - if (unlikely (status)) - { - _cairo_pattern_fini (&entry->base.source.base); - return status; - } - - entry->base.op = op; - entry->base.clip = _cairo_clip_copy (clip); - _cairo_tg_approximate_mask_extents (&entry->base.extents, op, source, mask, clip); - _cairo_rectangle_union (&journal->extents, &entry->base.extents); - - cairo_list_add_tail (&entry->base.link, &journal->entry_list); - journal->num_entries++; - - return CAIRO_INT_STATUS_SUCCESS; -} - -cairo_int_status_t -_cairo_tg_journal_log_stroke (cairo_tg_journal_t *journal, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - const cairo_stroke_style_t *style, - const cairo_matrix_t *ctm, - const cairo_matrix_t *ctm_inverse, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_int_status_t status; - cairo_tg_journal_entry_stroke_t *entry; - - entry = (cairo_tg_journal_entry_stroke_t *) - _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_STROKE); - - if (unlikely (entry == NULL)) - return CAIRO_INT_STATUS_NO_MEMORY; - - status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source); - - if (unlikely (status)) - return status; - - status = _cairo_path_fixed_init_copy (&entry->path, path); - - if (unlikely (status)) - { - _cairo_pattern_fini (&entry->base.source.base); - return status; - } - - status = _cairo_stroke_style_init_copy (&entry->style, style); - - if (unlikely (status)) - { - _cairo_path_fixed_fini (&entry->path); - _cairo_pattern_fini (&entry->base.source.base); - return status; - } - - entry->base.op = op; - entry->base.clip = _cairo_clip_copy (clip); - entry->ctm = *ctm; - entry->ctm_inverse = *ctm_inverse; - entry->tolerance = tolerance; - entry->antialias = antialias; - _cairo_tg_approximate_stroke_extents (&entry->base.extents, op, source, - path, style, ctm, ctm_inverse, - tolerance, antialias, clip); - _cairo_rectangle_union (&journal->extents, &entry->base.extents); - - cairo_list_add_tail (&entry->base.link, &journal->entry_list); - journal->num_entries++; - - return CAIRO_INT_STATUS_SUCCESS; -} - -cairo_int_status_t -_cairo_tg_journal_log_fill (cairo_tg_journal_t *journal, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_int_status_t status; - cairo_tg_journal_entry_fill_t *entry; - - entry = (cairo_tg_journal_entry_fill_t *) - _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_FILL); - - if (unlikely (entry == NULL)) - return CAIRO_INT_STATUS_NO_MEMORY; - - status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source); - - if (unlikely (status)) - return status; - - status = _cairo_path_fixed_init_copy (&entry->path, path); - - if (unlikely (status)) - { - _cairo_pattern_fini (&entry->base.source.base); - return status; - } - - entry->base.op = op; - entry->base.clip = _cairo_clip_copy (clip); - entry->fill_rule = fill_rule; - entry->tolerance = tolerance; - entry->antialias = antialias; - _cairo_tg_approximate_fill_extents (&entry->base.extents, op, source, - path, fill_rule, tolerance, antialias, clip); - _cairo_rectangle_union (&journal->extents, &entry->base.extents); - - cairo_list_add_tail (&entry->base.link, &journal->entry_list); - journal->num_entries++; - - return CAIRO_INT_STATUS_SUCCESS; -} - -cairo_int_status_t -_cairo_tg_journal_log_glyphs (cairo_tg_journal_t *journal, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - const cairo_clip_t *clip) -{ - cairo_int_status_t status; - cairo_tg_journal_entry_glyphs_t *entry; - - entry = (cairo_tg_journal_entry_glyphs_t *) - _cairo_tg_journal_entry_alloc (&journal->allocator, CAIRO_TG_JOURNAL_ENTRY_GLYPHS); - - if (unlikely (entry == NULL)) - return CAIRO_INT_STATUS_NO_MEMORY; - - status = _cairo_tg_journal_pattern_snapshot (&entry->base.source.base, source); - - if (unlikely (status)) - return status; - - entry->scaled_font = cairo_scaled_font_reference (scaled_font); - - if (unlikely (entry->scaled_font == NULL)) - { - _cairo_pattern_fini (&entry->base.source.base); - return CAIRO_INT_STATUS_NO_MEMORY; - } - - if (num_glyphs) - { - entry->glyphs = malloc (sizeof (cairo_glyph_t) * num_glyphs); - - if (unlikely (entry->glyphs == NULL)) - { - cairo_scaled_font_destroy (entry->scaled_font); - _cairo_pattern_fini (&entry->base.source.base); - return CAIRO_INT_STATUS_NO_MEMORY; - } - - memcpy (entry->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs); - } - else - { - entry->glyphs = NULL; - } - - entry->num_glyphs = num_glyphs; - entry->base.op = op; - entry->base.clip = _cairo_clip_copy (clip); - _cairo_tg_approximate_glyphs_extents (&entry->base.extents, op, source, - glyphs, num_glyphs, scaled_font, clip); - _cairo_rectangle_union (&journal->extents, &entry->base.extents); - - cairo_list_add_tail (&entry->base.link, &journal->entry_list); - journal->num_entries++; - - return CAIRO_INT_STATUS_SUCCESS; -} - -void -_cairo_tg_journal_clear (cairo_tg_journal_t *journal) -{ - cairo_tg_journal_entry_t *entry; - cairo_tg_journal_entry_t *next; - - cairo_list_foreach_entry_safe (entry, next, cairo_tg_journal_entry_t, - &journal->entry_list, link) - { - _cairo_tg_journal_entry_fini (entry); - } - - journal->num_entries = 0; - cairo_list_init (&journal->entry_list); - _cairo_tg_mono_allocator_reset(&journal->allocator); - journal->extents = _cairo_empty_rectangle; -} - -cairo_int_status_t -_cairo_tg_journal_replay (const cairo_tg_journal_t *journal, - void *closure, - const cairo_rectangle_int_t *extents, - const cairo_tg_journal_replay_funcs_t *funcs) -{ - const cairo_tg_journal_entry_t *entry; - const cairo_tg_journal_entry_t *next; - cairo_int_status_t status; - - cairo_list_foreach_entry_safe (entry, next, cairo_tg_journal_entry_t, - &journal->entry_list, link) - { - if (extents && ! _cairo_rectangle_intersects (extents, &entry->extents)) - { - continue; - } - - switch (entry->type) - { - case CAIRO_TG_JOURNAL_ENTRY_PAINT: - { - cairo_tg_journal_entry_paint_t *e = - (cairo_tg_journal_entry_paint_t *) entry; - - status = funcs->paint (closure, e->base.op, &e->base.source.base, - e->base.clip); - } - break; - case CAIRO_TG_JOURNAL_ENTRY_MASK: - { - cairo_tg_journal_entry_mask_t *e = - (cairo_tg_journal_entry_mask_t *) entry; - - status = funcs->mask (closure, e->base.op, &e->base.source.base, - &e->mask.base, e->base.clip); - } - break; - case CAIRO_TG_JOURNAL_ENTRY_STROKE: - { - cairo_tg_journal_entry_stroke_t *e = - (cairo_tg_journal_entry_stroke_t *) entry; - - status = funcs->stroke (closure, e->base.op, &e->base.source.base, - &e->path, &e->style, &e->ctm, &e->ctm_inverse, - e->tolerance, e->antialias, e->base.clip); - } - break; - case CAIRO_TG_JOURNAL_ENTRY_FILL: - { - cairo_tg_journal_entry_fill_t *e = - (cairo_tg_journal_entry_fill_t *) entry; - - status = funcs->fill (closure, e->base.op, &e->base.source.base, - &e->path, e->fill_rule, - e->tolerance, e->antialias, e->base.clip); - } - break; - case CAIRO_TG_JOURNAL_ENTRY_GLYPHS: - { - cairo_tg_journal_entry_glyphs_t *e = - (cairo_tg_journal_entry_glyphs_t *) entry; - - status = funcs->glyphs (closure, e->base.op, &e->base.source.base, - e->glyphs, e->num_glyphs, - e->scaled_font, e->base.clip); - } - break; - default: - ASSERT_NOT_REACHED; - break; - } - - if (unlikely (status) && status != CAIRO_INT_STATUS_NOTHING_TO_DO) - { - assert (0); - return status; - } - } - - return CAIRO_INT_STATUS_SUCCESS; -} diff --git a/src/cairo-tg-surface.c b/src/cairo-tg-surface.c deleted file mode 100755 index c32799fa4..000000000 --- a/src/cairo-tg-surface.c +++ /dev/null @@ -1,1372 +0,0 @@ -/* - * Copyright © 2012 SCore Corporation - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - * Author: Taekyun Kim (podain77@gmail.com) - */ - -#include "cairoint.h" -#include "cairo-surface-fallback-private.h" -#include "cairo-tg.h" -#include "cairo-tg-private.h" -#include "cairo-image-surface-inline.h" -#include "cairo-surface-subsurface-inline.h" -#include "cairo-compositor-private.h" -#include "cairo-clip-inline.h" -#include "cairo-recording-surface-inline.h" - -#if CAIRO_HAS_OPENMP -#include <omp.h> -#endif - -#define CAIRO_TG_THREAD_POOL_BUSY_WAIT -#define CAIRO_TG_NUM_MIN_ENTRIES_FOR_PARALLEL_FLUSH 2 - -static inline int -get_num_cpu_cores (void) -{ - static int num_cpu_cores = 0; - - if (num_cpu_cores == 0) - { -#if CAIRO_HAS_OPENMP - num_cpu_cores = omp_get_num_procs (); -#elif defined (__WIN32) - SYSTEM_INFO sysinfo; - - GetSystemInfo (&sysinfo); - num_cpu_cores = sysinfo.dwNumberOfProcessors; -#elif defined (__linux__) - cpu_set_t cs; - int i; - - CPU_ZERO (&cs); - - if (sched_getaffinity (0, sizeof (cs), &cs) != 0) - num_cpu_cores = 1; - - for (i = 0; i < 8; i++) - { - if (CPU_ISSET (i, &cs)) - num_cpu_cores++; - } -#else - num_cpu_cores = 1; -#endif - } - - return num_cpu_cores; -} - -static inline int -get_bpp_for_format (cairo_format_t format) -{ - switch (format) - { - case CAIRO_FORMAT_ARGB32: - case CAIRO_FORMAT_RGB24: - case CAIRO_FORMAT_RGB30: - return 32; - case CAIRO_FORMAT_RGB16_565: - return 16; - case CAIRO_FORMAT_A8: - return 8; - case CAIRO_FORMAT_A1: - return 1; - case CAIRO_FORMAT_INVALID: - default: - ASSERT_NOT_REACHED; - return 0; - } -} - -static inline cairo_bool_t -_cairo_surface_is_tg(const cairo_surface_t *surface) -{ - return surface->backend && surface->backend->type == CAIRO_SURFACE_TYPE_TG; -} - -static inline cairo_bool_t -_cairo_tg_surface_is_size_valid (int width, int height) -{ - if (width < 0 || height < 0) - return FALSE; - - /* TODO: Check for upper limit of surface size. */ - - return TRUE; -} - -static inline cairo_bool_t -_cairo_pattern_is_self_copy (cairo_surface_t *surface, - const cairo_pattern_t *pattern) -{ - if (unlikely (surface == NULL)) - return FALSE; - - if (unlikely (pattern == NULL)) - return FALSE; - - if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE ) - { - cairo_surface_t *pattern_surface = - ((cairo_surface_pattern_t *) pattern)->surface; - - while (_cairo_surface_is_subsurface (pattern_surface)) - { - pattern_surface = - _cairo_surface_subsurface_get_target (pattern_surface); - } - - return pattern_surface == surface; - } - - return FALSE; -} - -static inline cairo_bool_t -_cairo_pattern_is_recording (const cairo_pattern_t *pattern) -{ - cairo_surface_t *surface; - - if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE) - return FALSE; - - surface = ((const cairo_surface_pattern_t *) pattern)->surface; - return _cairo_surface_is_recording (surface); -} - -static inline cairo_bool_t -_cairo_tg_surface_owns_data (cairo_tg_surface_t *surface) -{ - return ((cairo_image_surface_t *) surface->image_surface)->owns_data; -} - -static inline cairo_int_status_t -_cairo_tg_image_surface_paint (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_clip_t *clip) -{ - cairo_image_surface_t *surface = (cairo_image_surface_t *) closure; - cairo_int_status_t status; - - status = _cairo_surface_begin_modification (&surface->base); - - if (unlikely (status)) - return status; - - status = _cairo_compositor_paint (surface->compositor, &surface->base, - op, source, clip); - - if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) - { - surface->base.is_clear = op == CAIRO_OPERATOR_CLEAR && clip == NULL; - surface->base.serial++; - } - - return status; -} - -static inline cairo_int_status_t -_cairo_tg_image_surface_mask (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_pattern_t *mask, - const cairo_clip_t *clip) -{ - cairo_image_surface_t *surface = (cairo_image_surface_t *) closure; - cairo_int_status_t status; - - status = _cairo_surface_begin_modification (&surface->base); - - if (unlikely (status)) - return status; - - status = _cairo_compositor_mask (surface->compositor, &surface->base, - op, source, mask, clip); - - if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) - { - surface->base.is_clear = FALSE; - surface->base.serial++; - } - - return status; -} - -static inline cairo_int_status_t -_cairo_tg_image_surface_stroke (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - const cairo_stroke_style_t *style, - const cairo_matrix_t *ctm, - const cairo_matrix_t *ctm_inverse, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_image_surface_t *surface = (cairo_image_surface_t *) closure; - cairo_int_status_t status; - - status = _cairo_surface_begin_modification (&surface->base); - - if (unlikely (status)) - return status; - - status = _cairo_compositor_stroke (surface->compositor, &surface->base, - op, source, path, - style, ctm, ctm_inverse, - tolerance, antialias, clip); - - if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) - { - surface->base.is_clear = FALSE; - surface->base.serial++; - } - - return status; -} - - -static inline cairo_int_status_t -_cairo_tg_image_surface_fill (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_image_surface_t *surface = (cairo_image_surface_t *) closure; - cairo_int_status_t status; - - status = _cairo_surface_begin_modification (&surface->base); - - if (unlikely (status)) - return status; - - status = _cairo_compositor_fill (surface->compositor, &surface->base, - op, source, path, - fill_rule, tolerance, antialias, clip); - - if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) - { - surface->base.is_clear = FALSE; - surface->base.serial++; - } - - return status; -} - -static inline cairo_int_status_t -_cairo_tg_image_surface_glyphs (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - const cairo_clip_t *clip) -{ - cairo_image_surface_t *surface = (cairo_image_surface_t *) closure; - cairo_int_status_t status; - - status = _cairo_surface_begin_modification (&surface->base); - - if (unlikely (status)) - return status; - - status = _cairo_compositor_glyphs (surface->compositor, &surface->base, - op, source, - glyphs, num_glyphs, scaled_font, - clip); - - if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) - { - surface->base.is_clear = FALSE; - surface->base.serial++; - } - - return status; -} - -const cairo_tg_journal_replay_funcs_t replay_funcs_image_fallback = -{ - _cairo_tg_image_surface_paint, - _cairo_tg_image_surface_mask, - _cairo_tg_image_surface_stroke, - _cairo_tg_image_surface_fill, - _cairo_tg_image_surface_glyphs, -}; - -typedef struct _cairo_tg_surface_tile -{ - cairo_surface_t *surface; - cairo_rectangle_int_t tile_rect; -} cairo_tg_surface_tile_t; - -static inline int -_cairo_tg_surface_tiles_init (cairo_tg_surface_t *surface, - const cairo_rectangle_int_t *extents, - int num_tiles, - cairo_tg_surface_tile_t *tiles) -{ - int tile_height; - int i; - - if (extents->height <= 0) - return 0; - - if (extents->height <= num_tiles) - num_tiles = extents->height; - - tile_height = extents->height / num_tiles; - - for (i = 0; i < num_tiles; i++) - { - tiles[i].surface = surface->tile_surfaces[i]; - tiles[i].tile_rect.x = extents->x; - tiles[i].tile_rect.y = extents->y + i * tile_height; - tiles[i].tile_rect.width = extents->width; - tiles[i].tile_rect.height = tile_height; - } - - tiles[num_tiles - 1].tile_rect.height = extents->height - i * (num_tiles - 1); - - return num_tiles; -} - -static cairo_int_status_t -_cairo_tg_surface_tile_paint (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_clip_t *clip) -{ - cairo_tg_surface_tile_t *tile = (cairo_tg_surface_tile_t *) closure; - cairo_clip_t *tile_clip; - cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; - - tile_clip = _cairo_clip_copy_intersect_rectangle (clip, &tile->tile_rect); - - if (! _cairo_clip_is_all_clipped (tile_clip)) - status = _cairo_tg_image_surface_paint (tile->surface, op, source, tile_clip); - - _cairo_clip_destroy (tile_clip); - - return status; -} - -static cairo_int_status_t -_cairo_tg_surface_tile_mask (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_pattern_t *mask, - const cairo_clip_t *clip) -{ - cairo_tg_surface_tile_t *tile = (cairo_tg_surface_tile_t *) closure; - cairo_clip_t *tile_clip; - cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; - - tile_clip = _cairo_clip_copy_intersect_rectangle (clip, &tile->tile_rect); - - if (! _cairo_clip_is_all_clipped (tile_clip)) - { - status = _cairo_tg_image_surface_mask (tile->surface, op, source, - mask, tile_clip); - } - - _cairo_clip_destroy (tile_clip); - - return status; -} - -static cairo_int_status_t -_cairo_tg_surface_tile_stroke (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - const cairo_stroke_style_t *style, - const cairo_matrix_t *ctm, - const cairo_matrix_t *ctm_inverse, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_tg_surface_tile_t *tile = (cairo_tg_surface_tile_t *) closure; - cairo_clip_t *tile_clip; - cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; - - tile_clip = _cairo_clip_copy_intersect_rectangle (clip, &tile->tile_rect); - - if (! _cairo_clip_is_all_clipped (tile_clip)) - { - status = _cairo_tg_image_surface_stroke (tile->surface, op, source, - path, style, ctm, ctm_inverse, - tolerance, antialias, tile_clip); - } - - _cairo_clip_destroy (tile_clip); - - return status; -} - -static cairo_int_status_t -_cairo_tg_surface_tile_fill (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_tg_surface_tile_t *tile = (cairo_tg_surface_tile_t *) closure; - cairo_clip_t *tile_clip; - cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; - - tile_clip = _cairo_clip_copy_intersect_rectangle (clip, &tile->tile_rect); - - if (! _cairo_clip_is_all_clipped (tile_clip)) - { - status = _cairo_tg_image_surface_fill (tile->surface, op, source, - path, fill_rule, tolerance, - antialias, tile_clip); - } - - _cairo_clip_destroy (tile_clip); - - return status; -} - -static cairo_int_status_t -_cairo_tg_surface_tile_glyphs (void *closure, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - const cairo_clip_t *clip) -{ - cairo_tg_surface_tile_t *tile = (cairo_tg_surface_tile_t *) closure; - cairo_clip_t *tile_clip; - cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; - - tile_clip = _cairo_clip_copy_intersect_rectangle (clip, &tile->tile_rect); - - if (! _cairo_clip_is_all_clipped (tile_clip)) - { - status = _cairo_tg_image_surface_glyphs (tile->surface, op, source, - glyphs, num_glyphs, scaled_font, - tile_clip); - } - - _cairo_clip_destroy (tile_clip); - - return status; -} - -const cairo_tg_journal_replay_funcs_t replay_funcs_tile = -{ - _cairo_tg_surface_tile_paint, - _cairo_tg_surface_tile_mask, - _cairo_tg_surface_tile_stroke, - _cairo_tg_surface_tile_fill, - _cairo_tg_surface_tile_glyphs, -}; - -#if ! CAIRO_HAS_OPENMP -#define CAIRO_TG_NUM_MAX_WORKERS CAIRO_TG_NUM_MAX_TILES - -typedef enum _cairo_tg_worker_status -{ - CAIRO_TG_WORKER_STATUS_IDLE, /* can transit to either OCCUPIED or KILLED */ - CAIRO_TG_WORKER_STATUS_TO_DO, /* only can transit to IDLE state */ - CAIRO_TG_WORKER_STATUS_KILLED, /* worker will be no longer valid */ -} cairo_tg_worker_status_t; - -typedef struct _cairo_tg_worker -{ - cairo_tg_journal_t *journal; - cairo_tg_surface_tile_t *tile; - - pthread_t thread; - pthread_mutex_t lock; - pthread_cond_t cond_wake_up; - cairo_tg_worker_status_t status; - -#ifdef CAIRO_TG_THREAD_POOL_BUSY_WAIT - pthread_spinlock_t spinlock; -#else - pthread_cond_t cond_done; -#endif -} cairo_tg_worker_t; - -cairo_tg_worker_t workers[CAIRO_TG_NUM_MAX_WORKERS]; - -pthread_mutex_t workers_lock; -cairo_bool_t workers_occupied; - -static void * -_cairo_tg_worker_mainloop (void *arg) -{ - cairo_tg_worker_t *worker = (cairo_tg_worker_t *) arg; - - while (1) - { - pthread_mutex_lock (&worker->lock); - - while (worker->status == CAIRO_TG_WORKER_STATUS_IDLE) - pthread_cond_wait (&worker->cond_wake_up, &worker->lock); - - /* Here, worker is kicked off to do some action. */ - - if (worker->status == CAIRO_TG_WORKER_STATUS_KILLED) - { - /* Worker is killed, so release mutex and exit. */ - pthread_mutex_unlock (&worker->lock); - pthread_exit (NULL); - } - - assert (worker->status == CAIRO_TG_WORKER_STATUS_TO_DO); - - _cairo_tg_journal_replay (worker->journal, (void *)worker->tile, - &worker->tile->tile_rect, &replay_funcs_tile); - - worker->status = CAIRO_TG_WORKER_STATUS_IDLE; - -#ifndef CAIRO_TG_THREAD_POOL_BUSY_WAIT - pthread_cond_signal (&worker->cond_done); -#endif - - pthread_mutex_unlock (&worker->lock); - } - - return NULL; -} - -static void -_cairo_tg_workers_init (void) -{ - int i; - - for (i = 0; i < CAIRO_TG_NUM_MAX_WORKERS; i++) - { - workers[i].status = CAIRO_TG_WORKER_STATUS_IDLE; - - pthread_mutex_init (&workers[i].lock, NULL); - pthread_cond_init (&workers[i].cond_wake_up, NULL); - -#ifdef CAIRO_TG_THREAD_POOL_BUSY_WAIT - pthread_spin_init (&workers[i].spinlock, 0); -#else - pthread_cond_init (&workers[i].cond_done, NULL); -#endif - - pthread_create (&workers[i].thread, NULL, _cairo_tg_worker_mainloop, (void *) &workers[i]); - } - - pthread_mutex_init (&workers_lock, NULL); - workers_occupied = FALSE; -} - -static void -_cairo_tg_workers_fini (void) -{ - int i; - - for (i = 0; i < CAIRO_TG_NUM_MAX_WORKERS; i++) - { - pthread_mutex_lock (&workers[i].lock); - - workers[i].status = CAIRO_TG_WORKER_STATUS_KILLED; - pthread_cond_signal (&workers[i].cond_wake_up); - pthread_mutex_unlock (&workers[i].lock); - } - - for (i = 0; i < CAIRO_TG_NUM_MAX_WORKERS; i++) - pthread_join (workers[i].thread, NULL); - - for (i = 0; i < CAIRO_TG_NUM_MAX_WORKERS; i++) - { - pthread_mutex_destroy (&workers[i].lock); - pthread_cond_destroy (&workers[i].cond_wake_up); - -#ifdef CAIRO_TG_THREAD_POOL_BUSY_WAIT - pthread_spin_destroy (&workers[i].spinlock); -#else - pthread_cond_destroy (&workers[i].cond_done); -#endif - } -} - -static void __attribute__((constructor)) -_cairo_tg_constructor (void) -{ - pthread_atfork (NULL, NULL, _cairo_tg_workers_init); - _cairo_tg_workers_init (); -} - -static void __attribute__((destructor)) -_cairo_tg_destructor (void) -{ - _cairo_tg_workers_fini (); -} - -#endif /* ! CAIRO_HAS_OPENMP */ - -static void -_cairo_tg_surface_prepare_flush_parallel (cairo_tg_surface_t *surface) -{ - const cairo_tg_journal_entry_t *entry; - const cairo_tg_journal_entry_t *next; - - cairo_list_foreach_entry_safe (entry, next, cairo_tg_journal_entry_t, - &surface->journal.entry_list, link) - { - if (entry->source.base.type == CAIRO_PATTERN_TYPE_SURFACE) - { - cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) (&entry->source.base); - cairo_surface_flush (pattern->surface); - } - - if (entry->type == CAIRO_TG_JOURNAL_ENTRY_MASK) - { - cairo_tg_journal_entry_mask_t *e = - (cairo_tg_journal_entry_mask_t *) entry; - - if (e->mask.base.type == CAIRO_PATTERN_TYPE_SURFACE) - { - cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) (&e->mask.base); - cairo_surface_flush (pattern->surface); - } - } - } -} - -static cairo_int_status_t -_cairo_tg_surface_flush_parallel (cairo_tg_surface_t *surface) -{ - int num_tiles, i; - cairo_tg_surface_tile_t tiles[CAIRO_TG_NUM_MAX_TILES]; - cairo_rectangle_int_t extents; - - if (surface->journal.num_entries < CAIRO_TG_NUM_MIN_ENTRIES_FOR_PARALLEL_FLUSH) - return CAIRO_INT_STATUS_UNSUPPORTED; - - _cairo_tg_surface_prepare_flush_parallel (surface); - - extents.x = 0; - extents.y = 0; - extents.width = surface->width; - extents.height = surface->height; - - _cairo_rectangle_intersect (&extents, &surface->journal.extents); - - num_tiles = get_num_cpu_cores (); - -#if ! CAIRO_HAS_OPENMP - if (num_tiles > CAIRO_TG_NUM_MAX_WORKERS) - num_tiles = CAIRO_TG_NUM_MAX_WORKERS; -#endif - - num_tiles = _cairo_tg_surface_tiles_init (surface, &extents, num_tiles, &tiles[0]); - -#if CAIRO_HAS_OPENMP - #pragma omp parallel for - for (i = 0; i < num_tiles; i++) - { - _cairo_tg_journal_replay (&surface->journal, (void *) &tiles[i], - &tiles[i].tile_rect, &replay_funcs_tile); - } -#else - pthread_mutex_lock (&workers_lock); - - if (workers_occupied) - { - pthread_mutex_unlock (&workers_lock); - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - workers_occupied = TRUE; - pthread_mutex_unlock (&workers_lock); - - /* Kick workers to start. */ - for (i = 0; i < num_tiles - 1; i++) - { - pthread_mutex_lock (&workers[i].lock); - - workers[i].status = CAIRO_TG_WORKER_STATUS_TO_DO; - workers[i].journal = &surface->journal; - workers[i].tile = &tiles[i]; - - pthread_cond_signal (&workers[i].cond_wake_up); - pthread_mutex_unlock (&workers[i].lock); - } - - _cairo_tg_journal_replay (&surface->journal, &tiles[num_tiles - 1], - &tiles[num_tiles - 1].tile_rect, &replay_funcs_tile); - - /* Wait for workers to finish. */ - for (i = 0; i < num_tiles - 1; i++) - { -#ifdef CAIRO_TG_THREAD_POOL_BUSY_WAIT - pthread_spin_lock (&workers[i].spinlock); - - while (workers[i].status == CAIRO_TG_WORKER_STATUS_TO_DO) - { - pthread_spin_unlock (&workers[i].spinlock); - pthread_spin_lock (&workers[i].spinlock); - } - - pthread_spin_unlock (&workers[i].spinlock); -#else - pthread_mutex_lock (&workers[i].lock); - - while (workers[i].status == CAIRO_TG_WORKER_STATUS_TO_DO) - pthread_cond_wait (&workers[i].cond_done, &workers[i].lock); - - pthread_mutex_unlock (&workers[i].lock); -#endif - } - - /* Release thread pool. */ - pthread_mutex_lock (&workers_lock); - workers_occupied = FALSE; - pthread_mutex_unlock (&workers_lock); -#endif - - return CAIRO_INT_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_tg_surface_flush (void *abstract_surface, - unsigned flags) -{ - cairo_tg_surface_t *surface = abstract_surface; - cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; - - if (flags) - return CAIRO_STATUS_SUCCESS; - - _cairo_tg_journal_lock (&surface->journal); - - if (surface->journal.num_entries) - { - status = _cairo_tg_surface_flush_parallel (surface); - - if (status) - { - status = _cairo_tg_journal_replay (&surface->journal, - (void *) surface->image_surface, - NULL, &replay_funcs_image_fallback); - } - - _cairo_tg_journal_clear (&surface->journal); - } - - _cairo_tg_journal_unlock (&surface->journal); - - return status; -} - -static cairo_image_surface_t * -_cairo_tg_surface_map_to_image (void *abstract_surface, - const cairo_rectangle_int_t *extents) -{ - cairo_tg_surface_t *other = abstract_surface; - cairo_surface_t *surface; - uint8_t *buffer; - - _cairo_tg_surface_flush (other, 0); - - buffer = other->data; - buffer += extents->y * other->stride; - buffer += extents->x * other->bpp / 8; - - surface = - _cairo_image_surface_create_with_pixman_format (buffer, - other->pixman_format, - extents->width, - extents->height, - other->stride); - - if (unlikely (surface == NULL)) - return NULL; - - cairo_surface_set_device_offset (surface, -extents->x, extents->y); - - return (cairo_image_surface_t *) surface; -} - -static cairo_int_status_t -_cairo_tg_surface_unmap_image (void *abstract_surface, - cairo_image_surface_t *image) -{ - cairo_surface_finish (&image->base); - cairo_surface_destroy (&image->base); - - return CAIRO_INT_STATUS_SUCCESS; -} - -static cairo_bool_t -_cairo_tg_surface_get_extents (void *abstract_surface, - cairo_rectangle_int_t *extents) -{ - cairo_tg_surface_t *surface = abstract_surface; - - extents->x = 0; - extents->y = 0; - extents->width = surface->width; - extents->height = surface->height; - - return TRUE; -} - -static cairo_int_status_t -_cairo_tg_surface_paint (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_clip_t *clip) -{ - cairo_tg_surface_t *surface = abstract_surface; - cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; - - if (! _cairo_pattern_is_self_copy (&surface->base, source) && - ! _cairo_pattern_is_recording (source)) - status = _cairo_tg_journal_log_paint (&surface->journal, op, source, clip); - - if (status) - { - status = _cairo_tg_surface_flush (surface, 0); - - if (unlikely (status)) - return status; - - status = _cairo_tg_image_surface_paint (surface->image_surface, op, source, clip); - } - - return status; -} - -static cairo_int_status_t -_cairo_tg_surface_mask (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_pattern_t *mask, - const cairo_clip_t *clip) -{ - cairo_tg_surface_t *surface = abstract_surface; - cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; - - if (! _cairo_pattern_is_self_copy (&surface->base, source) && - ! _cairo_pattern_is_self_copy (&surface->base, mask) && - ! _cairo_pattern_is_recording (source)) - status = _cairo_tg_journal_log_mask (&surface->journal, op, source, mask, clip); - - if (status) - { - status = _cairo_tg_surface_flush (surface, 0); - - if (unlikely (status)) - return status; - - status = _cairo_tg_image_surface_mask (surface->image_surface, op, source, - mask, clip); - } - - return status; -} - -static cairo_int_status_t -_cairo_tg_surface_stroke (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - const cairo_stroke_style_t *style, - const cairo_matrix_t *ctm, - const cairo_matrix_t *ctm_inverse, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_tg_surface_t *surface = abstract_surface; - cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; - - if (! _cairo_pattern_is_self_copy (&surface->base, source) && - ! _cairo_pattern_is_recording (source)) - { - status = _cairo_tg_journal_log_stroke (&surface->journal, op, source, - path, style, ctm, ctm_inverse, - tolerance, antialias, clip); - } - - if (status) - { - status = _cairo_tg_surface_flush (surface, 0); - - if (unlikely (status)) - return status; - - status = _cairo_tg_image_surface_stroke (surface->image_surface, op, source, - path, style, ctm, ctm_inverse, - tolerance, antialias, clip); - } - - return status; -} - -static cairo_int_status_t -_cairo_tg_surface_fill (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_tg_surface_t *surface = abstract_surface; - cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; - - if (! _cairo_pattern_is_self_copy (&surface->base, source) && - ! _cairo_pattern_is_recording (source)) - { - status = _cairo_tg_journal_log_fill (&surface->journal, op, source, - path, fill_rule, tolerance, antialias, clip); - } - - if (status) - { - status = _cairo_tg_surface_flush (surface, 0); - - if (unlikely (status)) - return status; - - status = _cairo_tg_image_surface_fill (surface->image_surface, op, source, - path, fill_rule, tolerance, antialias, clip); - } - - return status; -} - -static cairo_int_status_t -_cairo_tg_surface_glyphs (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - const cairo_clip_t *clip) -{ - cairo_tg_surface_t *surface = abstract_surface; - cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; - - if (! _cairo_pattern_is_self_copy (&surface->base, source) && - ! _cairo_pattern_is_recording (source)) - { - status = _cairo_tg_journal_log_glyphs (&surface->journal, op, source, - glyphs, num_glyphs, scaled_font, clip); - } - - if (status) - { - status = _cairo_tg_surface_flush (surface, 0); - - if (unlikely (status)) - return status; - - status = _cairo_tg_image_surface_glyphs (surface->image_surface, op, source, - glyphs, num_glyphs, scaled_font, clip); - } - - return status; -} - -static cairo_surface_t * -_cairo_tg_surface_create_similar (void *abstract_other, - cairo_content_t content, - int width, - int height) -{ - cairo_tg_surface_t *other = abstract_other; - - if (! _cairo_tg_surface_is_size_valid (width, height)) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); - - if (content == other->base.content) - return cairo_tg_surface_create (other->format, width, height); - - return cairo_tg_surface_create (_cairo_format_from_content (content), width, height); -} - -static cairo_surface_t * -_cairo_tg_surface_source (void *abstract_surface, - cairo_rectangle_int_t *extents) -{ - cairo_tg_surface_t *surface = abstract_surface; - - if (extents) - { - extents->x = extents->y = 0; - extents->width = surface->width; - extents->height = surface->height; - } - - return &surface->base; -} - -static cairo_status_t -_cairo_tg_surface_acquire_source_image (void *abstract_surface, - cairo_image_surface_t **image_out, - void **image_extra) -{ - cairo_tg_surface_t *surface = abstract_surface; - - _cairo_tg_surface_flush (surface, 0); - - *image_out = (cairo_image_surface_t *) surface->image_surface; - *image_extra = NULL; - - return CAIRO_STATUS_SUCCESS; -} - -static void -_cairo_tg_surface_release_source_image (void *abstract_surface, - cairo_image_surface_t *image, - void *image_extra) -{ - /* Do nothing */ -} - -static cairo_surface_t * -_cairo_tg_surface_snapshot (void *abstract_surface) -{ - cairo_tg_surface_t *surface = abstract_surface; - cairo_tg_surface_t *clone; - - _cairo_tg_surface_flush (surface, 0); - - if (_cairo_tg_surface_owns_data (surface) && surface->base._finishing) - { - return cairo_tg_surface_create_for_data (surface->data, surface->format, - surface->width, surface->height, - surface->stride); - } - - clone = (cairo_tg_surface_t *) - cairo_tg_surface_create (surface->format, surface->width, surface->height); - - if (unlikely (clone->base.status)) - return &clone->base; - - if (surface->stride == clone->stride) - { - memcpy (clone->data, surface->data, clone->stride * clone->height); - } - else - { - unsigned char *dst = clone->data; - unsigned char *src = surface->data; - int i; - int stride = clone->stride < surface->stride ? clone->stride : surface->stride; - - for (i = 0; i < clone->height; i++) - { - memcpy (dst, src, stride); - dst += clone->stride; - src += surface->stride; - } - } - - clone->base.is_clear = FALSE; - - return &clone->base; -} - -static cairo_int_status_t -_cairo_tg_surface_init_tile_surfaces (cairo_tg_surface_t *surface) -{ - int i; - cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; - - memset (&surface->tile_surfaces[0], 0x00, - sizeof (cairo_surface_t *) * CAIRO_TG_NUM_MAX_TILES); - - for (i = 0; i < CAIRO_TG_NUM_MAX_TILES; i++) - { - surface->tile_surfaces[i] = cairo_image_surface_create_for_data (surface->data, - surface->format, - surface->width, - surface->height, - surface->stride); - - if (surface->tile_surfaces[i] == NULL) - { - status = CAIRO_INT_STATUS_NO_MEMORY; - break; - } - } - - if (unlikely (status)) - { - for (i = 0; i < CAIRO_TG_NUM_MAX_TILES; i++) - { - if (surface->tile_surfaces[i]) - cairo_surface_destroy (surface->tile_surfaces[i]); - else - break; - } - } - - return status; -} - -static void -_cairo_tg_surface_fini_tile_surfaces (cairo_tg_surface_t *surface) -{ - int i; - - for (i = 0; i < CAIRO_TG_NUM_MAX_TILES; i++) - { - if (surface->tile_surfaces[i]) - cairo_surface_destroy (surface->tile_surfaces[i]); - else - break; - } -} - -static cairo_status_t -_cairo_tg_surface_finish (void *abstract_surface) -{ - cairo_tg_surface_t *surface = abstract_surface; - - _cairo_tg_surface_flush (surface, 0); - _cairo_tg_journal_fini (&surface->journal); - _cairo_tg_surface_fini_tile_surfaces (surface); - cairo_surface_destroy (surface->image_surface); - - return CAIRO_STATUS_SUCCESS; -} - -static const cairo_surface_backend_t _cairo_tg_surface_backend = -{ - CAIRO_SURFACE_TYPE_TG, - _cairo_tg_surface_finish, - - _cairo_default_context_create, - - _cairo_tg_surface_create_similar, - NULL, /* create_similar image */ - _cairo_tg_surface_map_to_image, - _cairo_tg_surface_unmap_image, - - _cairo_tg_surface_source, - _cairo_tg_surface_acquire_source_image, - _cairo_tg_surface_release_source_image, - _cairo_tg_surface_snapshot, - - NULL, /* copy_page */ - NULL, /* show_page */ - - _cairo_tg_surface_get_extents, - NULL, /* get_font_options */ - - _cairo_tg_surface_flush, - NULL, /* mark_dirty_rectangle */ - - _cairo_tg_surface_paint, - _cairo_tg_surface_mask, - _cairo_tg_surface_stroke, - _cairo_tg_surface_fill, - NULL, /* fill_stroke */ - _cairo_tg_surface_glyphs, -}; - -cairo_surface_t * -cairo_tg_surface_create (cairo_format_t format, - int width, - int height) -{ - cairo_tg_surface_t *surface; - cairo_surface_t *image_surface; - - image_surface = cairo_image_surface_create (format, width, height); - - if (unlikely (image_surface == NULL)) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - - surface = malloc (sizeof (cairo_tg_surface_t)); - - if (unlikely (surface == NULL)) - { - cairo_surface_destroy (image_surface); - - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - } - - _cairo_surface_init (&surface->base, - &_cairo_tg_surface_backend, - NULL, image_surface->content); - - surface->format = format; - surface->pixman_format = ((cairo_image_surface_t *) image_surface)->pixman_format; - surface->data = (unsigned char *) cairo_image_surface_get_data (image_surface); - surface->width = width; - surface->height = height; - surface->stride = cairo_image_surface_get_stride (image_surface); - surface->bpp = get_bpp_for_format (format); - surface->image_surface = image_surface; - surface->base.is_clear = image_surface->is_clear; - - _cairo_tg_journal_init (&surface->journal); - - if (_cairo_tg_surface_init_tile_surfaces (surface)) - { - cairo_surface_destroy (image_surface); - _cairo_tg_journal_fini (&surface->journal); - - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - } - - return &surface->base; -} - -cairo_surface_t * -cairo_tg_surface_create_for_data (unsigned char *data, - cairo_format_t format, - int width, - int height, - int stride) -{ - cairo_tg_surface_t *surface; - cairo_surface_t *image_surface; - - image_surface = cairo_image_surface_create_for_data (data, format, width, height, stride); - - if (unlikely (image_surface == NULL)) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - - surface = malloc (sizeof (cairo_tg_surface_t)); - - if (unlikely (surface == NULL)) - { - cairo_surface_destroy (image_surface); - - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - } - - _cairo_surface_init (&surface->base, - &_cairo_tg_surface_backend, - NULL, image_surface->content); - - surface->format = format; - surface->pixman_format = ((cairo_image_surface_t *) image_surface)->pixman_format; - surface->data = (unsigned char *) cairo_image_surface_get_data (image_surface); - surface->width = width; - surface->height = height; - surface->stride = cairo_image_surface_get_stride (image_surface); - surface->bpp = get_bpp_for_format (format); - surface->image_surface = image_surface; - surface->base.is_clear = image_surface->is_clear; - - _cairo_tg_journal_init (&surface->journal); - - if (_cairo_tg_surface_init_tile_surfaces (surface)) - { - cairo_surface_destroy (image_surface); - _cairo_tg_journal_fini (&surface->journal); - - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - } - - return &surface->base; -} - -unsigned char * -cairo_tg_surface_get_data (cairo_surface_t *surface) -{ - cairo_tg_surface_t *tg_surface = (cairo_tg_surface_t *) surface; - - if (! _cairo_surface_is_tg (surface)) { - _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); - return NULL; - } - - return tg_surface->data; -} - -cairo_format_t -cairo_tg_surface_get_format (cairo_surface_t *surface) -{ - cairo_tg_surface_t *tg_surface = (cairo_tg_surface_t *) surface; - - if (! _cairo_surface_is_tg (surface)) { - _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); - return CAIRO_FORMAT_INVALID; - } - - return tg_surface->format; -} - -int -cairo_tg_surface_get_width (cairo_surface_t *surface) -{ - cairo_tg_surface_t *tg_surface = (cairo_tg_surface_t *) surface; - - if (! _cairo_surface_is_tg (surface)) { - _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); - return 0; - } - - return tg_surface->width; -} - -int -cairo_tg_surface_get_height (cairo_surface_t *surface) -{ - cairo_tg_surface_t *tg_surface = (cairo_tg_surface_t *) surface; - - if (! _cairo_surface_is_tg (surface)) { - _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); - return 0; - } - - return tg_surface->height; -} - -int -cairo_tg_surface_get_stride (cairo_surface_t *surface) -{ - cairo_tg_surface_t *tg_surface = (cairo_tg_surface_t *) surface; - - if (! _cairo_surface_is_tg (surface)) { - _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); - return 0; - } - - return tg_surface->stride; -} diff --git a/src/cairo-thread-local-private.h b/src/cairo-thread-local-private.h deleted file mode 100755 index 994c049c7..000000000 --- a/src/cairo-thread-local-private.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright © 2012 SCore Corporation - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - * Author: Taekyun Kim (podain77@gmail.com) - */ - -#ifndef CAIRO_THREAD_LOCAL_PRIVATE_H -#define CAIRO_THREAD_LOCAL_PRIVATE_H - -#if CAIRO_HAS_TLS || CAIRO_HAS_PTHREAD_SETSPECIFIC -#define CAIRO_HAS_THREAD_LOCAL 1 -#endif - -#if CAIRO_HAS_THREAD_LOCAL -#if defined(TLS) - -# define CAIRO_DEFINE_THREAD_LOCAL(type, name) \ - static TLS type name - -# define CAIRO_GET_THREAD_LOCAL(name) \ - (&name) - -#elif defined(__MINGW32__) - -# define _NO_W32_PSEUDO_MODIFIERS -# include <windows.h> - -# define CAIRO_DEFINE_THREAD_LOCAL(type, name) \ - static volatile int tls_ ## name ## _initialized = 0; \ - static void *tls_ ## name ## _mutex = NULL; \ - static unsigned tls_ ## name ## _index; \ - \ - static type * \ - tls_ ## name ## _alloc (void) \ - { \ - type *value = calloc (1, sizeof (type)); \ - if (value) \ - TlsSetValue (tls_ ## name ## _index, value); \ - return value; \ - } \ - \ - static inline type * \ - tls_ ## name ## _get (void) \ - { \ - type *value; \ - if (!tls_ ## name ## _initialized) \ - { \ - if (!tls_ ## name ## _mutex) \ - { \ - void *mutex = CreateMutexA (NULL, 0, NULL); \ - if (InterlockedCompareExchangePointer ( \ - &tls_ ## name ## _mutex, mutex, NULL) != NULL) \ - { \ - CloseHandle (mutex); \ - } \ - } \ - WaitForSingleObject (tls_ ## name ## _mutex, 0xFFFFFFFF); \ - if (!tls_ ## name ## _initialized) \ - { \ - tls_ ## name ## _index = TlsAlloc (); \ - tls_ ## name ## _initialized = 1; \ - } \ - ReleaseMutex (tls_ ## name ## _mutex); \ - } \ - if (tls_ ## name ## _index == 0xFFFFFFFF) \ - return NULL; \ - value = TlsGetValue (tls_ ## name ## _index); \ - if (!value) \ - value = tls_ ## name ## _alloc (); \ - return value; \ - } - -# define CAIRO_GET_THREAD_LOCAL(name) \ - tls_ ## name ## _get () - -#elif defined(_MSC_VER) - -# define CAIRO_DEFINE_THREAD_LOCAL(type, name) \ - static __declspec(thread) type name - -# define CAIRO_GET_THREAD_LOCAL(name) \ - (&name) - -#elif defined(CAIRO_HAS_PTHREAD_SETSPECIFIC) - -#include <pthread.h> - -# define CAIRO_DEFINE_THREAD_LOCAL(type, name) \ - static pthread_once_t tls_ ## name ## _once_control = PTHREAD_ONCE_INIT; \ - static pthread_key_t tls_ ## name ## _key; \ - \ - static void \ - tls_ ## name ## _destroy_value (void *value) \ - { \ - free (value); \ - } \ - \ - static void \ - tls_ ## name ## _make_key (void) \ - { \ - pthread_key_create (&tls_ ## name ## _key, \ - tls_ ## name ## _destroy_value); \ - } \ - \ - static type * \ - tls_ ## name ## _alloc (void) \ - { \ - type *value = calloc (1, sizeof (type)); \ - if (value) \ - pthread_setspecific (tls_ ## name ## _key, value); \ - return value; \ - } \ - \ - static inline type * \ - tls_ ## name ## _get (void) \ - { \ - type *value = NULL; \ - if (pthread_once (&tls_ ## name ## _once_control, \ - tls_ ## name ## _make_key) == 0) \ - { \ - value = pthread_getspecific (tls_ ## name ## _key); \ - if (!value) \ - value = tls_ ## name ## _alloc (); \ - } \ - return value; \ - } - -# define CAIRO_GET_THREAD_LOCAL(name) \ - tls_ ## name ## _get () - -#else - -# error "Unknown thread local support for this system." - -#endif -#endif /* CAIRO_HAS_THREAD_LOCAL */ - -#endif /* CAIRO_THREAD_LOCAL_PRIVATE_H */ diff --git a/src/cairo-time-private.h b/src/cairo-time-private.h index 06dc912b4..06dc912b4 100755..100644 --- a/src/cairo-time-private.h +++ b/src/cairo-time-private.h diff --git a/src/cairo-time.c b/src/cairo-time.c index a0003fbfc..a0003fbfc 100755..100644 --- a/src/cairo-time.c +++ b/src/cairo-time.c diff --git a/src/cairo-tor-scan-converter.c b/src/cairo-tor-scan-converter.c index 89ef20f09..b1b51872b 100755..100644 --- a/src/cairo-tor-scan-converter.c +++ b/src/cairo-tor-scan-converter.c @@ -262,7 +262,7 @@ typedef int grid_scaled_y_t; struct quorem { int32_t quo; - int32_t rem; + int64_t rem; }; /* Header for a chunk of memory in a memory pool. */ @@ -277,9 +277,14 @@ struct _pool_chunk { * chunk in the pool header. */ struct _pool_chunk *prev_chunk; - /* Actual data starts here. Well aligned for pointers. */ + /* Actual data starts here. Well aligned even for 64 bit types. */ + int64_t data; }; +/* The int64_t data member of _pool_chunk just exists to enforce alignment, + * it shouldn't be included in the allocated size for the struct. */ +#define SIZEOF_POOL_CHUNK (sizeof(struct _pool_chunk) - sizeof(int64_t)) + /* A memory pool. This is supposed to be embedded on the stack or * within some other structure. It may optionally be followed by an * embedded array from which requests are fulfilled until @@ -299,8 +304,11 @@ struct pool { /* Header for the sentinel chunk. Directly following the pool * struct should be some space for embedded elements from which - * the sentinel chunk allocates from. */ - struct _pool_chunk sentinel[1]; + * the sentinel chunk allocates from. This is expressed as a char + * array so that the 'int64_t data' member of _pool_chunk isn't + * included. This way embedding struct pool in other structs works + * without wasting space. */ + char sentinel[SIZEOF_POOL_CHUNK]; }; /* A polygon edge. */ @@ -308,6 +316,9 @@ struct edge { /* Next in y-bucket or active list. */ struct edge *next, *prev; + /* The clipped y of the top of the edge. */ + grid_scaled_y_t ytop; + /* Number of subsample rows remaining to scan convert of this * edge. */ grid_scaled_y_t height_left; @@ -315,7 +326,7 @@ struct edge { /* Original sign of the edge: +1 for downwards, -1 for upwards * edges. */ int dir; - int vertical; + int cell; /* Current x coordinate while the edge is on the active * list. Initialised to the x coordinate of the top of the @@ -332,11 +343,8 @@ struct edge { * full row's worth of subsample rows at a time. */ struct quorem dxdy_full; - /* The clipped y of the top of the edge. */ - grid_scaled_y_t ytop; - /* y2-y1 after orienting the edge downwards. */ - grid_scaled_y_t dy; + int64_t dy; }; #define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/GRID_Y) @@ -458,37 +466,6 @@ struct glitter_scan_converter { grid_scaled_y_t ymin, ymax; }; -/* Compute the floored division a/b. Assumes / and % perform symmetric - * division. */ -inline static struct quorem -floored_divrem(int a, int b) -{ - struct quorem qr; - qr.quo = a/b; - qr.rem = a%b; - if ((a^b)<0 && qr.rem) { - qr.quo -= 1; - qr.rem += b; - } - return qr; -} - -/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric - * division. */ -static struct quorem -floored_muldivrem(int x, int a, int b) -{ - struct quorem qr; - long long xa = (long long)x*a; - qr.quo = xa/b; - qr.rem = xa%b; - if ((xa>=0) != (b>=0) && qr.rem) { - qr.quo -= 1; - qr.rem += b; - } - return qr; -} - static struct _pool_chunk * _pool_chunk_init( struct _pool_chunk *p, @@ -506,7 +483,7 @@ _pool_chunk_create(struct pool *pool, size_t size) { struct _pool_chunk *p; - p = malloc(size + sizeof(struct _pool_chunk)); + p = malloc(SIZEOF_POOL_CHUNK + size); if (unlikely (NULL == p)) longjmp (*pool->jmp, _cairo_error (CAIRO_STATUS_NO_MEMORY)); @@ -520,10 +497,10 @@ pool_init(struct pool *pool, size_t embedded_capacity) { pool->jmp = jmp; - pool->current = pool->sentinel; + pool->current = (void*) pool->sentinel; pool->first_free = NULL; pool->default_capacity = default_capacity; - _pool_chunk_init(pool->sentinel, NULL, embedded_capacity); + _pool_chunk_init(pool->current, NULL, embedded_capacity); } static void @@ -533,7 +510,7 @@ pool_fini(struct pool *pool) do { while (NULL != p) { struct _pool_chunk *prev = p->prev_chunk; - if (p != pool->sentinel) + if (p != (void *) pool->sentinel) free(p); p = prev; } @@ -573,14 +550,14 @@ _pool_alloc_from_new_chunk( chunk = _pool_chunk_create (pool, capacity); pool->current = chunk; - obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size); + obj = ((unsigned char*)&chunk->data + chunk->size); chunk->size += size; return obj; } /* Allocate size bytes from the pool. The first allocated address - * returned from a pool is aligned to sizeof(void*). Subsequent - * addresses will maintain alignment as long as multiples of void* are + * returned from a pool is aligned to 8 bytes. Subsequent + * addresses will maintain alignment as long as multiples of 8 are * allocated. Returns the address of a new memory area or %NULL on * allocation failures. The pool retains ownership of the returned * memory. */ @@ -590,7 +567,7 @@ pool_alloc (struct pool *pool, size_t size) struct _pool_chunk *chunk = pool->current; if (size <= chunk->capacity - chunk->size) { - void *obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size); + void *obj = ((unsigned char*)&chunk->data + chunk->size); chunk->size += size; return obj; } else { @@ -604,16 +581,16 @@ pool_reset (struct pool *pool) { /* Transfer all used chunks to the chunk free list. */ struct _pool_chunk *chunk = pool->current; - if (chunk != pool->sentinel) { - while (chunk->prev_chunk != pool->sentinel) { + if (chunk != (void *) pool->sentinel) { + while (chunk->prev_chunk != (void *) pool->sentinel) { chunk = chunk->prev_chunk; } chunk->prev_chunk = pool->first_free; pool->first_free = pool->current; } /* Reset the sentinel as the current chunk. */ - pool->current = pool->sentinel; - pool->sentinel->size = 0; + pool->current = (void *) pool->sentinel; + pool->current->size = 0; } /* Rewinds the cell list's cursor to the beginning. After rewinding @@ -778,6 +755,25 @@ cell_list_add_subspan(struct cell_list *cells, } } +inline static void full_step (struct edge *e) +{ + if (e->dy == 0) + return; + + e->x.quo += e->dxdy_full.quo; + e->x.rem += e->dxdy_full.rem; + if (e->x.rem < 0) { + e->x.quo--; + e->x.rem += e->dy; + } else if (e->x.rem >= e->dy) { + ++e->x.quo; + e->x.rem -= e->dy; + } + + e->cell = e->x.quo + (e->x.rem >= e->dy/2); +} + + /* Adds the analytical coverage of an edge crossing the current pixel * row to the coverage cells and advances the edge's x position to the * following row. @@ -800,28 +796,42 @@ cell_list_render_edge(struct cell_list *cells, struct edge *edge, int sign) { - grid_scaled_y_t y1, y2, dy; - grid_scaled_x_t dx; - int ix1, ix2; + struct quorem x1, x2; grid_scaled_x_t fx1, fx2; + int ix1, ix2; - struct quorem x1 = edge->x; - struct quorem x2 = x1; + x1 = edge->x; + full_step (edge); + x2 = edge->x; + + /* Step back from the sample location (half-subrow) to the pixel origin */ + if (edge->dy) { + x1.quo -= edge->dxdy.quo / 2; + x1.rem -= edge->dxdy.rem / 2; + if (x1.rem < 0) { + --x1.quo; + x1.rem += edge->dy; + } else if (x1.rem >= edge->dy) { + ++x1.quo; + x1.rem -= edge->dy; + } - if (! edge->vertical) { - x2.quo += edge->dxdy_full.quo; - x2.rem += edge->dxdy_full.rem; - if (x2.rem >= 0) { + x2.quo -= edge->dxdy.quo / 2; + x2.rem -= edge->dxdy.rem / 2; + if (x2.rem < 0) { + --x2.quo; + x2.rem += edge->dy; + } else if (x2.rem >= edge->dy) { ++x2.quo; x2.rem -= edge->dy; } - - edge->x = x2; } GRID_X_TO_INT_FRAC(x1.quo, ix1, fx1); GRID_X_TO_INT_FRAC(x2.quo, ix2, fx2); + cell_list_maybe_rewind(cells, MIN(ix1, ix2)); + /* Edge is entirely within a column? */ if (ix1 == ix2) { /* We always know that ix1 is >= the cell list cursor in this @@ -833,26 +843,39 @@ cell_list_render_edge(struct cell_list *cells, } /* Orient the edge left-to-right. */ - dx = x2.quo - x1.quo; - if (dx >= 0) { - y1 = 0; - y2 = GRID_Y; - } else { - int tmp; - tmp = ix1; ix1 = ix2; ix2 = tmp; - tmp = fx1; fx1 = fx2; fx2 = tmp; - dx = -dx; - sign = -sign; - y1 = GRID_Y; - y2 = 0; + if (ix2 < ix1) { + struct quorem tx; + int t; + + t = ix1; + ix1 = ix2; + ix2 = t; + + t = fx1; + fx1 = fx2; + fx2 = t; + + tx = x1; + x1 = x2; + x2 = tx; } - dy = y2 - y1; /* Add coverage for all pixels [ix1,ix2] on this row crossed * by the edge. */ { struct cell_pair pair; - struct quorem y = floored_divrem((GRID_X - fx1)*dy, dx); + struct quorem y; + int64_t tmp, dx; + int y_last; + + dx = (x2.quo - x1.quo) * edge->dy + (x2.rem - x1.rem); + + tmp = (ix1 + 1) * GRID_X * edge->dy; + tmp -= x1.quo * edge->dy + x1.rem; + tmp *= GRID_Y; + + y.quo = tmp / dx; + y.rem = tmp % dx; /* When rendering a previous edge on the active list we may * advance the cell list cursor past the leftmost pixel of the @@ -868,35 +891,32 @@ cell_list_render_edge(struct cell_list *cells, * * The left edge touches cells past the starting cell of the * right edge. Fortunately such cases are rare. - * - * The rewinding is never necessary if the current edge stays - * within a single column because we've checked before calling - * this function that the active list order won't change. */ - cell_list_maybe_rewind(cells, ix1); + */ pair = cell_list_find_pair(cells, ix1, ix1+1); pair.cell1->uncovered_area += sign*y.quo*(GRID_X + fx1); pair.cell1->covered_height += sign*y.quo; - y.quo += y1; + y_last = y.quo; if (ix1+1 < ix2) { - struct quorem dydx_full = floored_divrem(GRID_X*dy, dx); struct cell *cell = pair.cell2; + struct quorem dydx_full; + + dydx_full.quo = GRID_Y * GRID_X * edge->dy / dx; + dydx_full.rem = GRID_Y * GRID_X * edge->dy % dx; ++ix1; do { - grid_scaled_y_t y_skip = dydx_full.quo; + y.quo += dydx_full.quo; y.rem += dydx_full.rem; if (y.rem >= dx) { - ++y_skip; + y.quo++; y.rem -= dx; } - y.quo += y_skip; - - y_skip *= sign; - cell->uncovered_area += y_skip*GRID_X; - cell->covered_height += y_skip; + cell->uncovered_area += sign*(y.quo - y_last)*GRID_X; + cell->covered_height += sign*(y.quo - y_last); + y_last = y.quo; ++ix1; cell = cell_list_find(cells, ix1); @@ -904,8 +924,8 @@ cell_list_render_edge(struct cell_list *cells, pair.cell2 = cell; } - pair.cell2->uncovered_area += sign*(y2 - y.quo)*fx2; - pair.cell2->covered_height += sign*(y2 - y.quo); + pair.cell2->uncovered_area += sign*(GRID_Y - y_last)*fx2; + pair.cell2->covered_height += sign*(GRID_Y - y_last); } } @@ -976,78 +996,19 @@ _polygon_insert_edge_into_its_y_bucket(struct polygon *polygon, *ptail = e; } -inline static void -polygon_add_edge (struct polygon *polygon, - const cairo_edge_t *edge) -{ - struct edge *e; - grid_scaled_x_t dx; - grid_scaled_y_t dy; - grid_scaled_y_t ytop, ybot; - grid_scaled_y_t ymin = polygon->ymin; - grid_scaled_y_t ymax = polygon->ymax; - - if (unlikely (edge->top >= ymax || edge->bottom <= ymin)) - return; - - e = pool_alloc (polygon->edge_pool.base, sizeof (struct edge)); - - dx = edge->line.p2.x - edge->line.p1.x; - dy = edge->line.p2.y - edge->line.p1.y; - e->dy = dy; - e->dir = edge->dir; - - ytop = edge->top >= ymin ? edge->top : ymin; - ybot = edge->bottom <= ymax ? edge->bottom : ymax; - e->ytop = ytop; - e->height_left = ybot - ytop; - - if (dx == 0) { - e->vertical = TRUE; - e->x.quo = edge->line.p1.x; - e->x.rem = 0; - e->dxdy.quo = 0; - e->dxdy.rem = 0; - e->dxdy_full.quo = 0; - e->dxdy_full.rem = 0; - } else { - e->vertical = FALSE; - e->dxdy = floored_divrem (dx, dy); - if (ytop == edge->line.p1.y) { - e->x.quo = edge->line.p1.x; - e->x.rem = 0; - } else { - e->x = floored_muldivrem (ytop - edge->line.p1.y, dx, dy); - e->x.quo += edge->line.p1.x; - } - - if (e->height_left >= GRID_Y) { - e->dxdy_full = floored_muldivrem (GRID_Y, dx, dy); - } else { - e->dxdy_full.quo = 0; - e->dxdy_full.rem = 0; - } - } - - _polygon_insert_edge_into_its_y_bucket (polygon, e); - - e->x.rem -= dy; /* Bias the remainder for faster - * edge advancement. */ -} - static void active_list_reset (struct active_list *active) { - active->head.vertical = 1; active->head.height_left = INT_MAX; - active->head.x.quo = INT_MIN; + active->head.dy = 0; + active->head.cell = INT_MIN; active->head.prev = NULL; active->head.next = &active->tail; active->tail.prev = &active->head; active->tail.next = NULL; - active->tail.x.quo = INT_MAX; + active->tail.cell = INT_MAX; active->tail.height_left = INT_MAX; - active->tail.vertical = 1; + active->tail.dy = 0; active->min_height = 0; active->is_vertical = 1; } @@ -1084,7 +1045,7 @@ merge_sorted_edges (struct edge *head_a, struct edge *head_b) prev = head_a->prev; next = &head; - if (head_a->x.quo <= head_b->x.quo) { + if (head_a->cell <= head_b->cell) { head = head_a; } else { head = head_b; @@ -1093,8 +1054,8 @@ merge_sorted_edges (struct edge *head_a, struct edge *head_b) } do { - x = head_b->x.quo; - while (head_a != NULL && head_a->x.quo <= x) { + x = head_b->cell; + while (head_a != NULL && head_a->cell <= x) { prev = head_a; next = &head_a->next; head_a = head_a->next; @@ -1106,8 +1067,8 @@ merge_sorted_edges (struct edge *head_a, struct edge *head_b) return head; start_with_b: - x = head_a->x.quo; - while (head_b != NULL && head_b->x.quo <= x) { + x = head_a->cell; + while (head_b != NULL && head_b->cell <= x) { prev = head_b; next = &head_b->next; head_b = head_b->next; @@ -1153,7 +1114,7 @@ sort_edges (struct edge *list, } remaining = head_other->next; - if (list->x.quo <= head_other->x.quo) { + if (list->cell <= head_other->cell) { *head_out = list; head_other->next = NULL; } else { @@ -1197,7 +1158,7 @@ can_do_full_row (struct active_list *active) while (NULL != e) { if (e->height_left < min_height) min_height = e->height_left; - is_vertical &= e->vertical; + is_vertical &= e->dy == 0; e = e->next; } @@ -1210,19 +1171,27 @@ can_do_full_row (struct active_list *active) /* Check for intersections as no edges end during the next row. */ for (e = active->head.next; e != &active->tail; e = e->next) { - struct quorem x = e->x; + int cell; - if (! e->vertical) { + if (e->dy) { + struct quorem x = e->x; x.quo += e->dxdy_full.quo; x.rem += e->dxdy_full.rem; - if (x.rem >= 0) - ++x.quo; - } + if (x.rem < 0) { + x.quo--; + x.rem += e->dy; + } else if (x.rem >= e->dy) { + x.quo++; + x.rem -= e->dy; + } + cell = x.quo + (x.rem >= e->dy/2); + } else + cell = e->cell; - if (x.quo < prev_x) + if (cell < prev_x) return 0; - prev_x = x.quo; + prev_x = cell; } return 1; @@ -1237,7 +1206,7 @@ active_list_merge_edges_from_bucket(struct active_list *active, active->head.next = merge_unsorted_edges (active->head.next, edges); } -inline static void +inline static int polygon_fill_buckets (struct active_list *active, struct edge *edge, int y, @@ -1245,6 +1214,7 @@ polygon_fill_buckets (struct active_list *active, { grid_scaled_y_t min_height = active->min_height; int is_vertical = active->is_vertical; + int max_suby = 0; while (edge) { struct edge *next = edge->next; @@ -1256,12 +1226,34 @@ polygon_fill_buckets (struct active_list *active, buckets[suby] = edge; if (edge->height_left < min_height) min_height = edge->height_left; - is_vertical &= edge->vertical; + is_vertical &= edge->dy == 0; edge = next; + if (suby > max_suby) + max_suby = suby; } active->is_vertical = is_vertical; active->min_height = min_height; + + return max_suby; +} + +static void step (struct edge *edge) +{ + if (edge->dy == 0) + return; + + edge->x.quo += edge->dxdy.quo; + edge->x.rem += edge->dxdy.rem; + if (edge->x.rem < 0) { + --edge->x.quo; + edge->x.rem += edge->dy; + } else if (edge->x.rem >= edge->dy) { + ++edge->x.quo; + edge->x.rem -= edge->dy; + } + + edge->cell = edge->x.quo + (edge->x.rem >= edge->dy/2); } inline static void @@ -1277,29 +1269,24 @@ sub_row (struct active_list *active, while (&active->tail != edge) { struct edge *next = edge->next; - int xend = edge->x.quo; + int xend = edge->cell; if (--edge->height_left) { - edge->x.quo += edge->dxdy.quo; - edge->x.rem += edge->dxdy.rem; - if (edge->x.rem >= 0) { - ++edge->x.quo; - edge->x.rem -= edge->dy; - } + step (edge); - if (edge->x.quo < prev_x) { + if (edge->cell < prev_x) { struct edge *pos = edge->prev; pos->next = next; next->prev = pos; do { pos = pos->prev; - } while (edge->x.quo < pos->x.quo); + } while (edge->cell < pos->cell); pos->next->prev = edge; edge->next = pos->next; edge->prev = pos; pos->next = edge; } else - prev_x = edge->x.quo; + prev_x = edge->cell; active->min_height = -1; } else { edge->prev->next = next; @@ -1308,7 +1295,7 @@ sub_row (struct active_list *active, winding += edge->dir; if ((winding & mask) == 0) { - if (next->x.quo != xend) { + if (next->cell != xend) { cell_list_add_subspan (coverages, xstart, xend); xstart = INT_MIN; } @@ -1329,18 +1316,6 @@ inline static void dec (struct active_list *a, struct edge *e, int h) } } -inline static void full_step (struct edge *e) -{ - if (! e->vertical) { - e->x.quo += e->dxdy_full.quo; - e->x.rem += e->dxdy_full.rem; - if (e->x.rem >= 0) { - ++e->x.quo; - e->x.rem -= e->dy; - } - } -} - static void full_row (struct active_list *active, struct cell_list *coverages, @@ -1360,7 +1335,7 @@ full_row (struct active_list *active, dec (active, right, GRID_Y); winding += right->dir; - if ((winding & mask) == 0 && right->next->x.quo != right->x.quo) + if ((winding & mask) == 0 && right->next->cell != right->cell) break; full_step (right); @@ -1482,10 +1457,96 @@ glitter_scan_converter_reset( #define INPUT_TO_GRID_general(in, out, grid_scale) do { \ long long tmp__ = (long long)(grid_scale) * (in); \ + tmp__ += 1 << (GLITTER_INPUT_BITS-1); \ tmp__ >>= GLITTER_INPUT_BITS; \ (out) = tmp__; \ } while (0) +inline static void +polygon_add_edge (struct polygon *polygon, + const cairo_edge_t *edge) +{ + struct edge *e; + grid_scaled_y_t ytop, ybot; + const cairo_point_t *p1, *p2; + + INPUT_TO_GRID_Y (edge->top, ytop); + if (ytop < polygon->ymin) + ytop = polygon->ymin; + + INPUT_TO_GRID_Y (edge->bottom, ybot); + if (ybot > polygon->ymax) + ybot = polygon->ymax; + + if (ybot <= ytop) + return; + + e = pool_alloc (polygon->edge_pool.base, sizeof (struct edge)); + + e->ytop = ytop; + e->height_left = ybot - ytop; + if (edge->line.p2.y > edge->line.p1.y) { + e->dir = edge->dir; + p1 = &edge->line.p1; + p2 = &edge->line.p2; + } else { + e->dir = -edge->dir; + p1 = &edge->line.p2; + p2 = &edge->line.p1; + } + + if (p2->x == p1->x) { + e->cell = p1->x; + e->x.quo = p1->x; + e->x.rem = 0; + e->dxdy.quo = e->dxdy.rem = 0; + e->dxdy_full.quo = e->dxdy_full.rem = 0; + e->dy = 0; + } else { + int64_t Ex, Ey, tmp; + + Ex = (int64_t)(p2->x - p1->x) * GRID_X; + Ey = (int64_t)(p2->y - p1->y) * GRID_Y * (2 << GLITTER_INPUT_BITS); + + e->dxdy.quo = Ex * (2 << GLITTER_INPUT_BITS) / Ey; + e->dxdy.rem = Ex * (2 << GLITTER_INPUT_BITS) % Ey; + + tmp = (int64_t)(2*ytop + 1) << GLITTER_INPUT_BITS; + tmp -= (int64_t)p1->y * GRID_Y * 2; + tmp *= Ex; + e->x.quo = tmp / Ey; + e->x.rem = tmp % Ey; + +#if GRID_X_BITS == GLITTER_INPUT_BITS + e->x.quo += p1->x; +#else + tmp = (int64_t)p1->x * GRID_X; + e->x.quo += tmp >> GLITTER_INPUT_BITS; + e->x.rem += ((tmp & ((1 << GLITTER_INPUT_BITS) - 1)) * Ey) / (1 << GLITTER_INPUT_BITS); +#endif + + if (e->x.rem < 0) { + e->x.quo--; + e->x.rem += Ey; + } else if (e->x.rem >= Ey) { + e->x.quo++; + e->x.rem -= Ey; + } + + if (e->height_left >= GRID_Y) { + tmp = Ex * (2 * GRID_Y << GLITTER_INPUT_BITS); + e->dxdy_full.quo = tmp / Ey; + e->dxdy_full.rem = tmp % Ey; + } else + e->dxdy_full.quo = e->dxdy_full.rem = 0; + + e->cell = e->x.quo + (e->x.rem >= Ey/2); + e->dy = Ey; + } + + _polygon_insert_edge_into_its_y_bucket (polygon, e); +} + /* Add a new polygon edge from pixel (x1,y1) to (x2,y2) to the scan * converter. The coordinates represent pixel positions scaled by * 2**GLITTER_PIXEL_BITS. If this function fails then the scan @@ -1495,25 +1556,7 @@ I void glitter_scan_converter_add_edge (glitter_scan_converter_t *converter, const cairo_edge_t *edge) { - cairo_edge_t e; - - INPUT_TO_GRID_Y (edge->top, e.top); - INPUT_TO_GRID_Y (edge->bottom, e.bottom); - if (e.top >= e.bottom) - return; - - /* XXX: possible overflows if GRID_X/Y > 2**GLITTER_INPUT_BITS */ - INPUT_TO_GRID_Y (edge->line.p1.y, e.line.p1.y); - INPUT_TO_GRID_Y (edge->line.p2.y, e.line.p2.y); - if (e.line.p1.y == e.line.p2.y) - e.line.p2.y++; /* little fudge to prevent a div-by-zero */ - - INPUT_TO_GRID_X (edge->line.p1.x, e.line.p1.x); - INPUT_TO_GRID_X (edge->line.p2.x, e.line.p2.x); - - e.dir = edge->dir; - - polygon_add_edge (converter->polygon, &e); + polygon_add_edge (converter->polygon, edge); } static void @@ -1699,7 +1742,15 @@ glitter_scan_converter_render(glitter_scan_converter_t *converter, /* Determine if we can ignore this row or use the full pixel * stepper. */ - if (! polygon->y_buckets[i]) { + if (polygon_fill_buckets (active, + polygon->y_buckets[i], + (i+ymin_i)*GRID_Y, + buckets) == 0) { + if (buckets[0]) { + active_list_merge_edges_from_bucket (active, buckets[0]); + buckets[0] = NULL; + } + if (active->head.next == &active->tail) { active->min_height = INT_MAX; active->is_vertical = 1; @@ -1729,18 +1780,12 @@ glitter_scan_converter_render(glitter_scan_converter_t *converter, } else { int sub; - polygon_fill_buckets (active, - polygon->y_buckets[i], - (i+ymin_i)*GRID_Y, - buckets); - /* Subsample this row. */ for (sub = 0; sub < GRID_Y; sub++) { if (buckets[sub]) { active_list_merge_edges_from_bucket (active, buckets[sub]); buckets[sub] = NULL; } - sub_row (active, coverages, winding_mask); } } diff --git a/src/cairo-tor22-scan-converter.c b/src/cairo-tor22-scan-converter.c index 4cec5ee4f..4cec5ee4f 100755..100644 --- a/src/cairo-tor22-scan-converter.c +++ b/src/cairo-tor22-scan-converter.c diff --git a/src/cairo-toy-font-face.c b/src/cairo-toy-font-face.c index 363b9a284..4fe94ab09 100755..100644 --- a/src/cairo-toy-font-face.c +++ b/src/cairo-toy-font-face.c @@ -342,7 +342,7 @@ cairo_toy_font_face_create (const char *family, } slim_hidden_def (cairo_toy_font_face_create); -static void +static cairo_bool_t _cairo_toy_font_face_destroy (void *abstract_face) { cairo_toy_font_face_t *font_face = abstract_face; @@ -352,10 +352,10 @@ _cairo_toy_font_face_destroy (void *abstract_face) /* All created objects must have been mapped in the hash table. */ assert (hash_table != NULL); - if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->base.ref_count)) { + if (! _cairo_reference_count_dec_and_test (&font_face->base.ref_count)) { /* somebody recreated the font whilst we waited for the lock */ _cairo_toy_font_face_hash_table_unlock (); - return; + return FALSE; } /* Font faces in SUCCESS status are guaranteed to be in the @@ -369,6 +369,7 @@ _cairo_toy_font_face_destroy (void *abstract_face) _cairo_toy_font_face_hash_table_unlock (); _cairo_toy_font_face_fini (font_face); + return TRUE; } static cairo_status_t diff --git a/src/cairo-traps-compositor.c b/src/cairo-traps-compositor.c index 5d561f2be..c26a5df6f 100755..100644 --- a/src/cairo-traps-compositor.c +++ b/src/cairo-traps-compositor.c @@ -209,18 +209,18 @@ combine_clip_as_traps (const cairo_traps_compositor_t *compositor, return src->status; } - if (draw_color_glyph) - status = compositor->composite_traps (mask, CAIRO_OPERATOR_IN, mask, - 0, 0, - extents->x, extents->y, - extents, - antialias, &traps); - else + if (draw_color_glyph) + status = compositor->composite_traps (mask, CAIRO_OPERATOR_IN, mask, + 0, 0, + extents->x, extents->y, + extents, + antialias, &traps); + else status = compositor->composite_traps (mask, CAIRO_OPERATOR_IN, src, - src_x, src_y, - extents->x, extents->y, - extents, - antialias, &traps); + src_x, src_y, + extents->x, extents->y, + extents, + antialias, &traps); _cairo_traps_extents (&traps, &box); _cairo_box_round_to_rectangle (&box, &fixup); @@ -315,10 +315,11 @@ __clip_to_surface (const cairo_traps_compositor_t *compositor, if (unlikely (status)) return status; - mask = _cairo_surface_create_similar_scratch (composite->surface, - CAIRO_CONTENT_ALPHA, - extents->width, - extents->height); + mask = _cairo_surface_create_scratch (composite->surface, + CAIRO_CONTENT_ALPHA, + extents->width, + extents->height, + NULL); if (unlikely (mask->status)) { _cairo_traps_fini (&traps); return status; @@ -379,11 +380,11 @@ traps_get_clip_surface (const cairo_traps_compositor_t *compositor, status = __clip_to_surface (compositor, composite, extents, &surface); if (status == CAIRO_INT_STATUS_UNSUPPORTED) { - surface = _cairo_surface_create_similar_solid (composite->surface, - CAIRO_CONTENT_ALPHA, - extents->width, - extents->height, - CAIRO_COLOR_WHITE); + surface = _cairo_surface_create_scratch (composite->surface, + CAIRO_CONTENT_ALPHA, + extents->width, + extents->height, + CAIRO_COLOR_WHITE); if (unlikely (surface->status)) return surface; @@ -435,21 +436,22 @@ create_composite_mask (const cairo_traps_compositor_t *compositor, cairo_surface_t *surface, *src; cairo_int_status_t status; int src_x, src_y; - cairo_bool_t draw_color_glyph = FALSE; + cairo_bool_t draw_color_glyph = FALSE; TRACE ((stderr, "%s\n", __FUNCTION__)); - surface = _cairo_surface_create_similar_scratch (dst, CAIRO_CONTENT_ALPHA, - extents->bounded.width, - extents->bounded.height); + surface = _cairo_surface_create_scratch (dst, CAIRO_CONTENT_ALPHA, + extents->bounded.width, + extents->bounded.height, + NULL); if (unlikely (surface->status)) return surface; - /* FIXME: This is more like an ugly hack and wasteful. Reason - for this code is that we don't know whether the mask surface - should alpha-only or argb32 before we render a glyph. - */ - redo: + /* FIXME: This is more like an ugly hack and wasteful. Reason + for this code is that we don't know whether the mask surface + should alpha-only or argb32 before we render a glyph. + */ +redo: src = compositor->pattern_to_surface (surface, &_cairo_pattern_white.base, FALSE, @@ -503,22 +505,22 @@ create_composite_mask (const cairo_traps_compositor_t *compositor, CAIRO_OPERATOR_ADD, src, src_x, src_y, extents->bounded.x, extents->bounded.y, &extents->bounded, NULL); - if (unlikely (status)){ - if (cairo_surface_get_content (surface) == CAIRO_CONTENT_COLOR_ALPHA) - goto error; - else { - compositor->release (surface); - cairo_surface_destroy (surface); - cairo_surface_destroy (src); - surface = _cairo_surface_create_similar_scratch (dst, CAIRO_CONTENT_COLOR_ALPHA, - extents->bounded.width, - extents->bounded.height); - if (unlikely (surface->status)) - return surface; - /* we are drawing color glyph */ - draw_color_glyph = TRUE; - goto redo; - } + if (unlikely (status)) { + if (cairo_surface_get_content (surface) == CAIRO_CONTENT_COLOR_ALPHA) + goto error; + else { + compositor->release (surface); + cairo_surface_destroy (surface); + cairo_surface_destroy (src); + surface = _cairo_surface_create_similar_scratch (dst, CAIRO_CONTENT_COLOR_ALPHA, + extents->bounded.width, + extents->bounded.height); + if (unlikely (surface->status)) + return surface; + /* we are drawing color glyph */ + draw_color_glyph = TRUE; + goto redo; + } } surface->is_clear = FALSE; @@ -582,30 +584,31 @@ clip_and_composite_with_mask (const cairo_traps_compositor_t *compositor, if (mask->is_clear) goto skip; - if (mask->content == CAIRO_CONTENT_ALPHA) { - /* This is real mask */ - if (src != NULL || dst->content != CAIRO_CONTENT_ALPHA) { - compositor->composite (dst, op, src, mask, - extents->bounded.x + src_x, - extents->bounded.y + src_y, - 0, 0, - extents->bounded.x, extents->bounded.y, - extents->bounded.width, extents->bounded.height); - } else { - compositor->composite (dst, op, mask, NULL, - 0, 0, - 0, 0, - extents->bounded.x, extents->bounded.y, - extents->bounded.width, extents->bounded.height); - } + if (mask->content == CAIRO_CONTENT_ALPHA) { + /* This is real mask */ + if (src != NULL || dst->content != CAIRO_CONTENT_ALPHA) { + compositor->composite (dst, op, src, mask, + extents->bounded.x + src_x, + extents->bounded.y + src_y, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); } else { - compositor->composite (dst, op, mask, NULL, - 0, 0, - extents->bounded.x + src_x, - extents->bounded.y + src_y, - extents->bounded.x, extents->bounded.y, - extents->bounded.width, extents->bounded.height); + compositor->composite (dst, op, mask, NULL, + 0, 0, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); } + } + else { + compositor->composite (dst, op, mask, NULL, + 0, 0, + extents->bounded.x + src_x, + extents->bounded.y + src_y, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + } skip: cairo_surface_destroy (mask); return CAIRO_STATUS_SUCCESS; @@ -629,9 +632,10 @@ clip_and_composite_combine (const cairo_traps_compositor_t *compositor, TRACE ((stderr, "%s\n", __FUNCTION__)); - tmp = _cairo_surface_create_similar_scratch (dst, dst->content, - extents->bounded.width, - extents->bounded.height); + tmp = _cairo_surface_create_scratch (dst, dst->content, + extents->bounded.width, + extents->bounded.height, + NULL); if (unlikely (tmp->status)) { status = tmp->status; cairo_surface_destroy (tmp); @@ -701,15 +705,15 @@ clip_and_composite_source (const cairo_traps_compositor_t *compositor, const cairo_composite_rectangles_t *extents) { cairo_surface_t *mask = NULL; - /* create a white color pattern */ - cairo_pattern_t *white_pattern = _cairo_pattern_create_solid (CAIRO_COLOR_WHITE); - cairo_surface_t *white_mask = - compositor->pattern_to_surface (dst, white_pattern, TRUE, - &extents->bounded, - &extents->source_sample_area, - &src_x, &src_y); - if (unlikely (white_mask->status)) - goto skip; + /* create a white color pattern */ + cairo_pattern_t *white_pattern = _cairo_pattern_create_solid (CAIRO_COLOR_WHITE); + cairo_surface_t *white_mask = + compositor->pattern_to_surface (dst, white_pattern, TRUE, + &extents->bounded, + &extents->source_sample_area, + &src_x, &src_y); + if (unlikely (white_mask->status)) + goto skip; TRACE ((stderr, "%s\n", __FUNCTION__)); @@ -731,22 +735,22 @@ clip_and_composite_source (const cairo_traps_compositor_t *compositor, extents->bounded.width, extents->bounded.height); } else { if (mask->content == CAIRO_CONTENT_ALPHA) - compositor->lerp (dst, src, mask, - extents->bounded.x + src_x, extents->bounded.y + src_y, + compositor->lerp (dst, src, mask, + extents->bounded.x + src_x, extents->bounded.y + src_y, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + else + compositor->lerp_color_glyph (dst, mask, white_mask, 0, 0, + extents->bounded.x + src_x, extents->bounded.y + src_y, extents->bounded.x, extents->bounded.y, extents->bounded.width, extents->bounded.height); - else - compositor->lerp_color_glyph (dst, mask, white_mask, - 0, 0, - extents->bounded.x + src_x, extents->bounded.y + src_y, - extents->bounded.x, extents->bounded.y, - extents->bounded.width, extents->bounded.height); - } + } skip: cairo_surface_destroy (mask); - cairo_surface_destroy (white_mask); + cairo_surface_destroy (white_mask); cairo_pattern_destroy (white_pattern); return CAIRO_STATUS_SUCCESS; @@ -988,12 +992,20 @@ need_bounded_clip (cairo_composite_rectangles_t *extents) { unsigned int flags = 0; - if (extents->unbounded.width < extents->destination.width || - extents->unbounded.height < extents->destination.height) + if (extents->clip->num_boxes > 1 || + extents->mask.width > extents->unbounded.width || + extents->mask.height > extents->unbounded.height) { flags |= NEED_CLIP_REGION; } + if (extents->clip->num_boxes > 1 || + extents->mask.width > extents->bounded.width || + extents->mask.height > extents->bounded.height) + { + flags |= FORCE_CLIP_REGION; + } + if (! _cairo_clip_is_region (extents->clip)) flags |= NEED_CLIP_SURFACE; @@ -1258,7 +1270,9 @@ composite_aligned_boxes (const cairo_traps_compositor_t *compositor, &extents->source_sample_area)) { cairo_clip_t *recording_clip; - cairo_pattern_t *source = &extents->source_pattern.base; + const cairo_pattern_t *source = &extents->source_pattern.base; + const cairo_matrix_t *m; + cairo_matrix_t matrix; /* XXX could also do tiling repeat modes... */ @@ -1277,10 +1291,17 @@ composite_aligned_boxes (const cairo_traps_compositor_t *compositor, return status; } + m = &source->matrix; + if (_cairo_surface_has_device_transform (dst)) { + cairo_matrix_multiply (&matrix, + &source->matrix, + &dst->device_transform); + m = &matrix; + } + recording_clip = _cairo_clip_from_boxes (boxes); status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (source), - &source->matrix, - dst, recording_clip); + m, dst, recording_clip); _cairo_clip_destroy (recording_clip); return status; @@ -1433,7 +1454,7 @@ boxes_for_traps (cairo_boxes_t *boxes, cairo_traps_t *traps, cairo_antialias_t antialias) { - int i; + int i, j; /* first check that the traps are rectilinear */ if (antialias == CAIRO_ANTIALIAS_NONE) { @@ -1457,23 +1478,25 @@ boxes_for_traps (cairo_boxes_t *boxes, _cairo_boxes_init (boxes); - boxes->num_boxes = traps->num_traps; boxes->chunks.base = (cairo_box_t *) traps->traps; - boxes->chunks.count = traps->num_traps; boxes->chunks.size = traps->num_traps; if (antialias != CAIRO_ANTIALIAS_NONE) { - for (i = 0; i < traps->num_traps; i++) { + for (i = j = 0; i < traps->num_traps; i++) { /* Note the traps and boxes alias so we need to take the local copies first. */ cairo_fixed_t x1 = traps->traps[i].left.p1.x; cairo_fixed_t x2 = traps->traps[i].right.p1.x; cairo_fixed_t y1 = traps->traps[i].top; cairo_fixed_t y2 = traps->traps[i].bottom; - boxes->chunks.base[i].p1.x = x1; - boxes->chunks.base[i].p1.y = y1; - boxes->chunks.base[i].p2.x = x2; - boxes->chunks.base[i].p2.y = y2; + if (x1 == x2 || y1 == y2) + continue; + + boxes->chunks.base[j].p1.x = x1; + boxes->chunks.base[j].p1.y = y1; + boxes->chunks.base[j].p2.x = x2; + boxes->chunks.base[j].p2.y = y2; + j++; if (boxes->is_pixel_aligned) { boxes->is_pixel_aligned = @@ -1484,7 +1507,7 @@ boxes_for_traps (cairo_boxes_t *boxes, } else { boxes->is_pixel_aligned = TRUE; - for (i = 0; i < traps->num_traps; i++) { + for (i = j = 0; i < traps->num_traps; i++) { /* Note the traps and boxes alias so we need to take the local copies first. */ cairo_fixed_t x1 = traps->traps[i].left.p1.x; cairo_fixed_t x2 = traps->traps[i].right.p1.x; @@ -1492,12 +1515,16 @@ boxes_for_traps (cairo_boxes_t *boxes, cairo_fixed_t y2 = traps->traps[i].bottom; /* round down here to match Pixman's behavior when using traps. */ - boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1); - boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1); - boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2); - boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2); + boxes->chunks.base[j].p1.x = _cairo_fixed_round_down (x1); + boxes->chunks.base[j].p1.y = _cairo_fixed_round_down (y1); + boxes->chunks.base[j].p2.x = _cairo_fixed_round_down (x2); + boxes->chunks.base[j].p2.y = _cairo_fixed_round_down (y2); + j += (boxes->chunks.base[j].p1.x != boxes->chunks.base[j].p2.x && + boxes->chunks.base[j].p1.y != boxes->chunks.base[j].p2.y); } } + boxes->chunks.count = j; + boxes->num_boxes = j; return CAIRO_INT_STATUS_SUCCESS; } @@ -2220,18 +2247,14 @@ _cairo_traps_compositor_stroke (const cairo_compositor_t *_compositor, double tolerance, cairo_traps_t *traps); composite_traps_info_t info; - unsigned flags = 0; + unsigned flags; if (antialias == CAIRO_ANTIALIAS_BEST || antialias == CAIRO_ANTIALIAS_GOOD) { func = _cairo_path_fixed_stroke_polygon_to_traps; + flags = 0; } else { func = _cairo_path_fixed_stroke_to_traps; - if (extents->clip->num_boxes > 1 || - extents->mask.width > extents->unbounded.width || - extents->mask.height > extents->unbounded.height) - { - flags = NEED_CLIP_REGION | FORCE_CLIP_REGION; - } + flags = need_bounded_clip (extents) & ~NEED_CLIP_SURFACE; } info.antialias = antialias; @@ -2353,16 +2376,12 @@ _cairo_traps_compositor_glyphs (const cairo_compositor_t *_compositor, if (unlikely (status)) return status; -#if ! CAIRO_HAS_TG_SURFACE _cairo_scaled_font_freeze_cache (scaled_font); -#endif - status = compositor->check_composite_glyphs (extents, scaled_font, glyphs, &num_glyphs); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { cairo_composite_glyphs_info_t info; - unsigned flags = 0; info.font = scaled_font; info.glyphs = glyphs; @@ -2370,21 +2389,11 @@ _cairo_traps_compositor_glyphs (const cairo_compositor_t *_compositor, info.use_mask = overlap || ! extents->is_bounded; info.extents = extents->bounded; - if (extents->mask.width > extents->bounded.width || - extents->mask.height > extents->bounded.height) - { - flags |= FORCE_CLIP_REGION; - } - status = clip_and_composite (compositor, extents, composite_glyphs, NULL, &info, - need_bounded_clip (extents) | - flags); + need_bounded_clip (extents) | FORCE_CLIP_REGION); } - -#if ! CAIRO_HAS_TG_SURFACE _cairo_scaled_font_thaw_cache (scaled_font); -#endif return status; } diff --git a/src/cairo-traps-private.h b/src/cairo-traps-private.h index 7fef062a4..dcaf40d18 100755..100644 --- a/src/cairo-traps-private.h +++ b/src/cairo-traps-private.h @@ -91,8 +91,9 @@ cairo_private void _cairo_traps_translate (cairo_traps_t *traps, int x, int y); cairo_private void -_cairo_traps_tessellate_triangle (cairo_traps_t *traps, - const cairo_point_t t[3]); +_cairo_traps_tessellate_triangle_with_edges (cairo_traps_t *traps, + const cairo_point_t t[3], + const cairo_point_t edges[4]); cairo_private void _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, @@ -106,7 +107,8 @@ _cairo_traps_tessellate_rectangle (cairo_traps_t *traps, cairo_private void _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom, - cairo_line_t *left, cairo_line_t *right); + const cairo_line_t *left, + const cairo_line_t *right); cairo_private int _cairo_traps_contain (const cairo_traps_t *traps, diff --git a/src/cairo-traps.c b/src/cairo-traps.c index 8bdac45ab..92abe4496 100755..100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -42,6 +42,7 @@ #include "cairo-box-inline.h" #include "cairo-boxes-private.h" #include "cairo-error-private.h" +#include "cairo-line-private.h" #include "cairo-region-private.h" #include "cairo-slope-private.h" #include "cairo-traps-private.h" @@ -150,10 +151,20 @@ _cairo_traps_grow (cairo_traps_t *traps) void _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom, - cairo_line_t *left, cairo_line_t *right) + const cairo_line_t *left, + const cairo_line_t *right) { cairo_trapezoid_t *trap; + /* These asserts cause reporting of unreal crashes + in the case of gl/msaa. + Temporarily removed */ + /* + assert (left->p1.y != left->p2.y); + assert (right->p1.y != right->p2.y); + assert (bottom > top); + */ + if (unlikely (traps->num_traps == traps->traps_size)) { if (unlikely (! _cairo_traps_grow (traps))) return; @@ -169,7 +180,8 @@ _cairo_traps_add_trap (cairo_traps_t *traps, static void _cairo_traps_add_clipped_trap (cairo_traps_t *traps, cairo_fixed_t _top, cairo_fixed_t _bottom, - cairo_line_t *_left, cairo_line_t *_right) + const cairo_line_t *_left, + const cairo_line_t *_right) { /* Note: With the goofy trapezoid specification, (where an * arbitrary two points on the lines can specified for the left @@ -387,23 +399,73 @@ _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, } } -/* A triangle is simply a degenerate case of a convex - * quadrilateral. We would not benefit from having any distinct - * implementation of triangle vs. quadrilateral tessellation here. */ -void -_cairo_traps_tessellate_triangle (cairo_traps_t *traps, - const cairo_point_t t[3]) +static void add_tri (cairo_traps_t *traps, + int y1, int y2, + const cairo_line_t *left, + const cairo_line_t *right) { - cairo_point_t quad[4]; + if (y2 < y1) { + int tmp = y1; + y1 = y2; + y2 = tmp; + } - quad[0] = t[0]; - quad[1] = t[0]; - quad[2] = t[1]; - quad[3] = t[2]; + if (cairo_lines_compare_at_y (left, right, y1) > 0) { + const cairo_line_t *tmp = left; + left = right; + right = tmp; + } - _cairo_traps_tessellate_convex_quad (traps, quad); + _cairo_traps_add_clipped_trap (traps, y1, y2, left, right); } +void +_cairo_traps_tessellate_triangle_with_edges (cairo_traps_t *traps, + const cairo_point_t t[3], + const cairo_point_t edges[4]) +{ + cairo_line_t lines[3]; + + if (edges[0].y <= edges[1].y) { + lines[0].p1 = edges[0]; + lines[0].p2 = edges[1]; + } else { + lines[0].p1 = edges[1]; + lines[0].p2 = edges[0]; + } + + if (edges[2].y <= edges[3].y) { + lines[1].p1 = edges[2]; + lines[1].p2 = edges[3]; + } else { + lines[1].p1 = edges[3]; + lines[1].p2 = edges[2]; + } + + if (t[1].y == t[2].y) { + add_tri (traps, t[0].y, t[1].y, &lines[0], &lines[1]); + return; + } + + if (t[1].y <= t[2].y) { + lines[2].p1 = t[1]; + lines[2].p2 = t[2]; + } else { + lines[2].p1 = t[2]; + lines[2].p2 = t[1]; + } + + if (((t[1].y - t[0].y) < 0) ^ ((t[2].y - t[0].y) < 0)) { + add_tri (traps, t[0].y, t[1].y, &lines[0], &lines[2]); + add_tri (traps, t[0].y, t[2].y, &lines[1], &lines[2]); + } else if (abs(t[1].y - t[0].y) < abs(t[2].y - t[0].y)) { + add_tri (traps, t[0].y, t[1].y, &lines[0], &lines[1]); + add_tri (traps, t[1].y, t[2].y, &lines[2], &lines[1]); + } else { + add_tri (traps, t[0].y, t[2].y, &lines[1], &lines[0]); + add_tri (traps, t[1].y, t[2].y, &lines[2], &lines[0]); + } +} /** * _cairo_traps_init_boxes: diff --git a/src/cairo-tristrip-private.h b/src/cairo-tristrip-private.h index ccd28799e..ccd28799e 100755..100644 --- a/src/cairo-tristrip-private.h +++ b/src/cairo-tristrip-private.h diff --git a/src/cairo-tristrip.c b/src/cairo-tristrip.c index bb4972f50..bb4972f50 100755..100644 --- a/src/cairo-tristrip.c +++ b/src/cairo-tristrip.c diff --git a/src/cairo-truetype-subset-private.h b/src/cairo-truetype-subset-private.h index dc9573216..dc9573216 100755..100644 --- a/src/cairo-truetype-subset-private.h +++ b/src/cairo-truetype-subset-private.h diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c index 44d7f60f5..fa33d63e4 100755..100644 --- a/src/cairo-truetype-subset.c +++ b/src/cairo-truetype-subset.c @@ -1572,40 +1572,11 @@ _cairo_truetype_read_font_name (cairo_scaled_font_t *scaled_font, goto fail; } - free (name); + status = _cairo_escape_ps_name (&ps_name); + if (unlikely(status)) + goto fail; - /* Ensure PS name is a valid PDF/PS name object. In PDF names are - * treated as UTF8 and non ASCII bytes, ' ', and '#' are encoded - * as '#' followed by 2 hex digits that encode the byte. By also - * encoding the characters in the reserved string we ensure the - * name is also PS compatible. */ - if (ps_name) { - static const char *reserved = "()<>[]{}/%#\\"; - char buf[128]; /* max name length is 127 bytes */ - char *src = ps_name; - char *dst = buf; - - while (*src && dst < buf + 127) { - unsigned char c = *src; - if (c < 0x21 || c > 0x7e || strchr (reserved, c)) { - if (dst + 4 > buf + 127) - break; - - snprintf (dst, 4, "#%02X", c); - src++; - dst += 3; - } else { - *dst++ = *src++; - } - } - *dst = 0; - free (ps_name); - ps_name = strdup (buf); - if (ps_name == NULL) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto fail; - } - } + free (name); *ps_name_out = ps_name; *font_name_out = family_name; diff --git a/src/cairo-type1-fallback.c b/src/cairo-type1-fallback.c index d7d6eae12..d7d6eae12 100755..100644 --- a/src/cairo-type1-fallback.c +++ b/src/cairo-type1-fallback.c diff --git a/src/cairo-type1-glyph-names.c b/src/cairo-type1-glyph-names.c index 80ccb9626..80ccb9626 100755..100644 --- a/src/cairo-type1-glyph-names.c +++ b/src/cairo-type1-glyph-names.c diff --git a/src/cairo-type1-private.h b/src/cairo-type1-private.h index 1630397bc..1630397bc 100755..100644 --- a/src/cairo-type1-private.h +++ b/src/cairo-type1-private.h diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c index 8453cbd7d..81a1bdbc1 100755..100644 --- a/src/cairo-type1-subset.c +++ b/src/cairo-type1-subset.c @@ -53,7 +53,6 @@ #include "cairo-output-stream-private.h" #include <ctype.h> -#include <locale.h> #define TYPE1_STACKSIZE 24 /* Defined in Type 1 Font Format */ @@ -309,12 +308,10 @@ cairo_type1_font_subset_get_matrix (cairo_type1_font_subset_t *font, const char *start, *end, *segment_end; int ret, s_max, i, j; char *s; - struct lconv *locale_data; const char *decimal_point; int decimal_point_len; - locale_data = localeconv (); - decimal_point = locale_data->decimal_point; + decimal_point = cairo_get_locale_decimal_point (); decimal_point_len = strlen (decimal_point); assert (decimal_point_len != 0); @@ -407,6 +404,7 @@ cairo_type1_font_subset_get_fontname (cairo_type1_font_subset_t *font) const char *start, *end, *segment_end; char *s; int i; + cairo_status_t status; segment_end = font->header_segment + font->header_segment_size; start = find_token (font->header_segment, segment_end, "/FontName"); @@ -419,6 +417,9 @@ cairo_type1_font_subset_get_fontname (cairo_type1_font_subset_t *font) if (end == NULL) return CAIRO_INT_STATUS_UNSUPPORTED; + while (end > start && _cairo_isspace(end[-1])) + end--; + s = malloc (end - start + 1); if (unlikely (s == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -447,13 +448,9 @@ cairo_type1_font_subset_get_fontname (cairo_type1_font_subset_t *font) if (unlikely (font->base.base_font == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - s = font->base.base_font; - while (*s && !is_ps_delimiter(*s)) - s++; - - *s = 0; + status = _cairo_escape_ps_name (&font->base.base_font); - return CAIRO_STATUS_SUCCESS; + return status; } static cairo_status_t @@ -1133,8 +1130,9 @@ write_used_glyphs (cairo_type1_font_subset_t *font, cairo_status_t status; char buffer[256]; int length; - int subset_id; + unsigned int subset_id; int ch; + const char *wa_name; if (font->glyphs[glyph_number].subset_index < 0) return CAIRO_STATUS_SUCCESS; @@ -1146,12 +1144,18 @@ write_used_glyphs (cairo_type1_font_subset_t *font, * font with the standard name. **/ subset_id = font->glyphs[glyph_number].subset_index; - if (subset_id > 0) { + /* Any additional glyph included for use by the seac operator + * will either have subset_id >= font->scaled_font_subset->num_glyphs + * or will not map to a winansi name (wa_name = NULL). In this + * case the original name is used. + */ + if (subset_id > 0 && subset_id < font->scaled_font_subset->num_glyphs) { ch = font->scaled_font_subset->to_latin_char[subset_id]; - name = _cairo_winansi_to_glyphname (ch); - if (name == NULL) - return CAIRO_STATUS_NULL_POINTER; - name_length = strlen(name); + wa_name = _cairo_winansi_to_glyphname (ch); + if (wa_name) { + name = wa_name; + name_length = strlen(name); + } } } @@ -1263,21 +1267,21 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font, * the actual glyph definitions (charstrings). * * What we do here is scan directly to the /Subrs token, which - * marks the beginning of the subroutines. We then read in all the - * subroutines then move on to the /CharString token, which marks - * the beginning of the glyph definitions, and read in the chastrings. + * marks the beginning of the subroutines. We read in all the + * subroutines, then move on to the /CharString token, which marks + * the beginning of the glyph definitions, and read in the charstrings. * - * The charstrings are parsed to extracts glyph widths, work out - * which subroutines are called, and too see if any extra glyphs + * The charstrings are parsed to extract glyph widths, work out + * which subroutines are called, and to see if any extra glyphs * need to be included due to the use of the seac glyph combining * operator. * - * Finally the private dict is copied to the subset font minus the + * Finally, the private dict is copied to the subset font minus the * subroutines and charstrings not required. */ /* Determine lenIV, the number of random characters at the start of - each encrypted charstring. The defaults is 4, but this can be + each encrypted charstring. The default is 4, but this can be overridden in the private dict. */ font->lenIV = 4; if ((lenIV_start = find_token (font->cleartext, font->cleartext_end, "/lenIV")) != NULL) { @@ -1313,6 +1317,7 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font, if (subrs == NULL) { font->subset_subrs = FALSE; p = font->cleartext; + array_start = NULL; goto skip_subrs; } diff --git a/src/cairo-type3-glyph-surface-private.h b/src/cairo-type3-glyph-surface-private.h index b4abcf604..6f40f1c25 100755..100644 --- a/src/cairo-type3-glyph-surface-private.h +++ b/src/cairo-type3-glyph-surface-private.h @@ -45,8 +45,9 @@ #include "cairo-surface-clipper-private.h" #include "cairo-pdf-operators-private.h" -typedef cairo_status_t (*cairo_type3_glyph_surface_emit_image_t) (cairo_image_surface_t *image, - cairo_output_stream_t *stream); +typedef cairo_int_status_t +(*cairo_type3_glyph_surface_emit_image_t) (cairo_image_surface_t *image, + cairo_output_stream_t *stream); typedef struct cairo_type3_glyph_surface { cairo_surface_t base; @@ -64,7 +65,8 @@ cairo_private cairo_surface_t * _cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font, cairo_output_stream_t *stream, cairo_type3_glyph_surface_emit_image_t emit_image, - cairo_scaled_font_subsets_t *font_subsets); + cairo_scaled_font_subsets_t *font_subsets, + cairo_bool_t ps_output); cairo_private void _cairo_type3_glyph_surface_set_font_subsets_callback (void *abstract_surface, diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c index dc5dbdf61..63d2bd74c 100755..100644 --- a/src/cairo-type3-glyph-surface.c +++ b/src/cairo-type3-glyph-surface.c @@ -74,7 +74,8 @@ cairo_surface_t * _cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font, cairo_output_stream_t *stream, cairo_type3_glyph_surface_emit_image_t emit_image, - cairo_scaled_font_subsets_t *font_subsets) + cairo_scaled_font_subsets_t *font_subsets, + cairo_bool_t ps) { cairo_type3_glyph_surface_t *surface; cairo_matrix_t invert_y_axis; @@ -106,7 +107,8 @@ _cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font, _cairo_pdf_operators_init (&surface->pdf_operators, surface->stream, &surface->cairo_to_pdf, - font_subsets); + font_subsets, + ps); _cairo_surface_clipper_init (&surface->clipper, _cairo_type3_glyph_surface_clipper_intersect_clip_path); diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h index 5050fd552..9e2fd37e0 100755..100644 --- a/src/cairo-types-private.h +++ b/src/cairo-types-private.h @@ -113,7 +113,7 @@ struct _cairo_observer { }; /** - * cairo_hash_entry_t: + * _cairo_hash_entry: * * A #cairo_hash_entry_t contains both a key and a value for * #cairo_hash_table_t. User-derived types for #cairo_hash_entry_t must @@ -158,7 +158,7 @@ struct _cairo_array { }; /** - * cairo_lcd_filter_t: + * _cairo_lcd_filter: * @CAIRO_LCD_FILTER_DEFAULT: Use the default LCD filter for * font backend and target device * @CAIRO_LCD_FILTER_NONE: Do not perform LCD filtering @@ -194,7 +194,7 @@ struct _cairo_font_options { cairo_hint_style_t hint_style; cairo_hint_metrics_t hint_metrics; cairo_round_glyph_positions_t round_glyph_positions; - cairo_font_color_t color; + cairo_font_color_t color; }; struct _cairo_glyph_text_info { @@ -447,7 +447,7 @@ typedef struct _cairo_shadow_cache { double scale; cairo_list_t link; } cairo_shadow_cache_t; - + CAIRO_END_DECLS #endif /* CAIRO_TYPES_PRIVATE_H */ diff --git a/src/cairo-unicode.c b/src/cairo-unicode.c index 88de39516..88de39516 100755..100644 --- a/src/cairo-unicode.c +++ b/src/cairo-unicode.c diff --git a/src/cairo-uninstalled.pc.in b/src/cairo-uninstalled.pc.in index 9dc3231ae..9dc3231ae 100755..100644 --- a/src/cairo-uninstalled.pc.in +++ b/src/cairo-uninstalled.pc.in diff --git a/src/cairo-user-font-private.h b/src/cairo-user-font-private.h index d54ef78b4..d54ef78b4 100755..100644 --- a/src/cairo-user-font-private.h +++ b/src/cairo-user-font-private.h diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c index 297f21c91..6d2de2097 100755..100644 --- a/src/cairo-user-font.c +++ b/src/cairo-user-font.c @@ -507,7 +507,7 @@ _cairo_user_font_face_scaled_font_create (void *abstract_ const cairo_font_face_backend_t _cairo_user_font_face_backend = { CAIRO_FONT_TYPE_USER, _cairo_user_font_face_create_for_toy, - NULL, /* destroy */ + _cairo_font_face_destroy, _cairo_user_font_face_scaled_font_create }; diff --git a/src/cairo-version.c b/src/cairo-version.c index d9ad240bf..a94cef681 100755..100644 --- a/src/cairo-version.c +++ b/src/cairo-version.c @@ -79,10 +79,10 @@ * 1.0.1 - Development on a maintenance branch (toward 1.0.2 release) * 1.1.1 - Development on head (toward 1.1.2 snapshot and 1.2.0 release) * </screen></informalexample> - * </para> + * * <refsect2> * <title>Compatibility</title> - * <para> + * * The API/ABI compatibility guarantees for various versions are as * follows. First, let's assume some cairo-using application code that is * successfully using the API/ABI "from" one version of cairo. Then let's @@ -102,11 +102,11 @@ * with the same in-development version number. This is because these * numbers don't correspond to any fixed state of the software, but * rather the many states between snapshots and releases. - * </para> + * * </refsect2> * <refsect2> * <title>Examining the version</title> - * <para> + * * Cairo provides the ability to examine the version at either * compile-time or run-time and in both a human-readable form as well as * an encoded form suitable for direct comparison. Cairo also provides the @@ -135,8 +135,9 @@ * if (cairo_version() >= CAIRO_VERSION_ENCODE(1, 0, 0)) * printf ("Running with suitable cairo version: %s\n", cairo_version_string ()); * </programlisting></informalexample> - * </para> + * * </refsect2> + * **/ /** diff --git a/src/cairo-version.h b/src/cairo-version.h index 51008003f..51008003f 100755..100644 --- a/src/cairo-version.h +++ b/src/cairo-version.h diff --git a/src/cairo-vg-surface.c b/src/cairo-vg-surface.c index 6e0d9a0ed..6e0d9a0ed 100755..100644 --- a/src/cairo-vg-surface.c +++ b/src/cairo-vg-surface.c diff --git a/src/cairo-vg.h b/src/cairo-vg.h index f9a62e51c..f9a62e51c 100755..100644 --- a/src/cairo-vg.h +++ b/src/cairo-vg.h diff --git a/src/cairo-wgl-context.c b/src/cairo-wgl-context.c index 31cbcfe07..31cbcfe07 100755..100644 --- a/src/cairo-wgl-context.c +++ b/src/cairo-wgl-context.c diff --git a/src/cairo-wideint-private.h b/src/cairo-wideint-private.h index 3f5491bb1..3f5491bb1 100755..100644 --- a/src/cairo-wideint-private.h +++ b/src/cairo-wideint-private.h diff --git a/src/cairo-wideint-type-private.h b/src/cairo-wideint-type-private.h index 84a3cbab0..84a3cbab0 100755..100644 --- a/src/cairo-wideint-type-private.h +++ b/src/cairo-wideint-type-private.h diff --git a/src/cairo-wideint.c b/src/cairo-wideint.c index bba266b24..2e056fa36 100755..100644 --- a/src/cairo-wideint.c +++ b/src/cairo-wideint.c @@ -654,16 +654,16 @@ _cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den) return qr; } -cairo_int128_t -_cairo_int128_negate (cairo_int128_t a) +cairo_uint128_t +_cairo_uint128_negate (cairo_uint128_t a) { a.lo = _cairo_uint64_not (a.lo); a.hi = _cairo_uint64_not (a.hi); return _cairo_uint128_add (a, _cairo_uint32_to_uint128 (1)); } -cairo_int128_t -_cairo_int128_not (cairo_int128_t a) +cairo_uint128_t +_cairo_uint128_not (cairo_uint128_t a) { a.lo = _cairo_uint64_not (a.lo); a.hi = _cairo_uint64_not (a.hi); diff --git a/src/cairo-win32.h b/src/cairo-win32.h index 3d2e1c601..3d2e1c601 100755..100644 --- a/src/cairo-win32.h +++ b/src/cairo-win32.h diff --git a/src/cairo-xcb-connection-core.c b/src/cairo-xcb-connection-core.c index ae7c023e1..e01dc1a83 100755..100644 --- a/src/cairo-xcb-connection-core.c +++ b/src/cairo-xcb-connection-core.c @@ -268,8 +268,6 @@ _cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection, if (rows > height) rows = height; - length = rows * cpp * width; - _cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y, width, rows, cpp, stride, dst_x, dst_y, depth, _data); @@ -283,32 +281,20 @@ _cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection, } } -cairo_status_t +xcb_get_image_reply_t * _cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection, xcb_drawable_t src, int16_t src_x, int16_t src_y, uint16_t width, - uint16_t height, - xcb_get_image_reply_t **reply) + uint16_t height) { - xcb_generic_error_t *error; - - *reply = xcb_get_image_reply (connection->xcb_connection, - xcb_get_image (connection->xcb_connection, - XCB_IMAGE_FORMAT_Z_PIXMAP, - src, - src_x, src_y, - width, height, - (uint32_t) -1), - - &error); - if (error) { - free (error); - - free (*reply); - *reply = NULL; - } - - return CAIRO_STATUS_SUCCESS; + return xcb_get_image_reply (connection->xcb_connection, + xcb_get_image (connection->xcb_connection, + XCB_IMAGE_FORMAT_Z_PIXMAP, + src, + src_x, src_y, + width, height, + (uint32_t) -1), + NULL); } diff --git a/src/cairo-xcb-connection-render.c b/src/cairo-xcb-connection-render.c index 83f1d482e..83f1d482e 100755..100644 --- a/src/cairo-xcb-connection-render.c +++ b/src/cairo-xcb-connection-render.c diff --git a/src/cairo-xcb-connection-shm.c b/src/cairo-xcb-connection-shm.c index 8c1d50698..7720bbbd2 100755..100644 --- a/src/cairo-xcb-connection-shm.c +++ b/src/cairo-xcb-connection-shm.c @@ -82,7 +82,6 @@ _cairo_xcb_connection_shm_get_image (cairo_xcb_connection_t *connection, uint32_t offset) { xcb_shm_get_image_reply_t *reply; - xcb_generic_error_t *error; assert (connection->flags & CAIRO_XCB_HAS_SHM); reply = xcb_shm_get_image_reply (connection->xcb_connection, @@ -93,12 +92,11 @@ _cairo_xcb_connection_shm_get_image (cairo_xcb_connection_t *connection, (uint32_t) -1, XCB_IMAGE_FORMAT_Z_PIXMAP, shmseg, offset), - &error); + NULL); free (reply); - if (error) { + if (!reply) { /* an error here should be impossible */ - free (error); return _cairo_error (CAIRO_STATUS_READ_ERROR); } diff --git a/src/cairo-xcb-connection.c b/src/cairo-xcb-connection.c index 78bc9a101..a070720fd 100755..100644 --- a/src/cairo-xcb-connection.c +++ b/src/cairo-xcb-connection.c @@ -77,6 +77,9 @@ typedef struct _cairo_xcb_xid { #define XCB_RENDER_HAS_PICTURE_TRANSFORM(surface) XCB_RENDER_AT_LEAST((surface), 0, 6) #define XCB_RENDER_HAS_FILTERS(surface) XCB_RENDER_AT_LEAST((surface), 0, 6) +#define XCB_RENDER_HAS_FILTER_GOOD(surface) FALSE +#define XCB_RENDER_HAS_FILTER_BEST(surface) FALSE +#define XCB_RENDER_HAS_SUBPIXEL_ORDER(surface) XCB_RENDER_AT_LEAST((surface), 0, 6) #define XCB_RENDER_HAS_EXTENDED_REPEAT(surface) XCB_RENDER_AT_LEAST((surface), 0, 10) #define XCB_RENDER_HAS_GRADIENTS(surface) XCB_RENDER_AT_LEAST((surface), 0, 10) @@ -390,6 +393,12 @@ _cairo_xcb_connection_query_render (cairo_xcb_connection_t *connection) if (XCB_RENDER_HAS_FILTERS (version)) connection->flags |= CAIRO_XCB_RENDER_HAS_FILTERS; + if (XCB_RENDER_HAS_FILTER_GOOD (version)) + connection->flags |= CAIRO_XCB_RENDER_HAS_FILTER_GOOD; + + if (XCB_RENDER_HAS_FILTER_BEST (version)) + connection->flags |= CAIRO_XCB_RENDER_HAS_FILTER_BEST; + if (XCB_RENDER_HAS_PDF_OPERATORS (version)) connection->flags |= CAIRO_XCB_RENDER_HAS_PDF_OPERATORS; @@ -399,6 +408,15 @@ _cairo_xcb_connection_query_render (cairo_xcb_connection_t *connection) if (XCB_RENDER_HAS_GRADIENTS (version)) connection->flags |= CAIRO_XCB_RENDER_HAS_GRADIENTS; + if (XCB_RENDER_HAS_SUBPIXEL_ORDER (version)) { + uint32_t screen; + uint32_t *subpixel = xcb_render_query_pict_formats_subpixels(formats); + + /* The spec explicitly allows to have too few entries in the reply... */ + for (screen = 0; screen < formats->num_subpixel && screen < connection->root->roots_len; screen++) + connection->subpixel_orders[screen] = subpixel[screen]; + } + free (version); status = _cairo_xcb_connection_parse_xrender_formats (connection, formats); @@ -573,6 +591,7 @@ _device_destroy (void *device) CAIRO_MUTEX_FINI (connection->shm_mutex); CAIRO_MUTEX_FINI (connection->screens_mutex); + free (connection->subpixel_orders); free (connection); } @@ -684,6 +703,14 @@ _cairo_xcb_connection_get (xcb_connection_t *xcb_connection) } connection->render = NULL; + connection->subpixel_orders = calloc (connection->root->roots_len, sizeof(*connection->subpixel_orders)); + if (unlikely (connection->subpixel_orders == NULL)) { + CAIRO_MUTEX_UNLOCK (connection->device.mutex); + _cairo_xcb_connection_destroy (connection); + connection = NULL; + goto unlock; + } + ext = xcb_get_extension_data (xcb_connection, &xcb_render_id); if (ext != NULL && ext->present) { status = _cairo_xcb_connection_query_render (connection); @@ -890,6 +917,8 @@ cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device, CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS | CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM | CAIRO_XCB_RENDER_HAS_FILTERS | + CAIRO_XCB_RENDER_HAS_FILTER_GOOD | + CAIRO_XCB_RENDER_HAS_FILTER_BEST | CAIRO_XCB_RENDER_HAS_PDF_OPERATORS | CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT | CAIRO_XCB_RENDER_HAS_GRADIENTS); diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h index d162d73d4..1ede8c716 100755..100644 --- a/src/cairo-xcb-private.h +++ b/src/cairo-xcb-private.h @@ -37,10 +37,10 @@ #ifndef CAIRO_XCB_PRIVATE_H #define CAIRO_XCB_PRIVATE_H -#include "cairo-xcb.h" - #include "cairoint.h" +#include "cairo-xcb.h" + #include "cairo-cache-private.h" #include "cairo-compiler-private.h" #include "cairo-device-private.h" @@ -75,6 +75,7 @@ typedef struct _cairo_xcb_surface cairo_xcb_surface_t; typedef struct _cairo_xcb_picture cairo_xcb_picture_t; typedef struct _cairo_xcb_shm_mem_pool cairo_xcb_shm_mem_pool_t; typedef struct _cairo_xcb_shm_info cairo_xcb_shm_info_t; +typedef struct _cairo_xcb_resources cairo_xcb_resources_t; struct _cairo_xcb_shm_info { cairo_xcb_connection_t *connection; @@ -180,7 +181,8 @@ struct _cairo_xcb_font { struct _cairo_xcb_screen { cairo_xcb_connection_t *connection; - xcb_screen_t *xcb_screen; + xcb_screen_t *xcb_screen; + xcb_render_sub_pixel_t subpixel_order; xcb_gcontext_t gc[GC_CACHE_SIZE]; uint8_t gc_depths[GC_CACHE_SIZE]; @@ -199,6 +201,9 @@ struct _cairo_xcb_screen { cairo_list_t link; cairo_list_t surfaces; cairo_list_t pictures; + + cairo_bool_t has_font_options; + cairo_font_options_t font_options; }; struct _cairo_xcb_connection { @@ -219,6 +224,7 @@ struct _cairo_xcb_connection { const xcb_setup_t *root; const xcb_query_extension_reply_t *render; const xcb_query_extension_reply_t *shm; + xcb_render_sub_pixel_t *subpixel_orders; cairo_list_t free_xids; cairo_freepool_t xid_pool; @@ -236,6 +242,14 @@ struct _cairo_xcb_connection { cairo_list_t link; }; +struct _cairo_xcb_resources { + cairo_bool_t xft_antialias; + int xft_lcdfilter; + cairo_bool_t xft_hinting; + int xft_hintstyle; + int xft_rgba; +}; + enum { CAIRO_XCB_HAS_RENDER = 0x0001, CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES = 0x0002, @@ -247,6 +261,8 @@ enum { CAIRO_XCB_RENDER_HAS_PDF_OPERATORS = 0x0080, CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT = 0x0100, CAIRO_XCB_RENDER_HAS_GRADIENTS = 0x0200, + CAIRO_XCB_RENDER_HAS_FILTER_GOOD = 0x0400, + CAIRO_XCB_RENDER_HAS_FILTER_BEST = 0x0800, CAIRO_XCB_HAS_SHM = 0x80000000, @@ -259,7 +275,9 @@ enum { CAIRO_XCB_RENDER_HAS_FILTERS | CAIRO_XCB_RENDER_HAS_PDF_OPERATORS | CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT | - CAIRO_XCB_RENDER_HAS_GRADIENTS, + CAIRO_XCB_RENDER_HAS_GRADIENTS | + CAIRO_XCB_RENDER_HAS_FILTER_GOOD | + CAIRO_XCB_RENDER_HAS_FILTER_BEST, CAIRO_XCB_SHM_MASK = CAIRO_XCB_HAS_SHM }; @@ -267,6 +285,21 @@ enum { cairo_private extern const cairo_surface_backend_t _cairo_xcb_surface_backend; +/** + * _cairo_surface_is_xcb: + * @surface: a #cairo_surface_t + * + * Checks if a surface is an #cairo_xcb_surface_t + * + * Return value: %TRUE if the surface is an xcb surface + **/ +static inline cairo_bool_t +_cairo_surface_is_xcb (const cairo_surface_t *surface) +{ + /* _cairo_surface_nil sets a NULL backend so be safe */ + return surface->backend && surface->backend->type == CAIRO_SURFACE_TYPE_XCB; +} + cairo_private cairo_xcb_connection_t * _cairo_xcb_connection_get (xcb_connection_t *connection); @@ -342,6 +375,9 @@ _cairo_xcb_screen_get_gc (cairo_xcb_screen_t *screen, cairo_private void _cairo_xcb_screen_put_gc (cairo_xcb_screen_t *screen, int depth, xcb_gcontext_t gc); +cairo_private cairo_font_options_t * +_cairo_xcb_screen_get_font_options (cairo_xcb_screen_t *screen); + cairo_private cairo_status_t _cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen, const cairo_linear_pattern_t *linear, @@ -505,14 +541,13 @@ _cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection, uint8_t depth, void *data); -cairo_private cairo_status_t +cairo_private xcb_get_image_reply_t * _cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection, xcb_drawable_t src, int16_t src_x, int16_t src_y, uint16_t width, - uint16_t height, - xcb_get_image_reply_t **reply); + uint16_t height); cairo_private void _cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection, @@ -767,4 +802,8 @@ slim_hidden_proto_no_warn (cairo_xcb_device_debug_set_precision); slim_hidden_proto_no_warn (cairo_xcb_device_debug_cap_xrender_version); #endif +cairo_private void +_cairo_xcb_resources_get (cairo_xcb_screen_t *screen, + cairo_xcb_resources_t *resources); + #endif /* CAIRO_XCB_PRIVATE_H */ diff --git a/src/cairo-xcb-resources.c b/src/cairo-xcb-resources.c new file mode 100644 index 000000000..1877758c2 --- /dev/null +++ b/src/cairo-xcb-resources.c @@ -0,0 +1,281 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2014 Lukas Lalinsky + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * Authors: + * Lukas Lalinsky <lukas@oxygene.sk> + * + * Partially on code from xftdpy.c + * + * Copyright © 2000 Keith Packard + * + * 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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. + */ + +#include "cairoint.h" + +#include "cairo-xcb-private.h" + +#include "cairo-fontconfig-private.h" + +static void +parse_boolean (const char *v, cairo_bool_t *out) +{ + char c0, c1; + + c0 = *v; + if (c0 == 't' || c0 == 'T' || c0 == 'y' || c0 == 'Y' || c0 == '1') + *out = TRUE; + if (c0 == 'f' || c0 == 'F' || c0 == 'n' || c0 == 'N' || c0 == '0') + *out = FALSE; + if (c0 == 'o') { + c1 = v[1]; + if (c1 == 'n' || c1 == 'N') + *out = TRUE; + if (c1 == 'f' || c1 == 'F') + *out = FALSE; + } +} + +static void +parse_integer (const char *v, int *out) +{ + char *e; + int value; + +#if CAIRO_HAS_FC_FONT + if (FcNameConstant ((FcChar8 *) v, out)) + return; +#endif + + value = strtol (v, &e, 0); + if (e != v) + *out = value; +} + +static char * +skip_spaces(char *str) +{ + while (*str == ' ' || *str == '\t' || *str == '\n') + str++; + return str; +} + +struct resource_parser { + int buffer_size; + int bytes_in_buffer; + char* buffer; + cairo_xcb_resources_t *resources; +}; + +static cairo_bool_t +resource_parse_line (char *name, cairo_xcb_resources_t *resources) +{ + char *value; + + value = strchr (name, ':'); + if (value == NULL) + return FALSE; + + *value++ = 0; + + name = skip_spaces (name); + value = skip_spaces (value); + + if (strcmp (name, "Xft.antialias") == 0) + parse_boolean (value, &(resources->xft_antialias)); + else if (strcmp (name, "Xft.lcdfilter") == 0) + parse_integer (value, &(resources->xft_lcdfilter)); + else if (strcmp (name, "Xft.rgba") == 0) + parse_integer (value, &(resources->xft_rgba)); + else if (strcmp (name, "Xft.hinting") == 0) + parse_boolean (value, &(resources->xft_hinting)); + else if (strcmp (name, "Xft.hintstyle") == 0) + parse_integer (value, &(resources->xft_hintstyle)); + + return TRUE; +} + +static int +resource_parse_lines (struct resource_parser *parser) +{ + char *line, *newline; + + line = parser->buffer; + while (1) { + newline = strchr (line, '\n'); + if (newline == NULL) + break; + + *newline++ = 0; + + if (! resource_parse_line (line, parser->resources)) + break; + + line = newline; + } + + return line - parser->buffer; +} + +static void +resource_parser_init (struct resource_parser *parser, cairo_xcb_resources_t *resources) +{ + parser->buffer_size = 0; + parser->bytes_in_buffer = 0; + parser->buffer = NULL; + parser->resources = resources; +} + +static cairo_bool_t +resource_parser_update (struct resource_parser *parser, const char *data, int length) +{ + int bytes_parsed; + + if (parser->bytes_in_buffer + length + 1 > parser->buffer_size) { + parser->buffer_size = parser->bytes_in_buffer + length + 1; + parser->buffer = realloc(parser->buffer, parser->buffer_size); + if (! parser->buffer) { + parser->buffer_size = 0; + parser->bytes_in_buffer = 0; + return FALSE; + } + } + + memmove (parser->buffer + parser->bytes_in_buffer, data, length); + parser->bytes_in_buffer += length; + parser->buffer[parser->bytes_in_buffer] = 0; + + bytes_parsed = resource_parse_lines (parser); + + if (parser->bytes_in_buffer > bytes_parsed) { + memmove (parser->buffer, parser->buffer + bytes_parsed, parser->bytes_in_buffer - bytes_parsed); + parser->bytes_in_buffer -= bytes_parsed; + } else { + parser->bytes_in_buffer = 0; + } + + return TRUE; +} + +static void +resource_parser_done (struct resource_parser *parser) +{ + if (parser->bytes_in_buffer > 0) { + parser->buffer[parser->bytes_in_buffer] = 0; + resource_parse_line (parser->buffer, parser->resources); + } + + free (parser->buffer); +} + +static void +get_resources(xcb_connection_t *connection, xcb_screen_t *screen, cairo_xcb_resources_t *resources) +{ + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + struct resource_parser parser; + int offset; + cairo_bool_t has_more_data; + + resources->xft_antialias = TRUE; + resources->xft_lcdfilter = -1; + resources->xft_hinting = TRUE; + resources->xft_hintstyle = FC_HINT_FULL; + resources->xft_rgba = FC_RGBA_UNKNOWN; + + resource_parser_init (&parser, resources); + + offset = 0; + has_more_data = FALSE; + do { + cookie = xcb_get_property (connection, 0, screen->root, XCB_ATOM_RESOURCE_MANAGER, XCB_ATOM_STRING, offset, 1024); + reply = xcb_get_property_reply (connection, cookie, NULL); + + if (reply) { + if (reply->format == 8 && reply->type == XCB_ATOM_STRING) { + char *value = (char *) xcb_get_property_value (reply); + int length = xcb_get_property_value_length (reply); + + offset += length / 4; /* X needs the offset in 'long' units */ + has_more_data = reply->bytes_after > 0; + + if (! resource_parser_update (&parser, value, length)) + has_more_data = FALSE; /* early exit on error */ + } + + free (reply); + } + } while (has_more_data); + + resource_parser_done (&parser); +} + +void +_cairo_xcb_resources_get (cairo_xcb_screen_t *screen, cairo_xcb_resources_t *resources) +{ + get_resources (screen->connection->xcb_connection, screen->xcb_screen, resources); + + if (resources->xft_rgba == FC_RGBA_UNKNOWN) { + switch (screen->subpixel_order) { + case XCB_RENDER_SUB_PIXEL_UNKNOWN: + resources->xft_rgba = FC_RGBA_UNKNOWN; + break; + case XCB_RENDER_SUB_PIXEL_HORIZONTAL_RGB: + resources->xft_rgba = FC_RGBA_RGB; + break; + case XCB_RENDER_SUB_PIXEL_HORIZONTAL_BGR: + resources->xft_rgba = FC_RGBA_BGR; + break; + case XCB_RENDER_SUB_PIXEL_VERTICAL_RGB: + resources->xft_rgba = FC_RGBA_VRGB; + break; + case XCB_RENDER_SUB_PIXEL_VERTICAL_BGR: + resources->xft_rgba = FC_RGBA_VBGR; + break; + case XCB_RENDER_SUB_PIXEL_NONE: + resources->xft_rgba = FC_RGBA_NONE; + break; + } + } +} diff --git a/src/cairo-xcb-screen.c b/src/cairo-xcb-screen.c index 2858d23fb..d0019f9cd 100755..100644 --- a/src/cairo-xcb-screen.c +++ b/src/cairo-xcb-screen.c @@ -35,6 +35,96 @@ #include "cairo-xcb-private.h" #include "cairo-list-inline.h" +#include "cairo-fontconfig-private.h" + +static void +_cairo_xcb_init_screen_font_options (cairo_xcb_screen_t *screen) +{ + cairo_xcb_resources_t res; + cairo_antialias_t antialias; + cairo_subpixel_order_t subpixel_order; + cairo_lcd_filter_t lcd_filter; + cairo_hint_style_t hint_style; + + _cairo_xcb_resources_get (screen, &res); + + /* the rest of the code in this function is copied from + _cairo_xlib_init_screen_font_options in cairo-xlib-screen.c */ + + if (res.xft_hinting) { + switch (res.xft_hintstyle) { + case FC_HINT_NONE: + hint_style = CAIRO_HINT_STYLE_NONE; + break; + case FC_HINT_SLIGHT: + hint_style = CAIRO_HINT_STYLE_SLIGHT; + break; + case FC_HINT_MEDIUM: + hint_style = CAIRO_HINT_STYLE_MEDIUM; + break; + case FC_HINT_FULL: + hint_style = CAIRO_HINT_STYLE_FULL; + break; + default: + hint_style = CAIRO_HINT_STYLE_DEFAULT; + } + } else { + hint_style = CAIRO_HINT_STYLE_NONE; + } + + switch (res.xft_rgba) { + case FC_RGBA_RGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; + break; + case FC_RGBA_BGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; + break; + case FC_RGBA_VRGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; + break; + case FC_RGBA_VBGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; + break; + case FC_RGBA_UNKNOWN: + case FC_RGBA_NONE: + default: + subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + } + + switch (res.xft_lcdfilter) { + case FC_LCD_NONE: + lcd_filter = CAIRO_LCD_FILTER_NONE; + break; + case FC_LCD_DEFAULT: + lcd_filter = CAIRO_LCD_FILTER_FIR5; + break; + case FC_LCD_LIGHT: + lcd_filter = CAIRO_LCD_FILTER_FIR3; + break; + case FC_LCD_LEGACY: + lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL; + break; + default: + lcd_filter = CAIRO_LCD_FILTER_DEFAULT; + break; + } + + if (res.xft_antialias) { + if (subpixel_order == CAIRO_SUBPIXEL_ORDER_DEFAULT) + antialias = CAIRO_ANTIALIAS_GRAY; + else + antialias = CAIRO_ANTIALIAS_SUBPIXEL; + } else { + antialias = CAIRO_ANTIALIAS_NONE; + } + + cairo_font_options_set_hint_style (&screen->font_options, hint_style); + cairo_font_options_set_antialias (&screen->font_options, antialias); + cairo_font_options_set_subpixel_order (&screen->font_options, subpixel_order); + _cairo_font_options_set_lcd_filter (&screen->font_options, lcd_filter); + cairo_font_options_set_hint_metrics (&screen->font_options, CAIRO_HINT_METRICS_ON); +} + struct pattern_cache_entry { cairo_cache_entry_t key; cairo_xcb_screen_t *screen; @@ -117,6 +207,18 @@ _pattern_cache_entry_destroy (void *closure) _cairo_freelist_free (&entry->screen->pattern_cache_entry_freelist, entry); } +static int _get_screen_index(cairo_xcb_connection_t *xcb_connection, + xcb_screen_t *xcb_screen) +{ + int idx = 0; + xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_connection->root); + for (; iter.rem; xcb_screen_next(&iter), idx++) + if (iter.data->root == xcb_screen->root) + return idx; + + ASSERT_NOT_REACHED; +} + cairo_xcb_screen_t * _cairo_xcb_screen_get (xcb_connection_t *xcb_connection, xcb_screen_t *xcb_screen) @@ -124,6 +226,7 @@ _cairo_xcb_screen_get (xcb_connection_t *xcb_connection, cairo_xcb_connection_t *connection; cairo_xcb_screen_t *screen; cairo_status_t status; + int screen_idx; int i; connection = _cairo_xcb_connection_get (xcb_connection); @@ -150,8 +253,12 @@ _cairo_xcb_screen_get (xcb_connection_t *xcb_connection, if (unlikely (screen == NULL)) goto unlock; + screen_idx = _get_screen_index(connection, xcb_screen); + screen->connection = connection; screen->xcb_screen = xcb_screen; + screen->has_font_options = FALSE; + screen->subpixel_order = connection->subpixel_orders[screen_idx]; _cairo_freelist_init (&screen->pattern_cache_entry_freelist, sizeof (struct pattern_cache_entry)); @@ -362,3 +469,26 @@ _cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t *screen, return picture; } + +cairo_font_options_t * +_cairo_xcb_screen_get_font_options (cairo_xcb_screen_t *screen) +{ + if (! screen->has_font_options) { + _cairo_font_options_init_default (&screen->font_options); + _cairo_font_options_set_round_glyph_positions (&screen->font_options, CAIRO_ROUND_GLYPH_POS_ON); + + /* XXX: This is disabled because something seems to be merging + font options incorrectly for xcb. This effectively reverts + the changes brought in git e691d242, and restores ~150 tests + to resume passing. See mailing list archives for Sep 17, + 2014 for more discussion. */ + if (0 && ! _cairo_xcb_connection_acquire (screen->connection)) { + _cairo_xcb_init_screen_font_options (screen); + _cairo_xcb_connection_release (screen->connection); + } + + screen->has_font_options = TRUE; + } + + return &screen->font_options; +} diff --git a/src/cairo-xcb-shm.c b/src/cairo-xcb-shm.c index 2be2dac5b..2be2dac5b 100755..100644 --- a/src/cairo-xcb-shm.c +++ b/src/cairo-xcb-shm.c diff --git a/src/cairo-xcb-surface-core.c b/src/cairo-xcb-surface-core.c index db775cd17..e78cd80c2 100755..100644 --- a/src/cairo-xcb-surface-core.c +++ b/src/cairo-xcb-surface-core.c @@ -409,7 +409,7 @@ _cairo_xcb_surface_pixmap (cairo_xcb_surface_t *target, if (pixmap != NULL && pixmap->screen == target->screen) return (cairo_xcb_pixmap_t *) cairo_surface_reference (&pixmap->base); - if (source->type == CAIRO_SURFACE_TYPE_XCB && + if (_cairo_surface_is_xcb(source) && ((cairo_xcb_surface_t *) source)->screen == target->screen) { cairo_xcb_surface_t *xcb_source = (cairo_xcb_surface_t *) source; @@ -576,7 +576,7 @@ _cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t *dst, src->x0 + x1, src->y0 + y1, x1, y1, - x2 - x2, y2 - x2); + x2 - x1, y2 - y1); } } } diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c index c6393a809..eec45c7f3 100755..100644 --- a/src/cairo-xcb-surface-render.c +++ b/src/cairo-xcb-surface-render.c @@ -39,6 +39,7 @@ #include "cairo-clip-inline.h" #include "cairo-clip-private.h" #include "cairo-composite-rectangles-private.h" +#include "cairo-image-surface-inline.h" #include "cairo-image-surface-private.h" #include "cairo-list-inline.h" #include "cairo-region-private.h" @@ -396,11 +397,6 @@ _pattern_is_supported (uint32_t flags, if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) return TRUE; - if (! _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL)) { - if ((flags & CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM) == 0) - return FALSE; - } - switch (pattern->extend) { default: ASSERT_NOT_REACHED; @@ -414,19 +410,22 @@ _pattern_is_supported (uint32_t flags, } if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { - cairo_filter_t filter; - - filter = pattern->filter; - if (_cairo_matrix_has_unity_scale (&pattern->matrix) && - _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL)) - { - filter = CAIRO_FILTER_NEAREST; - } - - if (! (filter == CAIRO_FILTER_NEAREST || filter == CAIRO_FILTER_FAST)) { - if ((flags & CAIRO_XCB_RENDER_HAS_FILTERS) == 0) - return FALSE; + switch (pattern->filter) { + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + return (flags & CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM) || + _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL); + case CAIRO_FILTER_GOOD: + return flags & CAIRO_XCB_RENDER_HAS_FILTER_GOOD; + case CAIRO_FILTER_BEST: + return flags & CAIRO_XCB_RENDER_HAS_FILTER_BEST; + case CAIRO_FILTER_BILINEAR: + case CAIRO_FILTER_GAUSSIAN: + default: + return flags & CAIRO_XCB_RENDER_HAS_FILTERS; } + } else if (pattern->type == CAIRO_PATTERN_TYPE_MESH) { + return FALSE; } else { /* gradient */ if ((flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) == 0) return FALSE; @@ -438,9 +437,8 @@ _pattern_is_supported (uint32_t flags, { return FALSE; } + return TRUE; } - - return pattern->type != CAIRO_PATTERN_TYPE_MESH; } static void @@ -519,7 +517,7 @@ _cairo_xcb_picture_set_filter (cairo_xcb_picture_t *picture, render_filter = "best"; len = strlen ("best"); } - else { + else { render_filter = "convolution"; len = strlen ("convolution"); } @@ -1045,9 +1043,7 @@ _cairo_xcb_surface_setup_surface_picture(cairo_xcb_picture_t *picture, filter = pattern->base.filter; if (filter != CAIRO_FILTER_NEAREST && - _cairo_matrix_has_unity_scale (&pattern->base.matrix) && - _cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->base.matrix.x0)) && - _cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->base.matrix.y0))) + _cairo_matrix_is_pixel_exact (&pattern->base.matrix)) { filter = CAIRO_FILTER_NEAREST; } @@ -1113,10 +1109,11 @@ record_to_picture (cairo_surface_t *target, return _cairo_xcb_transparent_picture ((cairo_xcb_surface_t *) target); /* Now draw the recording surface to an xcb surface */ - tmp = _cairo_surface_create_similar_scratch (target, - source->content, - limit.width, - limit.height); + tmp = _cairo_surface_create_scratch (target, + source->content, + limit.width, + limit.height, + CAIRO_COLOR_TRANSPARENT); if (tmp->status != CAIRO_STATUS_SUCCESS) { return (cairo_xcb_picture_t *) tmp; } @@ -1176,13 +1173,13 @@ _cairo_xcb_surface_picture (cairo_xcb_surface_t *target, /* restore transform */ if (filtered_picture != picture) { - _cairo_xcb_picture_set_matrix (filtered_picture, + _cairo_xcb_picture_set_matrix (filtered_picture, &pattern->base.matrix, pattern->base.filter, extents->x + extents->width/2., extents->y + extents->height/2.); - _cairo_xcb_picture_set_matrix (picture, + _cairo_xcb_picture_set_matrix (picture, &pattern->base.matrix, pattern->base.filter, extents->x + extents->width/2., @@ -1199,7 +1196,7 @@ _cairo_xcb_surface_picture (cairo_xcb_surface_t *target, if (source->type == CAIRO_SURFACE_TYPE_XCB) { - if (source->backend->type == CAIRO_SURFACE_TYPE_XCB) { + if (_cairo_surface_is_xcb(source)) { cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) source; if (xcb->screen == target->screen && xcb->fallback == NULL) { picture = _copy_to_picture ((cairo_xcb_surface_t *) source); @@ -1360,13 +1357,13 @@ _cairo_xcb_surface_picture (cairo_xcb_surface_t *target, /* restore transform */ if (filtered_picture != picture) { - _cairo_xcb_picture_set_matrix (filtered_picture, + _cairo_xcb_picture_set_matrix (filtered_picture, &pattern->base.matrix, pattern->base.filter, extents->x + extents->width/2., extents->y + extents->height/2.); - _cairo_xcb_picture_set_matrix (picture, + _cairo_xcb_picture_set_matrix (picture, &pattern->base.matrix, pattern->base.filter, extents->x + extents->width/2., @@ -1425,7 +1422,7 @@ _render_fill_boxes (void *abstract_dst, cairo_boxes_t *boxes) { cairo_xcb_surface_t *dst = abstract_dst; - xcb_rectangle_t stack_xrects[CAIRO_STACK_ARRAY_LENGTH (sizeof (xcb_rectangle_t))]; + xcb_rectangle_t stack_xrects[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)]; xcb_rectangle_t *xrects = stack_xrects; xcb_render_color_t render_color; int render_op = _render_operator (op); @@ -1581,7 +1578,7 @@ _render_composite_boxes (cairo_xcb_surface_t *dst, src->x + extents->x, src->y + extents->y, 0, 0, extents->x, extents->y, - extents->width, extents->height); + extents->width, extents->height); } @@ -1770,11 +1767,11 @@ get_clip_surface (const cairo_clip_t *clip, cairo_surface_t *surface; cairo_status_t status; - surface = _cairo_surface_create_similar_solid (&target->base, - CAIRO_CONTENT_ALPHA, - clip->extents.width, - clip->extents.height, - CAIRO_COLOR_WHITE); + surface = _cairo_surface_create_scratch (&target->base, + CAIRO_CONTENT_ALPHA, + clip->extents.width, + clip->extents.height, + CAIRO_COLOR_WHITE); if (unlikely (surface->status)) return (cairo_xcb_surface_t *) surface; @@ -2033,7 +2030,7 @@ _clip_and_composite_combine (cairo_clip_t *clip, { cairo_xcb_surface_t *tmp; cairo_xcb_surface_t *clip_surface; - int clip_x, clip_y; + int clip_x = 0, clip_y = 0; xcb_render_picture_t clip_picture; cairo_status_t status; @@ -2336,7 +2333,7 @@ _cairo_xcb_surface_fixup_unbounded_with_mask (cairo_xcb_surface_t *dst, cairo_clip_t *clip) { cairo_xcb_surface_t *mask; - int mask_x, mask_y; + int mask_x = 0, mask_y = 0; mask = get_clip_surface (clip, dst, &mask_x, &mask_y); if (unlikely (mask->base.status)) @@ -2739,7 +2736,7 @@ _composite_boxes (cairo_xcb_surface_t *dst, if (need_clip_mask) { cairo_xcb_surface_t *clip_surface; - int clip_x, clip_y; + int clip_x = 0, clip_y = 0; clip_surface = get_clip_surface (extents->clip, dst, &clip_x, &clip_y); @@ -2877,7 +2874,7 @@ _upload_image_inplace (cairo_xcb_surface_t *surface, return CAIRO_INT_STATUS_UNSUPPORTED; pattern = (const cairo_surface_pattern_t *) source; - if (pattern->surface->type != CAIRO_SURFACE_TYPE_IMAGE) + if (! _cairo_surface_is_image (pattern->surface)) return CAIRO_INT_STATUS_UNSUPPORTED; /* Have we already upload this image to a pixmap? */ @@ -2992,27 +2989,29 @@ _boxes_for_traps (cairo_boxes_t *boxes, cairo_traps_t *traps, cairo_antialias_t antialias) { - int i; + int i, j; _cairo_boxes_init (boxes); - boxes->num_boxes = traps->num_traps; boxes->chunks.base = (cairo_box_t *) traps->traps; - boxes->chunks.count = traps->num_traps; boxes->chunks.size = traps->num_traps; if (antialias != CAIRO_ANTIALIAS_NONE) { - for (i = 0; i < traps->num_traps; i++) { + for (i = j = 0; i < traps->num_traps; i++) { /* Note the traps and boxes alias so we need to take the local copies first. */ cairo_fixed_t x1 = traps->traps[i].left.p1.x; cairo_fixed_t x2 = traps->traps[i].right.p1.x; cairo_fixed_t y1 = traps->traps[i].top; cairo_fixed_t y2 = traps->traps[i].bottom; - boxes->chunks.base[i].p1.x = x1; - boxes->chunks.base[i].p1.y = y1; - boxes->chunks.base[i].p2.x = x2; - boxes->chunks.base[i].p2.y = y2; + if (x1 == x2 || y1 == y2) + continue; + + boxes->chunks.base[j].p1.x = x1; + boxes->chunks.base[j].p1.y = y1; + boxes->chunks.base[j].p2.x = x2; + boxes->chunks.base[j].p2.y = y2; + j++; if (boxes->is_pixel_aligned) { boxes->is_pixel_aligned = @@ -3023,7 +3022,7 @@ _boxes_for_traps (cairo_boxes_t *boxes, } else { boxes->is_pixel_aligned = TRUE; - for (i = 0; i < traps->num_traps; i++) { + for (i = j = 0; i < traps->num_traps; i++) { /* Note the traps and boxes alias so we need to take the local copies first. */ cairo_fixed_t x1 = traps->traps[i].left.p1.x; cairo_fixed_t x2 = traps->traps[i].right.p1.x; @@ -3031,12 +3030,18 @@ _boxes_for_traps (cairo_boxes_t *boxes, cairo_fixed_t y2 = traps->traps[i].bottom; /* round down here to match Pixman's behavior when using traps. */ - boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1); - boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1); - boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2); - boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2); + boxes->chunks.base[j].p1.x = _cairo_fixed_round_down (x1); + boxes->chunks.base[j].p1.y = _cairo_fixed_round_down (y1); + boxes->chunks.base[j].p2.x = _cairo_fixed_round_down (x2); + boxes->chunks.base[j].p2.y = _cairo_fixed_round_down (y2); + + j += (boxes->chunks.base[j].p1.x != boxes->chunks.base[j].p2.x && + boxes->chunks.base[j].p1.y != boxes->chunks.base[j].p2.y); } } + + boxes->num_boxes = j; + boxes->chunks.count = j; } static cairo_status_t @@ -3209,6 +3214,9 @@ _clip_and_composite_boxes (cairo_xcb_surface_t *dst, clip = _cairo_clip_copy (extents->clip); clip = _cairo_clip_intersect_boxes (clip, boxes); + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias); _cairo_clip_path_destroy (clip->path); @@ -4561,6 +4569,9 @@ _cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection, const uint8_t *d; uint8_t *new, *n; + if (c == 0) + break; + new = malloc (c); if (unlikely (new == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -4589,6 +4600,9 @@ _cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection, const uint32_t *d; uint32_t *new, *n; + if (c == 0) + break; + new = malloc (4 * c); if (unlikely (new == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -4979,36 +4993,36 @@ _create_convolution_coef (double *convolution_matrix, return NULL; if (is_x_pass) { - length = col; + length = col; values = _cairo_malloc_ab (length + 2, sizeof (xcb_render_fixed_t)); if (values == NULL) return NULL; - v = col; - values[0] = _cairo_fixed_16_16_from_double (v); - values[1] = _cairo_fixed_16_16_from_double (1.0); + v = col; + values[0] = _cairo_fixed_16_16_from_double (v); + values[1] = _cairo_fixed_16_16_from_double (1.0); coef = _cairo_malloc_ab (length, sizeof (double)); if (coef == NULL) { free (values); return NULL; } memset (coef, 0, sizeof (double) * length); - compute_x_coef_to_double (convolution_matrix, row, col, coef); + compute_x_coef_to_double (convolution_matrix, row, col, coef); } else { - length = row; + length = row; values = _cairo_malloc_ab (length + 2, sizeof (xcb_render_fixed_t)); if (values == NULL) return NULL; - values[0] = _cairo_fixed_16_16_from_double (1.0); - v = row; - values[1] = _cairo_fixed_16_16_from_double (v); + values[0] = _cairo_fixed_16_16_from_double (1.0); + v = row; + values[1] = _cairo_fixed_16_16_from_double (v); coef = _cairo_malloc_ab (length, sizeof (double)); if (coef == NULL) { free (values); return NULL; } memset (coef, 0, sizeof (double) * length); - compute_y_coef_to_double (convolution_matrix, row, col, coef); + compute_y_coef_to_double (convolution_matrix, row, col, coef); } for (i = 0; i < length; i++) @@ -5102,7 +5116,7 @@ _cairo_xcb_gaussian_filter (cairo_xcb_surface_t *source, pixmap, xrender_format, 0, 0); - _cairo_xcb_connection_free_pixmap (source->connection, pixmap); + _cairo_xcb_connection_free_pixmap (source->connection, pixmap); } if (width != src_width || height != src_height) { diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index 7b74027d1..41e16f0db 100755..100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -383,13 +383,10 @@ _get_image (cairo_xcb_surface_t *surface, } } - status = _cairo_xcb_connection_get_image (connection, - surface->drawable, - x, y, - width, height, - &reply); - if (unlikely (status)) - goto FAIL; + reply =_cairo_xcb_connection_get_image (connection, + surface->drawable, + x, y, + width, height); if (reply == NULL && ! surface->owns_pixmap) { /* xcb_get_image_t from a window is dangerous because it can @@ -423,15 +420,11 @@ _get_image (cairo_xcb_surface_t *surface, _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc); - status = _cairo_xcb_connection_get_image (connection, - pixmap, - 0, 0, - width, height, - &reply); + reply = _cairo_xcb_connection_get_image (connection, + pixmap, + 0, 0, + width, height); _cairo_xcb_connection_free_pixmap (connection, pixmap); - - if (unlikely (status)) - goto FAIL; } if (unlikely (reply == NULL)) { @@ -543,9 +536,9 @@ static void _cairo_xcb_surface_get_font_options (void *abstract_surface, cairo_font_options_t *options) { - /* XXX copy from xlib */ - _cairo_font_options_init_default (options); - _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON); + cairo_xcb_surface_t *surface = abstract_surface; + + *options = *_cairo_xcb_screen_get_font_options (surface->screen); } static cairo_status_t @@ -1163,8 +1156,8 @@ _cairo_xcb_surface_glyphs (void *abstract_surface, if (shadow_type != CAIRO_SHADOW_INSET) status = _cairo_surface_shadow_glyphs (surface, op, source, - scaled_font, - glyphs, num_glyphs, + scaled_font, + glyphs, num_glyphs, clip, &source->shadow); if (unlikely (status)) { @@ -1190,8 +1183,8 @@ _cairo_xcb_surface_glyphs (void *abstract_surface, if (shadow_type == CAIRO_SHADOW_INSET) status = _cairo_surface_shadow_glyphs (surface, op, source, - scaled_font, - glyphs, num_glyphs, + scaled_font, + glyphs, num_glyphs, clip, &source->shadow); cairo_device_release (surface->device); @@ -1604,7 +1597,7 @@ cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface, } - if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) { + if ( !_cairo_surface_is_xcb(abstract_surface)) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); return; @@ -1658,7 +1651,7 @@ cairo_xcb_surface_set_drawable (cairo_surface_t *abstract_surface, } - if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) { + if ( !_cairo_surface_is_xcb(abstract_surface)) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); return; diff --git a/src/cairo-xcb.h b/src/cairo-xcb.h index e321d8482..e321d8482 100755..100644 --- a/src/cairo-xcb.h +++ b/src/cairo-xcb.h diff --git a/src/cairo-xlib-core-compositor.c b/src/cairo-xlib-core-compositor.c index 9398079b4..5babcc81b 100755..100644 --- a/src/cairo-xlib-core-compositor.c +++ b/src/cairo-xlib-core-compositor.c @@ -292,9 +292,7 @@ render_boxes (cairo_xlib_surface_t *dst, const cairo_pattern_t *pattern, cairo_boxes_t *boxes) { - double pad; - - if (_cairo_pattern_analyze_filter (pattern, &pad) != CAIRO_FILTER_NEAREST) + if (pattern->filter != CAIRO_FILTER_NEAREST) return fallback_boxes (dst, pattern, boxes); switch (pattern->extend) { diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c index cc82b3a99..88efe9c0e 100755..100644 --- a/src/cairo-xlib-display.c +++ b/src/cairo-xlib-display.c @@ -292,7 +292,7 @@ _cairo_xlib_device_create (Display *dpy) * * 1. The original bug that led to the buggy_repeat * workaround. This was a bug that Owen Taylor investigated, - * understood well, and characterized against carious X + * understood well, and characterized against various X * servers. Confirmed X servers with this bug include: * * "XFree86" <= 40500000 @@ -484,7 +484,7 @@ _cairo_xlib_display_get_xrender_format_for_pixman(cairo_xlib_display_t *display, #undef MASK /* XXX caching? */ - return XRenderFindFormat(dpy, mask, &tmpl, 1); + return XRenderFindFormat(dpy, mask, &tmpl, 0); } XRenderPictFormat * @@ -493,12 +493,6 @@ _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display, { XRenderPictFormat *xrender_format; -#if ! ATOMIC_OP_NEEDS_MEMORY_BARRIER - xrender_format = display->cached_xrender_formats[format]; - if (likely (xrender_format != NULL)) - return xrender_format; -#endif - xrender_format = display->cached_xrender_formats[format]; if (xrender_format == NULL) { int pict_format = PictStandardNUM; @@ -576,7 +570,7 @@ _cairo_xlib_display_has_gradients (cairo_device_t *device) * * Restricts all future Xlib surfaces for this devices to the specified version * of the RENDER extension. This function exists solely for debugging purpose. - * It let's you find out how cairo would behave with an older version of + * It lets you find out how cairo would behave with an older version of * the RENDER extension. * * Use the special values -1 and -1 for disabling the RENDER extension. diff --git a/src/cairo-xlib-fallback-compositor.c b/src/cairo-xlib-fallback-compositor.c index ed2845db5..ed2845db5 100755..100644 --- a/src/cairo-xlib-fallback-compositor.c +++ b/src/cairo-xlib-fallback-compositor.c diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h index 4fd725f93..0f2f2e1fa 100755..100644 --- a/src/cairo-xlib-private.h +++ b/src/cairo-xlib-private.h @@ -37,8 +37,8 @@ #ifndef CAIRO_XLIB_PRIVATE_H #define CAIRO_XLIB_PRIVATE_H -#include "cairo-xlib.h" #include "cairo-xlib-xrender-private.h" +#include "cairo-xlib.h" #include "cairo-compiler-private.h" #include "cairo-device-private.h" @@ -81,7 +81,7 @@ struct _cairo_xlib_display { int render_major; int render_minor; - XRenderPictFormat *cached_xrender_formats[CAIRO_FORMAT_RGB16_565 + 1]; + XRenderPictFormat *cached_xrender_formats[CAIRO_FORMAT_RGB30 + 1]; int force_precision; @@ -373,6 +373,8 @@ _cairo_xlib_font_close (cairo_xlib_font_t *font); #define CAIRO_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 6) #define CAIRO_RENDER_HAS_FILTERS(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 6) +#define CAIRO_RENDER_HAS_FILTER_GOOD(surface) FALSE +#define CAIRO_RENDER_HAS_FILTER_BEST(surface) FALSE #define CAIRO_RENDER_HAS_EXTENDED_REPEAT(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 10) #define CAIRO_RENDER_HAS_GRADIENTS(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 10) diff --git a/src/cairo-xlib-render-compositor.c b/src/cairo-xlib-render-compositor.c index 05cde708b..82ed26af7 100755..100644 --- a/src/cairo-xlib-render-compositor.c +++ b/src/cairo-xlib-render-compositor.c @@ -51,6 +51,7 @@ #include "cairo-image-surface-private.h" #include "cairo-list-inline.h" #include "cairo-pattern-private.h" +#include "cairo-pixman-private.h" #include "cairo-traps-private.h" #include "cairo-tristrip-private.h" @@ -99,7 +100,7 @@ set_clip_region (void *_surface, _cairo_xlib_surface_ensure_picture (surface); if (region != NULL) { - XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))]; + XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)]; XRectangle *rects = stack_rects; int n_rects, i; @@ -1295,6 +1296,9 @@ _cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display, unsigned char *d; unsigned char *new, *n; + if (c == 0) + break; + new = malloc (c); if (!new) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -1320,6 +1324,9 @@ _cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display, const uint32_t *d; uint32_t *new, *n; + if (c == 0) + break; + new = malloc (4 * c); if (unlikely (new == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -1478,14 +1485,14 @@ _emit_glyphs_chunk (cairo_xlib_display_t *display, */ if (_start_new_glyph_elt (j, &glyphs[i])) { if (j) { - elts[nelt].nchars = n; - nelt++; - n = 0; + elts[nelt].nchars = n; + nelt++; + n = 0; } elts[nelt].chars = char8 + size * j; elts[nelt].glyphset = info->glyphset; - elts[nelt].xOff = glyphs[i].i.x - dst_x; - elts[nelt].yOff = glyphs[i].i.y - dst_y; + elts[nelt].xOff = glyphs[i].i.x; + elts[nelt].yOff = glyphs[i].i.y; } switch (width) { @@ -1588,7 +1595,7 @@ composite_glyphs (void *surface, cairo_xlib_display_t *display = dst->display; cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; cairo_scaled_glyph_t *glyph; - cairo_fixed_t x = 0, y = 0; + cairo_fixed_t x = dst_x, y = dst_y; cairo_xlib_font_glyphset_t *glyphset = NULL, *this_glyphset_info; unsigned long max_index = 0; @@ -1606,11 +1613,6 @@ composite_glyphs (void *surface, op = _render_operator (op), _cairo_xlib_surface_ensure_picture (dst); - -#if CAIRO_HAS_TG_SURFACE - _cairo_scaled_font_freeze_cache(info->font); -#endif - for (i = 0; i < num_glyphs; i++) { int this_x, this_y; int old_width; @@ -1620,7 +1622,7 @@ composite_glyphs (void *surface, CAIRO_SCALED_GLYPH_INFO_METRICS, &glyph); if (unlikely (status)) - goto done; + return status; this_x = _cairo_lround (glyphs[i].d.x); this_y = _cairo_lround (glyphs[i].d.y); @@ -1629,7 +1631,7 @@ composite_glyphs (void *surface, if (glyph->dev_private_key != display) { status = _cairo_xlib_surface_add_glyph (display, info->font, &glyph); if (unlikely (status)) - goto done; + return status; } this_glyphset_info = glyph->dev_private; @@ -1681,7 +1683,7 @@ composite_glyphs (void *surface, op, src, src_x, src_y, num_elts, old_width, glyphset); if (unlikely (status)) - goto done; + return status; glyphs += i; num_glyphs -= i; @@ -1726,11 +1728,6 @@ composite_glyphs (void *surface, num_elts, width, glyphset); } -done: -#if CAIRO_HAS_TG_SURFACE - _cairo_scaled_font_thaw_cache(info->font); -#endif - return status; } @@ -2001,7 +1998,7 @@ _cairo_xlib_traps_compositor_get (void) compositor.check_composite = check_composite; compositor.composite = composite; compositor.lerp = lerp; - //FIXME: + // FIXME: compositor.lerp_color_glyph = lerp; //compositor.check_composite_boxes = check_composite_boxes; compositor.composite_boxes = composite_boxes; diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c index 119603e9a..119603e9a 100755..100644 --- a/src/cairo-xlib-screen.c +++ b/src/cairo-xlib-screen.c diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c index 4e9babd79..d5752ba99 100755..100644 --- a/src/cairo-xlib-source.c +++ b/src/cairo-xlib-source.c @@ -288,13 +288,14 @@ render_pattern (cairo_xlib_surface_t *dst, cairo_rectangle_int_t map_extents; src = (cairo_xlib_surface_t *) - _cairo_surface_create_similar_scratch (&dst->base, - is_mask ? CAIRO_CONTENT_ALPHA : CAIRO_CONTENT_COLOR_ALPHA, - extents->width, - extents->height); + _cairo_surface_create_scratch (&dst->base, + is_mask ? CAIRO_CONTENT_ALPHA : CAIRO_CONTENT_COLOR_ALPHA, + extents->width, + extents->height, + NULL); if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) { cairo_surface_destroy (&src->base); - return None; + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } map_extents = *extents; @@ -750,10 +751,11 @@ subsurface_source (cairo_xlib_surface_t *dst, source = &src->embedded_source; } else { src = (cairo_xlib_surface_t *) - _cairo_surface_create_similar_scratch (&dst->base, - sub->base.content, - sub->extents.width, - sub->extents.height); + _cairo_surface_create_scratch (&dst->base, + sub->base.content, + sub->extents.width, + sub->extents.height, + NULL); if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) { cairo_surface_destroy (&src->base); return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); @@ -867,11 +869,14 @@ recording_pattern_get_surface (const cairo_pattern_t *pattern) cairo_surface_t *surface; surface = ((const cairo_surface_pattern_t *) pattern)->surface; + if (_cairo_surface_is_paginated (surface)) - surface = _cairo_paginated_surface_get_recording (surface); + return cairo_surface_reference (_cairo_paginated_surface_get_recording (surface)); + if (_cairo_surface_is_snapshot (surface)) - surface = _cairo_surface_snapshot_get_target (surface); - return surface; + return _cairo_surface_snapshot_get_target (surface); + + return cairo_surface_reference (surface); } static cairo_surface_t * @@ -883,6 +888,7 @@ record_source (cairo_xlib_surface_t *dst, int *src_x, int *src_y) { cairo_xlib_surface_t *src; + cairo_surface_t *recording; cairo_matrix_t matrix, m; cairo_status_t status; cairo_rectangle_int_t upload, limit; @@ -898,19 +904,22 @@ record_source (cairo_xlib_surface_t *dst, } src = (cairo_xlib_surface_t *) - _cairo_surface_create_similar_scratch (&dst->base, - pattern->surface->content, - upload.width, - upload.height); + _cairo_surface_create_scratch (&dst->base, + pattern->surface->content, + upload.width, + upload.height, + NULL); if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) { cairo_surface_destroy (&src->base); return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); } cairo_matrix_init_translate (&matrix, upload.x, upload.y); - status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (&pattern->base), + recording = recording_pattern_get_surface (&pattern->base), + status = _cairo_recording_surface_replay_with_clip (recording, &matrix, &src->base, NULL); + cairo_surface_destroy (recording); if (unlikely (status)) { cairo_surface_destroy (&src->base); return _cairo_surface_create_in_error (status); @@ -993,6 +1002,9 @@ surface_source (cairo_xlib_surface_t *dst, if (pattern->base.extend == CAIRO_EXTEND_NONE) { if (! _cairo_rectangle_intersect (&upload, &limit)) return alpha_source (dst, 0); + } else if (pattern->base.extend == CAIRO_EXTEND_PAD) { + if (! _cairo_rectangle_intersect (&upload, &limit)) + upload = limit; } else { if (upload.x < limit.x || upload.x + upload.width > limit.x + limit.width || @@ -1005,14 +1017,15 @@ surface_source (cairo_xlib_surface_t *dst, } xsrc = (cairo_xlib_surface_t *) - _cairo_surface_create_similar_scratch (&dst->base, - src->content, - upload.width, - upload.height); + _cairo_surface_create_scratch (&dst->base, + src->content, + upload.width, + upload.height, + NULL); if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) { cairo_surface_destroy (src); cairo_surface_destroy (&xsrc->base); - return None; + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } if (_cairo_surface_is_image (src)) { @@ -1093,17 +1106,22 @@ pattern_is_supported (cairo_xlib_display_t *display, return FALSE; } - if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display)) { - if (!_cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL)) - return FALSE; - } - - if (! CAIRO_RENDER_HAS_FILTERS (display)) { - /* No filters implies no transforms, so we optimise away BILINEAR */ + switch (pattern->filter) { + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + return CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display) || + _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL); + case CAIRO_FILTER_GOOD: + return CAIRO_RENDER_HAS_FILTER_GOOD (display); + case CAIRO_FILTER_BEST: + return CAIRO_RENDER_HAS_FILTER_BEST (display); + case CAIRO_FILTER_BILINEAR: + case CAIRO_FILTER_GAUSSIAN: + default: + return CAIRO_RENDER_HAS_FILTERS (display); } - - return TRUE; } + cairo_surface_t * _cairo_xlib_source_create_for_pattern (cairo_surface_t *_dst, const cairo_pattern_t *pattern, diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h index 87db6962b..83d9b63cc 100755..100644 --- a/src/cairo-xlib-surface-private.h +++ b/src/cairo-xlib-surface-private.h @@ -33,9 +33,9 @@ #ifndef CAIRO_XLIB_SURFACE_PRIVATE_H #define CAIRO_XLIB_SURFACE_PRIVATE_H +#include "cairo-xlib-xrender-private.h" #include "cairo-xlib.h" #include "cairo-xlib-private.h" -#include "cairo-xlib-xrender-private.h" #include "cairo-surface-private.h" #include "cairo-surface-backend-private.h" diff --git a/src/cairo-xlib-surface-shm.c b/src/cairo-xlib-surface-shm.c index fa7d3eb9b..9b4dea5e5 100755..100644 --- a/src/cairo-xlib-surface-shm.c +++ b/src/cairo-xlib-surface-shm.c @@ -453,7 +453,7 @@ static void send_event(cairo_xlib_display_t *display, display->shm->last_event = ev.serial; } -static void sync (cairo_xlib_display_t *display) +static void _cairo_xlib_display_sync (cairo_xlib_display_t *display) { cairo_xlib_shm_info_t *info; struct pqueue *pq = &display->shm->info; @@ -670,6 +670,7 @@ _cairo_xlib_shm_surface_flush (void *abstract_surface, unsigned flags) cairo_xlib_shm_surface_t *shm = abstract_surface; cairo_xlib_display_t *display; Display *dpy; + _XQEvent *qev; cairo_status_t status; if (shm->active == 0) @@ -694,6 +695,10 @@ _cairo_xlib_shm_surface_flush (void *abstract_surface, unsigned flags) while (! seqno_passed (shm->active, LastKnownRequestProcessed (dpy))) { LockDisplay(dpy); _XReadEvents(dpy); + while (dpy->head) { + qev = dpy->head; + _XDeq (dpy, NULL, qev); + } UnlockDisplay(dpy); } @@ -893,7 +898,7 @@ _cairo_xlib_surface_update_shm (cairo_xlib_surface_t *surface) } if (damage->region) { - XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))]; + XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)]; XRectangle *rects = stack_rects; cairo_rectangle_int_t r; int n_rects, i; @@ -949,7 +954,7 @@ _cairo_xlib_surface_update_shm (cairo_xlib_surface_t *surface) XChangeGC (display->display, gc, GCSubwindowMode, &gcv); } - sync (display); + _cairo_xlib_display_sync (display); shm->active = 0; shm->idle--; @@ -1081,7 +1086,7 @@ _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface) TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__, damage->region ? cairo_region_num_rectangles (damage->region) : 0)); if (damage->status == CAIRO_STATUS_SUCCESS && damage->region) { - XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))]; + XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)]; XRectangle *rects = stack_rects; cairo_rectangle_int_t r; int n_rects, i; diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 2fb29e3d4..8128ebc05 100755..100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -60,6 +60,7 @@ #include "cairo-image-surface-private.h" #include "cairo-list-inline.h" #include "cairo-pattern-private.h" +#include "cairo-pixman-private.h" #include "cairo-region-private.h" #include "cairo-scaled-font-private.h" #include "cairo-surface-snapshot-private.h" @@ -385,14 +386,14 @@ _cairo_xlib_surface_finish (void *abstract_surface) cairo_status_t status; cairo_xlib_display_t *display; - X_DEBUG ((display->display, "finish (drawable=%x)", (unsigned int) surface->drawable)); - cairo_list_del (&surface->link); status = _cairo_xlib_display_acquire (surface->base.device, &display); if (unlikely (status)) return status; + X_DEBUG ((display->display, "finish (drawable=%x)", (unsigned int) surface->drawable)); + if (surface->embedded_source.picture) XRenderFreePicture (display->display, surface->embedded_source.picture); if (surface->picture) diff --git a/src/cairo-xlib-visual.c b/src/cairo-xlib-visual.c index d9aac44ca..863822eeb 100755..100644 --- a/src/cairo-xlib-visual.c +++ b/src/cairo-xlib-visual.c @@ -40,6 +40,7 @@ #include "cairo-xlib-private.h" #include "cairo-error-private.h" +#include "cairo-list-inline.h" /* A perceptual distance metric between two colors. No sqrt needed * since the square of the distance is still a valid metric. */ @@ -85,6 +86,7 @@ _cairo_xlib_visual_info_create (Display *dpy, if (unlikely (info == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); + cairo_list_init (&info->link); info->visualid = visualid; /* Allocate a gray ramp and a color cube. @@ -185,6 +187,7 @@ void _cairo_xlib_visual_info_destroy (cairo_xlib_visual_info_t *info) { /* No need for XFreeColors() whilst using DefaultColormap */ + _cairo_list_del (&info->link); free (info); } diff --git a/src/cairo-xlib-xcb-surface.c b/src/cairo-xlib-xcb-surface.c index 9c0d4b413..af3e15578 100755..100644 --- a/src/cairo-xlib-xcb-surface.c +++ b/src/cairo-xlib-xcb-surface.c @@ -519,21 +519,6 @@ cairo_xlib_surface_create (Display *dpy, width, height)); } -cairo_surface_t * -cairo_xlib_surface_create_for_bitmap (Display *dpy, - Pixmap bitmap, - Screen *scr, - int width, - int height) -{ - return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, NULL, - cairo_xcb_surface_create_for_bitmap (XGetXCBConnection (dpy), - (xcb_screen_t *) scr, - bitmap, - width, height)); -} - -#if CAIRO_HAS_XLIB_XRENDER_SURFACE static xcb_screen_t * _cairo_xcb_screen_from_root (xcb_connection_t *connection, xcb_window_t id) @@ -548,6 +533,24 @@ _cairo_xcb_screen_from_root (xcb_connection_t *connection, return NULL; } + +cairo_surface_t * +cairo_xlib_surface_create_for_bitmap (Display *dpy, + Pixmap bitmap, + Screen *scr, + int width, + int height) +{ + xcb_connection_t *connection = XGetXCBConnection (dpy); + xcb_screen_t *screen = _cairo_xcb_screen_from_root (connection, (xcb_window_t) scr->root); + return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, NULL, + cairo_xcb_surface_create_for_bitmap (connection, + screen, + bitmap, + width, height)); +} + +#if CAIRO_HAS_XLIB_XRENDER_SURFACE cairo_surface_t * cairo_xlib_surface_create_with_xrender_format (Display *dpy, Drawable drawable, diff --git a/src/cairo-xlib-xrender-private.h b/src/cairo-xlib-xrender-private.h index bf3199c4c..90769467b 100755..100644 --- a/src/cairo-xlib-xrender-private.h +++ b/src/cairo-xlib-xrender-private.h @@ -96,6 +96,10 @@ __attribute__((__unused__)) static void _void_consume_free (Display *p, XID #define PictOpBlendMaximum 0x3e #endif +#if !HAVE_XRENDERCREATESOLIDFILL +#define XRenderCreateSolidFill _int_consume +#endif + #if !HAVE_XRENDERCREATELINEARGRADIENT #define XRenderCreateLinearGradient _int_consume diff --git a/src/cairo-xlib-xrender.h b/src/cairo-xlib-xrender.h index b34b057de..b34b057de 100755..100644 --- a/src/cairo-xlib-xrender.h +++ b/src/cairo-xlib-xrender.h diff --git a/src/cairo-xlib.h b/src/cairo-xlib.h index ecf8d6c86..ecf8d6c86 100755..100644 --- a/src/cairo-xlib.h +++ b/src/cairo-xlib.h diff --git a/src/cairo-xml-surface.c b/src/cairo-xml-surface.c index 777d47089..6dbafdba2 100755..100644 --- a/src/cairo-xml-surface.c +++ b/src/cairo-xml-surface.c @@ -459,19 +459,79 @@ to_xml (cairo_xml_surface_t *surface) } static cairo_status_t +_cairo_xml_surface_emit_clip_boxes (cairo_xml_surface_t *surface, + const cairo_clip_t *clip) +{ + cairo_box_t *box; + cairo_xml_t *xml; + int n; + + if (clip->num_boxes == 0) + return CAIRO_STATUS_SUCCESS; + + /* skip the trivial clip covering the surface extents */ + if (surface->width >= 0 && surface->height >= 0 && clip->num_boxes == 1) { + box = &clip->boxes[0]; + if (box->p1.x <= 0 && box->p1.y <= 0 && + box->p2.x - box->p1.x >= _cairo_fixed_from_double (surface->width) && + box->p2.y - box->p1.y >= _cairo_fixed_from_double (surface->height)) + { + return CAIRO_STATUS_SUCCESS; + } + } + + xml = to_xml (surface); + + _cairo_xml_printf (xml, "<clip>"); + _cairo_xml_indent (xml, 2); + + _cairo_xml_printf (xml, "<path>"); + _cairo_xml_indent (xml, 2); + for (n = 0; n < clip->num_boxes; n++) { + box = &clip->boxes[n]; + + _cairo_xml_printf_start (xml, "%f %f m", + _cairo_fixed_to_double (box->p1.x), + _cairo_fixed_to_double (box->p1.y)); + _cairo_xml_printf_continue (xml, " %f %f l", + _cairo_fixed_to_double (box->p2.x), + _cairo_fixed_to_double (box->p1.y)); + _cairo_xml_printf_continue (xml, " %f %f l", + _cairo_fixed_to_double (box->p2.x), + _cairo_fixed_to_double (box->p2.y)); + _cairo_xml_printf_continue (xml, " %f %f l", + _cairo_fixed_to_double (box->p1.x), + _cairo_fixed_to_double (box->p2.y)); + _cairo_xml_printf_end (xml, " h"); + } + _cairo_xml_indent (xml, -2); + _cairo_xml_printf (xml, "</path>"); + _cairo_xml_emit_double (xml, "tolerance", 1.0); + _cairo_xml_emit_string (xml, "antialias", + _antialias_to_string (CAIRO_ANTIALIAS_NONE)); + _cairo_xml_emit_string (xml, "fill-rule", + _fill_rule_to_string (CAIRO_FILL_RULE_WINDING)); + + _cairo_xml_indent (xml, -2); + _cairo_xml_printf (xml, "</clip>"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t _cairo_xml_surface_emit_clip_path (cairo_xml_surface_t *surface, - cairo_clip_path_t *clip_path) + const cairo_clip_path_t *clip_path) { cairo_box_t box; cairo_status_t status; cairo_xml_t *xml; - if (clip_path->prev != NULL) { - status = _cairo_xml_surface_emit_clip_path (surface, clip_path->prev); - if (unlikely (status)) - return status; - } + if (clip_path == NULL) + return CAIRO_STATUS_SUCCESS; + status = _cairo_xml_surface_emit_clip_path (surface, clip_path->prev); + if (unlikely (status)) + return status; /* skip the trivial clip covering the surface extents */ if (surface->width >= 0 && surface->height >= 0 && @@ -507,9 +567,15 @@ static cairo_status_t _cairo_xml_surface_emit_clip (cairo_xml_surface_t *surface, const cairo_clip_t *clip) { + cairo_status_t status; + if (clip == NULL) return CAIRO_STATUS_SUCCESS; + status = _cairo_xml_surface_emit_clip_boxes (surface, clip); + if (unlikely (status)) + return status; + return _cairo_xml_surface_emit_clip_path (surface, clip->path); } diff --git a/src/cairo-xml.h b/src/cairo-xml.h index 9ae76e90a..9ae76e90a 100755..100644 --- a/src/cairo-xml.h +++ b/src/cairo-xml.h diff --git a/src/cairo.c b/src/cairo.c index 3a6607b1b..983f02cea 100755..100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -152,7 +152,9 @@ static const cairo_t _cairo_nil[] = { DEFINE_NIL_CONTEXT (CAIRO_STATUS_DEVICE_TYPE_MISMATCH), DEFINE_NIL_CONTEXT (CAIRO_STATUS_DEVICE_ERROR), DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_MESH_CONSTRUCTION), - DEFINE_NIL_CONTEXT (CAIRO_STATUS_DEVICE_FINISHED) + DEFINE_NIL_CONTEXT (CAIRO_STATUS_DEVICE_FINISHED), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_JBIG2_GLOBAL_MISSING) + }; COMPILE_TIME_ASSERT (ARRAY_LENGTH (_cairo_nil) == CAIRO_STATUS_LAST_STATUS - 1); @@ -228,6 +230,8 @@ cairo_create (cairo_surface_t *target) return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER)); if (unlikely (target->status)) return _cairo_create_in_error (target->status); + if (unlikely (target->finished)) + return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); if (target->backend->create_context == NULL) return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR)); @@ -1635,7 +1639,6 @@ cairo_arc (cairo_t *cr, angle2 += 2 * M_PI; angle2 += angle1; } - status = cr->backend->arc (cr, xc, yc, radius, angle1, angle2, TRUE); if (unlikely (status)) _cairo_set_error (cr, status); @@ -1868,6 +1871,53 @@ cairo_rectangle (cairo_t *cr, _cairo_set_error (cr, status); } +/** + * cairo_rounded_rectangle: + * @cr: a cairo context + * @x: the X coordinate of the top left corner of the rectangle + * @y: the Y coordinate to the top left corner of the rectangle + * @width: the width of the rectangle + * @height: the height of the rectangle + * @r_top_left: top left corner radius + * @r_top_right: top right corner radius + * @r_bottom_left: bottom left corner radius + * @r_bottom_left: top left corner radius + * + * Adds a closed sub-path roundedrectangle of the given size to the current + * path at position (@x, @y) in user-space coordinates. + * + * This function is logically equivalent to: + * <informalexample><programlisting> + * cairo_move_to (cr, x, y + r_top_left) + * cairo_rel_curve_to (cr, ....) + * cairo_rel_line_to (cr, ....) + * cairo_rel_curve_to (cr, ....) + * cairo_line_to (cr, ....) + * cairo_rel_curve_to (cr, ....) + * cairo_close_path (cr) + * </programlisting></informalexample> + * + * Since: 1.12 + **/ +void +cairo_rounded_rectangle (cairo_t *cr, + double x, double y, + double width, double height, + double r_top_left, double r_top_right, + double r_bottom_left, double r_bottom_right) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->rounded_rectangle (cr, x, y, width, height, + r_top_left, r_top_right, + r_bottom_left, r_bottom_right); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + #if 0 /* XXX: NYI */ void diff --git a/src/cairo.h b/src/cairo.h index 2b03e77ec..c1649dbe5 100755..100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -290,6 +290,8 @@ typedef struct _cairo_user_data_key { * cairo_mesh_pattern_begin_patch()/cairo_mesh_pattern_end_patch() * pair (Since 1.12) * @CAIRO_STATUS_DEVICE_FINISHED: target device has been finished (Since 1.12) + * @CAIRO_STATUS_JBIG2_GLOBAL_MISSING: %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID has been used on at least one image + * but no image provided %CAIRO_MIME_TYPE_JBIG2_GLOBAL (Since 1.14) * @CAIRO_STATUS_LAST_STATUS: this is a special value indicating the number of * status values defined in this enumeration. When using this value, note * that the version of cairo at run-time may have additional status values @@ -345,6 +347,7 @@ typedef enum _cairo_status { CAIRO_STATUS_DEVICE_ERROR, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION, CAIRO_STATUS_DEVICE_FINISHED, + CAIRO_STATUS_JBIG2_GLOBAL_MISSING, CAIRO_STATUS_LAST_STATUS } cairo_status_t; @@ -892,6 +895,13 @@ cairo_rectangle (cairo_t *cr, double x, double y, double width, double height); +cairo_public void +cairo_rounded_rectangle (cairo_t *cr, + double x, double y, + double width, double height, + double r_top_left, double r_top_right, + double r_bottom_left, double r_bottom_right); + /* XXX: NYI cairo_public void cairo_stroke_to_path (cairo_t *cr); @@ -1341,7 +1351,7 @@ typedef enum _cairo_hint_metrics { /** * cairo_font_color_t: * @CAIRO_FONT_COLOR_DEFAULT: default color, if the font has color, - * use font's color, otherwise, use user specified, since 1.12.14 + * use font's color, otherwise, use user specified, since 1.12.14 * @CAIRO_FONT_COLOR_USER: always uses user's color, since 1.0 * * When rendering text, specifies whether to use user's color set @@ -1349,12 +1359,12 @@ typedef enum _cairo_hint_metrics { * * Since: 1.4 **/ - typedef enum _cairo_font_color { - CAIRO_FONT_COLOR_DEFAULT, - CAIRO_FONT_COLOR_USER - } cairo_font_color_t; +typedef enum _cairo_font_color { + CAIRO_FONT_COLOR_DEFAULT, + CAIRO_FONT_COLOR_USER +} cairo_font_color_t; - /** +/** * cairo_font_options_t: * * An opaque structure holding all options that are used when @@ -1426,8 +1436,7 @@ cairo_font_options_get_hint_metrics (const cairo_font_options_t *options); cairo_public void cairo_font_options_set_font_color (cairo_font_options_t *options, -cairo_font_color_t font_color); - + cairo_font_color_t font_color); cairo_public cairo_font_color_t cairo_font_options_get_font_color (const cairo_font_options_t *options); @@ -2095,6 +2104,7 @@ typedef struct cairo_path { cairo_status_t status; cairo_path_data_t *data; int num_data; + unsigned int is_convex : 1; } cairo_path_t; cairo_public cairo_path_t * @@ -2231,6 +2241,15 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target, double width, double height); +/** + * cairo_surface_observer_mode_t: + * @CAIRO_SURFACE_OBSERVER_NORMAL: no recording is done + * @CAIRO_SURFACE_OBSERVER_RECORD_OPERATIONS: operations are recorded + * + * Whether operations should be recorded. + * + * Since: 1.12 + **/ typedef enum { CAIRO_SURFACE_OBSERVER_NORMAL = 0, CAIRO_SURFACE_OBSERVER_RECORD_OPERATIONS = 0x1 @@ -2405,8 +2424,7 @@ typedef enum _cairo_surface_type { CAIRO_SURFACE_TYPE_XML, CAIRO_SURFACE_TYPE_SKIA, CAIRO_SURFACE_TYPE_SUBSURFACE, - CAIRO_SURFACE_TYPE_COGL, - CAIRO_SURFACE_TYPE_TG, + CAIRO_SURFACE_TYPE_COGL } cairo_surface_type_t; cairo_public cairo_surface_type_t @@ -2443,6 +2461,9 @@ cairo_surface_set_user_data (cairo_surface_t *surface, #define CAIRO_MIME_TYPE_JP2 "image/jp2" #define CAIRO_MIME_TYPE_URI "text/x-uri" #define CAIRO_MIME_TYPE_UNIQUE_ID "application/x-cairo.uuid" +#define CAIRO_MIME_TYPE_JBIG2 "application/x-cairo.jbig2" +#define CAIRO_MIME_TYPE_JBIG2_GLOBAL "application/x-cairo.jbig2-global" +#define CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID "application/x-cairo.jbig2-global-id" cairo_public void cairo_surface_get_mime_data (cairo_surface_t *surface, @@ -2480,6 +2501,16 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, int height); cairo_public void +cairo_surface_set_device_scale (cairo_surface_t *surface, + double x_scale, + double y_scale); + +cairo_public void +cairo_surface_get_device_scale (cairo_surface_t *surface, + double *x_scale, + double *y_scale); + +cairo_public void cairo_surface_set_device_offset (cairo_surface_t *surface, double x_offset, double y_offset); @@ -2961,10 +2992,10 @@ cairo_public void cairo_set_shadow_rgba (cairo_t *cr, double red, double green, double blue, double alpha); -cairo_public void +cairo_public void cairo_set_shadow_blur (cairo_t *cr, double x_blur, double y_blur); -cairo_public void +cairo_public void cairo_set_draw_shadow_only (cairo_t *cr, cairo_bool_t draw_shadow_only); cairo_public void @@ -3090,6 +3121,17 @@ cairo_matrix_transform_point (const cairo_matrix_t *matrix, **/ typedef struct _cairo_region cairo_region_t; +/** + * cairo_region_overlap_t: + * @CAIRO_REGION_OVERLAP_IN: The contents are entirely inside the region. (Since 1.10) + * @CAIRO_REGION_OVERLAP_OUT: The contents are entirely outside the region. (Since 1.10) + * @CAIRO_REGION_OVERLAP_PART: The contents are partially inside and + * partially outside the region. (Since 1.10) + * + * Used as the return value for cairo_region_contains_rectangle(). + * + * Since: 1.10 + **/ typedef enum _cairo_region_overlap { CAIRO_REGION_OVERLAP_IN, /* completely inside region */ CAIRO_REGION_OVERLAP_OUT, /* completely outside region */ diff --git a/src/cairo.pc.in b/src/cairo.pc.in index b361edf18..b361edf18 100755..100644 --- a/src/cairo.pc.in +++ b/src/cairo.pc.in diff --git a/src/cairoint.h b/src/cairoint.h index e4f483a3a..7c73c3d13 100755..100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -229,7 +229,7 @@ be16_to_cpu(uint16_t v) static inline uint32_t cairo_const cpu_to_be32(uint32_t v) { - return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16); + return (v >> 24) | ((v >> 8) & 0xff00) | ((v << 8) & 0xff0000) | (v << 24); } static inline uint32_t cairo_const @@ -240,6 +240,32 @@ be32_to_cpu(uint32_t v) #endif +/* Unaligned big endian access + */ + +static inline uint16_t get_unaligned_be16 (const unsigned char *p) +{ + return p[0] << 8 | p[1]; +} + +static inline uint32_t get_unaligned_be32 (const unsigned char *p) +{ + return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; +} + +static inline void put_unaligned_be16 (uint16_t v, unsigned char *p) +{ + p[0] = (v >> 8) & 0xff; + p[1] = v & 0xff; +} + +static inline void put_unaligned_be32 (uint32_t v, unsigned char *p) +{ + p[0] = (v >> 24) & 0xff; + p[1] = (v >> 16) & 0xff; + p[2] = (v >> 8) & 0xff; + p[3] = v & 0xff; +} /* The glibc versions of ispace() and isdigit() are slow in UTF-8 locales. */ @@ -428,7 +454,7 @@ _cairo_cogl_context_reset_static_data (void); /* the font backend interface */ struct _cairo_unscaled_font_backend { - void (*destroy) (void *unscaled_font); + cairo_bool_t (*destroy) (void *unscaled_font); }; /* #cairo_toy_font_face_t - simple family/slant/weight font faces used for @@ -587,7 +613,7 @@ struct _cairo_font_face_backend { /* The destroy() function is allowed to resurrect the font face * by re-referencing. This is needed for the FreeType backend. */ - void + cairo_bool_t (*destroy) (void *font_face); cairo_warn cairo_status_t @@ -797,6 +823,9 @@ cairo_private void _cairo_font_face_init (cairo_font_face_t *font_face, const cairo_font_face_backend_t *backend); +cairo_private cairo_bool_t +_cairo_font_face_destroy (void *abstract_face); + cairo_private cairo_status_t _cairo_font_face_set_error (cairo_font_face_t *font_face, cairo_status_t status); @@ -872,6 +901,9 @@ _cairo_intern_string (const char **str_inout, int len); cairo_private void _cairo_intern_string_reset_static_data (void); +cairo_private const char * +cairo_get_locale_decimal_point (void); + /* cairo-path-fixed.c */ cairo_private cairo_path_fixed_t * _cairo_path_fixed_create (void); @@ -1034,6 +1066,9 @@ cairo_private cairo_bool_t _cairo_path_fixed_is_single_arc (const cairo_path_fixed_t *path); cairo_private cairo_bool_t +_cairo_path_fixed_is_empty (const cairo_path_fixed_t *path); + +cairo_private cairo_bool_t _cairo_path_fixed_is_single_line (const cairo_path_fixed_t *path); cairo_private cairo_bool_t @@ -1323,20 +1358,21 @@ _cairo_surface_set_resolution (cairo_surface_t *surface, cairo_private cairo_surface_t * _cairo_surface_create_similar_scratch (cairo_surface_t *other, - cairo_content_t content, - int width, - int height); + cairo_content_t content, + int width, + int height); + cairo_private cairo_surface_t * _cairo_surface_create_for_rectangle_int (cairo_surface_t *target, const cairo_rectangle_int_t *extents); cairo_private cairo_surface_t * -_cairo_surface_create_similar_solid (cairo_surface_t *other, - cairo_content_t content, - int width, - int height, - const cairo_color_t *color); +_cairo_surface_create_scratch (cairo_surface_t *other, + cairo_content_t content, + int width, + int height, + const cairo_color_t *color); cairo_private void _cairo_surface_init (cairo_surface_t *surface, @@ -1358,7 +1394,7 @@ cairo_private cairo_image_surface_t * _cairo_surface_map_to_image (cairo_surface_t *surface, const cairo_rectangle_int_t *extents); -cairo_private cairo_int_status_t +cairo_private_no_warn cairo_int_status_t _cairo_surface_unmap_image (cairo_surface_t *surface, cairo_image_surface_t *image); @@ -1454,11 +1490,6 @@ cairo_private_no_warn cairo_bool_t _cairo_surface_get_extents (cairo_surface_t *surface, cairo_rectangle_int_t *extents); -cairo_private void -_cairo_surface_set_device_scale (cairo_surface_t *surface, - double sx, - double sy); - cairo_private cairo_bool_t _cairo_surface_has_device_transform (cairo_surface_t *surface) cairo_pure; @@ -1651,18 +1682,18 @@ _cairo_polygon_limit_to_clip (cairo_polygon_t *polygon, cairo_private void _cairo_polygon_fini (cairo_polygon_t *polygon); -cairo_private cairo_status_t +cairo_private_no_warn cairo_status_t _cairo_polygon_add_line (cairo_polygon_t *polygon, const cairo_line_t *line, int top, int bottom, int dir); -cairo_private cairo_status_t +cairo_private_no_warn cairo_status_t _cairo_polygon_add_external_edge (void *polygon, const cairo_point_t *p1, const cairo_point_t *p2); -cairo_private cairo_status_t +cairo_private_no_warn cairo_status_t _cairo_polygon_add_contour (cairo_polygon_t *polygon, const cairo_contour_t *contour); @@ -1990,6 +2021,7 @@ slim_hidden_proto (cairo_surface_destroy); slim_hidden_proto (cairo_surface_finish); slim_hidden_proto (cairo_surface_flush); slim_hidden_proto (cairo_surface_get_device_offset); +slim_hidden_proto (cairo_surface_get_device_scale); slim_hidden_proto (cairo_surface_get_font_options); slim_hidden_proto (cairo_surface_get_mime_data); slim_hidden_proto (cairo_surface_has_show_text_glyphs); @@ -1997,6 +2029,7 @@ slim_hidden_proto (cairo_surface_mark_dirty); slim_hidden_proto (cairo_surface_mark_dirty_rectangle); slim_hidden_proto_no_warn (cairo_surface_reference); slim_hidden_proto (cairo_surface_set_device_offset); +slim_hidden_proto (cairo_surface_set_device_scale); slim_hidden_proto (cairo_surface_set_fallback_resolution); slim_hidden_proto (cairo_surface_set_mime_data); slim_hidden_proto (cairo_surface_show_page); @@ -2055,10 +2088,6 @@ slim_hidden_proto (cairo_surface_write_to_png_stream); #endif -cairo_private_no_warn cairo_filter_t -_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern, - double *pad_out); - CAIRO_END_DECLS #include "cairo-mutex-private.h" diff --git a/src/check-def.sh b/src/check-def.sh index 9008c5871..beefb46a3 100755 --- a/src/check-def.sh +++ b/src/check-def.sh @@ -39,7 +39,7 @@ for def in $defs; do { echo EXPORTS - eval $get_cairo_syms | c++filt --no-params | grep -v '^_cairo_test_\|^_fini\|^_init\|^_save[fg]pr\|^_rest[fg]pr\|^_Z\|^__gnu' | sort -u + eval $get_cairo_syms | c++filt --no-params | grep -v '^_cairo_test_\|^_fini\|^_init\|^_save[fg]pr\|^_rest[fg]pr\|^_Z\|^__gnu\|^__bss\|^_edata\|^_end' | sort -u # cheat: copy the last line from the def file! tail -n1 "$def" } | diff "$def" - >&2 || stat=1 diff --git a/src/check-doc-syntax.awk b/src/check-doc-syntax.awk index 5fdabdac9..1fa8b8d22 100755..100644 --- a/src/check-doc-syntax.awk +++ b/src/check-doc-syntax.awk @@ -1,5 +1,3 @@ -#!/usr/bin/awk -f - BEGIN { name_found = 1 SECTION_DOC = 0 diff --git a/src/check-doc-syntax.sh b/src/check-doc-syntax.sh index c74fb875d..762a48429 100755 --- a/src/check-doc-syntax.sh +++ b/src/check-doc-syntax.sh @@ -72,7 +72,7 @@ fi >&2 # Only run the syntax checker on the source files (not doc/) if test -e ./check-doc-syntax.awk; then - if echo $FILES | xargs ./check-doc-syntax.awk ; then + if echo $FILES | xargs awk -f ./check-doc-syntax.awk ; then : else stat=1 diff --git a/src/check-has-hidden-symbols.c b/src/check-has-hidden-symbols.c index 120412776..120412776 100755..100644 --- a/src/check-has-hidden-symbols.c +++ b/src/check-has-hidden-symbols.c diff --git a/src/check-link.c b/src/check-link.c index 66ca1b241..66ca1b241 100755..100644 --- a/src/check-link.c +++ b/src/check-link.c diff --git a/src/check-preprocessor-syntax.sh b/src/check-preprocessor-syntax.sh index c4154151d..b718f604e 100755 --- a/src/check-preprocessor-syntax.sh +++ b/src/check-preprocessor-syntax.sh @@ -9,10 +9,10 @@ stat=0 HEADERS=$all_cairo_headers -test "x$HEADERS" = x && HEADERS=`find . -name 'cairo*.h' ! -name 'cairo*-private.h' ! -name 'cairoint.h'` +test "x$HEADERS" = x && HEADERS=`find . -name 'cairo*.h' ! -name 'cairo*-private.h' ! -name 'cairo*-inline.h' ! -name 'cairoint.h'` PRIVATE=$all_cairo_private -test "x$PRIVATE" = x && PRIVATE=`find . -name 'cairo*-private.h' -or -name 'cairoint.h'` +test "x$PRIVATE" = x && PRIVATE=`find . -name 'cairo*-private.h' -or -name 'cairo*-inline.h' -or -name 'cairoint.h'` SOURCES=$all_cairo_sources test "x$SOURCES" = x && SOURCES=`find . -name 'cairo*.c' -or -name 'cairo*.cpp'` diff --git a/src/drm/cairo-drm-bo.c b/src/drm/cairo-drm-bo.c index a5b59f2c9..a5b59f2c9 100755..100644 --- a/src/drm/cairo-drm-bo.c +++ b/src/drm/cairo-drm-bo.c diff --git a/src/drm/cairo-drm-gallium-surface.c b/src/drm/cairo-drm-gallium-surface.c index 164ab03ce..164ab03ce 100755..100644 --- a/src/drm/cairo-drm-gallium-surface.c +++ b/src/drm/cairo-drm-gallium-surface.c diff --git a/src/drm/cairo-drm-i915-glyphs.c b/src/drm/cairo-drm-i915-glyphs.c index 9944f15a4..9944f15a4 100755..100644 --- a/src/drm/cairo-drm-i915-glyphs.c +++ b/src/drm/cairo-drm-i915-glyphs.c diff --git a/src/drm/cairo-drm-i915-private.h b/src/drm/cairo-drm-i915-private.h index c750cf4cf..c750cf4cf 100755..100644 --- a/src/drm/cairo-drm-i915-private.h +++ b/src/drm/cairo-drm-i915-private.h diff --git a/src/drm/cairo-drm-i915-shader.c b/src/drm/cairo-drm-i915-shader.c index a1911d0a4..85aa98433 100755..100644 --- a/src/drm/cairo-drm-i915-shader.c +++ b/src/drm/cairo-drm-i915-shader.c @@ -1467,42 +1467,6 @@ i915_shader_acquire_solid_surface (i915_shader_t *shader, return CAIRO_STATUS_SUCCESS; } -static cairo_filter_t -sampled_area (const cairo_surface_pattern_t *pattern, - const cairo_rectangle_int_t *extents, - cairo_rectangle_int_t *sample) -{ - cairo_rectangle_int_t surface_extents; - cairo_filter_t filter; - double x1, x2, y1, y2; - double pad; - - x1 = extents->x; - y1 = extents->y; - x2 = extents->x + (int) extents->width; - y2 = extents->y + (int) extents->height; - - if (_cairo_matrix_is_translation (&pattern->base.matrix)) { - x1 += pattern->base.matrix.x0; x2 += pattern->base.matrix.x0; - y1 += pattern->base.matrix.y0; y2 += pattern->base.matrix.y0; - } else { - _cairo_matrix_transform_bounding_box (&pattern->base.matrix, - &x1, &y1, &x2, &y2, - NULL); - } - - filter = _cairo_pattern_analyze_filter (&pattern->base, &pad); - sample->x = floor (x1 - pad); - sample->y = floor (y1 - pad); - sample->width = ceil (x2 + pad) - sample->x; - sample->height = ceil (y2 + pad) - sample->y; - - if (_cairo_surface_get_extents (pattern->surface, &surface_extents)) - _cairo_rectangle_intersect (sample, &surface_extents); - - return filter; -} - static cairo_status_t i915_shader_acquire_surface (i915_shader_t *shader, union i915_shader_channel *src, @@ -1524,7 +1488,8 @@ i915_shader_acquire_surface (i915_shader_t *shader, extend = pattern->base.extend; src->base.matrix = pattern->base.matrix; - filter = sampled_area (pattern, extents, &sample); + filter = pattern->base.filter; + _cairo_pattern_sampled_area(&pattern->base, extents, sample); if (surface->type == CAIRO_SURFACE_TYPE_DRM) { if (surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { diff --git a/src/drm/cairo-drm-i915-spans.c b/src/drm/cairo-drm-i915-spans.c index b3f4e0afd..b3f4e0afd 100755..100644 --- a/src/drm/cairo-drm-i915-spans.c +++ b/src/drm/cairo-drm-i915-spans.c diff --git a/src/drm/cairo-drm-i915-surface.c b/src/drm/cairo-drm-i915-surface.c index c1a04529f..c1a04529f 100755..100644 --- a/src/drm/cairo-drm-i915-surface.c +++ b/src/drm/cairo-drm-i915-surface.c diff --git a/src/drm/cairo-drm-i965-glyphs.c b/src/drm/cairo-drm-i965-glyphs.c index c66a63d73..c66a63d73 100755..100644 --- a/src/drm/cairo-drm-i965-glyphs.c +++ b/src/drm/cairo-drm-i965-glyphs.c diff --git a/src/drm/cairo-drm-i965-private.h b/src/drm/cairo-drm-i965-private.h index 79568a63d..79568a63d 100755..100644 --- a/src/drm/cairo-drm-i965-private.h +++ b/src/drm/cairo-drm-i965-private.h diff --git a/src/drm/cairo-drm-i965-shader.c b/src/drm/cairo-drm-i965-shader.c index eed5f5f09..eed5f5f09 100755..100644 --- a/src/drm/cairo-drm-i965-shader.c +++ b/src/drm/cairo-drm-i965-shader.c diff --git a/src/drm/cairo-drm-i965-spans.c b/src/drm/cairo-drm-i965-spans.c index 5cba7cec8..5cba7cec8 100755..100644 --- a/src/drm/cairo-drm-i965-spans.c +++ b/src/drm/cairo-drm-i965-spans.c diff --git a/src/drm/cairo-drm-i965-surface.c b/src/drm/cairo-drm-i965-surface.c index ec7b5954c..ec7b5954c 100755..100644 --- a/src/drm/cairo-drm-i965-surface.c +++ b/src/drm/cairo-drm-i965-surface.c diff --git a/src/drm/cairo-drm-intel-brw-defines.h b/src/drm/cairo-drm-intel-brw-defines.h index b2be36f18..b2be36f18 100755..100644 --- a/src/drm/cairo-drm-intel-brw-defines.h +++ b/src/drm/cairo-drm-intel-brw-defines.h diff --git a/src/drm/cairo-drm-intel-brw-eu-emit.c b/src/drm/cairo-drm-intel-brw-eu-emit.c index f27b23804..f27b23804 100755..100644 --- a/src/drm/cairo-drm-intel-brw-eu-emit.c +++ b/src/drm/cairo-drm-intel-brw-eu-emit.c diff --git a/src/drm/cairo-drm-intel-brw-eu-util.c b/src/drm/cairo-drm-intel-brw-eu-util.c index 592235b12..592235b12 100755..100644 --- a/src/drm/cairo-drm-intel-brw-eu-util.c +++ b/src/drm/cairo-drm-intel-brw-eu-util.c diff --git a/src/drm/cairo-drm-intel-brw-eu.c b/src/drm/cairo-drm-intel-brw-eu.c index 2b47d8c37..2b47d8c37 100755..100644 --- a/src/drm/cairo-drm-intel-brw-eu.c +++ b/src/drm/cairo-drm-intel-brw-eu.c diff --git a/src/drm/cairo-drm-intel-brw-eu.h b/src/drm/cairo-drm-intel-brw-eu.h index 2662a2e7f..2662a2e7f 100755..100644 --- a/src/drm/cairo-drm-intel-brw-eu.h +++ b/src/drm/cairo-drm-intel-brw-eu.h diff --git a/src/drm/cairo-drm-intel-brw-structs.h b/src/drm/cairo-drm-intel-brw-structs.h index f42483ed1..f42483ed1 100755..100644 --- a/src/drm/cairo-drm-intel-brw-structs.h +++ b/src/drm/cairo-drm-intel-brw-structs.h diff --git a/src/drm/cairo-drm-intel-command-private.h b/src/drm/cairo-drm-intel-command-private.h index a93ac12ab..a93ac12ab 100755..100644 --- a/src/drm/cairo-drm-intel-command-private.h +++ b/src/drm/cairo-drm-intel-command-private.h diff --git a/src/drm/cairo-drm-intel-debug.c b/src/drm/cairo-drm-intel-debug.c index 7068c933e..7068c933e 100755..100644 --- a/src/drm/cairo-drm-intel-debug.c +++ b/src/drm/cairo-drm-intel-debug.c diff --git a/src/drm/cairo-drm-intel-ioctl-private.h b/src/drm/cairo-drm-intel-ioctl-private.h index 004d3bfd7..004d3bfd7 100755..100644 --- a/src/drm/cairo-drm-intel-ioctl-private.h +++ b/src/drm/cairo-drm-intel-ioctl-private.h diff --git a/src/drm/cairo-drm-intel-private.h b/src/drm/cairo-drm-intel-private.h index 343270a3c..343270a3c 100755..100644 --- a/src/drm/cairo-drm-intel-private.h +++ b/src/drm/cairo-drm-intel-private.h diff --git a/src/drm/cairo-drm-intel-surface.c b/src/drm/cairo-drm-intel-surface.c index 88f5b8f0c..88f5b8f0c 100755..100644 --- a/src/drm/cairo-drm-intel-surface.c +++ b/src/drm/cairo-drm-intel-surface.c diff --git a/src/drm/cairo-drm-intel.c b/src/drm/cairo-drm-intel.c index d45155ebe..d45155ebe 100755..100644 --- a/src/drm/cairo-drm-intel.c +++ b/src/drm/cairo-drm-intel.c diff --git a/src/drm/cairo-drm-ioctl-private.h b/src/drm/cairo-drm-ioctl-private.h index 4294de2d5..4294de2d5 100755..100644 --- a/src/drm/cairo-drm-ioctl-private.h +++ b/src/drm/cairo-drm-ioctl-private.h diff --git a/src/drm/cairo-drm-private.h b/src/drm/cairo-drm-private.h index 2db7f38d6..2db7f38d6 100755..100644 --- a/src/drm/cairo-drm-private.h +++ b/src/drm/cairo-drm-private.h diff --git a/src/drm/cairo-drm-radeon-private.h b/src/drm/cairo-drm-radeon-private.h index 546126c6f..546126c6f 100755..100644 --- a/src/drm/cairo-drm-radeon-private.h +++ b/src/drm/cairo-drm-radeon-private.h diff --git a/src/drm/cairo-drm-radeon-surface.c b/src/drm/cairo-drm-radeon-surface.c index 6dbddaae4..6dbddaae4 100755..100644 --- a/src/drm/cairo-drm-radeon-surface.c +++ b/src/drm/cairo-drm-radeon-surface.c diff --git a/src/drm/cairo-drm-radeon.c b/src/drm/cairo-drm-radeon.c index a6d22089b..a6d22089b 100755..100644 --- a/src/drm/cairo-drm-radeon.c +++ b/src/drm/cairo-drm-radeon.c diff --git a/src/drm/cairo-drm-surface.c b/src/drm/cairo-drm-surface.c index 8c4dd0ee8..8c4dd0ee8 100755..100644 --- a/src/drm/cairo-drm-surface.c +++ b/src/drm/cairo-drm-surface.c diff --git a/src/drm/cairo-drm.c b/src/drm/cairo-drm.c index 051b79e4f..661e181b6 100755..100644 --- a/src/drm/cairo-drm.c +++ b/src/drm/cairo-drm.c @@ -202,8 +202,7 @@ cairo_drm_device_get (struct udev_device *device) parent = udev_device_get_parent (device); pci_id = get_udev_property (parent, "PCI_ID"); if (pci_id == NULL || sscanf (pci_id, "%x:%x", &vendor_id, &chip_id) != 2) { - dev = (cairo_drm_device_t *) - _cairo_device_create_in_error (CAIRO_STATUS_DEVICE_ERROR); + dev = NULL; goto DONE; } @@ -239,6 +238,7 @@ cairo_drm_device_get (struct udev_device *device) if (fd == -1) { /* XXX more likely to be a permissions issue... */ _cairo_error_throw (CAIRO_STATUS_FILE_NOT_FOUND); + dev = NULL; goto DONE; } @@ -249,7 +249,10 @@ cairo_drm_device_get (struct udev_device *device) DONE: CAIRO_MUTEX_UNLOCK (_cairo_drm_device_mutex); - return &dev->base; + if (dev == NULL) + return _cairo_device_create_in_error (CAIRO_STATUS_DEVICE_ERROR); + else + return &dev->base; } slim_hidden_def (cairo_drm_device_get); diff --git a/src/skia/cairo-skia-context.cpp b/src/skia/cairo-skia-context.cpp index bbe5507f6..9ffb8f6a2 100755..100644 --- a/src/skia/cairo-skia-context.cpp +++ b/src/skia/cairo-skia-context.cpp @@ -53,6 +53,7 @@ #include "cairo-skia-private.h" #include "cairo-surface-backend-private.h" +#include <SkPaint.h> #include <SkShader.h> #include <SkColorShader.h> #include <SkGradientShader.h> @@ -236,16 +237,19 @@ surface_to_sk_bitmap (cairo_surface_t *surface, SkBitmap& bitmap) { cairo_image_surface_t *img = (cairo_image_surface_t *) surface; SkBitmap::Config config; + SkColorType colorType; bool opaque; if (unlikely (! format_to_sk_config (img->format, config, opaque))) return false; bitmap.reset (); - bitmap.setConfig (config, img->width, img->height, img->stride); - bitmap.setIsOpaque (opaque); + bitmap.setAlphaType (opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); + colorType = SkBitmapConfigToColorType(config); + bitmap.setInfo (SkImageInfo::Make(img->width, img->height, colorType, kPremul_SkAlphaType), img->stride); bitmap.setPixels (img->data); + return true; } @@ -330,9 +334,18 @@ source_to_sk_shader (cairo_skia_context_t *cr, if (surface->type == CAIRO_SURFACE_TYPE_SKIA) { cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface; - shader = SkShader::CreateBitmapShader (*esurf->bitmap, - extend_to_sk (pattern->extend), - extend_to_sk (pattern->extend)); + if (! _cairo_matrix_is_identity (&pattern->matrix)) + { + SkMatrix localMatrix = matrix_inverse_to_sk (pattern->matrix); + shader = SkShader::CreateBitmapShader (*esurf->bitmap, + extend_to_sk (pattern->extend), + extend_to_sk (pattern->extend), + &localMatrix); + } else { + shader = SkShader::CreateBitmapShader (*esurf->bitmap, + extend_to_sk (pattern->extend), + extend_to_sk (pattern->extend)); + } } else { SkBitmap bitmap; @@ -351,9 +364,18 @@ source_to_sk_shader (cairo_skia_context_t *cr, if (unlikely (! surface_to_sk_bitmap (surface, bitmap))) return NULL; - shader = SkShader::CreateBitmapShader (bitmap, - extend_to_sk (pattern->extend), - extend_to_sk (pattern->extend)); + if (! _cairo_matrix_is_identity (&pattern->matrix)) + { + SkMatrix localMatrix = matrix_inverse_to_sk (pattern->matrix); + shader = SkShader::CreateBitmapShader (bitmap, + extend_to_sk (pattern->extend), + extend_to_sk (pattern->extend), + &localMatrix); + } else { + shader = SkShader::CreateBitmapShader (bitmap, + extend_to_sk (pattern->extend), + extend_to_sk (pattern->extend)); + } } } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR /* || pattern->type == CAIRO_PATTERN_TYPE_RADIAL */) @@ -382,8 +404,17 @@ source_to_sk_shader (cairo_skia_context_t *cr, SkFloatToScalar (linear->pd1.y)); points[1].set (SkFloatToScalar (linear->pd2.x), SkFloatToScalar (linear->pd2.y)); - shader = SkGradientShader::CreateLinear (points, colors, pos, gradient->n_stops, - extend_to_sk (pattern->extend)); + + if(! _cairo_matrix_is_identity (&pattern->matrix)) + { + SkMatrix localMatrix = matrix_inverse_to_sk (pattern->matrix); + shader = SkGradientShader::CreateLinear (points, colors, pos, gradient->n_stops, + extend_to_sk (pattern->extend), + 0, &localMatrix); + } else { + shader = SkGradientShader::CreateLinear (points, colors, pos, gradient->n_stops, + extend_to_sk (pattern->extend)); + } } else { // XXX todo -- implement real radial shaders in Skia } @@ -394,9 +425,6 @@ source_to_sk_shader (cairo_skia_context_t *cr, } } - if (shader && ! _cairo_matrix_is_identity (&pattern->matrix)) - shader->setLocalMatrix (matrix_inverse_to_sk (pattern->matrix)); - return shader; } @@ -446,6 +474,7 @@ _cairo_skia_context_set_source (void *abstract_cr, cr->paint->setColor (color); } else { SkShader *shader = source_to_sk_shader (cr, source); + bool fLevel = pattern_filter_to_sk (source); if (shader == NULL) { UNSUPPORTED; return CAIRO_STATUS_SUCCESS; @@ -454,7 +483,8 @@ _cairo_skia_context_set_source (void *abstract_cr, cr->paint->setShader (shader); shader->unref (); - cr->paint->setFilterBitmap (pattern_filter_to_sk (source)); + cr->paint->setFilterLevel (fLevel ? + (SkPaint::kLow_FilterLevel) : (SkPaint::kNone_FilterLevel)); } /* XXX change notification */ @@ -496,7 +526,8 @@ _cairo_skia_context_set_source_surface (void *abstract_cr, cr->paint->setShader (shader); shader->unref (); - cr->paint->setFilterBitmap (true); + cr->paint->setFilterLevel (true ? + (SkPaint::kLow_FilterLevel) : (SkPaint::kNone_FilterLevel)); return CAIRO_STATUS_SUCCESS; } @@ -682,7 +713,7 @@ _cairo_skia_context_set_dash (void *abstract_cr, intervals[i++] = SkFloatToScalar (dashes[j]); } while (loop--); - SkDashPathEffect *dash = new SkDashPathEffect (intervals, num_dashes, SkFloatToScalar (offset)); + SkDashPathEffect *dash = SkDashPathEffect::Create (intervals, num_dashes, SkFloatToScalar (offset)); cr->paint->setPathEffect (dash); dash->unref (); @@ -1264,7 +1295,7 @@ _cairo_skia_context_paint_with_alpha (void *abstract_cr, if (CAIRO_ALPHA_IS_OPAQUE (alpha)) return _cairo_skia_context_paint (cr); - cr->paint->setAlpha(SkScalarRound(255*alpha)); + cr->paint->setAlpha(SkScalarRoundToInt(255*alpha)); status = _cairo_skia_context_paint (cr); cr->paint->setAlpha(255); diff --git a/src/skia/cairo-skia-private.h b/src/skia/cairo-skia-private.h index cbd8c888d..f538b486b 100755..100644 --- a/src/skia/cairo-skia-private.h +++ b/src/skia/cairo-skia-private.h @@ -44,7 +44,26 @@ #include <SkPaint.h> #include <SkPath.h> +/** + * cairo_skia_context_t: + * + * A #cairo_skia_context_t includes handles to Skia's canvas, + * paint, and path objects along with the Cairo source surfaces + * and matrix, and the original and target #cairo_skia_surface_t + * objects. + * + * Since: 1.10 + **/ typedef struct _cairo_skia_context cairo_skia_context_t; + +/** + * cairo_skia_surface_t: + * + * A #cairo_skia_surface_t is a container for the underlying + * #SkBitmap and the corresponding Cairo image surface. + * + * Since: 1.10 + **/ typedef struct _cairo_skia_surface cairo_skia_surface_t; struct _cairo_skia_context { @@ -92,11 +111,9 @@ format_to_sk_config (cairo_format_t format, case CAIRO_FORMAT_A8: config = SkBitmap::kA8_Config; break; - case CAIRO_FORMAT_A1: - config = SkBitmap::kA1_Config; - break; case CAIRO_FORMAT_RGB30: case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_A1: default: return false; } diff --git a/src/skia/cairo-skia-surface.cpp b/src/skia/cairo-skia-surface.cpp index bb785e192..834a2f13b 100755..100644 --- a/src/skia/cairo-skia-surface.cpp +++ b/src/skia/cairo-skia-surface.cpp @@ -64,7 +64,7 @@ _cairo_skia_surface_create_similar (void *asurface, if (content == surface->image.base.content) { - config = surface->bitmap->getConfig (); + config = surface->bitmap->config (); opaque = surface->bitmap->isOpaque (); } else if (! format_to_sk_config (_cairo_format_from_content (content), @@ -207,9 +207,6 @@ sk_config_to_pixman_format_code (SkBitmap::Config config, case SkBitmap::kA8_Config: return PIXMAN_a8; - - case SkBitmap::kA1_Config: - return PIXMAN_a1; case SkBitmap::kRGB_565_Config: return PIXMAN_r5g6b5; case SkBitmap::kARGB_4444_Config: @@ -217,8 +214,6 @@ sk_config_to_pixman_format_code (SkBitmap::Config config, case SkBitmap::kNo_Config: case SkBitmap::kIndex8_Config: - case SkBitmap::kRLE_Index8_Config: - case SkBitmap::kConfigCount: default: ASSERT_NOT_REACHED; return (pixman_format_code_t) -1; @@ -236,6 +231,7 @@ _cairo_skia_surface_create_internal (SkBitmap::Config config, cairo_skia_surface_t *surface; pixman_image_t *pixman_image; pixman_format_code_t pixman_format; + SkColorType colorType; surface = (cairo_skia_surface_t *) malloc (sizeof (cairo_skia_surface_t)); if (unlikely (surface == NULL)) @@ -245,8 +241,10 @@ _cairo_skia_surface_create_internal (SkBitmap::Config config, pixman_image = pixman_image_create_bits (pixman_format, width, height, (uint32_t *) data, stride); - if (unlikely (pixman_image == NULL)) + if (unlikely (pixman_image == NULL)) { + free (surface); return (cairo_skia_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } _cairo_surface_init (&surface->image.base, &cairo_skia_surface_backend, @@ -256,8 +254,9 @@ _cairo_skia_surface_create_internal (SkBitmap::Config config, _cairo_image_surface_init (&surface->image, pixman_image, pixman_format); surface->bitmap = new SkBitmap; - surface->bitmap->setConfig (config, width, height, surface->image.stride); - surface->bitmap->setIsOpaque (opaque); + colorType = SkBitmapConfigToColorType(config); + surface->bitmap->setAlphaType (opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); + surface->bitmap->setInfo (SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType), surface->image.stride); surface->bitmap->setPixels (surface->image.data); surface->image.base.is_clear = data == NULL; diff --git a/src/test-base-compositor-surface.c b/src/test-base-compositor-surface.c index ff84b10af..ff84b10af 100755..100644 --- a/src/test-base-compositor-surface.c +++ b/src/test-base-compositor-surface.c diff --git a/src/test-compositor-surface-private.h b/src/test-compositor-surface-private.h index 491f241ba..491f241ba 100755..100644 --- a/src/test-compositor-surface-private.h +++ b/src/test-compositor-surface-private.h diff --git a/src/test-compositor-surface.c b/src/test-compositor-surface.c index ddee06f3e..1cc5f6921 100755..100644 --- a/src/test-compositor-surface.c +++ b/src/test-compositor-surface.c @@ -145,6 +145,8 @@ test_compositor_surface_stroke (void *_surface, const cairo_clip_t *clip) { test_compositor_surface_t *surface = _surface; + if (antialias == CAIRO_ANTIALIAS_DEFAULT) + antialias = CAIRO_ANTIALIAS_BEST; return _cairo_compositor_stroke (surface->base.compositor, _surface, op, source, path, style, ctm, ctm_inverse, @@ -163,6 +165,8 @@ test_compositor_surface_fill (void *_surface, const cairo_clip_t *clip) { test_compositor_surface_t *surface = _surface; + if (antialias == CAIRO_ANTIALIAS_DEFAULT) + antialias = CAIRO_ANTIALIAS_BEST; return _cairo_compositor_fill (surface->base.compositor, _surface, op, source, path, fill_rule, tolerance, antialias, diff --git a/src/test-compositor-surface.h b/src/test-compositor-surface.h index 8d8af2d54..8d8af2d54 100755..100644 --- a/src/test-compositor-surface.h +++ b/src/test-compositor-surface.h diff --git a/src/test-null-compositor-surface.c b/src/test-null-compositor-surface.c index 4fdaac4a3..395a5f4a6 100755..100644 --- a/src/test-null-compositor-surface.c +++ b/src/test-null-compositor-surface.c @@ -419,7 +419,7 @@ no_traps_compositor_get (void) compositor.check_composite = check_composite; compositor.composite = composite; compositor.lerp = lerp; - //FIXME: + // FIXME: compositor.lerp_color_glyph = lerp; //compositor.check_composite_boxes = check_composite_boxes; compositor.composite_boxes = composite_boxes; diff --git a/src/test-null-compositor-surface.h b/src/test-null-compositor-surface.h index 52d864b28..52d864b28 100755..100644 --- a/src/test-null-compositor-surface.h +++ b/src/test-null-compositor-surface.h diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c index 0a7c79b37..0a7c79b37 100755..100644 --- a/src/test-paginated-surface.c +++ b/src/test-paginated-surface.c diff --git a/src/test-paginated-surface.h b/src/test-paginated-surface.h index 2bd98aa5e..2bd98aa5e 100755..100644 --- a/src/test-paginated-surface.h +++ b/src/test-paginated-surface.h diff --git a/src/win32/cairo-win32-debug.c b/src/win32/cairo-win32-debug.c index ff7aeaf1f..ff7aeaf1f 100755..100644 --- a/src/win32/cairo-win32-debug.c +++ b/src/win32/cairo-win32-debug.c diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c index 741e49e33..741e49e33 100755..100644 --- a/src/win32/cairo-win32-device.c +++ b/src/win32/cairo-win32-device.c diff --git a/src/win32/cairo-win32-display-surface.c b/src/win32/cairo-win32-display-surface.c index ccd285d7d..965f2c45d 100755..100644 --- a/src/win32/cairo-win32-display-surface.c +++ b/src/win32/cairo-win32-display-surface.c @@ -415,7 +415,8 @@ _cairo_win32_display_surface_finish (void *abstract_surface) { cairo_win32_display_surface_t *surface = abstract_surface; - if (surface->image) { + if (surface->image && to_image_surface(surface->image)->parent) { + assert (to_image_surface(surface->image)->parent == &surface->win32.base); /* Unhook ourselves first to avoid the double-unref from the image */ to_image_surface(surface->image)->parent = NULL; cairo_surface_finish (surface->image); @@ -429,6 +430,8 @@ _cairo_win32_display_surface_finish (void *abstract_surface) DeleteDC (surface->win32.dc); } + _cairo_win32_display_surface_discard_fallback (surface); + if (surface->initial_clip_rgn) DeleteObject (surface->initial_clip_rgn); @@ -452,17 +455,17 @@ _cairo_win32_display_surface_map_to_image (void *abstract_sur surface->fallback = _cairo_win32_display_surface_create_for_dc (surface->win32.dc, surface->win32.format, - surface->win32.extents.width, - surface->win32.extents.height); + surface->win32.extents.x + surface->win32.extents.width, + surface->win32.extents.y + surface->win32.extents.height); if (unlikely (status = surface->fallback->status)) goto err; if (!BitBlt (to_win32_surface(surface->fallback)->dc, - 0, 0, + surface->win32.extents.x, surface->win32.extents.y, surface->win32.extents.width, surface->win32.extents.height, surface->win32.dc, - 0, 0, + surface->win32.extents.x, surface->win32.extents.y, SRCCOPY)) { status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR); goto err; @@ -758,6 +761,7 @@ _cairo_win32_display_surface_discard_fallback (cairo_win32_display_surface_t *su TRACE ((stderr, "%s (surface=%d)\n", __FUNCTION__, surface->win32.base.unique_id)); + cairo_surface_finish (surface->fallback); cairo_surface_destroy (surface->fallback); surface->fallback = NULL; } diff --git a/src/win32/cairo-win32-font.c b/src/win32/cairo-win32-font.c index a65d81b1a..1599b0751 100755..100644 --- a/src/win32/cairo-win32-font.c +++ b/src/win32/cairo-win32-font.c @@ -157,10 +157,6 @@ static cairo_status_t _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph); -static void -_cairo_win32_font_face_destroy (void *abstract_face); - - #define NEARLY_ZERO(d) (fabs(d) < (1. / 65536.)) static HDC @@ -1847,49 +1843,6 @@ struct _cairo_win32_font_face { HFONT hfont; }; -/* implement the platform-specific interface */ - -static cairo_bool_t -_is_scale (const cairo_matrix_t *matrix, double scale) -{ - return matrix->xx == scale && matrix->yy == scale && - matrix->xy == 0. && matrix->yx == 0. && - matrix->x0 == 0. && matrix->y0 == 0.; -} - -static cairo_status_t -_cairo_win32_font_face_scaled_font_create (void *abstract_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_font_options_t *options, - cairo_scaled_font_t **font) -{ - HFONT hfont = NULL; - - cairo_win32_font_face_t *font_face = abstract_face; - - if (font_face->hfont) { - /* Check whether it's OK to go ahead and use the font-face's HFONT. */ - if (_is_scale (ctm, 1.) && - _is_scale (font_matrix, -font_face->logfont.lfHeight)) { - hfont = font_face->hfont; - } - } - - return _win32_scaled_font_create (&font_face->logfont, - hfont, - &font_face->base, - font_matrix, ctm, options, - font); -} - -const cairo_font_face_backend_t _cairo_win32_font_face_backend = { - CAIRO_FONT_TYPE_WIN32, - _cairo_win32_font_face_create_for_toy, - _cairo_win32_font_face_destroy, - _cairo_win32_font_face_scaled_font_create -}; - /* We maintain a hash table from LOGFONT,HFONT => #cairo_font_face_t. * The primary purpose of this mapping is to provide unique * #cairo_font_face_t values so that our cache and mapping from @@ -1950,7 +1903,7 @@ _cairo_win32_font_face_hash_table_unlock (void) CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex); } -static void +static cairo_bool_t _cairo_win32_font_face_destroy (void *abstract_face) { cairo_win32_font_face_t *font_face = abstract_face; @@ -1960,10 +1913,10 @@ _cairo_win32_font_face_destroy (void *abstract_face) /* All created objects must have been mapped in the hash table. */ assert (hash_table != NULL); - if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->base.ref_count)) { + if (! _cairo_reference_count_dec_and_test (&font_face->base.ref_count)) { /* somebody recreated the font whilst we waited for the lock */ _cairo_win32_font_face_hash_table_unlock (); - return; + return FALSE; } /* Font faces in SUCCESS status are guaranteed to be in the @@ -1975,6 +1928,7 @@ _cairo_win32_font_face_destroy (void *abstract_face) _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); _cairo_win32_font_face_hash_table_unlock (); + return TRUE; } static void @@ -2015,6 +1969,49 @@ _cairo_win32_font_face_keys_equal (const void *key_a, return FALSE; } +/* implement the platform-specific interface */ + +static cairo_bool_t +_is_scale (const cairo_matrix_t *matrix, double scale) +{ + return matrix->xx == scale && matrix->yy == scale && + matrix->xy == 0. && matrix->yx == 0. && + matrix->x0 == 0. && matrix->y0 == 0.; +} + +static cairo_status_t +_cairo_win32_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font) +{ + HFONT hfont = NULL; + + cairo_win32_font_face_t *font_face = abstract_face; + + if (font_face->hfont) { + /* Check whether it's OK to go ahead and use the font-face's HFONT. */ + if (_is_scale (ctm, 1.) && + _is_scale (font_matrix, -font_face->logfont.lfHeight)) { + hfont = font_face->hfont; + } + } + + return _win32_scaled_font_create (&font_face->logfont, + hfont, + &font_face->base, + font_matrix, ctm, options, + font); +} + +const cairo_font_face_backend_t _cairo_win32_font_face_backend = { + CAIRO_FONT_TYPE_WIN32, + _cairo_win32_font_face_create_for_toy, + _cairo_win32_font_face_destroy, + _cairo_win32_font_face_scaled_font_create +}; + /** * cairo_win32_font_face_create_for_logfontw_hfont: * @logfont: A #LOGFONTW structure specifying the font to use. diff --git a/src/win32/cairo-win32-gdi-compositor.c b/src/win32/cairo-win32-gdi-compositor.c index c70b0f90a..073e889ab 100755..100644 --- a/src/win32/cairo-win32-gdi-compositor.c +++ b/src/win32/cairo-win32-gdi-compositor.c @@ -151,10 +151,11 @@ static cairo_bool_t upload_box (cairo_box_t *box, void *closure) int y = _cairo_fixed_integer_part (box->p1.y); int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x); int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y); + int src_height = -cb->bi.bmiHeader.biHeight; TRACE ((stderr, "%s\n", __FUNCTION__)); return StretchDIBits (cb->dst, x, y + height - 1, width, -height, - x + cb->tx, height - (y + cb->ty - 1), + x + cb->tx, src_height - (y + cb->ty - 1), width, -height, cb->data, &cb->bi, DIB_RGB_COLORS, SRCCOPY); diff --git a/src/win32/cairo-win32-printing-surface.c b/src/win32/cairo-win32-printing-surface.c index be91445cf..6005cb53d 100755..100644 --- a/src/win32/cairo-win32-printing-surface.c +++ b/src/win32/cairo-win32-printing-surface.c @@ -726,6 +726,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_ /* _cairo_pattern_set_matrix guarantees invertibility */ assert (status == CAIRO_STATUS_SUCCESS); + cairo_matrix_multiply (&m, &m, &surface->ctm); cairo_matrix_multiply (&m, &m, &surface->gdi_ctm); SaveDC (surface->win32.dc); _cairo_matrix_to_win32_xform (&m, &xform); @@ -1578,14 +1579,18 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac * CAIRO_INT_STATUS_UNSUPPORTED and a fallback image will be * used. */ + _cairo_scaled_font_freeze_cache (scaled_font); for (i = 0; i < num_glyphs; i++) { status = _cairo_scaled_glyph_lookup (scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_PATH, &scaled_glyph); if (status) - return status; + break; } + _cairo_scaled_font_thaw_cache (scaled_font); + if (status) + return status; return _cairo_win32_printing_surface_analyze_operation (surface, op, source); } @@ -1623,6 +1628,7 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac old_has_ctm = surface->has_ctm; surface->has_ctm = TRUE; surface->path_empty = TRUE; + _cairo_scaled_font_freeze_cache (scaled_font); BeginPath (surface->win32.dc); for (i = 0; i < num_glyphs; i++) { status = _cairo_scaled_glyph_lookup (scaled_font, @@ -1636,6 +1642,7 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac status = _cairo_win32_printing_surface_emit_path (surface, scaled_glyph->path); } EndPath (surface->win32.dc); + _cairo_scaled_font_thaw_cache (scaled_font); surface->ctm = old_ctm; surface->has_ctm = old_has_ctm; if (status == CAIRO_STATUS_SUCCESS && surface->path_empty == FALSE) { diff --git a/src/win32/cairo-win32-private.h b/src/win32/cairo-win32-private.h index b6c24311a..b6c24311a 100755..100644 --- a/src/win32/cairo-win32-private.h +++ b/src/win32/cairo-win32-private.h diff --git a/src/win32/cairo-win32-surface.c b/src/win32/cairo-win32-surface.c index 7cd46fc60..e6862bd10 100755..100644 --- a/src/win32/cairo-win32-surface.c +++ b/src/win32/cairo-win32-surface.c @@ -172,6 +172,21 @@ cairo_win32_surface_get_dc (cairo_surface_t *surface) } /** + * _cairo_surface_is_win32: + * @surface: a #cairo_surface_t + * + * Checks if a surface is an #cairo_win32_surface_t + * + * Return value: %TRUE if the surface is an win32 surface + **/ +static inline cairo_bool_t +_cairo_surface_is_win32 (const cairo_surface_t *surface) +{ + /* _cairo_surface_nil sets a NULL backend so be safe */ + return surface->backend && surface->backend->type == CAIRO_SURFACE_TYPE_WIN32; +} + +/** * cairo_win32_surface_get_image: * @surface: a #cairo_surface_t * @@ -187,8 +202,10 @@ cairo_win32_surface_get_dc (cairo_surface_t *surface) cairo_surface_t * cairo_win32_surface_get_image (cairo_surface_t *surface) { - if (surface->backend->type != CAIRO_SURFACE_TYPE_WIN32) - return NULL; + + if (! _cairo_surface_is_win32 (surface)) { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + } GdiFlush(); return to_win32_display_surface(surface)->image; diff --git a/src/win32/cairo-win32-system.c b/src/win32/cairo-win32-system.c index 878553009..878553009 100755..100644 --- a/src/win32/cairo-win32-system.c +++ b/src/win32/cairo-win32-system.c |