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_int_status_t _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx, cairo_gl_composite_t *setup, cairo_clip_t *clip, cairo_traps_t *traps) { cairo_int_status_t status; cairo_polygon_t polygon; cairo_antialias_t antialias; cairo_fill_rule_t fill_rule; if (! clip) return CAIRO_INT_STATUS_UNSUPPORTED; if (clip->num_boxes == 1 && ! clip->path) return _cairo_gl_msaa_compositor_draw_quad (ctx, setup, &clip->boxes[0]); if (traps->num_traps == 0) { 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. */ 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); 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; }
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; }
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_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_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; }
/* Masking with the SOURCE operator requires two passes. In the first * pass we use the mask as the source to get: * result = (1 - ma) * dst * In the second pass we use the add operator to achieve: * result = (src * ma) + dst * Combined this produces: * 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_clip_t *clip = composite->clip; cairo_traps_t traps; /* If we have a non-rectangular clip, we can avoid using the stencil buffer * for clipping and just draw the clip polygon. */ if (clip) { status = _clip_to_traps (clip, &traps); if (unlikely (status)) { _cairo_traps_fini (&traps); return status; } } status = _cairo_gl_composite_init (&setup, CAIRO_OPERATOR_DEST_OUT, dst, FALSE /* assume_component_alpha */); if (unlikely (status)) return status; status = _cairo_gl_composite_set_source (&setup, &composite->mask_pattern.base, &composite->mask_sample_area, &composite->bounded, FALSE); if (unlikely (status)) goto finish; _cairo_gl_composite_set_multisample (&setup); status = _cairo_gl_composite_begin (&setup, &ctx); if (unlikely (status)) goto finish; if (! clip) status = _draw_int_rect (ctx, &setup, &composite->bounded); else status = _draw_traps (ctx, &setup, &traps); /* Now draw the second pass. */ _cairo_gl_composite_set_operator (&setup, CAIRO_OPERATOR_ADD, FALSE /* assume_component_alpha */); if (unlikely (status)) goto finish; 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, FALSE); if (unlikely (status)) goto finish; status = _cairo_gl_set_operands_and_operator (&setup, ctx); if (unlikely (status)) goto finish; if (! clip) status = _draw_int_rect (ctx, &setup, &composite->bounded); else status = _draw_traps (ctx, &setup, &traps); finish: _cairo_gl_composite_fini (&setup); if (ctx) status = _cairo_gl_context_release (ctx, status); if (clip) _cairo_traps_fini (&traps); return status; }