diff options
88 files changed, 7469 insertions, 3501 deletions
diff --git a/src/Makefile.sources b/src/Makefile.sources index 5371e81ca..97f452a70 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -118,9 +118,14 @@ cairo_sources = \ cairo-bentley-ottmann-rectilinear.c \ cairo-botor-scan-converter.c \ cairo-boxes.c \ + cairo-boxes-intersect.c \ cairo.c \ cairo-cache.c \ cairo-clip.c \ + cairo-clip-boxes.c \ + cairo-clip-polygon.c \ + cairo-clip-region.c \ + cairo-clip-surface.c \ cairo-color.c \ cairo-composite-rectangles.c \ cairo-debug.c \ @@ -156,6 +161,8 @@ cairo_sources = \ cairo-pattern.c \ cairo-pen.c \ cairo-polygon.c \ + cairo-polygon-intersect.c \ + cairo-polygon-reduce.c \ cairo-recording-surface.c \ cairo-rectangle.c \ cairo-rectangular-scan-converter.c \ diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index affa55634..aa0977ec7 100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c @@ -67,8 +67,8 @@ _cairo_analysis_surface_merge_status (cairo_int_status_t status_a, cairo_int_status_t status_b) { /* fatal errors should be checked and propagated at source */ - assert (! _cairo_status_is_error (status_a)); - assert (! _cairo_status_is_error (status_b)); + assert (! _cairo_int_status_is_error (status_a)); + assert (! _cairo_int_status_is_error (status_b)); /* return the most important status */ if (status_a == CAIRO_INT_STATUS_UNSUPPORTED || @@ -88,10 +88,10 @@ _cairo_analysis_surface_merge_status (cairo_int_status_t status_a, return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; /* at this point we have checked all the valid internal codes, so... */ - assert (status_a == CAIRO_STATUS_SUCCESS && - status_b == CAIRO_STATUS_SUCCESS); + assert (status_a == CAIRO_INT_STATUS_SUCCESS && + status_b == CAIRO_INT_STATUS_SUCCESS); - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } static cairo_int_status_t @@ -144,10 +144,10 @@ _add_operation (cairo_analysis_surface_t *surface, /* Even though the operation is not visible we must be careful * to not allow unsupported operations to be replayed to the * backend during CAIRO_PAGINATED_MODE_RENDER */ - if (backend_status == CAIRO_STATUS_SUCCESS || + if (backend_status == CAIRO_INT_STATUS_SUCCESS || backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) { - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } else { @@ -172,10 +172,10 @@ _add_operation (cairo_analysis_surface_t *surface, * careful to not allow unsupported operations to be * replayed to the backend during * CAIRO_PAGINATED_MODE_RENDER */ - if (backend_status == CAIRO_STATUS_SUCCESS || + if (backend_status == CAIRO_INT_STATUS_SUCCESS || backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) { - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } else { @@ -217,10 +217,10 @@ _add_operation (cairo_analysis_surface_t *surface, * transparency into the white background. */ if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT) - backend_status = CAIRO_STATUS_SUCCESS; + backend_status = CAIRO_INT_STATUS_SUCCESS; } - if (backend_status == CAIRO_STATUS_SUCCESS) { + if (backend_status == CAIRO_INT_STATUS_SUCCESS) { /* Add the operation to the supported region. Operations in * this region will be emitted as native operations. */ @@ -241,7 +241,7 @@ _add_operation (cairo_analysis_surface_t *surface, * invoke the cairo-surface-fallback path then return * CAIRO_STATUS_SUCCESS. */ - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) return CAIRO_INT_STATUS_IMAGE_FALLBACK; else return status; @@ -270,23 +270,17 @@ _cairo_analysis_surface_get_extents (void *abstract_surface, } static void -_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip) +_rectangle_intersect_clip (cairo_rectangle_int_t *extents, const cairo_clip_t *clip) { - const cairo_rectangle_int_t *clip_extents; - - clip_extents = NULL; if (clip != NULL) - clip_extents = _cairo_clip_get_extents (clip); - - if (clip_extents != NULL) - _cairo_rectangle_intersect (extents, clip_extents); + _cairo_rectangle_intersect (extents, _cairo_clip_get_extents (clip)); } static void _cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip, + const cairo_clip_t *clip, cairo_rectangle_int_t *extents) { cairo_bool_t is_empty; @@ -307,10 +301,10 @@ static cairo_int_status_t _cairo_analysis_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; - cairo_status_t backend_status; + cairo_int_status_t backend_status; cairo_rectangle_int_t extents; if (surface->target->backend->paint == NULL) { @@ -319,7 +313,7 @@ _cairo_analysis_surface_paint (void *abstract_surface, backend_status = surface->target->backend->paint (surface->target, op, source, clip); - if (_cairo_status_is_error (backend_status)) + if (_cairo_int_status_is_error (backend_status)) return backend_status; } @@ -338,7 +332,7 @@ _cairo_analysis_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; cairo_int_status_t backend_status; @@ -350,7 +344,7 @@ _cairo_analysis_surface_mask (void *abstract_surface, backend_status = surface->target->backend->mask (surface->target, op, source, mask, clip); - if (_cairo_status_is_error (backend_status)) + if (_cairo_int_status_is_error (backend_status)) return backend_status; } @@ -363,7 +357,7 @@ _cairo_analysis_surface_mask (void *abstract_surface, if (_cairo_surface_is_recording (surface_pattern->surface)) { backend_source_status = _analyze_recording_surface_pattern (surface, source); - if (_cairo_status_is_error (backend_source_status)) + if (_cairo_int_status_is_error (backend_source_status)) return backend_source_status; } } @@ -373,7 +367,7 @@ _cairo_analysis_surface_mask (void *abstract_surface, if (_cairo_surface_is_recording (surface_pattern->surface)) { backend_mask_status = _analyze_recording_surface_pattern (surface, mask); - if (_cairo_status_is_error (backend_mask_status)) + if (_cairo_int_status_is_error (backend_mask_status)) return backend_mask_status; } } @@ -401,16 +395,16 @@ static cairo_int_status_t _cairo_analysis_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; - cairo_status_t backend_status; + cairo_int_status_t backend_status; cairo_rectangle_int_t extents; if (surface->target->backend->stroke == NULL) { @@ -422,7 +416,7 @@ _cairo_analysis_surface_stroke (void *abstract_surface, ctm, ctm_inverse, tolerance, antialias, clip); - if (_cairo_status_is_error (backend_status)) + if (_cairo_int_status_is_error (backend_status)) return backend_status; } @@ -435,7 +429,7 @@ _cairo_analysis_surface_stroke (void *abstract_surface, if (_cairo_operator_bounded_by_mask (op)) { cairo_rectangle_int_t mask_extents; - cairo_status_t status; + cairo_int_status_t status; status = _cairo_path_fixed_stroke_extents (path, style, ctm, ctm_inverse, @@ -454,14 +448,14 @@ static cairo_int_status_t _cairo_analysis_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; - cairo_status_t backend_status; + cairo_int_status_t backend_status; cairo_rectangle_int_t extents; if (surface->target->backend->fill == NULL) { @@ -472,7 +466,7 @@ _cairo_analysis_surface_fill (void *abstract_surface, source, path, fill_rule, tolerance, antialias, clip); - if (_cairo_status_is_error (backend_status)) + if (_cairo_int_status_is_error (backend_status)) return backend_status; } @@ -502,11 +496,11 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs) { cairo_analysis_surface_t *surface = abstract_surface; - cairo_status_t status, backend_status; + cairo_int_status_t status, backend_status; cairo_rectangle_int_t extents, glyph_extents; /* Adapted from _cairo_surface_show_glyphs */ @@ -518,7 +512,7 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface, scaled_font, clip, remaining_glyphs); - if (_cairo_status_is_error (backend_status)) + if (_cairo_int_status_is_error (backend_status)) return backend_status; } else if (surface->target->backend->show_text_glyphs != NULL) @@ -532,7 +526,7 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface, FALSE, scaled_font, clip); - if (_cairo_status_is_error (backend_status)) + if (_cairo_int_status_is_error (backend_status)) return backend_status; } else @@ -582,10 +576,10 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; - cairo_status_t status, backend_status; + cairo_int_status_t status, backend_status; cairo_rectangle_int_t extents, glyph_extents; /* Adapted from _cairo_surface_show_glyphs */ @@ -600,7 +594,7 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, cluster_flags, scaled_font, clip); - if (_cairo_status_is_error (backend_status)) + if (_cairo_int_status_is_error (backend_status)) return backend_status; } if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && @@ -614,7 +608,7 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, scaled_font, clip, &remaining_glyphs); - if (_cairo_status_is_error (backend_status)) + if (_cairo_int_status_is_error (backend_status)) return backend_status; glyphs += num_glyphs - remaining_glyphs; @@ -803,36 +797,36 @@ typedef cairo_int_status_t (*_paint_func) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip); + const cairo_clip_t *clip); typedef cairo_int_status_t (*_mask_func) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip); + const cairo_clip_t *clip); typedef cairo_int_status_t (*_stroke_func) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); typedef cairo_int_status_t (*_fill_func) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); typedef cairo_int_status_t (*_show_glyphs_func) (void *surface, @@ -841,7 +835,7 @@ typedef cairo_int_status_t cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs); static const cairo_surface_backend_t cairo_null_surface_backend = { diff --git a/src/cairo-bentley-ottmann-rectangular.c b/src/cairo-bentley-ottmann-rectangular.c index 9a4dcd9f3..ceeddd303 100644 --- a/src/cairo-bentley-ottmann-rectangular.c +++ b/src/cairo-bentley-ottmann-rectangular.c @@ -320,7 +320,7 @@ edge_end_box (sweep_line_t *sweep_line, box.p2.x = left->right->x; box.p2.y = bot; - status = _cairo_boxes_add (container, &box); + status = _cairo_boxes_add (container, CAIRO_ANTIALIAS_DEFAULT, &box); } } if (unlikely (status)) @@ -746,7 +746,7 @@ _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in, box.p2.x = tmp; } - status = _cairo_boxes_add (out, &box); + status = _cairo_boxes_add (out, CAIRO_ANTIALIAS_DEFAULT, &box); assert (status == CAIRO_STATUS_SUCCESS); return CAIRO_STATUS_SUCCESS; } diff --git a/src/cairo-bentley-ottmann-rectilinear.c b/src/cairo-bentley-ottmann-rectilinear.c index 1696d9367..a3eb4901a 100644 --- a/src/cairo-bentley-ottmann-rectilinear.c +++ b/src/cairo-bentley-ottmann-rectilinear.c @@ -237,7 +237,7 @@ _cairo_bo_edge_end_trap (cairo_bo_edge_t *left, box.p1.y = trap->top; box.p2.x = trap->right->edge.line.p1.x; box.p2.y = bot; - status = _cairo_boxes_add (container, &box); + status = _cairo_boxes_add (container, CAIRO_ANTIALIAS_DEFAULT, &box); } } diff --git a/src/cairo-boxes-intersect.c b/src/cairo-boxes-intersect.c new file mode 100644 index 000000000..831abc104 --- /dev/null +++ b/src/cairo-boxes-intersect.c @@ -0,0 +1,666 @@ +/* + * Copyright © 2004 Carl Worth + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Carl Worth + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +/* Provide definitions for standalone compilation */ +#include "cairoint.h" + +#include "cairo-boxes-private.h" +#include "cairo-error-private.h" +#include "cairo-combsort-private.h" +#include "cairo-list-private.h" + +#include <setjmp.h> + +typedef struct _rectangle rectangle_t; +typedef struct _edge edge_t; + +struct _edge { + edge_t *next, *prev; + edge_t *right; + cairo_fixed_t x, top; + int a_or_b; + int dir; +}; + +struct _rectangle { + edge_t left, right; + int32_t top, bottom; +}; + +#define UNROLL3(x) x x x + +/* the parent is always given by index/2 */ +#define PQ_PARENT_INDEX(i) ((i) >> 1) +#define PQ_FIRST_ENTRY 1 + +/* left and right children are index * 2 and (index * 2) +1 respectively */ +#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1) + +typedef struct _pqueue { + int size, max_size; + + rectangle_t **elements; + rectangle_t *elements_embedded[1024]; +} pqueue_t; + +typedef struct _sweep_line { + rectangle_t **rectangles; + pqueue_t pq; + edge_t head, tail; + edge_t *insert_left, *insert_right; + int32_t current_y; + int32_t last_y; + + jmp_buf unwind; +} sweep_line_t; + +#define DEBUG_TRAPS 0 + +#if DEBUG_TRAPS +static void +dump_traps (cairo_traps_t *traps, const char *filename) +{ + FILE *file; + int n; + + if (getenv ("CAIRO_DEBUG_TRAPS") == NULL) + return; + + file = fopen (filename, "a"); + if (file != NULL) { + for (n = 0; n < traps->num_traps; n++) { + fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n", + traps->traps[n].top, + traps->traps[n].bottom, + traps->traps[n].left.p1.x, + traps->traps[n].left.p1.y, + traps->traps[n].left.p2.x, + traps->traps[n].left.p2.y, + traps->traps[n].right.p1.x, + traps->traps[n].right.p1.y, + traps->traps[n].right.p2.x, + traps->traps[n].right.p2.y); + } + fprintf (file, "\n"); + fclose (file); + } +} +#else +#define dump_traps(traps, filename) +#endif + +static inline int +rectangle_compare_start (const rectangle_t *a, + const rectangle_t *b) +{ + return a->top - b->top; +} + +static inline int +rectangle_compare_stop (const rectangle_t *a, + const rectangle_t *b) +{ + return a->bottom - b->bottom; +} + +static inline void +pqueue_init (pqueue_t *pq) +{ + pq->max_size = ARRAY_LENGTH (pq->elements_embedded); + pq->size = 0; + + pq->elements = pq->elements_embedded; + pq->elements[PQ_FIRST_ENTRY] = NULL; +} + +static inline void +pqueue_fini (pqueue_t *pq) +{ + if (pq->elements != pq->elements_embedded) + free (pq->elements); +} + +static cairo_bool_t +pqueue_grow (pqueue_t *pq) +{ + rectangle_t **new_elements; + pq->max_size *= 2; + + if (pq->elements == pq->elements_embedded) { + new_elements = _cairo_malloc_ab (pq->max_size, + sizeof (rectangle_t *)); + if (unlikely (new_elements == NULL)) + return FALSE; + + memcpy (new_elements, pq->elements_embedded, + sizeof (pq->elements_embedded)); + } else { + new_elements = _cairo_realloc_ab (pq->elements, + pq->max_size, + sizeof (rectangle_t *)); + if (unlikely (new_elements == NULL)) + return FALSE; + } + + pq->elements = new_elements; + return TRUE; +} + +static inline void +pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle) +{ + rectangle_t **elements; + int i, parent; + + if (unlikely (sweep->pq.size + 1 == sweep->pq.max_size)) { + if (unlikely (! pqueue_grow (&sweep->pq))) { + longjmp (sweep->unwind, + _cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + } + + elements = sweep->pq.elements; + for (i = ++sweep->pq.size; + i != PQ_FIRST_ENTRY && + rectangle_compare_stop (rectangle, + elements[parent = PQ_PARENT_INDEX (i)]) < 0; + i = parent) + { + elements[i] = elements[parent]; + } + + elements[i] = rectangle; +} + +static inline void +pqueue_pop (pqueue_t *pq) +{ + rectangle_t **elements = pq->elements; + rectangle_t *tail; + int child, i; + + tail = elements[pq->size--]; + if (pq->size == 0) { + elements[PQ_FIRST_ENTRY] = NULL; + return; + } + + for (i = PQ_FIRST_ENTRY; + (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size; + i = child) + { + if (child != pq->size && + rectangle_compare_stop (elements[child+1], + elements[child]) < 0) + { + child++; + } + + if (rectangle_compare_stop (elements[child], tail) >= 0) + break; + + elements[i] = elements[child]; + } + elements[i] = tail; +} + +static inline rectangle_t * +rectangle_pop_start (sweep_line_t *sweep_line) +{ + return *sweep_line->rectangles++; +} + +static inline rectangle_t * +rectangle_peek_stop (sweep_line_t *sweep_line) +{ + return sweep_line->pq.elements[PQ_FIRST_ENTRY]; +} + +CAIRO_COMBSORT_DECLARE (_rectangle_sort, + rectangle_t *, + rectangle_compare_start) + +static void +sweep_line_init (sweep_line_t *sweep_line, + rectangle_t **rectangles, + int num_rectangles) +{ + _rectangle_sort (rectangles, num_rectangles); + rectangles[num_rectangles] = NULL; + sweep_line->rectangles = rectangles; + + sweep_line->head.x = INT32_MIN; + sweep_line->head.right = NULL; + sweep_line->head.dir = 0; + sweep_line->head.next = &sweep_line->tail; + sweep_line->tail.x = INT32_MAX; + sweep_line->tail.right = NULL; + sweep_line->tail.dir = 0; + sweep_line->tail.prev = &sweep_line->head; + + sweep_line->insert_left = &sweep_line->tail; + sweep_line->insert_right = &sweep_line->tail; + + sweep_line->current_y = INT32_MIN; + sweep_line->last_y = INT32_MIN; + + pqueue_init (&sweep_line->pq); +} + +static void +sweep_line_fini (sweep_line_t *sweep_line) +{ + pqueue_fini (&sweep_line->pq); +} + +static void +end_box (sweep_line_t *sweep_line, edge_t *left, int32_t bot, cairo_boxes_t *out) +{ + if (likely (left->top < bot)) { + cairo_status_t status; + cairo_box_t box; + + box.p1.x = left->x; + box.p1.y = left->top; + box.p2.x = left->right->x; + box.p2.y = bot; + + status = _cairo_boxes_add (out, CAIRO_ANTIALIAS_DEFAULT, &box); + if (unlikely (status)) + longjmp (sweep_line->unwind, status); + } + + left->right = NULL; +} + +/* Start a new trapezoid at the given top y coordinate, whose edges + * are `edge' and `edge->next'. If `edge' already has a trapezoid, + * then either add it to the traps in `traps', if the trapezoid's + * right edge differs from `edge->next', or do nothing if the new + * trapezoid would be a continuation of the existing one. */ +static inline void +start_or_continue_box (sweep_line_t *sweep_line, + edge_t *left, + edge_t *right, + int top, + cairo_boxes_t *out) +{ + if (left->right == right) + return; + + if (left->right != NULL) { + if (right != NULL && left->right->x == right->x) { + /* continuation on right, so just swap edges */ + left->right = right; + return; + } + + end_box (sweep_line, left, top, out); + } + + if (right != NULL && left->x != right->x) { + left->top = top; + left->right = right; + } +} + +static inline int is_zero(const int *winding) +{ + return winding[0] == 0 || winding[1] == 0; +} + +static inline void +active_edges (sweep_line_t *sweep, cairo_boxes_t *out) +{ + int top = sweep->current_y; + int winding[2] = { 0 }; + edge_t *pos; + + if (sweep->last_y == sweep->current_y) + return; + + pos = sweep->head.next; + if (pos == &sweep->tail) + return; + + do { + edge_t *left, *right; + + left = pos; + do { + winding[left->a_or_b] += left->dir; + if (!is_zero (winding)) + break; + if (left->next == &sweep->tail) + goto out; + + if (unlikely (left->right != NULL)) + end_box (sweep, left, top, out); + + left = left->next; + } while (1); + + right = left->next; + do { + if (unlikely (right->right != NULL)) + end_box (sweep, right, top, out); + + winding[right->a_or_b] += right->dir; + if (is_zero (winding)) { + /* skip co-linear edges */ + if (likely (right->x != right->next->x)) + break; + } + + right = right->next; + } while (TRUE); + + start_or_continue_box (sweep, left, right, top, out); + + pos = right->next; + } while (pos != &sweep->tail); + +out: + sweep->last_y = sweep->current_y; +} + +static inline void +sweep_line_delete_edge (sweep_line_t *sweep_line, edge_t *edge, cairo_boxes_t *out) +{ + if (edge->right != NULL) { + edge_t *next = edge->next; + if (next->x == edge->x) { + next->top = edge->top; + next->right = edge->right; + } else { + end_box (sweep_line, edge, sweep_line->current_y, out); + } + } + + if (sweep_line->insert_left == edge) + sweep_line->insert_left = edge->next; + if (sweep_line->insert_right == edge) + sweep_line->insert_right = edge->next; + + edge->prev->next = edge->next; + edge->next->prev = edge->prev; +} + +static inline void +sweep_line_delete (sweep_line_t *sweep, + rectangle_t *rectangle, + cairo_boxes_t *out) +{ + sweep_line_delete_edge (sweep, &rectangle->left, out); + sweep_line_delete_edge (sweep, &rectangle->right, out); + + pqueue_pop (&sweep->pq); +} + +static inline void +insert_edge (edge_t *edge, edge_t *pos) +{ + if (pos->x != edge->x) { + if (pos->x > edge->x) { + do { + UNROLL3({ + if (pos->prev->x <= edge->x) + break; + pos = pos->prev; + }) + } while (TRUE); + } else { + do { + UNROLL3({ + pos = pos->next; + if (pos->x >= edge->x) + break; + }) + } while (TRUE); + } + } + + pos->prev->next = edge; + edge->prev = pos->prev; + edge->next = pos; + pos->prev = edge; +} + +static inline void +sweep_line_insert (sweep_line_t *sweep, rectangle_t *rectangle) +{ + edge_t *pos; + + /* right edge */ + pos = sweep->insert_right; + insert_edge (&rectangle->right, pos); + sweep->insert_right = &rectangle->right; + + /* left edge */ + pos = sweep->insert_left; + if (pos->x > sweep->insert_right->x) + pos = sweep->insert_right->prev; + insert_edge (&rectangle->left, pos); + sweep->insert_left = &rectangle->left; + + pqueue_push (sweep, rectangle); +} + +static cairo_status_t +intersect (rectangle_t **rectangles, int num_rectangles, cairo_boxes_t *out) +{ + sweep_line_t sweep_line; + rectangle_t *rectangle; + cairo_status_t status; + + sweep_line_init (&sweep_line, rectangles, num_rectangles); + if ((status = setjmp (sweep_line.unwind))) + goto unwind; + + rectangle = rectangle_pop_start (&sweep_line); + do { + if (rectangle->top != sweep_line.current_y) { + rectangle_t *stop; + + stop = rectangle_peek_stop (&sweep_line); + while (stop != NULL && stop->bottom < rectangle->top) { + if (stop->bottom != sweep_line.current_y) { + active_edges (&sweep_line, out); + sweep_line.current_y = stop->bottom; + } + + sweep_line_delete (&sweep_line, stop, out); + + stop = rectangle_peek_stop (&sweep_line); + } + + active_edges (&sweep_line, out); + sweep_line.current_y = rectangle->top; + } + + sweep_line_insert (&sweep_line, rectangle); + } while ((rectangle = rectangle_pop_start (&sweep_line)) != NULL); + + while ((rectangle = rectangle_peek_stop (&sweep_line)) != NULL) { + if (rectangle->bottom != sweep_line.current_y) { + active_edges (&sweep_line, out); + sweep_line.current_y = rectangle->bottom; + } + + sweep_line_delete (&sweep_line, rectangle, out); + } + +unwind: + sweep_line_fini (&sweep_line); + return status; +} + +static cairo_status_t +_cairo_boxes_intersect_with_box (const cairo_boxes_t *boxes, + const cairo_box_t *box, + cairo_boxes_t *out) +{ + const struct _cairo_boxes_chunk *chunk; + cairo_status_t status; + int i; + + _cairo_boxes_clear (out); + _cairo_boxes_limit (out, box, 1); + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + status = _cairo_boxes_add (out, + CAIRO_ANTIALIAS_DEFAULT, + &chunk->base[i]); + if (unlikely (status)) + return status; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_boxes_intersect (const cairo_boxes_t *a, + const cairo_boxes_t *b, + cairo_boxes_t *out) +{ + rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)]; + rectangle_t *rectangles; + rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1]; + rectangle_t **rectangles_ptrs; + const struct _cairo_boxes_chunk *chunk; + cairo_status_t status; + int i, j, count; + + if (unlikely (a->num_boxes == 0 || b->num_boxes == 0)) { + _cairo_boxes_clear (out); + return CAIRO_STATUS_SUCCESS; + } + + if (unlikely (a->num_boxes == 1)) { + cairo_box_t box = a->chunks.base[0]; + return _cairo_boxes_intersect_with_box (b, &box, out); + } + if (unlikely (b->num_boxes == 1)) { + cairo_box_t box = b->chunks.base[0]; + return _cairo_boxes_intersect_with_box (a, &box, out); + /* XXX */ + } + + rectangles = stack_rectangles; + rectangles_ptrs = stack_rectangles_ptrs; + count = a->num_boxes + b->num_boxes; + if (count > ARRAY_LENGTH (stack_rectangles)) { + rectangles = _cairo_malloc_ab_plus_c (count, + sizeof (rectangle_t) + + sizeof (rectangle_t *), + sizeof (rectangle_t *)); + if (unlikely (rectangles == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + rectangles_ptrs = (rectangle_t **) (rectangles + count); + } + + j = 0; + for (chunk = &a->chunks; chunk != NULL; chunk = chunk->next) { + const cairo_box_t *box = chunk->base; + for (i = 0; i < chunk->count; i++) { + if (box[i].p1.x < box[i].p2.x) { + rectangles[j].left.x = box[i].p1.x; + rectangles[j].left.dir = 1; + + rectangles[j].right.x = box[i].p2.x; + rectangles[j].right.dir = -1; + } else { + rectangles[j].right.x = box[i].p1.x; + rectangles[j].right.dir = 1; + + rectangles[j].left.x = box[i].p2.x; + rectangles[j].left.dir = -1; + } + + rectangles[j].left.a_or_b = 0; + rectangles[j].left.right = NULL; + rectangles[j].right.a_or_b = 0; + rectangles[j].right.right = NULL; + + rectangles[j].top = box[i].p1.y; + rectangles[j].bottom = box[i].p2.y; + + rectangles_ptrs[j] = &rectangles[j]; + j++; + } + } + for (chunk = &b->chunks; chunk != NULL; chunk = chunk->next) { + const cairo_box_t *box = chunk->base; + for (i = 0; i < chunk->count; i++) { + if (box[i].p1.x < box[i].p2.x) { + rectangles[j].left.x = box[i].p1.x; + rectangles[j].left.dir = 1; + + rectangles[j].right.x = box[i].p2.x; + rectangles[j].right.dir = -1; + } else { + rectangles[j].right.x = box[i].p1.x; + rectangles[j].right.dir = 1; + + rectangles[j].left.x = box[i].p2.x; + rectangles[j].left.dir = -1; + } + + rectangles[j].left.a_or_b = 1; + rectangles[j].left.right = NULL; + rectangles[j].right.a_or_b = 1; + rectangles[j].right.right = NULL; + + rectangles[j].top = box[i].p1.y; + rectangles[j].bottom = box[i].p2.y; + + rectangles_ptrs[j] = &rectangles[j]; + j++; + } + } + assert (j == count); + + _cairo_boxes_clear (out); + status = intersect (rectangles_ptrs, j, out); + if (rectangles != stack_rectangles) + free (rectangles); + + return status; +} diff --git a/src/cairo-boxes-private.h b/src/cairo-boxes-private.h index 3af0fbdef..619545f61 100644 --- a/src/cairo-boxes-private.h +++ b/src/cairo-boxes-private.h @@ -58,6 +58,10 @@ cairo_private void _cairo_boxes_init (cairo_boxes_t *boxes); cairo_private void +_cairo_boxes_init_with_clip (cairo_boxes_t *boxes, + cairo_clip_t *clip); + +cairo_private void _cairo_boxes_init_for_array (cairo_boxes_t *boxes, cairo_box_t *array, int num_boxes); @@ -69,16 +73,39 @@ _cairo_boxes_limit (cairo_boxes_t *boxes, cairo_private cairo_status_t _cairo_boxes_add (cairo_boxes_t *boxes, + cairo_antialias_t antialias, const cairo_box_t *box); cairo_private void _cairo_boxes_extents (const cairo_boxes_t *boxes, cairo_rectangle_int_t *extents); +cairo_private cairo_box_t * +_cairo_boxes_to_array (const cairo_boxes_t *boxes, + int *num_boxes, + cairo_bool_t force_allocation); + +static inline void +_cairo_boxes_free_array (const cairo_boxes_t *boxes, + cairo_box_t *box) +{ + if (box != boxes->chunks.base) + free(box); +} + +cairo_private cairo_status_t +_cairo_boxes_intersect (const cairo_boxes_t *a, + const cairo_boxes_t *b, + cairo_boxes_t *out); + cairo_private void _cairo_boxes_clear (cairo_boxes_t *boxes); cairo_private void _cairo_boxes_fini (cairo_boxes_t *boxes); +cairo_private void +_cairo_debug_print_boxes (FILE *stream, + const cairo_boxes_t *boxes); + #endif /* CAIRO_BOXES_H */ diff --git a/src/cairo-boxes.c b/src/cairo-boxes.c index 31bfc0e4e..130a44c76 100644 --- a/src/cairo-boxes.c +++ b/src/cairo-boxes.c @@ -53,6 +53,15 @@ _cairo_boxes_init (cairo_boxes_t *boxes) } void +_cairo_boxes_init_with_clip (cairo_boxes_t *boxes, + cairo_clip_t *clip) +{ + _cairo_boxes_init (boxes); + if (clip) + _cairo_boxes_limit (boxes, clip->boxes, clip->num_boxes); +} + +void _cairo_boxes_init_for_array (cairo_boxes_t *boxes, cairo_box_t *array, int num_boxes) @@ -156,8 +165,19 @@ _cairo_boxes_add_internal (cairo_boxes_t *boxes, cairo_status_t _cairo_boxes_add (cairo_boxes_t *boxes, + cairo_antialias_t antialias, const cairo_box_t *box) { + cairo_box_t b; + + if (antialias == CAIRO_ANTIALIAS_NONE) { + b.p1.x = _cairo_fixed_round_down (box->p1.x); + b.p1.y = _cairo_fixed_round_down (box->p1.y); + b.p2.x = _cairo_fixed_round_down (box->p2.x); + b.p2.y = _cairo_fixed_round_down (box->p2.y); + box = &b; + } + if (box->p1.y == box->p2.y) return CAIRO_STATUS_SUCCESS; @@ -247,6 +267,11 @@ _cairo_boxes_extents (const cairo_boxes_t *boxes, cairo_box_t box; int i; + if (boxes->num_boxes == 0) { + extents->x = extents->y = extents->width = extents->height = 0; + return; + } + box.p1.y = box.p1.x = INT_MAX; box.p2.y = box.p2.x = INT_MIN; @@ -283,11 +308,41 @@ _cairo_boxes_clear (cairo_boxes_t *boxes) boxes->tail = &boxes->chunks; boxes->chunks.next = 0; boxes->chunks.count = 0; + boxes->chunks.base = boxes->boxes_embedded; + boxes->chunks.size = ARRAY_LENGTH (boxes->boxes_embedded); boxes->num_boxes = 0; boxes->is_pixel_aligned = TRUE; } +cairo_box_t * +_cairo_boxes_to_array (const cairo_boxes_t *boxes, + int *num_boxes, + cairo_bool_t force_allocation) +{ + const struct _cairo_boxes_chunk *chunk; + cairo_box_t *box; + int i, j; + + *num_boxes = boxes->num_boxes; + if (boxes->chunks.next == NULL && ! force_allocation) + return boxes->chunks.base; + + box = _cairo_malloc_ab (boxes->num_boxes, sizeof (cairo_box_t)); + if (box == NULL) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + j = 0; + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) + box[j++] = chunk->base[i]; + } + + return box; +} + void _cairo_boxes_fini (cairo_boxes_t *boxes) { @@ -298,3 +353,26 @@ _cairo_boxes_fini (cairo_boxes_t *boxes) free (chunk); } } + +void +_cairo_debug_print_boxes (FILE *stream, const cairo_boxes_t *boxes) +{ + cairo_rectangle_int_t extents; + const struct _cairo_boxes_chunk *chunk; + int i; + + _cairo_boxes_extents (boxes, &extents); + fprintf (stream, "boxes x %d: (%d, %d) x (%d, %d)\n", + boxes->num_boxes, + extents.x, extents.y, extents.width, extents.height); + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + fprintf (stderr, " box[%d]: (%f, %f), (%f, %f)\n", i, + _cairo_fixed_to_double (chunk->base[i].p1.x), + _cairo_fixed_to_double (chunk->base[i].p1.y), + _cairo_fixed_to_double (chunk->base[i].p2.x), + _cairo_fixed_to_double (chunk->base[i].p2.y)); + } + } +} diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c index 1a52ca26c..02f2cba61 100644 --- a/src/cairo-cff-subset.c +++ b/src/cairo-cff-subset.c @@ -1373,12 +1373,12 @@ cairo_cff_find_subroutines_used (cairo_cff_font_t *font, return cairo_cff_parse_charstring (font, charstring, length, glyph_id); } -static cairo_status_t +static cairo_int_status_t cairo_cff_font_subset_charstrings_and_subroutines (cairo_cff_font_t *font) { cff_index_element_t *element; unsigned int i; - cairo_status_t status; + cairo_int_status_t status; unsigned long glyph; font->subset_subroutines = TRUE; @@ -1758,23 +1758,23 @@ cairo_cff_font_write_fdselect (cairo_cff_font_t *font) byte = 3; status = _cairo_array_append (&font->output, &byte); - assert (status == CAIRO_STATUS_SUCCESS); + assert (status == CAIRO_INT_STATUS_SUCCESS); word = cpu_to_be16 (1); status = _cairo_array_append_multiple (&font->output, &word, 2); - assert (status == CAIRO_STATUS_SUCCESS); + assert (status == CAIRO_INT_STATUS_SUCCESS); word = cpu_to_be16 (0); status = _cairo_array_append_multiple (&font->output, &word, 2); - assert (status == CAIRO_STATUS_SUCCESS); + assert (status == CAIRO_INT_STATUS_SUCCESS); byte = 0; status = _cairo_array_append (&font->output, &byte); - assert (status == CAIRO_STATUS_SUCCESS); + assert (status == CAIRO_INT_STATUS_SUCCESS); word = cpu_to_be16 (font->scaled_font_subset->num_glyphs); status = _cairo_array_append_multiple (&font->output, &word, 2); - assert (status == CAIRO_STATUS_SUCCESS); + assert (status == CAIRO_INT_STATUS_SUCCESS); } return CAIRO_STATUS_SUCCESS; diff --git a/src/cairo-clip-boxes.c b/src/cairo-clip-boxes.c new file mode 100644 index 000000000..aa560ce54 --- /dev/null +++ b/src/cairo-clip-boxes.c @@ -0,0 +1,559 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + * Kristian Høgsberg <krh@redhat.com> + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "cairoint.h" +#include "cairo-clip-private.h" +#include "cairo-error-private.h" +#include "cairo-freed-pool-private.h" +#include "cairo-gstate-private.h" +#include "cairo-path-fixed-private.h" +#include "cairo-pattern-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-region-private.h" + +static inline int +pot (int v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + + +static cairo_bool_t +_cairo_clip_contains_rectangle_box (const cairo_clip_t *clip, + const cairo_rectangle_int_t *rect, + const cairo_box_t *box) +{ + int i; + + /* clip == NULL means no clip, so the clip contains everything */ + if (clip == NULL) + return TRUE; + + if (_cairo_clip_is_all_clipped (clip)) + return FALSE; + + /* If we have a non-trivial path, just say no */ + if (clip->path) + return FALSE; + + if (clip->extents.x > rect->x || + clip->extents.y > rect->y || + clip->extents.x + clip->extents.width < rect->x + rect->width || + clip->extents.y + clip->extents.height < rect->y + rect->height) + { + return FALSE; + } + + /* Check for a clip-box that wholly contains the rectangle */ + assert (clip->num_boxes); + for (i = 0; i < clip->num_boxes; i++) { + if (box->p1.x >= clip->boxes[i].p1.x && + box->p1.y >= clip->boxes[i].p1.y && + box->p2.x <= clip->boxes[i].p2.x && + box->p2.y <= clip->boxes[i].p2.y) + { + return TRUE; + } + } + + return FALSE; +} + +cairo_bool_t +_cairo_clip_contains_box (const cairo_clip_t *clip, + const cairo_box_t *box) +{ + cairo_rectangle_int_t rect; + + _cairo_box_round_to_rectangle (box, &rect); + return _cairo_clip_contains_rectangle_box(clip, &rect, box); +} + +cairo_bool_t +_cairo_clip_contains_rectangle (const cairo_clip_t *clip, + const cairo_rectangle_int_t *rect) +{ + cairo_box_t box; + + box.p1.x = _cairo_fixed_from_int (rect->x); + box.p1.y = _cairo_fixed_from_int (rect->y); + box.p2.x = _cairo_fixed_from_int (rect->x + rect->width); + box.p2.y = _cairo_fixed_from_int (rect->y + rect->height); + + return _cairo_clip_contains_rectangle_box (clip, rect, &box); +} + +cairo_clip_t * +_cairo_clip_intersect_rectilinear_path (cairo_clip_t *clip, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias) +{ + cairo_status_t status; + cairo_boxes_t boxes; + + _cairo_boxes_init (&boxes); + status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, + fill_rule, + antialias, + &boxes); + if (likely (status == CAIRO_STATUS_SUCCESS)) + clip = _cairo_clip_intersect_boxes (clip, &boxes); + else + clip = _cairo_clip_set_all_clipped (clip); + _cairo_boxes_fini (&boxes); + + return clip; +} + +static cairo_clip_t * +_cairo_clip_intersect_rectangle_box (cairo_clip_t *clip, + const cairo_rectangle_int_t *r, + const cairo_box_t *box) +{ + cairo_box_t extents_box; + int i, j; + + if (clip == NULL) { + clip = _cairo_clip_create (); + if (clip == NULL) + return _cairo_clip_set_all_clipped (clip); + + clip->boxes = _cairo_malloc (sizeof (cairo_box_t)); + if (clip->boxes == NULL) + return _cairo_clip_set_all_clipped (clip); + + clip->extents = *r; + clip->num_boxes = 1; + clip->boxes[0] = *box; + + return clip; + } + + if (clip->num_boxes == 0) { + clip->boxes = _cairo_malloc (sizeof (cairo_box_t)); + if (clip->boxes == NULL) + return _cairo_clip_set_all_clipped (clip); + + j = 1; + clip->boxes[0] = *box; + } else for (i = j = 0; i < clip->num_boxes; i++) { + cairo_box_t *b = &clip->boxes[j]; + + if (j != i) + *b = clip->boxes[i]; + + if (box->p1.x > b->p1.x) + b->p1.x = box->p1.x; + if (box->p2.x < b->p2.x) + b->p2.x = box->p2.x; + + if (box->p1.y > b->p1.y) + b->p1.y = box->p1.y; + if (box->p2.y < b->p2.y) + b->p2.y = box->p2.y; + + j += b->p2.x > b->p1.x && b->p2.y > b->p1.y; + } + clip->num_boxes = j; + + if (clip->num_boxes == 0) + return _cairo_clip_set_all_clipped (clip); + + extents_box = clip->boxes[0]; + for (i = 1; i < clip->num_boxes; i++) { + if (clip->boxes[i].p1.x < extents_box.p1.x) + extents_box.p1.x = clip->boxes[i].p1.x; + + if (clip->boxes[i].p1.y < extents_box.p1.y) + extents_box.p1.y = clip->boxes[i].p1.y; + + if (clip->boxes[i].p2.x > extents_box.p2.x) + extents_box.p2.x = clip->boxes[i].p2.x; + + if (clip->boxes[i].p2.y > extents_box.p2.y) + extents_box.p2.y = clip->boxes[i].p2.y; + } + + if (clip->path == NULL) { + _cairo_box_round_to_rectangle (&extents_box, &clip->extents); + } else { + cairo_rectangle_int_t extents_rect; + + _cairo_box_round_to_rectangle (&extents_box, &extents_rect); + if (! _cairo_rectangle_intersect (&clip->extents, &extents_rect)) + return _cairo_clip_set_all_clipped (clip); + } + + if (clip->region) { + cairo_region_destroy (clip->region); + clip->region = NULL; + } + + clip->is_region = FALSE; + return clip; +} + +cairo_clip_t * +_cairo_clip_intersect_box (cairo_clip_t *clip, + const cairo_box_t *box) +{ + cairo_rectangle_int_t r; + + _cairo_box_round_to_rectangle (box, &r); + if (r.width == 0 || r.height == 0) + return _cairo_clip_set_all_clipped (clip); + + return _cairo_clip_intersect_rectangle_box (clip, &r, box); +} + +cairo_clip_t * +_cairo_clip_intersect_boxes (cairo_clip_t *clip, + const cairo_boxes_t *boxes) +{ + cairo_boxes_t clip_boxes; + cairo_rectangle_int_t extents; + + if (boxes->num_boxes == 0) + return clip; + + if (clip == NULL) + clip = _cairo_clip_create (); + + if (clip->num_boxes == 0) { + clip->boxes = _cairo_boxes_to_array (boxes, &clip->num_boxes, TRUE); + _cairo_boxes_extents (boxes, &extents); + } else { + _cairo_boxes_init_for_array (&clip_boxes, clip->boxes, clip->num_boxes); + if (unlikely (_cairo_boxes_intersect (&clip_boxes, boxes, &clip_boxes))) + return _cairo_clip_set_all_clipped (clip); + + free (clip->boxes); + clip->boxes = _cairo_boxes_to_array (&clip_boxes, &clip->num_boxes, TRUE); + _cairo_boxes_extents (&clip_boxes, &extents); + } + + if (clip->path == NULL) + clip->extents = extents; + else if (! _cairo_rectangle_intersect (&clip->extents, &extents)) + clip = _cairo_clip_set_all_clipped (clip); + + if (clip->region) { + cairo_region_destroy (clip->region); + clip->region = NULL; + } + clip->is_region = FALSE; + + return clip; +} + +cairo_clip_t * +_cairo_clip_intersect_rectangle (cairo_clip_t *clip, + const cairo_rectangle_int_t *r) +{ + cairo_box_t box; + + if (_cairo_clip_is_all_clipped (clip)) + return clip; + + if (r->width == 0 || r->height == 0) + return _cairo_clip_set_all_clipped (clip); + + box.p1.x = _cairo_fixed_from_int (r->x); + box.p1.y = _cairo_fixed_from_int (r->y); + box.p2.x = _cairo_fixed_from_int (r->x + r->width); + box.p2.y = _cairo_fixed_from_int (r->y + r->height); + + return _cairo_clip_intersect_rectangle_box (clip, r, &box); +} + +struct reduce { + cairo_clip_t *clip; + cairo_box_t limit; + cairo_box_t extents; + cairo_bool_t inside; + + cairo_point_t current_point; + cairo_point_t last_move_to; +}; + +static void +_add_clipped_edge (struct reduce *r, + const cairo_point_t *p1, + const cairo_point_t *p2, + int y1, int y2) +{ + cairo_fixed_t x; + + x = _cairo_edge_compute_intersection_x_for_y (p1, p2, y1); + if (x < r->extents.p1.x) + r->extents.p1.x = x; + + x = _cairo_edge_compute_intersection_x_for_y (p1, p2, y2); + if (x > r->extents.p2.x) + r->extents.p2.x = x; + + if (y1 < r->extents.p1.y) + r->extents.p1.y = y1; + + if (y2 > r->extents.p2.y) + r->extents.p2.y = y2; + + r->inside = TRUE; +} + +static void +_add_edge (struct reduce *r, + const cairo_point_t *p1, + const cairo_point_t *p2) +{ + int top, bottom; + int top_y, bot_y; + int n; + + if (p1->y < p2->y) { + top = p1->y; + bottom = p2->y; + } else { + top = p2->y; + bottom = p1->y; + } + + if (bottom < r->limit.p1.y || top > r->limit.p2.y) + return; + + if (p1->x > p2->x) { + const cairo_point_t *t = p1; + p1 = p2; + p2 = t; + } + + if (p2->x <= r->limit.p1.x || p1->x >= r->limit.p2.x) + return; + + for (n = 0; n < r->clip->num_boxes; n++) { + const cairo_box_t *limits = &r->clip->boxes[n]; + + if (bottom < limits->p1.y || top > limits->p2.y) + continue; + + if (p2->x <= limits->p1.x || p1->x >= limits->p2.x) + continue; + + if (p1->x >= limits->p1.x && p2->x <= limits->p1.x) { + top_y = top; + bot_y = bottom; + } else { + int p1_y, p2_y; + + p1_y = _cairo_edge_compute_intersection_y_for_x (p1, p2, + limits->p1.x); + p2_y = _cairo_edge_compute_intersection_y_for_x (p1, p2, + limits->p2.x); + if (p1_y < p2_y) { + top_y = p1_y; + bot_y = p2_y; + } else { + top_y = p2_y; + bot_y = p1_y; + } + + if (top_y < top) + top_y = top; + if (bot_y > bottom) + bot_y = bottom; + } + + if (top_y < limits->p1.y) + top_y = limits->p1.y; + + if (bot_y > limits->p2.y) + bot_y = limits->p2.y; + if (bot_y > top_y) + _add_clipped_edge (r, p1, p2, top_y, bot_y); + } +} + +static cairo_status_t +_reduce_line_to (void *closure, + const cairo_point_t *point) +{ + struct reduce *r = closure; + + _add_edge (r, &r->current_point, point); + r->current_point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_reduce_close (void *closure) +{ + struct reduce *r = closure; + + return _reduce_line_to (r, &r->last_move_to); +} + +static cairo_status_t +_reduce_move_to (void *closure, + const cairo_point_t *point) +{ + struct reduce *r = closure; + cairo_status_t status; + + /* close current subpath */ + status = _reduce_close (closure); + + /* make sure that the closure represents a degenerate path */ + r->current_point = *point; + r->last_move_to = *point; + + return status; +} + +static cairo_clip_t * +_cairo_clip_reduce_to_boxes (cairo_clip_t *clip) +{ + struct reduce r; + cairo_clip_path_t *clip_path; + cairo_status_t status; + + return clip; + if (clip->path == NULL) + return clip; + + r.clip = clip; + r.extents.p1.x = r.extents.p1.y = INT_MAX; + r.extents.p2.x = r.extents.p2.y = INT_MIN; + r.inside = FALSE; + + r.limit.p1.x = _cairo_fixed_from_int (clip->extents.x); + r.limit.p1.y = _cairo_fixed_from_int (clip->extents.y); + r.limit.p2.x = _cairo_fixed_from_int (clip->extents.x + clip->extents.width); + r.limit.p2.y = _cairo_fixed_from_int (clip->extents.y + clip->extents.height); + + clip_path = clip->path; + do { + r.current_point.x = 0; + r.current_point.y = 0; + r.last_move_to = r.current_point; + + status = _cairo_path_fixed_interpret_flat (&clip_path->path, + _reduce_move_to, + _reduce_line_to, + _reduce_close, + &r, + clip_path->tolerance); + assert (status == CAIRO_STATUS_SUCCESS); + _reduce_close (&r); + } while ((clip_path = clip_path->prev)); + + if (! r.inside) { + _cairo_clip_path_destroy (clip->path); + clip->path = NULL; + } + + return _cairo_clip_intersect_box (clip, &r.extents); +} + +cairo_clip_t * +_cairo_clip_reduce_to_rectangle (const cairo_clip_t *clip, + const cairo_rectangle_int_t *r) +{ + cairo_clip_t *copy; + + if (_cairo_clip_is_all_clipped (clip)) + return (cairo_clip_t *) clip; + + if (_cairo_clip_contains_rectangle (clip, r)) + return _cairo_clip_intersect_rectangle (NULL, r); + + copy = _cairo_clip_copy_intersect_rectangle (clip, r); + if (_cairo_clip_is_all_clipped (copy)) + return copy; + + return _cairo_clip_reduce_to_boxes (copy); +} + +cairo_clip_t * +_cairo_clip_reduce_for_composite (const cairo_clip_t *clip, + cairo_composite_rectangles_t *extents) +{ + const cairo_rectangle_int_t *r; + + r = extents->is_bounded ? &extents->bounded : &extents->unbounded; + return _cairo_clip_reduce_to_rectangle (clip, r); +} + +cairo_status_t +_cairo_clip_to_boxes (cairo_clip_t *clip, + cairo_boxes_t *boxes) +{ + _cairo_boxes_init_for_array (boxes, clip->boxes, clip->num_boxes); + + if (clip->path == NULL) { + cairo_box_t *src = clip->boxes; + int i; + + clip->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t)); + if (clip->boxes == NULL) { + clip->boxes = src; + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + for (i = 0; i < clip->num_boxes; i++) { + clip->boxes[i].p1.x = _cairo_fixed_floor (src[i].p1.x); + clip->boxes[i].p1.y = _cairo_fixed_floor (src[i].p1.y); + clip->boxes[i].p2.x = _cairo_fixed_ceil (src[i].p2.x); + clip->boxes[i].p2.y = _cairo_fixed_ceil (src[i].p2.y); + } + } + + return CAIRO_STATUS_SUCCESS; + +} diff --git a/src/cairo-clip-polygon.c b/src/cairo-clip-polygon.c new file mode 100644 index 000000000..19da15dc5 --- /dev/null +++ b/src/cairo-clip-polygon.c @@ -0,0 +1,127 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "cairoint.h" +#include "cairo-clip-private.h" +#include "cairo-error-private.h" +#include "cairo-freed-pool-private.h" +#include "cairo-gstate-private.h" +#include "cairo-path-fixed-private.h" +#include "cairo-pattern-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-region-private.h" + +static cairo_bool_t +can_convert_to_polygon (const cairo_clip_t *clip) +{ + cairo_clip_path_t *clip_path = clip->path; + cairo_antialias_t antialias = clip_path->antialias; + + while ((clip_path = clip_path->prev) != NULL) { + if (clip_path->antialias != antialias) + return FALSE; + } + + return TRUE; +} + +cairo_int_status_t +_cairo_clip_get_polygon (const cairo_clip_t *clip, + cairo_polygon_t *polygon, + cairo_fill_rule_t *fill_rule, + cairo_antialias_t *antialias) +{ + cairo_status_t status; + cairo_clip_path_t *clip_path; + + if (_cairo_clip_is_all_clipped (clip)) { + _cairo_polygon_init (polygon, NULL, 0); + return CAIRO_INT_STATUS_SUCCESS; + } + + /* If there is no clip, we need an infinite polygon */ + assert (clip && (clip->path || clip->num_boxes)); + + if (clip->path == NULL) { + *fill_rule = CAIRO_FILL_RULE_WINDING; + *antialias = CAIRO_ANTIALIAS_DEFAULT; + return _cairo_polygon_init_box_array (polygon, + clip->boxes, + clip->num_boxes); + } + + /* check that residual is all of the same type/tolerance */ + if (! can_convert_to_polygon (clip)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_polygon_init_with_clip (polygon, clip); + + clip_path = clip->path; + status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, + clip_path->tolerance, + polygon); + if (unlikely (status)) { + _cairo_polygon_fini (polygon); + return status; + } + + polygon->limits = NULL; + polygon->num_limits = 0; + + *fill_rule = clip_path->fill_rule; + *antialias = clip_path->antialias; + while ((clip_path = clip_path->prev) != NULL) { + cairo_polygon_t next; + + _cairo_polygon_init (&next, NULL, 0); + status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, + clip_path->tolerance, + &next); + if (likely (status == CAIRO_STATUS_SUCCESS)) + status = _cairo_polygon_intersect (polygon, *fill_rule, + &next, clip_path->fill_rule); + _cairo_polygon_fini (&next); + if (unlikely (status)) { + _cairo_polygon_fini (polygon); + return status; + } + + *fill_rule = CAIRO_FILL_RULE_WINDING; + } + + return CAIRO_STATUS_SUCCESS; +} diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h index bfbb539aa..861be63cc 100644 --- a/src/cairo-clip-private.h +++ b/src/cairo-clip-private.h @@ -31,24 +31,21 @@ * * Contributor(s): * Kristian Høgsberg <krh@redhat.com> + * Chris Wilson <chris@chris-wilson.co.uk> */ #ifndef CAIRO_CLIP_PRIVATE_H #define CAIRO_CLIP_PRIVATE_H #include "cairo-types-private.h" + +#include "cairo-boxes-private.h" #include "cairo-compiler-private.h" #include "cairo-path-fixed-private.h" #include "cairo-reference-count-private.h" extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil; -enum { - CAIRO_CLIP_PATH_HAS_REGION = 0x1, - CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED = 0x2, - CAIRO_CLIP_PATH_IS_BOX = 0x4 -}; - struct _cairo_clip_path { cairo_reference_count_t ref_count; cairo_path_fixed_t path; @@ -58,92 +55,124 @@ struct _cairo_clip_path { cairo_clip_path_t *prev; cairo_rectangle_int_t extents; - - /* partial caches */ - unsigned int flags; - cairo_region_t *region; - cairo_surface_t *surface; }; struct _cairo_clip { - /* can be used as a cairo_hash_entry_t for live clips */ + cairo_rectangle_int_t extents; cairo_clip_path_t *path; - cairo_bool_t all_clipped; + cairo_box_t *boxes; + int num_boxes; + cairo_region_t *region; + cairo_bool_t is_region; }; +cairo_private cairo_clip_t * +_cairo_clip_create (void); + cairo_private void -_cairo_clip_init (cairo_clip_t *clip); +_cairo_clip_path_destroy (cairo_clip_path_t *clip_path); -cairo_private_no_warn cairo_clip_t * -_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other); +cairo_private void +_cairo_clip_destroy (cairo_clip_t *clip); -cairo_private cairo_status_t -_cairo_clip_init_copy_transformed (cairo_clip_t *clip, - cairo_clip_t *other, - const cairo_matrix_t *matrix); +extern const cairo_clip_t __cairo_clip_all; -cairo_private void -_cairo_clip_reset (cairo_clip_t *clip); +static inline cairo_bool_t _cairo_clip_is_all_clipped(const cairo_clip_t *clip) +{ + return clip == &__cairo_clip_all; +} -cairo_private cairo_bool_t -_cairo_clip_equal (const cairo_clip_t *clip_a, - const cairo_clip_t *clip_b); +static inline cairo_clip_t * +_cairo_clip_set_all_clipped (cairo_clip_t *clip) +{ + _cairo_clip_destroy (clip); + return (cairo_clip_t *) &__cairo_clip_all; +} -#define _cairo_clip_fini(clip) _cairo_clip_reset (clip) +cairo_private cairo_clip_t * +_cairo_clip_copy (const cairo_clip_t *clip); -cairo_private cairo_status_t -_cairo_clip_rectangle (cairo_clip_t *clip, - const cairo_rectangle_int_t *rectangle); +cairo_private cairo_clip_t * +_cairo_clip_copy_with_translation (const cairo_clip_t *clip, int tx, int ty); -cairo_private cairo_status_t -_cairo_clip_clip (cairo_clip_t *clip, - const cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias); +cairo_private cairo_bool_t +_cairo_clip_equal (const cairo_clip_t *clip_a, + const cairo_clip_t *clip_b); -cairo_private cairo_status_t -_cairo_clip_apply_clip (cairo_clip_t *clip, - const cairo_clip_t *other); +cairo_private cairo_clip_t * +_cairo_clip_intersect_rectangle (cairo_clip_t *clip, + const cairo_rectangle_int_t *rectangle); + +static inline cairo_clip_t * +_cairo_clip_copy_intersect_rectangle (const cairo_clip_t *clip, + const cairo_rectangle_int_t *r) +{ + return _cairo_clip_intersect_rectangle (_cairo_clip_copy (clip), r); +} + +cairo_private cairo_clip_t * +_cairo_clip_intersect_box (cairo_clip_t *clip, + const cairo_box_t *box); + +cairo_private cairo_clip_t * +_cairo_clip_intersect_boxes (cairo_clip_t *clip, + const cairo_boxes_t *boxes); + +cairo_private cairo_clip_t * +_cairo_clip_intersect_rectilinear_path (cairo_clip_t *clip, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias); + +cairo_private cairo_clip_t * +_cairo_clip_intersect_path (cairo_clip_t *clip, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias); cairo_private const cairo_rectangle_int_t * _cairo_clip_get_extents (const cairo_clip_t *clip); cairo_private cairo_surface_t * -_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *dst, int *tx, int *ty); +_cairo_clip_get_surface (const cairo_clip_t *clip, cairo_surface_t *dst, int *tx, int *ty); cairo_private cairo_status_t -_cairo_clip_combine_with_surface (cairo_clip_t *clip, +_cairo_clip_combine_with_surface (const cairo_clip_t *clip, cairo_surface_t *dst, int dst_x, int dst_y); -cairo_private cairo_int_status_t -_cairo_clip_get_region (cairo_clip_t *clip, - cairo_region_t **region); +cairo_private cairo_status_t +_cairo_clip_to_boxes (cairo_clip_t *clip, + cairo_boxes_t *boxes); -cairo_private cairo_int_status_t -_cairo_clip_get_boxes (cairo_clip_t *clip, - cairo_box_t **boxes, - int *count); +cairo_private cairo_region_t * +_cairo_clip_get_region (const cairo_clip_t *clip); -cairo_private cairo_status_t -_cairo_clip_to_boxes (cairo_clip_t **clip, - cairo_composite_rectangles_t *extents, - cairo_box_t **boxes, - int *num_boxes); +cairo_private cairo_bool_t +_cairo_clip_is_region (const cairo_clip_t *clip); + +cairo_private cairo_clip_t * +_cairo_clip_reduce_to_rectangle (const cairo_clip_t *clip, + const cairo_rectangle_int_t *r); + +cairo_private cairo_clip_t * +_cairo_clip_reduce_for_composite (const cairo_clip_t *clip, + cairo_composite_rectangles_t *extents); cairo_private cairo_bool_t -_cairo_clip_contains_rectangle (cairo_clip_t *clip, +_cairo_clip_contains_rectangle (const cairo_clip_t *clip, const cairo_rectangle_int_t *rect); cairo_private cairo_bool_t -_cairo_clip_contains_extents (cairo_clip_t *clip, - const cairo_composite_rectangles_t *extents); +_cairo_clip_contains_box (const cairo_clip_t *clip, + const cairo_box_t *box); -cairo_private void -_cairo_clip_drop_cache (cairo_clip_t *clip); +cairo_private cairo_bool_t +_cairo_clip_contains_extents (const cairo_clip_t *clip, + const cairo_composite_rectangles_t *extents); cairo_private cairo_rectangle_list_t* _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate); @@ -151,4 +180,10 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate); cairo_private cairo_rectangle_list_t * _cairo_rectangle_list_create_in_error (cairo_status_t status); +cairo_private cairo_int_status_t +_cairo_clip_get_polygon (const cairo_clip_t *clip, + cairo_polygon_t *polygon, + cairo_fill_rule_t *fill_rule, + cairo_antialias_t *antialias); + #endif /* CAIRO_CLIP_PRIVATE_H */ diff --git a/src/cairo-clip-region.c b/src/cairo-clip-region.c new file mode 100644 index 000000000..28a0d4bbd --- /dev/null +++ b/src/cairo-clip-region.c @@ -0,0 +1,117 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + * Kristian Høgsberg <krh@redhat.com> + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "cairoint.h" +#include "cairo-clip-private.h" +#include "cairo-error-private.h" +#include "cairo-freed-pool-private.h" +#include "cairo-gstate-private.h" +#include "cairo-path-fixed-private.h" +#include "cairo-pattern-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-region-private.h" + +static void +_cairo_clip_extract_region (cairo_clip_t *clip) +{ + cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)]; + cairo_rectangle_int_t *r = stack_rects; + cairo_bool_t is_region; + int i; + + if (clip->num_boxes == 0) + return; + + if (clip->num_boxes > ARRAY_LENGTH (stack_rects)) { + r = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_rectangle_int_t)); + if (r == NULL){ + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return; + } + } + + is_region = clip->path == NULL; + for (i = 0; i < clip->num_boxes; i++) { + cairo_box_t *b = &clip->boxes[i]; + if (is_region) + is_region = + _cairo_fixed_is_integer (b->p1.x | b->p1.y | b->p2.x | b->p2.y); + r[i].x = _cairo_fixed_integer_floor (b->p1.x); + r[i].y = _cairo_fixed_integer_floor (b->p1.y); + r[i].width = _cairo_fixed_integer_ceil (b->p2.x) - r[i].x; + r[i].height = _cairo_fixed_integer_ceil (b->p2.y) - r[i].y; + } + clip->is_region = is_region; + + clip->region = cairo_region_create_rectangles (r, i); + + if (r != stack_rects) + free (r); +} + +cairo_region_t * +_cairo_clip_get_region (const cairo_clip_t *clip) +{ + if (clip == NULL) + return NULL; + + if (clip->region == NULL) + _cairo_clip_extract_region ((cairo_clip_t *) clip); + + return clip->region; +} + +cairo_bool_t +_cairo_clip_is_region (const cairo_clip_t *clip) +{ + if (clip == NULL) + return TRUE; + + /* XXX Geometric reduction? */ + + if (clip->path) + return FALSE; + + if (clip->region == NULL) + _cairo_clip_extract_region ((cairo_clip_t *) clip); + + return clip->is_region; +} diff --git a/src/cairo-clip-surface.c b/src/cairo-clip-surface.c new file mode 100644 index 000000000..79e6a6274 --- /dev/null +++ b/src/cairo-clip-surface.c @@ -0,0 +1,142 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + * Kristian Høgsberg <krh@redhat.com> + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "cairoint.h" +#include "cairo-clip-private.h" +#include "cairo-error-private.h" +#include "cairo-freed-pool-private.h" +#include "cairo-gstate-private.h" +#include "cairo-path-fixed-private.h" +#include "cairo-pattern-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-region-private.h" + +cairo_status_t +_cairo_clip_combine_with_surface (const cairo_clip_t *clip, + cairo_surface_t *dst, + int dst_x, int dst_y) +{ + cairo_clip_path_t *clip_path; + cairo_clip_path_t *copy_path; + cairo_clip_t *copy; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + copy = _cairo_clip_copy_with_translation (clip, -dst_x, -dst_y); + copy_path = copy->path; + copy->path = NULL; + + if (copy_path == NULL) { + assert (copy->num_boxes); + status = _cairo_surface_paint (dst, + CAIRO_OPERATOR_IN, + &_cairo_pattern_white.base, + copy); + } + + clip_path = copy_path; + while (status == CAIRO_STATUS_SUCCESS && clip_path) { + status = _cairo_surface_fill (dst, + CAIRO_OPERATOR_IN, + &_cairo_pattern_white.base, + &clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + clip_path->antialias, + copy); + clip_path = clip_path->prev; + } + + copy->path = copy_path; + _cairo_clip_destroy (copy); + return status; +} + +cairo_surface_t * +_cairo_clip_get_surface (const cairo_clip_t *clip, + cairo_surface_t *target, + int *tx, int *ty) +{ + cairo_surface_t *surface; + cairo_status_t status; + cairo_clip_t *copy; + cairo_clip_path_t *copy_path, *clip_path; + + surface = _cairo_surface_create_similar_solid (target, + CAIRO_CONTENT_ALPHA, + clip->extents.width, + clip->extents.height, + CAIRO_COLOR_TRANSPARENT, + TRUE); + if (unlikely (surface->status)) + return surface; + + copy = _cairo_clip_copy_with_translation (clip, + -clip->extents.x, + -clip->extents.y); + copy_path = copy->path; + copy->path = NULL; + + assert (copy->num_boxes); + status = _cairo_surface_paint (surface, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + copy); + + clip_path = copy_path; + while (status == CAIRO_STATUS_SUCCESS && clip_path) { + status = _cairo_surface_fill (surface, + CAIRO_OPERATOR_IN, + &_cairo_pattern_white.base, + &clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + clip_path->antialias, + copy); + clip_path = clip_path->prev; + } + + copy->path = copy_path; + _cairo_clip_destroy (copy); + + *tx = clip->extents.x; + *ty = clip->extents.y; + return surface; +} diff --git a/src/cairo-clip.c b/src/cairo-clip.c index 9054b4e9d..99d7cd466 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -50,6 +50,16 @@ #include "cairo-region-private.h" static freed_pool_t clip_path_pool; +static freed_pool_t clip_pool; + +const cairo_clip_t __cairo_clip_all; + +static const cairo_rectangle_int_t _cairo_empty_rectangle = { 0, 0, 0, 0 }; +static const cairo_rectangle_int_t _cairo_unbounded_rectangle = { + CAIRO_RECT_INT_MIN, CAIRO_RECT_INT_MIN, + CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN, + CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN, +}; static cairo_clip_path_t * _cairo_clip_path_create (cairo_clip_t *clip) @@ -65,10 +75,6 @@ _cairo_clip_path_create (cairo_clip_t *clip) CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1); - clip_path->flags = 0; - clip_path->region = NULL; - clip_path->surface = NULL; - clip_path->prev = clip->path; clip->path = clip_path; @@ -85,7 +91,7 @@ _cairo_clip_path_reference (cairo_clip_path_t *clip_path) return clip_path; } -static void +void _cairo_clip_path_destroy (cairo_clip_path_t *clip_path) { assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count)); @@ -94,10 +100,6 @@ _cairo_clip_path_destroy (cairo_clip_path_t *clip_path) return; _cairo_path_fixed_fini (&clip_path->path); - if (clip_path->region != NULL) - cairo_region_destroy (clip_path->region); - if (clip_path->surface != NULL) - cairo_surface_destroy (clip_path->surface); if (clip_path->prev != NULL) _cairo_clip_path_destroy (clip_path->prev); @@ -105,115 +107,75 @@ _cairo_clip_path_destroy (cairo_clip_path_t *clip_path) _freed_pool_put (&clip_path_pool, clip_path); } -void -_cairo_clip_init (cairo_clip_t *clip) +cairo_clip_t * +_cairo_clip_create (void) { - clip->all_clipped = FALSE; + cairo_clip_t *clip; + + clip = _freed_pool_get (&clip_pool); + if (unlikely (clip == NULL)) { + clip = malloc (sizeof (cairo_clip_t)); + if (unlikely (clip == NULL)) + return NULL; + } + + clip->extents = _cairo_unbounded_rectangle; + clip->path = NULL; + clip->boxes = NULL; + clip->num_boxes = 0; + clip->region = NULL; + clip->is_region = FALSE; + + return clip; } -static void -_cairo_clip_set_all_clipped (cairo_clip_t *clip) +void +_cairo_clip_destroy (cairo_clip_t *clip) { - clip->all_clipped = TRUE; - if (clip->path != NULL) { + if (clip == NULL || _cairo_clip_is_all_clipped (clip)) + return; + + if (clip->path != NULL) _cairo_clip_path_destroy (clip->path); - clip->path = NULL; - } + + free (clip->boxes); + cairo_region_destroy (clip->region); + + _freed_pool_put (&clip_pool, clip); } -static cairo_status_t -_cairo_clip_intersect_rectangle (cairo_clip_t *clip, - const cairo_rectangle_int_t *rect) +cairo_clip_t * +_cairo_clip_copy (const cairo_clip_t *clip) { - cairo_clip_path_t *clip_path; - cairo_status_t status; + cairo_clip_t *copy; - if (clip->path != NULL) { - if (rect->x <= clip->path->extents.x && - rect->y <= clip->path->extents.y && - rect->x + rect->width >= clip->path->extents.x + clip->path->extents.width && - rect->y + rect->height >= clip->path->extents.y + clip->path->extents.height) - { - return CAIRO_STATUS_SUCCESS; - } - } + if (clip == NULL || _cairo_clip_is_all_clipped (clip)) + return (cairo_clip_t *) clip; - clip_path = _cairo_clip_path_create (clip); - if (unlikely (clip_path == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - _cairo_path_fixed_init (&clip_path->path); - - status = _cairo_path_fixed_move_to (&clip_path->path, - _cairo_fixed_from_int (rect->x), - _cairo_fixed_from_int (rect->y)); - assert (status == CAIRO_STATUS_SUCCESS); - status = _cairo_path_fixed_rel_line_to (&clip_path->path, - _cairo_fixed_from_int (rect->width), - _cairo_fixed_from_int (0)); - assert (status == CAIRO_STATUS_SUCCESS); - status = _cairo_path_fixed_rel_line_to (&clip_path->path, - _cairo_fixed_from_int (0), - _cairo_fixed_from_int (rect->height)); - assert (status == CAIRO_STATUS_SUCCESS); - status = _cairo_path_fixed_rel_line_to (&clip_path->path, - _cairo_fixed_from_int (-rect->width), - _cairo_fixed_from_int (0)); - assert (status == CAIRO_STATUS_SUCCESS); - status = _cairo_path_fixed_close_path (&clip_path->path); - assert (status == CAIRO_STATUS_SUCCESS); - - clip_path->fill_rule = CAIRO_FILL_RULE_WINDING; - clip_path->tolerance = 1; - clip_path->antialias = CAIRO_ANTIALIAS_DEFAULT; - clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX; - - clip_path->extents = *rect; - if (clip_path->prev != NULL) { - if (! _cairo_rectangle_intersect (&clip_path->extents, - &clip_path->prev->extents)) - { - _cairo_clip_set_all_clipped (clip); - } - } + copy = _cairo_clip_create (); - /* could preallocate the region if it proves worthwhile */ + if (clip->path) + copy->path = _cairo_clip_path_reference (clip->path); - return CAIRO_STATUS_SUCCESS; -} + if (clip->num_boxes) { + copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t)); + if (unlikely (copy->boxes == NULL)) + return _cairo_clip_set_all_clipped (copy); -cairo_clip_t * -_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other) -{ - if (other != NULL) { - clip->all_clipped = other->all_clipped; - if (other->path == NULL) { - clip->path = NULL; - if (! clip->all_clipped) - clip = NULL; - } else { - clip->path = _cairo_clip_path_reference (other->path); - } - } else { - _cairo_clip_init (clip); - clip = NULL; + memcpy (copy->boxes, clip->boxes, + clip->num_boxes * sizeof (cairo_box_t)); + copy->num_boxes = clip->num_boxes; } - return clip; -} + copy->extents = clip->extents; + copy->region = cairo_region_reference (clip->region); + copy->is_region = clip->is_region; -void -_cairo_clip_reset (cairo_clip_t *clip) -{ - clip->all_clipped = FALSE; - if (clip->path != NULL) { - _cairo_clip_path_destroy (clip->path); - clip->path = NULL; - } + return copy; } -static cairo_status_t +cairo_clip_t * _cairo_clip_intersect_path (cairo_clip_t *clip, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, @@ -224,928 +186,147 @@ _cairo_clip_intersect_path (cairo_clip_t *clip, cairo_status_t status; cairo_rectangle_int_t extents; cairo_box_t box; - cairo_bool_t is_box = FALSE; - - if (clip->path != NULL) { - if (clip->path->fill_rule == fill_rule && - (_cairo_path_fixed_fill_is_rectilinear (path) || tolerance == clip->path->tolerance) && - antialias == clip->path->antialias && - _cairo_path_fixed_equal (&clip->path->path, path)) - { - return CAIRO_STATUS_SUCCESS; + + if (_cairo_clip_is_all_clipped (clip)) + return clip; + + /* catch the empty clip path */ + if (_cairo_path_fixed_fill_is_empty (path)) + return _cairo_clip_set_all_clipped (clip); + + if (_cairo_path_fixed_is_box (path, &box)) { + if (antialias == CAIRO_ANTIALIAS_NONE) { + box.p1.x = _cairo_fixed_round_down (box.p1.x); + box.p1.y = _cairo_fixed_round_down (box.p1.y); + box.p2.x = _cairo_fixed_round_down (box.p2.x); + box.p2.y = _cairo_fixed_round_down (box.p2.y); } + + return _cairo_clip_intersect_box (clip, &box); } + if (_cairo_path_fixed_fill_is_rectilinear (path)) + return _cairo_clip_intersect_rectilinear_path (clip, path, + fill_rule, antialias); _cairo_path_fixed_approximate_clip_extents (path, &extents); - if (extents.width == 0 || extents.height == 0) { - _cairo_clip_set_all_clipped (clip); - return CAIRO_STATUS_SUCCESS; - } + if (extents.width == 0 || extents.height == 0) + return _cairo_clip_set_all_clipped (clip); - is_box = _cairo_path_fixed_is_box (path, &box); - if (clip->path != NULL) { - if (! _cairo_rectangle_intersect (&extents, &clip->path->extents)) { - _cairo_clip_set_all_clipped (clip); - return CAIRO_STATUS_SUCCESS; - } + if (clip && ! _cairo_rectangle_intersect (&clip->extents, &extents)) + return _cairo_clip_set_all_clipped (clip); - /* does this clip wholly subsume the others? */ - if (is_box && - box.p1.x <= _cairo_fixed_from_int (clip->path->extents.x) && - box.p2.x >= _cairo_fixed_from_int (clip->path->extents.x + clip->path->extents.width) && - box.p1.y <= _cairo_fixed_from_int (clip->path->extents.y) && - box.p2.y >= _cairo_fixed_from_int (clip->path->extents.y + clip->path->extents.height)) - { - return CAIRO_STATUS_SUCCESS; - } + if (clip == NULL) { + clip = _cairo_clip_create (); + if (unlikely (clip == NULL)) + return _cairo_clip_set_all_clipped (clip); + + clip->extents = extents; } clip_path = _cairo_clip_path_create (clip); if (unlikely (clip_path == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + return _cairo_clip_set_all_clipped (clip); status = _cairo_path_fixed_init_copy (&clip_path->path, path); - if (unlikely (status)) { - clip->path = clip->path->prev; - _cairo_clip_path_destroy (clip_path); - return status; - } + if (unlikely (status)) + return _cairo_clip_set_all_clipped (clip); - clip_path->extents = extents; clip_path->fill_rule = fill_rule; clip_path->tolerance = tolerance; clip_path->antialias = antialias; - if (is_box) - clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX; - return CAIRO_STATUS_SUCCESS; + clip->is_region = FALSE; + return clip; } cairo_bool_t _cairo_clip_equal (const cairo_clip_t *clip_a, const cairo_clip_t *clip_b) { - const cairo_clip_path_t *clip_path_a, *clip_path_b; - - clip_path_a = clip_a->path; - clip_path_b = clip_b->path; - - while (clip_path_a && clip_path_b) { - if (clip_path_a == clip_path_b) - return TRUE; - - if (clip_path_a->fill_rule != clip_path_b->fill_rule) - return FALSE; - - if (clip_path_a->tolerance != clip_path_b->tolerance) - return FALSE; - - if (clip_path_a->antialias != clip_path_b->antialias) - return FALSE; - - if (! _cairo_path_fixed_equal (&clip_path_a->path, &clip_path_b->path)) - return FALSE; - - clip_path_a = clip_path_a->prev; - clip_path_b = clip_path_b->prev; - } - - return clip_path_a == clip_path_b; /* ie both NULL */ -} - -cairo_status_t -_cairo_clip_clip (cairo_clip_t *clip, - const cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - if (clip->all_clipped) - return CAIRO_STATUS_SUCCESS; - - /* catch the empty clip path */ - if (_cairo_path_fixed_fill_is_empty (path)) { - _cairo_clip_set_all_clipped (clip); - return CAIRO_STATUS_SUCCESS; - } - - return _cairo_clip_intersect_path (clip, - path, fill_rule, tolerance, - antialias); -} - -cairo_status_t -_cairo_clip_rectangle (cairo_clip_t *clip, - const cairo_rectangle_int_t *rectangle) -{ - if (clip->all_clipped) - return CAIRO_STATUS_SUCCESS; - - if (rectangle->width == 0 || rectangle->height == 0) { - _cairo_clip_set_all_clipped (clip); - return CAIRO_STATUS_SUCCESS; - } - - /* if a smaller clip has already been set, ignore the new path */ - if (clip->path != NULL) { - if (rectangle->x <= clip->path->extents.x && - rectangle->y <= clip->path->extents.y && - rectangle->x + rectangle->width >= clip->path->extents.x + clip->path->extents.width && - rectangle->y + rectangle->height >= clip->path->extents.y + clip->path->extents.height) - { - return CAIRO_STATUS_SUCCESS; - } - } - - return _cairo_clip_intersect_rectangle (clip, rectangle); -} - -static cairo_status_t -_cairo_clip_path_reapply_clip_path_transform (cairo_clip_t *clip, - cairo_clip_path_t *other_path, - const cairo_matrix_t *matrix) -{ - cairo_status_t status; - cairo_clip_path_t *clip_path; - - if (other_path->prev != NULL) { - status = _cairo_clip_path_reapply_clip_path_transform (clip, - other_path->prev, - matrix); - if (unlikely (status)) - return status; - } - - clip_path = _cairo_clip_path_create (clip); - if (unlikely (clip_path == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - status = _cairo_path_fixed_init_copy (&clip_path->path, - &other_path->path); - if (unlikely (status)) { - clip->path = clip->path->prev; - _cairo_clip_path_destroy (clip_path); - return status; - } - - _cairo_path_fixed_transform (&clip_path->path, matrix); - _cairo_path_fixed_approximate_clip_extents (&clip_path->path, - &clip_path->extents); - if (clip_path->prev != NULL) { - _cairo_rectangle_intersect (&clip_path->extents, - &clip_path->prev->extents); - } - - clip_path->fill_rule = other_path->fill_rule; - clip_path->tolerance = other_path->tolerance; - clip_path->antialias = other_path->antialias; + /* are both all-clipped or no-clip? */ + if (clip_a == clip_b) + return TRUE; - return CAIRO_STATUS_SUCCESS; + return FALSE; } -static cairo_status_t -_cairo_clip_path_reapply_clip_path_translate (cairo_clip_t *clip, - cairo_clip_path_t *other_path, - int tx, int ty) +static cairo_clip_t * +_cairo_clip_path_copy_with_translation (cairo_clip_t *clip, + cairo_clip_path_t *other_path, + int fx, int fy) { cairo_status_t status; cairo_clip_path_t *clip_path; - if (other_path->prev != NULL) { - status = _cairo_clip_path_reapply_clip_path_translate (clip, - other_path->prev, - tx, ty); - if (unlikely (status)) - return status; - } + if (other_path->prev != NULL) + clip = _cairo_clip_path_copy_with_translation (clip, other_path->prev, + fx, fy); + if (_cairo_clip_is_all_clipped (clip)) + return clip; clip_path = _cairo_clip_path_create (clip); if (unlikely (clip_path == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + return _cairo_clip_set_all_clipped (clip); status = _cairo_path_fixed_init_copy (&clip_path->path, &other_path->path); - if (unlikely (status)) { - clip->path = clip->path->prev; - _cairo_clip_path_destroy (clip_path); - return status; - } + if (unlikely (status)) + return _cairo_clip_set_all_clipped (clip); - _cairo_path_fixed_translate (&clip_path->path, - _cairo_fixed_from_int (tx), - _cairo_fixed_from_int (ty)); + _cairo_path_fixed_translate (&clip_path->path, fx, fy); clip_path->fill_rule = other_path->fill_rule; clip_path->tolerance = other_path->tolerance; clip_path->antialias = other_path->antialias; - clip_path->flags = other_path->flags; - if (other_path->region != NULL) { - clip_path->region = cairo_region_copy (other_path->region); - status = clip_path->region->status; - if (unlikely (status)) { - clip->path = clip->path->prev; - _cairo_clip_path_destroy (clip_path); - return status; - } - - cairo_region_translate (clip_path->region, tx, ty); - } - clip_path->surface = cairo_surface_reference (other_path->surface); - - clip_path->extents = other_path->extents; - clip_path->extents.x += tx; - clip_path->extents.y += ty; - - return CAIRO_STATUS_SUCCESS; -} - -cairo_status_t -_cairo_clip_init_copy_transformed (cairo_clip_t *clip, - cairo_clip_t *other, - const cairo_matrix_t *matrix) -{ - cairo_status_t status = CAIRO_STATUS_SUCCESS; - int tx, ty; - - if (other == NULL) { - _cairo_clip_init (clip); - return CAIRO_STATUS_SUCCESS; - } - - if (other->all_clipped) { - _cairo_clip_init (clip); - clip->all_clipped = TRUE; - return CAIRO_STATUS_SUCCESS; - } - - if (_cairo_matrix_is_identity (matrix)) { - _cairo_clip_init_copy (clip, other); - return CAIRO_STATUS_SUCCESS; - } - - if (other->path != NULL) { - _cairo_clip_init (clip); - - /* if we only need to translate, so we can reuse the caches... */ - /* XXX we still loose the benefit of constructs when the copy is - * deleted though. Indirect clip_paths? - */ - if (_cairo_matrix_is_integer_translation (matrix, &tx, &ty)) { - status = _cairo_clip_path_reapply_clip_path_translate (clip, - other->path, - tx, ty); - } else { - status = _cairo_clip_path_reapply_clip_path_transform (clip, - other->path, - matrix); - if (clip->path->extents.width == 0 && - clip->path->extents.height == 0) - { - _cairo_clip_set_all_clipped (clip); - } - } - } - - return status; -} - -static cairo_status_t -_cairo_clip_apply_clip_path (cairo_clip_t *clip, - const cairo_clip_path_t *path) -{ - if (path->prev != NULL) { - cairo_status_t status; - - status = _cairo_clip_apply_clip_path (clip, path->prev); - if (unlikely (status)) - return status; - } - - return _cairo_clip_intersect_path (clip, - &path->path, - path->fill_rule, - path->tolerance, - path->antialias); -} - -cairo_status_t -_cairo_clip_apply_clip (cairo_clip_t *clip, - const cairo_clip_t *other) -{ - cairo_status_t status; - - if (clip->all_clipped) - return CAIRO_STATUS_SUCCESS; - - if (other->all_clipped) { - _cairo_clip_set_all_clipped (clip); - return CAIRO_STATUS_SUCCESS; - } - - status = CAIRO_STATUS_SUCCESS; - if (other->path != NULL) - status = _cairo_clip_apply_clip_path (clip, other->path); - - return status; -} - -static inline cairo_bool_t -_clip_paths_are_rectilinear (cairo_clip_path_t *clip_path) -{ - while (clip_path != NULL) { - if (! _cairo_path_fixed_fill_is_rectilinear (&clip_path->path)) - return FALSE; - - clip_path = clip_path->prev; - } - - return TRUE; -} - -static cairo_int_status_t -_cairo_clip_path_to_region_geometric (cairo_clip_path_t *clip_path) -{ - cairo_traps_t traps; - cairo_box_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (cairo_box_t)]; - cairo_box_t *boxes = stack_boxes; - cairo_status_t status; - int n; - - /* If we have nothing to intersect with this path, then it cannot - * magically be reduced into a region. - */ - if (clip_path->prev == NULL) - goto UNSUPPORTED; - - /* Start simple... Intersect some boxes with an arbitrary path. */ - if (! _cairo_path_fixed_fill_is_rectilinear (&clip_path->path)) - goto UNSUPPORTED; - if (clip_path->prev->prev != NULL) - goto UNSUPPORTED; - - _cairo_traps_init (&traps); - _cairo_box_from_rectangle (&boxes[0], &clip_path->extents); - _cairo_traps_limit (&traps, boxes, 1); - - status = _cairo_path_fixed_fill_rectilinear_to_traps (&clip_path->path, - clip_path->fill_rule, - &traps); - if (unlikely (_cairo_status_is_error (status))) - return status; - if (status == CAIRO_INT_STATUS_UNSUPPORTED) - goto UNSUPPORTED; - - if (traps.num_traps > ARRAY_LENGTH (stack_boxes)) { - boxes = _cairo_malloc_ab (traps.num_traps, sizeof (cairo_box_t)); - if (unlikely (boxes == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - - for (n = 0; n < traps.num_traps; n++) { - boxes[n].p1.x = traps.traps[n].left.p1.x; - boxes[n].p1.y = traps.traps[n].top; - boxes[n].p2.x = traps.traps[n].right.p1.x; - boxes[n].p2.y = traps.traps[n].bottom; - } - - _cairo_traps_clear (&traps); - _cairo_traps_limit (&traps, boxes, n); - status = _cairo_path_fixed_fill_to_traps (&clip_path->prev->path, - clip_path->prev->fill_rule, - clip_path->prev->tolerance, - &traps); - if (boxes != stack_boxes) - free (boxes); - - if (unlikely (status)) - return status; - - status = _cairo_traps_extract_region (&traps, &clip_path->region); - _cairo_traps_fini (&traps); - - if (status == CAIRO_INT_STATUS_UNSUPPORTED) - goto UNSUPPORTED; - if (unlikely (status)) - return status; - - clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION; - return CAIRO_STATUS_SUCCESS; - -UNSUPPORTED: - clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED; - return CAIRO_INT_STATUS_UNSUPPORTED; -} - -static cairo_int_status_t -_cairo_clip_path_to_region (cairo_clip_path_t *clip_path) -{ - cairo_int_status_t status; - cairo_region_t *prev = NULL; - - if (clip_path->flags & - (CAIRO_CLIP_PATH_HAS_REGION | - CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED)) - { - return clip_path->flags & CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED ? - CAIRO_INT_STATUS_UNSUPPORTED : - CAIRO_STATUS_SUCCESS; - } - - if (! _cairo_path_fixed_fill_maybe_region (&clip_path->path)) - return _cairo_clip_path_to_region_geometric (clip_path); - - /* first retrieve the region for our antecedents */ - if (clip_path->prev != NULL) { - status = _cairo_clip_path_to_region (clip_path->prev); - if (status) { - if (status == CAIRO_INT_STATUS_UNSUPPORTED) - return _cairo_clip_path_to_region_geometric (clip_path); - - return status; - } - - prev = clip_path->prev->region; - } - - /* now extract the region for ourselves */ - clip_path->region = - _cairo_path_fixed_fill_rectilinear_to_region (&clip_path->path, - clip_path->fill_rule, - &clip_path->extents); - assert (clip_path->region != NULL); - - status = clip_path->region->status; - if (unlikely (status)) - return status; - - if (prev != NULL) { - status = cairo_region_intersect (clip_path->region, prev); - if (unlikely (status)) - return status; - } - - clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION; - return CAIRO_STATUS_SUCCESS; -} - -static inline int -pot (int v) -{ - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; -} - -/* XXX there is likely a faster method! ;-) */ -static cairo_status_t -_region_clip_to_boxes (const cairo_region_t *region, - cairo_box_t **boxes, - int *num_boxes, - int *size_boxes) -{ - cairo_traps_t traps; - cairo_status_t status; - int n, num_rects; - - _cairo_traps_init (&traps); - _cairo_traps_limit (&traps, *boxes, *num_boxes); - traps.is_rectilinear = TRUE; - traps.is_rectangular = TRUE; - - num_rects = cairo_region_num_rectangles (region); - for (n = 0; n < num_rects; n++) { - cairo_rectangle_int_t rect; - cairo_point_t p1, p2; - - cairo_region_get_rectangle (region, n, &rect); - - p1.x = _cairo_fixed_from_int (rect.x); - p1.y = _cairo_fixed_from_int (rect.y); - p2.x = _cairo_fixed_from_int (rect.x + rect.width); - p2.y = _cairo_fixed_from_int (rect.y + rect.height); - - status = _cairo_traps_tessellate_rectangle (&traps, &p1, &p2); - if (unlikely (status)) - goto CLEANUP; - } - - status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps, CAIRO_FILL_RULE_WINDING); - if (unlikely (status)) - goto CLEANUP; - - n = *size_boxes; - if (n < 0) - n = -n; - - if (traps.num_traps > n) { - cairo_box_t *new_boxes; - - new_boxes = _cairo_malloc_ab (traps.num_traps, sizeof (cairo_box_t)); - if (unlikely (new_boxes == NULL)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto CLEANUP; - } - - if (*size_boxes > 0) - free (*boxes); - - *boxes = new_boxes; - *size_boxes = traps.num_traps; - } - - for (n = 0; n < traps.num_traps; n++) { - (*boxes)[n].p1.x = traps.traps[n].left.p1.x; - (*boxes)[n].p1.y = traps.traps[n].top; - (*boxes)[n].p2.x = traps.traps[n].right.p1.x; - (*boxes)[n].p2.y = traps.traps[n].bottom; - } - *num_boxes = n; - - CLEANUP: - _cairo_traps_fini (&traps); - - return status; -} - -static cairo_status_t -_rectilinear_clip_to_boxes (const cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - cairo_box_t **boxes, - int *num_boxes, - int *size_boxes) -{ - cairo_polygon_t polygon; - cairo_traps_t traps; - cairo_status_t status; - - _cairo_traps_init (&traps); - _cairo_traps_limit (&traps, *boxes, *num_boxes); - - _cairo_polygon_init (&polygon, *boxes, *num_boxes); - - status = _cairo_path_fixed_fill_rectilinear_to_traps (path, - fill_rule, - &traps); - if (unlikely (_cairo_status_is_error (status))) - goto CLEANUP; - if (status == CAIRO_STATUS_SUCCESS) - goto BOXES; - - /* tolerance will be ignored as the path is rectilinear */ - status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon); - if (unlikely (status)) - goto CLEANUP; - - if (polygon.num_edges == 0) { - *num_boxes = 0; - } else { - status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps, - &polygon, - fill_rule); - if (likely (status == CAIRO_STATUS_SUCCESS)) { - int i; - - BOXES: - i = *size_boxes; - if (i < 0) - i = -i; - - if (traps.num_traps > i) { - cairo_box_t *new_boxes; - int new_size; - - new_size = pot (traps.num_traps); - new_boxes = _cairo_malloc_ab (new_size, sizeof (cairo_box_t)); - if (unlikely (new_boxes == NULL)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto CLEANUP; - } - - if (*size_boxes > 0) - free (*boxes); - - *boxes = new_boxes; - *size_boxes = new_size; - } - - for (i = 0; i < traps.num_traps; i++) { - (*boxes)[i].p1.x = traps.traps[i].left.p1.x; - (*boxes)[i].p1.y = traps.traps[i].top; - (*boxes)[i].p2.x = traps.traps[i].right.p1.x; - (*boxes)[i].p2.y = traps.traps[i].bottom; - } - *num_boxes = i; - } - } - - CLEANUP: - _cairo_polygon_fini (&polygon); - _cairo_traps_fini (&traps); - - return status; -} - -static cairo_int_status_t -_cairo_clip_path_to_boxes (cairo_clip_path_t *clip_path, - cairo_box_t **boxes, - int *count) -{ - int size = -*count; - int num_boxes = 0; - cairo_status_t status; - - if (clip_path->region != NULL) { - int num_rects, n; - - num_rects = cairo_region_num_rectangles (clip_path->region); - if (num_rects > -size) { - cairo_box_t *new_boxes; - - new_boxes = _cairo_malloc_ab (num_rects, sizeof (cairo_box_t)); - if (unlikely (new_boxes == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - *boxes = new_boxes; - } - - for (n = 0; n < num_rects; n++) { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (clip_path->region, n, &rect); - (*boxes)[n].p1.x = _cairo_fixed_from_int (rect.x); - (*boxes)[n].p1.y = _cairo_fixed_from_int (rect.y); - (*boxes)[n].p2.x = _cairo_fixed_from_int (rect.x + rect.width); - (*boxes)[n].p2.y = _cairo_fixed_from_int (rect.y + rect.height); - } - - *count = num_rects; - return CAIRO_STATUS_SUCCESS; - } - - /* keep it simple at first */ - if (! _clip_paths_are_rectilinear (clip_path)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - assert (-size >= 1); - if (_cairo_path_fixed_is_box (&clip_path->path, *boxes)) { - num_boxes = 1; - } else { - status = _rectilinear_clip_to_boxes (&clip_path->path, - clip_path->fill_rule, - boxes, &num_boxes, &size); - if (unlikely (status)) - return status; - } - - while (num_boxes > 0 && (clip_path = clip_path->prev) != NULL) { - cairo_box_t box; - - if (clip_path->region != NULL) { - status = _region_clip_to_boxes (clip_path->region, - boxes, &num_boxes, &size); - if (unlikely (status)) - return status; - - break; - } else if (_cairo_path_fixed_is_box (&clip_path->path, &box)) { - int i, j; - - for (i = j = 0; i < num_boxes; i++) { - if (j != i) - (*boxes)[j] = (*boxes)[i]; - - if (box.p1.x > (*boxes)[j].p1.x) - (*boxes)[j].p1.x = box.p1.x; - if (box.p2.x < (*boxes)[j].p2.x) - (*boxes)[j].p2.x = box.p2.x; - - if (box.p1.y > (*boxes)[j].p1.y) - (*boxes)[j].p1.y = box.p1.y; - if (box.p2.y < (*boxes)[j].p2.y) - (*boxes)[j].p2.y = box.p2.y; - - j += (*boxes)[j].p2.x > (*boxes)[j].p1.x && - (*boxes)[j].p2.y > (*boxes)[j].p1.y; - } - - num_boxes = j; - } else { - status = _rectilinear_clip_to_boxes (&clip_path->path, - clip_path->fill_rule, - boxes, &num_boxes, &size); - if (unlikely (status)) - return status; - } - } - - *count = num_boxes; - return CAIRO_STATUS_SUCCESS; + return clip; } -static cairo_surface_t * -_cairo_clip_path_get_surface (cairo_clip_path_t *clip_path, - cairo_surface_t *target, - int *tx, int *ty) +cairo_clip_t * +_cairo_clip_copy_with_translation (const cairo_clip_t *clip, int tx, int ty) { - const cairo_rectangle_int_t *clip_extents = &clip_path->extents; - cairo_bool_t need_translate; - cairo_surface_t *surface; - cairo_clip_path_t *prev; - cairo_status_t status; + cairo_clip_t *copy; + int fx, fy, i; - while (clip_path->prev != NULL && - clip_path->flags & CAIRO_CLIP_PATH_IS_BOX && - _cairo_path_fixed_fill_maybe_region (&clip_path->path)) - { - clip_path = clip_path->prev; - } + if (clip == NULL || _cairo_clip_is_all_clipped (clip)) + return (cairo_clip_t *)clip; - clip_extents = &clip_path->extents; - if (clip_path->surface != NULL && - clip_path->surface->backend == target->backend) - { - *tx = clip_extents->x; - *ty = clip_extents->y; - return clip_path->surface; - } + if (tx == 0 && ty == 0) + return _cairo_clip_copy (clip); - surface = _cairo_surface_create_similar_scratch (target, - CAIRO_CONTENT_ALPHA, - clip_extents->width, - clip_extents->height); - if (surface == NULL) { - surface = cairo_image_surface_create (CAIRO_FORMAT_A8, - clip_extents->width, - clip_extents->height); - } - if (unlikely (surface->status)) - return surface; - - need_translate = clip_extents->x | clip_extents->y; - if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX && - _cairo_path_fixed_fill_maybe_region (&clip_path->path)) - { - status = _cairo_surface_paint (surface, - CAIRO_OPERATOR_SOURCE, - &_cairo_pattern_white.base, - NULL); - if (unlikely (status)) - goto BAIL; - } - else - { - status = _cairo_surface_paint (surface, - CAIRO_OPERATOR_CLEAR, - &_cairo_pattern_clear.base, - NULL); - if (unlikely (status)) - goto BAIL; - - if (need_translate) { - _cairo_path_fixed_translate (&clip_path->path, - _cairo_fixed_from_int (-clip_extents->x), - _cairo_fixed_from_int (-clip_extents->y)); - } - status = _cairo_surface_fill (surface, - CAIRO_OPERATOR_ADD, - &_cairo_pattern_white.base, - &clip_path->path, - clip_path->fill_rule, - clip_path->tolerance, - clip_path->antialias, - NULL); - if (need_translate) { - _cairo_path_fixed_translate (&clip_path->path, - _cairo_fixed_from_int (clip_extents->x), - _cairo_fixed_from_int (clip_extents->y)); - } + copy = _cairo_clip_create (); + if (copy == NULL) + return _cairo_clip_set_all_clipped (copy); - if (unlikely (status)) - goto BAIL; - } + fx = _cairo_fixed_from_int (tx); + fy = _cairo_fixed_from_int (ty); - prev = clip_path->prev; - while (prev != NULL) { - if (prev->flags & CAIRO_CLIP_PATH_IS_BOX && - _cairo_path_fixed_fill_maybe_region (&prev->path)) - { - /* a simple box only affects the extents */ - } - else if (_cairo_path_fixed_fill_is_rectilinear (&prev->path) || - prev->surface == NULL || - prev->surface->backend != target->backend) - { - if (need_translate) { - _cairo_path_fixed_translate (&prev->path, - _cairo_fixed_from_int (-clip_extents->x), - _cairo_fixed_from_int (-clip_extents->y)); - } - status = _cairo_surface_fill (surface, - CAIRO_OPERATOR_IN, - &_cairo_pattern_white.base, - &prev->path, - prev->fill_rule, - prev->tolerance, - prev->antialias, - NULL); - if (need_translate) { - _cairo_path_fixed_translate (&prev->path, - _cairo_fixed_from_int (clip_extents->x), - _cairo_fixed_from_int (clip_extents->y)); - } + if (clip->num_boxes) { + copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t)); + if (unlikely (copy->boxes == NULL)) + return _cairo_clip_set_all_clipped (copy); - if (unlikely (status)) - goto BAIL; - } - else - { - cairo_surface_pattern_t pattern; - cairo_surface_t *prev_surface; - int prev_tx, prev_ty; - - prev_surface = _cairo_clip_path_get_surface (prev, target, &prev_tx, &prev_ty); - status = prev_surface->status; - if (unlikely (status)) - goto BAIL; - - _cairo_pattern_init_for_surface (&pattern, prev_surface); - pattern.base.filter = CAIRO_FILTER_NEAREST; - cairo_matrix_init_translate (&pattern.base.matrix, - clip_extents->x - prev_tx, - clip_extents->y - prev_ty); - status = _cairo_surface_paint (surface, - CAIRO_OPERATOR_IN, - &pattern.base, - NULL); - _cairo_pattern_fini (&pattern.base); - - if (unlikely (status)) - goto BAIL; - - break; + for (i = 0; i < clip->num_boxes; i++) { + copy->boxes[i].p1.x = clip->boxes[i].p1.x + fx; + copy->boxes[i].p2.x = clip->boxes[i].p2.x + fx; + copy->boxes[i].p1.y = clip->boxes[i].p1.y + fy; + copy->boxes[i].p2.y = clip->boxes[i].p2.y + fy; } - - prev = prev->prev; + copy->num_boxes = clip->num_boxes; } - *tx = clip_extents->x; - *ty = clip_extents->y; - cairo_surface_destroy (clip_path->surface); - return clip_path->surface = surface; - - BAIL: - cairo_surface_destroy (surface); - return _cairo_surface_create_in_error (status); -} - -cairo_bool_t -_cairo_clip_contains_rectangle (cairo_clip_t *clip, - const cairo_rectangle_int_t *rect) -{ - cairo_clip_path_t *clip_path; - - /* clip == NULL means no clip, so the clip contains everything */ - if (clip == NULL) - return TRUE; - - clip_path = clip->path; - if (clip_path->extents.x > rect->x || - clip_path->extents.y > rect->y || - clip_path->extents.x + clip_path->extents.width < rect->x + rect->width || - clip_path->extents.y + clip_path->extents.height < rect->y + rect->height) - { - return FALSE; - } + copy->extents = clip->extents; + copy->extents.x += tx; + copy->extents.y += ty; - do { - cairo_box_t box; - - if ((clip_path->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) - return FALSE; - - if (! _cairo_path_fixed_is_box (&clip_path->path, &box)) - return FALSE; - - if (box.p1.x > _cairo_fixed_from_int (rect->x) || - box.p1.y > _cairo_fixed_from_int (rect->y) || - box.p2.x < _cairo_fixed_from_int (rect->x + rect->width) || - box.p2.y < _cairo_fixed_from_int (rect->y + rect->height)) - { - return FALSE; - } - } while ((clip_path = clip_path->prev) != NULL); + if (clip->path == NULL) + return copy; - return TRUE; + return _cairo_clip_path_copy_with_translation (copy, clip->path, fx, fy); } cairo_bool_t -_cairo_clip_contains_extents (cairo_clip_t *clip, +_cairo_clip_contains_extents (const cairo_clip_t *clip, const cairo_composite_rectangles_t *extents) { const cairo_rectangle_int_t *rect; @@ -1155,149 +336,57 @@ _cairo_clip_contains_extents (cairo_clip_t *clip, } void -_cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip) +_cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip) { - cairo_clip_path_t *clip_path; + int i; if (clip == NULL) { fprintf (stream, "no clip\n"); return; } - if (clip->all_clipped) { + if (_cairo_clip_is_all_clipped (clip)) { fprintf (stream, "clip: all-clipped\n"); return; } - if (clip->path == NULL) { - fprintf (stream, "clip: empty\n"); - return; - } - fprintf (stream, "clip:\n"); + fprintf (stream, " extents: (%d, %d) x (%d, %d)", + clip->extents.x, clip->extents.y, + clip->extents.width, clip->extents.height); - clip_path = clip->path; - do { - fprintf (stream, "path: has region? %s, has surface? %s, aa=%d, tolerance=%f, rule=%d: ", - clip_path->region == NULL ? "no" : "yes", - clip_path->surface == NULL ? "no" : "yes", - clip_path->antialias, - clip_path->tolerance, - clip_path->fill_rule); - _cairo_debug_print_path (stream, &clip_path->path); - fprintf (stream, "\n"); - } while ((clip_path = clip_path->prev) != NULL); -} - -cairo_surface_t * -_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target, int *tx, int *ty) -{ - /* XXX is_clear -> all_clipped */ - assert (clip->path != NULL); - return _cairo_clip_path_get_surface (clip->path, target, tx, ty); -} - -cairo_status_t -_cairo_clip_combine_with_surface (cairo_clip_t *clip, - cairo_surface_t *dst, - int dst_x, int dst_y) -{ - cairo_clip_path_t *clip_path = clip->path; - cairo_bool_t need_translate; - cairo_status_t status; - - assert (clip_path != NULL); - - need_translate = dst_x | dst_y; - do { - if (clip_path->surface != NULL && - clip_path->surface->backend == dst->backend) - { - cairo_surface_pattern_t pattern; - - _cairo_pattern_init_for_surface (&pattern, clip_path->surface); - cairo_matrix_init_translate (&pattern.base.matrix, - dst_x - clip_path->extents.x, - dst_y - clip_path->extents.y); - pattern.base.filter = CAIRO_FILTER_NEAREST; - status = _cairo_surface_paint (dst, - CAIRO_OPERATOR_IN, - &pattern.base, - NULL); - - _cairo_pattern_fini (&pattern.base); - - return status; - } - - if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX && - _cairo_path_fixed_fill_maybe_region (&clip_path->path)) - { - continue; - } - - if (need_translate) { - _cairo_path_fixed_translate (&clip_path->path, - _cairo_fixed_from_int (-dst_x), - _cairo_fixed_from_int (-dst_y)); - } - status = _cairo_surface_fill (dst, - CAIRO_OPERATOR_IN, - &_cairo_pattern_white.base, - &clip_path->path, - clip_path->fill_rule, - clip_path->tolerance, - clip_path->antialias, - NULL); - if (need_translate) { - _cairo_path_fixed_translate (&clip_path->path, - _cairo_fixed_from_int (dst_x), - _cairo_fixed_from_int (dst_y)); - } - - if (unlikely (status)) - return status; - } while ((clip_path = clip_path->prev) != NULL); + fprintf (stream, " num_boxes = %d\n", clip->num_boxes); + for (i = 0; i < clip->num_boxes; i++) { + fprintf (stream, " [%d] = (%f, %f), (%f, %f)\n", i, + _cairo_fixed_to_double (clip->boxes[i].p1.x), + _cairo_fixed_to_double (clip->boxes[i].p1.y), + _cairo_fixed_to_double (clip->boxes[i].p2.x), + _cairo_fixed_to_double (clip->boxes[i].p2.y)); + } - return CAIRO_STATUS_SUCCESS; + if (clip->path) { + cairo_clip_path_t *clip_path = clip->path; + do { + fprintf (stream, "path: aa=%d, tolerance=%f, rule=%d: ", + clip_path->antialias, + clip_path->tolerance, + clip_path->fill_rule); + _cairo_debug_print_path (stream, &clip_path->path); + fprintf (stream, "\n"); + } while ((clip_path = clip_path->prev) != NULL); + } } -static const cairo_rectangle_int_t _cairo_empty_rectangle_int = { 0, 0, 0, 0 }; - const cairo_rectangle_int_t * _cairo_clip_get_extents (const cairo_clip_t *clip) { - if (clip->all_clipped) - return &_cairo_empty_rectangle_int; - - if (clip->path == NULL) - return NULL; - - return &clip->path->extents; -} - -void -_cairo_clip_drop_cache (cairo_clip_t *clip) -{ - cairo_clip_path_t *clip_path; - - if (clip->path == NULL) - return; + if (clip == NULL) + return &_cairo_unbounded_rectangle; - clip_path = clip->path; - do { - if (clip_path->region != NULL) { - cairo_region_destroy (clip_path->region); - clip_path->region = NULL; - } + if (_cairo_clip_is_all_clipped (clip)) + return &_cairo_empty_rectangle; - if (clip_path->surface != NULL) { - cairo_surface_destroy (clip_path->surface); - clip_path->surface = NULL; - } - - clip_path->flags &= ~CAIRO_CLIP_PATH_HAS_REGION; - } while ((clip_path = clip_path->prev) != NULL); + return &clip->extents; } const cairo_rectangle_list_t _cairo_rectangles_nil = @@ -1329,145 +418,6 @@ _cairo_clip_int_rect_to_user (cairo_gstate_t *gstate, return is_tight; } -cairo_int_status_t -_cairo_clip_get_region (cairo_clip_t *clip, - cairo_region_t **region) -{ - cairo_int_status_t status; - - if (clip->all_clipped) - goto CLIPPED; - - assert (clip->path != NULL); - - status = _cairo_clip_path_to_region (clip->path); - if (status) - return status; - - if (cairo_region_is_empty (clip->path->region)) { - _cairo_clip_set_all_clipped (clip); - goto CLIPPED; - } - - if (region) - *region = clip->path->region; - return CAIRO_STATUS_SUCCESS; - - CLIPPED: - if (region) - *region = NULL; - return CAIRO_INT_STATUS_NOTHING_TO_DO; -} - -cairo_int_status_t -_cairo_clip_get_boxes (cairo_clip_t *clip, - cairo_box_t **boxes, - int *count) -{ - cairo_int_status_t status; - - if (clip->all_clipped) - return CAIRO_INT_STATUS_NOTHING_TO_DO; - - assert (clip->path != NULL); - - status = _cairo_clip_path_to_boxes (clip->path, boxes, count); - if (status) - return status; - - if (*count == 0) { - _cairo_clip_set_all_clipped (clip); - return CAIRO_INT_STATUS_NOTHING_TO_DO; - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_bool_t -box_is_aligned (const cairo_box_t *box) -{ - return - _cairo_fixed_is_integer (box->p1.x) && - _cairo_fixed_is_integer (box->p1.y) && - _cairo_fixed_is_integer (box->p2.x) && - _cairo_fixed_is_integer (box->p2.y); -} - -static void -intersect_with_boxes (cairo_composite_rectangles_t *extents, - cairo_box_t *boxes, - int num_boxes) -{ - cairo_rectangle_int_t rect; - cairo_box_t box; - int i; - - assert (num_boxes > 0); - - /* Find the extents over all the clip boxes */ - box = boxes[0]; - for (i = 1; i < num_boxes; i++) { - if (boxes[i].p1.x < box.p1.x) - box.p1.x = boxes[i].p1.x; - if (boxes[i].p1.y < box.p1.y) - box.p1.y = boxes[i].p1.y; - - if (boxes[i].p2.x > box.p2.x) - box.p2.x = boxes[i].p2.x; - if (boxes[i].p2.y > box.p2.y) - box.p2.y = boxes[i].p2.y; - } - - _cairo_box_round_to_rectangle (&box, &rect); - _cairo_rectangle_intersect (&extents->bounded, &rect); - _cairo_rectangle_intersect (&extents->unbounded, &rect); -} - -cairo_status_t -_cairo_clip_to_boxes (cairo_clip_t **clip, - cairo_composite_rectangles_t *extents, - cairo_box_t **boxes, - int *num_boxes) -{ - cairo_status_t status; - const cairo_rectangle_int_t *rect; - - rect = extents->is_bounded ? &extents->bounded : &extents->unbounded; - - if (*clip == NULL) - goto EXTENTS; - - status = _cairo_clip_rectangle (*clip, rect); - if (unlikely (status)) - return status; - - status = _cairo_clip_get_boxes (*clip, boxes, num_boxes); - switch ((int) status) { - case CAIRO_STATUS_SUCCESS: - intersect_with_boxes (extents, *boxes, *num_boxes); - if (rect->width == 0 || rect->height == 0 || - extents->is_bounded || - (*num_boxes == 1 && box_is_aligned (*boxes))) - { - *clip = NULL; - } - goto DONE; - - case CAIRO_INT_STATUS_UNSUPPORTED: - goto EXTENTS; - - default: - return status; - } - - EXTENTS: - status = CAIRO_STATUS_SUCCESS; - _cairo_box_from_rectangle (&(*boxes)[0], rect); - *num_boxes = 1; - DONE: - return status; -} - cairo_rectangle_list_t * _cairo_rectangle_list_create_in_error (cairo_status_t status) { @@ -1499,24 +449,18 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate) cairo_rectangle_list_t *list; cairo_rectangle_t *rectangles = NULL; cairo_region_t *region = NULL; - cairo_int_status_t status; int n_rects = 0; int i; - if (clip->all_clipped) - goto DONE; - - if (!clip->path) + if (clip == NULL) return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE); - status = _cairo_clip_get_region (clip, ®ion); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { + if (_cairo_clip_is_all_clipped (clip)) goto DONE; - } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) { - return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE); - } else if (unlikely (status)) { - return ERROR_LIST (status); - } + + region = _cairo_clip_get_region (clip); + if (region == NULL) + return ERROR_LIST (CAIRO_STATUS_NO_MEMORY); n_rects = cairo_region_num_rectangles (region); if (n_rects) { diff --git a/src/cairo-composite-rectangles-private.h b/src/cairo-composite-rectangles-private.h index a0f7c1a54..2b4bdba93 100644 --- a/src/cairo-composite-rectangles-private.h +++ b/src/cairo-composite-rectangles-private.h @@ -56,6 +56,8 @@ struct _cairo_composite_rectangles { cairo_rectangle_int_t bounded; /* dst */ cairo_rectangle_int_t unbounded; /* clip */ uint32_t is_bounded; + + cairo_clip_t *clip; }; cairo_private cairo_int_status_t @@ -63,7 +65,7 @@ _cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extent int surface_width, int surface_height, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_int_status_t _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents, @@ -71,25 +73,25 @@ _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_int_status_t _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents, int surface_width, int surface_height, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_int_status_t _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents, int surface_width, int surface_height, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, - cairo_clip_t *clip); + const cairo_path_fixed_t *path, + const cairo_clip_t *clip); cairo_private cairo_int_status_t _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents, @@ -99,7 +101,10 @@ _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *exten cairo_scaled_font_t *scaled_font, cairo_glyph_t *glyphs, int num_glyphs, - cairo_clip_t *clip, + const cairo_clip_t *clip, cairo_bool_t *overlap); +cairo_private void +_cairo_composite_rectangles_fini (cairo_composite_rectangles_t *extents); + #endif /* CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H */ diff --git a/src/cairo-composite-rectangles.c b/src/cairo-composite-rectangles.c index 4240de3c9..cab7c0cfd 100644 --- a/src/cairo-composite-rectangles.c +++ b/src/cairo-composite-rectangles.c @@ -41,25 +41,29 @@ /* A collection of routines to facilitate writing compositors. */ +void _cairo_composite_rectangles_fini (cairo_composite_rectangles_t *extents) +{ + _cairo_clip_destroy (extents->clip); +} + static inline cairo_bool_t _cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents, int width, int height, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { extents->unbounded.x = extents->unbounded.y = 0; extents->unbounded.width = width; extents->unbounded.height = height; + extents->clip = NULL; - if (clip != NULL) { - const cairo_rectangle_int_t *clip_extents; - - clip_extents = _cairo_clip_get_extents (clip); - if (clip_extents == NULL) - return FALSE; + if (_cairo_clip_is_all_clipped (clip)) + return FALSE; - if (! _cairo_rectangle_intersect (&extents->unbounded, clip_extents)) + if (clip != NULL) { + if (! _cairo_rectangle_intersect (&extents->unbounded, + _cairo_clip_get_extents (clip))) return FALSE; } @@ -80,7 +84,7 @@ _cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extent int surface_width, int surface_height, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { if (! _cairo_composite_rectangles_init (extents, surface_width, surface_height, @@ -90,11 +94,17 @@ _cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extent } extents->mask = extents->bounded; + + extents->clip = _cairo_clip_reduce_for_composite (clip, extents); + if (_cairo_clip_is_all_clipped (extents->clip)) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t -_cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents) +_cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents, + const cairo_clip_t *clip) { cairo_bool_t ret; @@ -102,6 +112,10 @@ _cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents) if (! ret && extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) return CAIRO_INT_STATUS_NOTHING_TO_DO; + extents->clip = _cairo_clip_reduce_for_composite (clip, extents); + if (_cairo_clip_is_all_clipped (extents->clip)) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + return CAIRO_STATUS_SUCCESS; } @@ -111,7 +125,7 @@ _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { if (! _cairo_composite_rectangles_init (extents, surface_width, surface_height, @@ -122,7 +136,7 @@ _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents _cairo_pattern_get_extents (mask, &extents->mask); - return _cairo_composite_rectangles_intersect (extents); + return _cairo_composite_rectangles_intersect (extents, clip); } cairo_int_status_t @@ -130,10 +144,10 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten int surface_width, int surface_height, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, - cairo_clip_t *clip) + const cairo_clip_t *clip) { if (! _cairo_composite_rectangles_init (extents, surface_width, surface_height, @@ -144,7 +158,7 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &extents->mask); - return _cairo_composite_rectangles_intersect (extents); + return _cairo_composite_rectangles_intersect (extents, clip); } cairo_int_status_t @@ -152,8 +166,8 @@ _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents int surface_width, int surface_height, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, - cairo_clip_t *clip) + const cairo_path_fixed_t *path, + const cairo_clip_t *clip) { if (! _cairo_composite_rectangles_init (extents, surface_width, surface_height, @@ -164,7 +178,7 @@ _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents _cairo_path_fixed_approximate_fill_extents (path, &extents->mask); - return _cairo_composite_rectangles_intersect (extents); + return _cairo_composite_rectangles_intersect (extents, clip); } cairo_int_status_t @@ -175,7 +189,7 @@ _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *exten cairo_scaled_font_t *scaled_font, cairo_glyph_t *glyphs, int num_glyphs, - cairo_clip_t *clip, + const cairo_clip_t *clip, cairo_bool_t *overlap) { cairo_status_t status; @@ -194,5 +208,5 @@ _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *exten if (unlikely (status)) return status; - return _cairo_composite_rectangles_intersect (extents); + return _cairo_composite_rectangles_intersect (extents, clip); } diff --git a/src/cairo-debug.c b/src/cairo-debug.c index 9b16de842..99289e3f8 100644 --- a/src/cairo-debug.c +++ b/src/cairo-debug.c @@ -35,7 +35,6 @@ #include "cairoint.h" - /** * cairo_debug_reset_static_data: * @@ -234,8 +233,10 @@ void _cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path) { cairo_status_t status; + cairo_box_t box; - printf ("path: extents=(%f, %f), (%f, %f)\n", + fprintf (stream, + "path: extents=(%f, %f), (%f, %f)\n", _cairo_fixed_to_double (path->extents.p1.x), _cairo_fixed_to_double (path->extents.p1.y), _cairo_fixed_to_double (path->extents.p2.x), @@ -249,5 +250,37 @@ _cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path) stream); assert (status == CAIRO_STATUS_SUCCESS); + if (_cairo_path_fixed_is_box (path, &box)) { + fprintf (stream, "[box (%d, %d), (%d, %d)]", + box.p1.x, box.p1.y, box.p2.x, box.p2.y); + } + printf ("\n"); } + +void +_cairo_debug_print_polygon (FILE *stream, cairo_polygon_t *polygon) +{ + int n; + + fprintf (stream, + "polygon: extents=(%f, %f), (%f, %f)\n", + _cairo_fixed_to_double (polygon->extents.p1.x), + _cairo_fixed_to_double (polygon->extents.p1.y), + _cairo_fixed_to_double (polygon->extents.p2.x), + _cairo_fixed_to_double (polygon->extents.p2.y)); + for (n = 0; n < polygon->num_edges; n++) { + cairo_edge_t *edge = &polygon->edges[n]; + + fprintf (stream, + " (%f, %f) -> (%f, %f), top=%f, bottom=%f, dir=%d\n", + _cairo_fixed_to_double (edge->line.p1.x), + _cairo_fixed_to_double (edge->line.p1.y), + _cairo_fixed_to_double (edge->line.p2.x), + _cairo_fixed_to_double (edge->line.p2.y), + _cairo_fixed_to_double (edge->top), + _cairo_fixed_to_double (edge->bottom), + edge->dir); + + } +} diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c index cec8016f2..1798e5c10 100644 --- a/src/cairo-default-context.c +++ b/src/cairo-default-context.c @@ -131,7 +131,7 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content) cairo_status_t status; clip = _cairo_gstate_get_clip (cr->gstate); - if (clip->all_clipped) { + if (_cairo_clip_is_all_clipped (clip)) { group_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); status = group_surface->status; if (unlikely (status)) @@ -276,7 +276,8 @@ _cairo_default_context_set_source_rgba (void *abstract_cr, double red, double gr cairo_pattern_t *pattern; cairo_status_t status; - if (_current_source_matches_solid (cr->gstate->source, red, green, blue, 1.)) + if (_current_source_matches_solid (cr->gstate->source, + red, green, blue, alpha)) return CAIRO_STATUS_SUCCESS; /* push the current pattern to the freed lists */ diff --git a/src/cairo-error-private.h b/src/cairo-error-private.h index fc0c56438..953e8afaf 100644 --- a/src/cairo-error-private.h +++ b/src/cairo-error-private.h @@ -43,9 +43,63 @@ CAIRO_BEGIN_DECLS +enum _cairo_int_status { + CAIRO_INT_STATUS_SUCCESS = 0, + + CAIRO_INT_STATUS_NO_MEMORY, + CAIRO_INT_STATUS_INVALID_RESTORE, + CAIRO_INT_STATUS_INVALID_POP_GROUP, + CAIRO_INT_STATUS_NO_CURRENT_POINT, + CAIRO_INT_STATUS_INVALID_MATRIX, + CAIRO_INT_STATUS_INVALID_STATUS, + CAIRO_INT_STATUS_NULL_POINTER, + CAIRO_INT_STATUS_INVALID_STRING, + CAIRO_INT_STATUS_INVALID_PATH_DATA, + CAIRO_INT_STATUS_READ_ERROR, + CAIRO_INT_STATUS_WRITE_ERROR, + CAIRO_INT_STATUS_SURFACE_FINISHED, + CAIRO_INT_STATUS_SURFACE_TYPE_MISMATCH, + CAIRO_INT_STATUS_PATTERN_TYPE_MISMATCH, + CAIRO_INT_STATUS_INVALID_CONTENT, + CAIRO_INT_STATUS_INVALID_FORMAT, + CAIRO_INT_STATUS_INVALID_VISUAL, + CAIRO_INT_STATUS_FILE_NOT_FOUND, + CAIRO_INT_STATUS_INVALID_DASH, + CAIRO_INT_STATUS_INVALID_DSC_COMMENT, + CAIRO_INT_STATUS_INVALID_INDEX, + CAIRO_INT_STATUS_CLIP_NOT_REPRESENTABLE, + CAIRO_INT_STATUS_TEMP_FILE_ERROR, + CAIRO_INT_STATUS_INVALID_STRIDE, + CAIRO_INT_STATUS_FONT_TYPE_MISMATCH, + CAIRO_INT_STATUS_USER_FONT_IMMUTABLE, + CAIRO_INT_STATUS_USER_FONT_ERROR, + CAIRO_INT_STATUS_NEGATIVE_COUNT, + CAIRO_INT_STATUS_INVALID_CLUSTERS, + CAIRO_INT_STATUS_INVALID_SLANT, + CAIRO_INT_STATUS_INVALID_WEIGHT, + CAIRO_INT_STATUS_INVALID_SIZE, + CAIRO_INT_STATUS_USER_FONT_NOT_IMPLEMENTED, + CAIRO_INT_STATUS_DEVICE_TYPE_MISMATCH, + CAIRO_INT_STATUS_DEVICE_ERROR, + CAIRO_INT_STATUS_INVALID_MESH_CONSTRUCTION, + CAIRO_INT_STATUS_DEVICE_FINISHED, + + CAIRO_INT_STATUS_LAST_STATUS, + + CAIRO_INT_STATUS_UNSUPPORTED = 100, + CAIRO_INT_STATUS_DEGENERATE, + CAIRO_INT_STATUS_NOTHING_TO_DO, + CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY, + CAIRO_INT_STATUS_IMAGE_FALLBACK, + CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN, +}; + #define _cairo_status_is_error(status) \ (status != CAIRO_STATUS_SUCCESS && status <= CAIRO_STATUS_LAST_STATUS) +#define _cairo_int_status_is_error(status) \ + (status != CAIRO_INT_STATUS_SUCCESS && status <= CAIRO_INT_STATUS_LAST_STATUS) + cairo_private cairo_status_t _cairo_error (cairo_status_t status); diff --git a/src/cairo-error.c b/src/cairo-error.c index a3fc19726..1b9bd76be 100644 --- a/src/cairo-error.c +++ b/src/cairo-error.c @@ -39,7 +39,9 @@ #include "cairoint.h" #include "cairo-private.h" +#include "cairo-compiler-private.h" #include "cairo-error-private.h" + #include <assert.h> /** @@ -67,3 +69,5 @@ _cairo_error (cairo_status_t status) return status; } + +COMPILE_TIME_ASSERT ((int)CAIRO_INT_STATUS_LAST_STATUS == (int)CAIRO_STATUS_LAST_STATUS); diff --git a/src/cairo-fixed-private.h b/src/cairo-fixed-private.h index 6cecc8dc5..9a16a037b 100644 --- a/src/cairo-fixed-private.h +++ b/src/cairo-fixed-private.h @@ -164,6 +164,12 @@ _cairo_fixed_floor (cairo_fixed_t f) } static inline cairo_fixed_t +_cairo_fixed_ceil (cairo_fixed_t f) +{ + return _cairo_fixed_floor (f + CAIRO_FIXED_FRAC_MASK); +} + +static inline cairo_fixed_t _cairo_fixed_round (cairo_fixed_t f) { return _cairo_fixed_floor (f + (CAIRO_FIXED_FRAC_MASK+1)/2); diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c index 98c6dd8a9..2ad263028 100644 --- a/src/cairo-font-face-twin.c +++ b/src/cairo-font-face-twin.c @@ -283,16 +283,14 @@ face_props_parse (twin_face_properties_t *props, parse_field (props, start, end - start); } -static cairo_status_t -twin_font_face_create_properties (cairo_font_face_t *twin_face, - twin_face_properties_t **props_out) +static twin_face_properties_t * +twin_font_face_create_properties (cairo_font_face_t *twin_face) { twin_face_properties_t *props; - cairo_status_t status; props = malloc (sizeof (twin_face_properties_t)); if (unlikely (props == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + return NULL; props->stretch = TWIN_STRETCH_NORMAL; props->slant = CAIRO_FONT_SLANT_NORMAL; @@ -300,30 +298,25 @@ twin_font_face_create_properties (cairo_font_face_t *twin_face, props->monospace = FALSE; props->smallcaps = FALSE; - status = cairo_font_face_set_user_data (twin_face, + if (unlikely (cairo_font_face_set_user_data (twin_face, &twin_properties_key, - props, free); - if (unlikely (status)) { + props, free))) { free (props); - return status; + return NULL; } - if (props_out) - *props_out = props; - - return CAIRO_STATUS_SUCCESS; + return props; } static cairo_status_t twin_font_face_set_properties_from_toy (cairo_font_face_t *twin_face, cairo_toy_font_face_t *toy_face) { - cairo_status_t status; twin_face_properties_t *props; - status = twin_font_face_create_properties (twin_face, &props); - if (unlikely (status)) - return status; + props = twin_font_face_create_properties (twin_face); + if (unlikely (props == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); props->slant = toy_face->slant; props->weight = toy_face->weight == CAIRO_FONT_WEIGHT_NORMAL ? @@ -729,11 +722,9 @@ cairo_font_face_t * _cairo_font_face_twin_create_fallback (void) { cairo_font_face_t *twin_font_face; - cairo_status_t status; twin_font_face = _cairo_font_face_twin_create_internal (); - status = twin_font_face_create_properties (twin_font_face, NULL); - if (status) { + if (! twin_font_face_create_properties (twin_font_face)) { cairo_font_face_destroy (twin_font_face); return (cairo_font_face_t *) &_cairo_font_face_nil; } diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 638920067..ff737a305 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -2573,27 +2573,28 @@ static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = { /* #cairo_ft_font_face_t */ #if CAIRO_HAS_FC_FONT -static cairo_status_t -_cairo_ft_font_face_create_for_pattern (FcPattern *pattern, - cairo_font_face_t **out); +static cairo_font_face_t * +_cairo_ft_font_face_create_for_pattern (FcPattern *pattern); static cairo_status_t -_cairo_ft_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, - cairo_font_face_t **font_face) +_cairo_ft_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, + cairo_font_face_t **font_face_out) { + cairo_font_face_t *font_face = (cairo_font_face_t *) &_cairo_font_face_nil; FcPattern *pattern; int fcslant; int fcweight; - cairo_status_t status = CAIRO_STATUS_SUCCESS; pattern = FcPatternCreate (); - if (!pattern) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (!pattern) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return font_face->status; + } if (!FcPatternAddString (pattern, FC_FAMILY, (unsigned char *) toy_face->family)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); goto FREE_PATTERN; } @@ -2612,7 +2613,7 @@ _cairo_ft_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, } if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); goto FREE_PATTERN; } @@ -2628,16 +2629,17 @@ _cairo_ft_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, } if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); goto FREE_PATTERN; } - status = _cairo_ft_font_face_create_for_pattern (pattern, font_face); + font_face = _cairo_ft_font_face_create_for_pattern (pattern); FREE_PATTERN: FcPatternDestroy (pattern); - return status; + *font_face_out = font_face; + return font_face->status; } #endif @@ -2776,15 +2778,16 @@ const cairo_font_face_backend_t _cairo_ft_font_face_backend = { }; #if CAIRO_HAS_FC_FONT -static cairo_status_t -_cairo_ft_font_face_create_for_pattern (FcPattern *pattern, - cairo_font_face_t **out) +static cairo_font_face_t * +_cairo_ft_font_face_create_for_pattern (FcPattern *pattern) { cairo_ft_font_face_t *font_face; font_face = malloc (sizeof (cairo_ft_font_face_t)); - if (unlikely (font_face == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (unlikely (font_face == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *) &_cairo_font_face_nil; + } font_face->unscaled = NULL; font_face->next = NULL; @@ -2792,7 +2795,8 @@ _cairo_ft_font_face_create_for_pattern (FcPattern *pattern, font_face->pattern = FcPatternDuplicate (pattern); if (unlikely (font_face->pattern == NULL)) { free (font_face); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *) &_cairo_font_face_nil; } font_face->resolved_font_face = NULL; @@ -2800,8 +2804,7 @@ _cairo_ft_font_face_create_for_pattern (FcPattern *pattern, _cairo_font_face_init (&font_face->base, &_cairo_ft_font_face_backend); - *out = &font_face->base; - return CAIRO_STATUS_SUCCESS; + return &font_face->base; } #endif @@ -3156,12 +3159,7 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern) if (unlikely (unscaled == NULL)) { /* Store the pattern. We will resolve it and create unscaled * font when creating scaled fonts */ - status = _cairo_ft_font_face_create_for_pattern (pattern, - &font_face); - if (unlikely (status)) - return (cairo_font_face_t *) &_cairo_font_face_nil; - - return font_face; + return _cairo_ft_font_face_create_for_pattern (pattern); } _get_pattern_ft_options (pattern, &ft_options); diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c index f09cf419c..81efbbb52 100644 --- a/src/cairo-gl-glyphs.c +++ b/src/cairo-gl-glyphs.c @@ -40,6 +40,7 @@ #include "cairo-gl-private.h" +#include "cairo-composite-rectangles-private.h" #include "cairo-error-private.h" #include "cairo-rtree-private.h" @@ -54,7 +55,7 @@ typedef struct _cairo_gl_glyph_private { struct { float x, y; } p1, p2; } cairo_gl_glyph_private_t; -static cairo_status_t +static cairo_int_status_t _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx, cairo_gl_glyph_cache_t *cache, cairo_scaled_glyph_t *scaled_glyph) @@ -63,7 +64,7 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx, cairo_gl_surface_t *cache_surface; cairo_gl_glyph_private_t *glyph_private; cairo_rtree_node_t *node = NULL; - cairo_status_t status; + cairo_int_status_t status; int width, height; width = glyph_surface->width; @@ -79,7 +80,7 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx, if (status == CAIRO_INT_STATUS_UNSUPPORTED) { status = _cairo_rtree_evict_random (&cache->rtree, width, height, &node); - if (status == CAIRO_STATUS_SUCCESS) { + if (status == CAIRO_INT_STATUS_SUCCESS) { status = _cairo_rtree_node_insert (&cache->rtree, node, width, height, &node); } @@ -148,6 +149,7 @@ cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx, cache = &ctx->glyph_cache[1]; content = CAIRO_CONTENT_ALPHA; break; + default: case CAIRO_FORMAT_INVALID: ASSERT_NOT_REACHED; return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); @@ -227,10 +229,9 @@ _render_glyphs (cairo_gl_surface_t *dst, const cairo_pattern_t *source, cairo_glyph_t *glyphs, int num_glyphs, - const cairo_rectangle_int_t *glyph_extents, cairo_scaled_font_t *scaled_font, + const cairo_composite_rectangles_t *extents, cairo_bool_t *has_component_alpha, - cairo_region_t *clip_region, int *remaining_glyphs) { cairo_format_t last_format = CAIRO_FORMAT_INVALID; @@ -249,7 +250,7 @@ _render_glyphs (cairo_gl_surface_t *dst, _cairo_scaled_font_freeze_cache (scaled_font); status = _cairo_gl_composite_init (&setup, op, dst, - TRUE, glyph_extents); + TRUE, &extents->bounded); if (unlikely (status)) goto FINISH; @@ -260,10 +261,11 @@ _render_glyphs (cairo_gl_surface_t *dst, } status = _cairo_gl_composite_set_source (&setup, source, - glyph_extents->x, glyph_extents->y, + extents->bounded.x, + extents->bounded.y, dst_x, dst_y, - glyph_extents->width, - glyph_extents->height); + extents->bounded.width, + extents->bounded.height); if (unlikely (status)) goto FINISH; @@ -273,7 +275,8 @@ _render_glyphs (cairo_gl_surface_t *dst, cairo_list_add (&scaled_font->link, &ctx->fonts); } - _cairo_gl_composite_set_clip_region (&setup, clip_region); + _cairo_gl_composite_set_clip_region (&setup, + _cairo_clip_get_region (extents->clip)); for (i = 0; i < num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; @@ -374,35 +377,41 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst, const cairo_pattern_t *source, cairo_glyph_t *glyphs, int num_glyphs, - const cairo_rectangle_int_t *glyph_extents, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + cairo_composite_rectangles_t *extents, int *remaining_glyphs) { cairo_surface_t *mask; cairo_status_t status; cairo_bool_t has_component_alpha; + cairo_clip_t *saved_clip; int i; /* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */ mask = cairo_gl_surface_create (dst->base.device, CAIRO_CONTENT_COLOR_ALPHA, - glyph_extents->width, - glyph_extents->height); + extents->bounded.width, + extents->bounded.height); if (unlikely (mask->status)) return mask->status; for (i = 0; i < num_glyphs; i++) { - glyphs[i].x -= glyph_extents->x; - glyphs[i].y -= glyph_extents->y; + glyphs[i].x -= extents->bounded.x; + glyphs[i].y -= extents->bounded.y; } + + saved_clip = extents->clip; + extents->clip = NULL; status = _render_glyphs ((cairo_gl_surface_t *) mask, 0, 0, CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base, - glyphs, num_glyphs, glyph_extents, - scaled_font, &has_component_alpha, - NULL, remaining_glyphs); + glyphs, num_glyphs, scaled_font, + extents, + &has_component_alpha, + remaining_glyphs); + extents->clip = saved_clip; + if (likely (status == CAIRO_STATUS_SUCCESS)) { cairo_surface_pattern_t mask_pattern; @@ -410,14 +419,15 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst, _cairo_pattern_init_for_surface (&mask_pattern, mask); mask_pattern.base.has_component_alpha = has_component_alpha; cairo_matrix_init_translate (&mask_pattern.base.matrix, - -glyph_extents->x, -glyph_extents->y); + -extents->bounded.x, -extents->bounded.y); status = _cairo_surface_mask (&dst->base, op, - source, &mask_pattern.base, clip); + source, &mask_pattern.base, + extents->clip); _cairo_pattern_fini (&mask_pattern.base); } else { for (i = 0; i < num_glyphs; i++) { - glyphs[i].x += glyph_extents->x; - glyphs[i].y += glyph_extents->y; + glyphs[i].x += extents->bounded.x; + glyphs[i].y += extents->bounded.y; } *remaining_glyphs = num_glyphs; } @@ -434,13 +444,11 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs) { cairo_gl_surface_t *dst = abstract_dst; - cairo_rectangle_int_t surface_extents; - cairo_rectangle_int_t extents; - cairo_region_t *clip_region = NULL; + cairo_composite_rectangles_t extents; cairo_bool_t overlap, use_mask = FALSE; cairo_bool_t has_component_alpha; cairo_status_t status; @@ -526,60 +534,40 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst, if (! _cairo_gl_surface_owns_font (dst, scaled_font)) return UNSUPPORTED ("do not control font"); - /* If the glyphs overlap, we need to build an intermediate mask rather - * then perform the compositing directly. - */ - status = _cairo_scaled_font_glyph_device_extents (scaled_font, - glyphs, num_glyphs, - &extents, - &overlap); + status = _cairo_composite_rectangles_init_for_glyphs (&extents, + dst->width, + dst->height, + op, source, + scaled_font, + glyphs, num_glyphs, + clip, &overlap); if (unlikely (status)) return status; + /* If the glyphs overlap, we need to build an intermediate mask rather + * then perform the compositing directly. + */ use_mask |= overlap; - - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - /* the empty clip should never be propagated this far */ - assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO); - if (unlikely (_cairo_status_is_error (status))) - return status; - - use_mask |= status == CAIRO_INT_STATUS_UNSUPPORTED; - - if (! _cairo_rectangle_intersect (&extents, - _cairo_clip_get_extents (clip))) - goto EMPTY; - } - - surface_extents.x = surface_extents.y = 0; - surface_extents.width = dst->width; - surface_extents.height = dst->height; - if (! _cairo_rectangle_intersect (&extents, &surface_extents)) - goto EMPTY; + use_mask |= ! _cairo_clip_is_region (extents.clip); if (use_mask) { - return _cairo_gl_surface_show_glyphs_via_mask (dst, op, - source, - glyphs, num_glyphs, - &extents, - scaled_font, - clip, - remaining_glyphs); + status = _cairo_gl_surface_show_glyphs_via_mask (dst, op, + source, + glyphs, num_glyphs, + scaled_font, + &extents, + remaining_glyphs); + } else { + status = _render_glyphs (dst, extents.bounded.x, extents.bounded.y, + op, source, + glyphs, num_glyphs, scaled_font, + &extents, + &has_component_alpha, + remaining_glyphs); } - return _render_glyphs (dst, extents.x, extents.y, - op, source, - glyphs, num_glyphs, &extents, - scaled_font, &has_component_alpha, - clip_region, remaining_glyphs); - -EMPTY: - *remaining_glyphs = 0; - if (! _cairo_operator_bounded_by_mask (op)) - return _cairo_surface_paint (&dst->base, op, source, clip); - else - return CAIRO_STATUS_SUCCESS; + _cairo_composite_rectangles_fini (&extents); + return status; } void diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index edd1355a0..c83d78f25 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -501,7 +501,7 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs); static inline int diff --git a/src/cairo-gl-surface-legacy.c b/src/cairo-gl-surface-legacy.c new file mode 100644 index 000000000..0ba356e19 --- /dev/null +++ b/src/cairo-gl-surface-legacy.c @@ -0,0 +1,601 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Eric Anholt + * Copyright © 2009 Chris Wilson + * Copyright © 2005,2010 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Benjamin Otte <otte@gnome.org> + * Carl Worth <cworth@cworth.org> + * Chris Wilson <chris@chris-wilson.co.uk> + * Eric Anholt <eric@anholt.net> + */ + +#include "cairoint.h" + +#include "cairo-composite-rectangles-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-gl-private.h" + +cairo_status_t +_cairo_gl_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_int_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_int_t *image_rect_out, + void **image_extra) +{ + cairo_gl_surface_t *surface = abstract_surface; + cairo_int_status_t status; + + status = _cairo_gl_surface_deferred_clear (surface); + if (unlikely (status)) + return status; + + *image_extra = NULL; + return _cairo_gl_surface_get_image (surface, interest_rect, image_out, + image_rect_out); +} + +void +_cairo_gl_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_int_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_int_t *image_rect, + void *image_extra) +{ + cairo_status_t status; + + status = _cairo_gl_surface_draw_image (abstract_surface, image, + 0, 0, + image->width, image->height, + image_rect->x, image_rect->y); + /* as we created the image, its format should be directly applicable */ + assert (status == CAIRO_STATUS_SUCCESS); + + cairo_surface_destroy (&image->base); +} + +cairo_status_t +_cairo_gl_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + int src_x, + int src_y, + int width, + int height, + int *clone_offset_x, + int *clone_offset_y, + cairo_surface_t **clone_out) +{ + cairo_gl_surface_t *surface = abstract_surface; + cairo_int_status_t status; + + /* XXX: Use GLCopyTexImage2D to clone non-texture-surfaces */ + if (src->device == surface->base.device && + _cairo_gl_surface_is_texture ((cairo_gl_surface_t *) src)) { + status = _cairo_gl_surface_deferred_clear ((cairo_gl_surface_t *)src); + if (unlikely (status)) + return status; + + *clone_offset_x = 0; + *clone_offset_y = 0; + *clone_out = cairo_surface_reference (src); + + return CAIRO_STATUS_SUCCESS; + } else if (_cairo_surface_is_image (src)) { + cairo_image_surface_t *image_src = (cairo_image_surface_t *)src; + cairo_gl_surface_t *clone; + + clone = (cairo_gl_surface_t *) + _cairo_gl_surface_create_similar (&surface->base, + src->content, + width, height); + if (clone == NULL) + return UNSUPPORTED ("create_similar failed"); + if (clone->base.status) + return clone->base.status; + + status = _cairo_gl_surface_draw_image (clone, image_src, + src_x, src_y, + width, height, + 0, 0); + if (status) { + cairo_surface_destroy (&clone->base); + return status; + } + + *clone_out = &clone->base; + *clone_offset_x = src_x; + *clone_offset_y = src_y; + + return CAIRO_STATUS_SUCCESS; + } + + return UNSUPPORTED ("unknown src surface type in clone_similar"); +} + +/** Creates a cairo-gl pattern surface for the given trapezoids */ +static cairo_status_t +_cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst, + int dst_x, int dst_y, + int width, int height, + cairo_trapezoid_t *traps, + int num_traps, + cairo_antialias_t antialias, + cairo_surface_pattern_t *pattern) +{ + pixman_format_code_t pixman_format; + pixman_image_t *image; + cairo_surface_t *surface; + int i; + + pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1, + image = pixman_image_create_bits (pixman_format, width, height, NULL, 0); + if (unlikely (image == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + for (i = 0; i < num_traps; i++) { + pixman_trapezoid_t trap; + + trap.top = _cairo_fixed_to_16_16 (traps[i].top); + trap.bottom = _cairo_fixed_to_16_16 (traps[i].bottom); + + trap.left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x); + trap.left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y); + trap.left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x); + trap.left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y); + + trap.right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x); + trap.right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y); + trap.right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x); + trap.right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y); + + pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y); + } + + surface = _cairo_image_surface_create_for_pixman_image (image, + pixman_format); + if (unlikely (surface->status)) { + pixman_image_unref (image); + return surface->status; + } + + _cairo_pattern_init_for_surface (pattern, surface); + cairo_surface_destroy (surface); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_int_status_t +_cairo_gl_surface_composite (cairo_operator_t op, + const cairo_pattern_t *src, + const cairo_pattern_t *mask, + void *abstract_dst, + 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_region_t *clip_region) +{ + cairo_gl_surface_t *dst = abstract_dst; + cairo_gl_context_t *ctx; + cairo_status_t status; + cairo_gl_composite_t setup; + cairo_rectangle_int_t rect = { dst_x, dst_y, width, height }; + int dx, dy; + + status = _cairo_gl_surface_deferred_clear (dst); + if (unlikely (status)) + return status; + + if (op == CAIRO_OPERATOR_SOURCE && + mask == NULL && + src->type == CAIRO_PATTERN_TYPE_SURFACE && + _cairo_surface_is_image (((cairo_surface_pattern_t *) src)->surface) && + _cairo_matrix_is_integer_translation (&src->matrix, &dx, &dy)) { + cairo_image_surface_t *image = (cairo_image_surface_t *) + ((cairo_surface_pattern_t *) src)->surface; + dx += src_x; + dy += src_y; + if (dx >= 0 && + dy >= 0 && + dx + width <= (unsigned int) image->width && + dy + height <= (unsigned int) image->height) { + status = _cairo_gl_surface_draw_image (dst, image, + dx, dy, + width, height, + dst_x, dst_y); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + } + + status = _cairo_gl_composite_init (&setup, op, dst, + mask && mask->has_component_alpha, + &rect); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_gl_composite_set_source (&setup, src, + src_x, src_y, + dst_x, dst_y, + width, height); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_gl_composite_set_mask (&setup, mask, + mask_x, mask_y, + dst_x, dst_y, + width, height); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_gl_composite_begin (&setup, &ctx); + if (unlikely (status)) + goto CLEANUP; + + if (clip_region != NULL) { + int i, num_rectangles; + + num_rectangles = cairo_region_num_rectangles (clip_region); + + for (i = 0; i < num_rectangles; i++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (clip_region, i, &rect); + _cairo_gl_composite_emit_rect (ctx, + rect.x, rect.y, + rect.x + rect.width, rect.y + rect.height, + 0); + } + } else { + _cairo_gl_composite_emit_rect (ctx, + dst_x, dst_y, + dst_x + width, dst_y + height, + 0); + } + + status = _cairo_gl_context_release (ctx, status); + + CLEANUP: + _cairo_gl_composite_fini (&setup); + + return status; +} + +cairo_int_status_t +_cairo_gl_surface_composite_trapezoids (cairo_operator_t op, + const cairo_pattern_t *pattern, + void *abstract_dst, + cairo_antialias_t antialias, + int src_x, int src_y, + int dst_x, int dst_y, + unsigned int width, + unsigned int height, + cairo_trapezoid_t *traps, + int num_traps, + cairo_region_t *clip_region) +{ + cairo_gl_surface_t *dst = abstract_dst; + cairo_surface_pattern_t traps_pattern; + cairo_int_status_t status; + + if (! _cairo_gl_operator_is_supported (op)) + return UNSUPPORTED ("unsupported operator"); + + status = _cairo_gl_surface_deferred_clear (dst); + if (unlikely (status)) + return status; + + status = _cairo_gl_get_traps_pattern (dst, + dst_x, dst_y, width, height, + traps, num_traps, antialias, + &traps_pattern); + if (unlikely (status)) + return status; + + status = _cairo_gl_surface_composite (op, + pattern, &traps_pattern.base, dst, + src_x, src_y, + 0, 0, + dst_x, dst_y, + width, height, + clip_region); + + _cairo_pattern_fini (&traps_pattern.base); + + assert (status != CAIRO_INT_STATUS_UNSUPPORTED); + return status; +} + +cairo_int_status_t +_cairo_gl_surface_fill_rectangles (void *abstract_dst, + cairo_operator_t op, + const cairo_color_t *color, + cairo_rectangle_int_t *rects, + int num_rects) +{ + cairo_gl_surface_t *dst = abstract_dst; + cairo_solid_pattern_t solid; + cairo_gl_context_t *ctx; + cairo_status_t status; + cairo_gl_composite_t setup; + int i; + + status = _cairo_gl_surface_deferred_clear (dst); + if (unlikely (status)) + return status; + + status = _cairo_gl_composite_init (&setup, op, dst, + FALSE, + /* XXX */ NULL); + if (unlikely (status)) + goto CLEANUP; + + _cairo_pattern_init_solid (&solid, color); + status = _cairo_gl_composite_set_source (&setup, &solid.base, + 0, 0, + 0, 0, + 0, 0); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_gl_composite_set_mask (&setup, NULL, + 0, 0, + 0, 0, + 0, 0); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_gl_composite_begin (&setup, &ctx); + if (unlikely (status)) + goto CLEANUP; + + for (i = 0; i < num_rects; i++) { + _cairo_gl_composite_emit_rect (ctx, + rects[i].x, + rects[i].y, + rects[i].x + rects[i].width, + rects[i].y + rects[i].height, + 0); + } + + status = _cairo_gl_context_release (ctx, status); + + CLEANUP: + _cairo_gl_composite_fini (&setup); + + return status; +} + +typedef struct _cairo_gl_surface_span_renderer { + cairo_span_renderer_t base; + + cairo_gl_composite_t setup; + + int xmin, xmax; + int ymin, ymax; + + cairo_gl_context_t *ctx; +} cairo_gl_surface_span_renderer_t; + +static cairo_status_t +_cairo_gl_render_bounded_spans (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_gl_surface_span_renderer_t *renderer = abstract_renderer; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + do { + if (spans[0].coverage) { + _cairo_gl_composite_emit_rect (renderer->ctx, + spans[0].x, y, + spans[1].x, y + height, + spans[0].coverage); + } + + spans++; + } while (--num_spans > 1); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_gl_render_unbounded_spans (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_gl_surface_span_renderer_t *renderer = abstract_renderer; + + if (y > renderer->ymin) { + _cairo_gl_composite_emit_rect (renderer->ctx, + renderer->xmin, renderer->ymin, + renderer->xmax, y, + 0); + } + + if (num_spans == 0) { + _cairo_gl_composite_emit_rect (renderer->ctx, + renderer->xmin, y, + renderer->xmax, y + height, + 0); + } else { + if (spans[0].x != renderer->xmin) { + _cairo_gl_composite_emit_rect (renderer->ctx, + renderer->xmin, y, + spans[0].x, y + height, + 0); + } + + do { + _cairo_gl_composite_emit_rect (renderer->ctx, + spans[0].x, y, + spans[1].x, y + height, + spans[0].coverage); + spans++; + } while (--num_spans > 1); + + if (spans[0].x != renderer->xmax) { + _cairo_gl_composite_emit_rect (renderer->ctx, + spans[0].x, y, + renderer->xmax, y + height, + 0); + } + } + + renderer->ymin = y + height; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_gl_finish_unbounded_spans (void *abstract_renderer) +{ + cairo_gl_surface_span_renderer_t *renderer = abstract_renderer; + + if (renderer->ymax > renderer->ymin) { + _cairo_gl_composite_emit_rect (renderer->ctx, + renderer->xmin, renderer->ymin, + renderer->xmax, renderer->ymax, + 0); + } + + return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS); +} + +static cairo_status_t +_cairo_gl_finish_bounded_spans (void *abstract_renderer) +{ + cairo_gl_surface_span_renderer_t *renderer = abstract_renderer; + + return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS); +} + +static void +_cairo_gl_surface_span_renderer_destroy (void *abstract_renderer) +{ + cairo_gl_surface_span_renderer_t *renderer = abstract_renderer; + + if (!renderer) + return; + + _cairo_gl_composite_fini (&renderer->setup); + + free (renderer); +} + +cairo_bool_t +_cairo_gl_surface_check_span_renderer (cairo_operator_t op, + const cairo_pattern_t *pattern, + void *abstract_dst, + cairo_antialias_t antialias) +{ + if (! _cairo_gl_operator_is_supported (op)) + return FALSE; + + return TRUE; + + (void) pattern; + (void) abstract_dst; + (void) antialias; +} + +cairo_span_renderer_t * +_cairo_gl_surface_create_span_renderer (cairo_operator_t op, + const cairo_pattern_t *src, + void *abstract_dst, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects) +{ + cairo_gl_surface_t *dst = abstract_dst; + cairo_gl_surface_span_renderer_t *renderer; + cairo_status_t status; + const cairo_rectangle_int_t *extents; + + status = _cairo_gl_surface_deferred_clear (dst); + if (unlikely (status)) + return _cairo_span_renderer_create_in_error (status); + + renderer = calloc (1, sizeof (*renderer)); + if (unlikely (renderer == NULL)) + return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY); + + renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy; + if (rects->is_bounded) { + renderer->base.render_rows = _cairo_gl_render_bounded_spans; + renderer->base.finish = _cairo_gl_finish_bounded_spans; + extents = &rects->bounded; + } else { + renderer->base.render_rows = _cairo_gl_render_unbounded_spans; + renderer->base.finish = _cairo_gl_finish_unbounded_spans; + extents = &rects->unbounded; + } + renderer->xmin = extents->x; + renderer->xmax = extents->x + extents->width; + renderer->ymin = extents->y; + renderer->ymax = extents->y + extents->height; + + status = _cairo_gl_composite_init (&renderer->setup, + op, dst, + FALSE, extents); + if (unlikely (status)) + goto FAIL; + + status = _cairo_gl_composite_set_source (&renderer->setup, src, + extents->x, extents->y, + extents->x, extents->y, + extents->width, extents->height); + if (unlikely (status)) + goto FAIL; + + _cairo_gl_composite_set_spans (&renderer->setup); + _cairo_gl_composite_set_clip_region (&renderer->setup, + _cairo_clip_get_region (rects->clip)); + + status = _cairo_gl_composite_begin (&renderer->setup, &renderer->ctx); + if (unlikely (status)) + goto FAIL; + + return &renderer->base; + +FAIL: + _cairo_gl_composite_fini (&renderer->setup); + free (renderer); + return _cairo_span_renderer_create_in_error (status); +} + diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c index eb317f0b6..1b001b6ca 100644 --- a/src/cairo-gl-surface.c +++ b/src/cairo-gl-surface.c @@ -745,7 +745,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, cairo_image_surface_t *clone = NULL; cairo_gl_context_t *ctx; int cpp; - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; status = _cairo_gl_context_acquire (dst->base.device, &ctx); if (unlikely (status)) @@ -851,7 +851,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, } } else { cairo_surface_t *tmp; - + tmp = _cairo_gl_surface_create_scratch (ctx, dst->base.content, width, height); @@ -864,7 +864,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, src_x, src_y, width, height, 0, 0); - if (status == CAIRO_STATUS_SUCCESS) { + if (status == CAIRO_INT_STATUS_SUCCESS) { cairo_surface_pattern_t tmp_pattern; _cairo_pattern_init_for_surface (&tmp_pattern, tmp); @@ -1212,7 +1212,7 @@ _cairo_gl_surface_composite (cairo_operator_t op, { cairo_gl_surface_t *dst = abstract_dst; cairo_gl_context_t *ctx; - cairo_status_t status; + cairo_int_status_t status; cairo_gl_composite_t setup; cairo_rectangle_int_t rect = { dst_x, dst_y, width, height }; int dx, dy; @@ -1634,7 +1634,7 @@ static cairo_int_status_t _cairo_gl_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { /* simplify the common case of clearing the surface */ if (clip == NULL) { @@ -1658,22 +1658,12 @@ _cairo_gl_surface_polygon (cairo_gl_surface_t *dst, cairo_polygon_t *polygon, cairo_fill_rule_t fill_rule, cairo_antialias_t antialias, - const cairo_composite_rectangles_t *extents, - cairo_clip_t *clip) + const cairo_composite_rectangles_t *extents) { - cairo_status_t status; - cairo_region_t *clip_region = NULL; + cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip); - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) - return CAIRO_STATUS_SUCCESS; - if (unlikely (_cairo_status_is_error (status))) - return status; - - if (status == CAIRO_INT_STATUS_UNSUPPORTED) - return UNSUPPORTED ("a clip surface would be required"); - } + if (! _cairo_clip_is_region (extents->clip)) + return UNSUPPORTED ("a clip surface would be required"); if (! _cairo_surface_check_span_renderer (op, src, &dst->base, antialias)) return UNSUPPORTED ("no span renderer"); @@ -1685,35 +1675,30 @@ _cairo_gl_surface_polygon (cairo_gl_surface_t *dst, src = &_cairo_pattern_white.base; } - status = _cairo_surface_composite_polygon (&dst->base, - op, - src, - fill_rule, - antialias, - extents, - polygon, - clip_region); - return status; + return _cairo_surface_composite_polygon (&dst->base, + op, + src, + fill_rule, + antialias, + extents, + polygon, + clip_region); } static cairo_int_status_t _cairo_gl_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_gl_surface_t *surface = abstract_surface; cairo_composite_rectangles_t extents; - cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; - int num_boxes = ARRAY_LENGTH (boxes_stack); - cairo_clip_t local_clip; - cairo_bool_t have_clip = FALSE; cairo_polygon_t polygon; cairo_status_t status; @@ -1726,24 +1711,7 @@ _cairo_gl_surface_stroke (void *abstract_surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; - - if (clip != NULL) { - clip = _cairo_clip_init_copy (&local_clip, clip); - have_clip = TRUE; - } - - status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); - if (unlikely (status)) { - if (have_clip) - _cairo_clip_fini (&local_clip); - - return status; - } - - _cairo_polygon_init (&polygon, clip_boxes, num_boxes); - + _cairo_polygon_init_with_clip (&polygon, extents.clip); status = _cairo_path_fixed_stroke_to_polygon (path, style, ctm, ctm_inverse, @@ -1752,13 +1720,11 @@ _cairo_gl_surface_stroke (void *abstract_surface, if (likely (status == CAIRO_STATUS_SUCCESS)) { status = _cairo_gl_surface_polygon (surface, op, source, &polygon, CAIRO_FILL_RULE_WINDING, antialias, - &extents, clip); + &extents); } - _cairo_polygon_fini (&polygon); - if (have_clip) - _cairo_clip_fini (&local_clip); + _cairo_composite_rectangles_fini (&extents); return status; } @@ -1767,18 +1733,14 @@ static cairo_int_status_t _cairo_gl_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t*path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_gl_surface_t *surface = abstract_surface; cairo_composite_rectangles_t extents; - cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; - cairo_clip_t local_clip; - cairo_bool_t have_clip = FALSE; - int num_boxes = ARRAY_LENGTH (boxes_stack); cairo_polygon_t polygon; cairo_status_t status; @@ -1790,50 +1752,16 @@ _cairo_gl_surface_fill (void *abstract_surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; - -#if 0 - if (extents.is_bounded && clip != NULL) { - cairo_clip_path_t *clip_path; - - if (((clip_path = _clip_get_single_path (clip)) != NULL) && - _cairo_path_fixed_equal (&clip_path->path, path)) - { - clip = NULL; - } - } -#endif - - if (clip != NULL) { - clip = _cairo_clip_init_copy (&local_clip, clip); - have_clip = TRUE; - } - - status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); - if (unlikely (status)) { - if (have_clip) - _cairo_clip_fini (&local_clip); - - return status; - } - - _cairo_polygon_init (&polygon, clip_boxes, num_boxes); - + _cairo_polygon_init_with_clip (&polygon, extents.clip); status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); if (likely (status == CAIRO_STATUS_SUCCESS)) { status = _cairo_gl_surface_polygon (surface, op, source, &polygon, fill_rule, antialias, - &extents, clip); + &extents); } - _cairo_polygon_fini (&polygon); - if (clip_boxes != boxes_stack) - free (clip_boxes); - - if (have_clip) - _cairo_clip_fini (&local_clip); + _cairo_composite_rectangles_fini (&extents); return status; } diff --git a/src/cairo-gstate-private.h b/src/cairo-gstate-private.h index 9e823fa0f..38f11c7ad 100644 --- a/src/cairo-gstate-private.h +++ b/src/cairo-gstate-private.h @@ -55,7 +55,7 @@ struct _cairo_gstate { cairo_matrix_t font_matrix; cairo_font_options_t font_options; - cairo_clip_t clip; + cairo_clip_t *clip; cairo_surface_t *target; /* The target to which all rendering is directed */ cairo_surface_t *parent_target; /* The previous target which was receiving rendering */ diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index a7eced65a..b6252de2d 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -111,7 +111,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate, _cairo_font_options_init_default (&gstate->font_options); - _cairo_clip_init (&gstate->clip); + gstate->clip = NULL; gstate->target = cairo_surface_reference (target); gstate->parent_target = NULL; @@ -169,7 +169,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) _cairo_font_options_init_copy (&gstate->font_options , &other->font_options); - _cairo_clip_init_copy (&gstate->clip, &other->clip); + gstate->clip = _cairo_clip_copy (other->clip); gstate->target = cairo_surface_reference (other->target); /* parent_target is always set to NULL; it's only ever set by redirect_target */ @@ -206,7 +206,7 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) cairo_scaled_font_destroy (gstate->scaled_font); gstate->scaled_font = NULL; - _cairo_clip_reset (&gstate->clip); + _cairo_clip_destroy (gstate->clip); cairo_list_del (&gstate->device_transform_observer.link); @@ -300,8 +300,6 @@ _cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist) cairo_status_t _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child) { - cairo_matrix_t matrix; - /* If this gstate is already redirected, this is an error; we need a * new gstate to be able to redirect */ assert (gstate->parent_target == NULL); @@ -320,13 +318,11 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child) /* The clip is in surface backend coordinates for the previous target; * translate it into the child's backend coordinates. */ - cairo_matrix_init_translate (&matrix, - child->device_transform.x0 - gstate->parent_target->device_transform.x0, - child->device_transform.y0 - gstate->parent_target->device_transform.y0); - _cairo_clip_reset (&gstate->clip); - return _cairo_clip_init_copy_transformed (&gstate->clip, - &gstate->next->clip, - &matrix); + gstate->clip = _cairo_clip_copy_with_translation (gstate->next->clip, + child->device_transform.x0 - gstate->parent_target->device_transform.x0, + child->device_transform.y0 - gstate->parent_target->device_transform.y0); + + return CAIRO_STATUS_SUCCESS; } /** @@ -388,7 +384,7 @@ _cairo_gstate_get_original_target (cairo_gstate_t *gstate) cairo_clip_t * _cairo_gstate_get_clip (cairo_gstate_t *gstate) { - return &gstate->clip; + return gstate->clip; } cairo_status_t @@ -938,39 +934,6 @@ _cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate, &gstate->ctm_inverse); } -/* We need to take a copy of the clip so that the lower layers may modify it - * by, perhaps, intersecting it with the operation extents and other paths. - */ -#define _gstate_get_clip(G, C) _cairo_clip_init_copy ((C), &(G)->clip) - -static cairo_bool_t -_clipped (cairo_gstate_t *gstate) -{ - cairo_rectangle_int_t extents; - - if (gstate->clip.all_clipped) - return TRUE; - - /* XXX consider applying a surface clip? */ - - if (gstate->clip.path == NULL) - return FALSE; - - if (_cairo_surface_get_extents (gstate->target, &extents)) { - if (extents.width == 0 || extents.height == 0) - return TRUE; - - if (! _cairo_rectangle_intersect (&extents, - &gstate->clip.path->extents)) - { - return TRUE; - } - } - - /* perform a simple query to exclude trivial all-clipped cases */ - return _cairo_clip_get_region (&gstate->clip, NULL) == CAIRO_INT_STATUS_NOTHING_TO_DO; -} - static cairo_operator_t _reduce_op (cairo_gstate_t *gstate) { @@ -1029,7 +992,6 @@ _cairo_gstate_paint (cairo_gstate_t *gstate) { cairo_pattern_union_t source_pattern; const cairo_pattern_t *pattern; - cairo_clip_t clip; cairo_status_t status; cairo_operator_t op; @@ -1040,7 +1002,7 @@ _cairo_gstate_paint (cairo_gstate_t *gstate) if (gstate->op == CAIRO_OPERATOR_DEST) return CAIRO_STATUS_SUCCESS; - if (_clipped (gstate)) + if (_cairo_clip_is_all_clipped (gstate->clip)) return CAIRO_STATUS_SUCCESS; op = _reduce_op (gstate); @@ -1051,12 +1013,9 @@ _cairo_gstate_paint (cairo_gstate_t *gstate) pattern = &source_pattern.base; } - status = _cairo_surface_paint (gstate->target, - op, pattern, - _gstate_get_clip (gstate, &clip)); - _cairo_clip_fini (&clip); - - return status; + return _cairo_surface_paint (gstate->target, + op, pattern, + gstate->clip); } cairo_status_t @@ -1066,7 +1025,6 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, cairo_pattern_union_t source_pattern, mask_pattern; const cairo_pattern_t *source; cairo_operator_t op; - cairo_clip_t clip; cairo_status_t status; status = _cairo_gstate_get_pattern_status (mask); @@ -1080,7 +1038,7 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, if (gstate->op == CAIRO_OPERATOR_DEST) return CAIRO_STATUS_SUCCESS; - if (_clipped (gstate)) + if (_cairo_clip_is_all_clipped (gstate->clip)) return CAIRO_STATUS_SUCCESS; assert (gstate->opacity == 1.0); @@ -1126,16 +1084,15 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, status = _cairo_surface_paint (gstate->target, op, &source_pattern.base, - _gstate_get_clip (gstate, &clip)); + gstate->clip); } else { status = _cairo_surface_mask (gstate->target, op, source, &mask_pattern.base, - _gstate_get_clip (gstate, &clip)); + gstate->clip); } - _cairo_clip_fini (&clip); return status; } @@ -1146,7 +1103,6 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) cairo_pattern_union_t source_pattern; cairo_stroke_style_t style; double dash[2]; - cairo_clip_t clip; cairo_status_t status; status = _cairo_gstate_get_pattern_status (gstate->source); @@ -1159,7 +1115,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) if (gstate->stroke_style.line_width <= 0.0) return CAIRO_STATUS_SUCCESS; - if (_clipped (gstate)) + if (_cairo_clip_is_all_clipped (gstate->clip)) return CAIRO_STATUS_SUCCESS; assert (gstate->opacity == 1.0); @@ -1175,19 +1131,16 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); - status = _cairo_surface_stroke (gstate->target, - gstate->op, - &source_pattern.base, - path, - &style, - &gstate->ctm, - &gstate->ctm_inverse, - gstate->tolerance, - gstate->antialias, - _gstate_get_clip (gstate, &clip)); - _cairo_clip_fini (&clip); - - return status; + return _cairo_surface_stroke (gstate->target, + gstate->op, + &source_pattern.base, + path, + &style, + &gstate->ctm, + &gstate->ctm_inverse, + gstate->tolerance, + gstate->antialias, + gstate->clip); } cairo_status_t @@ -1251,7 +1204,6 @@ BAIL: cairo_status_t _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { - cairo_clip_t clip; cairo_status_t status; status = _cairo_gstate_get_pattern_status (gstate->source); @@ -1261,7 +1213,7 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) if (gstate->op == CAIRO_OPERATOR_DEST) return CAIRO_STATUS_SUCCESS; - if (_clipped (gstate)) + if (_cairo_clip_is_all_clipped (gstate->clip)) return CAIRO_STATUS_SUCCESS; assert (gstate->opacity == 1.0); @@ -1273,7 +1225,7 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) status = _cairo_surface_paint (gstate->target, CAIRO_OPERATOR_CLEAR, &_cairo_pattern_clear.base, - _gstate_get_clip (gstate, &clip)); + gstate->clip); } else { cairo_pattern_union_t source_pattern; const cairo_pattern_t *pattern; @@ -1298,7 +1250,7 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) box.p2.y >= _cairo_fixed_from_int (extents.y + extents.height)) { status = _cairo_surface_paint (gstate->target, op, pattern, - _gstate_get_clip (gstate, &clip)); + gstate->clip); } else { @@ -1307,12 +1259,10 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) gstate->fill_rule, gstate->tolerance, gstate->antialias, - _gstate_get_clip (gstate, &clip)); + gstate->clip); } } - _cairo_clip_fini (&clip); - return status; } @@ -1335,32 +1285,46 @@ _cairo_gstate_in_clip (cairo_gstate_t *gstate, double x, double y) { - cairo_clip_path_t *clip_path; + cairo_clip_t *clip = gstate->clip; + int i; - if (gstate->clip.all_clipped) + if (_cairo_clip_is_all_clipped (clip)) return FALSE; - clip_path = gstate->clip.path; - if (clip_path == NULL) - return TRUE; - _cairo_gstate_user_to_backend (gstate, &x, &y); - if (x < clip_path->extents.x || - x >= clip_path->extents.x + clip_path->extents.width || - y < clip_path->extents.y || - y >= clip_path->extents.y + clip_path->extents.height) + if (x < clip->extents.x || + x >= clip->extents.x + clip->extents.width || + y < clip->extents.y || + y >= clip->extents.y + clip->extents.height) { return FALSE; } - do { - if (! _cairo_path_fixed_in_fill (&clip_path->path, - clip_path->fill_rule, - clip_path->tolerance, - x, y)) + if (clip->num_boxes) { + int fx, fy; + + fx = _cairo_fixed_from_double (x); + fy = _cairo_fixed_from_double (y); + for (i = 0; i < clip->num_boxes; i++) { + if (fx >= clip->boxes[i].p1.x && fx <= clip->boxes[i].p2.x && + fy >= clip->boxes[i].p1.y && fy <= clip->boxes[i].p2.y) + break; + } + if (i == clip->num_boxes) return FALSE; - } while ((clip_path = clip_path->prev) != NULL); + } + + if (clip->path) { + cairo_clip_path_t *clip_path = clip->path; + do { + if (! _cairo_path_fixed_in_fill (&clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + x, y)) + return FALSE; + } while ((clip_path = clip_path->prev) != NULL); + } return TRUE; } @@ -1500,7 +1464,8 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate, cairo_status_t _cairo_gstate_reset_clip (cairo_gstate_t *gstate) { - _cairo_clip_reset (&gstate->clip); + _cairo_clip_destroy (gstate->clip); + gstate->clip = NULL; return CAIRO_STATUS_SUCCESS; } @@ -1508,23 +1473,27 @@ _cairo_gstate_reset_clip (cairo_gstate_t *gstate) cairo_status_t _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { - return _cairo_clip_clip (&gstate->clip, - path, gstate->fill_rule, - gstate->tolerance, gstate->antialias); + gstate->clip = + _cairo_clip_intersect_path (gstate->clip, + path, + gstate->fill_rule, + gstate->tolerance, + gstate->antialias); + /* XXX */ + return CAIRO_STATUS_SUCCESS; } static cairo_bool_t _cairo_gstate_int_clip_extents (cairo_gstate_t *gstate, cairo_rectangle_int_t *extents) { - const cairo_rectangle_int_t *clip_extents; cairo_bool_t is_bounded; is_bounded = _cairo_surface_get_extents (gstate->target, extents); - clip_extents = _cairo_clip_get_extents (&gstate->clip); - if (clip_extents != NULL) { - _cairo_rectangle_intersect (extents, clip_extents); + if (gstate->clip) { + _cairo_rectangle_intersect (extents, + _cairo_clip_get_extents (gstate->clip)); is_bounded = TRUE; } @@ -1568,23 +1537,19 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate, cairo_rectangle_list_t* _cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate) { - cairo_clip_t clip; cairo_rectangle_int_t extents; cairo_rectangle_list_t *list; - cairo_status_t status; - - _cairo_clip_init_copy (&clip, &gstate->clip); + cairo_clip_t *clip; if (_cairo_surface_get_extents (gstate->target, &extents)) - status = _cairo_clip_rectangle (&clip, &extents); + clip = _cairo_clip_copy_intersect_rectangle (gstate->clip, &extents); else - status = CAIRO_STATUS_SUCCESS; + clip = gstate->clip; - if (unlikely (status)) - return _cairo_rectangle_list_create_in_error (status); + list = _cairo_clip_copy_rectangle_list (clip, gstate); - list = _cairo_clip_copy_rectangle_list (&clip, gstate); - _cairo_clip_fini (&clip); + if (clip != gstate->clip) + _cairo_clip_destroy (clip); return list; } @@ -1875,7 +1840,6 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, cairo_text_cluster_t *transformed_clusters = NULL; cairo_operator_t op; cairo_status_t status; - cairo_clip_t clip; status = _cairo_gstate_get_pattern_status (gstate->source); if (unlikely (status)) @@ -1884,7 +1848,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, if (gstate->op == CAIRO_OPERATOR_DEST) return CAIRO_STATUS_SUCCESS; - if (_clipped (gstate)) + if (_cairo_clip_is_all_clipped (gstate->clip)) return CAIRO_STATUS_SUCCESS; status = _cairo_gstate_ensure_scaled_font (gstate); @@ -1958,14 +1922,14 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, transformed_clusters, info->num_clusters, info->cluster_flags, gstate->scaled_font, - _gstate_get_clip (gstate, &clip)); + gstate->clip); } else { status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern, NULL, 0, transformed_glyphs, num_glyphs, NULL, 0, 0, gstate->scaled_font, - _gstate_get_clip (gstate, &clip)); + gstate->clip); } } else @@ -1984,14 +1948,12 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, CAIRO_FILL_RULE_WINDING, gstate->tolerance, gstate->scaled_font->options.antialias, - _gstate_get_clip (gstate, &clip)); + gstate->clip); } _cairo_path_fixed_fini (&path); } - _cairo_clip_fini (&clip); - CLEANUP_GLYPHS: if (transformed_glyphs != stack_transformed_glyphs) cairo_glyph_free (transformed_glyphs); diff --git a/src/cairo-image-info.c b/src/cairo-image-info.c index 63201e65b..4489698e8 100644 --- a/src/cairo-image-info.c +++ b/src/cairo-image-info.c @@ -34,6 +34,8 @@ */ #include "cairoint.h" + +#include "cairo-error-private.h" #include "cairo-image-info-private.h" static uint32_t diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index be42724fe..d7e8b82b6 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -77,16 +77,6 @@ * @Since: 1.8 */ -static cairo_int_status_t -_cairo_image_surface_fill (void *dst, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - cairo_clip_t *clip); - static pixman_image_t * _pixman_image_for_solid (const cairo_solid_pattern_t *pattern); @@ -113,6 +103,7 @@ _cairo_format_from_pixman_format (pixman_format_code_t pixman_format) return CAIRO_FORMAT_A1; case PIXMAN_r5g6b5: return CAIRO_FORMAT_RGB16_565; + case PIXMAN_r8g8b8a8: case PIXMAN_r8g8b8x8: case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: case PIXMAN_r8g8b8: case PIXMAN_b8g8r8: case PIXMAN_b5g6r5: case PIXMAN_a1r5g5b5: case PIXMAN_x1r5g5b5: case PIXMAN_a1b5g5r5: @@ -181,6 +172,8 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, surface->stride = pixman_image_get_stride (pixman_image); surface->depth = pixman_image_get_depth (pixman_image); + surface->base.is_clear = width == 0 || height == 0; + return &surface->base; } @@ -1099,7 +1092,7 @@ _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern, cairo_circle_double_t extremes[2]; pixman_point_fixed_t p1, p2; unsigned int i; - cairo_status_t status; + cairo_int_status_t status; if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) { pixman_stops = _cairo_malloc_ab (pattern->n_stops, @@ -1150,7 +1143,7 @@ _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern, extents->y + extents->height/2., &pixman_transform, ix, iy); if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { - if (unlikely (status != CAIRO_STATUS_SUCCESS) || + if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) || ! pixman_image_set_transform (pixman_image, &pixman_transform)) { pixman_image_unref (pixman_image); @@ -1328,7 +1321,7 @@ _pixman_image_for_surface (const cairo_surface_pattern_t *pattern, cairo_rectangle_int_t sample; cairo_extend_t extend; cairo_filter_t filter; - cairo_status_t status; + cairo_int_status_t status; cairo_bool_t undo_src_transform = FALSE; extend = pattern->base.extend; @@ -1529,7 +1522,7 @@ _pixman_image_for_surface (const cairo_surface_pattern_t *pattern, * and we can use any filtering, so choose the fastest one. */ pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0); } - else if (unlikely (status != CAIRO_STATUS_SUCCESS || + else if (unlikely (status != CAIRO_INT_STATUS_SUCCESS || ! pixman_image_set_transform (pixman_image, &pixman_transform))) { @@ -1795,7 +1788,7 @@ _cairo_image_surface_fixup_unbounded_boxes (cairo_image_surface_t *dst, _cairo_boxes_init (&tmp); - status = _cairo_boxes_add (&tmp, &box); + status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box); assert (status == CAIRO_STATUS_SUCCESS); tmp.chunks.next = &boxes->chunks; @@ -1812,12 +1805,14 @@ _cairo_image_surface_fixup_unbounded_boxes (cairo_image_surface_t *dst, pbox = pixman_region32_rectangles (&clip_region->rgn, &i); _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i); - status = _cairo_boxes_add (&clear, &box); + status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box); assert (status == CAIRO_STATUS_SUCCESS); for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { for (i = 0; i < chunk->count; i++) { - status = _cairo_boxes_add (&clear, &chunk->base[i]); + status = _cairo_boxes_add (&clear, + CAIRO_ANTIALIAS_DEFAULT, + &chunk->base[i]); if (unlikely (status)) { _cairo_boxes_fini (&clear); return status; @@ -1885,7 +1880,7 @@ typedef cairo_status_t const cairo_pattern_t *src, int dst_x, int dst_y, - cairo_matrix_t *dst_device_transform, + cairo_matrix_t *dst_device_transform, const cairo_rectangle_int_t *extents, cairo_region_t *clip_region); @@ -1896,23 +1891,13 @@ _create_composite_mask_pattern (cairo_clip_t *clip, cairo_image_surface_t *dst, const cairo_rectangle_int_t *extents) { - cairo_region_t *clip_region = NULL; + cairo_region_t *clip_region = _cairo_clip_get_region (clip); + cairo_bool_t need_clip_surface = ! _cairo_clip_is_region (clip); pixman_image_t *mask; cairo_status_t status; - cairo_bool_t need_clip_surface = FALSE; - - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - assert (! _cairo_status_is_error (status)); - - /* The all-clipped state should never propagate this far. */ - assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO); - - need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; - if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1) - clip_region = NULL; - } + if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1) + clip_region = NULL; mask = pixman_image_create_bits (PIXMAN_a8, extents->width, extents->height, NULL, 0); @@ -1955,7 +1940,8 @@ _create_composite_mask_pattern (cairo_clip_t *clip, pixman_image_ref (mask); - status = _cairo_clip_combine_with_surface (clip, tmp, extents->x, extents->y); + status = _cairo_clip_combine_with_surface (clip, tmp, + extents->x, extents->y); cairo_surface_destroy (tmp); if (unlikely (status)) { pixman_image_unref (mask); @@ -2014,7 +2000,9 @@ _clip_and_composite_with_mask (cairo_clip_t *clip, pixman_image_t *src; int src_x, src_y; - src = _pixman_image_for_pattern (pattern, FALSE, extents, &dst->base.device_transform, &src_x, &src_y); + src = _pixman_image_for_pattern (pattern, FALSE, extents, + &dst->base.device_transform, + &src_x, &src_y); if (unlikely (src == NULL)) { pixman_image_unref (mask); return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -2085,7 +2073,6 @@ _clip_and_composite_combine (cairo_clip_t *clip, if (unlikely (status)) goto CLEANUP_SURFACE; - assert (clip->path != NULL); clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y); if (unlikely (clip_surface->status)) goto CLEANUP_SURFACE; @@ -2156,7 +2143,6 @@ _clip_and_composite_source (cairo_clip_t *clip, int src_x, src_y; if (pattern == NULL) { - cairo_region_t *clip_region; cairo_status_t status; status = draw_func (draw_closure, @@ -2168,7 +2154,7 @@ _clip_and_composite_source (cairo_clip_t *clip, if (unlikely (status)) return status; - if (_cairo_clip_get_region (clip, &clip_region) == CAIRO_INT_STATUS_UNSUPPORTED) + if (! _cairo_clip_is_region (clip)) status = _cairo_clip_combine_with_surface (clip, &dst->base, 0, 0); return status; @@ -2179,7 +2165,9 @@ _clip_and_composite_source (cairo_clip_t *clip, if (unlikely (mask == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - src = _pixman_image_for_pattern (pattern, FALSE, extents, &dst->base.device_transform, &src_x, &src_y); + src = _pixman_image_for_pattern (pattern, FALSE, extents, + &dst->base.device_transform, + &src_x, &src_y); if (unlikely (src == NULL)) { pixman_image_unref (mask); return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -2230,39 +2218,14 @@ _clip_and_composite (cairo_image_surface_t *dst, const cairo_pattern_t *src, image_draw_func_t draw_func, void *draw_closure, - cairo_composite_rectangles_t*extents, - cairo_clip_t *clip) + cairo_composite_rectangles_t*extents) { + cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip); + cairo_bool_t need_clip_surface = ! _cairo_clip_is_region (extents->clip); cairo_status_t status; - cairo_region_t *clip_region = NULL; - cairo_bool_t need_clip_surface = FALSE; - - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) - return CAIRO_STATUS_SUCCESS; - if (unlikely (_cairo_status_is_error (status))) - return status; - - need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; - - if (clip_region != NULL) { - cairo_rectangle_int_t rect; - cairo_bool_t is_empty; - - cairo_region_get_extents (clip_region, &rect); - is_empty = ! _cairo_rectangle_intersect (&extents->unbounded, &rect); - if (unlikely (is_empty)) - return CAIRO_STATUS_SUCCESS; - is_empty = ! _cairo_rectangle_intersect (&extents->bounded, &rect); - if (unlikely (is_empty && extents->is_bounded)) - return CAIRO_STATUS_SUCCESS; - - if (cairo_region_num_rectangles (clip_region) == 1) - clip_region = NULL; - } - } + if (cairo_region_num_rectangles (clip_region) == 1) + clip_region = NULL; if (clip_region != NULL) { status = _cairo_image_surface_set_clip_region (dst, clip_region); @@ -2276,7 +2239,7 @@ _clip_and_composite (cairo_image_surface_t *dst, } if (op == CAIRO_OPERATOR_SOURCE) { - status = _clip_and_composite_source (clip, src, + status = _clip_and_composite_source (extents->clip, src, draw_func, draw_closure, dst, &extents->bounded); } else { @@ -2287,11 +2250,11 @@ _clip_and_composite (cairo_image_surface_t *dst, if (need_clip_surface) { if (extents->is_bounded) { - status = _clip_and_composite_with_mask (clip, op, src, + status = _clip_and_composite_with_mask (extents->clip, op, src, draw_func, draw_closure, dst, &extents->bounded); } else { - status = _clip_and_composite_combine (clip, op, src, + status = _clip_and_composite_combine (extents->clip, op, src, draw_func, draw_closure, dst, &extents->bounded); } @@ -2308,7 +2271,7 @@ _clip_and_composite (cairo_image_surface_t *dst, if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) { status = _cairo_image_surface_fixup_unbounded (dst, extents, - need_clip_surface ? clip : NULL); + need_clip_surface ? extents->clip : NULL); } if (clip_region != NULL) @@ -2444,7 +2407,9 @@ _composite_traps (void *closure, return CAIRO_STATUS_SUCCESS; } - src = _pixman_image_for_pattern (pattern, FALSE, extents, dst_device_transform, &src_x, &src_y); + src = _pixman_image_for_pattern (pattern, FALSE, extents, + dst_device_transform, + &src_x, &src_y); if (unlikely (src == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -2856,7 +2821,9 @@ _composite_unaligned_boxes (cairo_image_surface_t *dst, if (unlikely (status)) goto CLEANUP; - src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &dst->base.device_transform, &src_x, &src_y); + src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, + &dst->base.device_transform, + &src_x, &src_y); if (unlikely (src == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP; @@ -2882,44 +2849,36 @@ _composite_boxes (cairo_image_surface_t *dst, cairo_operator_t op, const cairo_pattern_t *pattern, cairo_boxes_t *boxes, - cairo_antialias_t antialias, - cairo_clip_t *clip, const cairo_composite_rectangles_t *extents) { - cairo_region_t *clip_region = NULL; - cairo_bool_t need_clip_mask = FALSE; + cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip); + cairo_bool_t need_clip_mask = extents->clip->path != NULL; cairo_status_t status; struct _cairo_boxes_chunk *chunk; uint32_t pixel; int i; - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - need_clip_mask = status == CAIRO_INT_STATUS_UNSUPPORTED; - if (need_clip_mask && - (op == CAIRO_OPERATOR_SOURCE || ! extents->is_bounded)) - { - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1) - clip_region = NULL; + if (need_clip_mask && + (op == CAIRO_OPERATOR_SOURCE || ! extents->is_bounded)) + { + return CAIRO_INT_STATUS_UNSUPPORTED; } - if (antialias != CAIRO_ANTIALIAS_NONE) { - if (! boxes->is_pixel_aligned) { - if (need_clip_mask) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1) + clip_region = NULL; - if (pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, - dst->pixman_format, &pixel)) - { - return _fill_unaligned_boxes (dst, pattern, pixel, boxes, extents); - } - else - { - return _composite_unaligned_boxes (dst, op, pattern, boxes, extents); - } + if (! boxes->is_pixel_aligned) { + if (need_clip_mask) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, + dst->pixman_format, &pixel)) + { + return _fill_unaligned_boxes (dst, pattern, pixel, boxes, extents); + } + else + { + return _composite_unaligned_boxes (dst, op, pattern, boxes, extents); } } @@ -2957,7 +2916,9 @@ _composite_boxes (cairo_image_surface_t *dst, cairo_surface_t *clip_surface; int clip_x, clip_y; - clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y); + clip_surface = _cairo_clip_get_surface (extents->clip, + &dst->base, + &clip_x, &clip_y); if (unlikely (clip_surface->status)) return clip_surface->status; @@ -2970,10 +2931,14 @@ _composite_boxes (cairo_image_surface_t *dst, } mask = ((cairo_image_surface_t *) clip_surface)->pixman_image; + pixman_image_ref (mask); + cairo_surface_destroy (clip_surface); } if (pattern != NULL) { - src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &dst->base.device_transform, &src_x, &src_y); + src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, + &dst->base.device_transform, + &src_x, &src_y); if (unlikely (src == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } else { @@ -3022,19 +2987,17 @@ _clip_and_composite_boxes (cairo_image_surface_t *dst, cairo_operator_t op, const cairo_pattern_t *src, cairo_boxes_t *boxes, - cairo_antialias_t antialias, - cairo_composite_rectangles_t *extents, - cairo_clip_t *clip) + cairo_composite_rectangles_t *extents) { cairo_traps_t traps; - cairo_status_t status; + cairo_int_status_t status; composite_traps_info_t info; if (boxes->num_boxes == 0 && extents->is_bounded) return CAIRO_STATUS_SUCCESS; /* Use a fast path if the boxes are pixel aligned */ - status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents); + status = _composite_boxes (dst, op, src, boxes, extents); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; @@ -3045,10 +3008,10 @@ _clip_and_composite_boxes (cairo_image_surface_t *dst, info.num_traps = traps.num_traps; info.traps = traps.traps; - info.antialias = antialias; + info.antialias = CAIRO_ANTIALIAS_DEFAULT; status = _clip_and_composite (dst, op, src, _composite_traps, &info, - extents, clip); + extents); _cairo_traps_fini (&traps); return status; @@ -3151,8 +3114,7 @@ _clip_and_composite_trapezoids (cairo_image_surface_t *dst, const cairo_pattern_t *src, cairo_traps_t *traps, cairo_antialias_t antialias, - cairo_composite_rectangles_t *extents, - cairo_clip_t *clip) + cairo_composite_rectangles_t *extents) { composite_traps_info_t info; cairo_bool_t need_clip_surface = FALSE; @@ -3161,12 +3123,7 @@ _clip_and_composite_trapezoids (cairo_image_surface_t *dst, if (traps->num_traps == 0 && extents->is_bounded) return CAIRO_STATUS_SUCCESS; - if (clip != NULL) { - cairo_region_t *clip_region; - - status = _cairo_clip_get_region (clip, &clip_region); - need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; - } + need_clip_surface = ! _cairo_clip_is_region (extents->clip); if (traps->has_intersections) { if (traps->is_rectangular) @@ -3191,8 +3148,7 @@ _clip_and_composite_trapezoids (cairo_image_surface_t *dst, _boxes_for_traps (&boxes, traps, antialias); return _clip_and_composite_boxes (dst, op, src, - &boxes, antialias, - extents, clip); + &boxes, extents); } /* No fast path, exclude self-intersections and clip trapezoids. */ @@ -3204,27 +3160,7 @@ _clip_and_composite_trapezoids (cairo_image_surface_t *dst, info.antialias = antialias; return _clip_and_composite (dst, op, src, _composite_traps, &info, - extents, clip); -} - -static cairo_clip_path_t * -_clip_get_single_path (cairo_clip_t *clip) -{ - cairo_clip_path_t *iter = clip->path; - cairo_clip_path_t *path = NULL; - - /* Boxes only effect the extents, so discard any outer boxes. */ - do { - if (path != NULL) - return FALSE; - - if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) - path = iter; - - iter = iter->prev; - } while (iter != NULL); - - return path; + extents); } /* high level image interface */ @@ -3233,16 +3169,12 @@ static cairo_int_status_t _cairo_image_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_image_surface_t *surface = abstract_surface; cairo_composite_rectangles_t extents; - cairo_clip_path_t *clip_path; - cairo_clip_t local_clip; - cairo_bool_t have_clip = FALSE; - cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; - int num_boxes = ARRAY_LENGTH (boxes_stack); cairo_status_t status; + cairo_boxes_t boxes; status = _cairo_composite_rectangles_init_for_paint (&extents, surface->width, @@ -3252,53 +3184,20 @@ _cairo_image_surface_paint (void *abstract_surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; - - if (clip != NULL) { - clip = _cairo_clip_init_copy (&local_clip, clip); - have_clip = TRUE; - } - - status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); - if (unlikely (status)) { - if (have_clip) - _cairo_clip_fini (&local_clip); - - return status; - } - /* If the clip cannot be reduced to a set of boxes, we will need to * use a clipmask. Paint is special as it is the only operation that * does not implicitly use a mask, so we may be able to reduce this * operation to a fill... */ - if (clip != NULL && - extents.is_bounded && - (clip_path = _clip_get_single_path (clip)) != NULL) - { - status = _cairo_image_surface_fill (surface, op, source, - &clip_path->path, - clip_path->fill_rule, - clip_path->tolerance, - clip_path->antialias, - NULL); - } - else - { - cairo_boxes_t boxes; - _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes); + status = _cairo_clip_to_boxes (extents.clip, &boxes); + if (likely (status == CAIRO_STATUS_SUCCESS)) { status = _clip_and_composite_boxes (surface, op, source, - &boxes, CAIRO_ANTIALIAS_DEFAULT, - &extents, clip); + &boxes, &extents); + _cairo_boxes_fini (&boxes); } - if (clip_boxes != boxes_stack) - free (clip_boxes); - - if (have_clip) - _cairo_clip_fini (&local_clip); + _cairo_composite_rectangles_fini (&extents); return status; } @@ -3311,7 +3210,7 @@ _composite_mask (void *closure, const cairo_pattern_t *src_pattern, int dst_x, int dst_y, - cairo_matrix_t *dst_device_transform, + cairo_matrix_t *dst_device_transform, const cairo_rectangle_int_t *extents, cairo_region_t *clip_region) { @@ -3321,11 +3220,15 @@ _composite_mask (void *closure, int mask_x = 0, mask_y = 0; if (src_pattern != NULL) { - src = _pixman_image_for_pattern (src_pattern, FALSE, extents, dst_device_transform, &src_x, &src_y); + src = _pixman_image_for_pattern (src_pattern, FALSE, extents, + dst_device_transform, + &src_x, &src_y); if (unlikely (src == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - mask = _pixman_image_for_pattern (mask_pattern, TRUE, extents, dst_device_transform, &mask_x, &mask_y); + mask = _pixman_image_for_pattern (mask_pattern, TRUE, extents, + dst_device_transform, + &mask_x, &mask_y); if (unlikely (mask == NULL)) { pixman_image_unref (src); return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -3334,7 +3237,9 @@ _composite_mask (void *closure, if (mask_pattern->has_component_alpha) pixman_image_set_component_alpha (mask, TRUE); } else { - src = _pixman_image_for_pattern (mask_pattern, FALSE, extents, dst_device_transform, &src_x, &src_y); + src = _pixman_image_for_pattern (mask_pattern, FALSE, extents, + dst_device_transform, + &src_x, &src_y); if (unlikely (src == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -3357,12 +3262,10 @@ _cairo_image_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_image_surface_t *surface = abstract_surface; cairo_composite_rectangles_t extents; - cairo_clip_t local_clip; - cairo_bool_t have_clip = FALSE; cairo_status_t status; status = _cairo_composite_rectangles_init_for_mask (&extents, @@ -3371,26 +3274,11 @@ _cairo_image_surface_mask (void *abstract_surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; - - if (clip != NULL && extents.is_bounded) { - clip = _cairo_clip_init_copy (&local_clip, clip); - status = _cairo_clip_rectangle (clip, &extents.bounded); - if (unlikely (status)) { - _cairo_clip_fini (&local_clip); - return status; - } - - have_clip = TRUE; - } - status = _clip_and_composite (surface, op, source, _composite_mask, (void *) mask, - &extents, clip); + &extents); - if (have_clip) - _cairo_clip_fini (&local_clip); + _cairo_composite_rectangles_fini (&extents); return status; } @@ -3410,7 +3298,7 @@ _composite_spans (void *closure, const cairo_pattern_t *pattern, int dst_x, int dst_y, - cairo_matrix_t *dst_device_transform, + cairo_matrix_t *dst_device_transform, const cairo_rectangle_int_t *extents, cairo_region_t *clip_region) { @@ -3494,7 +3382,9 @@ _composite_spans (void *closure, pixman_image_t *src; int src_x, src_y; - src = _pixman_image_for_pattern (pattern, FALSE, extents, dst_device_transform, &src_x, &src_y); + src = _pixman_image_for_pattern (pattern, FALSE, extents, + dst_device_transform, + &src_x, &src_y); if (unlikely (src == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_RENDERER; @@ -3527,8 +3417,7 @@ _clip_and_composite_polygon (cairo_image_surface_t *dst, cairo_polygon_t *polygon, cairo_fill_rule_t fill_rule, cairo_antialias_t antialias, - cairo_composite_rectangles_t *extents, - cairo_clip_t *clip) + cairo_composite_rectangles_t *extents) { cairo_status_t status; @@ -3541,7 +3430,7 @@ _clip_and_composite_polygon (cairo_image_surface_t *dst, _cairo_traps_init (&traps); status = _clip_and_composite_trapezoids (dst, op, src, &traps, antialias, - extents, clip); + extents); _cairo_traps_fini (&traps); return status; @@ -3560,7 +3449,7 @@ _clip_and_composite_polygon (cairo_image_surface_t *dst, status = _clip_and_composite (dst, op, src, _composite_spans, &info, - extents, clip); + extents); } else { cairo_traps_t traps; @@ -3573,7 +3462,7 @@ _clip_and_composite_polygon (cairo_image_surface_t *dst, if (likely (status == CAIRO_STATUS_SUCCESS)) { status = _clip_and_composite_trapezoids (dst, op, src, &traps, antialias, - extents, clip); + extents); } _cairo_traps_fini (&traps); @@ -3586,21 +3475,17 @@ static cairo_int_status_t _cairo_image_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_image_surface_t *surface = abstract_surface; cairo_composite_rectangles_t extents; - cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; - int num_boxes = ARRAY_LENGTH (boxes_stack); - cairo_clip_t local_clip; - cairo_bool_t have_clip = FALSE; - cairo_status_t status; + cairo_int_status_t status; status = _cairo_composite_rectangles_init_for_stroke (&extents, surface->width, @@ -3611,80 +3496,42 @@ _cairo_image_surface_stroke (void *abstract_surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; - - if (clip != NULL) { - clip = _cairo_clip_init_copy (&local_clip, clip); - have_clip = TRUE; - } - - status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); - if (unlikely (status)) { - if (have_clip) - _cairo_clip_fini (&local_clip); - - return status; - } - status = CAIRO_INT_STATUS_UNSUPPORTED; if (_cairo_path_fixed_stroke_is_rectilinear (path)) { cairo_boxes_t boxes; - _cairo_boxes_init (&boxes); - if (num_boxes == 0) { - /* When compositing with the span renderer, we limit the mask - * to the bounded area, and so we must also constrain the path - * appropriately. (Unlike the other compositing paths - * where the operation itself is limited to extents.) - */ - boxes_stack[0].p1.x = extents.bounded.x; - boxes_stack[0].p1.y = extents.bounded.y; - boxes_stack[0].p2.x = extents.bounded.x + extents.bounded.width; - boxes_stack[0].p2.y = extents.bounded.y + extents.bounded.height; - - clip_boxes = boxes_stack; - num_boxes = 1; - } - _cairo_boxes_limit (&boxes, clip_boxes, num_boxes); - + _cairo_boxes_init_with_clip (&boxes, extents.clip); status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, style, ctm, + antialias, &boxes); - if (likely (status == CAIRO_STATUS_SUCCESS)) { + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { status = _clip_and_composite_boxes (surface, op, source, - &boxes, antialias, - &extents, clip); + &boxes, &extents); } - _cairo_boxes_fini (&boxes); } if (status == CAIRO_INT_STATUS_UNSUPPORTED) { cairo_polygon_t polygon; - _cairo_polygon_init (&polygon, clip_boxes, num_boxes); - + _cairo_polygon_init_with_clip (&polygon, extents.clip); status = _cairo_path_fixed_stroke_to_polygon (path, style, ctm, ctm_inverse, tolerance, &polygon); - if (likely (status == CAIRO_STATUS_SUCCESS)) { + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { status = _clip_and_composite_polygon (surface, op, source, &polygon, - CAIRO_FILL_RULE_WINDING, antialias, - &extents, clip); + CAIRO_FILL_RULE_WINDING, + antialias, + &extents); } - _cairo_polygon_fini (&polygon); } - if (clip_boxes != boxes_stack) - free (clip_boxes); - - if (have_clip) - _cairo_clip_fini (&local_clip); + _cairo_composite_rectangles_fini (&extents); return status; } @@ -3693,18 +3540,14 @@ static cairo_int_status_t _cairo_image_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_image_surface_t *surface = abstract_surface; cairo_composite_rectangles_t extents; - cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; - cairo_clip_t local_clip; - cairo_bool_t have_clip = FALSE; - int num_boxes = ARRAY_LENGTH (boxes_stack); cairo_status_t status; status = _cairo_composite_rectangles_init_for_fill (&extents, @@ -3715,84 +3558,35 @@ _cairo_image_surface_fill (void *abstract_surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; - - if (extents.is_bounded && clip != NULL) { - cairo_clip_path_t *clip_path; - - if (((clip_path = _clip_get_single_path (clip)) != NULL) && - _cairo_path_fixed_equal (&clip_path->path, path)) - { - clip = NULL; - } - } - - if (clip != NULL) { - clip = _cairo_clip_init_copy (&local_clip, clip); - have_clip = TRUE; - } - - status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); - if (unlikely (status)) { - if (have_clip) - _cairo_clip_fini (&local_clip); - - return status; - } - if (_cairo_path_fixed_fill_is_rectilinear (path)) { cairo_boxes_t boxes; - _cairo_boxes_init (&boxes); - if (num_boxes == 0) { - /* When compositing with the span renderer, we limit the mask - * to the bounded area, and so we must also constrain the path - * appropriately. (Unlike the other compositing paths - * where the operation itself is limited to extents.) - */ - boxes_stack[0].p1.x = extents.bounded.x; - boxes_stack[0].p1.y = extents.bounded.y; - boxes_stack[0].p2.x = extents.bounded.x + extents.bounded.width; - boxes_stack[0].p2.y = extents.bounded.y + extents.bounded.height; - - clip_boxes = boxes_stack; - num_boxes = 1; - } - _cairo_boxes_limit (&boxes, clip_boxes, num_boxes); - + _cairo_boxes_init_with_clip (&boxes, extents.clip); status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, fill_rule, + antialias, &boxes); if (likely (status == CAIRO_STATUS_SUCCESS)) { status = _clip_and_composite_boxes (surface, op, source, - &boxes, antialias, - &extents, clip); + &boxes, &extents); } - _cairo_boxes_fini (&boxes); } else { cairo_polygon_t polygon; assert (! _cairo_path_fixed_fill_is_empty (path)); - _cairo_polygon_init (&polygon, clip_boxes, num_boxes); - + _cairo_polygon_init_with_clip (&polygon, extents.clip); status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); if (likely (status == CAIRO_STATUS_SUCCESS)) { status = _clip_and_composite_polygon (surface, op, source, &polygon, fill_rule, antialias, - &extents, clip); + &extents); } - _cairo_polygon_fini (&polygon); } - if (clip_boxes != boxes_stack) - free (clip_boxes); - - if (have_clip) - _cairo_clip_fini (&local_clip); + _cairo_composite_rectangles_fini (&extents); return status; } @@ -3811,7 +3605,7 @@ _composite_glyphs_via_mask (void *closure, const cairo_pattern_t *pattern, int dst_x, int dst_y, - cairo_matrix_t *dst_device_transform, + cairo_matrix_t *dst_device_transform, const cairo_rectangle_int_t *extents, cairo_region_t *clip_region) { @@ -3827,7 +3621,9 @@ _composite_glyphs_via_mask (void *closure, int src_x, src_y; int i; - src = _pixman_image_for_pattern (pattern, FALSE, extents, dst_device_transform, &src_x, &src_y); + src = _pixman_image_for_pattern (pattern, FALSE, extents, + dst_device_transform, + &src_x, &src_y); if (unlikely (src == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -3961,7 +3757,9 @@ _composite_glyphs (void *closure, int i; if (pattern != NULL) { - src = _pixman_image_for_pattern (pattern, FALSE, extents, dst_device_transform, &src_x, &src_y); + src = _pixman_image_for_pattern (pattern, FALSE, extents, + dst_device_transform, + &src_x, &src_y); src_x -= dst_x; src_y -= dst_y; } else { @@ -4042,16 +3840,14 @@ _cairo_image_surface_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *num_remaining) { cairo_image_surface_t *surface = abstract_surface; cairo_composite_rectangles_t extents; composite_glyphs_info_t glyph_info; - cairo_clip_t local_clip; - cairo_bool_t have_clip = FALSE; - cairo_bool_t overlap; cairo_status_t status; + cairo_bool_t overlap; status = _cairo_composite_rectangles_init_for_glyphs (&extents, surface->width, @@ -4064,20 +3860,6 @@ _cairo_image_surface_glyphs (void *abstract_surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_rectangle (clip, &extents.mask)) - clip = NULL; - - if (clip != NULL && extents.is_bounded) { - clip = _cairo_clip_init_copy (&local_clip, clip); - status = _cairo_clip_rectangle (clip, &extents.bounded); - if (unlikely (status)) { - _cairo_clip_fini (&local_clip); - return status; - } - - have_clip = TRUE; - } - glyph_info.font = scaled_font; glyph_info.glyphs = glyphs; glyph_info.num_glyphs = num_glyphs; @@ -4085,10 +3867,9 @@ _cairo_image_surface_glyphs (void *abstract_surface, status = _clip_and_composite (surface, op, source, overlap || extents.is_bounded == 0 ? _composite_glyphs_via_mask : _composite_glyphs, &glyph_info, - &extents, clip); + &extents); - if (have_clip) - _cairo_clip_fini (&local_clip); + _cairo_composite_rectangles_fini (&extents); *num_remaining = 0; return status; @@ -4228,7 +4009,9 @@ _cairo_image_surface_composite (cairo_operator_t op, extents.is_bounded = _cairo_operator_bounded_by_either (op); - src = _pixman_image_for_pattern (src_pattern, FALSE, &extents.source, &dst->base.device_transform, &src_offset_x, &src_offset_y); + src = _pixman_image_for_pattern (src_pattern, FALSE, &extents.source, + &dst->base.device_transform, + &src_offset_x, &src_offset_y); if (unlikely (src == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -4237,7 +4020,9 @@ _cairo_image_surface_composite (cairo_operator_t op, pixman_image_t *mask; int mask_offset_x, mask_offset_y; - mask = _pixman_image_for_pattern (mask_pattern, TRUE, &extents.mask, &dst->base.device_transform, &mask_offset_x, &mask_offset_y); + mask = _pixman_image_for_pattern (mask_pattern, TRUE, &extents.mask, + &dst->base.device_transform, + &mask_offset_x, &mask_offset_y); if (unlikely (mask == NULL)) { pixman_image_unref (src); return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -4507,7 +4292,9 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer) return status; } - src = _pixman_image_for_pattern (renderer->pattern, FALSE, &rects->bounded, &renderer->dst->base.device_transform, &src_x, &src_y); + src = _pixman_image_for_pattern (renderer->pattern, FALSE, &rects->bounded, + &renderer->dst->base.device_transform, + &src_x, &src_y); if (src == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); diff --git a/src/cairo-misc.c b/src/cairo-misc.c index 926d3aabf..c04fe1125 100644 --- a/src/cairo-misc.c +++ b/src/cairo-misc.c @@ -41,7 +41,7 @@ #include "cairoint.h" #include "cairo-error-private.h" -COMPILE_TIME_ASSERT (CAIRO_STATUS_LAST_STATUS < CAIRO_INT_STATUS_UNSUPPORTED); +COMPILE_TIME_ASSERT ((int)CAIRO_STATUS_LAST_STATUS < (int)CAIRO_INT_STATUS_UNSUPPORTED); COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127); /** diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c index 74c8468e2..e87612711 100644 --- a/src/cairo-paginated-surface.c +++ b/src/cairo-paginated-surface.c @@ -279,7 +279,7 @@ _paint_fallback_image (cairo_paginated_surface_t *surface, cairo_status_t status; cairo_surface_t *image; cairo_surface_pattern_t pattern; - cairo_clip_t clip; + cairo_clip_t *clip; x = rect->x; y = rect->y; @@ -304,15 +304,14 @@ _paint_fallback_image (cairo_paginated_surface_t *surface, * filtering (if possible) to avoid introducing potential artifacts. */ pattern.base.filter = CAIRO_FILTER_NEAREST; - _cairo_clip_init (&clip); - status = _cairo_clip_rectangle (&clip, rect); + clip = _cairo_clip_intersect_rectangle (NULL, rect); if (likely (status == CAIRO_STATUS_SUCCESS)) { status = _cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, - &pattern.base, &clip); + &pattern.base, clip); } - _cairo_clip_fini (&clip); + _cairo_clip_destroy (clip); _cairo_pattern_fini (&pattern.base); CLEANUP_IMAGE: @@ -325,7 +324,7 @@ static cairo_int_status_t _paint_page (cairo_paginated_surface_t *surface) { cairo_surface_t *analysis; - cairo_status_t status; + cairo_int_status_t status; cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback; if (unlikely (surface->target->status)) @@ -340,7 +339,7 @@ _paint_page (cairo_paginated_surface_t *surface) status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface, analysis); if (status || analysis->status) { - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) status = analysis->status; goto FAIL; } @@ -542,7 +541,7 @@ static cairo_int_status_t _cairo_paginated_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_paginated_surface_t *surface = abstract_surface; @@ -554,7 +553,7 @@ _cairo_paginated_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_paginated_surface_t *surface = abstract_surface; @@ -565,13 +564,13 @@ static cairo_int_status_t _cairo_paginated_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_paginated_surface_t *surface = abstract_surface; @@ -586,11 +585,11 @@ static cairo_int_status_t _cairo_paginated_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_paginated_surface_t *surface = abstract_surface; @@ -620,7 +619,7 @@ _cairo_paginated_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_paginated_surface_t *surface = abstract_surface; diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c index 204b98283..1fc9a06a9 100644 --- a/src/cairo-path-bounds.c +++ b/src/cairo-path-bounds.c @@ -37,6 +37,7 @@ #include "cairoint.h" #include "cairo-box-private.h" +#include "cairo-error-private.h" #include "cairo-path-fixed-private.h" diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c index 6074a5232..b15b1a4a0 100644 --- a/src/cairo-path-fill.c +++ b/src/cairo-path-fill.c @@ -120,6 +120,86 @@ _cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path, return _cairo_filler_close (&filler); } +typedef struct cairo_filler_rectilinear_aligned { + cairo_polygon_t *polygon; + + cairo_point_t current_point; + cairo_point_t last_move_to; +} cairo_filler_ra_t; + +static cairo_status_t +_cairo_filler_ra_line_to (void *closure, + const cairo_point_t *point) +{ + cairo_filler_ra_t *filler = closure; + cairo_status_t status; + cairo_point_t p; + + p.x = _cairo_fixed_round_down (point->x); + p.y = _cairo_fixed_round_down (point->y); + + status = _cairo_polygon_add_external_edge (filler->polygon, + &filler->current_point, + &p); + + filler->current_point = p; + + return status; +} + +static cairo_status_t +_cairo_filler_ra_move_to (void *closure, + const cairo_point_t *point) +{ + cairo_filler_t *filler = closure; + cairo_status_t status; + cairo_point_t p; + + /* close current subpath */ + status = _cairo_filler_close (closure); + if (unlikely (status)) + return status; + + p.x = _cairo_fixed_round_down (point->x); + p.y = _cairo_fixed_round_down (point->y); + + /* make sure that the closure represents a degenerate path */ + filler->current_point = p; + filler->last_move_to = p; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_path_fixed_fill_rectilinear_to_polygon (const cairo_path_fixed_t *path, + cairo_antialias_t antialias, + cairo_polygon_t *polygon) +{ + cairo_filler_ra_t filler; + cairo_status_t status; + + if (antialias != CAIRO_ANTIALIAS_NONE) + return _cairo_path_fixed_fill_to_polygon (path, 0., polygon); + + filler.polygon = polygon; + + /* make sure that the closure represents a degenerate path */ + filler.current_point.x = 0; + filler.current_point.y = 0; + filler.last_move_to = filler.current_point; + + status = _cairo_path_fixed_interpret_flat (path, + _cairo_filler_ra_move_to, + _cairo_filler_ra_line_to, + _cairo_filler_close, + &filler, + 0.); + if (unlikely (status)) + return status; + + return _cairo_filler_close (&filler); +} + cairo_status_t _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, @@ -170,12 +250,15 @@ _cairo_path_fixed_fill_rectilinear_tessellate_to_region (const cairo_path_fixed_ _cairo_traps_init (&traps); status = _cairo_path_fixed_fill_rectilinear_to_traps (path, fill_rule, + CAIRO_ANTIALIAS_NONE, &traps); if (_cairo_status_is_error (status)) goto CLEANUP_TRAPS; if (status == CAIRO_STATUS_SUCCESS) { - status = _cairo_traps_extract_region (&traps, ®ion); + status = _cairo_traps_extract_region (&traps, + CAIRO_ANTIALIAS_NONE, + ®ion); goto CLEANUP_TRAPS; } @@ -200,7 +283,9 @@ _cairo_path_fixed_fill_rectilinear_tessellate_to_region (const cairo_path_fixed_ &polygon, fill_rule); if (likely (status == CAIRO_STATUS_SUCCESS)) - status = _cairo_traps_extract_region (&traps, ®ion); + status = _cairo_traps_extract_region (&traps, + CAIRO_ANTIALIAS_NONE, + ®ion); } CLEANUP_POLYGON: @@ -338,6 +423,7 @@ TESSELLATE: cairo_int_status_t _cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, cairo_traps_t *traps) { cairo_box_t box; @@ -347,6 +433,12 @@ _cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path, traps->is_rectangular = TRUE; if (_cairo_path_fixed_is_box (path, &box)) { + if (antialias == CAIRO_ANTIALIAS_NONE) { + box.p1.x = _cairo_fixed_round_down (box.p1.x); + box.p1.y = _cairo_fixed_round_down (box.p1.y); + box.p2.x = _cairo_fixed_round_down (box.p2.x); + box.p2.y = _cairo_fixed_round_down (box.p2.y); + } return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2); } else { cairo_path_fixed_iter_t iter; @@ -365,6 +457,13 @@ _cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path, box.p2.x = t; } + if (antialias == CAIRO_ANTIALIAS_NONE) { + box.p1.x = _cairo_fixed_round_down (box.p1.x); + box.p1.y = _cairo_fixed_round_down (box.p1.y); + box.p2.x = _cairo_fixed_round_down (box.p2.x); + box.p2.y = _cairo_fixed_round_down (box.p2.y); + } + status = _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2); if (unlikely (status)) { @@ -384,6 +483,7 @@ _cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path, static cairo_status_t _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, cairo_boxes_t *boxes) { cairo_polygon_t polygon; @@ -393,7 +493,7 @@ _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (const cairo_path_fixed_t boxes->num_limits = 0; /* tolerance will be ignored as the path is rectilinear */ - status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon); + status = _cairo_path_fixed_fill_rectilinear_to_polygon (path, antialias, &polygon); if (likely (status == CAIRO_STATUS_SUCCESS)) { status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (&polygon, @@ -409,6 +509,7 @@ _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (const cairo_path_fixed_t cairo_status_t _cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, cairo_boxes_t *boxes) { cairo_path_fixed_iter_t iter; @@ -416,7 +517,7 @@ _cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path, cairo_box_t box; if (_cairo_path_fixed_is_box (path, &box)) - return _cairo_boxes_add (boxes, &box); + return _cairo_boxes_add (boxes, antialias, &box); _cairo_path_fixed_iter_init (&iter, path); while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) { @@ -435,7 +536,7 @@ _cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path, box.p2.x = t; } - status = _cairo_boxes_add (boxes, &box); + status = _cairo_boxes_add (boxes, antialias, &box); if (unlikely (status)) return status; } @@ -447,5 +548,6 @@ _cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path, _cairo_boxes_clear (boxes); return _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (path, fill_rule, + antialias, boxes); } diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c index 6b0df9cc1..31ce1ac06 100644 --- a/src/cairo-path-stroke.c +++ b/src/cairo-path-stroke.c @@ -1402,6 +1402,7 @@ _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path, status = _cairo_path_fixed_stroke_rectilinear_to_traps (path, stroke_style, ctm, + CAIRO_ANTIALIAS_DEFAULT, traps); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; @@ -1440,6 +1441,7 @@ typedef struct _segment_t { typedef struct _cairo_rectilinear_stroker { const cairo_stroke_style_t *stroke_style; const cairo_matrix_t *ctm; + cairo_antialias_t antialias; cairo_fixed_t half_line_width; cairo_bool_t do_traps; @@ -1478,6 +1480,7 @@ static cairo_bool_t _cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t *stroker, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, + cairo_antialias_t antialias, cairo_bool_t do_traps, void *container) { @@ -1512,6 +1515,7 @@ _cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t *stroker, stroker->stroke_style = stroke_style; stroker->ctm = ctm; + stroker->antialias = antialias; stroker->half_line_width = _cairo_fixed_from_double (stroke_style->line_width / 2.0); @@ -1687,6 +1691,12 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker) } if (stroker->do_traps) { + if (stroker->antialias == CAIRO_ANTIALIAS_NONE) { + a->x = _cairo_fixed_round_down (a->x); + a->y = _cairo_fixed_round_down (a->y); + b->x = _cairo_fixed_round_down (b->x); + b->y = _cairo_fixed_round_down (b->y); + } status = _cairo_traps_tessellate_rectangle (stroker->container, a, b); } else { cairo_box_t box; @@ -1694,7 +1704,7 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker) box.p1 = *a; box.p2 = *b; - status = _cairo_boxes_add (stroker->container, &box); + status = _cairo_boxes_add (stroker->container, stroker->antialias, &box); } if (unlikely (status)) return status; @@ -1762,6 +1772,12 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st } if (stroker->do_traps) { + if (stroker->antialias == CAIRO_ANTIALIAS_NONE) { + p1.x = _cairo_fixed_round_down (p1.x); + p1.y = _cairo_fixed_round_down (p1.y); + p2.x = _cairo_fixed_round_down (p2.x); + p2.y = _cairo_fixed_round_down (p2.y); + } status = _cairo_traps_tessellate_rectangle (stroker->container, &p1, &p2); } else { cairo_box_t box; @@ -1769,7 +1785,7 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st box.p1 = p1; box.p2 = p2; - status = _cairo_boxes_add (stroker->container, &box); + status = _cairo_boxes_add (stroker->container, stroker->antialias, &box); } if (unlikely (status)) return status; @@ -1824,6 +1840,12 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st continue; if (stroker->do_traps) { + if (stroker->antialias == CAIRO_ANTIALIAS_NONE) { + a->x = _cairo_fixed_round_down (a->x); + a->y = _cairo_fixed_round_down (a->y); + b->x = _cairo_fixed_round_down (b->x); + b->y = _cairo_fixed_round_down (b->y); + } status = _cairo_traps_tessellate_rectangle (stroker->container, a, b); } else { cairo_box_t box; @@ -1831,7 +1853,7 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st box.p1 = *a; box.p2 = *b; - status = _cairo_boxes_add (stroker->container, &box); + status = _cairo_boxes_add (stroker->container, stroker->antialias, &box); } if (unlikely (status)) return status; @@ -2029,6 +2051,7 @@ cairo_int_status_t _cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, + cairo_antialias_t antialias, cairo_traps_t *traps) { cairo_rectilinear_stroker_t rectilinear_stroker; @@ -2037,7 +2060,7 @@ _cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path, assert (_cairo_path_fixed_stroke_is_rectilinear (path)); if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker, - stroke_style, ctm, + stroke_style, ctm, antialias, TRUE, traps)) { return CAIRO_INT_STATUS_UNSUPPORTED; @@ -2082,6 +2105,7 @@ cairo_int_status_t _cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, + cairo_antialias_t antialias, cairo_boxes_t *boxes) { cairo_rectilinear_stroker_t rectilinear_stroker; @@ -2090,7 +2114,7 @@ _cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path, assert (_cairo_path_fixed_stroke_is_rectilinear (path)); if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker, - stroke_style, ctm, + stroke_style, ctm, antialias, FALSE, boxes)) { return CAIRO_INT_STATUS_UNSUPPORTED; diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index b14a5f877..bb4c643b9 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -2118,7 +2118,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat pixman_transform_t pixman_transform; cairo_circle_double_t extremes[2]; pixman_point_fixed_t p1, p2; - cairo_status_t status; + cairo_int_status_t status; cairo_bool_t repeat = FALSE; int ix, iy; pixman_gradient_stop_t pixman_stops_static[2]; @@ -2241,7 +2241,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat &pixman_transform, &ix, &iy); if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { - if (unlikely (status != CAIRO_STATUS_SUCCESS) || + if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) || ! pixman_image_set_transform (pixman_image, &pixman_transform)) { cairo_surface_destroy (&image->base); diff --git a/src/cairo-pdf-operators-private.h b/src/cairo-pdf-operators-private.h index 14d60b6f6..48ae6b5c1 100644 --- a/src/cairo-pdf-operators-private.h +++ b/src/cairo-pdf-operators-private.h @@ -129,8 +129,8 @@ cairo_private void _cairo_pdf_operators_reset (cairo_pdf_operators_t *pdf_operators); cairo_private cairo_int_status_t -_cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators, - cairo_path_fixed_t *path, +_cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule); cairo_private cairo_int_status_t @@ -140,19 +140,19 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, cairo_private cairo_int_status_t _cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse); cairo_private cairo_int_status_t -_cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule); +_cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule); cairo_private cairo_int_status_t _cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c index 0f2500e44..58c647219 100644 --- a/src/cairo-pdf-operators.c +++ b/src/cairo-pdf-operators.c @@ -493,7 +493,7 @@ _cairo_pdf_path_rectangle (pdf_path_info_t *info, cairo_box_t *box) */ static cairo_status_t _cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators, - cairo_path_fixed_t *path, + const cairo_path_fixed_t*path, cairo_matrix_t *path_transform, cairo_line_cap_t line_cap) { @@ -530,7 +530,7 @@ _cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators, cairo_int_status_t _cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule) { const char *pdf_operator; @@ -763,7 +763,7 @@ _cairo_matrix_factor_out_scale (cairo_matrix_t *m, double *scale) static cairo_int_status_t _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, @@ -854,7 +854,7 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, cairo_int_status_t _cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse) @@ -869,7 +869,7 @@ _cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators, cairo_int_status_t _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule) { const char *pdf_operator; @@ -908,7 +908,7 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, cairo_int_status_t _cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index dbb722832..8bfa556c5 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -1089,12 +1089,12 @@ _get_jpeg_image_info (cairo_surface_t *source, return _cairo_image_info_get_jpeg_info (info, *mime_data, *mime_data_length); } -static cairo_status_t +static cairo_int_status_t _get_source_surface_size (cairo_surface_t *source, int *width, int *height) { - cairo_status_t status; + cairo_int_status_t status; cairo_rectangle_int_t extents; cairo_image_info_t info; const unsigned char *mime_data; @@ -2184,12 +2184,12 @@ static cairo_status_t _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface, cairo_surface_t *source, cairo_pdf_resource_t resource, - cairo_bool_t interpolate, + cairo_bool_t interpolate, cairo_bool_t mask) { cairo_image_surface_t *image; void *image_extra; - cairo_status_t status; + cairo_int_status_t status; status = _cairo_pdf_surface_emit_jpx_image (surface, source, resource); if (status != CAIRO_INT_STATUS_UNSUPPORTED) @@ -2226,7 +2226,7 @@ _cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t *surface, cairo_image_surface_t *image; cairo_surface_t *pad_image; void *image_extra; - cairo_status_t status; + cairo_int_status_t status; cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern; int x = 0; int y = 0; @@ -2276,6 +2276,7 @@ _cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t *surface, } switch (pdf_pattern->pattern->filter) { + default: case CAIRO_FILTER_GOOD: case CAIRO_FILTER_BEST: case CAIRO_FILTER_BILINEAR: @@ -2323,7 +2324,7 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface, cairo_paginated_mode_t old_paginated_mode; cairo_rectangle_int_t recording_extents; cairo_bool_t is_bounded; - cairo_status_t status; + cairo_int_status_t status; int alpha = 0; is_bounded = _cairo_surface_get_extents (recording_surface, &recording_extents); @@ -2384,7 +2385,7 @@ _cairo_pdf_surface_emit_recording_subsurface (cairo_pdf_surface_t *surface, { double old_width, old_height; cairo_paginated_mode_t old_paginated_mode; - cairo_status_t status; + cairo_int_status_t status; int alpha = 0; old_width = surface->width; @@ -4351,6 +4352,7 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface, if (_cairo_status_is_error (status)) return status; + last_glyph = font_subset->num_glyphs - 1; if (font_subset->is_latin) { /* find last glyph used */ for (i = 255; i >= 32; i--) @@ -4404,7 +4406,7 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface, tag, subset->base_font, font_subset->is_latin ? 32 : 0, - font_subset->is_latin ? last_glyph : font_subset->num_glyphs - 1, + last_glyph, descriptor.id); if (font_subset->is_latin) @@ -4741,7 +4743,7 @@ _cairo_pdf_emit_imagemask (cairo_image_surface_t *image, return _cairo_output_stream_get_status (stream); } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset, void *closure) { @@ -4781,7 +4783,7 @@ _cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_su return status; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, cairo_scaled_font_subset_t *font_subset) { @@ -4966,12 +4968,12 @@ _cairo_pdf_surface_emit_type3_font_subset (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_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset, void *closure) { cairo_pdf_surface_t *surface = closure; - cairo_status_t status; + cairo_int_status_t status; status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset); if (status != CAIRO_INT_STATUS_UNSUPPORTED) @@ -4994,22 +4996,22 @@ _cairo_pdf_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_s return status; ASSERT_NOT_REACHED; - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _cairo_pdf_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset, void *closure) { cairo_pdf_surface_t *surface = closure; - cairo_status_t status; + cairo_int_status_t status; status = _cairo_pdf_surface_emit_type3_font_subset (surface, font_subset); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; ASSERT_NOT_REACHED; - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } static cairo_status_t @@ -5742,20 +5744,20 @@ static cairo_int_status_t _cairo_pdf_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; - cairo_status_t status; cairo_pdf_smask_group_t *group; cairo_pdf_resource_t pattern_res, gstate_res; cairo_composite_rectangles_t extents; + cairo_int_status_t status; status = _cairo_composite_rectangles_init_for_paint (&extents, surface->width, surface->height, op, source, clip); if (unlikely (status)) { if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; return status; } @@ -5859,12 +5861,12 @@ _cairo_pdf_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_smask_group_t *group; - cairo_status_t status; cairo_composite_rectangles_t extents; + cairo_int_status_t status; status = _cairo_composite_rectangles_init_for_mask (&extents, surface->width, surface->height, @@ -5966,19 +5968,19 @@ static cairo_int_status_t _cairo_pdf_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_smask_group_t *group; cairo_pdf_resource_t pattern_res, gstate_res; cairo_composite_rectangles_t extents; - cairo_status_t status; + cairo_int_status_t status; status = _cairo_composite_rectangles_init_for_stroke (&extents, surface->width, @@ -5988,7 +5990,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface, clip); if (unlikely (status)) { if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; return status; } @@ -6003,7 +6005,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface, return status; if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask)) - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) @@ -6021,7 +6023,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface, &extents.bounded, &pattern_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; @@ -6097,14 +6099,14 @@ static cairo_int_status_t _cairo_pdf_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t*path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; - cairo_status_t status; + cairo_int_status_t status; cairo_pdf_smask_group_t *group; cairo_pdf_resource_t pattern_res, gstate_res; cairo_composite_rectangles_t extents; @@ -6116,7 +6118,7 @@ _cairo_pdf_surface_fill (void *abstract_surface, clip); if (unlikely (status)) { if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; return status; } @@ -6129,7 +6131,7 @@ _cairo_pdf_surface_fill (void *abstract_surface, &extents.mask); if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask)) - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { @@ -6180,7 +6182,7 @@ _cairo_pdf_surface_fill (void *abstract_surface, &extents.bounded, &pattern_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; @@ -6251,7 +6253,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, cairo_fill_rule_t fill_rule, double fill_tolerance, cairo_antialias_t fill_antialias, - cairo_path_fixed_t *path, + const cairo_path_fixed_t*path, cairo_operator_t stroke_op, const cairo_pattern_t *stroke_source, const cairo_stroke_style_t *stroke_style, @@ -6259,10 +6261,10 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; - cairo_status_t status; + cairo_int_status_t status; cairo_pdf_resource_t fill_pattern_res, stroke_pattern_res, gstate_res; cairo_composite_rectangles_t extents; @@ -6408,14 +6410,14 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_smask_group_t *group; cairo_pdf_resource_t pattern_res, gstate_res; cairo_composite_rectangles_t extents; cairo_bool_t overlap; - cairo_status_t status; + cairo_int_status_t status; status = _cairo_composite_rectangles_init_for_glyphs (&extents, surface->width, @@ -6427,7 +6429,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, &overlap); if (unlikely (status)) { if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; return status; } @@ -6447,7 +6449,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, &extents.bounded, &pattern_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; diff --git a/src/cairo-png.c b/src/cairo-png.c index 5cb132e06..5468096c9 100644 --- a/src/cairo-png.c +++ b/src/cairo-png.c @@ -169,7 +169,7 @@ write_png (cairo_surface_t *surface, void *closure) { int i; - cairo_status_t status; + cairo_int_status_t status; cairo_image_surface_t *image; cairo_image_surface_t * volatile clone; void *image_extra; diff --git a/src/cairo-polygon-intersect.c b/src/cairo-polygon-intersect.c new file mode 100644 index 000000000..e2ed6e970 --- /dev/null +++ b/src/cairo-polygon-intersect.c @@ -0,0 +1,1466 @@ +/* + * Copyright © 2004 Carl Worth + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 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 Carl Worth + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +/* Provide definitions for standalone compilation */ +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-freelist-private.h" +#include "cairo-combsort-private.h" + +typedef cairo_point_t cairo_bo_point32_t; + +typedef struct _cairo_bo_intersect_ordinate { + int32_t ordinate; + enum { EXACT, INEXACT } exactness; +} cairo_bo_intersect_ordinate_t; + +typedef struct _cairo_bo_intersect_point { + cairo_bo_intersect_ordinate_t x; + cairo_bo_intersect_ordinate_t y; +} cairo_bo_intersect_point_t; + +typedef struct _cairo_bo_edge cairo_bo_edge_t; + +typedef struct _cairo_bo_deferred { + cairo_bo_edge_t *other; + int32_t top; + int dir; +} cairo_bo_deferred_t; + +struct _cairo_bo_edge { + int a_or_b; + cairo_edge_t edge; + cairo_bo_edge_t *prev; + cairo_bo_edge_t *next; + cairo_bo_deferred_t deferred; +}; + +/* the parent is always given by index/2 */ +#define PQ_PARENT_INDEX(i) ((i) >> 1) +#define PQ_FIRST_ENTRY 1 + +/* left and right children are index * 2 and (index * 2) +1 respectively */ +#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1) + +typedef enum { + CAIRO_BO_EVENT_TYPE_STOP, + CAIRO_BO_EVENT_TYPE_INTERSECTION, + CAIRO_BO_EVENT_TYPE_START +} cairo_bo_event_type_t; + +typedef struct _cairo_bo_event { + cairo_bo_event_type_t type; + cairo_point_t point; +} cairo_bo_event_t; + +typedef struct _cairo_bo_start_event { + cairo_bo_event_type_t type; + cairo_point_t point; + cairo_bo_edge_t edge; +} cairo_bo_start_event_t; + +typedef struct _cairo_bo_queue_event { + cairo_bo_event_type_t type; + cairo_point_t point; + cairo_bo_edge_t *e1; + cairo_bo_edge_t *e2; +} cairo_bo_queue_event_t; + +typedef struct _pqueue { + int size, max_size; + + cairo_bo_event_t **elements; + cairo_bo_event_t *elements_embedded[1024]; +} pqueue_t; + +typedef struct _cairo_bo_event_queue { + cairo_freepool_t pool; + pqueue_t pqueue; + cairo_bo_event_t **start_events; +} cairo_bo_event_queue_t; + +typedef struct _cairo_bo_sweep_line { + cairo_bo_edge_t *head; + int32_t current_y; + cairo_bo_edge_t *current_edge; +} cairo_bo_sweep_line_t; + +static cairo_fixed_t +_line_compute_intersection_x_for_y (const cairo_line_t *line, + cairo_fixed_t y) +{ + cairo_fixed_t x, dy; + + if (y == line->p1.y) + return line->p1.x; + if (y == line->p2.y) + return line->p2.x; + + x = line->p1.x; + dy = line->p2.y - line->p1.y; + if (dy != 0) { + x += _cairo_fixed_mul_div_floor (y - line->p1.y, + line->p2.x - line->p1.x, + dy); + } + + return x; +} + +static inline int +_cairo_bo_point32_compare (cairo_bo_point32_t const *a, + cairo_bo_point32_t const *b) +{ + int cmp; + + cmp = a->y - b->y; + if (cmp) + return cmp; + + return a->x - b->x; +} + +/* Compare the slope of a to the slope of b, returning 1, 0, -1 if the + * slope a is respectively greater than, equal to, or less than the + * slope of b. + * + * For each edge, consider the direction vector formed from: + * + * top -> bottom + * + * which is: + * + * (dx, dy) = (line.p2.x - line.p1.x, line.p2.y - line.p1.y) + * + * We then define the slope of each edge as dx/dy, (which is the + * inverse of the slope typically used in math instruction). We never + * compute a slope directly as the value approaches infinity, but we + * can derive a slope comparison without division as follows, (where + * the ? represents our compare operator). + * + * 1. slope(a) ? slope(b) + * 2. adx/ady ? bdx/bdy + * 3. (adx * bdy) ? (bdx * ady) + * + * Note that from step 2 to step 3 there is no change needed in the + * sign of the result since both ady and bdy are guaranteed to be + * greater than or equal to 0. + * + * When using this slope comparison to sort edges, some care is needed + * when interpreting the results. Since the slope compare operates on + * distance vectors from top to bottom it gives a correct left to + * right sort for edges that have a common top point, (such as two + * edges with start events at the same location). On the other hand, + * the sense of the result will be exactly reversed for two edges that + * have a common stop point. + */ +static inline int +_slope_compare (const cairo_bo_edge_t *a, + const cairo_bo_edge_t *b) +{ + /* 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 adx = a->edge.line.p2.x - a->edge.line.p1.x; + int32_t bdx = b->edge.line.p2.x - b->edge.line.p1.x; + + /* Since the dy's are all positive by construction we can fast + * path several common cases. + */ + + /* First check for vertical lines. */ + if (adx == 0) + return -bdx; + if (bdx == 0) + return adx; + + /* Then where the two edges point in different directions wrt x. */ + if ((adx ^ bdx) < 0) + return adx; + + /* Finally we actually need to do the general comparison. */ + { + int32_t ady = a->edge.line.p2.y - a->edge.line.p1.y; + int32_t bdy = b->edge.line.p2.y - b->edge.line.p1.y; + cairo_int64_t adx_bdy = _cairo_int32x32_64_mul (adx, bdy); + cairo_int64_t bdx_ady = _cairo_int32x32_64_mul (bdx, ady); + + return _cairo_int64_cmp (adx_bdy, bdx_ady); + } +} + +/* + * 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 + * given x, 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 ∘ X + * where ∘ is our inequality operator. + * + * By construction, we know that A_dy (and (Y - A_y)) are + * all positive, so we can rearrange it thus without causing a sign change: + * (Y - A_y) * A_dx ∘ (X - A_x) * A_dy + * + * Given the assumption that all the deltas fit within 32 bits, we can compute + * this comparison directly using 64 bit arithmetic. + * + * See the similar discussion for _slope_compare() and + * edges_compare_x_for_y_general(). + */ +static int +edge_compare_for_y_against_x (const cairo_bo_edge_t *a, + int32_t y, + int32_t x) +{ + int32_t adx, ady; + int32_t dx, dy; + cairo_int64_t L, R; + + if (x < a->edge.line.p1.x && x < a->edge.line.p2.x) + return 1; + if (x > a->edge.line.p1.x && x > a->edge.line.p2.x) + return -1; + + adx = a->edge.line.p2.x - a->edge.line.p1.x; + dx = x - a->edge.line.p1.x; + + if (adx == 0) + return -dx; + if (dx == 0 || (adx ^ dx) < 0) + return adx; + + dy = y - a->edge.line.p1.y; + ady = a->edge.line.p2.y - a->edge.line.p1.y; + + L = _cairo_int32x32_64_mul (dy, adx); + R = _cairo_int32x32_64_mul (dx, ady); + + 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 int +_cairo_bo_sweep_line_compare_edges (cairo_bo_sweep_line_t *sweep_line, + const cairo_bo_edge_t *a, + const cairo_bo_edge_t *b) +{ + int cmp; + + /* compare the edges if not identical */ + if (! _line_equal (&a->edge.line, &b->edge.line)) { + 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) + return cmp; + } + + /* We've got two collinear edges now. */ + return b->edge.bottom - a->edge.bottom; +} + +static inline cairo_int64_t +det32_64 (int32_t a, int32_t b, + int32_t c, int32_t d) +{ + /* det = a * d - b * c */ + return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d), + _cairo_int32x32_64_mul (b, c)); +} + +static inline cairo_int128_t +det64x32_128 (cairo_int64_t a, int32_t b, + cairo_int64_t c, int32_t d) +{ + /* det = a * d - b * c */ + return _cairo_int128_sub (_cairo_int64x32_128_mul (a, d), + _cairo_int64x32_128_mul (c, b)); +} + +/* Compute the intersection of two lines as defined by two edges. The + * result is provided as a coordinate pair of 128-bit integers. + * + * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or + * %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel. + */ +static cairo_bool_t +intersect_lines (cairo_bo_edge_t *a, + cairo_bo_edge_t *b, + cairo_bo_intersect_point_t *intersection) +{ + cairo_int64_t a_det, b_det; + + /* 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. + * What we're doing to mitigate this is to perform clamping in + * cairo_bo_tessellate_polygon(). + */ + int32_t dx1 = a->edge.line.p1.x - a->edge.line.p2.x; + int32_t dy1 = a->edge.line.p1.y - a->edge.line.p2.y; + + int32_t dx2 = b->edge.line.p1.x - b->edge.line.p2.x; + int32_t dy2 = b->edge.line.p1.y - b->edge.line.p2.y; + + cairo_int64_t den_det; + cairo_int64_t R; + cairo_quorem64_t qr; + + den_det = det32_64 (dx1, dy1, dx2, dy2); + + /* Q: Can we determine that the lines do not intersect (within range) + * much more cheaply than computing the intersection point i.e. by + * avoiding the division? + * + * X = ax + t * adx = bx + s * bdx; + * Y = ay + t * ady = by + s * bdy; + * ∴ t * (ady*bdx - bdy*adx) = bdx * (by - ay) + bdy * (ax - bx) + * => t * L = R + * + * Therefore we can reject any intersection (under the criteria for + * valid intersection events) if: + * L^R < 0 => t < 0, or + * L<R => t > 1 + * + * (where top/bottom must at least extend to the line endpoints). + * + * A similar substitution can be performed for s, yielding: + * s * (ady*bdx - bdy*adx) = ady * (ax - bx) - adx * (ay - by) + */ + R = det32_64 (dx2, dy2, + b->edge.line.p1.x - a->edge.line.p1.x, + b->edge.line.p1.y - a->edge.line.p1.y); + if (_cairo_int64_negative (den_det)) { + if (_cairo_int64_ge (den_det, R)) + return FALSE; + } else { + if (_cairo_int64_le (den_det, R)) + return FALSE; + } + + R = det32_64 (dy1, dx1, + a->edge.line.p1.y - b->edge.line.p1.y, + a->edge.line.p1.x - b->edge.line.p1.x); + if (_cairo_int64_negative (den_det)) { + if (_cairo_int64_ge (den_det, R)) + return FALSE; + } else { + if (_cairo_int64_le (den_det, R)) + return FALSE; + } + + /* We now know that the two lines should intersect within range. */ + + a_det = det32_64 (a->edge.line.p1.x, a->edge.line.p1.y, + a->edge.line.p2.x, a->edge.line.p2.y); + b_det = det32_64 (b->edge.line.p1.x, b->edge.line.p1.y, + b->edge.line.p2.x, b->edge.line.p2.y); + + /* x = det (a_det, dx1, b_det, dx2) / den_det */ + qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dx1, + b_det, dx2), + den_det); + if (_cairo_int64_eq (qr.rem, den_det)) + return FALSE; +#if 0 + intersection->x.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT; +#else + intersection->x.exactness = EXACT; + if (! _cairo_int64_is_zero (qr.rem)) { + if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem)) + qr.rem = _cairo_int64_negate (qr.rem); + qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2)); + if (_cairo_int64_ge (qr.rem, den_det)) { + qr.quo = _cairo_int64_add (qr.quo, + _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1)); + } else + intersection->x.exactness = INEXACT; + } +#endif + intersection->x.ordinate = _cairo_int64_to_int32 (qr.quo); + + /* y = det (a_det, dy1, b_det, dy2) / den_det */ + qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dy1, + b_det, dy2), + den_det); + if (_cairo_int64_eq (qr.rem, den_det)) + return FALSE; +#if 0 + intersection->y.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT; +#else + intersection->y.exactness = EXACT; + if (! _cairo_int64_is_zero (qr.rem)) { + if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem)) + qr.rem = _cairo_int64_negate (qr.rem); + qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2)); + if (_cairo_int64_ge (qr.rem, den_det)) { + qr.quo = _cairo_int64_add (qr.quo, + _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1)); + } else + intersection->y.exactness = INEXACT; + } +#endif + intersection->y.ordinate = _cairo_int64_to_int32 (qr.quo); + + return TRUE; +} + +static int +_cairo_bo_intersect_ordinate_32_compare (cairo_bo_intersect_ordinate_t a, + int32_t b) +{ + /* First compare the quotient */ + if (a.ordinate > b) + return +1; + if (a.ordinate < b) + return -1; + /* With quotient identical, if remainder is 0 then compare equal */ + /* Otherwise, the non-zero remainder makes a > b */ + return INEXACT == a.exactness; +} + +/* Does the given edge contain the given point. The point must already + * be known to be contained within the line determined by the edge, + * (most likely the point results from an intersection of this edge + * with another). + * + * If we had exact arithmetic, then this function would simply be a + * matter of examining whether the y value of the point lies within + * the range of y values of the edge. But since intersection points + * are not exact due to being rounded to the nearest integer within + * the available precision, we must also examine the x value of the + * point. + * + * The definition of "contains" here is that the given intersection + * point will be seen by the sweep line after the start event for the + * given edge and before the stop event for the edge. See the comments + * in the implementation for more details. + */ +static cairo_bool_t +_cairo_bo_edge_contains_intersect_point (cairo_bo_edge_t *edge, + cairo_bo_intersect_point_t *point) +{ + int cmp_top, cmp_bottom; + + /* XXX: When running the actual algorithm, we don't actually need to + * compare against edge->top at all here, since any intersection above + * top is eliminated early via a slope comparison. We're leaving these + * here for now only for the sake of the quadratic-time intersection + * finder which needs them. + */ + + cmp_top = _cairo_bo_intersect_ordinate_32_compare (point->y, + edge->edge.top); + cmp_bottom = _cairo_bo_intersect_ordinate_32_compare (point->y, + edge->edge.bottom); + + if (cmp_top < 0 || cmp_bottom > 0) + { + return FALSE; + } + + if (cmp_top > 0 && cmp_bottom < 0) + { + return TRUE; + } + + /* At this stage, the point lies on the same y value as either + * edge->top or edge->bottom, so we have to examine the x value in + * order to properly determine containment. */ + + /* If the y value of the point is the same as the y value of the + * top of the edge, then the x value of the point must be greater + * to be considered as inside the edge. Similarly, if the y value + * of the point is the same as the y value of the bottom of the + * edge, then the x value of the point must be less to be + * considered as inside. */ + + if (cmp_top == 0) { + cairo_fixed_t top_x; + + top_x = _line_compute_intersection_x_for_y (&edge->edge.line, + edge->edge.top); + return _cairo_bo_intersect_ordinate_32_compare (point->x, top_x) > 0; + } else { /* cmp_bottom == 0 */ + cairo_fixed_t bot_x; + + bot_x = _line_compute_intersection_x_for_y (&edge->edge.line, + edge->edge.bottom); + return _cairo_bo_intersect_ordinate_32_compare (point->x, bot_x) < 0; + } +} + +/* Compute the intersection of two edges. The result is provided as a + * coordinate pair of 128-bit integers. + * + * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection + * that is within both edges, %CAIRO_BO_STATUS_NO_INTERSECTION if the + * intersection of the lines defined by the edges occurs outside of + * one or both edges, and %CAIRO_BO_STATUS_PARALLEL if the two edges + * are exactly parallel. + * + * Note that when determining if a candidate intersection is "inside" + * an edge, we consider both the infinitesimal shortening and the + * infinitesimal tilt rules described by John Hobby. Specifically, if + * the intersection is exactly the same as an edge point, it is + * effectively outside (no intersection is returned). Also, if the + * intersection point has the same + */ +static cairo_bool_t +_cairo_bo_edge_intersect (cairo_bo_edge_t *a, + cairo_bo_edge_t *b, + cairo_bo_point32_t *intersection) +{ + cairo_bo_intersect_point_t quorem; + + if (! intersect_lines (a, b, &quorem)) + return FALSE; + + if (! _cairo_bo_edge_contains_intersect_point (a, &quorem)) + return FALSE; + + if (! _cairo_bo_edge_contains_intersect_point (b, &quorem)) + return FALSE; + + /* Now that we've correctly compared the intersection point and + * determined that it lies within the edge, then we know that we + * no longer need any more bits of storage for the intersection + * than we do for our edge coordinates. We also no longer need the + * remainder from the division. */ + intersection->x = quorem.x.ordinate; + intersection->y = quorem.y.ordinate; + + return TRUE; +} + +static inline int +cairo_bo_event_compare (const cairo_bo_event_t *a, + const cairo_bo_event_t *b) +{ + int cmp; + + cmp = _cairo_bo_point32_compare (&a->point, &b->point); + if (cmp) + return cmp; + + cmp = a->type - b->type; + if (cmp) + return cmp; + + return a - b; +} + +static inline void +_pqueue_init (pqueue_t *pq) +{ + pq->max_size = ARRAY_LENGTH (pq->elements_embedded); + pq->size = 0; + + pq->elements = pq->elements_embedded; +} + +static inline void +_pqueue_fini (pqueue_t *pq) +{ + if (pq->elements != pq->elements_embedded) + free (pq->elements); +} + +static cairo_status_t +_pqueue_grow (pqueue_t *pq) +{ + cairo_bo_event_t **new_elements; + pq->max_size *= 2; + + if (pq->elements == pq->elements_embedded) { + new_elements = _cairo_malloc_ab (pq->max_size, + sizeof (cairo_bo_event_t *)); + if (unlikely (new_elements == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (new_elements, pq->elements_embedded, + sizeof (pq->elements_embedded)); + } else { + new_elements = _cairo_realloc_ab (pq->elements, + pq->max_size, + sizeof (cairo_bo_event_t *)); + if (unlikely (new_elements == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + pq->elements = new_elements; + return CAIRO_STATUS_SUCCESS; +} + +static inline cairo_status_t +_pqueue_push (pqueue_t *pq, cairo_bo_event_t *event) +{ + cairo_bo_event_t **elements; + int i, parent; + + if (unlikely (pq->size + 1 == pq->max_size)) { + cairo_status_t status; + + status = _pqueue_grow (pq); + if (unlikely (status)) + return status; + } + + elements = pq->elements; + + for (i = ++pq->size; + i != PQ_FIRST_ENTRY && + cairo_bo_event_compare (event, + elements[parent = PQ_PARENT_INDEX (i)]) < 0; + i = parent) + { + elements[i] = elements[parent]; + } + + elements[i] = event; + + return CAIRO_STATUS_SUCCESS; +} + +static inline void +_pqueue_pop (pqueue_t *pq) +{ + cairo_bo_event_t **elements = pq->elements; + cairo_bo_event_t *tail; + int child, i; + + tail = elements[pq->size--]; + if (pq->size == 0) { + elements[PQ_FIRST_ENTRY] = NULL; + return; + } + + for (i = PQ_FIRST_ENTRY; + (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size; + i = child) + { + if (child != pq->size && + cairo_bo_event_compare (elements[child+1], + elements[child]) < 0) + { + child++; + } + + if (cairo_bo_event_compare (elements[child], tail) >= 0) + break; + + elements[i] = elements[child]; + } + elements[i] = tail; +} + +static inline cairo_status_t +_cairo_bo_event_queue_insert (cairo_bo_event_queue_t *queue, + cairo_bo_event_type_t type, + cairo_bo_edge_t *e1, + cairo_bo_edge_t *e2, + const cairo_point_t *point) +{ + cairo_bo_queue_event_t *event; + + event = _cairo_freepool_alloc (&queue->pool); + if (unlikely (event == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + event->type = type; + event->e1 = e1; + event->e2 = e2; + event->point = *point; + + return _pqueue_push (&queue->pqueue, (cairo_bo_event_t *) event); +} + +static void +_cairo_bo_event_queue_delete (cairo_bo_event_queue_t *queue, + cairo_bo_event_t *event) +{ + _cairo_freepool_free (&queue->pool, event); +} + +static cairo_bo_event_t * +_cairo_bo_event_dequeue (cairo_bo_event_queue_t *event_queue) +{ + cairo_bo_event_t *event, *cmp; + + event = event_queue->pqueue.elements[PQ_FIRST_ENTRY]; + cmp = *event_queue->start_events; + if (event == NULL || + (cmp != NULL && cairo_bo_event_compare (cmp, event) < 0)) + { + event = cmp; + event_queue->start_events++; + } + else + { + _pqueue_pop (&event_queue->pqueue); + } + + return event; +} + +CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort, + cairo_bo_event_t *, + cairo_bo_event_compare) + +static void +_cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue, + cairo_bo_event_t **start_events, + int num_events) +{ + _cairo_bo_event_queue_sort (start_events, num_events); + start_events[num_events] = NULL; + + event_queue->start_events = start_events; + + _cairo_freepool_init (&event_queue->pool, + sizeof (cairo_bo_queue_event_t)); + _pqueue_init (&event_queue->pqueue); + event_queue->pqueue.elements[PQ_FIRST_ENTRY] = NULL; +} + +static cairo_status_t +event_queue_insert_stop (cairo_bo_event_queue_t *event_queue, + cairo_bo_edge_t *edge) +{ + cairo_bo_point32_t point; + + point.y = edge->edge.bottom; + point.x = _line_compute_intersection_x_for_y (&edge->edge.line, + point.y); + return _cairo_bo_event_queue_insert (event_queue, + CAIRO_BO_EVENT_TYPE_STOP, + edge, NULL, + &point); +} + +static void +_cairo_bo_event_queue_fini (cairo_bo_event_queue_t *event_queue) +{ + _pqueue_fini (&event_queue->pqueue); + _cairo_freepool_fini (&event_queue->pool); +} + +static inline cairo_status_t +event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_t *event_queue, + cairo_bo_edge_t *left, + cairo_bo_edge_t *right) +{ + cairo_bo_point32_t intersection; + + if (_line_equal (&left->edge.line, &right->edge.line)) + return CAIRO_STATUS_SUCCESS; + + /* The names "left" and "right" here are correct descriptions of + * the order of the two edges within the active edge list. So if a + * slope comparison also puts left less than right, then we know + * that the intersection of these two segments has already + * occurred before the current sweep line position. */ + if (_slope_compare (left, right) <= 0) + return CAIRO_STATUS_SUCCESS; + + if (! _cairo_bo_edge_intersect (left, right, &intersection)) + return CAIRO_STATUS_SUCCESS; + + return _cairo_bo_event_queue_insert (event_queue, + CAIRO_BO_EVENT_TYPE_INTERSECTION, + left, right, + &intersection); +} + +static void +_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line) +{ + sweep_line->head = NULL; + sweep_line->current_y = INT32_MIN; + sweep_line->current_edge = NULL; +} + +static cairo_status_t +sweep_line_insert (cairo_bo_sweep_line_t *sweep_line, + cairo_bo_edge_t *edge) +{ + if (sweep_line->current_edge != NULL) { + cairo_bo_edge_t *prev, *next; + int cmp; + + cmp = _cairo_bo_sweep_line_compare_edges (sweep_line, + sweep_line->current_edge, + edge); + if (cmp < 0) { + prev = sweep_line->current_edge; + next = prev->next; + while (next != NULL && + _cairo_bo_sweep_line_compare_edges (sweep_line, + next, edge) < 0) + { + prev = next, next = prev->next; + } + + prev->next = edge; + edge->prev = prev; + edge->next = next; + if (next != NULL) + next->prev = edge; + } else if (cmp > 0) { + next = sweep_line->current_edge; + prev = next->prev; + while (prev != NULL && + _cairo_bo_sweep_line_compare_edges (sweep_line, + prev, edge) > 0) + { + next = prev, prev = next->prev; + } + + next->prev = edge; + edge->next = next; + edge->prev = prev; + if (prev != NULL) + prev->next = edge; + else + sweep_line->head = edge; + } else { + prev = sweep_line->current_edge; + edge->prev = prev; + edge->next = prev->next; + if (prev->next != NULL) + prev->next->prev = edge; + prev->next = edge; + } + } else { + sweep_line->head = edge; + } + + sweep_line->current_edge = edge; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line, + cairo_bo_edge_t *edge) +{ + if (edge->prev != NULL) + edge->prev->next = edge->next; + else + sweep_line->head = edge->next; + + if (edge->next != NULL) + edge->next->prev = edge->prev; + + if (sweep_line->current_edge == edge) + sweep_line->current_edge = edge->prev ? edge->prev : edge->next; +} + +static void +_cairo_bo_sweep_line_swap (cairo_bo_sweep_line_t *sweep_line, + cairo_bo_edge_t *left, + cairo_bo_edge_t *right) +{ + if (left->prev != NULL) + left->prev->next = right; + else + sweep_line->head = right; + + if (right->next != NULL) + right->next->prev = left; + + left->next = right->next; + right->next = left; + + right->prev = left->prev; + left->prev = right; +} + +static inline cairo_bool_t +edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b) +{ + if (_line_equal (&a->edge.line, &b->edge.line)) + return TRUE; + + if (_slope_compare (a, b)) + return FALSE; + + /* The choice of y is not truly arbitrary since we must guarantee that it + * is greater than the start of either line. + */ + if (a->edge.line.p1.y == b->edge.line.p1.y) { + return a->edge.line.p1.x == b->edge.line.p1.x; + } else if (a->edge.line.p1.y < b->edge.line.p1.y) { + return edge_compare_for_y_against_x (b, + a->edge.line.p1.y, + a->edge.line.p1.x) == 0; + } else { + return edge_compare_for_y_against_x (a, + b->edge.line.p1.y, + b->edge.line.p1.x) == 0; + } +} + +static void +edges_end (cairo_bo_edge_t *left, + int32_t bot, + cairo_polygon_t *polygon) +{ + cairo_bo_deferred_t *l = &left->deferred; + cairo_bo_edge_t *right = l->other; + cairo_bo_deferred_t *r = &right->deferred; + + if (likely (l->top < bot)) { + _cairo_polygon_add_line (polygon, &left->edge.line, + l->top, bot, l->dir); + _cairo_polygon_add_line (polygon, &right->edge.line, + l->top, bot, r->dir); + } + + l->other = NULL; + r->other = NULL; +} + + +static inline void +edges_start_or_continue (cairo_bo_edge_t *left, + cairo_bo_edge_t *right, + int top, + cairo_polygon_t *polygon) +{ + if (left->deferred.other == right) { + assert (right->deferred.other == left); + assert (left->deferred.dir == 1); + assert (right->deferred.dir == -1); + return; + } + + if (left->deferred.other != NULL) { + assert (left->deferred.dir == 1); + if (right != NULL && edges_colinear (left->deferred.other, right)) { + /* continuation on right, so just swap edges */ + left->deferred.other->deferred.other = NULL; + left->deferred.other = right; + right->deferred.other = left; + right->deferred.dir = -1; + return; + } + + edges_end (left, top, polygon); + } + + if (right != NULL && ! edges_colinear (left, right)) { + left->deferred.top = top; + left->deferred.dir = 1; + left->deferred.other = right; + + right->deferred.top = top; + right->deferred.dir = -1; + right->deferred.other = left; + } +} + +#define is_zero(w) ((w)[0] == 0 || (w)[1] == 0) + +static inline void +active_edges (cairo_bo_edge_t *left, + int32_t top, + cairo_polygon_t *polygon) +{ + cairo_bo_edge_t *right; + int winding[2] = {0, 0}; + + /* Yes, this is naive. Consider this a placeholder. */ + + while (left != NULL) { + assert (is_zero (winding)); + + do { + winding[left->a_or_b] += left->edge.dir; + if (! is_zero (winding)) + break; + + if unlikely ((left->deferred.other)) + edges_end (left, top, polygon); + + left = left->next; + if (! left) + return; + } while (1); + + right = left->next; + do { + if unlikely ((right->deferred.other)) + edges_end (right, top, polygon); + + winding[right->a_or_b] += right->edge.dir; + if (is_zero (winding)) { + if (right->next == NULL || + ! edges_colinear (right, right->next)) + break; + } + + right = right->next; + } while (right); + + edges_start_or_continue (left, right, top, polygon); + + left = right; + if (left != NULL) + left = left->next; + } +} + + +static cairo_status_t +intersection_sweep (cairo_bo_event_t **start_events, + int num_events, + cairo_polygon_t *polygon) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; /* silence compiler */ + cairo_bo_event_queue_t event_queue; + cairo_bo_sweep_line_t sweep_line; + cairo_bo_event_t *event; + cairo_bo_edge_t *left, *right; + cairo_bo_edge_t *e1, *e2; + + _cairo_bo_event_queue_init (&event_queue, start_events, num_events); + _cairo_bo_sweep_line_init (&sweep_line); + + while ((event = _cairo_bo_event_dequeue (&event_queue))) { + if (event->point.y != sweep_line.current_y) { + active_edges (sweep_line.head, + sweep_line.current_y, + polygon); + sweep_line.current_y = event->point.y; + } + + switch (event->type) { + case CAIRO_BO_EVENT_TYPE_START: + e1 = &((cairo_bo_start_event_t *) event)->edge; + + status = sweep_line_insert (&sweep_line, e1); + if (unlikely (status)) + goto unwind; + + status = event_queue_insert_stop (&event_queue, e1); + if (unlikely (status)) + goto unwind; + + left = e1->prev; + right = e1->next; + + if (left != NULL) { + status = event_queue_insert_if_intersect_below_current_y (&event_queue, left, e1); + if (unlikely (status)) + goto unwind; + } + + if (right != NULL) { + status = event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right); + if (unlikely (status)) + goto unwind; + } + + break; + + case CAIRO_BO_EVENT_TYPE_STOP: + e1 = ((cairo_bo_queue_event_t *) event)->e1; + _cairo_bo_event_queue_delete (&event_queue, event); + + if (e1->deferred.other) + edges_end (e1, sweep_line.current_y, polygon); + + left = e1->prev; + right = e1->next; + + _cairo_bo_sweep_line_delete (&sweep_line, e1); + + if (left != NULL && right != NULL) { + status = event_queue_insert_if_intersect_below_current_y (&event_queue, left, right); + if (unlikely (status)) + goto unwind; + } + + break; + + case CAIRO_BO_EVENT_TYPE_INTERSECTION: + e1 = ((cairo_bo_queue_event_t *) event)->e1; + e2 = ((cairo_bo_queue_event_t *) event)->e2; + _cairo_bo_event_queue_delete (&event_queue, event); + + /* skip this intersection if its edges are not adjacent */ + if (e2 != e1->next) + break; + + left = e1->prev; + right = e2->next; + + _cairo_bo_sweep_line_swap (&sweep_line, e1, e2); + + /* after the swap e2 is left of e1 */ + + if (left != NULL) { + status = event_queue_insert_if_intersect_below_current_y (&event_queue, left, e2); + if (unlikely (status)) + goto unwind; + } + + if (right != NULL) { + status = event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right); + if (unlikely (status)) + goto unwind; + } + + break; + } + } + + unwind: + _cairo_bo_event_queue_fini (&event_queue); + + return status; +} + +cairo_status_t +_cairo_polygon_intersect (cairo_polygon_t *a, int winding_a, + cairo_polygon_t *b, int winding_b) +{ + cairo_status_t status; + cairo_bo_start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_start_event_t)]; + cairo_bo_start_event_t *events; + cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1]; + cairo_bo_event_t **event_ptrs; + int num_events; + int i, j; + + /* XXX lazy */ + if (winding_a != CAIRO_FILL_RULE_WINDING) { + status = _cairo_polygon_reduce (a, winding_a); + if (unlikely (status)) + return status; + } + + if (winding_b != CAIRO_FILL_RULE_WINDING) { + status = _cairo_polygon_reduce (b, winding_b); + if (unlikely (status)) + return status; + } + + if (unlikely (0 == a->num_edges)) + return CAIRO_STATUS_SUCCESS; + + if (unlikely (b->num_edges == 0)) { + a->num_edges = 0; + return CAIRO_STATUS_SUCCESS; + } + + events = stack_events; + event_ptrs = stack_event_ptrs; + num_events = a->num_edges + b->num_edges; + if (num_events > ARRAY_LENGTH (stack_events)) { + events = _cairo_malloc_ab_plus_c (num_events, + sizeof (cairo_bo_start_event_t) + + sizeof (cairo_bo_event_t *), + sizeof (cairo_bo_event_t *)); + if (unlikely (events == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + event_ptrs = (cairo_bo_event_t **) (events + num_events); + } + + j = 0; + for (i = 0; i < a->num_edges; i++) { + event_ptrs[j] = (cairo_bo_event_t *) &events[j]; + + events[j].type = CAIRO_BO_EVENT_TYPE_START; + events[j].point.y = a->edges[i].top; + events[j].point.x = + _line_compute_intersection_x_for_y (&a->edges[i].line, + events[j].point.y); + + events[j].edge.a_or_b = 0; + events[j].edge.edge = a->edges[i]; + events[j].edge.deferred.other = NULL; + events[j].edge.prev = NULL; + events[j].edge.next = NULL; + j++; + } + + for (i = 0; i < b->num_edges; i++) { + event_ptrs[j] = (cairo_bo_event_t *) &events[j]; + + events[j].type = CAIRO_BO_EVENT_TYPE_START; + events[j].point.y = b->edges[i].top; + events[j].point.x = + _line_compute_intersection_x_for_y (&b->edges[i].line, + events[j].point.y); + + events[j].edge.a_or_b = 1; + events[j].edge.edge = b->edges[i]; + events[j].edge.deferred.other = NULL; + events[j].edge.prev = NULL; + events[j].edge.next = NULL; + j++; + } + assert (j == num_events); + + //fprintf(stderr, "a "); _cairo_debug_print_polygon(stderr,a); + //fprintf(stderr, "b "); _cairo_debug_print_polygon(stderr,b); + + a->num_edges = 0; + status = intersection_sweep (event_ptrs, num_events, a); + if (events != stack_events) + free (events); + + return status; +} diff --git a/src/cairo-polygon-reduce.c b/src/cairo-polygon-reduce.c new file mode 100644 index 000000000..f18e234da --- /dev/null +++ b/src/cairo-polygon-reduce.c @@ -0,0 +1,1491 @@ +/* + * Copyright © 2004 Carl Worth + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 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 Carl Worth + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +/* Provide definitions for standalone compilation */ +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-freelist-private.h" +#include "cairo-combsort-private.h" + +typedef cairo_point_t cairo_bo_point32_t; + +typedef struct _cairo_bo_intersect_ordinate { + int32_t ordinate; + enum { EXACT, INEXACT } exactness; +} cairo_bo_intersect_ordinate_t; + +typedef struct _cairo_bo_intersect_point { + cairo_bo_intersect_ordinate_t x; + cairo_bo_intersect_ordinate_t y; +} cairo_bo_intersect_point_t; + +typedef struct _cairo_bo_edge cairo_bo_edge_t; + +typedef struct _cairo_bo_deferred { + cairo_bo_edge_t *right; + int32_t top; +} cairo_bo_deferred_t; + +struct _cairo_bo_edge { + cairo_edge_t edge; + cairo_bo_edge_t *prev; + cairo_bo_edge_t *next; + cairo_bo_deferred_t deferred; +}; + +/* the parent is always given by index/2 */ +#define PQ_PARENT_INDEX(i) ((i) >> 1) +#define PQ_FIRST_ENTRY 1 + +/* left and right children are index * 2 and (index * 2) +1 respectively */ +#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1) + +typedef enum { + CAIRO_BO_EVENT_TYPE_STOP, + CAIRO_BO_EVENT_TYPE_INTERSECTION, + CAIRO_BO_EVENT_TYPE_START +} cairo_bo_event_type_t; + +typedef struct _cairo_bo_event { + cairo_bo_event_type_t type; + cairo_point_t point; +} cairo_bo_event_t; + +typedef struct _cairo_bo_start_event { + cairo_bo_event_type_t type; + cairo_point_t point; + cairo_bo_edge_t edge; +} cairo_bo_start_event_t; + +typedef struct _cairo_bo_queue_event { + cairo_bo_event_type_t type; + cairo_point_t point; + cairo_bo_edge_t *e1; + cairo_bo_edge_t *e2; +} cairo_bo_queue_event_t; + +typedef struct _pqueue { + int size, max_size; + + cairo_bo_event_t **elements; + cairo_bo_event_t *elements_embedded[1024]; +} pqueue_t; + +typedef struct _cairo_bo_event_queue { + cairo_freepool_t pool; + pqueue_t pqueue; + cairo_bo_event_t **start_events; +} cairo_bo_event_queue_t; + +typedef struct _cairo_bo_sweep_line { + cairo_bo_edge_t *head; + cairo_bo_edge_t *stopped; + int32_t current_y; + cairo_bo_edge_t *current_edge; +} cairo_bo_sweep_line_t; + +static cairo_fixed_t +_line_compute_intersection_x_for_y (const cairo_line_t *line, + cairo_fixed_t y) +{ + cairo_fixed_t x, dy; + + if (y == line->p1.y) + return line->p1.x; + if (y == line->p2.y) + return line->p2.x; + + x = line->p1.x; + dy = line->p2.y - line->p1.y; + if (dy != 0) { + x += _cairo_fixed_mul_div_floor (y - line->p1.y, + line->p2.x - line->p1.x, + dy); + } + + return x; +} + +static inline int +_cairo_bo_point32_compare (cairo_bo_point32_t const *a, + cairo_bo_point32_t const *b) +{ + int cmp; + + cmp = a->y - b->y; + if (cmp) + return cmp; + + return a->x - b->x; +} + +/* Compare the slope of a to the slope of b, returning 1, 0, -1 if the + * slope a is respectively greater than, equal to, or less than the + * slope of b. + * + * For each edge, consider the direction vector formed from: + * + * top -> bottom + * + * which is: + * + * (dx, dy) = (line.p2.x - line.p1.x, line.p2.y - line.p1.y) + * + * We then define the slope of each edge as dx/dy, (which is the + * inverse of the slope typically used in math instruction). We never + * compute a slope directly as the value approaches infinity, but we + * can derive a slope comparison without division as follows, (where + * the ? represents our compare operator). + * + * 1. slope(a) ? slope(b) + * 2. adx/ady ? bdx/bdy + * 3. (adx * bdy) ? (bdx * ady) + * + * Note that from step 2 to step 3 there is no change needed in the + * sign of the result since both ady and bdy are guaranteed to be + * greater than or equal to 0. + * + * When using this slope comparison to sort edges, some care is needed + * when interpreting the results. Since the slope compare operates on + * distance vectors from top to bottom it gives a correct left to + * right sort for edges that have a common top point, (such as two + * edges with start events at the same location). On the other hand, + * the sense of the result will be exactly reversed for two edges that + * have a common stop point. + */ +static inline int +_slope_compare (const cairo_bo_edge_t *a, + const cairo_bo_edge_t *b) +{ + /* 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 adx = a->edge.line.p2.x - a->edge.line.p1.x; + int32_t bdx = b->edge.line.p2.x - b->edge.line.p1.x; + + /* Since the dy's are all positive by construction we can fast + * path several common cases. + */ + + /* First check for vertical lines. */ + if (adx == 0) + return -bdx; + if (bdx == 0) + return adx; + + /* Then where the two edges point in different directions wrt x. */ + if ((adx ^ bdx) < 0) + return adx; + + /* Finally we actually need to do the general comparison. */ + { + int32_t ady = a->edge.line.p2.y - a->edge.line.p1.y; + int32_t bdy = b->edge.line.p2.y - b->edge.line.p1.y; + cairo_int64_t adx_bdy = _cairo_int32x32_64_mul (adx, bdy); + cairo_int64_t bdx_ady = _cairo_int32x32_64_mul (bdx, ady); + + return _cairo_int64_cmp (adx_bdy, bdx_ady); + } +} + +/* + * 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 + * given x, 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 ∘ X + * where ∘ is our inequality operator. + * + * By construction, we know that A_dy (and (Y - A_y)) are + * all positive, so we can rearrange it thus without causing a sign change: + * (Y - A_y) * A_dx ∘ (X - A_x) * A_dy + * + * Given the assumption that all the deltas fit within 32 bits, we can compute + * this comparison directly using 64 bit arithmetic. + * + * See the similar discussion for _slope_compare() and + * edges_compare_x_for_y_general(). + */ +static int +edge_compare_for_y_against_x (const cairo_bo_edge_t *a, + int32_t y, + int32_t x) +{ + int32_t adx, ady; + int32_t dx, dy; + cairo_int64_t L, R; + + if (x < a->edge.line.p1.x && x < a->edge.line.p2.x) + return 1; + if (x > a->edge.line.p1.x && x > a->edge.line.p2.x) + return -1; + + adx = a->edge.line.p2.x - a->edge.line.p1.x; + dx = x - a->edge.line.p1.x; + + if (adx == 0) + return -dx; + if (dx == 0 || (adx ^ dx) < 0) + return adx; + + dy = y - a->edge.line.p1.y; + ady = a->edge.line.p2.y - a->edge.line.p1.y; + + L = _cairo_int32x32_64_mul (dy, adx); + R = _cairo_int32x32_64_mul (dx, ady); + + 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 int +_cairo_bo_sweep_line_compare_edges (cairo_bo_sweep_line_t *sweep_line, + const cairo_bo_edge_t *a, + const cairo_bo_edge_t *b) +{ + int cmp; + + /* compare the edges if not identical */ + if (! _line_equal (&a->edge.line, &b->edge.line)) { + 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) + return cmp; + } + + /* We've got two collinear edges now. */ + return b->edge.bottom - a->edge.bottom; +} + +static inline cairo_int64_t +det32_64 (int32_t a, int32_t b, + int32_t c, int32_t d) +{ + /* det = a * d - b * c */ + return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d), + _cairo_int32x32_64_mul (b, c)); +} + +static inline cairo_int128_t +det64x32_128 (cairo_int64_t a, int32_t b, + cairo_int64_t c, int32_t d) +{ + /* det = a * d - b * c */ + return _cairo_int128_sub (_cairo_int64x32_128_mul (a, d), + _cairo_int64x32_128_mul (c, b)); +} + +/* Compute the intersection of two lines as defined by two edges. The + * result is provided as a coordinate pair of 128-bit integers. + * + * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or + * %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel. + */ +static cairo_bool_t +intersect_lines (cairo_bo_edge_t *a, + cairo_bo_edge_t *b, + cairo_bo_intersect_point_t *intersection) +{ + cairo_int64_t a_det, b_det; + + /* 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. + * What we're doing to mitigate this is to perform clamping in + * cairo_bo_tessellate_polygon(). + */ + int32_t dx1 = a->edge.line.p1.x - a->edge.line.p2.x; + int32_t dy1 = a->edge.line.p1.y - a->edge.line.p2.y; + + int32_t dx2 = b->edge.line.p1.x - b->edge.line.p2.x; + int32_t dy2 = b->edge.line.p1.y - b->edge.line.p2.y; + + cairo_int64_t den_det; + cairo_int64_t R; + cairo_quorem64_t qr; + + den_det = det32_64 (dx1, dy1, dx2, dy2); + + /* Q: Can we determine that the lines do not intersect (within range) + * much more cheaply than computing the intersection point i.e. by + * avoiding the division? + * + * X = ax + t * adx = bx + s * bdx; + * Y = ay + t * ady = by + s * bdy; + * ∴ t * (ady*bdx - bdy*adx) = bdx * (by - ay) + bdy * (ax - bx) + * => t * L = R + * + * Therefore we can reject any intersection (under the criteria for + * valid intersection events) if: + * L^R < 0 => t < 0, or + * L<R => t > 1 + * + * (where top/bottom must at least extend to the line endpoints). + * + * A similar substitution can be performed for s, yielding: + * s * (ady*bdx - bdy*adx) = ady * (ax - bx) - adx * (ay - by) + */ + R = det32_64 (dx2, dy2, + b->edge.line.p1.x - a->edge.line.p1.x, + b->edge.line.p1.y - a->edge.line.p1.y); + if (_cairo_int64_negative (den_det)) { + if (_cairo_int64_ge (den_det, R)) + return FALSE; + } else { + if (_cairo_int64_le (den_det, R)) + return FALSE; + } + + R = det32_64 (dy1, dx1, + a->edge.line.p1.y - b->edge.line.p1.y, + a->edge.line.p1.x - b->edge.line.p1.x); + if (_cairo_int64_negative (den_det)) { + if (_cairo_int64_ge (den_det, R)) + return FALSE; + } else { + if (_cairo_int64_le (den_det, R)) + return FALSE; + } + + /* We now know that the two lines should intersect within range. */ + + a_det = det32_64 (a->edge.line.p1.x, a->edge.line.p1.y, + a->edge.line.p2.x, a->edge.line.p2.y); + b_det = det32_64 (b->edge.line.p1.x, b->edge.line.p1.y, + b->edge.line.p2.x, b->edge.line.p2.y); + + /* x = det (a_det, dx1, b_det, dx2) / den_det */ + qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dx1, + b_det, dx2), + den_det); + if (_cairo_int64_eq (qr.rem, den_det)) + return FALSE; +#if 0 + intersection->x.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT; +#else + intersection->x.exactness = EXACT; + if (! _cairo_int64_is_zero (qr.rem)) { + if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem)) + qr.rem = _cairo_int64_negate (qr.rem); + qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2)); + if (_cairo_int64_ge (qr.rem, den_det)) { + qr.quo = _cairo_int64_add (qr.quo, + _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1)); + } else + intersection->x.exactness = INEXACT; + } +#endif + intersection->x.ordinate = _cairo_int64_to_int32 (qr.quo); + + /* y = det (a_det, dy1, b_det, dy2) / den_det */ + qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dy1, + b_det, dy2), + den_det); + if (_cairo_int64_eq (qr.rem, den_det)) + return FALSE; +#if 0 + intersection->y.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT; +#else + intersection->y.exactness = EXACT; + if (! _cairo_int64_is_zero (qr.rem)) { + if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem)) + qr.rem = _cairo_int64_negate (qr.rem); + qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2)); + if (_cairo_int64_ge (qr.rem, den_det)) { + qr.quo = _cairo_int64_add (qr.quo, + _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1)); + } else + intersection->y.exactness = INEXACT; + } +#endif + intersection->y.ordinate = _cairo_int64_to_int32 (qr.quo); + + return TRUE; +} + +static int +_cairo_bo_intersect_ordinate_32_compare (cairo_bo_intersect_ordinate_t a, + int32_t b) +{ + /* First compare the quotient */ + if (a.ordinate > b) + return +1; + if (a.ordinate < b) + return -1; + /* With quotient identical, if remainder is 0 then compare equal */ + /* Otherwise, the non-zero remainder makes a > b */ + return INEXACT == a.exactness; +} + +/* Does the given edge contain the given point. The point must already + * be known to be contained within the line determined by the edge, + * (most likely the point results from an intersection of this edge + * with another). + * + * If we had exact arithmetic, then this function would simply be a + * matter of examining whether the y value of the point lies within + * the range of y values of the edge. But since intersection points + * are not exact due to being rounded to the nearest integer within + * the available precision, we must also examine the x value of the + * point. + * + * The definition of "contains" here is that the given intersection + * point will be seen by the sweep line after the start event for the + * given edge and before the stop event for the edge. See the comments + * in the implementation for more details. + */ +static cairo_bool_t +_cairo_bo_edge_contains_intersect_point (cairo_bo_edge_t *edge, + cairo_bo_intersect_point_t *point) +{ + int cmp_top, cmp_bottom; + + /* XXX: When running the actual algorithm, we don't actually need to + * compare against edge->top at all here, since any intersection above + * top is eliminated early via a slope comparison. We're leaving these + * here for now only for the sake of the quadratic-time intersection + * finder which needs them. + */ + + cmp_top = _cairo_bo_intersect_ordinate_32_compare (point->y, + edge->edge.top); + cmp_bottom = _cairo_bo_intersect_ordinate_32_compare (point->y, + edge->edge.bottom); + + if (cmp_top < 0 || cmp_bottom > 0) + { + return FALSE; + } + + if (cmp_top > 0 && cmp_bottom < 0) + { + return TRUE; + } + + /* At this stage, the point lies on the same y value as either + * edge->top or edge->bottom, so we have to examine the x value in + * order to properly determine containment. */ + + /* If the y value of the point is the same as the y value of the + * top of the edge, then the x value of the point must be greater + * to be considered as inside the edge. Similarly, if the y value + * of the point is the same as the y value of the bottom of the + * edge, then the x value of the point must be less to be + * considered as inside. */ + + if (cmp_top == 0) { + cairo_fixed_t top_x; + + top_x = _line_compute_intersection_x_for_y (&edge->edge.line, + edge->edge.top); + return _cairo_bo_intersect_ordinate_32_compare (point->x, top_x) > 0; + } else { /* cmp_bottom == 0 */ + cairo_fixed_t bot_x; + + bot_x = _line_compute_intersection_x_for_y (&edge->edge.line, + edge->edge.bottom); + return _cairo_bo_intersect_ordinate_32_compare (point->x, bot_x) < 0; + } +} + +/* Compute the intersection of two edges. The result is provided as a + * coordinate pair of 128-bit integers. + * + * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection + * that is within both edges, %CAIRO_BO_STATUS_NO_INTERSECTION if the + * intersection of the lines defined by the edges occurs outside of + * one or both edges, and %CAIRO_BO_STATUS_PARALLEL if the two edges + * are exactly parallel. + * + * Note that when determining if a candidate intersection is "inside" + * an edge, we consider both the infinitesimal shortening and the + * infinitesimal tilt rules described by John Hobby. Specifically, if + * the intersection is exactly the same as an edge point, it is + * effectively outside (no intersection is returned). Also, if the + * intersection point has the same + */ +static cairo_bool_t +_cairo_bo_edge_intersect (cairo_bo_edge_t *a, + cairo_bo_edge_t *b, + cairo_bo_point32_t *intersection) +{ + cairo_bo_intersect_point_t quorem; + + if (! intersect_lines (a, b, &quorem)) + return FALSE; + + if (! _cairo_bo_edge_contains_intersect_point (a, &quorem)) + return FALSE; + + if (! _cairo_bo_edge_contains_intersect_point (b, &quorem)) + return FALSE; + + /* Now that we've correctly compared the intersection point and + * determined that it lies within the edge, then we know that we + * no longer need any more bits of storage for the intersection + * than we do for our edge coordinates. We also no longer need the + * remainder from the division. */ + intersection->x = quorem.x.ordinate; + intersection->y = quorem.y.ordinate; + + return TRUE; +} + +static inline int +cairo_bo_event_compare (const cairo_bo_event_t *a, + const cairo_bo_event_t *b) +{ + int cmp; + + cmp = _cairo_bo_point32_compare (&a->point, &b->point); + if (cmp) + return cmp; + + cmp = a->type - b->type; + if (cmp) + return cmp; + + return a - b; +} + +static inline void +_pqueue_init (pqueue_t *pq) +{ + pq->max_size = ARRAY_LENGTH (pq->elements_embedded); + pq->size = 0; + + pq->elements = pq->elements_embedded; +} + +static inline void +_pqueue_fini (pqueue_t *pq) +{ + if (pq->elements != pq->elements_embedded) + free (pq->elements); +} + +static cairo_status_t +_pqueue_grow (pqueue_t *pq) +{ + cairo_bo_event_t **new_elements; + pq->max_size *= 2; + + if (pq->elements == pq->elements_embedded) { + new_elements = _cairo_malloc_ab (pq->max_size, + sizeof (cairo_bo_event_t *)); + if (unlikely (new_elements == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (new_elements, pq->elements_embedded, + sizeof (pq->elements_embedded)); + } else { + new_elements = _cairo_realloc_ab (pq->elements, + pq->max_size, + sizeof (cairo_bo_event_t *)); + if (unlikely (new_elements == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + pq->elements = new_elements; + return CAIRO_STATUS_SUCCESS; +} + +static inline cairo_status_t +_pqueue_push (pqueue_t *pq, cairo_bo_event_t *event) +{ + cairo_bo_event_t **elements; + int i, parent; + + if (unlikely (pq->size + 1 == pq->max_size)) { + cairo_status_t status; + + status = _pqueue_grow (pq); + if (unlikely (status)) + return status; + } + + elements = pq->elements; + + for (i = ++pq->size; + i != PQ_FIRST_ENTRY && + cairo_bo_event_compare (event, + elements[parent = PQ_PARENT_INDEX (i)]) < 0; + i = parent) + { + elements[i] = elements[parent]; + } + + elements[i] = event; + + return CAIRO_STATUS_SUCCESS; +} + +static inline void +_pqueue_pop (pqueue_t *pq) +{ + cairo_bo_event_t **elements = pq->elements; + cairo_bo_event_t *tail; + int child, i; + + tail = elements[pq->size--]; + if (pq->size == 0) { + elements[PQ_FIRST_ENTRY] = NULL; + return; + } + + for (i = PQ_FIRST_ENTRY; + (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size; + i = child) + { + if (child != pq->size && + cairo_bo_event_compare (elements[child+1], + elements[child]) < 0) + { + child++; + } + + if (cairo_bo_event_compare (elements[child], tail) >= 0) + break; + + elements[i] = elements[child]; + } + elements[i] = tail; +} + +static inline cairo_status_t +_cairo_bo_event_queue_insert (cairo_bo_event_queue_t *queue, + cairo_bo_event_type_t type, + cairo_bo_edge_t *e1, + cairo_bo_edge_t *e2, + const cairo_point_t *point) +{ + cairo_bo_queue_event_t *event; + + event = _cairo_freepool_alloc (&queue->pool); + if (unlikely (event == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + event->type = type; + event->e1 = e1; + event->e2 = e2; + event->point = *point; + + return _pqueue_push (&queue->pqueue, (cairo_bo_event_t *) event); +} + +static void +_cairo_bo_event_queue_delete (cairo_bo_event_queue_t *queue, + cairo_bo_event_t *event) +{ + _cairo_freepool_free (&queue->pool, event); +} + +static cairo_bo_event_t * +_cairo_bo_event_dequeue (cairo_bo_event_queue_t *event_queue) +{ + cairo_bo_event_t *event, *cmp; + + event = event_queue->pqueue.elements[PQ_FIRST_ENTRY]; + cmp = *event_queue->start_events; + if (event == NULL || + (cmp != NULL && cairo_bo_event_compare (cmp, event) < 0)) + { + event = cmp; + event_queue->start_events++; + } + else + { + _pqueue_pop (&event_queue->pqueue); + } + + return event; +} + +CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort, + cairo_bo_event_t *, + cairo_bo_event_compare) + +static void +_cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue, + cairo_bo_event_t **start_events, + int num_events) +{ + _cairo_bo_event_queue_sort (start_events, num_events); + start_events[num_events] = NULL; + + event_queue->start_events = start_events; + + _cairo_freepool_init (&event_queue->pool, + sizeof (cairo_bo_queue_event_t)); + _pqueue_init (&event_queue->pqueue); + event_queue->pqueue.elements[PQ_FIRST_ENTRY] = NULL; +} + +static cairo_status_t +_cairo_bo_event_queue_insert_stop (cairo_bo_event_queue_t *event_queue, + cairo_bo_edge_t *edge) +{ + cairo_bo_point32_t point; + + point.y = edge->edge.bottom; + point.x = _line_compute_intersection_x_for_y (&edge->edge.line, + point.y); + return _cairo_bo_event_queue_insert (event_queue, + CAIRO_BO_EVENT_TYPE_STOP, + edge, NULL, + &point); +} + +static void +_cairo_bo_event_queue_fini (cairo_bo_event_queue_t *event_queue) +{ + _pqueue_fini (&event_queue->pqueue); + _cairo_freepool_fini (&event_queue->pool); +} + +static inline cairo_status_t +_cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_t *event_queue, + cairo_bo_edge_t *left, + cairo_bo_edge_t *right) +{ + cairo_bo_point32_t intersection; + + if (_line_equal (&left->edge.line, &right->edge.line)) + return CAIRO_STATUS_SUCCESS; + + /* The names "left" and "right" here are correct descriptions of + * the order of the two edges within the active edge list. So if a + * slope comparison also puts left less than right, then we know + * that the intersection of these two segments has already + * occurred before the current sweep line position. */ + if (_slope_compare (left, right) <= 0) + return CAIRO_STATUS_SUCCESS; + + if (! _cairo_bo_edge_intersect (left, right, &intersection)) + return CAIRO_STATUS_SUCCESS; + + return _cairo_bo_event_queue_insert (event_queue, + CAIRO_BO_EVENT_TYPE_INTERSECTION, + left, right, + &intersection); +} + +static void +_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line) +{ + sweep_line->head = NULL; + sweep_line->stopped = NULL; + sweep_line->current_y = INT32_MIN; + sweep_line->current_edge = NULL; +} + +static cairo_status_t +_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line, + cairo_bo_edge_t *edge) +{ + if (sweep_line->current_edge != NULL) { + cairo_bo_edge_t *prev, *next; + int cmp; + + cmp = _cairo_bo_sweep_line_compare_edges (sweep_line, + sweep_line->current_edge, + edge); + if (cmp < 0) { + prev = sweep_line->current_edge; + next = prev->next; + while (next != NULL && + _cairo_bo_sweep_line_compare_edges (sweep_line, + next, edge) < 0) + { + prev = next, next = prev->next; + } + + prev->next = edge; + edge->prev = prev; + edge->next = next; + if (next != NULL) + next->prev = edge; + } else if (cmp > 0) { + next = sweep_line->current_edge; + prev = next->prev; + while (prev != NULL && + _cairo_bo_sweep_line_compare_edges (sweep_line, + prev, edge) > 0) + { + next = prev, prev = next->prev; + } + + next->prev = edge; + edge->next = next; + edge->prev = prev; + if (prev != NULL) + prev->next = edge; + else + sweep_line->head = edge; + } else { + prev = sweep_line->current_edge; + edge->prev = prev; + edge->next = prev->next; + if (prev->next != NULL) + prev->next->prev = edge; + prev->next = edge; + } + } else { + sweep_line->head = edge; + } + + sweep_line->current_edge = edge; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line, + cairo_bo_edge_t *edge) +{ + if (edge->prev != NULL) + edge->prev->next = edge->next; + else + sweep_line->head = edge->next; + + if (edge->next != NULL) + edge->next->prev = edge->prev; + + if (sweep_line->current_edge == edge) + sweep_line->current_edge = edge->prev ? edge->prev : edge->next; +} + +static void +_cairo_bo_sweep_line_swap (cairo_bo_sweep_line_t *sweep_line, + cairo_bo_edge_t *left, + cairo_bo_edge_t *right) +{ + if (left->prev != NULL) + left->prev->next = right; + else + sweep_line->head = right; + + if (right->next != NULL) + right->next->prev = left; + + left->next = right->next; + right->next = left; + + right->prev = left->prev; + left->prev = right; +} + +static inline cairo_bool_t +edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b) +{ + if (_line_equal (&a->edge.line, &b->edge.line)) + return TRUE; + + if (_slope_compare (a, b)) + return FALSE; + + /* The choice of y is not truly arbitrary since we must guarantee that it + * is greater than the start of either line. + */ + if (a->edge.line.p1.y == b->edge.line.p1.y) { + return a->edge.line.p1.x == b->edge.line.p1.x; + } else if (a->edge.line.p1.y < b->edge.line.p1.y) { + return edge_compare_for_y_against_x (b, + a->edge.line.p1.y, + a->edge.line.p1.x) == 0; + } else { + return edge_compare_for_y_against_x (a, + b->edge.line.p1.y, + b->edge.line.p1.x) == 0; + } +} + +static void +_cairo_bo_edge_end (cairo_bo_edge_t *left, + int32_t bot, + cairo_polygon_t *polygon) +{ + cairo_bo_deferred_t *d = &left->deferred; + + if (likely (d->top < bot)) { + _cairo_polygon_add_line (polygon, + &left->edge.line, + d->top, bot, + 1); + _cairo_polygon_add_line (polygon, + &d->right->edge.line, + d->top, bot, + -1); + } + + d->right = NULL; +} + + +static inline void +_cairo_bo_edge_start_or_continue (cairo_bo_edge_t *left, + cairo_bo_edge_t *right, + int top, + cairo_polygon_t *polygon) +{ + if (left->deferred.right == right) + return; + + if (left->deferred.right != NULL) { + if (right != NULL && edges_colinear (left->deferred.right, right)) + { + /* continuation on right, so just swap edges */ + left->deferred.right = right; + return; + } + + _cairo_bo_edge_end (left, top, polygon); + } + + if (right != NULL && ! edges_colinear (left, right)) { + left->deferred.top = top; + left->deferred.right = right; + } +} + +static inline void +_active_edges_to_polygon (cairo_bo_edge_t *left, + int32_t top, + cairo_fill_rule_t fill_rule, + cairo_polygon_t *polygon) +{ + cairo_bo_edge_t *right; + + if (fill_rule == CAIRO_FILL_RULE_WINDING) { + while (left != NULL) { + int in_out = left->edge.dir; + + right = left->next; + if (left->deferred.right == NULL) { + while (right != NULL && right->deferred.right == NULL) + right = right->next; + + if (right != NULL && edges_colinear (left, right)) { + /* continuation on left */ + left->deferred = right->deferred; + right->deferred.right = NULL; + } + } + + right = left->next; + while (right != NULL) { + if (right->deferred.right != NULL) + _cairo_bo_edge_end (right, top, polygon); + + in_out += right->edge.dir; + if (in_out == 0) { + cairo_bo_edge_t *next; + cairo_bool_t skip = FALSE; + + /* skip co-linear edges */ + next = right->next; + if (next != NULL) + skip = edges_colinear (right, next); + + if (! skip) + break; + } + + right = right->next; + } + + _cairo_bo_edge_start_or_continue (left, right, top, polygon); + + left = right; + if (left != NULL) + left = left->next; + } + } else { + while (left != NULL) { + int in_out = 0; + + right = left->next; + while (right != NULL) { + if (right->deferred.right != NULL) + _cairo_bo_edge_end (right, top, polygon); + + if ((in_out++ & 1) == 0) { + cairo_bo_edge_t *next; + cairo_bool_t skip = FALSE; + + /* skip co-linear edges */ + next = right->next; + if (next != NULL) + skip = edges_colinear (right, next); + + if (! skip) + break; + } + + right = right->next; + } + + _cairo_bo_edge_start_or_continue (left, right, top, polygon); + + left = right; + if (left != NULL) + left = left->next; + } + } +} + + +static cairo_status_t +_cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t **start_events, + int num_events, + cairo_fill_rule_t fill_rule, + cairo_polygon_t *polygon) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; /* silence compiler */ + cairo_bo_event_queue_t event_queue; + cairo_bo_sweep_line_t sweep_line; + cairo_bo_event_t *event; + cairo_bo_edge_t *left, *right; + cairo_bo_edge_t *e1, *e2; + + _cairo_bo_event_queue_init (&event_queue, start_events, num_events); + _cairo_bo_sweep_line_init (&sweep_line); + + while ((event = _cairo_bo_event_dequeue (&event_queue))) { + if (event->point.y != sweep_line.current_y) { + for (e1 = sweep_line.stopped; e1; e1 = e1->next) { + if (e1->deferred.right != NULL) + _cairo_bo_edge_end (e1, e1->edge.bottom, polygon); + } + sweep_line.stopped = NULL; + + _active_edges_to_polygon (sweep_line.head, + sweep_line.current_y, + fill_rule, polygon); + + sweep_line.current_y = event->point.y; + } + + switch (event->type) { + case CAIRO_BO_EVENT_TYPE_START: + e1 = &((cairo_bo_start_event_t *) event)->edge; + + status = _cairo_bo_sweep_line_insert (&sweep_line, e1); + if (unlikely (status)) + goto unwind; + + status = _cairo_bo_event_queue_insert_stop (&event_queue, e1); + if (unlikely (status)) + goto unwind; + + /* check to see if this is a continuation of a stopped edge */ + /* XXX change to an infinitesimal lengthening rule */ + for (left = sweep_line.stopped; left; left = left->next) { + if (e1->edge.top <= left->edge.bottom && + edges_colinear (e1, left)) + { + e1->deferred = left->deferred; + if (left->prev != NULL) + left->prev = left->next; + else + sweep_line.stopped = left->next; + if (left->next != NULL) + left->next->prev = left->prev; + break; + } + } + + left = e1->prev; + right = e1->next; + + if (left != NULL) { + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, e1); + if (unlikely (status)) + goto unwind; + } + + if (right != NULL) { + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right); + if (unlikely (status)) + goto unwind; + } + + break; + + case CAIRO_BO_EVENT_TYPE_STOP: + e1 = ((cairo_bo_queue_event_t *) event)->e1; + _cairo_bo_event_queue_delete (&event_queue, event); + + left = e1->prev; + right = e1->next; + + _cairo_bo_sweep_line_delete (&sweep_line, e1); + + /* first, check to see if we have a continuation via a fresh edge */ + if (e1->deferred.right != NULL) { + e1->next = sweep_line.stopped; + if (sweep_line.stopped != NULL) + sweep_line.stopped->prev = e1; + sweep_line.stopped = e1; + e1->prev = NULL; + } + + if (left != NULL && right != NULL) { + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, right); + if (unlikely (status)) + goto unwind; + } + + break; + + case CAIRO_BO_EVENT_TYPE_INTERSECTION: + e1 = ((cairo_bo_queue_event_t *) event)->e1; + e2 = ((cairo_bo_queue_event_t *) event)->e2; + _cairo_bo_event_queue_delete (&event_queue, event); + + /* skip this intersection if its edges are not adjacent */ + if (e2 != e1->next) + break; + + left = e1->prev; + right = e2->next; + + _cairo_bo_sweep_line_swap (&sweep_line, e1, e2); + + /* after the swap e2 is left of e1 */ + + if (left != NULL) { + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, e2); + if (unlikely (status)) + goto unwind; + } + + if (right != NULL) { + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right); + if (unlikely (status)) + goto unwind; + } + + break; + } + } + + for (e1 = sweep_line.stopped; e1; e1 = e1->next) { + if (e1->deferred.right != NULL) + _cairo_bo_edge_end (e1, e1->edge.bottom, polygon); + } + unwind: + _cairo_bo_event_queue_fini (&event_queue); + + return status; +} + +cairo_status_t +_cairo_polygon_reduce (cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule) +{ + cairo_status_t status; + cairo_bo_start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_start_event_t)]; + cairo_bo_start_event_t *events; + cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1]; + cairo_bo_event_t **event_ptrs; + int num_limits; + int num_events; + int i; + + num_events = polygon->num_edges; + if (unlikely (0 == num_events)) + return CAIRO_STATUS_SUCCESS; + + events = stack_events; + event_ptrs = stack_event_ptrs; + if (num_events > ARRAY_LENGTH (stack_events)) { + events = _cairo_malloc_ab_plus_c (num_events, + sizeof (cairo_bo_start_event_t) + + sizeof (cairo_bo_event_t *), + sizeof (cairo_bo_event_t *)); + if (unlikely (events == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + event_ptrs = (cairo_bo_event_t **) (events + num_events); + } + + for (i = 0; i < num_events; i++) { + event_ptrs[i] = (cairo_bo_event_t *) &events[i]; + + events[i].type = CAIRO_BO_EVENT_TYPE_START; + events[i].point.y = polygon->edges[i].top; + events[i].point.x = + _line_compute_intersection_x_for_y (&polygon->edges[i].line, + events[i].point.y); + + events[i].edge.edge = polygon->edges[i]; + events[i].edge.deferred.right = NULL; + events[i].edge.prev = NULL; + events[i].edge.next = NULL; + } + + num_limits = polygon->num_limits; polygon->num_limits = 0; + polygon->num_edges = 0; + + status = _cairo_bentley_ottmann_tessellate_bo_edges (event_ptrs, + num_events, + fill_rule, + polygon); + polygon->num_limits = num_limits; + + if (events != stack_events) + free (events); + + return status; +} diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c index c3f3631d8..cc9faae93 100644 --- a/src/cairo-polygon.c +++ b/src/cairo-polygon.c @@ -37,8 +37,14 @@ #include "cairoint.h" +#include "cairo-boxes-private.h" #include "cairo-error-private.h" +static void +_cairo_polygon_add_edge (cairo_polygon_t *polygon, + const cairo_point_t *p1, + const cairo_point_t *p2); + void _cairo_polygon_init (cairo_polygon_t *polygon, const cairo_box_t *limits, @@ -80,6 +86,111 @@ _cairo_polygon_init (cairo_polygon_t *polygon, } void +_cairo_polygon_init_with_clip (cairo_polygon_t *polygon, + const cairo_clip_t *clip) +{ + if (clip) + _cairo_polygon_init (polygon, clip->boxes, clip->num_boxes); + else + _cairo_polygon_init (polygon, 0, 0); +} + +cairo_status_t +_cairo_polygon_init_boxes (cairo_polygon_t *polygon, + const cairo_boxes_t *boxes) +{ + const struct _cairo_boxes_chunk *chunk; + int i; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t))); + + polygon->status = CAIRO_STATUS_SUCCESS; + + polygon->num_edges = 0; + + polygon->edges = polygon->edges_embedded; + polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded); + if (boxes->num_boxes > ARRAY_LENGTH (polygon->edges_embedded)/2) { + polygon->edges_size = 2 * boxes->num_boxes; + polygon->edges = _cairo_malloc_ab (polygon->edges_size, + 2*sizeof(cairo_edge_t)); + if (unlikely (polygon->edges == NULL)) + return polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX; + polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN; + + polygon->limits = NULL; + polygon->num_limits = 0; + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + cairo_point_t p1, p2; + + p1 = chunk->base[i].p1; + p2.x = p1.x; + p2.y = chunk->base[i].p2.y; + _cairo_polygon_add_edge (polygon, &p1, &p2); + + p1 = chunk->base[i].p2; + p2.x = p1.x; + p2.y = chunk->base[i].p1.y; + _cairo_polygon_add_edge (polygon, &p1, &p2); + } + } + + return polygon->status; +} + +cairo_status_t +_cairo_polygon_init_box_array (cairo_polygon_t *polygon, + cairo_box_t *boxes, + int num_boxes) +{ + int i; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t))); + + polygon->status = CAIRO_STATUS_SUCCESS; + + polygon->num_edges = 0; + + polygon->edges = polygon->edges_embedded; + polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded); + if (num_boxes > ARRAY_LENGTH (polygon->edges_embedded)/2) { + polygon->edges_size = 2 * num_boxes; + polygon->edges = _cairo_malloc_ab (polygon->edges_size, + 2*sizeof(cairo_edge_t)); + if (unlikely (polygon->edges == NULL)) + return polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX; + polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN; + + polygon->limits = NULL; + polygon->num_limits = 0; + + for (i = 0; i < num_boxes; i++) { + cairo_point_t p1, p2; + + p1 = boxes[i].p1; + p2.x = p1.x; + p2.y = boxes[i].p2.y; + _cairo_polygon_add_edge (polygon, &p1, &p2); + + p1 = boxes[i].p2; + p2.x = p1.x; + p2.y = boxes[i].p1.y; + _cairo_polygon_add_edge (polygon, &p1, &p2); + } + + return polygon->status; +} + + +void _cairo_polygon_fini (cairo_polygon_t *polygon) { if (polygon->edges != polygon->edges_embedded) diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 0b5f8e975..80ad47473 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -572,7 +572,7 @@ _cairo_ps_emit_imagemask (cairo_image_surface_t *image, return _cairo_output_stream_get_status (stream); } -static cairo_status_t +static cairo_int_status_t _cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset, void *closure) { @@ -704,16 +704,15 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface, return CAIRO_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _cairo_ps_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset, void *closure) { cairo_ps_surface_t *surface = closure; - cairo_status_t status; - + cairo_int_status_t status; status = _cairo_scaled_font_subset_create_glyph_names (font_subset); - if (_cairo_status_is_error (status)) + if (_cairo_int_status_is_error (status)) return status; status = _cairo_ps_surface_emit_type1_font_subset (surface, font_subset); @@ -732,15 +731,15 @@ _cairo_ps_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_su return CAIRO_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _cairo_ps_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset, void *closure) { cairo_ps_surface_t *surface = closure; - cairo_status_t status; + cairo_int_status_t status; status = _cairo_scaled_font_subset_create_glyph_names (font_subset); - if (_cairo_status_is_error (status)) + if (_cairo_int_status_is_error (status)) return status; status = _cairo_ps_surface_emit_type3_font_subset (surface, font_subset); @@ -748,7 +747,7 @@ _cairo_ps_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subs return status; ASSERT_NOT_REACHED; - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } static cairo_status_t @@ -1640,7 +1639,7 @@ _cairo_ps_surface_end_page (cairo_ps_surface_t *surface) if (unlikely (status)) return status; - if (surface->clipper.clip.path != NULL) { + if (surface->clipper.clip != NULL) { _cairo_output_stream_printf (surface->stream, "Q Q\n"); _cairo_surface_clipper_reset (&surface->clipper); } else @@ -2444,7 +2443,7 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface, cairo_content_t old_content; cairo_rectangle_int_t old_page_bbox; cairo_box_t bbox; - cairo_status_t status; + cairo_int_status_t status; old_content = surface->content; old_width = surface->width; @@ -2516,7 +2515,7 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface, return CAIRO_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t *surface, cairo_surface_t *recording_surface, const cairo_rectangle_int_t *extents) @@ -2525,7 +2524,7 @@ _cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t *surface, cairo_matrix_t old_cairo_to_ps; cairo_content_t old_content; cairo_rectangle_int_t old_page_bbox; - cairo_status_t status; + cairo_int_status_t status; old_content = surface->content; old_width = surface->width; @@ -2733,7 +2732,7 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface, int width, int height) { - cairo_status_t status; + cairo_int_status_t status; if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { cairo_surface_t *source = pattern->surface; @@ -3576,7 +3575,7 @@ static cairo_int_status_t _cairo_ps_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_ps_surface_t *surface = abstract_surface; cairo_output_stream_t *stream = surface->stream; @@ -3635,13 +3634,13 @@ static cairo_int_status_t _cairo_ps_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_ps_surface_t *surface = abstract_surface; cairo_composite_rectangles_t extents; @@ -3699,11 +3698,11 @@ static cairo_int_status_t _cairo_ps_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t*path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_ps_surface_t *surface = abstract_surface; cairo_composite_rectangles_t extents; @@ -3786,7 +3785,7 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs) { cairo_ps_surface_t *surface = abstract_surface; @@ -3840,7 +3839,7 @@ _cairo_ps_surface_set_paginated_mode (void *abstract_surface, surface->paginated_mode = paginated_mode; - if (surface->clipper.clip.path != NULL) { + if (surface->clipper.clip != NULL) { status = _cairo_pdf_operators_flush (&surface->pdf_operators); _cairo_output_stream_printf (surface->stream, "Q q\n"); diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index 9628c877e..5b996806d 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -1725,7 +1725,7 @@ static cairo_int_status_t _cairo_quartz_surface_paint_cg (cairo_quartz_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_quartz_drawing_state_t state; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -1752,7 +1752,7 @@ static cairo_int_status_t _cairo_quartz_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv; @@ -1779,11 +1779,11 @@ static cairo_int_status_t _cairo_quartz_surface_fill_cg (cairo_quartz_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_quartz_drawing_state_t state; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -1827,11 +1827,11 @@ static cairo_int_status_t _cairo_quartz_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv; @@ -1864,13 +1864,13 @@ static cairo_int_status_t _cairo_quartz_surface_stroke_cg (cairo_quartz_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_quartz_drawing_state_t state; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -1947,13 +1947,13 @@ static cairo_int_status_t _cairo_quartz_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv; @@ -1987,7 +1987,7 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs) { CGAffineTransform textTransform, invTextTransform; @@ -2131,7 +2131,7 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; @@ -2248,7 +2248,7 @@ _cairo_quartz_surface_mask_cg (cairo_quartz_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_surface_t *mask_surf; cairo_matrix_t matrix; @@ -2350,7 +2350,7 @@ _cairo_quartz_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv; diff --git a/src/cairo-recording-surface-private.h b/src/cairo-recording-surface-private.h index 3d8cba302..a901e7b14 100644 --- a/src/cairo-recording-surface-private.h +++ b/src/cairo-recording-surface-private.h @@ -40,7 +40,6 @@ #include "cairoint.h" #include "cairo-path-fixed-private.h" #include "cairo-pattern-private.h" -#include "cairo-clip-private.h" typedef enum { /* The 5 basic drawing operations. */ @@ -61,7 +60,7 @@ typedef struct _cairo_command_header { cairo_command_type_t type; cairo_recording_region_type_t region; cairo_operator_t op; - cairo_clip_t clip; + cairo_clip_t *clip; } cairo_command_header_t; typedef struct _cairo_command_paint { @@ -130,8 +129,6 @@ typedef struct _cairo_recording_surface { cairo_rectangle_int_t extents; cairo_bool_t unbounded; - cairo_clip_t clip; - cairo_array_t commands; int replay_start_idx; diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c index 84ae347a0..ea5ee0178 100644 --- a/src/cairo-recording-surface.c +++ b/src/cairo-recording-surface.c @@ -136,7 +136,6 @@ cairo_recording_surface_create (cairo_content_t content, const cairo_rectangle_t *extents) { cairo_recording_surface_t *recording_surface; - cairo_status_t status; recording_surface = malloc (sizeof (cairo_recording_surface_t)); if (unlikely (recording_surface == NULL)) @@ -150,7 +149,6 @@ cairo_recording_surface_create (cairo_content_t content, recording_surface->content = content; recording_surface->unbounded = TRUE; - _cairo_clip_init (&recording_surface->clip); /* unbounded -> 'infinite' extents */ if (extents != NULL) { @@ -162,13 +160,6 @@ cairo_recording_surface_create (cairo_content_t content, recording_surface->extents.width = ceil (extents->x + extents->width) - recording_surface->extents.x; recording_surface->extents.height = ceil (extents->y + extents->height) - recording_surface->extents.y; - status = _cairo_clip_rectangle (&recording_surface->clip, - &recording_surface->extents); - if (unlikely (status)) { - free (recording_surface); - return _cairo_surface_create_in_error (status); - } - recording_surface->unbounded = FALSE; } @@ -239,12 +230,11 @@ _cairo_recording_surface_finish (void *abstract_surface) ASSERT_NOT_REACHED; } - _cairo_clip_fini (&command->header.clip); + _cairo_clip_destroy (command->header.clip); free (command); } _cairo_array_fini (&recording_surface->commands); - _cairo_clip_fini (&recording_surface->clip); return CAIRO_STATUS_SUCCESS; } @@ -321,16 +311,14 @@ _command_init (cairo_recording_surface_t *recording_surface, cairo_command_header_t *command, cairo_command_type_t type, cairo_operator_t op, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status = CAIRO_STATUS_SUCCESS; command->type = type; command->op = op; command->region = CAIRO_RECORDING_REGION_ALL; - _cairo_clip_init_copy (&command->clip, clip); - if (recording_surface->clip.path != NULL) - status = _cairo_clip_apply_clip (&command->clip, &recording_surface->clip); + command->clip = _cairo_clip_copy (clip); return status; } @@ -339,7 +327,7 @@ static cairo_int_status_t _cairo_recording_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; cairo_recording_surface_t *recording_surface = abstract_surface; @@ -373,7 +361,7 @@ _cairo_recording_surface_paint (void *abstract_surface, CLEANUP_SOURCE: _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: - _cairo_clip_fini (&command->header.clip); + _cairo_clip_destroy (command->header.clip); free (command); return status; } @@ -383,7 +371,7 @@ _cairo_recording_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; cairo_recording_surface_t *recording_surface = abstract_surface; @@ -417,7 +405,7 @@ _cairo_recording_surface_mask (void *abstract_surface, CLEANUP_SOURCE: _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: - _cairo_clip_fini (&command->header.clip); + _cairo_clip_destroy (command->header.clip); free (command); return status; } @@ -426,13 +414,13 @@ static cairo_int_status_t _cairo_recording_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; cairo_recording_surface_t *recording_surface = abstract_surface; @@ -477,7 +465,7 @@ _cairo_recording_surface_stroke (void *abstract_surface, CLEANUP_SOURCE: _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: - _cairo_clip_fini (&command->header.clip); + _cairo_clip_destroy (command->header.clip); free (command); return status; } @@ -486,11 +474,11 @@ static cairo_int_status_t _cairo_recording_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; cairo_recording_surface_t *recording_surface = abstract_surface; @@ -528,7 +516,7 @@ _cairo_recording_surface_fill (void *abstract_surface, CLEANUP_SOURCE: _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: - _cairo_clip_fini (&command->header.clip); + _cairo_clip_destroy (command->header.clip); free (command); return status; } @@ -551,7 +539,7 @@ _cairo_recording_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; cairo_recording_surface_t *recording_surface = abstract_surface; @@ -622,7 +610,7 @@ _cairo_recording_surface_show_text_glyphs (void *abstract_surface, _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: - _cairo_clip_fini (&command->header.clip); + _cairo_clip_destroy (command->header.clip); free (command); return status; } @@ -661,8 +649,6 @@ _cairo_recording_surface_snapshot (void *abstract_other) recording_surface->unbounded = other->unbounded; recording_surface->content = other->content; - _cairo_clip_init_copy (&recording_surface->clip, &other->clip); - /* XXX We should in theory be able to reuse the original array, but we * need to handle reference cycles during subsurface and self-copy. */ @@ -795,7 +781,7 @@ _cairo_recording_surface_get_path (cairo_surface_t *surface, command->stroke.tolerance, &traps); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) status = _cairo_traps_path (&traps, path); _cairo_traps_fini (&traps); @@ -828,7 +814,6 @@ _cairo_recording_surface_get_path (cairo_surface_t *surface, return _cairo_surface_set_error (surface, status); } -#define _clip(c) ((c)->header.clip.path ? &(c)->header.clip : NULL) static cairo_status_t _cairo_recording_surface_replay_internal (cairo_surface_t *surface, const cairo_rectangle_int_t *surface_extents, @@ -867,18 +852,24 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface, for (i = recording_surface->replay_start_idx; i < num_elements; i++) { cairo_command_t *command = elements[i]; + cairo_clip_t *clip = command->header.clip; if (type == CAIRO_RECORDING_REPLAY && region != CAIRO_RECORDING_REGION_ALL) { if (command->header.region != region) continue; } + if (! recording_surface->unbounded) + clip = _cairo_clip_copy_intersect_rectangle (clip, &recording_surface->extents); + if (_cairo_clip_is_all_clipped (clip)) + continue; + switch (command->header.type) { case CAIRO_COMMAND_PAINT: status = _cairo_surface_wrapper_paint (&wrapper, command->header.op, &command->paint.source.base, - _clip (command)); + clip); break; case CAIRO_COMMAND_MASK: @@ -886,7 +877,7 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface, command->header.op, &command->mask.source.base, &command->mask.mask.base, - _clip (command)); + clip); break; case CAIRO_COMMAND_STROKE: @@ -900,7 +891,7 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface, &command->stroke.ctm_inverse, command->stroke.tolerance, command->stroke.antialias, - _clip (command)); + clip); break; } case CAIRO_COMMAND_FILL: @@ -938,7 +929,7 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface, &stroke_command->stroke.ctm_inverse, stroke_command->stroke.tolerance, stroke_command->stroke.antialias, - _clip (command)); + clip); i++; } else @@ -950,7 +941,7 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface, command->fill.fill_rule, command->fill.tolerance, command->fill.antialias, - _clip (command)); + clip); } break; } @@ -980,7 +971,7 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface, command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters, command->show_text_glyphs.cluster_flags, command->show_text_glyphs.scaled_font, - _clip (command)); + clip); free (glyphs_copy); break; } @@ -989,29 +980,24 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface, } if (type == CAIRO_RECORDING_CREATE_REGIONS) { - if (status == CAIRO_STATUS_SUCCESS) { + if (status == CAIRO_INT_STATUS_SUCCESS) { command->header.region = CAIRO_RECORDING_REGION_NATIVE; } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) { command->header.region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK; - status = CAIRO_STATUS_SUCCESS; + status = CAIRO_INT_STATUS_SUCCESS; } else { - assert (_cairo_status_is_error (status)); + assert (_cairo_int_status_is_error (status)); } } + if (clip != command->header.clip) + _cairo_clip_destroy (clip); + if (unlikely (status)) break; } - /* free up any caches */ - for (i = recording_surface->replay_start_idx; i < num_elements; i++) { - cairo_command_t *command = elements[i]; - - _cairo_clip_drop_cache (&command->header.clip); - } - _cairo_surface_wrapper_fini (&wrapper); - return _cairo_surface_set_error (surface, status); } diff --git a/src/cairo-scaled-font-subsets-private.h b/src/cairo-scaled-font-subsets-private.h index 1f952c441..1504eaa99 100644 --- a/src/cairo-scaled-font-subsets-private.h +++ b/src/cairo-scaled-font-subsets-private.h @@ -216,11 +216,11 @@ cairo_private cairo_status_t _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *font_subsets, cairo_scaled_font_t *scaled_font, unsigned long scaled_font_glyph_index, - const char * utf8, + const char * utf8, int utf8_len, cairo_scaled_font_subsets_glyph_t *subset_glyph_ret); -typedef cairo_status_t +typedef cairo_int_status_t (*cairo_scaled_font_subset_callback_func_t) (cairo_scaled_font_subset_t *font_subset, void *closure); diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c index 433ca3f9d..dd6b8244f 100644 --- a/src/cairo-scaled-font-subsets.c +++ b/src/cairo-scaled-font-subsets.c @@ -511,7 +511,7 @@ _cairo_sub_font_add_glyph (cairo_sub_font_t *sub_font, int *num_glyphs_in_subset_ptr; double x_advance; double y_advance; - cairo_status_t status; + cairo_int_status_t status; _cairo_scaled_font_freeze_cache (sub_font->scaled_font); status = _cairo_scaled_glyph_lookup (sub_font->scaled_font, @@ -828,7 +828,7 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, cairo_matrix_t identity; cairo_font_options_t font_options; cairo_scaled_font_t *unscaled_font; - cairo_status_t status; + cairo_int_status_t status; int max_glyphs; cairo_bool_t type1_font; @@ -881,10 +881,10 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, &scaled_glyph); _cairo_scaled_font_thaw_cache (scaled_font); } - if (_cairo_status_is_error (status)) + if (_cairo_int_status_is_error (status)) return status; - if (status == CAIRO_STATUS_SUCCESS && + if (status == CAIRO_INT_STATUS_SUCCESS && subsets->type != CAIRO_SUBSETS_SCALED && ! _cairo_font_face_is_user (scaled_font->font_face)) { diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index c6c599b9f..6cca4acc2 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -1858,7 +1858,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, cairo_text_cluster_flags_t *cluster_flags) { int num_chars = 0; - cairo_status_t status; + cairo_int_status_t status; cairo_glyph_t *orig_glyphs; cairo_text_cluster_t *orig_clusters; @@ -1941,7 +1941,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, clusters, num_clusters, cluster_flags); if (status != CAIRO_INT_STATUS_UNSUPPORTED) { - if (status == CAIRO_STATUS_SUCCESS) { + if (status == CAIRO_INT_STATUS_SUCCESS) { /* The checks here are crude; we only should do them in * user-font backend, but they don't hurt here. This stuff * can be hard to get right. */ @@ -2193,7 +2193,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, int num_glyphs, cairo_region_t *clip_region) { - cairo_status_t status; + cairo_int_status_t status; cairo_surface_t *mask = NULL; cairo_format_t mask_format = CAIRO_FORMAT_A1; /* shut gcc up */ cairo_surface_pattern_t mask_pattern; @@ -2224,7 +2224,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, glyphs += num_glyphs - remaining_glyphs; num_glyphs = remaining_glyphs; if (remaining_glyphs == 0) - status = CAIRO_STATUS_SUCCESS; + status = CAIRO_INT_STATUS_SUCCESS; if (status != CAIRO_INT_STATUS_UNSUPPORTED) return _cairo_scaled_font_set_error (scaled_font, status); } @@ -2480,7 +2480,7 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, int num_glyphs, cairo_path_fixed_t *path) { - cairo_status_t status; + cairo_int_status_t status; int i; status = scaled_font->status; @@ -2495,7 +2495,7 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_PATH, &scaled_glyph); - if (status == CAIRO_STATUS_SUCCESS) { + if (status == CAIRO_INT_STATUS_SUCCESS) { status = _cairo_path_fixed_append (path, scaled_glyph->path, _cairo_fixed_from_double (glyphs[i].x), @@ -2787,7 +2787,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, cairo_scaled_glyph_info_t info, cairo_scaled_glyph_t **scaled_glyph_ret) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; cairo_scaled_glyph_t *scaled_glyph; cairo_scaled_glyph_info_t need_info; diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c index 4ca0faf50..6f4632008 100644 --- a/src/cairo-script-surface.c +++ b/src/cairo-script-surface.c @@ -839,6 +839,7 @@ _format_to_string (cairo_format_t format) { switch (format) { case CAIRO_FORMAT_ARGB32: return "ARGB32"; + case CAIRO_FORMAT_RGB30: return "RGB30"; case CAIRO_FORMAT_RGB24: return "RGB24"; case CAIRO_FORMAT_RGB16_565: return "RGB16_565"; case CAIRO_FORMAT_A8: return "A8"; @@ -1204,6 +1205,7 @@ _write_image_surface (cairo_output_stream_t *output, data += stride; } break; + case CAIRO_FORMAT_RGB30: case CAIRO_FORMAT_ARGB32: for (row = image->height; row--; ) { uint32_t *src = (uint32_t *) data; @@ -1279,14 +1281,14 @@ _undef (void *data) free (def); } -static cairo_status_t +static cairo_int_status_t _emit_image_surface (cairo_script_surface_t *surface, cairo_image_surface_t *image) { cairo_script_context_t *ctx = to_context (surface); cairo_output_stream_t *base85_stream; cairo_output_stream_t *zlib_stream; - cairo_status_t status, status2; + cairo_int_status_t status, status2; const uint8_t *mime_data; unsigned long mime_data_length; struct def *tag; @@ -1297,11 +1299,11 @@ _emit_image_surface (cairo_script_surface_t *surface, _cairo_output_stream_printf (ctx->stream, "s%u ", image->base.unique_id); - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } status = _emit_png_surface (surface, image); - if (_cairo_status_is_error (status)) { + if (_cairo_int_status_is_error (status)) { return status; } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) { cairo_image_surface_t *clone; @@ -1336,6 +1338,7 @@ _emit_image_surface (cairo_script_surface_t *surface, case CAIRO_FORMAT_RGB24: len = clone->width * 3; break; + case CAIRO_FORMAT_RGB30: case CAIRO_FORMAT_ARGB32: len = clone->width * 4; break; @@ -1357,10 +1360,10 @@ _emit_image_surface (cairo_script_surface_t *surface, status = _write_image_surface (zlib_stream, clone); status2 = _cairo_output_stream_destroy (zlib_stream); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) status = status2; status2 = _cairo_output_stream_destroy (base85_stream); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) status = status2; if (unlikely (status)) return status; @@ -1370,7 +1373,7 @@ _emit_image_surface (cairo_script_surface_t *surface, base85_stream = _cairo_base85_stream_create (ctx->stream); status = _write_image_surface (base85_stream, clone); status2 = _cairo_output_stream_destroy (base85_stream); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) status = status2; if (unlikely (status)) return status; @@ -1432,10 +1435,10 @@ _emit_image_surface (cairo_script_surface_t *surface, _cairo_output_stream_puts (ctx->stream, "~> set-mime-data\n"); } - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _emit_image_surface_pattern (cairo_script_surface_t *surface, cairo_surface_t *source) { @@ -1458,12 +1461,12 @@ _emit_image_surface_pattern (cairo_script_surface_t *surface, return status; } -static cairo_status_t +static cairo_int_status_t _emit_subsurface_pattern (cairo_script_surface_t *surface, cairo_surface_subsurface_t *sub) { cairo_surface_t *source = sub->target; - cairo_status_t status; + cairo_int_status_t status; switch ((int) source->backend->type) { case CAIRO_SURFACE_TYPE_RECORDING: @@ -1485,16 +1488,16 @@ _emit_subsurface_pattern (cairo_script_surface_t *surface, sub->extents.y, sub->extents.width, sub->extents.height); - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _emit_surface_pattern (cairo_script_surface_t *surface, const cairo_pattern_t *pattern) { cairo_surface_pattern_t *surface_pattern; cairo_surface_t *source; - cairo_status_t status; + cairo_int_status_t status; surface_pattern = (cairo_surface_pattern_t *) pattern; source = surface_pattern->surface; @@ -1520,15 +1523,15 @@ _emit_surface_pattern (cairo_script_surface_t *surface, return status; _cairo_output_stream_puts (to_context (surface)->stream, "pattern"); - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _emit_pattern (cairo_script_surface_t *surface, const cairo_pattern_t *pattern) { cairo_script_context_t *ctx = to_context (surface); - cairo_status_t status; + cairo_int_status_t status; cairo_bool_t is_default_extend; cairo_bool_t need_newline = TRUE; @@ -1599,17 +1602,17 @@ _emit_pattern (cairo_script_surface_t *surface, if (need_newline) _cairo_output_stream_puts (ctx->stream, "\n "); - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _emit_identity (cairo_script_surface_t *surface, cairo_bool_t *matrix_updated) { assert (target_is_active (surface)); if (_cairo_matrix_is_identity (&surface->cr.current_ctm)) - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; _cairo_output_stream_puts (to_context (surface)->stream, "identity set-matrix\n"); @@ -1617,26 +1620,26 @@ _emit_identity (cairo_script_surface_t *surface, *matrix_updated = TRUE; cairo_matrix_init_identity (&surface->cr.current_ctm); - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _emit_source (cairo_script_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source) { cairo_bool_t matrix_updated = FALSE; - cairo_status_t status; + cairo_int_status_t status; assert (target_is_active (surface)); if (op == CAIRO_OPERATOR_CLEAR) { /* the source is ignored, so don't change it */ - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } if (_cairo_pattern_equal (&surface->cr.current_source.base, source)) - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; _cairo_pattern_fini (&surface->cr.current_source.base); status = _cairo_pattern_init_copy (&surface->cr.current_source.base, @@ -1655,7 +1658,7 @@ _emit_source (cairo_script_surface_t *surface, assert (target_is_active (surface)); _cairo_output_stream_puts (to_context (surface)->stream, " set-source\n"); - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } static cairo_status_t @@ -1711,7 +1714,7 @@ _path_close (void *closure) static cairo_status_t _emit_path (cairo_script_surface_t *surface, - cairo_path_fixed_t *path) + const cairo_path_fixed_t *path) { cairo_script_context_t *ctx = to_context (surface); cairo_box_t box; @@ -2263,7 +2266,7 @@ static cairo_int_status_t _cairo_script_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_status_t status; @@ -2310,7 +2313,7 @@ _cairo_script_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_status_t status; @@ -2366,13 +2369,13 @@ static cairo_int_status_t _cairo_script_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_bool_t matrix_updated = FALSE; @@ -2457,11 +2460,11 @@ static cairo_int_status_t _cairo_script_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_bool_t matrix_updated = FALSE; @@ -2743,7 +2746,7 @@ _emit_scaled_font_init (cairo_script_surface_t *surface, { cairo_script_context_t *ctx = to_context (surface); cairo_script_surface_font_private_t *font_private; - cairo_status_t status; + cairo_int_status_t status; font_private = malloc (sizeof (cairo_script_surface_font_private_t)); if (unlikely (font_private == NULL)) @@ -3135,7 +3138,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t backward, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_script_context_t *ctx = to_context (surface); diff --git a/src/cairo-spans.c b/src/cairo-spans.c index 09af57a4c..f6586506b 100644 --- a/src/cairo-spans.c +++ b/src/cairo-spans.c @@ -27,7 +27,10 @@ #include "cairoint.h" #include "cairo-composite-rectangles-private.h" +#include "cairo-clip-private.h" +#include "cairo-error-private.h" #include "cairo-fixed-private.h" +#include "cairo-types-private.h" static cairo_scan_converter_t * _create_scan_converter (cairo_fill_rule_t fill_rule, @@ -62,6 +65,31 @@ _cairo_surface_composite_polygon (cairo_surface_t *surface, cairo_span_renderer_t *renderer; cairo_scan_converter_t *converter; cairo_status_t status; + cairo_clip_path_t *clip_path = rects->clip->path; + + if (rects->is_bounded) { + if (polygon->num_edges == 0) + return CAIRO_STATUS_SUCCESS; + + if (clip_path) { /* XXX */ + cairo_polygon_t clipper; + cairo_fill_rule_t clipper_fill_rule; + cairo_antialias_t clipper_antialias; + + if (_cairo_clip_get_polygon (rects->clip, &clipper, + &clipper_fill_rule, + &clipper_antialias) == CAIRO_INT_STATUS_SUCCESS) { + if (clipper_antialias != CAIRO_ANTIALIAS_NONE && + _cairo_polygon_intersect (polygon, fill_rule, + &clipper, clipper_fill_rule) == CAIRO_STATUS_SUCCESS) + { + rects->clip->path = NULL; + } + + _cairo_polygon_fini (&clipper); + } + } + } converter = _create_scan_converter (fill_rule, antialias, rects); status = converter->add_polygon (converter, polygon); @@ -81,6 +109,7 @@ _cairo_surface_composite_polygon (cairo_surface_t *surface, renderer->destroy (renderer); CLEANUP_CONVERTER: converter->destroy (converter); + rects->clip->path = clip_path; return status; } diff --git a/src/cairo-surface-clipper-private.h b/src/cairo-surface-clipper-private.h index b9ca3cb1c..e5b00af7c 100644 --- a/src/cairo-surface-clipper-private.h +++ b/src/cairo-surface-clipper-private.h @@ -51,14 +51,13 @@ typedef cairo_status_t double, cairo_antialias_t); struct _cairo_surface_clipper { - cairo_clip_t clip; - cairo_bool_t is_clipped; + cairo_clip_t *clip; cairo_surface_clipper_intersect_clip_path_func_t intersect_clip_path; }; cairo_private cairo_status_t _cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private void _cairo_surface_clipper_init (cairo_surface_clipper_t *clipper, diff --git a/src/cairo-surface-clipper.c b/src/cairo-surface-clipper.c index 948730047..c1644b495 100644 --- a/src/cairo-surface-clipper.c +++ b/src/cairo-surface-clipper.c @@ -39,6 +39,63 @@ /* A collection of routines to facilitate vector surface clipping */ +/* XXX Eliminate repeated paths and nested clips */ + +static cairo_status_t +_cairo_path_fixed_add_box (cairo_path_fixed_t *path, + const cairo_box_t *box) +{ + cairo_status_t status; + + status = _cairo_path_fixed_move_to (path, box->p1.x, box->p1.y); + if (unlikely (status)) + return status; + + status = _cairo_path_fixed_line_to (path, box->p2.x, box->p1.y); + if (unlikely (status)) + return status; + + status = _cairo_path_fixed_line_to (path, box->p2.x, box->p2.y); + if (unlikely (status)) + return status; + + status = _cairo_path_fixed_line_to (path, box->p1.x, box->p2.y); + if (unlikely (status)) + return status; + + return _cairo_path_fixed_close_path (path); +} + +static cairo_status_t +_cairo_surface_clipper_intersect_clip_boxes (cairo_surface_clipper_t *clipper, + const cairo_clip_t *clip) +{ + cairo_path_fixed_t path; + cairo_status_t status; + int i; + + /* Reconstruct the path for the clip boxes. + * XXX maybe a new clipper callback? + */ + + _cairo_path_fixed_init (&path); + for (i = 0; i < clip->num_boxes; i++) { + status = _cairo_path_fixed_add_box (&path, &clip->boxes[i]); + if (unlikely (status)) { + _cairo_path_fixed_fini (&path); + return status; + } + } + + status = clipper->intersect_clip_path (clipper, &path, + CAIRO_FILL_RULE_WINDING, + 0., + CAIRO_ANTIALIAS_DEFAULT); + _cairo_path_fixed_init (&path); + + return status; +} + static cairo_status_t _cairo_surface_clipper_intersect_clip_path_recursive (cairo_surface_clipper_t *clipper, cairo_clip_path_t *clip_path) @@ -62,57 +119,33 @@ _cairo_surface_clipper_intersect_clip_path_recursive (cairo_surface_clipper_t *c cairo_status_t _cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; - cairo_bool_t clear; - - /* XXX as we cache a reference to the path, and compare every time, - * we may in future need to install a notification if the clip->path - * is every modified (e.g. cairo_clip_translate). - */ - if (clip == NULL && clipper->clip.path == NULL) + if (_cairo_clip_equal (clip, clipper->clip)) return CAIRO_STATUS_SUCCESS; - if (clip != NULL && clipper->clip.path != NULL && - _cairo_clip_equal (clip, &clipper->clip)) - { - return CAIRO_STATUS_SUCCESS; - } - /* all clipped out state should never propagate this far */ - assert (clip == NULL || clip->path != NULL); + assert (!_cairo_clip_is_all_clipped (clip)); - /* Check whether this clip is a continuation of the previous. - * If not, we have to remove the current clip and rebuild. - */ - clear = clip == NULL || clip->path->prev != clipper->clip.path; + _cairo_clip_destroy (clipper->clip); + clipper->clip = _cairo_clip_copy (clip); - _cairo_clip_reset (&clipper->clip); - _cairo_clip_init_copy (&clipper->clip, clip); + status = clipper->intersect_clip_path (clipper, NULL, 0, 0, 0); + if (unlikely (status)) + return status; - if (clear) { - clipper->is_clipped = FALSE; - status = clipper->intersect_clip_path (clipper, NULL, 0, 0, 0); - if (unlikely (status)) - return status; + if (clip == NULL) + return CAIRO_STATUS_SUCCESS; - if (clip != NULL && clip->path != NULL) { - status = - _cairo_surface_clipper_intersect_clip_path_recursive (clipper, - clip->path); - clipper->is_clipped = TRUE; - } - } else { - cairo_clip_path_t *path = clip->path; - - clipper->is_clipped = TRUE; - status = clipper->intersect_clip_path (clipper, - &path->path, - path->fill_rule, - path->tolerance, - path->antialias); + status = _cairo_surface_clipper_intersect_clip_boxes (clipper, clip); + if (unlikely (status)) + return status; + + if (clip->path != NULL) { + status = _cairo_surface_clipper_intersect_clip_path_recursive (clipper, + clip->path); } return status; @@ -122,14 +155,13 @@ void _cairo_surface_clipper_init (cairo_surface_clipper_t *clipper, cairo_surface_clipper_intersect_clip_path_func_t func) { - _cairo_clip_init (&clipper->clip); - clipper->is_clipped = FALSE; + clipper->clip = NULL; clipper->intersect_clip_path = func; } void _cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper) { - _cairo_clip_reset (&clipper->clip); - clipper->is_clipped = FALSE; + _cairo_clip_destroy (clipper->clip); + clipper->clip = NULL; } diff --git a/src/cairo-surface-fallback-private.h b/src/cairo-surface-fallback-private.h index e993de62e..ffb6f9199 100644 --- a/src/cairo-surface-fallback-private.h +++ b/src/cairo-surface-fallback-private.h @@ -45,36 +45,36 @@ cairo_private cairo_status_t _cairo_surface_fallback_paint (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_fallback_mask (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_fallback_stroke (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_fallback_fill (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, @@ -83,7 +83,7 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_surface_t * _cairo_surface_fallback_snapshot (cairo_surface_t *surface); diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c index 5a30d4f3c..21966fe42 100644 --- a/src/cairo-surface-fallback.c +++ b/src/cairo-surface-fallback.c @@ -128,20 +128,10 @@ _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern, const cairo_rectangle_int_t *extents) { cairo_surface_t *mask; - cairo_region_t *clip_region = NULL, *fallback_region = NULL; cairo_status_t status; - cairo_bool_t clip_surface = FALSE; - - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - if (unlikely (_cairo_status_is_error (status) || - status == CAIRO_INT_STATUS_NOTHING_TO_DO)) - { - return status; - } - - clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; - } + cairo_region_t *clip_region = _cairo_clip_get_region (clip); + cairo_bool_t clip_surface = ! _cairo_clip_is_region (clip); + cairo_region_t *fallback_region = NULL; /* We need to use solid here, because to use CAIRO_OPERATOR_SOURCE with * a mask (as called via _cairo_surface_mask) triggers assertion failures. @@ -282,7 +272,6 @@ _clip_and_composite_combine (cairo_clip_t *clip, if (unlikely (status)) goto CLEANUP_SURFACE; - assert (clip->path != NULL); clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y); if (unlikely (clip_surface->status)) goto CLEANUP_SURFACE; @@ -344,18 +333,9 @@ _clip_and_composite_source (cairo_clip_t *clip, const cairo_rectangle_int_t *extents) { cairo_surface_pattern_t mask_pattern; - cairo_region_t *clip_region = NULL; + cairo_region_t *clip_region = _cairo_clip_get_region (clip); cairo_status_t status; - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - if (unlikely (_cairo_status_is_error (status) || - status == CAIRO_INT_STATUS_NOTHING_TO_DO)) - { - return status; - } - } - /* Create a surface that is mask IN clip */ status = _create_composite_mask_pattern (&mask_pattern, clip, @@ -390,12 +370,6 @@ _clip_and_composite_source (cairo_clip_t *clip, return status; } -static int -_cairo_rectangle_empty (const cairo_rectangle_int_t *rect) -{ - return rect->width == 0 || rect->height == 0; -} - /** * _clip_and_composite: * @clip: a #cairo_clip_t @@ -428,10 +402,6 @@ _clip_and_composite (cairo_clip_t *clip, { cairo_status_t status; - if (_cairo_rectangle_empty (extents)) - /* Nothing to do */ - return CAIRO_STATUS_SUCCESS; - if (op == CAIRO_OPERATOR_CLEAR) { src = &_cairo_pattern_white.base; op = CAIRO_OPERATOR_DEST_OUT; @@ -443,21 +413,7 @@ _clip_and_composite (cairo_clip_t *clip, draw_func, draw_closure, dst, extents); } else { - cairo_bool_t clip_surface = FALSE; - cairo_region_t *clip_region = NULL; - - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - if (unlikely (_cairo_status_is_error (status) || - status == CAIRO_INT_STATUS_NOTHING_TO_DO)) - { - return status; - } - - clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; - } - - if (clip_surface) { + if (! _cairo_clip_is_region (clip)) { if (_cairo_operator_bounded_by_mask (op)) { status = _clip_and_composite_with_mask (clip, op, src, @@ -474,7 +430,7 @@ _clip_and_composite (cairo_clip_t *clip, src, dst, 0, 0, extents, - clip_region); + _cairo_clip_get_region (clip)); } } @@ -779,23 +735,12 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src, cairo_rectangle_int_t *extents) { cairo_composite_traps_info_t traps_info; - cairo_region_t *clip_region = NULL; - cairo_bool_t clip_surface = FALSE; - cairo_status_t status; + cairo_bool_t clip_surface = ! _cairo_clip_is_region (clip); + cairo_int_status_t status; if (traps->num_traps == 0 && _cairo_operator_bounded_by_mask (op)) return CAIRO_STATUS_SUCCESS; - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - if (unlikely (_cairo_status_is_error (status))) - return status; - if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) - return CAIRO_STATUS_SUCCESS; - - clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; - } - /* Use a fast path if the trapezoids consist of a simple region, * but we can only do this if we do not have a clip surface, or can * substitute the mask with the clip. @@ -815,8 +760,8 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src, return status; } - status = _cairo_traps_extract_region (traps, &trap_region); - if (unlikely (_cairo_status_is_error (status))) + status = _cairo_traps_extract_region (traps, antialias, &trap_region); + if (unlikely (_cairo_int_status_is_error (status))) return status; if (trap_region != NULL) { @@ -826,21 +771,13 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src, return status; } - if (clip_region != NULL) { - status = cairo_region_intersect (trap_region, clip_region); - if (unlikely (status)) { - cairo_region_destroy (trap_region); - return status; - } - } - if (_cairo_operator_bounded_by_mask (op)) { cairo_rectangle_int_t trap_extents; cairo_region_get_extents (trap_region, &trap_extents); if (! _cairo_rectangle_intersect (extents, &trap_extents)) { cairo_region_destroy (trap_region); - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } } @@ -882,16 +819,12 @@ cairo_status_t _cairo_surface_fallback_paint (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_composite_rectangles_t extents; cairo_rectangle_int_t rect; - cairo_clip_path_t *clip_path = clip ? clip->path : NULL; - cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; cairo_boxes_t boxes; - int num_boxes = ARRAY_LENGTH (boxes_stack); - cairo_status_t status; - cairo_traps_t traps; + cairo_int_status_t status; if (!_cairo_surface_get_extents (surface, &rect)) ASSERT_NOT_REACHED; @@ -904,44 +837,22 @@ _cairo_surface_fallback_paint (cairo_surface_t *surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; - - status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); - if (unlikely (status)) - return status; - - /* If the clip cannot be reduced to a set of boxes, we will need to - * use a clipmask. Paint is special as it is the only operation that - * does not implicitly use a mask, so we may be able to reduce this - * operation to a fill... - */ - if (clip != NULL && clip_path->prev == NULL && - _cairo_operator_bounded_by_mask (op)) - { - return _cairo_surface_fill (surface, op, source, - &clip_path->path, - clip_path->fill_rule, - clip_path->tolerance, - clip_path->antialias, - NULL); + status = _cairo_clip_to_boxes (extents.clip, &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + cairo_traps_t traps; + + /* meh, surface-fallback is dying anyway... */ + status = _cairo_traps_init_boxes (&traps, &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + status = _clip_and_composite_trapezoids (source, op, surface, + &traps, CAIRO_ANTIALIAS_DEFAULT, + extents.clip, + extents.is_bounded ? &extents.bounded : &extents.unbounded); + _cairo_traps_fini (&traps); + } } - /* meh, surface-fallback is dying anyway... */ - _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes); - status = _cairo_traps_init_boxes (&traps, &boxes); - if (unlikely (status)) - goto CLEANUP_BOXES; - - status = _clip_and_composite_trapezoids (source, op, surface, - &traps, CAIRO_ANTIALIAS_DEFAULT, - clip, - extents.is_bounded ? &extents.bounded : &extents.unbounded); - _cairo_traps_fini (&traps); - -CLEANUP_BOXES: - if (clip_boxes != boxes_stack) - free (clip_boxes); + _cairo_composite_rectangles_fini (&extents); return status; } @@ -957,7 +868,7 @@ _cairo_surface_mask_draw_func (void *closure, cairo_region_t *clip_region) { cairo_pattern_t *mask = closure; - cairo_status_t status; + cairo_int_status_t status; cairo_region_t *extents_region = NULL; if (clip_region == NULL && @@ -998,7 +909,7 @@ _cairo_surface_fallback_mask (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_composite_rectangles_t extents; cairo_rectangle_int_t rect; @@ -1013,38 +924,31 @@ _cairo_surface_fallback_mask (cairo_surface_t *surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; + status = _clip_and_composite (extents.clip, op, source, + _cairo_surface_mask_draw_func, + (void *) mask, + surface, + extents.is_bounded ? &extents.bounded : &extents.unbounded); - if (clip != NULL && extents.is_bounded) { - status = _cairo_clip_rectangle (clip, &extents.bounded); - if (unlikely (status)) - return status; - } + _cairo_composite_rectangles_fini (&extents); - return _clip_and_composite (clip, op, source, - _cairo_surface_mask_draw_func, - (void *) mask, - surface, - extents.is_bounded ? &extents.bounded : &extents.unbounded); + return status; } cairo_status_t _cairo_surface_fallback_stroke (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_polygon_t polygon; cairo_traps_t traps; - cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; - int num_boxes = ARRAY_LENGTH (boxes_stack); cairo_composite_rectangles_t extents; cairo_rectangle_int_t rect; cairo_status_t status; @@ -1061,22 +965,14 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; - - status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); - if (unlikely (status)) - return status; - - _cairo_polygon_init (&polygon, clip_boxes, num_boxes); - - _cairo_traps_init (&traps); - _cairo_traps_limit (&traps, clip_boxes, num_boxes); + _cairo_polygon_init_with_clip (&polygon, extents.clip); + _cairo_traps_init_with_clip (&traps, extents.clip); if (_cairo_path_fixed_stroke_is_rectilinear (path)) { status = _cairo_path_fixed_stroke_rectilinear_to_traps (path, stroke_style, ctm, + antialias, &traps); if (likely (status == CAIRO_STATUS_SUCCESS)) goto DO_TRAPS; @@ -1112,13 +1008,13 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, DO_TRAPS: status = _clip_and_composite_trapezoids (source, op, surface, &traps, antialias, - clip, + extents.clip, extents.is_bounded ? &extents.bounded : &extents.unbounded); CLEANUP: _cairo_traps_fini (&traps); _cairo_polygon_fini (&polygon); - if (clip_boxes != boxes_stack) - free (clip_boxes); + + _cairo_composite_rectangles_fini (&extents); return status; } @@ -1127,16 +1023,14 @@ cairo_status_t _cairo_surface_fallback_fill (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_polygon_t polygon; cairo_traps_t traps; - cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; - int num_boxes = ARRAY_LENGTH (boxes_stack); cairo_bool_t is_rectilinear; cairo_composite_rectangles_t extents; cairo_rectangle_int_t rect; @@ -1153,17 +1047,8 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; - - status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); - if (unlikely (status)) - return status; - - _cairo_traps_init (&traps); - _cairo_traps_limit (&traps, clip_boxes, num_boxes); - - _cairo_polygon_init (&polygon, clip_boxes, num_boxes); + _cairo_traps_init_with_clip (&traps, extents.clip); + _cairo_polygon_init_with_clip (&polygon, extents.clip); if (_cairo_path_fixed_fill_is_empty (path)) goto DO_TRAPS; @@ -1172,6 +1057,7 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, if (is_rectilinear) { status = _cairo_path_fixed_fill_rectilinear_to_traps (path, fill_rule, + antialias, &traps); if (likely (status == CAIRO_STATUS_SUCCESS)) goto DO_TRAPS; @@ -1214,13 +1100,13 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, DO_TRAPS: status = _clip_and_composite_trapezoids (source, op, surface, &traps, antialias, - clip, + extents.clip, extents.is_bounded ? &extents.bounded : &extents.unbounded); CLEANUP: _cairo_traps_fini (&traps); _cairo_polygon_fini (&polygon); - if (clip_boxes != boxes_stack) - free (clip_boxes); + + _cairo_composite_rectangles_fini (&extents); return status; } @@ -1242,17 +1128,7 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure cairo_region_t *clip_region) { cairo_show_glyphs_info_t *glyph_info = closure; - cairo_status_t status; - cairo_region_t *extents_region = NULL; - - if (clip_region == NULL && - !_cairo_operator_bounded_by_source (op)) { - extents_region = cairo_region_create_rectangle (extents); - if (unlikely (extents_region->status)) - return extents_region->status; - cairo_region_translate (extents_region, -dst_x, -dst_y); - clip_region = extents_region; - } + cairo_int_status_t status; /* Modifying the glyph array is fine because we know that this function * will be called only once, and we've already made a copy of the @@ -1291,9 +1167,6 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure clip_region); } - if (extents_region) - cairo_region_destroy (extents_region); - return status; } @@ -1304,12 +1177,12 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_show_glyphs_info_t glyph_info; cairo_composite_rectangles_t extents; cairo_rectangle_int_t rect; - cairo_status_t status; + cairo_int_status_t status; if (!_cairo_surface_get_extents (surface, &rect)) ASSERT_NOT_REACHED; @@ -1325,24 +1198,18 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_rectangle (clip, &extents.mask)) - clip = NULL; - - if (clip != NULL && extents.is_bounded) { - status = _cairo_clip_rectangle (clip, &extents.bounded); - if (unlikely (status)) - return status; - } - glyph_info.font = scaled_font; glyph_info.glyphs = glyphs; glyph_info.num_glyphs = num_glyphs; - return _clip_and_composite (clip, op, source, - _cairo_surface_old_show_glyphs_draw_func, - &glyph_info, - surface, - extents.is_bounded ? &extents.bounded : &extents.unbounded); + status = _clip_and_composite (extents.clip, op, source, + _cairo_surface_old_show_glyphs_draw_func, + &glyph_info, surface, + extents.is_bounded ? &extents.bounded : &extents.unbounded); + + _cairo_composite_rectangles_fini (&extents); + + return status; } cairo_surface_t * diff --git a/src/cairo-surface-offset-private.h b/src/cairo-surface-offset-private.h index b7877b3de..310ba5691 100644 --- a/src/cairo-surface-offset-private.h +++ b/src/cairo-surface-offset-private.h @@ -48,7 +48,7 @@ _cairo_surface_offset_paint (cairo_surface_t *target, int x, int y, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_offset_mask (cairo_surface_t *target, @@ -56,31 +56,31 @@ _cairo_surface_offset_mask (cairo_surface_t *target, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_offset_stroke (cairo_surface_t *surface, int x, int y, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_offset_fill (cairo_surface_t *surface, int x, int y, cairo_operator_t op, const cairo_pattern_t*source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_offset_glyphs (cairo_surface_t *surface, @@ -90,6 +90,6 @@ _cairo_surface_offset_glyphs (cairo_surface_t *surface, cairo_scaled_font_t *scaled_font, cairo_glyph_t *glyphs, int num_glyphs, - cairo_clip_t *clip); + const cairo_clip_t *clip); #endif /* CAIRO_SURFACE_OFFSET_PRIVATE_H */ diff --git a/src/cairo-surface-offset.c b/src/cairo-surface-offset.c index c36196e93..d2cc03032 100644 --- a/src/cairo-surface-offset.c +++ b/src/cairo-surface-offset.c @@ -59,29 +59,22 @@ _cairo_surface_offset_paint (cairo_surface_t *target, int x, int y, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; - cairo_clip_t clip_copy, *dev_clip = clip; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; cairo_pattern_union_t source_copy; if (unlikely (target->status)) return target->status; - if (clip && clip->all_clipped) + if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; if (x | y) { cairo_matrix_t m; - if (clip != NULL) { - cairo_matrix_init_translate (&m, -x, -y); - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); - if (unlikely (status)) - goto FINISH; - - dev_clip = &clip_copy; - } + dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y); cairo_matrix_init_translate (&m, x, y); _copy_transformed_pattern (&source_copy.base, source, &m); @@ -90,9 +83,8 @@ _cairo_surface_offset_paint (cairo_surface_t *target, status = _cairo_surface_paint (target, op, source, dev_clip); - FINISH: if (dev_clip != clip) - _cairo_clip_reset (dev_clip); + _cairo_clip_destroy (dev_clip); return status; } @@ -103,30 +95,23 @@ _cairo_surface_offset_mask (cairo_surface_t *target, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; - cairo_clip_t clip_copy, *dev_clip = clip; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; cairo_pattern_union_t source_copy; cairo_pattern_union_t mask_copy; if (unlikely (target->status)) return target->status; - if (clip && clip->all_clipped) + if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; if (x | y) { cairo_matrix_t m; - if (clip != NULL) { - cairo_matrix_init_translate (&m, -x, -y); - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); - if (unlikely (status)) - goto FINISH; - - dev_clip = &clip_copy; - } + dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y); cairo_matrix_init_translate (&m, x, y); _copy_transformed_pattern (&source_copy.base, source, &m); @@ -139,9 +124,8 @@ _cairo_surface_offset_mask (cairo_surface_t *target, source, mask, dev_clip); - FINISH: if (dev_clip != clip) - _cairo_clip_reset (dev_clip); + _cairo_clip_destroy (dev_clip); return status; } @@ -151,16 +135,16 @@ _cairo_surface_offset_stroke (cairo_surface_t *surface, int x, int y, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t*stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { - cairo_path_fixed_t path_copy, *dev_path = path; - cairo_clip_t clip_copy, *dev_clip = clip; + cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; cairo_matrix_t dev_ctm = *ctm; cairo_matrix_t dev_ctm_inverse = *ctm_inverse; cairo_pattern_union_t source_copy; @@ -169,12 +153,14 @@ _cairo_surface_offset_stroke (cairo_surface_t *surface, if (unlikely (surface->status)) return surface->status; - if (clip && clip->all_clipped) + if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; if (x | y) { cairo_matrix_t m; + dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y); + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); if (unlikely (status)) goto FINISH; @@ -186,13 +172,6 @@ _cairo_surface_offset_stroke (cairo_surface_t *surface, cairo_matrix_init_translate (&m, -x, -y); cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m); - if (clip != NULL) { - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); - if (unlikely (status)) - goto FINISH; - - dev_clip = &clip_copy; - } cairo_matrix_init_translate (&m, x, y); _copy_transformed_pattern (&source_copy.base, source, &m); @@ -206,11 +185,11 @@ _cairo_surface_offset_stroke (cairo_surface_t *surface, tolerance, antialias, dev_clip); - FINISH: +FINISH: if (dev_path != path) _cairo_path_fixed_fini (dev_path); if (dev_clip != clip) - _cairo_clip_reset (dev_clip); + _cairo_clip_destroy (dev_clip); return status; } @@ -220,26 +199,28 @@ _cairo_surface_offset_fill (cairo_surface_t *surface, int x, int y, cairo_operator_t op, const cairo_pattern_t*source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; - cairo_path_fixed_t path_copy, *dev_path = path; - cairo_clip_t clip_copy, *dev_clip = clip; + cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; cairo_pattern_union_t source_copy; if (unlikely (surface->status)) return surface->status; - if (clip && clip->all_clipped) + if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; if (x | y) { cairo_matrix_t m; + dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y); + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); if (unlikely (status)) goto FINISH; @@ -249,15 +230,6 @@ _cairo_surface_offset_fill (cairo_surface_t *surface, _cairo_fixed_from_int (-y)); dev_path = &path_copy; - if (clip != NULL) { - cairo_matrix_init_translate (&m, -x, -y); - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); - if (unlikely (status)) - goto FINISH; - - dev_clip = &clip_copy; - } - cairo_matrix_init_translate (&m, x, y); _copy_transformed_pattern (&source_copy.base, source, &m); source = &source_copy.base; @@ -268,11 +240,11 @@ _cairo_surface_offset_fill (cairo_surface_t *surface, tolerance, antialias, dev_clip); - FINISH: +FINISH: if (dev_path != path) _cairo_path_fixed_fini (dev_path); if (dev_clip != clip) - _cairo_clip_reset (dev_clip); + _cairo_clip_destroy (dev_clip); return status; } @@ -285,10 +257,10 @@ _cairo_surface_offset_glyphs (cairo_surface_t *surface, cairo_scaled_font_t *scaled_font, cairo_glyph_t *glyphs, int num_glyphs, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; - cairo_clip_t clip_copy, *dev_clip = clip; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; cairo_pattern_union_t source_copy; cairo_glyph_t *dev_glyphs; int i; @@ -296,7 +268,7 @@ _cairo_surface_offset_glyphs (cairo_surface_t *surface, if (unlikely (surface->status)) return surface->status; - if (clip && clip->all_clipped) + if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); @@ -308,14 +280,7 @@ _cairo_surface_offset_glyphs (cairo_surface_t *surface, if (x | y) { cairo_matrix_t m; - if (clip != NULL) { - cairo_matrix_init_translate (&m, -x, -y); - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); - if (unlikely (status)) - goto FINISH; - - dev_clip = &clip_copy; - } + dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y); cairo_matrix_init_translate (&m, x, y); _copy_transformed_pattern (&source_copy.base, source, &m); @@ -334,9 +299,8 @@ _cairo_surface_offset_glyphs (cairo_surface_t *surface, scaled_font, dev_clip); - FINISH: if (dev_clip != clip) - _cairo_clip_reset (dev_clip); + _cairo_clip_destroy (dev_clip); free (dev_glyphs); return status; diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c index ff1df839a..2a4a4fb57 100644 --- a/src/cairo-surface-subsurface.c +++ b/src/cairo-surface-subsurface.c @@ -65,23 +65,18 @@ static cairo_int_status_t _cairo_surface_subsurface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_surface_subsurface_t *surface = abstract_surface; cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; cairo_status_t status; - cairo_clip_t target_clip; - - _cairo_clip_init_copy (&target_clip, clip); - status = _cairo_clip_rectangle (&target_clip, &rect); - if (unlikely (status)) - goto CLEANUP; + cairo_clip_t *target_clip; + target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); status = _cairo_surface_offset_paint (surface->target, -surface->extents.x, -surface->extents.y, - op, source, &target_clip); - CLEANUP: - _cairo_clip_fini (&target_clip); + op, source, target_clip); + _cairo_clip_destroy (target_clip); return status; } @@ -90,23 +85,18 @@ _cairo_surface_subsurface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_surface_subsurface_t *surface = abstract_surface; cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; cairo_status_t status; - cairo_clip_t target_clip; - - _cairo_clip_init_copy (&target_clip, clip); - status = _cairo_clip_rectangle (&target_clip, &rect); - if (unlikely (status)) - goto CLEANUP; + cairo_clip_t *target_clip; + target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); status = _cairo_surface_offset_mask (surface->target, -surface->extents.x, -surface->extents.y, - op, source, mask, &target_clip); - CLEANUP: - _cairo_clip_fini (&target_clip); + op, source, mask, target_clip); + _cairo_clip_destroy (target_clip); return status; } @@ -114,28 +104,23 @@ static cairo_int_status_t _cairo_surface_subsurface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_surface_subsurface_t *surface = abstract_surface; cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; cairo_status_t status; - cairo_clip_t target_clip; - - _cairo_clip_init_copy (&target_clip, clip); - status = _cairo_clip_rectangle (&target_clip, &rect); - if (unlikely (status)) - goto CLEANUP; + cairo_clip_t *target_clip; + target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); status = _cairo_surface_offset_fill (surface->target, -surface->extents.x, -surface->extents.y, op, source, path, fill_rule, tolerance, antialias, - &target_clip); - CLEANUP: - _cairo_clip_fini (&target_clip); + target_clip); + _cairo_clip_destroy (target_clip); return status; } @@ -143,31 +128,26 @@ static cairo_int_status_t _cairo_surface_subsurface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_surface_subsurface_t *surface = abstract_surface; cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; cairo_status_t status; - cairo_clip_t target_clip; - - _cairo_clip_init_copy (&target_clip, clip); - status = _cairo_clip_rectangle (&target_clip, &rect); - if (unlikely (status)) - goto CLEANUP; + cairo_clip_t *target_clip; + target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); status = _cairo_surface_offset_stroke (surface->target, -surface->extents.x, -surface->extents.y, op, source, path, stroke_style, ctm, ctm_inverse, tolerance, antialias, - &target_clip); - CLEANUP: - _cairo_clip_fini (&target_clip); + target_clip); + _cairo_clip_destroy (target_clip); return status; } @@ -178,27 +158,22 @@ _cairo_surface_subsurface_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs) { cairo_surface_subsurface_t *surface = abstract_surface; cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; cairo_status_t status; - cairo_clip_t target_clip; - - _cairo_clip_init_copy (&target_clip, clip); - status = _cairo_clip_rectangle (&target_clip, &rect); - if (unlikely (status)) - goto CLEANUP; + cairo_clip_t *target_clip; + target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); status = _cairo_surface_offset_glyphs (surface->target, -surface->extents.x, -surface->extents.y, op, source, scaled_font, glyphs, num_glyphs, - &target_clip); + target_clip); *remaining_glyphs = 0; - CLEANUP: - _cairo_clip_fini (&target_clip); + _cairo_clip_destroy (target_clip); return status; } diff --git a/src/cairo-surface-wrapper-private.h b/src/cairo-surface-wrapper-private.h index 39dad2bd2..b3d3a55ae 100644 --- a/src/cairo-surface-wrapper-private.h +++ b/src/cairo-surface-wrapper-private.h @@ -76,26 +76,26 @@ cairo_private cairo_status_t _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, @@ -112,17 +112,17 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, @@ -136,7 +136,7 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_surface_t * _cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper, diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c index a76003b46..9e746f9c6 100644 --- a/src/cairo-surface-wrapper.c +++ b/src/cairo-surface-wrapper.c @@ -90,26 +90,20 @@ cairo_status_t _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; - cairo_clip_t clip_copy, *dev_clip = clip; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; + cairo_clip_t *target_clip = NULL; cairo_pattern_union_t source_copy; - cairo_clip_t target_clip; if (unlikely (wrapper->target->status)) return wrapper->target->status; - if (wrapper->has_extents) { - _cairo_clip_init_copy (&target_clip, clip); - status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); - if (unlikely (status)) - goto FINISH; - - dev_clip = clip = &target_clip; - } + if (wrapper->has_extents) + dev_clip = target_clip = _cairo_clip_copy_intersect_rectangle (clip, &wrapper->extents); - if (clip && clip->all_clipped) { + if (_cairo_clip_is_all_clipped (dev_clip)) { status = CAIRO_STATUS_SUCCESS; goto FINISH; } @@ -127,13 +121,8 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper, if (_cairo_surface_wrapper_needs_device_transform (wrapper)) cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m); - if (clip != NULL) { - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); - if (unlikely (status)) - goto FINISH; - - dev_clip = &clip_copy; - } + /* XXX */ + dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y); status = cairo_matrix_invert (&m); assert (status == CAIRO_STATUS_SUCCESS); @@ -145,10 +134,9 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper, status = _cairo_surface_paint (wrapper->target, op, source, dev_clip); FINISH: - if (wrapper->has_extents) - _cairo_clip_reset (&target_clip); + _cairo_clip_destroy (target_clip); if (dev_clip != clip) - _cairo_clip_reset (dev_clip); + _cairo_clip_destroy (dev_clip); return status; } @@ -157,27 +145,21 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; - cairo_clip_t clip_copy, *dev_clip = clip; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; cairo_pattern_union_t source_copy; cairo_pattern_union_t mask_copy; - cairo_clip_t target_clip; + cairo_clip_t *target_clip = NULL; if (unlikely (wrapper->target->status)) return wrapper->target->status; - if (wrapper->has_extents) { - _cairo_clip_init_copy (&target_clip, clip); - status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); - if (unlikely (status)) - goto FINISH; - - dev_clip = clip = &target_clip; - } + if (wrapper->has_extents) + dev_clip = target_clip = _cairo_clip_copy_intersect_rectangle (clip, &wrapper->extents); - if (clip && clip->all_clipped) { + if (_cairo_clip_is_all_clipped (dev_clip)) { status = CAIRO_STATUS_SUCCESS; goto FINISH; } @@ -195,13 +177,8 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper, if (_cairo_surface_wrapper_needs_device_transform (wrapper)) cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m); - if (clip != NULL) { - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); - if (unlikely (status)) - goto FINISH; - - dev_clip = &clip_copy; - } + /* XXX */ + dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y); status = cairo_matrix_invert (&m); assert (status == CAIRO_STATUS_SUCCESS); @@ -216,10 +193,9 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper, status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip); FINISH: - if (wrapper->has_extents) - _cairo_clip_reset (&target_clip); + _cairo_clip_destroy (target_clip); if (dev_clip != clip) - _cairo_clip_reset (dev_clip); + _cairo_clip_destroy (dev_clip); return status; } @@ -227,35 +203,29 @@ cairo_status_t _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; - cairo_path_fixed_t path_copy, *dev_path = path; - cairo_clip_t clip_copy, *dev_clip = clip; + cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; cairo_matrix_t dev_ctm = *ctm; cairo_matrix_t dev_ctm_inverse = *ctm_inverse; cairo_pattern_union_t source_copy; - cairo_clip_t target_clip; + cairo_clip_t *target_clip = NULL; if (unlikely (wrapper->target->status)) return wrapper->target->status; - if (wrapper->has_extents) { - _cairo_clip_init_copy (&target_clip, clip); - status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); - if (unlikely (status)) - goto FINISH; - - dev_clip = clip = &target_clip; - } + if (wrapper->has_extents) + dev_clip = target_clip = _cairo_clip_copy_intersect_rectangle (clip, &wrapper->extents); - if (clip && clip->all_clipped) { + if (_cairo_clip_is_all_clipped (dev_clip)) { status = CAIRO_STATUS_SUCCESS; goto FINISH; } @@ -280,13 +250,8 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper, _cairo_path_fixed_transform (&path_copy, &m); dev_path = &path_copy; - if (clip != NULL) { - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); - if (unlikely (status)) - goto FINISH; - - dev_clip = &clip_copy; - } + /* XXX */ + dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y); cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m); @@ -298,13 +263,6 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper, _copy_transformed_pattern (&source_copy.base, source, &m); source = &source_copy.base; } - else - { - if (clip != NULL) { - dev_clip = &clip_copy; - _cairo_clip_init_copy (&clip_copy, clip); - } - } status = _cairo_surface_stroke (wrapper->target, op, source, dev_path, stroke_style, @@ -315,10 +273,9 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper, FINISH: if (dev_path != path) _cairo_path_fixed_fini (dev_path); - if (wrapper->has_extents) - _cairo_clip_reset (&target_clip); + _cairo_clip_destroy (target_clip); if (dev_clip != clip) - _cairo_clip_reset (dev_clip); + _cairo_clip_destroy (dev_clip); return status; } @@ -337,30 +294,24 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; cairo_path_fixed_t path_copy, *dev_path = path; - cairo_clip_t clip_copy, *dev_clip = clip; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; cairo_matrix_t dev_ctm = *stroke_ctm; cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse; cairo_pattern_union_t stroke_source_copy; cairo_pattern_union_t fill_source_copy; - cairo_clip_t target_clip; + cairo_clip_t *target_clip = NULL; if (unlikely (wrapper->target->status)) return wrapper->target->status; - if (wrapper->has_extents) { - _cairo_clip_init_copy (&target_clip, clip); - status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); - if (unlikely (status)) - goto FINISH; - - dev_clip = clip = &target_clip; - } + if (wrapper->has_extents) + dev_clip = target_clip = _cairo_clip_copy_intersect_rectangle (clip, &wrapper->extents); - if (clip && clip->all_clipped) { + if (_cairo_clip_is_all_clipped (dev_clip)) { status = CAIRO_STATUS_SUCCESS; goto FINISH; } @@ -385,13 +336,8 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, _cairo_path_fixed_transform (&path_copy, &m); dev_path = &path_copy; - if (clip != NULL) { - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); - if (unlikely (status)) - goto FINISH; - - dev_clip = &clip_copy; - } + /* XXX */ + dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y); cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m); @@ -406,13 +352,6 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, _copy_transformed_pattern (&fill_source_copy.base, fill_source, &m); fill_source = &fill_source_copy.base; } - else - { - if (clip != NULL) { - dev_clip = &clip_copy; - _cairo_clip_init_copy (&clip_copy, clip); - } - } status = _cairo_surface_fill_stroke (wrapper->target, fill_op, fill_source, fill_rule, @@ -427,10 +366,9 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, FINISH: if (dev_path != path) _cairo_path_fixed_fini (dev_path); - if (wrapper->has_extents) - _cairo_clip_reset (&target_clip); + _cairo_clip_destroy (target_clip); if (dev_clip != clip) - _cairo_clip_reset (dev_clip); + _cairo_clip_destroy (dev_clip); return status; } @@ -438,31 +376,25 @@ cairo_status_t _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; - cairo_path_fixed_t path_copy, *dev_path = path; - cairo_clip_t clip_copy, *dev_clip = clip; + cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; cairo_pattern_union_t source_copy; - cairo_clip_t target_clip; + cairo_clip_t *target_clip = NULL; if (unlikely (wrapper->target->status)) return wrapper->target->status; - if (wrapper->has_extents) { - _cairo_clip_init_copy (&target_clip, clip); - status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); - if (unlikely (status)) - goto FINISH; - - dev_clip = clip = &target_clip; - } + if (wrapper->has_extents) + dev_clip = target_clip = _cairo_clip_copy_intersect_rectangle (clip, &wrapper->extents); - if (clip && clip->all_clipped) { + if (_cairo_clip_is_all_clipped (dev_clip)) { status = CAIRO_STATUS_SUCCESS; goto FINISH; } @@ -487,13 +419,8 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper, _cairo_path_fixed_transform (&path_copy, &m); dev_path = &path_copy; - if (clip != NULL) { - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); - if (unlikely (status)) - goto FINISH; - - dev_clip = &clip_copy; - } + /* XXX */ + dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y); status = cairo_matrix_invert (&m); assert (status == CAIRO_STATUS_SUCCESS); @@ -501,13 +428,6 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper, _copy_transformed_pattern (&source_copy.base, source, &m); source = &source_copy.base; } - else - { - if (clip != NULL) { - dev_clip = &clip_copy; - _cairo_clip_init_copy (&clip_copy, clip); - } - } status = _cairo_surface_fill (wrapper->target, op, source, dev_path, fill_rule, @@ -517,10 +437,9 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper, FINISH: if (dev_path != path) _cairo_path_fixed_fini (dev_path); - if (wrapper->has_extents) - _cairo_clip_reset (&target_clip); + _cairo_clip_destroy (target_clip); if (dev_clip != clip) - _cairo_clip_reset (dev_clip); + _cairo_clip_destroy (dev_clip); return status; } @@ -536,13 +455,13 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; - cairo_clip_t clip_copy, *dev_clip = clip; + cairo_clip_t *dev_clip = (cairo_clip_t *)clip; cairo_glyph_t *dev_glyphs = glyphs; cairo_pattern_union_t source_copy; - cairo_clip_t target_clip; + cairo_clip_t *target_clip = NULL; if (unlikely (wrapper->target->status)) return wrapper->target->status; @@ -550,16 +469,10 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, if (glyphs == NULL || num_glyphs == 0) return CAIRO_STATUS_SUCCESS; - if (wrapper->has_extents) { - _cairo_clip_init_copy (&target_clip, clip); - status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); - if (unlikely (status)) - goto FINISH; - - dev_clip = clip = &target_clip; - } + if (wrapper->has_extents) + dev_clip = target_clip = _cairo_clip_copy_intersect_rectangle (clip, &wrapper->extents); - if (clip && clip->all_clipped) { + if (_cairo_clip_is_all_clipped (dev_clip)) { status = CAIRO_STATUS_SUCCESS; goto FINISH; } @@ -578,13 +491,8 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, if (_cairo_surface_wrapper_needs_device_transform (wrapper)) cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m); - if (clip != NULL) { - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); - if (unlikely (status)) - goto FINISH; - - dev_clip = &clip_copy; - } + /* XXX */ + dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y); dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); if (dev_glyphs == NULL) { @@ -603,13 +511,6 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, _copy_transformed_pattern (&source_copy.base, source, &m); source = &source_copy.base; } - else - { - if (clip != NULL) { - dev_clip = &clip_copy; - _cairo_clip_init_copy (&clip_copy, clip); - } - } status = _cairo_surface_show_text_glyphs (wrapper->target, op, source, utf8, utf8_len, @@ -621,9 +522,8 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, FINISH: if (dev_clip != clip) - _cairo_clip_reset (dev_clip); - if (wrapper->has_extents) - _cairo_clip_reset (&target_clip); + _cairo_clip_destroy (dev_clip); + _cairo_clip_destroy (target_clip); if (dev_glyphs != glyphs) free (dev_glyphs); return status; diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 98903dcb5..1f9028d0c 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -170,7 +170,7 @@ _cairo_surface_set_error (cairo_surface_t *surface, cairo_status_t status) { if (status == CAIRO_STATUS_SUCCESS || - status == CAIRO_INT_STATUS_NOTHING_TO_DO) + status == (int)CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; /* Don't overwrite an existing error. This preserves the first @@ -498,6 +498,8 @@ cairo_surface_create_similar (cairo_surface_t *other, int width, int height) { + cairo_surface_t *surface; + if (unlikely (other->status)) return _cairo_surface_create_in_error (other->status); if (unlikely (other->finished)) @@ -508,10 +510,13 @@ cairo_surface_create_similar (cairo_surface_t *other, if (unlikely (! CAIRO_CONTENT_VALID (content))) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT)); - return _cairo_surface_create_similar_solid (other, - content, width, height, - CAIRO_COLOR_TRANSPARENT, - TRUE); + surface = _cairo_surface_create_similar_solid (other, + content, width, height, + CAIRO_COLOR_TRANSPARENT, + TRUE); + assert (surface->is_clear); + + return surface; } cairo_surface_t * @@ -1699,7 +1704,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, int *clone_offset_y, cairo_surface_t **clone_out) { - cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; cairo_image_surface_t *image; void *image_extra; @@ -1746,7 +1751,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, /* If we failed, try again with an image surface */ status = _cairo_surface_acquire_source_image (src, &image, &image_extra); - if (status == CAIRO_STATUS_SUCCESS) { + if (status == CAIRO_INT_STATUS_SUCCESS) { status = surface->backend->clone_similar (surface, &image->base, src_x, src_y, @@ -1995,27 +2000,27 @@ _pattern_has_error (const cairo_pattern_t *pattern) } cairo_status_t -_cairo_surface_paint (cairo_surface_t *surface, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_clip_t *clip) +_cairo_surface_paint (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) { - cairo_status_t status; + cairo_int_status_t status; if (unlikely (surface->status)) return surface->status; - if (clip && clip->all_clipped) + if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; + if (op == CAIRO_OPERATOR_SOURCE && _cairo_pattern_is_clear (source)) + op = CAIRO_OPERATOR_CLEAR; + if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear) return CAIRO_STATUS_SUCCESS; - if (op == CAIRO_OPERATOR_OVER && - _cairo_pattern_is_clear (source)) - { + if (op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_clear (source)) return CAIRO_STATUS_SUCCESS; - } status = _pattern_has_error (source); if (unlikely (status)) @@ -2043,14 +2048,14 @@ _cairo_surface_mask (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { - cairo_status_t status; + cairo_int_status_t status; if (unlikely (surface->status)) return surface->status; - if (clip && clip->all_clipped) + if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear) @@ -2109,14 +2114,14 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { - cairo_status_t status; + cairo_int_status_t status; if (unlikely (surface->status)) return surface->status; - if (clip && clip->all_clipped) + if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; if (surface->is_clear && @@ -2178,20 +2183,20 @@ cairo_status_t _cairo_surface_stroke (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { - cairo_status_t status; + cairo_int_status_t status; if (unlikely (surface->status)) return surface->status; - if (clip && clip->all_clipped) + if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear) @@ -2237,18 +2242,18 @@ cairo_status_t _cairo_surface_fill (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { - cairo_status_t status; + cairo_int_status_t status; if (unlikely (surface->status)) return surface->status; - if (clip && clip->all_clipped) + if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear) @@ -2355,11 +2360,8 @@ _cairo_surface_create_span_renderer (cairo_operator_t op, return _cairo_span_renderer_create_in_error (CAIRO_STATUS_SURFACE_FINISHED); if (dst->backend->create_span_renderer) { - return dst->backend->create_span_renderer (op, - pattern, dst, - antialias, - rects, - clip_region); + return dst->backend->create_span_renderer (op, pattern, dst, antialias, + rects, clip_region); } ASSERT_NOT_REACHED; return _cairo_span_renderer_create_in_error (CAIRO_INT_STATUS_UNSUPPORTED); @@ -2570,9 +2572,9 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip) + const cairo_clip_t *clip) { - cairo_status_t status; + cairo_int_status_t status; cairo_scaled_font_t *dev_scaled_font = scaled_font; if (unlikely (surface->status)) @@ -2581,7 +2583,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, if (num_glyphs == 0 && utf8_len == 0) return CAIRO_STATUS_SUCCESS; - if (clip && clip->all_clipped) + if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear) @@ -2641,7 +2643,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, glyphs += num_glyphs - remaining_glyphs; num_glyphs = remaining_glyphs; if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0) - status = CAIRO_STATUS_SUCCESS; + status = CAIRO_INT_STATUS_SUCCESS; } } else { /* A mere show_glyphs call. Try show_glyphs backend method first */ diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index 7adcfb726..e5ddb7e63 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -85,7 +85,7 @@ static const cairo_svg_version_t _cairo_svg_versions[] = static void _cairo_svg_surface_emit_path (cairo_output_stream_t *output, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_matrix_t *ctm_inverse); static cairo_bool_t @@ -562,10 +562,10 @@ _cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t *stream, static cairo_svg_page_t * _cairo_svg_surface_store_page (cairo_svg_surface_t *surface) { - unsigned int i; cairo_svg_page_t page; cairo_output_stream_t *stream; - cairo_status_t status; + cairo_int_status_t status; + unsigned int i; stream = _cairo_memory_stream_create (); if (_cairo_output_stream_get_status (stream)) { @@ -715,7 +715,7 @@ _cairo_svg_path_close_path (void *closure) static void _cairo_svg_surface_emit_path (cairo_output_stream_t *output, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_matrix_t *ctm_inverse) { cairo_status_t status; @@ -814,14 +814,14 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document, return CAIRO_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _cairo_svg_document_emit_glyph (cairo_svg_document_t *document, cairo_scaled_font_t *scaled_font, unsigned long scaled_font_glyph_index, unsigned int font_id, unsigned int subset_glyph_index) { - cairo_status_t status; + cairo_int_status_t status; _cairo_output_stream_printf (document->xml_node_glyphs, "<symbol overflow=\"visible\" id=\"glyph%d-%d\">\n", @@ -840,16 +840,16 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t *document, _cairo_output_stream_printf (document->xml_node_glyphs, "</symbol>\n"); - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } -static cairo_status_t +static cairo_int_status_t _cairo_svg_document_emit_font_subset (cairo_scaled_font_subset_t *font_subset, void *closure) { cairo_svg_document_t *document = closure; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; unsigned int i; - cairo_status_t status = CAIRO_STATUS_SUCCESS; _cairo_scaled_font_freeze_cache (font_subset->scaled_font); for (i = 0; i < font_subset->num_glyphs; i++) { @@ -1163,7 +1163,7 @@ static cairo_int_status_t _cairo_surface_base64_encode (cairo_surface_t *surface, cairo_output_stream_t *output) { - cairo_status_t status; + cairo_int_status_t status; base64_write_closure_t info; status = _cairo_surface_base64_encode_jpeg (surface, output); @@ -2137,7 +2137,7 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface, cairo_fill_rule_t fill_rule, double fill_tolerance, cairo_antialias_t fill_antialias, - cairo_path_fixed_t *path, + const cairo_path_fixed_t*path, cairo_operator_t stroke_op, const cairo_pattern_t *stroke_source, const cairo_stroke_style_t *stroke_style, @@ -2145,7 +2145,7 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface, const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_svg_surface_t *surface = abstract_surface; cairo_status_t status; @@ -2179,11 +2179,11 @@ static cairo_int_status_t _cairo_svg_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t*path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_svg_surface_t *surface = abstract_surface; cairo_status_t status; @@ -2274,7 +2274,7 @@ static cairo_int_status_t _cairo_svg_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; cairo_svg_surface_t *surface = abstract_surface; @@ -2340,7 +2340,7 @@ _cairo_svg_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_status_t status; cairo_svg_surface_t *surface = abstract_surface; @@ -2430,13 +2430,13 @@ static cairo_int_status_t _cairo_svg_surface_stroke (void *abstract_dst, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t*path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_svg_surface_t *surface = abstract_dst; cairo_status_t status; @@ -2473,13 +2473,13 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs) { cairo_svg_surface_t *surface = abstract_surface; cairo_svg_document_t *document = surface->document; cairo_path_fixed_t path; - cairo_status_t status; + cairo_int_status_t status; cairo_scaled_font_subsets_glyph_t subset_glyph; int i; @@ -2834,7 +2834,7 @@ _cairo_svg_surface_supports_fine_grained_fallbacks (void *abstract_surface) CAIRO_OPERATOR_SOURCE); } - return status == CAIRO_STATUS_SUCCESS; + return status == CAIRO_INT_STATUS_SUCCESS; } static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backend = { diff --git a/src/cairo-tee-surface.c b/src/cairo-tee-surface.c index df0ae9970..40f8aa3b9 100644 --- a/src/cairo-tee-surface.c +++ b/src/cairo-tee-surface.c @@ -199,12 +199,12 @@ static cairo_int_status_t _cairo_tee_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_tee_surface_t *surface = abstract_surface; cairo_surface_wrapper_t *slaves; int n, num_slaves; - cairo_status_t status; + cairo_int_status_t status; status = _cairo_surface_wrapper_paint (&surface->master, op, source, clip); if (unlikely (status)) @@ -226,12 +226,12 @@ _cairo_tee_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_tee_surface_t *surface = abstract_surface; cairo_surface_wrapper_t *slaves; + cairo_int_status_t status; int n, num_slaves; - cairo_status_t status; status = _cairo_surface_wrapper_mask (&surface->master, op, source, mask, clip); @@ -254,18 +254,18 @@ static cairo_int_status_t _cairo_tee_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_tee_surface_t *surface = abstract_surface; cairo_surface_wrapper_t *slaves; + cairo_int_status_t status; int n, num_slaves; - cairo_status_t status; status = _cairo_surface_wrapper_stroke (&surface->master, op, source, @@ -296,16 +296,16 @@ static cairo_int_status_t _cairo_tee_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_tee_surface_t *surface = abstract_surface; cairo_surface_wrapper_t *slaves; + cairo_int_status_t status; int n, num_slaves; - cairo_status_t status; status = _cairo_surface_wrapper_fill (&surface->master, op, source, @@ -327,7 +327,7 @@ _cairo_tee_surface_fill (void *abstract_surface, return status; } - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_SUCCESS; } static cairo_bool_t @@ -348,12 +348,12 @@ _cairo_tee_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_tee_surface_t *surface = abstract_surface; cairo_surface_wrapper_t *slaves; + cairo_int_status_t status; int n, num_slaves; - cairo_status_t status; cairo_glyph_t *glyphs_copy; /* XXX: This copying is ugly. */ @@ -504,8 +504,8 @@ cairo_tee_surface_remove (cairo_surface_t *abstract_surface, { cairo_tee_surface_t *surface; cairo_surface_wrapper_t *slaves; + cairo_int_status_t status; int n, num_slaves; - cairo_status_t status; if (unlikely (abstract_surface->status)) return; @@ -549,7 +549,7 @@ cairo_tee_surface_remove (cairo_surface_t *abstract_surface, cairo_surface_t * cairo_tee_surface_index (cairo_surface_t *abstract_surface, - int index) + unsigned int index) { cairo_tee_surface_t *surface; diff --git a/src/cairo-tee.h b/src/cairo-tee.h index 9c048c6fe..9125a3a4a 100644 --- a/src/cairo-tee.h +++ b/src/cairo-tee.h @@ -55,7 +55,7 @@ cairo_tee_surface_remove (cairo_surface_t *surface, cairo_public cairo_surface_t * cairo_tee_surface_index (cairo_surface_t *surface, - int index); + unsigned int index); CAIRO_END_DECLS diff --git a/src/cairo-tor-scan-converter.c b/src/cairo-tor-scan-converter.c index 888a39556..4c0d8dc96 100644 --- a/src/cairo-tor-scan-converter.c +++ b/src/cairo-tor-scan-converter.c @@ -1960,8 +1960,8 @@ blit_with_span_renderer (struct cell_list *cells, int xmin, int xmax) { struct cell *cell = cells->head; - int prev_x = xmin; - int cover = 0; + int prev_x = xmin, last_x = -1; + int cover = 0, last_cover = -1; cairo_half_open_span_t *spans; unsigned num_spans; @@ -2005,26 +2005,34 @@ blit_with_span_renderer (struct cell_list *cells, if (x > prev_x) { spans[num_spans].x = prev_x; spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover); + last_cover = cover; + last_x = prev_x; ++num_spans; } cover += cell->covered_height*GRID_X*2; area = cover - cell->uncovered_area; - spans[num_spans].x = x; - spans[num_spans].coverage = GRID_AREA_TO_ALPHA (area); - ++num_spans; + if (area != last_cover) { + spans[num_spans].x = x; + spans[num_spans].coverage = GRID_AREA_TO_ALPHA (area); + last_cover = area; + last_x = x; + ++num_spans; + } prev_x = x+1; } - if (prev_x <= xmax) { + if (prev_x <= xmax && cover != last_cover) { spans[num_spans].x = prev_x; spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover); + last_cover = cover; + last_x = prev_x; ++num_spans; } - if (prev_x < xmax && cover) { + if (last_x < xmax && last_cover) { spans[num_spans].x = xmax; spans[num_spans].coverage = 0; ++num_spans; diff --git a/src/cairo-traps.c b/src/cairo-traps.c index 2fe6684db..42e2eb553 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -76,6 +76,15 @@ _cairo_traps_limit (cairo_traps_t *traps, } void +_cairo_traps_init_with_clip (cairo_traps_t *traps, + const cairo_clip_t *clip) +{ + _cairo_traps_init (traps); + if (clip) + _cairo_traps_limit (traps, clip->boxes, clip->num_boxes); +} + +void _cairo_traps_clear (cairo_traps_t *traps) { traps->status = CAIRO_STATUS_SUCCESS; @@ -485,6 +494,44 @@ _cairo_traps_extents (const cairo_traps_t *traps, } } +static cairo_bool_t +_mono_edge_is_vertical (const cairo_line_t *line) +{ + return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x); +} + +static cairo_bool_t +_traps_are_pixel_aligned (cairo_traps_t *traps, + cairo_antialias_t antialias) +{ + int i; + + if (antialias == CAIRO_ANTIALIAS_NONE) { + for (i = 0; i < traps->num_traps; i++) { + if (! _mono_edge_is_vertical (&traps->traps[i].left) || + ! _mono_edge_is_vertical (&traps->traps[i].right)) + { + traps->maybe_region = FALSE; + return FALSE; + } + } + } else { + for (i = 0; i < traps->num_traps; i++) { + if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x || + traps->traps[i].right.p1.x != traps->traps[i].right.p2.x || + ! _cairo_fixed_is_integer (traps->traps[i].top) || + ! _cairo_fixed_is_integer (traps->traps[i].bottom) || + ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) || + ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x)) + { + traps->maybe_region = FALSE; + return FALSE; + } + } + } + + return TRUE; +} /** * _cairo_traps_extract_region: @@ -502,6 +549,7 @@ _cairo_traps_extents (const cairo_traps_t *traps, **/ cairo_int_status_t _cairo_traps_extract_region (cairo_traps_t *traps, + cairo_antialias_t antialias, cairo_region_t **region) { cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)]; @@ -510,20 +558,12 @@ _cairo_traps_extract_region (cairo_traps_t *traps, int i, rect_count; /* we only treat this a hint... */ - if (! traps->maybe_region) + if (antialias != CAIRO_ANTIALIAS_NONE && ! traps->maybe_region) return CAIRO_INT_STATUS_UNSUPPORTED; - for (i = 0; i < traps->num_traps; i++) { - if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x || - traps->traps[i].right.p1.x != traps->traps[i].right.p2.x || - ! _cairo_fixed_is_integer (traps->traps[i].top) || - ! _cairo_fixed_is_integer (traps->traps[i].bottom) || - ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) || - ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x)) - { - traps->maybe_region = FALSE; - return CAIRO_INT_STATUS_UNSUPPORTED; - } + if (! _traps_are_pixel_aligned (traps, antialias)) { + traps->maybe_region = FALSE; + return CAIRO_INT_STATUS_UNSUPPORTED; } if (traps->num_traps > ARRAY_LENGTH (stack_rects)) { @@ -535,19 +575,30 @@ _cairo_traps_extract_region (cairo_traps_t *traps, rect_count = 0; for (i = 0; i < traps->num_traps; i++) { - int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x); - int y1 = _cairo_fixed_integer_part (traps->traps[i].top); - int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x); - int y2 = _cairo_fixed_integer_part (traps->traps[i].bottom); - - rects[rect_count].x = x1; - rects[rect_count].y = y1; - rects[rect_count].width = x2 - x1; - rects[rect_count].height = y2 - y1; + int x1, y1, x2, y2; + + if (antialias == CAIRO_ANTIALIAS_NONE) { + x1 = _cairo_fixed_integer_round_down (traps->traps[i].left.p1.x); + y1 = _cairo_fixed_integer_round_down (traps->traps[i].top); + x2 = _cairo_fixed_integer_round_down (traps->traps[i].right.p1.x); + y2 = _cairo_fixed_integer_round_down (traps->traps[i].bottom); + } else { + x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x); + y1 = _cairo_fixed_integer_part (traps->traps[i].top); + x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x); + y2 = _cairo_fixed_integer_part (traps->traps[i].bottom); + } - rect_count++; + if (x2 > x1 && y2 > y1) { + rects[rect_count].x = x1; + rects[rect_count].y = y1; + rects[rect_count].width = x2 - x1; + rects[rect_count].height = y2 - y1; + rect_count++; + } } + *region = cairo_region_create_rectangles (rects, rect_count); status = (*region)->status; diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c index 176f163c2..844e52119 100644 --- a/src/cairo-truetype-subset.c +++ b/src/cairo-truetype-subset.c @@ -122,7 +122,8 @@ static cairo_status_t _cairo_truetype_font_set_error (cairo_truetype_font_t *font, cairo_status_t status) { - if (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED) + if (status == CAIRO_STATUS_SUCCESS || + status == (int)CAIRO_INT_STATUS_UNSUPPORTED) return status; _cairo_status_set_error (&font->status, status); @@ -1056,19 +1057,19 @@ cairo_truetype_font_create_truetype_table_list (cairo_truetype_font_t *font) size = 0; if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, TT_TAG_cvt, 0, NULL, - &size) == CAIRO_STATUS_SUCCESS) + &size) == CAIRO_INT_STATUS_SUCCESS) has_cvt = TRUE; size = 0; if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, TT_TAG_fpgm, 0, NULL, - &size) == CAIRO_STATUS_SUCCESS) + &size) == CAIRO_INT_STATUS_SUCCESS) has_fpgm = TRUE; size = 0; if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, TT_TAG_prep, 0, NULL, - &size) == CAIRO_STATUS_SUCCESS) + &size) == CAIRO_INT_STATUS_SUCCESS) has_prep = TRUE; font->num_tables = 0; @@ -1344,7 +1345,7 @@ _cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font, unsigned long index, uint32_t *ucs4) { - cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; const cairo_scaled_font_backend_t *backend; tt_cmap_t *cmap; char buf[4]; diff --git a/src/cairo-type1-fallback.c b/src/cairo-type1-fallback.c index 39bc53ff7..5284cfed0 100644 --- a/src/cairo-type1-fallback.c +++ b/src/cairo-type1-fallback.c @@ -626,7 +626,7 @@ cairo_type1_font_write_private_dict (cairo_type1_font_t *font, fail: status2 = _cairo_output_stream_destroy (encrypted_output); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) status = status2; return status; diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c index e9e831150..bad0d3b26 100644 --- a/src/cairo-type3-glyph-surface.c +++ b/src/cairo-type3-glyph-surface.c @@ -188,7 +188,7 @@ static cairo_int_status_t _cairo_type3_glyph_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_type3_glyph_surface_t *surface = abstract_surface; const cairo_surface_pattern_t *pattern; @@ -224,7 +224,7 @@ _cairo_type3_glyph_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { return _cairo_type3_glyph_surface_paint (abstract_surface, op, mask, @@ -235,13 +235,13 @@ static cairo_int_status_t _cairo_type3_glyph_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_type3_glyph_surface_t *surface = abstract_surface; cairo_int_status_t status; @@ -261,11 +261,11 @@ static cairo_int_status_t _cairo_type3_glyph_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_type3_glyph_surface_t *surface = abstract_surface; cairo_int_status_t status; @@ -286,7 +286,7 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs) { cairo_type3_glyph_surface_t *surface = abstract_surface; @@ -418,7 +418,7 @@ _cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface, { cairo_type3_glyph_surface_t *surface = abstract_surface; cairo_scaled_glyph_t *scaled_glyph; - cairo_status_t status, status2; + cairo_int_status_t status, status2; cairo_output_stream_t *null_stream; if (unlikely (surface->base.status)) @@ -436,11 +436,11 @@ _cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface, CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE, &scaled_glyph); - if (_cairo_status_is_error (status)) + if (_cairo_int_status_is_error (status)) goto cleanup; if (status == CAIRO_INT_STATUS_UNSUPPORTED) { - status = CAIRO_STATUS_SUCCESS; + status = CAIRO_INT_STATUS_SUCCESS; goto cleanup; } @@ -451,13 +451,13 @@ _cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface, status = _cairo_pdf_operators_flush (&surface->pdf_operators); if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) - status = CAIRO_STATUS_SUCCESS; + status = CAIRO_INT_STATUS_SUCCESS; cleanup: _cairo_scaled_font_thaw_cache (surface->scaled_font); status2 = _cairo_output_stream_destroy (null_stream); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) status = status2; return status; @@ -472,7 +472,7 @@ _cairo_type3_glyph_surface_emit_glyph (void *abstract_surface, { cairo_type3_glyph_surface_t *surface = abstract_surface; cairo_scaled_glyph_t *scaled_glyph; - cairo_status_t status, status2; + cairo_int_status_t status, status2; double x_advance, y_advance; cairo_matrix_t font_matrix_inverse; @@ -492,10 +492,10 @@ _cairo_type3_glyph_surface_emit_glyph (void *abstract_surface, glyph_index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) status = CAIRO_INT_STATUS_IMAGE_FALLBACK; } - if (_cairo_status_is_error (status)) { + if (_cairo_int_status_is_error (status)) { _cairo_scaled_font_thaw_cache (surface->scaled_font); return status; } @@ -508,7 +508,7 @@ _cairo_type3_glyph_surface_emit_glyph (void *abstract_surface, /* The invertability of font_matrix is tested in * pdf_operators_show_glyphs before any glyphs are mapped to the * subset. */ - assert (status2 == CAIRO_STATUS_SUCCESS); + assert (status2 == CAIRO_INT_STATUS_SUCCESS); cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance); *width = x_advance; @@ -525,7 +525,7 @@ _cairo_type3_glyph_surface_emit_glyph (void *abstract_surface, _cairo_fixed_to_double (bbox->p2.x), - _cairo_fixed_to_double (bbox->p1.y)); - if (status == CAIRO_STATUS_SUCCESS) { + if (status == CAIRO_INT_STATUS_SUCCESS) { cairo_output_stream_t *mem_stream; mem_stream = _cairo_memory_stream_create (); @@ -540,17 +540,17 @@ _cairo_type3_glyph_surface_emit_glyph (void *abstract_surface, &surface->base); status2 = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) status = status2; _cairo_output_stream_printf (surface->stream, "Q\n"); _cairo_type3_glyph_surface_set_stream (surface, stream); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) _cairo_memory_stream_copy (mem_stream, stream); status2 = _cairo_output_stream_destroy (mem_stream); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) status = status2; } diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h index 8881055ea..bed641211 100644 --- a/src/cairo-types-private.h +++ b/src/cairo-types-private.h @@ -228,16 +228,7 @@ typedef enum _cairo_paginated_mode { * 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 */ -typedef enum _cairo_int_status { - CAIRO_INT_STATUS_UNSUPPORTED = 100, - CAIRO_INT_STATUS_DEGENERATE, - CAIRO_INT_STATUS_NOTHING_TO_DO, - CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY, - CAIRO_INT_STATUS_IMAGE_FALLBACK, - CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN, - - CAIRO_INT_STATUS_LAST_STATUS -} cairo_int_status_t; +typedef enum _cairo_int_status cairo_int_status_t; typedef enum _cairo_internal_surface_type { CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT = 0x1000, diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c index a524d588f..522711d5c 100644 --- a/src/cairo-user-font.c +++ b/src/cairo-user-font.c @@ -158,7 +158,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font, status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font, _cairo_scaled_glyph_index(scaled_glyph), cr, &extents); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_INT_STATUS_SUCCESS) status = cairo_status (cr); cairo_destroy (cr); @@ -328,11 +328,12 @@ _cairo_user_text_to_glyphs (void *abstract_font, glyphs, num_glyphs, clusters, num_clusters, cluster_flags); - if (status != CAIRO_STATUS_SUCCESS && - status != CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED) + if (status != CAIRO_INT_STATUS_SUCCESS && + status != CAIRO_INT_STATUS_USER_FONT_NOT_IMPLEMENTED) return status; - if (status == CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED || *num_glyphs < 0) { + if (status == CAIRO_INT_STATUS_USER_FONT_NOT_IMPLEMENTED || + *num_glyphs < 0) { if (orig_glyphs != *glyphs) { cairo_glyph_free (*glyphs); *glyphs = orig_glyphs; diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c index 58d404a6e..a5d278779 100644 --- a/src/cairo-win32-printing-surface.c +++ b/src/cairo-win32-printing-surface.c @@ -1167,7 +1167,7 @@ static cairo_int_status_t _cairo_win32_printing_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_win32_surface_t *surface = abstract_surface; cairo_solid_pattern_t clear; @@ -1244,13 +1244,13 @@ static cairo_int_status_t _cairo_win32_printing_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *stroke_ctm, const cairo_matrix_t *stroke_ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_win32_surface_t *surface = abstract_surface; cairo_int_status_t status; @@ -1373,11 +1373,11 @@ static cairo_int_status_t _cairo_win32_printing_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_win32_surface_t *surface = abstract_surface; cairo_int_status_t status; @@ -1528,7 +1528,7 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs) { cairo_win32_surface_t *surface = abstract_surface; diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c index 0f0bffcba..f309b4b35 100644 --- a/src/cairo-win32-surface.c +++ b/src/cairo-win32-surface.c @@ -1522,7 +1522,7 @@ _cairo_win32_surface_show_glyphs_internal (void *surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs, cairo_bool_t glyph_indexing) { @@ -1674,11 +1674,11 @@ cairo_int_status_t _cairo_win32_surface_show_glyphs (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_glyph_t *glyphs, + cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, - int *remaining_glyphs) + const cairo_clip_t *clip, + int *remaining_glyphs) { return _cairo_win32_surface_show_glyphs_internal (surface, op, diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h index 92898b84d..d52306ec1 100644 --- a/src/cairo-xcb-private.h +++ b/src/cairo-xcb-private.h @@ -360,36 +360,36 @@ cairo_private cairo_int_status_t _cairo_xcb_surface_cairo_paint (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_int_status_t _cairo_xcb_surface_cairo_mask (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_int_status_t _cairo_xcb_surface_cairo_stroke (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_int_status_t _cairo_xcb_surface_cairo_fill (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_int_status_t _cairo_xcb_surface_cairo_glyphs (cairo_xcb_surface_t *surface, @@ -398,42 +398,42 @@ _cairo_xcb_surface_cairo_glyphs (cairo_xcb_surface_t *surface, cairo_scaled_font_t *scaled_font, cairo_glyph_t *glyphs, int num_glyphs, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_int_status_t _cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_int_status_t _cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_int_status_t -_cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_path_fixed_t *path, +_cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias, - cairo_clip_t *clip); + cairo_antialias_t antialias, + const cairo_clip_t *clip); cairo_private cairo_int_status_t _cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface, - cairo_operator_t op, + cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t*path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_int_status_t _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface, @@ -442,7 +442,7 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface, cairo_scaled_font_t *scaled_font, cairo_glyph_t *glyphs, int num_glyphs, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private void _cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font); diff --git a/src/cairo-xcb-surface-cairo.c b/src/cairo-xcb-surface-cairo.c index 79c4d6cc5..338a616cb 100644 --- a/src/cairo-xcb-surface-cairo.c +++ b/src/cairo-xcb-surface-cairo.c @@ -38,7 +38,7 @@ cairo_int_status_t _cairo_xcb_surface_cairo_paint (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { return CAIRO_INT_STATUS_UNSUPPORTED; } @@ -48,7 +48,7 @@ _cairo_xcb_surface_cairo_mask (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { return CAIRO_INT_STATUS_UNSUPPORTED; } @@ -57,13 +57,13 @@ cairo_int_status_t _cairo_xcb_surface_cairo_stroke (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { return CAIRO_INT_STATUS_UNSUPPORTED; } @@ -72,11 +72,11 @@ cairo_int_status_t _cairo_xcb_surface_cairo_fill (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { return CAIRO_INT_STATUS_UNSUPPORTED; } @@ -88,7 +88,7 @@ _cairo_xcb_surface_cairo_glyphs (cairo_xcb_surface_t *surface, cairo_scaled_font_t *scaled_font, cairo_glyph_t *glyphs, int num_glyphs, - cairo_clip_t *clip) + const cairo_clip_t *clip) { return CAIRO_INT_STATUS_UNSUPPORTED; } diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c index fc349a3a2..000f00f25 100644 --- a/src/cairo-xcb-surface-render.c +++ b/src/cairo-xcb-surface-render.c @@ -425,7 +425,7 @@ _cairo_xcb_picture_set_matrix (cairo_xcb_picture_t *picture, { xcb_render_transform_t transform; pixman_transform_t *pixman_transform; - cairo_status_t ignored; + cairo_int_status_t ignored; /* Casting between pixman_transform_t and xcb_render_transform_t is safe * because they happen to be the exact same type. @@ -1572,13 +1572,7 @@ _create_composite_mask (cairo_clip_t *clip, cairo_bool_t clip_surface = FALSE; cairo_status_t status; - if (clip != NULL) { - cairo_region_t *clip_region; - - status = _cairo_clip_get_region (clip, &clip_region); - assert (! _cairo_status_is_error (status)); - clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; - } + clip_surface = ! _cairo_clip_is_region (clip); surface = (cairo_xcb_surface_t *) _cairo_xcb_surface_create_similar (dst, CAIRO_CONTENT_ALPHA, @@ -1794,6 +1788,7 @@ _clip_and_composite_combine (cairo_clip_t *clip, extents->x, extents->y, extents->width, extents->height); } + cairo_surface_destroy (clip_surface); CLEANUP_SURFACE: cairo_surface_destroy (&tmp->base); @@ -2056,6 +2051,8 @@ _cairo_xcb_surface_fixup_unbounded_with_mask (cairo_xcb_surface_t *dst, width, height); } + cairo_surface_destroy (&mask->base); + return CAIRO_STATUS_SUCCESS; } @@ -2086,7 +2083,7 @@ _cairo_xcb_surface_fixup_unbounded_boxes (cairo_xcb_surface_t *dst, _cairo_boxes_init (&tmp); - status = _cairo_boxes_add (&tmp, &box); + status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box); assert (status == CAIRO_STATUS_SUCCESS); tmp.chunks.next = &boxes->chunks; @@ -2103,12 +2100,14 @@ _cairo_xcb_surface_fixup_unbounded_boxes (cairo_xcb_surface_t *dst, pbox = pixman_region32_rectangles (&clip_region->rgn, &i); _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i); - status = _cairo_boxes_add (&clear, &box); + status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box); assert (status == CAIRO_STATUS_SUCCESS); for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { for (i = 0; i < chunk->count; i++) { - status = _cairo_boxes_add (&clear, &chunk->base[i]); + status = _cairo_boxes_add (&clear, + CAIRO_ANTIALIAS_DEFAULT, + &chunk->base[i]); if (unlikely (status)) { _cairo_boxes_fini (&clear); return status; @@ -2173,6 +2172,22 @@ _cairo_xcb_surface_clear (cairo_xcb_surface_t *dst) return CAIRO_STATUS_SUCCESS; } +static cairo_bool_t +need_bounded_clip (cairo_composite_rectangles_t *extents) +{ + return ! _cairo_clip_is_region (extents->clip); +} + +static cairo_bool_t +need_unbounded_clip (cairo_composite_rectangles_t *extents) +{ + if (! extents->is_bounded) + return need_bounded_clip (extents); + + return extents->clip->path != NULL; +} + + static cairo_status_t _clip_and_composite (cairo_xcb_surface_t *dst, cairo_operator_t op, @@ -2180,43 +2195,10 @@ _clip_and_composite (cairo_xcb_surface_t *dst, xcb_draw_func_t draw_func, void *draw_closure, cairo_composite_rectangles_t*extents, - cairo_clip_t *clip) + cairo_bool_t need_clip_surface) { cairo_status_t status; - cairo_region_t *clip_region = NULL; - cairo_region_t extents_region; - cairo_bool_t need_clip_surface = FALSE; - - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) - return CAIRO_STATUS_SUCCESS; - - assert (! _cairo_status_is_error (status)); - need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; - - if (clip_region != NULL) { - cairo_rectangle_int_t rect; - cairo_bool_t is_empty; - - cairo_region_get_extents (clip_region, &rect); - is_empty = ! _cairo_rectangle_intersect (&extents->unbounded, &rect); - if (unlikely (is_empty)) - return CAIRO_STATUS_SUCCESS; - - is_empty = ! _cairo_rectangle_intersect (&extents->bounded, &rect); - if (unlikely (is_empty && extents->is_bounded)) - return CAIRO_STATUS_SUCCESS; - } - } else if (!extents->is_bounded) { - /* The X server will estimate the affected region of the unbounded - * operation and will apply the operation to that rectangle. - * However, there are cases where this estimate is too high (e.g. - * the test suite's clip-fill-{eo,nz}-unbounded tests). - */ - _cairo_region_init_rectangle (&extents_region, &extents->unbounded); - clip_region = &extents_region; - } + cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip); status = _cairo_xcb_connection_acquire (dst->connection); if (unlikely (status)) @@ -2241,7 +2223,7 @@ _clip_and_composite (cairo_xcb_surface_t *dst, } if (op == CAIRO_OPERATOR_SOURCE) { - status = _clip_and_composite_source (clip, src, + status = _clip_and_composite_source (extents->clip, src, draw_func, draw_closure, dst, &extents->bounded); } else { @@ -2252,11 +2234,11 @@ _clip_and_composite (cairo_xcb_surface_t *dst, if (need_clip_surface) { if (extents->is_bounded) { - status = _clip_and_composite_with_mask (clip, op, src, + status = _clip_and_composite_with_mask (extents->clip, op, src, draw_func, draw_closure, dst, &extents->bounded); } else { - status = _clip_and_composite_combine (clip, op, src, + status = _clip_and_composite_combine (extents->clip, op, src, draw_func, draw_closure, dst, &extents->bounded); } @@ -2271,15 +2253,13 @@ _clip_and_composite (cairo_xcb_surface_t *dst, if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) { if (need_clip_surface) - status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst, extents, clip); + status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst, extents, extents->clip); else status = _cairo_xcb_surface_fixup_unbounded (dst, extents); } if (clip_region != NULL) _cairo_xcb_surface_clear_clip_region (dst); - if (clip_region == &extents_region) - _cairo_region_fini (&extents_region); _cairo_xcb_connection_release (dst->connection); @@ -2291,26 +2271,13 @@ _core_boxes (cairo_xcb_surface_t *dst, cairo_operator_t op, const cairo_pattern_t *src, cairo_boxes_t *boxes, - cairo_antialias_t antialias, - cairo_clip_t *clip, const cairo_composite_rectangles_t *extents) { - if (antialias != CAIRO_ANTIALIAS_NONE) { - if (! boxes->is_pixel_aligned) - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - if (clip != NULL) { - cairo_region_t *clip_region; - cairo_status_t status; - - status = _cairo_clip_get_region (clip, &clip_region); - assert (status == CAIRO_STATUS_SUCCESS || - status == CAIRO_INT_STATUS_UNSUPPORTED); + if (! boxes->is_pixel_aligned) + return CAIRO_INT_STATUS_UNSUPPORTED; - if (status == CAIRO_INT_STATUS_UNSUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; - } + if (! _cairo_clip_is_region (extents->clip)) + return CAIRO_INT_STATUS_UNSUPPORTED; if (op == CAIRO_OPERATOR_CLEAR) return _cairo_xcb_surface_core_fill_boxes (dst, CAIRO_COLOR_TRANSPARENT, boxes); @@ -2336,36 +2303,25 @@ _composite_boxes (cairo_xcb_surface_t *dst, cairo_operator_t op, const cairo_pattern_t *src, cairo_boxes_t *boxes, - cairo_antialias_t antialias, - cairo_clip_t *clip, const cairo_composite_rectangles_t *extents) { - cairo_bool_t need_clip_mask = FALSE; - cairo_region_t *clip_region = NULL; + cairo_bool_t need_clip_mask = extents->clip->path != NULL; + cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip); cairo_status_t status; /* If the boxes are not pixel-aligned, we will need to compute a real mask */ - if (antialias != CAIRO_ANTIALIAS_NONE) { - if (! boxes->is_pixel_aligned) - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - assert (status == CAIRO_STATUS_SUCCESS || - status == CAIRO_INT_STATUS_UNSUPPORTED); - - need_clip_mask = status == CAIRO_INT_STATUS_UNSUPPORTED; - if (need_clip_mask && - (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE)) - { - return CAIRO_INT_STATUS_UNSUPPORTED; - } + if (! boxes->is_pixel_aligned) + return CAIRO_INT_STATUS_UNSUPPORTED; - if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1) - clip_region = NULL; + if (need_clip_mask && + (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE)) + { + return CAIRO_INT_STATUS_UNSUPPORTED; } + if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1) + clip_region = NULL; + status = _cairo_xcb_connection_acquire (dst->connection); if (unlikely (status)) return status; @@ -2391,7 +2347,9 @@ _composite_boxes (cairo_xcb_surface_t *dst, cairo_surface_t *clip_surface; int clip_x, clip_y; - clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y); + clip_surface = _cairo_clip_get_surface (extents->clip, + &dst->base, + &clip_x, &clip_y); if (unlikely (clip_surface->status)) return clip_surface->status; @@ -2400,6 +2358,7 @@ _composite_boxes (cairo_xcb_surface_t *dst, cairo_matrix_init_translate (&mask.base.matrix, -clip_x, -clip_y); + cairo_surface_destroy (clip_surface); if (op == CAIRO_OPERATOR_CLEAR) { src = NULL; @@ -2426,17 +2385,96 @@ _composite_boxes (cairo_xcb_surface_t *dst, return status; } +static cairo_bool_t +cairo_boxes_for_each_box (cairo_boxes_t *boxes, + cairo_bool_t (*func) (cairo_box_t *box, + void *data), + void *data) +{ + struct _cairo_boxes_chunk *chunk; + int i; + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) + if (! func (&chunk->base[i], data)) + return FALSE; + } + + return TRUE; +} + +struct image_contains_box { + int width, height; + int tx, ty; +}; + +static cairo_bool_t image_contains_box (cairo_box_t *box, void *closure) +{ + struct image_contains_box *data = closure; + + return + box->p1.x + data->tx >= 0 && + box->p1.y + data->ty >= 0 && + box->p2.x + data->tx <= data->width && + box->p2.y + data->ty <= data->height; +} + +struct image_upload_box { + cairo_xcb_surface_t *surface; + cairo_image_surface_t *image; + xcb_gcontext_t gc; + int tx, ty; +}; + +static cairo_bool_t image_upload_box (cairo_box_t *box, void *closure) +{ + const struct image_upload_box *iub = closure; + int width = box->p2.x - box->p1.x; + int height = box->p2.y - box->p1.y; + int bpp = PIXMAN_FORMAT_BPP (iub->image->pixman_format); + int len = CAIRO_STRIDE_FOR_WIDTH_BPP (width, bpp); + if (len == iub->image->stride) { + _cairo_xcb_connection_put_image (iub->surface->connection, + iub->surface->drawable, + iub->gc, + width, height, + box->p1.x, box->p2.y, + iub->image->depth, + iub->image->stride, + iub->image->data + + (box->p1.y + iub->ty) * iub->image->stride + + (box->p1.x + iub->tx) * bpp/8); + } else { + _cairo_xcb_connection_put_subimage (iub->surface->connection, + iub->surface->drawable, + iub->gc, + box->p1.x + iub->tx, + box->p1.y + iub->ty, + width, height, + bpp / 8, + iub->image->stride, + box->p1.x, box->p2.y, + iub->image->depth, + iub->image->data); + } + + return TRUE; +} + static cairo_status_t _upload_image_inplace (cairo_xcb_surface_t *surface, const cairo_pattern_t *source, - const cairo_rectangle_int_t *extents) + cairo_boxes_t *boxes) { const cairo_surface_pattern_t *pattern; + struct image_contains_box icb; + struct image_upload_box iub; cairo_image_surface_t *image; - xcb_gcontext_t gc; cairo_status_t status; int tx, ty; - int len, bpp; + + if (! boxes->is_pixel_aligned) + return CAIRO_INT_STATUS_UNSUPPORTED; if (source->type != CAIRO_PATTERN_TYPE_SURFACE) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -2445,6 +2483,7 @@ _upload_image_inplace (cairo_xcb_surface_t *surface, if (pattern->surface->type != CAIRO_SURFACE_TYPE_IMAGE) return CAIRO_INT_STATUS_UNSUPPORTED; + /* Have we already upload this image to a pixmap? */ { cairo_xcb_picture_t *snapshot; @@ -2466,79 +2505,73 @@ _upload_image_inplace (cairo_xcb_surface_t *surface, if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty)) return CAIRO_INT_STATUS_UNSUPPORTED; - image = (cairo_image_surface_t *) pattern->surface; - if (source->extend != CAIRO_EXTEND_NONE && - (extents->x + tx < 0 || - extents->y + ty < 0 || - extents->x + tx + extents->width > image->width || - extents->y + ty + extents->height > image->height)) - { + /* Check that the data is entirely within the image */ + icb.width = image->width; + icb.height = image->height; + icb.tx = tx; + icb.ty = ty; + if (! cairo_boxes_for_each_box (boxes, image_contains_box, &icb)) return CAIRO_INT_STATUS_UNSUPPORTED; - } status = _cairo_xcb_connection_acquire (surface->connection); if (unlikely (status)) return status; - gc = _cairo_xcb_screen_get_gc (surface->screen, surface->drawable, image->depth); - - /* Do we need to trim the image? */ - bpp = PIXMAN_FORMAT_BPP (image->pixman_format); - len = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->width, bpp); - if (len == image->stride) { - _cairo_xcb_connection_put_image (surface->connection, - surface->drawable, gc, - extents->width, extents->height, - extents->x, extents->y, - image->depth, - image->stride, - image->data + - (extents->y + ty) * image->stride + - (extents->x + tx) * bpp/8); - } else { - _cairo_xcb_connection_put_subimage (surface->connection, - surface->drawable, gc, - extents->x + tx, extents->y + ty, - extents->width, extents->height, - bpp / 8, - image->stride, - extents->x, extents->y, - image->depth, - image->data); - } + iub.surface = surface; + iub.image = image; + iub.gc = _cairo_xcb_screen_get_gc (surface->screen, + surface->drawable, + image->depth); + iub.tx = tx; + iub.ty = ty; + cairo_boxes_for_each_box (boxes, image_upload_box, &iub); - _cairo_xcb_screen_put_gc (surface->screen, image->depth, gc); + _cairo_xcb_screen_put_gc (surface->screen, image->depth, iub.gc); _cairo_xcb_connection_release (surface->connection); return CAIRO_STATUS_SUCCESS; } +static void +trim_extents_to_traps (cairo_composite_rectangles_t *extents, + cairo_traps_t *traps) +{ + cairo_box_t box; + + /* X trims the affected area to the extents of the trapezoids, so + * we need to compensate when fixing up the unbounded area. + */ + _cairo_traps_extents (traps, &box); + _cairo_box_round_to_rectangle (&box, &extents->mask); + _cairo_rectangle_intersect (&extents->bounded, &extents->mask); +} + static cairo_status_t _clip_and_composite_boxes (cairo_xcb_surface_t *dst, cairo_operator_t op, const cairo_pattern_t *src, cairo_boxes_t *boxes, - cairo_antialias_t antialias, - cairo_composite_rectangles_t *extents, - cairo_clip_t *clip) + cairo_composite_rectangles_t *extents) { composite_traps_info_t info; - cairo_status_t status; + cairo_int_status_t status; if (boxes->num_boxes == 0 && extents->is_bounded) return CAIRO_STATUS_SUCCESS; - if (clip == NULL && - (op == CAIRO_OPERATOR_SOURCE || (op == CAIRO_OPERATOR_OVER && dst->base.is_clear)) && - boxes->num_boxes == 1 && - extents->bounded.width == dst->width && - extents->bounded.height == dst->height) + if (boxes->is_pixel_aligned && _cairo_clip_is_region (extents->clip) && + (op == CAIRO_OPERATOR_SOURCE || (op == CAIRO_OPERATOR_OVER && dst->base.is_clear))) { - op = CAIRO_OPERATOR_SOURCE; - dst->deferred_clear = FALSE; + if (boxes->num_boxes == 1 && + extents->bounded.width == dst->width && + extents->bounded.height == dst->height) + { + op = CAIRO_OPERATOR_SOURCE; + dst->deferred_clear = FALSE; + } - status = _upload_image_inplace (dst, src, &extents->bounded); + status = _upload_image_inplace (dst, src, boxes); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } @@ -2553,14 +2586,16 @@ _clip_and_composite_boxes (cairo_xcb_surface_t *dst, op = CAIRO_OPERATOR_SOURCE; } - if (clip == NULL && op == CAIRO_OPERATOR_SOURCE && boxes->num_boxes == 1) { - status = _upload_image_inplace (dst, src, &extents->bounded); + if (boxes->is_pixel_aligned && + _cairo_clip_is_region (extents->clip) && + op == CAIRO_OPERATOR_SOURCE) { + status = _upload_image_inplace (dst, src, boxes); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } if ((dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0) - return _core_boxes (dst, op, src, boxes, antialias, clip, extents); + return _core_boxes (dst, op, src, boxes, extents); if (dst->deferred_clear) { status = _cairo_xcb_surface_clear (dst); @@ -2569,7 +2604,7 @@ _clip_and_composite_boxes (cairo_xcb_surface_t *dst, } /* Use a fast path if the boxes are pixel aligned */ - status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents); + status = _composite_boxes (dst, op, src, boxes, extents); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; @@ -2581,10 +2616,11 @@ _clip_and_composite_boxes (cairo_xcb_surface_t *dst, if (unlikely (status)) return status; - info.antialias = antialias; + trim_extents_to_traps (extents, &info.traps); + info.antialias = CAIRO_ANTIALIAS_DEFAULT; status = _clip_and_composite (dst, op, src, _composite_traps, &info, - extents, clip); + extents, need_unbounded_clip (extents)); _cairo_traps_fini (&info.traps); return status; @@ -2738,38 +2774,14 @@ _composite_mask (void *closure, /* high level rasteriser -> compositor */ -static cairo_clip_path_t * -_clip_get_single_path (cairo_clip_t *clip) -{ - cairo_clip_path_t *iter = clip->path; - cairo_clip_path_t *path = NULL; - - do { - if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) { - if (path != NULL) - return FALSE; - - path = iter; - } - iter = iter->prev; - } while (iter != NULL); - - return path; -} - cairo_int_status_t _cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_composite_rectangles_t extents; cairo_boxes_t boxes; - cairo_box_t *clip_boxes = boxes.boxes_embedded; - cairo_clip_t local_clip; - cairo_clip_path_t *clip_path; - cairo_bool_t have_clip = FALSE; - int num_boxes = ARRAY_LENGTH (boxes.boxes_embedded); cairo_status_t status; if (unlikely (! _operator_is_supported (surface->flags, op))) @@ -2794,45 +2806,13 @@ _cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; - - if (clip != NULL) { - clip = _cairo_clip_init_copy (&local_clip, clip); - have_clip = TRUE; - } - - status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); - if (unlikely (status)) { - if (have_clip) - _cairo_clip_fini (&local_clip); - - return status; - } - - if (clip != NULL && - extents.is_bounded && - (clip_path = _clip_get_single_path (clip)) != NULL) - { - status = _cairo_xcb_surface_render_fill (surface, op, source, - &clip_path->path, - clip_path->fill_rule, - clip_path->tolerance, - clip_path->antialias, - NULL); - } - else - { - _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes); + status = _cairo_clip_to_boxes(extents.clip, &boxes); + if (likely (status == CAIRO_STATUS_SUCCESS)) { status = _clip_and_composite_boxes (surface, op, source, - &boxes, CAIRO_ANTIALIAS_DEFAULT, - &extents, clip); - if (clip_boxes != boxes.boxes_embedded) - free (clip_boxes); + &boxes, &extents); } - if (have_clip) - _cairo_clip_fini (&local_clip); + _cairo_composite_rectangles_fini (&extents); return status; } @@ -2842,11 +2822,9 @@ _cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_composite_rectangles_t extents; - cairo_clip_t local_clip; - cairo_bool_t have_clip = FALSE; cairo_status_t status; if (unlikely (! _operator_is_supported (surface->flags, op))) @@ -2861,25 +2839,11 @@ _cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; - - if (clip != NULL && extents.is_bounded) { - clip = _cairo_clip_init_copy (&local_clip, clip); - status = _cairo_clip_rectangle (clip, &extents.bounded); - if (unlikely (status)) { - _cairo_clip_fini (&local_clip); - return status; - } - have_clip = TRUE; - } - status = _clip_and_composite (surface, op, source, _composite_mask, (void *) mask, - &extents, clip); + &extents, need_bounded_clip (&extents)); - if (have_clip) - _cairo_clip_fini (&local_clip); + _cairo_composite_rectangles_fini (&extents); return status; } @@ -2891,27 +2855,19 @@ _cairo_xcb_surface_render_composite_polygon (cairo_xcb_surface_t *dst, cairo_polygon_t *polygon, cairo_antialias_t antialias, cairo_fill_rule_t fill_rule, - cairo_composite_rectangles_t *extents, - cairo_clip_t *clip) + cairo_composite_rectangles_t *extents) { composite_traps_info_t traps; - cairo_bool_t clip_surface = FALSE; + cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip); + cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip); cairo_status_t status; - cairo_bool_t is_not_empty; if (polygon->num_edges == 0) { status = CAIRO_STATUS_SUCCESS; if (! extents->is_bounded) { - cairo_region_t *clip_region = NULL; - - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; - if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1) clip_region = NULL; - } if (clip_surface == FALSE) { if (clip_region != NULL) @@ -2924,31 +2880,19 @@ _cairo_xcb_surface_render_composite_polygon (cairo_xcb_surface_t *dst, } else { status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst, extents, - clip); + extents->clip); } } return status; } - _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask); - is_not_empty = _cairo_rectangle_intersect (&extents->bounded, &extents->mask); - if (extents->is_bounded && ! is_not_empty) - return CAIRO_STATUS_SUCCESS; - _cairo_traps_init (&traps.traps); status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule); if (unlikely (status)) goto CLEANUP_TRAPS; - if (clip != NULL) { - cairo_region_t *clip_region; - - status = _cairo_clip_get_region (clip, &clip_region); - clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; - } - if (traps.traps.has_intersections) { if (traps.traps.is_rectangular) status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps.traps, CAIRO_FILL_RULE_WINDING); @@ -2973,18 +2917,18 @@ _cairo_xcb_surface_render_composite_polygon (cairo_xcb_surface_t *dst, _boxes_for_traps (&boxes, &traps.traps, antialias); status = _clip_and_composite_boxes (dst, op, source, - &boxes, antialias, - extents, clip); + &boxes, extents); } else { /* Otherwise render the trapezoids to a mask and composite in the usual * fashion. */ + trim_extents_to_traps (extents, &traps.traps); traps.antialias = antialias; status = _clip_and_composite (dst, op, source, _composite_traps, &traps, - extents, clip); + extents, need_unbounded_clip (extents)); } CLEANUP_TRAPS: @@ -2997,22 +2941,18 @@ static cairo_int_status_t _cairo_xcb_surface_render_stroke_as_polygon (cairo_xcb_surface_t *dst, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip, - const cairo_box_t *clip_boxes, - int num_boxes, cairo_composite_rectangles_t *extents) { cairo_polygon_t polygon; cairo_status_t status; - _cairo_polygon_init (&polygon, clip_boxes, num_boxes); - + _cairo_polygon_init_with_clip (&polygon, extents->clip); status = _cairo_path_fixed_stroke_to_polygon (path, stroke_style, ctm, ctm_inverse, @@ -3022,9 +2962,8 @@ _cairo_xcb_surface_render_stroke_as_polygon (cairo_xcb_surface_t *dst, status = _cairo_xcb_surface_render_composite_polygon (dst, op, source, &polygon, antialias, CAIRO_FILL_RULE_WINDING, - extents, clip); + extents); } - _cairo_polygon_fini (&polygon); return status; @@ -3042,13 +2981,12 @@ static cairo_status_t _cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t *dst, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip, cairo_composite_rectangles_t *extents) { cairo_surface_t *image; @@ -3081,7 +3019,7 @@ _cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t *dst, cairo_matrix_init_translate (&mask.base.matrix, -x, -y); status = _clip_and_composite (dst, op, source, _composite_mask, (void *) &mask.base, - extents, clip); + extents, need_bounded_clip (extents)); _cairo_pattern_fini (&mask.base); } @@ -3095,20 +3033,16 @@ cairo_int_status_t _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_composite_rectangles_t extents; - cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; - int num_boxes = ARRAY_LENGTH (boxes_stack); - cairo_clip_t local_clip; - cairo_bool_t have_clip = FALSE; - cairo_status_t status; + cairo_int_status_t status; if (unlikely (! _operator_is_supported (surface->flags, op))) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -3128,39 +3062,21 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; - - if (clip != NULL) { - clip = _cairo_clip_init_copy (&local_clip, clip); - have_clip = TRUE; - } - - status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); - if (unlikely (status)) { - if (have_clip) - _cairo_clip_fini (&local_clip); - - return status; - } status = CAIRO_INT_STATUS_UNSUPPORTED; if (_cairo_path_fixed_stroke_is_rectilinear (path)) { cairo_boxes_t boxes; - _cairo_boxes_init (&boxes); - _cairo_boxes_limit (&boxes, clip_boxes, num_boxes); - + _cairo_boxes_init_with_clip (&boxes, extents.clip); status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, style, ctm, + antialias, &boxes); - if (likely (status == CAIRO_STATUS_SUCCESS)) { + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { status = _clip_and_composite_boxes (surface, op, source, - &boxes, antialias, - &extents, clip); + &boxes, &extents); } - _cairo_boxes_fini (&boxes); } @@ -3170,25 +3086,19 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface, path, style, ctm, ctm_inverse, tolerance, antialias, - clip, clip_boxes, num_boxes, &extents); } else if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) { status = _cairo_xcb_surface_render_stroke_via_mask (surface, op, source, path, style, ctm, ctm_inverse, tolerance, antialias, - have_clip ? &local_clip : NULL, &extents); } else { ASSERT_NOT_REACHED; } } - if (clip_boxes != boxes_stack) - free (clip_boxes); - - if (have_clip) - _cairo_clip_fini (&local_clip); + _cairo_composite_rectangles_fini (&extents); return status; } @@ -3197,28 +3107,24 @@ static cairo_status_t _cairo_xcb_surface_render_fill_as_polygon (cairo_xcb_surface_t *dst, cairo_operator_t op, const cairo_pattern_t*source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip, - cairo_box_t *clip_boxes, - int num_boxes, cairo_composite_rectangles_t *extents) { cairo_polygon_t polygon; cairo_status_t status; - _cairo_polygon_init (&polygon, clip_boxes, num_boxes); - + _cairo_polygon_init_with_clip (&polygon, extents->clip); status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); if (likely (status == CAIRO_STATUS_SUCCESS)) { status = _cairo_xcb_surface_render_composite_polygon (dst, op, source, - &polygon, antialias, + &polygon, + antialias, fill_rule, - extents, clip); + extents); } - _cairo_polygon_fini (&polygon); return status; @@ -3228,11 +3134,10 @@ static cairo_status_t _cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t *dst, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip, cairo_composite_rectangles_t *extents) { cairo_surface_t *image; @@ -3264,7 +3169,7 @@ _cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t *dst, cairo_matrix_init_translate (&mask.base.matrix, -x, -y); status = _clip_and_composite (dst, op, source, _composite_mask, (void *) &mask.base, - extents, clip); + extents, need_bounded_clip (extents)); _cairo_pattern_fini (&mask.base); } @@ -3279,18 +3184,14 @@ cairo_int_status_t _cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_composite_rectangles_t extents; - cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; - int num_boxes = ARRAY_LENGTH (boxes_stack); - cairo_clip_t local_clip; - cairo_bool_t have_clip = FALSE; - cairo_status_t status; + cairo_int_status_t status; if (unlikely (! _operator_is_supported (surface->flags, op))) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -3309,38 +3210,19 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_extents (clip, &extents)) - clip = NULL; - - if (clip != NULL) { - clip = _cairo_clip_init_copy (&local_clip, clip); - have_clip = TRUE; - } - - status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); - if (unlikely (status)) { - if (have_clip) - _cairo_clip_fini (&local_clip); - - return status; - } - status = CAIRO_INT_STATUS_UNSUPPORTED; if (_cairo_path_fixed_fill_is_rectilinear (path)) { cairo_boxes_t boxes; - _cairo_boxes_init (&boxes); - _cairo_boxes_limit (&boxes, clip_boxes, num_boxes); - + _cairo_boxes_init_with_clip (&boxes, extents.clip); status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, fill_rule, + antialias, &boxes); - if (likely (status == CAIRO_STATUS_SUCCESS)) { + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { status = _clip_and_composite_boxes (surface, op, source, - &boxes, antialias, - &extents, clip); + &boxes, &extents); } - _cairo_boxes_fini (&boxes); } @@ -3348,23 +3230,17 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface, if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) { status = _cairo_xcb_surface_render_fill_as_polygon (surface, op, source, path, fill_rule, tolerance, antialias, - clip, clip_boxes, num_boxes, &extents); } else if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) { status = _cairo_xcb_surface_render_fill_via_mask (surface, op, source, path, fill_rule, tolerance, antialias, - have_clip ? &local_clip : NULL, &extents); } else { ASSERT_NOT_REACHED; } } - if (clip_boxes != boxes_stack) - free (clip_boxes); - - if (have_clip) - _cairo_clip_fini (&local_clip); + _cairo_composite_rectangles_fini (&extents); return status; } @@ -3376,7 +3252,6 @@ _cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t *dst, cairo_scaled_font_t *scaled_font, cairo_glyph_t *glyphs, int num_glyphs, - cairo_clip_t *clip, cairo_composite_rectangles_t *extents) { cairo_surface_t *image; @@ -3414,7 +3289,7 @@ _cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t *dst, cairo_matrix_init_translate (&mask.base.matrix, -x, -y); status = _clip_and_composite (dst, op, source, _composite_mask, (void *) &mask.base, - extents, clip); + extents, need_bounded_clip (extents)); _cairo_pattern_fini (&mask.base); } @@ -4290,12 +4165,10 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface, cairo_scaled_font_t *scaled_font, cairo_glyph_t *glyphs, int num_glyphs, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_composite_rectangles_t extents; - cairo_clip_t local_clip; - cairo_bool_t have_clip = FALSE; - cairo_status_t status; + cairo_int_status_t status; cairo_bool_t overlap; if (unlikely (! _operator_is_supported (surface->flags, op))) @@ -4314,20 +4187,6 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface, if (unlikely (status)) return status; - if (_cairo_clip_contains_rectangle (clip, &extents.mask)) - clip = NULL; - - if (clip != NULL && extents.is_bounded) { - clip = _cairo_clip_init_copy (&local_clip, clip); - status = _cairo_clip_rectangle (clip, &extents.bounded); - if (unlikely (status)) { - _cairo_clip_fini (&local_clip); - return status; - } - - have_clip = TRUE; - } - status = CAIRO_INT_STATUS_UNSUPPORTED; if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS) { _cairo_scaled_font_freeze_cache (scaled_font); @@ -4335,17 +4194,20 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface, if (_surface_owns_font (surface, scaled_font)) { status = _can_composite_glyphs (surface, &extents.bounded, scaled_font, glyphs, &num_glyphs); - if (likely (status == CAIRO_STATUS_SUCCESS)) { + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { composite_glyphs_info_t info; info.font = scaled_font; info.glyphs = (cairo_xcb_glyph_t *) glyphs; info.num_glyphs = num_glyphs; - info.use_mask = overlap || clip != NULL || ! extents.is_bounded; + info.use_mask = + overlap || + ! extents.is_bounded || + ! _cairo_clip_is_region(extents.clip); status = _clip_and_composite (surface, op, source, _composite_glyphs, &info, - &extents, clip); + &extents, need_bounded_clip (&extents)); } } @@ -4357,11 +4219,10 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface, status = _cairo_xcb_surface_render_glyphs_via_mask (surface, op, source, scaled_font, glyphs, num_glyphs, - clip, &extents); + &extents); } - if (have_clip) - _cairo_clip_fini (&local_clip); + _cairo_composite_rectangles_fini (&extents); return status; } diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index 157c8fb4f..6738cdd9b 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -379,7 +379,7 @@ _get_image (cairo_xcb_surface_t *surface, cairo_image_surface_t *image; cairo_xcb_connection_t *connection; xcb_get_image_reply_t *reply; - cairo_status_t status; + cairo_int_status_t status; if (surface->base.is_clear || surface->deferred_clear) { image = (cairo_image_surface_t *) @@ -594,7 +594,7 @@ static cairo_status_t _put_image (cairo_xcb_surface_t *surface, cairo_image_surface_t *image) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; /* XXX track damaged region? */ @@ -688,10 +688,10 @@ static cairo_int_status_t _cairo_xcb_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; - cairo_status_t status; + cairo_int_status_t status; if (surface->fallback == NULL) { status = _cairo_xcb_surface_cairo_paint (surface, op, source, clip); @@ -713,10 +713,10 @@ _cairo_xcb_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; - cairo_status_t status; + cairo_int_status_t status; if (surface->fallback == NULL) { status = _cairo_xcb_surface_cairo_mask (surface, @@ -741,16 +741,16 @@ static cairo_int_status_t _cairo_xcb_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; - cairo_status_t status; + cairo_int_status_t status; if (surface->fallback == NULL) { status = _cairo_xcb_surface_cairo_stroke (surface, op, source, @@ -786,14 +786,14 @@ static cairo_int_status_t _cairo_xcb_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t*path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; - cairo_status_t status; + cairo_int_status_t status; if (surface->fallback == NULL) { status = _cairo_xcb_surface_cairo_fill (surface, op, source, @@ -827,11 +827,11 @@ _cairo_xcb_surface_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *num_remaining) { cairo_xcb_surface_t *surface = abstract_surface; - cairo_status_t status; + cairo_int_status_t status; *num_remaining = 0; diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 25cfc6853..46ca63ff4 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -175,7 +175,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs); /* @@ -369,6 +369,9 @@ _cairo_xlib_surface_create_similar (void *abstract_src, if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) return NULL; + if (width == 0 || height == 0) + return NULL; + if (! CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (src)) return NULL; @@ -1695,7 +1698,7 @@ _cairo_xlib_surface_can_repaint_solid_pattern_surface (void *abstract_surface, return CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other); } -static cairo_status_t +static cairo_int_status_t _cairo_xlib_surface_set_matrix (cairo_xlib_display_t *display, cairo_xlib_surface_t *surface, const cairo_matrix_t *matrix, @@ -1707,7 +1710,7 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_display_t *display, { XTransform xtransform; pixman_transform_t *pixman_transform; - cairo_status_t status; + cairo_int_status_t status; /* Casting between pixman_transform_t and XTransform is safe because * they happen to be the exact same type. @@ -1718,8 +1721,8 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_display_t *display, pixman_transform, x_offset, y_offset); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - status = CAIRO_STATUS_SUCCESS; - if (unlikely (status != CAIRO_STATUS_SUCCESS)) + status = CAIRO_INT_STATUS_SUCCESS; + if (unlikely (status != CAIRO_INT_STATUS_SUCCESS)) return status; if (memcmp (&xtransform, &surface->xtransform, sizeof (XTransform)) == 0) @@ -4573,7 +4576,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_display_t *display, int *remaining_glyphs) { int i; - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; cairo_scaled_glyph_t *scaled_glyph; cairo_fixed_t x = 0, y = 0; cairo_xlib_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info; @@ -4725,7 +4728,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_display_t *display, } *remaining_glyphs = num_glyphs - i; - if (*remaining_glyphs != 0 && status == CAIRO_STATUS_SUCCESS) + if (*remaining_glyphs != 0 && status == CAIRO_INT_STATUS_SUCCESS) status = CAIRO_INT_STATUS_UNSUPPORTED; return status; @@ -4755,7 +4758,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs) { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; @@ -4779,23 +4782,16 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, * then the entire thing is copied to the destination surface, * including the fully transparent "background" of the rectangular * glyph surface. */ - if (op == CAIRO_OPERATOR_SOURCE && - ! CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11)) - { + if (op == CAIRO_OPERATOR_SOURCE) return UNSUPPORTED ("known bug in Render"); - } /* We can only use our code if we either have no clip or * have a real native clip region set. If we're using * fallback clip masking, we have to go through the full * fallback path. */ - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO); - if (status) - return status; - } + if (!_cairo_clip_is_region (clip)) + return UNSUPPORTED ("clip mask required"); operation = _categorize_composite_operation (dst, op, src_pattern, TRUE); if (operation == DO_UNSUPPORTED) diff --git a/src/cairo-xml-surface.c b/src/cairo-xml-surface.c index cf99ee6c9..1a6b01df3 100644 --- a/src/cairo-xml-surface.c +++ b/src/cairo-xml-surface.c @@ -206,6 +206,7 @@ _format_to_string (cairo_format_t format) { switch (format) { case CAIRO_FORMAT_ARGB32: return "ARGB32"; + case CAIRO_FORMAT_RGB30: return "RGB30"; case CAIRO_FORMAT_RGB24: return "RGB24"; case CAIRO_FORMAT_RGB16_565: return "RGB16_565"; case CAIRO_FORMAT_A8: return "A8"; @@ -416,7 +417,7 @@ _cairo_xml_close_path (void *closure) static void _cairo_xml_emit_path (cairo_xml_t *xml, - cairo_path_fixed_t *path) + const cairo_path_fixed_t *path) { cairo_status_t status; @@ -500,7 +501,7 @@ _cairo_xml_surface_emit_clip_path (cairo_xml_surface_t *surface, static cairo_status_t _cairo_xml_surface_emit_clip (cairo_xml_surface_t *surface, - cairo_clip_t *clip) + const cairo_clip_t *clip) { if (clip == NULL) return CAIRO_STATUS_SUCCESS; @@ -686,7 +687,7 @@ static cairo_int_status_t _cairo_xml_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_xml_surface_t *surface = abstract_surface; cairo_xml_t *xml = to_xml (surface); @@ -713,10 +714,10 @@ _cairo_xml_surface_paint (void *abstract_surface, static cairo_int_status_t _cairo_xml_surface_mask (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_pattern_t *mask, - cairo_clip_t *clip) + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) { cairo_xml_surface_t *surface = abstract_surface; cairo_xml_t *xml = to_xml (surface); @@ -749,13 +750,13 @@ static cairo_int_status_t _cairo_xml_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_xml_surface_t *surface = abstract_surface; cairo_xml_t *xml = to_xml (surface); @@ -805,11 +806,11 @@ static cairo_int_status_t _cairo_xml_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t*path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { cairo_xml_surface_t *surface = abstract_surface; cairo_xml_t *xml = to_xml (surface); @@ -924,7 +925,7 @@ _cairo_xml_emit_scaled_font (cairo_xml_t *xml, cairo_glyph_t *glyphs, int num_glyphs) { - cairo_status_t status; + cairo_int_status_t status; _cairo_xml_printf (xml, "<scaled-font>"); _cairo_xml_indent (xml, 2); @@ -948,7 +949,7 @@ _cairo_xml_surface_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs) { cairo_xml_surface_t *surface = abstract_surface; diff --git a/src/cairoint.h b/src/cairoint.h index 0ae205182..5503a07e2 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -744,7 +744,8 @@ struct _cairo_surface_backend { void *dst, cairo_antialias_t antialias, const cairo_composite_rectangles_t *rects, - cairo_region_t *clip_region); + cairo_region_t *clip_region); + cairo_warn cairo_bool_t (*check_span_renderer) (cairo_operator_t op, @@ -818,36 +819,36 @@ struct _cairo_surface_backend { (*paint) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_warn cairo_int_status_t (*mask) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_warn cairo_int_status_t (*stroke) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_warn cairo_int_status_t (*fill) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_warn cairo_int_status_t (*show_glyphs) (void *surface, @@ -856,7 +857,7 @@ struct _cairo_surface_backend { cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs); cairo_surface_t * @@ -873,7 +874,7 @@ struct _cairo_surface_backend { cairo_fill_rule_t fill_rule, double fill_tolerance, cairo_antialias_t fill_antialias, - cairo_path_fixed_t *path, + const cairo_path_fixed_t*path, cairo_operator_t stroke_op, const cairo_pattern_t *stroke_source, const cairo_stroke_style_t *stroke_style, @@ -881,7 +882,7 @@ struct _cairo_surface_backend { const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_surface_t * (*create_solid_pattern_surface) @@ -908,7 +909,7 @@ struct _cairo_surface_backend { int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_warn cairo_status_t (*acquire_source_image_transformed) (void *abstract_surface, @@ -1357,14 +1358,21 @@ _cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path, double tolerance, cairo_polygon_t *polygon); +cairo_private cairo_status_t +_cairo_path_fixed_fill_rectilinear_to_polygon (const cairo_path_fixed_t *path, + cairo_antialias_t antialias, + cairo_polygon_t *polygon); + cairo_private cairo_int_status_t _cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, cairo_traps_t *traps); cairo_private cairo_status_t _cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, cairo_boxes_t *boxes); cairo_private cairo_region_t * @@ -1391,12 +1399,14 @@ cairo_private cairo_int_status_t _cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, + cairo_antialias_t antialias, cairo_traps_t *traps); cairo_private cairo_int_status_t _cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, + cairo_antialias_t antialias, cairo_boxes_t *boxes); cairo_private cairo_int_status_t @@ -1656,14 +1666,14 @@ cairo_private cairo_status_t _cairo_surface_paint (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_mask (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_fill_stroke (cairo_surface_t *surface, @@ -1680,29 +1690,29 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_stroke (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_fill (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_show_text_glyphs (cairo_surface_t *surface, @@ -1716,7 +1726,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip); + const cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_composite_trapezoids (cairo_operator_t op, @@ -2026,6 +2036,19 @@ _cairo_polygon_init (cairo_polygon_t *polygon, int num_boxes); cairo_private void +_cairo_polygon_init_with_clip (cairo_polygon_t *polygon, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_polygon_init_boxes (cairo_polygon_t *polygon, + const cairo_boxes_t *boxes); + +cairo_private cairo_status_t +_cairo_polygon_init_box_array (cairo_polygon_t *polygon, + cairo_box_t *boxes, + int num_boxes); + +cairo_private void _cairo_polygon_fini (cairo_polygon_t *polygon); cairo_private cairo_status_t @@ -2039,6 +2062,14 @@ _cairo_polygon_add_external_edge (void *polygon, const cairo_point_t *p1, const cairo_point_t *p2); +cairo_private cairo_status_t +_cairo_polygon_reduce (cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule); + +cairo_private cairo_status_t +_cairo_polygon_intersect (cairo_polygon_t *a, int winding_a, + cairo_polygon_t *b, int winding_b); + #define _cairo_polygon_status(P) ((cairo_polygon_t *) (P))->status /* cairo-spline.c */ @@ -2129,6 +2160,10 @@ cairo_private void _cairo_traps_init (cairo_traps_t *traps); cairo_private void +_cairo_traps_init_with_clip (cairo_traps_t *traps, + const cairo_clip_t *clip); + +cairo_private void _cairo_traps_limit (cairo_traps_t *traps, const cairo_box_t *boxes, int num_boxes); @@ -2200,6 +2235,7 @@ _cairo_traps_extents (const cairo_traps_t *traps, cairo_private cairo_int_status_t _cairo_traps_extract_region (cairo_traps_t *traps, + cairo_antialias_t antialias, cairo_region_t **region); cairo_private cairo_status_t @@ -2454,6 +2490,9 @@ cairo_private void _cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path); cairo_private void -_cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip); +_cairo_debug_print_polygon (FILE *stream, cairo_polygon_t *polygon); + +cairo_private void +_cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip); #endif diff --git a/src/test-null-surface.c b/src/test-null-surface.c index 620dd2f1a..a71ce8b17 100644 --- a/src/test-null-surface.c +++ b/src/test-null-surface.c @@ -56,36 +56,36 @@ typedef cairo_int_status_t (*_paint_func) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip); + const cairo_clip_t *clip); typedef cairo_int_status_t (*_mask_func) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip); + const cairo_clip_t *clip); typedef cairo_int_status_t (*_stroke_func) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); typedef cairo_int_status_t (*_fill_func) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t*path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip); + const cairo_clip_t *clip); typedef cairo_int_status_t (*_show_glyphs_func) (void *surface, @@ -94,7 +94,7 @@ typedef cairo_int_status_t cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, + const cairo_clip_t *clip, int *remaining_glyphs); typedef cairo_int_status_t @@ -109,7 +109,7 @@ typedef cairo_int_status_t int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip); + const cairo_clip_t *clip); static cairo_surface_t * _cairo_null_surface_create_similar (void *other, diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c index 241f1bd1f..773628298 100644 --- a/src/test-paginated-surface.c +++ b/src/test-paginated-surface.c @@ -122,7 +122,7 @@ static cairo_int_status_t _test_paginated_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { test_paginated_surface_t *surface = abstract_surface; @@ -137,7 +137,7 @@ _test_paginated_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { test_paginated_surface_t *surface = abstract_surface; @@ -152,13 +152,13 @@ static cairo_int_status_t _test_paginated_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { test_paginated_surface_t *surface = abstract_surface; @@ -176,11 +176,11 @@ static cairo_int_status_t _test_paginated_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { test_paginated_surface_t *surface = abstract_surface; @@ -213,7 +213,7 @@ _test_paginated_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip) + const cairo_clip_t *clip) { test_paginated_surface_t *surface = abstract_surface; diff --git a/src/test-wrapping-surface.c b/src/test-wrapping-surface.c index 4dd6c4c68..cef70556f 100644 --- a/src/test-wrapping-surface.c +++ b/src/test-wrapping-surface.c @@ -138,7 +138,7 @@ static cairo_int_status_t _test_wrapping_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_clip_t *clip) + const cairo_clip_t *clip) { test_wrapping_surface_t *surface = abstract_surface; @@ -150,7 +150,7 @@ _test_wrapping_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_clip_t *clip) + const cairo_clip_t *clip) { test_wrapping_surface_t *surface = abstract_surface; @@ -162,13 +162,13 @@ static cairo_int_status_t _test_wrapping_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { test_wrapping_surface_t *surface = abstract_surface; @@ -184,11 +184,11 @@ static cairo_int_status_t _test_wrapping_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_clip_t *clip) + const cairo_clip_t *clip) { test_wrapping_surface_t *surface = abstract_surface; @@ -219,7 +219,7 @@ _test_wrapping_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip) + const cairo_clip_t *clip) { test_wrapping_surface_t *surface = abstract_surface; diff --git a/test/clip-group-shapes-circles.ref.png b/test/clip-group-shapes-circles.ref.png Binary files differindex 064cc589d..7dd6a8353 100644 --- a/test/clip-group-shapes-circles.ref.png +++ b/test/clip-group-shapes-circles.ref.png diff --git a/test/clip-shape.ref.png b/test/clip-shape.ref.png Binary files differindex e80f666f2..313e2450c 100644 --- a/test/clip-shape.ref.png +++ b/test/clip-shape.ref.png diff --git a/test/clip-stroke.ref.png b/test/clip-stroke.ref.png Binary files differindex e66cc4344..0b316e6f9 100644 --- a/test/clip-stroke.ref.png +++ b/test/clip-stroke.ref.png |