static cairo_int_status_t _draw_int_rect (cairo_gl_context_t *ctx, cairo_gl_composite_t *setup, cairo_rectangle_int_t *rect) { cairo_box_t box; _cairo_box_from_rectangle (&box, rect); return _cairo_gl_msaa_compositor_draw_quad (ctx, setup, &box); }
cairo_status_t _cairo_recording_surface_get_bbox (cairo_recording_surface_t *surface, cairo_box_t *bbox, const cairo_matrix_t *transform) { if (! surface->unbounded) { _cairo_box_from_rectangle (bbox, &surface->extents); if (transform != NULL) _cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL); return CAIRO_STATUS_SUCCESS; } return _recording_surface_get_ink_bbox (surface, bbox, transform); }
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; }
cairo_bool_t _cairo_composite_rectangles_can_reduce_clip (cairo_composite_rectangles_t *composite, cairo_clip_t *clip) { cairo_rectangle_int_t extents; cairo_box_t box; if (clip == NULL) return TRUE; extents = composite->destination; if (composite->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) _cairo_rectangle_intersect (&extents, &composite->source); if (composite->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) _cairo_rectangle_intersect (&extents, &composite->mask); _cairo_box_from_rectangle (&box, &extents); return _cairo_clip_contains_box (clip, &box); }
static cairo_int_status_t _draw_int_rect (cairo_gl_context_t *ctx, cairo_gl_composite_t *setup, cairo_rectangle_int_t *rect) { cairo_box_t box; cairo_point_t quad[4]; _cairo_box_from_rectangle (&box, rect); quad[0].x = box.p1.x; quad[0].y = box.p1.y; quad[1].x = box.p1.x; quad[1].y = box.p2.y; quad[2].x = box.p2.x; quad[2].y = box.p2.y; quad[3].x = box.p2.x; quad[3].y = box.p1.y; return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad); }
static cairo_int_status_t composite_boxes (const cairo_spans_compositor_t *compositor, cairo_composite_rectangles_t *extents, cairo_boxes_t *boxes) { cairo_abstract_span_renderer_t renderer; cairo_rectangular_scan_converter_t converter; const struct _cairo_boxes_chunk *chunk; cairo_int_status_t status; cairo_box_t box; TRACE ((stderr, "%s\n", __FUNCTION__)); _cairo_box_from_rectangle (&box, &extents->unbounded); if (composite_needs_clip (extents, &box)) { TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__)); return CAIRO_INT_STATUS_UNSUPPORTED; } _cairo_rectangular_scan_converter_init (&converter, &extents->unbounded); for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { const cairo_box_t *box = chunk->base; int i; for (i = 0; i < chunk->count; i++) { status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1); if (unlikely (status)) goto cleanup_converter; } } status = compositor->renderer_init (&renderer, extents, CAIRO_ANTIALIAS_DEFAULT, FALSE); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = converter.base.generate (&converter.base, &renderer.base); compositor->renderer_fini (&renderer, status); cleanup_converter: converter.base.destroy (&converter.base); 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; }
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; }
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_spans_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) { const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor; cairo_int_status_t status; TRACE_ (_cairo_debug_print_path (stderr, path)); status = CAIRO_INT_STATUS_UNSUPPORTED; if (_cairo_path_fixed_stroke_is_rectilinear (path)) { cairo_boxes_t boxes; _cairo_boxes_init (&boxes); if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask)) _cairo_boxes_limit (&boxes, extents->clip->boxes, extents->clip->num_boxes); status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, style, ctm, antialias, &boxes); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = clip_and_composite_boxes (compositor, extents, &boxes); _cairo_boxes_fini (&boxes); } if (status == CAIRO_INT_STATUS_UNSUPPORTED) { cairo_polygon_t polygon; cairo_fill_rule_t fill_rule = CAIRO_FILL_RULE_WINDING; if (extents->mask.width > extents->unbounded.width || extents->mask.height > extents->unbounded.height) { cairo_box_t limits; _cairo_box_from_rectangle (&limits, &extents->unbounded); _cairo_polygon_init (&polygon, &limits, 1); } else { _cairo_polygon_init (&polygon, NULL, 0); } status = _cairo_path_fixed_stroke_to_polygon (path, style, ctm, ctm_inverse, tolerance, &polygon); TRACE_ (_cairo_debug_print_polygon (stderr, &polygon)); if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) { status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule, extents->clip->boxes, extents->clip->num_boxes); } if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { cairo_clip_t *saved_clip = extents->clip; if (extents->is_bounded) { extents->clip = _cairo_clip_copy_path (extents->clip); extents->clip = _cairo_clip_intersect_box(extents->clip, &polygon.extents); } status = clip_and_composite_polygon (compositor, extents, &polygon, fill_rule, antialias); if (extents->is_bounded) { _cairo_clip_destroy (extents->clip); extents->clip = saved_clip; } } _cairo_polygon_fini (&polygon); } return status; }
static cairo_surface_t * get_clip_surface (const cairo_spans_compositor_t *compositor, cairo_surface_t *dst, const cairo_clip_t *clip, const cairo_rectangle_int_t *extents) { cairo_composite_rectangles_t composite; cairo_surface_t *surface; cairo_box_t box; cairo_polygon_t polygon; const cairo_clip_path_t *clip_path; cairo_antialias_t antialias; cairo_fill_rule_t fill_rule; cairo_int_status_t status; assert (clip->path); surface = _cairo_surface_create_similar_solid (dst, CAIRO_CONTENT_ALPHA, extents->width, extents->height, CAIRO_COLOR_TRANSPARENT); _cairo_box_from_rectangle (&box, extents); _cairo_polygon_init (&polygon, &box, 1); clip_path = clip->path; status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, clip_path->tolerance, &polygon); if (unlikely (status)) goto cleanup_polygon; antialias = clip_path->antialias; fill_rule = clip_path->fill_rule; if (clip->boxes) { cairo_polygon_t intersect; cairo_boxes_t tmp; _cairo_boxes_init_for_array (&tmp, clip->boxes, clip->num_boxes); status= _cairo_polygon_init_boxes (&intersect, &tmp); if (unlikely (status)) goto cleanup_polygon; status = _cairo_polygon_intersect (&polygon, fill_rule, &intersect, CAIRO_FILL_RULE_WINDING); _cairo_polygon_fini (&intersect); if (unlikely (status)) goto cleanup_polygon; fill_rule = CAIRO_FILL_RULE_WINDING; } polygon.limits = NULL; polygon.num_limits = 0; clip_path = clip_path->prev; while (clip_path) { if (clip_path->antialias == antialias) { 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_INT_STATUS_SUCCESS)) status = _cairo_polygon_intersect (&polygon, fill_rule, &next, clip_path->fill_rule); _cairo_polygon_fini (&next); if (unlikely (status)) goto cleanup_polygon; fill_rule = CAIRO_FILL_RULE_WINDING; } clip_path = clip_path->prev; } _cairo_polygon_translate (&polygon, -extents->x, -extents->y); status = _cairo_composite_rectangles_init_for_polygon (&composite, surface, CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base, &polygon, NULL); if (unlikely (status)) goto cleanup_polygon; status = composite_polygon (compositor, &composite, &polygon, fill_rule, antialias); _cairo_composite_rectangles_fini (&composite); _cairo_polygon_fini (&polygon); if (unlikely (status)) goto error; _cairo_polygon_init (&polygon, &box, 1); clip_path = clip->path; antialias = clip_path->antialias == CAIRO_ANTIALIAS_DEFAULT ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT; clip_path = clip_path->prev; while (clip_path) { if (clip_path->antialias == antialias) { if (polygon.num_edges == 0) { status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, clip_path->tolerance, &polygon); fill_rule = clip_path->fill_rule; polygon.limits = NULL; polygon.num_limits = 0; } else { 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_INT_STATUS_SUCCESS)) status = _cairo_polygon_intersect (&polygon, fill_rule, &next, clip_path->fill_rule); _cairo_polygon_fini (&next); fill_rule = CAIRO_FILL_RULE_WINDING; } if (unlikely (status)) goto error; } clip_path = clip_path->prev; } if (polygon.num_edges) { _cairo_polygon_translate (&polygon, -extents->x, -extents->y); status = _cairo_composite_rectangles_init_for_polygon (&composite, surface, CAIRO_OPERATOR_IN, &_cairo_pattern_white.base, &polygon, NULL); if (unlikely (status)) goto cleanup_polygon; status = composite_polygon (compositor, &composite, &polygon, fill_rule, antialias); _cairo_composite_rectangles_fini (&composite); _cairo_polygon_fini (&polygon); if (unlikely (status)) goto error; } return surface; cleanup_polygon: _cairo_polygon_fini (&polygon); error: cairo_surface_destroy (surface); return _cairo_int_surface_create_in_error (status); }
static cairo_int_status_t _cairo_spans_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) { const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor; cairo_int_status_t status; TRACE((stderr, "%s op=%d, antialias=%d\n", __FUNCTION__, extents->op, antialias)); status = CAIRO_INT_STATUS_UNSUPPORTED; if (_cairo_path_fixed_fill_is_rectilinear (path)) { cairo_boxes_t boxes; TRACE((stderr, "%s - rectilinear\n", __FUNCTION__)); _cairo_boxes_init (&boxes); if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask)) _cairo_boxes_limit (&boxes, extents->clip->boxes, extents->clip->num_boxes); status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, fill_rule, antialias, &boxes); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = clip_and_composite_boxes (compositor, extents, &boxes); _cairo_boxes_fini (&boxes); } if (status == CAIRO_INT_STATUS_UNSUPPORTED) { cairo_polygon_t polygon; TRACE((stderr, "%s - polygon\n", __FUNCTION__)); if (extents->mask.width > extents->unbounded.width || extents->mask.height > extents->unbounded.height) { cairo_box_t limits; TRACE((stderr, "%s - clipping to bounds\n", __FUNCTION__)); _cairo_box_from_rectangle (&limits, &extents->unbounded); _cairo_polygon_init (&polygon, &limits, 1); } else { _cairo_polygon_init (&polygon, NULL, 0); } status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) { TRACE((stderr, "%s - polygon intersect with %d clip boxes\n", __FUNCTION__, extents->clip->num_boxes)); status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule, extents->clip->boxes, extents->clip->num_boxes); } if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { cairo_clip_t *saved_clip = extents->clip; if (extents->is_bounded) { TRACE((stderr, "%s - polygon discard clip boxes\n", __FUNCTION__)); extents->clip = _cairo_clip_copy_path (extents->clip); extents->clip = _cairo_clip_intersect_box(extents->clip, &polygon.extents); } status = clip_and_composite_polygon (compositor, extents, &polygon, fill_rule, antialias); if (extents->is_bounded) { _cairo_clip_destroy (extents->clip); extents->clip = saved_clip; } } _cairo_polygon_fini (&polygon); TRACE((stderr, "%s - polygon status=%d\n", __FUNCTION__, status)); } return status; }
static cairo_int_status_t _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, const cairo_pattern_t *pattern, cairo_rectangle_int_t *extents) { const cairo_surface_pattern_t *surface_pattern; cairo_analysis_surface_t *tmp; cairo_surface_t *source, *proxy; cairo_matrix_t p2d; cairo_int_status_t status, analysis_status; cairo_bool_t surface_is_unbounded; cairo_bool_t unused; assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); surface_pattern = (const cairo_surface_pattern_t *) pattern; assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING); source = surface_pattern->surface; proxy = _cairo_surface_has_snapshot (source, &proxy_backend); if (proxy != NULL) { /* nothing untoward found so far */ return CAIRO_STATUS_SUCCESS; } tmp = (cairo_analysis_surface_t *) _cairo_analysis_surface_create (surface->target); if (unlikely (tmp->base.status)) { status =tmp->base.status; goto cleanup1; } proxy = attach_proxy (source, &tmp->base); p2d = pattern->matrix; status = cairo_matrix_invert (&p2d); assert (status == CAIRO_INT_STATUS_SUCCESS); _cairo_analysis_surface_set_ctm (&tmp->base, &p2d); source = _cairo_surface_get_source (source, NULL); surface_is_unbounded = (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_REFLECT); status = _cairo_recording_surface_replay_and_create_regions (source, &pattern->matrix, &tmp->base, surface_is_unbounded); if (unlikely (status)) goto cleanup2; /* black background or mime data fills entire extents */ if (!(source->content & CAIRO_CONTENT_ALPHA) || _cairo_surface_has_mime_image (source)) { cairo_rectangle_int_t rect; if (_cairo_surface_get_extents (source, &rect)) { cairo_box_t bbox; _cairo_box_from_rectangle (&bbox, &rect); _cairo_matrix_transform_bounding_box_fixed (&p2d, &bbox, NULL); _cairo_box_round_to_rectangle (&bbox, &rect); status = _add_operation (tmp, &rect, CAIRO_INT_STATUS_SUCCESS); if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) status = CAIRO_INT_STATUS_SUCCESS; if (unlikely (status)) goto cleanup2; } } if (tmp->has_supported) { surface->has_supported = TRUE; unused = cairo_region_union (&surface->supported_region, &tmp->supported_region); } if (tmp->has_unsupported) { surface->has_unsupported = TRUE; unused = cairo_region_union (&surface->fallback_region, &tmp->fallback_region); } analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS; if (pattern->extend != CAIRO_EXTEND_NONE) { _cairo_unbounded_rectangle_init (extents); } else { status = cairo_matrix_invert (&tmp->ctm); _cairo_matrix_transform_bounding_box_fixed (&tmp->ctm, &tmp->page_bbox, NULL); _cairo_box_round_to_rectangle (&tmp->page_bbox, extents); } cleanup2: detach_proxy (proxy); cleanup1: cairo_surface_destroy (&tmp->base); if (unlikely (status)) return status; return analysis_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_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 _add_operation (cairo_analysis_surface_t *surface, cairo_rectangle_int_t *rect, cairo_int_status_t backend_status) { cairo_int_status_t status; cairo_box_t bbox; if (rect->width == 0 || rect->height == 0) { /* 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 || backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) { return CAIRO_STATUS_SUCCESS; } else { return CAIRO_INT_STATUS_IMAGE_FALLBACK; } } _cairo_box_from_rectangle (&bbox, rect); if (surface->has_ctm) { _cairo_matrix_transform_bounding_box_fixed (&surface->ctm, &bbox, NULL); if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) { /* 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 || backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) { return CAIRO_STATUS_SUCCESS; } else { return CAIRO_INT_STATUS_IMAGE_FALLBACK; } } _cairo_box_round_to_rectangle (&bbox, rect); } if (surface->first_op) { surface->first_op = FALSE; surface->page_bbox = bbox; } else { if (bbox.p1.x < surface->page_bbox.p1.x) surface->page_bbox.p1.x = bbox.p1.x; if (bbox.p1.y < surface->page_bbox.p1.y) surface->page_bbox.p1.y = bbox.p1.y; if (bbox.p2.x > surface->page_bbox.p2.x) surface->page_bbox.p2.x = bbox.p2.x; if (bbox.p2.y > surface->page_bbox.p2.y) surface->page_bbox.p2.y = bbox.p2.y; } /* If the operation is completely enclosed within the fallback * region there is no benefit in emitting a native operation as * the fallback image will be painted on top. */ if (_cairo_region_contains_rectangle (&surface->fallback_region, rect) == PIXMAN_REGION_IN) return CAIRO_INT_STATUS_IMAGE_FALLBACK; if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) { /* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates * that the backend only supports this operation if the * transparency removed. If the extents of this operation does * not intersect any other native operation, the operation is * natively supported and the backend will blend the * transparency into the white background. */ if (_cairo_region_contains_rectangle (&surface->supported_region, rect) == PIXMAN_REGION_OUT) backend_status = CAIRO_STATUS_SUCCESS; } if (backend_status == CAIRO_STATUS_SUCCESS) { /* Add the operation to the supported region. Operations in * this region will be emitted as native operations. */ surface->has_supported = TRUE; status = _cairo_region_union_rect (&surface->supported_region, &surface->supported_region, rect); return status; } /* Add the operation to the unsupported region. This region will * be painted as an image after all native operations have been * emitted. */ surface->has_unsupported = TRUE; status = _cairo_region_union_rect (&surface->fallback_region, &surface->fallback_region, rect); /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate * unsupported operations to the meta surface as using * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to * invoke the cairo-surface-fallback path then return * CAIRO_STATUS_SUCCESS. */ if (status == CAIRO_STATUS_SUCCESS) return CAIRO_INT_STATUS_IMAGE_FALLBACK; else return status; }
static cairo_int_status_t _cairo_spans_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) { const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor; cairo_int_status_t status; status = CAIRO_INT_STATUS_UNSUPPORTED; if (_cairo_path_fixed_fill_is_rectilinear (path)) { cairo_boxes_t boxes; _cairo_boxes_init (&boxes); if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask)) _cairo_boxes_limit (&boxes, extents->clip->boxes, extents->clip->num_boxes); status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, fill_rule, antialias, &boxes); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = clip_and_composite_boxes (compositor, extents, &boxes); _cairo_boxes_fini (&boxes); } if (status == CAIRO_INT_STATUS_UNSUPPORTED) { cairo_polygon_t polygon; if (extents->mask.width > extents->unbounded.width || extents->mask.height > extents->unbounded.height) { cairo_box_t limits; _cairo_box_from_rectangle (&limits, &extents->unbounded); _cairo_polygon_init (&polygon, &limits, 1); } else { _cairo_polygon_init (&polygon, NULL, 0); } status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule, extents->clip->boxes, extents->clip->num_boxes); } if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { if (extents->is_bounded) { if (extents->clip->boxes != &extents->clip->embedded_box) free (extents->clip->boxes); extents->clip->num_boxes = 1; extents->clip->boxes = &extents->clip->embedded_box; extents->clip->boxes[0] = polygon.extents; } status = clip_and_composite_polygon (compositor, extents, &polygon, fill_rule, antialias); } _cairo_polygon_fini (&polygon); } return status; }