cairo_status_t _cairo_surface_fallback_fill (cairo_surface_t *surface, cairo_operator_t op, cairo_pattern_t *source, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { cairo_status_t status; cairo_traps_t traps; _cairo_traps_init (&traps); status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); if (status) { _cairo_traps_fini (&traps); return status; } status = _clip_and_composite_trapezoids (source, op, surface, &traps, surface->clip, antialias); _cairo_traps_fini (&traps); return status; }
static cairo_status_t _cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t *clip_path, cairo_rectangle_int_t *rectangle) { while (clip_path) { cairo_status_t status; cairo_traps_t traps; cairo_box_t extents; cairo_rectangle_int_t extents_rect; _cairo_traps_init (&traps); status = _cairo_path_fixed_fill_to_traps (&clip_path->path, clip_path->fill_rule, clip_path->tolerance, &traps); if (status) { _cairo_traps_fini (&traps); return status; } _cairo_traps_extents (&traps, &extents); _cairo_box_round_to_rectangle (&extents, &extents_rect); _cairo_rectangle_intersect (rectangle, &extents_rect); _cairo_traps_fini (&traps); clip_path = clip_path->prev; } return CAIRO_STATUS_SUCCESS; }
cairo_status_t _cairo_surface_fallback_fill (cairo_surface_t *surface, cairo_operator_t op, cairo_pattern_t *source, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { cairo_status_t status; cairo_traps_t traps; cairo_box_t box; cairo_rectangle_int_t extents; status = _cairo_surface_get_extents (surface, &extents); if (status) return status; if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); if (status) return status; _cairo_rectangle_intersect (&extents, &source_extents); } status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); if (status) return status; box.p1.x = _cairo_fixed_from_int (extents.x); box.p1.y = _cairo_fixed_from_int (extents.y); box.p2.x = _cairo_fixed_from_int (extents.x + extents.width); box.p2.y = _cairo_fixed_from_int (extents.y + extents.height); _cairo_traps_init (&traps); _cairo_traps_limit (&traps, &box); status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); if (status) { _cairo_traps_fini (&traps); return status; } status = _clip_and_composite_trapezoids (source, op, surface, &traps, surface->clip, antialias); _cairo_traps_fini (&traps); return status; }
static cairo_int_status_t base_compositor_stroke (const cairo_compositor_t *_compositor, cairo_composite_rectangles_t *extents, const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias) { composite_traps_info_t info; cairo_int_status_t status; info.antialias = antialias; _cairo_traps_init_with_clip (&info.traps, extents->clip); status = _cairo_path_fixed_stroke_to_traps (path, style, ctm, ctm_inverse, tolerance, &info.traps); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = trim_extents_to_traps (extents, &info.traps); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = clip_and_composite (extents, composite_traps, &info); _cairo_traps_fini (&info.traps); return status; }
static cairo_int_status_t base_compositor_fill (const cairo_compositor_t *_compositor, cairo_composite_rectangles_t *extents, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { composite_traps_info_t info; cairo_int_status_t status; TRACE ((stderr, "%s\n", __FUNCTION__)); info.antialias = antialias; _cairo_traps_init_with_clip (&info.traps, extents->clip); status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &info.traps); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = trim_extents_to_traps (extents, &info.traps); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = clip_and_composite (extents, composite_traps, &info); _cairo_traps_fini (&info.traps); return status; }
cairo_status_t _cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path, cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_rectangle_int_t *extents) { cairo_traps_t traps; cairo_box_t bbox; cairo_status_t status; _cairo_traps_init (&traps); status = _cairo_path_fixed_stroke_to_traps (path, stroke_style, ctm, ctm_inverse, tolerance, &traps); _cairo_traps_extents (&traps, &bbox); _cairo_traps_fini (&traps); _cairo_box_round_to_rectangle (&bbox, extents); return status; }
cairo_status_t _cairo_clip_clip (cairo_clip_t *clip, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, cairo_surface_t *target) { cairo_status_t status; cairo_traps_t traps; cairo_path_fixed_t path_transformed; if (_cairo_surface_has_device_offset_or_scale (target)) { _cairo_path_fixed_init_copy (&path_transformed, path); _cairo_path_fixed_offset (&path_transformed, _cairo_fixed_from_double (target->device_x_offset), _cairo_fixed_from_double (target->device_y_offset)); path = &path_transformed; } status = _cairo_clip_intersect_path (clip, path, fill_rule, tolerance, antialias); if (status == CAIRO_STATUS_SUCCESS) clip->serial = _cairo_surface_allocate_clip_serial (target); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; _cairo_traps_init (&traps); status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); if (status) goto bail; status = _cairo_clip_intersect_region (clip, &traps, target); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto bail; status = _cairo_clip_intersect_mask (clip, &traps, antialias, target); bail: _cairo_traps_fini (&traps); if (path == &path_transformed) _cairo_path_fixed_fini (&path_transformed); return status; }
cairo_status_t _cairo_surface_fallback_stroke (cairo_surface_t *surface, cairo_operator_t op, cairo_pattern_t *source, cairo_path_fixed_t *path, cairo_stroke_style_t *stroke_style, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias) { cairo_status_t status; cairo_traps_t traps; _cairo_traps_init (&traps); status = _cairo_path_fixed_stroke_to_traps (path, stroke_style, ctm, ctm_inverse, tolerance, &traps); if (status) { _cairo_traps_fini (&traps); return status; } _clip_and_composite_trapezoids (source, op, surface, &traps, surface->clip, antialias); _cairo_traps_fini (&traps); return CAIRO_STATUS_SUCCESS; }
cairo_status_t _cairo_clip_clip (cairo_clip_t *clip, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, cairo_surface_t *target) { cairo_status_t status; cairo_traps_t traps; if (clip->all_clipped) return CAIRO_STATUS_SUCCESS; /* catch the empty clip path */ if (! path->has_current_point) { _cairo_clip_set_all_clipped (clip, target); return CAIRO_STATUS_SUCCESS; } status = _cairo_clip_intersect_path (clip, path, fill_rule, tolerance, antialias); if (status == CAIRO_STATUS_SUCCESS) clip->serial = _cairo_surface_allocate_clip_serial (target); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; _cairo_traps_init (&traps); status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); if (status) goto bail; status = _cairo_clip_intersect_region (clip, &traps, target); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto bail; status = _cairo_clip_intersect_mask (clip, &traps, antialias, target); bail: _cairo_traps_fini (&traps); return status; }
cairo_int_status_t _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx, cairo_gl_composite_t *setup, cairo_clip_t *clip) { cairo_int_status_t status; cairo_traps_t traps; status = _clip_to_traps (clip, &traps); if (unlikely (status)) return status; status = _draw_traps (ctx, setup, &traps); _cairo_traps_fini (&traps); return status; }
cairo_status_t _cairo_surface_fallback_paint (cairo_surface_t *surface, cairo_operator_t op, cairo_pattern_t *source) { cairo_status_t status; cairo_rectangle_int_t extents; cairo_box_t box; cairo_traps_t traps; status = _cairo_surface_get_extents (surface, &extents); if (status) return status; if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); if (status) return status; _cairo_rectangle_intersect (&extents, &source_extents); } status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); if (status) return status; box.p1.x = _cairo_fixed_from_int (extents.x); box.p1.y = _cairo_fixed_from_int (extents.y); box.p2.x = _cairo_fixed_from_int (extents.x + extents.width); box.p2.y = _cairo_fixed_from_int (extents.y + extents.height); status = _cairo_traps_init_box (&traps, &box); if (status) return status; status = _clip_and_composite_trapezoids (source, op, surface, &traps, surface->clip, CAIRO_ANTIALIAS_NONE); _cairo_traps_fini (&traps); return status; }
/** * _cairo_traps_init_boxes: * @traps: a #cairo_traps_t * @box: an array box that will each be converted to a single trapezoid * to store in @traps. * * Initializes a #cairo_traps_t to contain an array of rectangular * trapezoids. **/ cairo_status_t _cairo_traps_init_boxes (cairo_traps_t *traps, const cairo_boxes_t *boxes) { cairo_trapezoid_t *trap; const struct _cairo_boxes_chunk *chunk; _cairo_traps_init (traps); while (traps->traps_size < boxes->num_boxes) { if (unlikely (! _cairo_traps_grow (traps))) { _cairo_traps_fini (traps); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } } traps->num_traps = boxes->num_boxes; traps->is_rectilinear = TRUE; traps->is_rectangular = TRUE; traps->maybe_region = boxes->is_pixel_aligned; trap = &traps->traps[0]; for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { const cairo_box_t *box; int i; box = chunk->base; for (i = 0; i < chunk->count; i++) { trap->top = box->p1.y; trap->bottom = box->p2.y; trap->left.p1 = box->p1; trap->left.p2.x = box->p1.x; trap->left.p2.y = box->p2.y; trap->right.p1.x = box->p2.x; trap->right.p1.y = box->p1.y; trap->right.p2 = box->p2; box++, trap++; } } return CAIRO_STATUS_SUCCESS; }
cairo_status_t _cairo_surface_fallback_paint (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source) { cairo_status_t status; cairo_rectangle_int_t extents; cairo_box_t box; cairo_traps_t traps; status = _cairo_surface_get_extents (surface, &extents); if (unlikely (status)) return status; if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); if (unlikely (status)) return status; if (! _cairo_rectangle_intersect (&extents, &source_extents)) return CAIRO_STATUS_SUCCESS; } status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); if (unlikely (status)) return status; _cairo_box_from_rectangle (&box, &extents); _cairo_traps_init_box (&traps, &box); status = _clip_and_composite_trapezoids (source, op, surface, &traps, surface->clip, CAIRO_ANTIALIAS_NONE); _cairo_traps_fini (&traps); return status; }
static cairo_int_status_t _draw_clip (cairo_gl_context_t *ctx, cairo_gl_composite_t *setup, cairo_clip_t *clip) { cairo_int_status_t status; cairo_traps_t traps; cairo_polygon_t polygon; cairo_antialias_t antialias; cairo_fill_rule_t fill_rule; status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias); if (unlikely (status)) return status; /* We ignore the antialias mode of the clip here, since the user requested * unantialiased rendering of their path and we expect that this stencil * based rendering of the clip to be a reasonable approximation to * the intersection between that clip and the path. * * In other words, what the user expects when they try to perform * a geometric intersection between an unantialiased polygon and an * antialiased polygon is open to interpretation. And we choose the fast * option. */ _cairo_traps_init (&traps); status = _cairo_bentley_ottmann_tessellate_polygon (&traps, &polygon, fill_rule); _cairo_polygon_fini (&polygon); if (unlikely (status)) return status; status = _draw_traps (ctx, setup, &traps); _cairo_traps_fini (&traps); return status; }
/* 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_int_status_t _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite, 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_int_status_t status; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; struct _tristrip_composite_info info; cairo_bool_t use_color_attribute; if (! can_use_msaa_compositor (dst, antialias)) return CAIRO_INT_STATUS_UNSUPPORTED; if (composite->is_bounded == FALSE) { cairo_surface_t* surface = _prepare_unbounded_surface (dst); if (unlikely (surface == NULL)) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_compositor_stroke (compositor, surface, CAIRO_OPERATOR_SOURCE, &composite->source_pattern.base, path, style, ctm, ctm_inverse, tolerance, antialias, NULL); if (unlikely (status)) { cairo_surface_destroy (surface); return status; } return _paint_back_unbounded_surface (compositor, composite, surface); } status = _cairo_gl_composite_init (&info.setup, composite->op, dst, FALSE /* assume_component_alpha */); if (unlikely (status)) return status; info.ctx = NULL; use_color_attribute = _cairo_path_fixed_stroke_is_rectilinear (path) || _cairo_gl_hairline_style_is_hairline (style, ctm); status = _cairo_gl_composite_set_source (&info.setup, composite->original_source_pattern, &composite->source_sample_area, &composite->bounded, use_color_attribute); if (unlikely (status)) goto finish; _cairo_gl_msaa_compositor_set_clip (composite, &info.setup); status = _cairo_gl_composite_begin_multisample (&info.setup, &info.ctx, antialias != CAIRO_ANTIALIAS_NONE); if (unlikely (status)) goto finish; if (_cairo_gl_hairline_style_is_hairline (style, ctm)) { cairo_gl_hairline_closure_t closure; if (! (_is_continuous_arc (path, style) || _is_continuous_single_line (path, style))) { status = _prevent_overlapping_drawing (info.ctx, &info.setup, composite, path, style, ctm); if (unlikely (status)) goto finish; } closure.ctx = info.ctx; closure.tolerance = tolerance; status = _cairo_gl_path_fixed_stroke_to_hairline (path, &closure, style, ctm, ctm_inverse, _cairo_gl_hairline_move_to, style->dash ? _cairo_gl_hairline_line_to_dashed : _cairo_gl_hairline_line_to, _cairo_gl_hairline_curve_to, _cairo_gl_hairline_close_path); goto finish; } if (use_color_attribute) { cairo_traps_t traps; _cairo_traps_init (&traps); status = _cairo_path_fixed_stroke_to_traps (path, style, ctm, ctm_inverse, tolerance, &traps); if (unlikely (status)) { _cairo_traps_fini (&traps); goto finish; } status = _draw_traps (info.ctx, &info.setup, &traps); _cairo_traps_fini (&traps); } else { if (!_is_continuous_single_line (path, style)) { status = _prevent_overlapping_drawing (info.ctx, &info.setup, composite, path, style, ctm); if (unlikely (status)) goto finish; } status = _cairo_path_fixed_stroke_to_shaper ((cairo_path_fixed_t *) path, style, ctm, ctm_inverse, tolerance, _stroke_shaper_add_triangle, _stroke_shaper_add_triangle_fan, _stroke_shaper_add_quad, &info); if (unlikely (status)) goto finish; } finish: _cairo_gl_composite_fini (&info.setup); if (info.ctx) status = _cairo_gl_context_release (info.ctx, status); return status; }
static cairo_int_status_t _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { cairo_gl_composite_t setup; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; cairo_gl_context_t *ctx = NULL; cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; cairo_traps_t traps; cairo_bool_t use_color_attr = FALSE; if (! can_use_msaa_compositor (dst, antialias)) return CAIRO_INT_STATUS_UNSUPPORTED; if (composite->is_bounded == FALSE) { cairo_surface_t* surface = _prepare_unbounded_surface (dst); if (unlikely (surface == NULL)) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_compositor_fill (compositor, surface, CAIRO_OPERATOR_SOURCE, &composite->source_pattern.base, path, fill_rule, tolerance, antialias, NULL); if (unlikely (status)) { cairo_surface_destroy (surface); return status; } return _paint_back_unbounded_surface (compositor, composite, surface); } if (_cairo_path_fixed_fill_is_rectilinear (path) && composite->clip != NULL && composite->clip->num_boxes == 1 && composite->clip->path == NULL) { cairo_clip_t *clip = _cairo_clip_copy (composite->clip); clip = _cairo_clip_intersect_rectilinear_path (clip, path, fill_rule, antialias); if (clip->num_boxes) status = _cairo_gl_msaa_compositor_fill_rectilinear (compositor, composite, path, fill_rule, tolerance, antialias, clip); _cairo_clip_destroy (clip); return status; } status = _cairo_gl_composite_init (&setup, composite->op, dst, FALSE /* assume_component_alpha */); if (unlikely (status)) { _cairo_gl_composite_fini (&setup); return status; } _cairo_traps_init (&traps); if (_cairo_path_fixed_fill_is_rectilinear (path)) { status = _cairo_path_fixed_fill_rectilinear_to_traps (path, fill_rule, antialias, &traps); use_color_attr = TRUE; } else status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); if (unlikely (status)) goto cleanup_traps; status = _cairo_gl_composite_set_source (&setup, composite->original_source_pattern, &composite->source_sample_area, &composite->bounded, use_color_attr); if (unlikely (status)) goto cleanup_setup; _cairo_gl_msaa_compositor_set_clip (composite, &setup); status = _cairo_gl_composite_begin_multisample (&setup, &ctx, antialias != CAIRO_ANTIALIAS_NONE); if (unlikely (status)) goto cleanup_setup; status = _draw_traps (ctx, &setup, &traps); if (unlikely (status)) goto cleanup_setup; cleanup_setup: _cairo_gl_composite_fini (&setup); if (ctx) status = _cairo_gl_context_release (ctx, status); cleanup_traps: _cairo_traps_fini (&traps); return status; }
/* The first pass, we use mask as source, to get dst1 = (1 - ma) * dst) with * DEST_OUT operator. In the second pass, we use ADD operator to achieve * result = (src * ma) + dst1. Combining two passes, we have * result = (src * ma) + (1 - ma) * dst */ static cairo_int_status_t _cairo_gl_msaa_compositor_mask_source_operator (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite) { cairo_gl_composite_t setup; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; cairo_gl_context_t *ctx = NULL; cairo_int_status_t status; cairo_traps_t traps; _cairo_traps_init (&traps); status = _cairo_gl_composite_init (&setup, CAIRO_OPERATOR_DEST_OUT, dst, FALSE /* assume_component_alpha */); if (unlikely (status)) goto finish; _gl_pattern_fix_reference_count (composite->original_mask_pattern); status = _cairo_gl_composite_set_source (&setup, &composite->mask_pattern.base, &composite->mask_sample_area, &composite->bounded, FALSE); if (unlikely (status)) goto finish; status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE); if (unlikely (status)) goto finish; if (! composite->clip) status = _draw_int_rect (ctx, &setup, &composite->bounded); else status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, composite->clip, &traps); _cairo_gl_composite_fini (&setup); status = _cairo_gl_context_release (ctx, status); ctx = NULL; if (unlikely (status)) return status; /* second pass */ status = _cairo_gl_composite_init (&setup, CAIRO_OPERATOR_ADD, dst, FALSE /* assume_component_alpha */); if (unlikely (status)) goto finish; _gl_pattern_fix_reference_count (composite->original_source_pattern); status = _cairo_gl_composite_set_source (&setup, &composite->source_pattern.base, &composite->source_sample_area, &composite->bounded, FALSE); if (unlikely (status)) goto finish; status = _cairo_gl_composite_set_mask (&setup, &composite->mask_pattern.base, &composite->source_sample_area, &composite->bounded); if (unlikely (status)) goto finish; /* We always use multisampling here, because we do not yet have the smarts to calculate when the clip or the source requires it. */ status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE); if (unlikely (status)) goto finish; if (! composite->clip) status = _draw_int_rect (ctx, &setup, &composite->bounded); else status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, composite->clip, &traps); finish: _cairo_traps_fini (&traps); _cairo_gl_composite_fini (&setup); if (ctx) status = _cairo_gl_context_release (ctx, status); return status; }
static cairo_int_status_t _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite) { cairo_gl_composite_t setup; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; cairo_gl_context_t *ctx = NULL; cairo_int_status_t status; cairo_operator_t op = composite->op; cairo_traps_t traps; cairo_bool_t use_color_attribute = FALSE; if (! can_use_msaa_compositor (dst, CAIRO_ANTIALIAS_DEFAULT)) return CAIRO_INT_STATUS_UNSUPPORTED; /* GL compositing operators cannot properly represent a mask operation using the SOURCE compositing operator in one pass. This only matters if there actually is a mask (there isn't in a paint operation) and if the mask isn't totally opaque. */ if (op == CAIRO_OPERATOR_SOURCE && composite->original_mask_pattern != NULL && ! _cairo_pattern_is_opaque (&composite->mask_pattern.base, &composite->mask_sample_area)) { /* If the source is opaque the operation reduces to OVER. */ if (_cairo_pattern_is_opaque (&composite->source_pattern.base, &composite->source_sample_area)) op = CAIRO_OPERATOR_OVER; else return _cairo_gl_msaa_compositor_mask_source_operator (compositor, composite); } if (_should_use_unbounded_surface (composite)) { cairo_surface_t* surface = _prepare_unbounded_surface (dst); if (unlikely (surface == NULL)) return CAIRO_INT_STATUS_UNSUPPORTED; /* This may be a paint operation. */ if (composite->original_mask_pattern == NULL) { status = _cairo_compositor_paint (compositor, surface, CAIRO_OPERATOR_SOURCE, &composite->source_pattern.base, NULL); } else { status = _cairo_compositor_mask (compositor, surface, CAIRO_OPERATOR_SOURCE, &composite->source_pattern.base, &composite->mask_pattern.base, NULL); } if (unlikely (status)) { cairo_surface_destroy (surface); return status; } return _paint_back_unbounded_surface (compositor, composite, surface); } status = _cairo_gl_composite_init (&setup, op, dst, FALSE /* assume_component_alpha */); if (unlikely (status)) goto finish; _gl_pattern_fix_reference_count (composite->original_source_pattern); if (! composite->clip || (composite->clip->num_boxes == 1 && ! composite->clip->path)) use_color_attribute = TRUE; status = _cairo_gl_composite_set_source (&setup, composite->original_source_pattern, &composite->source_sample_area, &composite->bounded, use_color_attribute); if (unlikely (status)) goto finish; if (composite->original_mask_pattern != NULL) { status = _cairo_gl_composite_set_mask (&setup, composite->original_mask_pattern, &composite->mask_sample_area, &composite->bounded); } if (unlikely (status)) goto finish; /* We always use multisampling here, because we do not yet have the smarts to calculate when the clip or the source requires it. */ status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE); if (unlikely (status)) goto finish; _cairo_traps_init (&traps); if (! composite->clip) status = _draw_int_rect (ctx, &setup, &composite->bounded); else status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, composite->clip, &traps); _cairo_traps_fini (&traps); finish: _cairo_gl_composite_fini (&setup); if (ctx) status = _cairo_gl_context_release (ctx, status); 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, cairo_stroke_style_t *stroke_style, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias) { cairo_status_t status; cairo_traps_t traps; cairo_box_t box; cairo_rectangle_int_t extents; status = _cairo_surface_get_extents (surface, &extents); if (unlikely (status)) return status; if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); if (unlikely (status)) return status; if (! _cairo_rectangle_intersect (&extents, &source_extents)) return CAIRO_STATUS_SUCCESS; } status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); if (unlikely (status)) return status; if (extents.width == 0 || extents.height == 0) return CAIRO_STATUS_SUCCESS; _cairo_box_from_rectangle (&box, &extents); _cairo_traps_init (&traps); _cairo_traps_limit (&traps, &box); status = _cairo_path_fixed_stroke_to_traps (path, stroke_style, ctm, ctm_inverse, tolerance, &traps); if (unlikely (status)) goto FAIL; status = _clip_and_composite_trapezoids (source, op, surface, &traps, surface->clip, antialias); FAIL: _cairo_traps_fini (&traps); return status; }
static cairo_int_status_t _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { cairo_gl_composite_t setup; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; cairo_gl_context_t *ctx = NULL; cairo_int_status_t status; cairo_traps_t traps; cairo_bool_t draw_path_with_traps; if (! can_use_msaa_compositor (dst, antialias)) return CAIRO_INT_STATUS_UNSUPPORTED; if (composite->is_bounded == FALSE) { cairo_surface_t* surface = _prepare_unbounded_surface (dst); if (unlikely (surface == NULL)) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_compositor_fill (compositor, surface, CAIRO_OPERATOR_SOURCE, &composite->source_pattern.base, path, fill_rule, tolerance, antialias, NULL); if (unlikely (status)) { cairo_surface_destroy (surface); return status; } return _paint_back_unbounded_surface (compositor, composite, surface); } draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path); if (draw_path_with_traps) { _cairo_traps_init (&traps); status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); if (unlikely (status)) goto cleanup_traps; } status = _cairo_gl_composite_init (&setup, composite->op, dst, FALSE /* assume_component_alpha */); if (unlikely (status)) goto cleanup_traps; status = _cairo_gl_composite_set_source (&setup, &composite->source_pattern.base, &composite->source_sample_area, &composite->bounded, FALSE); if (unlikely (status)) goto cleanup_setup; _cairo_gl_msaa_compositor_set_clip (composite, &setup); if (antialias != CAIRO_ANTIALIAS_NONE) _cairo_gl_composite_set_multisample (&setup); status = _cairo_gl_composite_begin (&setup, &ctx); if (unlikely (status)) goto cleanup_setup; if (! draw_path_with_traps) status = _draw_simple_quad_path (ctx, &setup, path); else status = _draw_traps (ctx, &setup, &traps); if (unlikely (status)) goto cleanup_setup; cleanup_setup: _cairo_gl_composite_fini (&setup); if (ctx) status = _cairo_gl_context_release (ctx, status); cleanup_traps: if (draw_path_with_traps) _cairo_traps_fini (&traps); return status; }
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, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { cairo_status_t status; cairo_traps_t traps; cairo_box_t box; cairo_rectangle_int_t extents; status = _cairo_surface_get_extents (surface, &extents); if (unlikely (status)) return status; if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); if (unlikely (status)) return status; if (! _cairo_rectangle_intersect (&extents, &source_extents)) return CAIRO_STATUS_SUCCESS; } status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); if (unlikely (status)) return status; if (extents.width == 0 || extents.height == 0) return CAIRO_STATUS_SUCCESS; /* Ask if the surface would like to render this combination of * op/source/dst/antialias with spans or not, but don't actually * make a renderer yet. We'll try to hit the region optimisations * in _clip_and_composite_trapezoids() if it looks like the path * is a region. */ /* TODO: Until we have a mono scan converter we won't even try * to use spans for CAIRO_ANTIALIAS_NONE. */ /* TODO: The region filling code should be lifted from * _clip_and_composite_trapezoids() and given first priority * explicitly before deciding between spans and trapezoids. */ if (antialias != CAIRO_ANTIALIAS_NONE && !_cairo_path_fixed_is_box (path, &box) && !_cairo_path_fixed_is_region (path) && _cairo_surface_check_span_renderer ( op, source, surface, antialias, NULL)) { cairo_composite_spans_fill_info_t info; info.path = path; info.fill_rule = fill_rule; info.tolerance = tolerance; info.antialias = antialias; if (_cairo_operator_bounded_by_mask (op)) { cairo_rectangle_int_t path_extents; _cairo_path_fixed_approximate_clip_extents (path, &path_extents); if (! _cairo_rectangle_intersect (&extents, &path_extents)) return CAIRO_STATUS_SUCCESS; } return _clip_and_composite ( surface->clip, op, source, _composite_spans_fill_func, &info, surface, &extents); } /* Fall back to trapezoid fills. */ _cairo_box_from_rectangle (&box, &extents); _cairo_traps_init (&traps); _cairo_traps_limit (&traps, &box); status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); if (unlikely (status)) { _cairo_traps_fini (&traps); return status; } status = _clip_and_composite_trapezoids (source, op, surface, &traps, surface->clip, antialias); _cairo_traps_fini (&traps); return status; }
static cairo_region_t * _cairo_path_fixed_fill_rectilinear_tessellate_to_region (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, const cairo_rectangle_int_t *extents) { cairo_box_t box; cairo_polygon_t polygon; cairo_traps_t traps; cairo_status_t status; cairo_region_t *region; /* first try to bypass fill-to-polygon */ _cairo_traps_init (&traps); status = _cairo_path_fixed_fill_rectilinear_to_traps (path, fill_rule, &traps); if (_cairo_status_is_error (status)) goto CLEANUP_TRAPS; if (status == CAIRO_STATUS_SUCCESS) { status = _cairo_traps_extract_region (&traps, ®ion); goto CLEANUP_TRAPS; } /* path is not rectangular, try extracting clipped rectilinear edges */ _cairo_polygon_init (&polygon); if (extents != NULL) { _cairo_box_from_rectangle (&box, extents); _cairo_polygon_limit (&polygon, &box, 1); } /* tolerance will be ignored as the path is rectilinear */ status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon); if (unlikely (status)) goto CLEANUP_POLYGON; if (polygon.num_edges == 0) { region = cairo_region_create (); } else { status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps, &polygon, fill_rule); if (likely (status == CAIRO_STATUS_SUCCESS)) status = _cairo_traps_extract_region (&traps, ®ion); } CLEANUP_POLYGON: _cairo_polygon_fini (&polygon); CLEANUP_TRAPS: _cairo_traps_fini (&traps); if (unlikely (status)) { /* XXX _cairo_region_create_in_error() */ region = cairo_region_create (); if (likely (region->status) == CAIRO_STATUS_SUCCESS) region->status = status; } return region; }
cairo_status_t _cairo_clip_clip (cairo_clip_t *clip, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, cairo_surface_t *target) { cairo_status_t status; cairo_rectangle_int_t rectangle; cairo_traps_t traps; cairo_box_t ignored_box; if (clip->all_clipped) return CAIRO_STATUS_SUCCESS; /* catch the empty clip path */ if (! path->has_current_point) { _cairo_clip_set_all_clipped (clip, target); return CAIRO_STATUS_SUCCESS; } status = _cairo_clip_intersect_path (clip, path, fill_rule, tolerance, antialias); if (status == CAIRO_STATUS_SUCCESS) clip->serial = _cairo_surface_allocate_clip_serial (target); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; /* TODO: allow ANTIALIAS_NONE when we have a mono scan converter * again. */ if (antialias != CAIRO_ANTIALIAS_NONE && !_cairo_path_fixed_is_box (path, &ignored_box) && !_cairo_path_fixed_is_region (path)) { status = _cairo_clip_intersect_mask_using_spans ( clip, path, fill_rule, tolerance, antialias, target); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } _cairo_traps_init (&traps); /* Limit the traps to the target surface * - so we don't add more traps than needed. */ status = _cairo_surface_get_extents (target, &rectangle); if (status == CAIRO_STATUS_SUCCESS) { cairo_box_t box; _cairo_box_from_rectangle (&box, &rectangle); _cairo_traps_limit (&traps, &box); } status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); if (unlikely (status)) goto bail; status = _cairo_clip_intersect_region (clip, &traps, target); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto bail; status = _cairo_clip_intersect_mask (clip, &traps, antialias, target); bail: _cairo_traps_fini (&traps); return status; }
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 (! clip_path->path.is_rectilinear) 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_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { cairo_gl_composite_t setup; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; cairo_gl_context_t *ctx = NULL; cairo_int_status_t status; cairo_traps_t traps; cairo_bool_t used_stencil_buffer; if (antialias != CAIRO_ANTIALIAS_NONE) return CAIRO_INT_STATUS_UNSUPPORTED; _cairo_traps_init (&traps); status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); if (unlikely (status)) goto cleanup_traps; status = _cairo_gl_composite_init (&setup, composite->op, dst, FALSE, /* assume_component_alpha */ &composite->bounded); if (unlikely (status)) goto cleanup_traps; status = _cairo_gl_composite_set_source (&setup, &composite->source_pattern.base, &composite->source_sample_area, &composite->bounded); if (unlikely (status)) goto cleanup_setup; status = _cairo_gl_composite_begin_tristrip (&setup, &ctx); if (unlikely (status)) goto cleanup_setup; status = _scissor_and_clip (ctx, &setup, composite, &used_stencil_buffer); if (unlikely (status)) goto cleanup_setup; status = _draw_traps (ctx, &setup, &traps); if (unlikely (status)) goto cleanup_setup; _cairo_gl_composite_flush (ctx); cleanup_setup: _cairo_gl_composite_fini (&setup); if (ctx) { glDisable (GL_SCISSOR_TEST); _disable_stencil_buffer (); status = _cairo_gl_context_release (ctx, status); } cleanup_traps: _cairo_traps_fini (&traps); return status; }
static cairo_int_status_t _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup, cairo_gl_context_t *ctx, int vertex_size, cairo_bool_t equal_clip) { cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; cairo_gl_surface_t *dst = setup->dst; cairo_clip_t *clip = setup->clip; cairo_traps_t traps; const cairo_rectangle_int_t *clip_extents; if (clip->num_boxes == 1 && clip->path == NULL) { _scissor_to_box (dst, &clip->boxes[0]); goto disable_stencil_buffer_and_return; } if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto disable_stencil_buffer_and_return; } if (! ctx->states_cache.depth_mask ) { glDepthMask (GL_TRUE); ctx->states_cache.depth_mask = TRUE; } glEnable (GL_STENCIL_TEST); clip_extents = _cairo_clip_get_extents ((const cairo_clip_t *)clip); _cairo_gl_scissor_to_extents (dst, clip_extents); if (equal_clip) return CAIRO_INT_STATUS_SUCCESS; glClearStencil (0); glClear (GL_STENCIL_BUFFER_BIT); glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilFunc (GL_EQUAL, 1, 0xffffffff); glColorMask (0, 0, 0, 0); _cairo_traps_init (&traps); status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip, &traps); _cairo_traps_fini (&traps); if (unlikely (status)) { glColorMask (1, 1, 1, 1); goto disable_stencil_buffer_and_return; } /* We want to only render to the stencil buffer, so draw everything now. Flushing also unbinds the VBO, which we want to rebind for regular drawing. */ _cairo_gl_composite_flush (ctx); _cairo_gl_composite_setup_vbo (ctx, vertex_size); glColorMask (1, 1, 1, 1); glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); glStencilFunc (GL_EQUAL, 1, 0xffffffff); return CAIRO_INT_STATUS_SUCCESS; disable_stencil_buffer_and_return: _disable_stencil_buffer (); return status; }
cairo_int_status_t _cairo_recording_surface_get_path (cairo_surface_t *surface, cairo_path_fixed_t *path) { cairo_recording_surface_t *recording_surface; cairo_command_t **elements; int i, num_elements; cairo_int_status_t status; if (surface->status) return surface->status; recording_surface = (cairo_recording_surface_t *) surface; status = CAIRO_STATUS_SUCCESS; num_elements = recording_surface->commands.num_elements; elements = _cairo_array_index (&recording_surface->commands, 0); for (i = recording_surface->replay_start_idx; i < num_elements; i++) { cairo_command_t *command = elements[i]; switch (command->header.type) { case CAIRO_COMMAND_PAINT: case CAIRO_COMMAND_MASK: status = CAIRO_INT_STATUS_UNSUPPORTED; break; case CAIRO_COMMAND_STROKE: { cairo_traps_t traps; _cairo_traps_init (&traps); /* XXX call cairo_stroke_to_path() when that is implemented */ status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path, &command->stroke.style, &command->stroke.ctm, &command->stroke.ctm_inverse, command->stroke.tolerance, &traps); if (status == CAIRO_STATUS_SUCCESS) status = _cairo_traps_path (&traps, path); _cairo_traps_fini (&traps); break; } case CAIRO_COMMAND_FILL: { status = _cairo_path_fixed_append (path, &command->fill.path, CAIRO_DIRECTION_FORWARD, 0, 0); break; } case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: { status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font, command->show_text_glyphs.glyphs, command->show_text_glyphs.num_glyphs, path); break; } default: ASSERT_NOT_REACHED; } if (unlikely (status)) break; } return _cairo_surface_set_error (surface, status); }
static cairo_int_status_t _cairo_analysis_surface_fill (void *abstract_surface, cairo_operator_t op, cairo_pattern_t *source, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { cairo_analysis_surface_t *surface = abstract_surface; cairo_status_t status, backend_status; cairo_traps_t traps; cairo_rectangle_int_t extents; if (!surface->target->backend->fill) backend_status = CAIRO_INT_STATUS_UNSUPPORTED; else backend_status = (*surface->target->backend->fill) (surface->target, op, source, path, fill_rule, tolerance, antialias); if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) backend_status = _analyze_meta_surface_pattern (surface, source); status = _cairo_surface_get_extents (&surface->base, &extents); if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) return status; if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); if (status) return status; _cairo_rectangle_intersect (&extents, &source_extents); } _cairo_rectangle_intersect (&extents, &surface->current_clip); if (_cairo_operator_bounded_by_mask (op)) { cairo_box_t box; _cairo_box_from_rectangle (&box, &extents); _cairo_traps_init (&traps); _cairo_traps_limit (&traps, &box); status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); if (status) { _cairo_traps_fini (&traps); return status; } _cairo_traps_extents (&traps, &box); _cairo_traps_fini (&traps); _cairo_box_round_to_rectangle (&box, &extents); } status = _add_operation (surface, &extents, backend_status); 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); _cairo_polygon_limit (&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; }