cairo_int_status_t _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup, const cairo_pattern_t *pattern, const cairo_rectangle_int_t *sample, const cairo_rectangle_int_t *extents) { cairo_int_status_t status; _cairo_gl_operand_destroy (&setup->mask); if (pattern == NULL) return CAIRO_STATUS_SUCCESS; /* XXX: shoot me - we need to set component_alpha to be true if op is CAIRO_OPERATOR_CLEAR AND pattern is a surface_pattern */ status = _cairo_gl_operand_init (&setup->mask, pattern, setup->dst, sample, extents, FALSE); if (unlikely (status)) return status; if (setup->op == CAIRO_OPERATOR_CLEAR && ! _cairo_pattern_is_opaque (pattern, sample)) setup->mask.texture.attributes.has_component_alpha = TRUE; return status; }
static cairo_int_status_t _prevent_overlapping_strokes (cairo_gl_context_t *ctx, cairo_gl_composite_t *setup, cairo_composite_rectangles_t *composite, const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm) { cairo_rectangle_int_t stroke_extents; if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) return CAIRO_INT_STATUS_UNSUPPORTED; if (_cairo_pattern_is_opaque (&composite->source_pattern.base, &composite->source_sample_area)) return CAIRO_INT_STATUS_SUCCESS; if (glIsEnabled (GL_STENCIL_TEST) == FALSE) { cairo_bool_t scissor_was_enabled; /* In case we have pending operations we have to flush before adding the stencil buffer. */ _cairo_gl_composite_flush (ctx); /* Enable the stencil buffer, even if we are not using it for clipping, so we can use it below to prevent overlapping shapes. We initialize it all to one here which represents infinite clip. */ glDepthMask (GL_TRUE); glEnable (GL_STENCIL_TEST); /* We scissor here so that we don't have to clear the entire stencil * buffer. If the scissor test is already enabled, it was enabled * for clipping. In that case, instead of calculating an intersection, * we just reuse it, and risk clearing too much. */ scissor_was_enabled = glIsEnabled (GL_SCISSOR_TEST); if (! scissor_was_enabled) { _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, FALSE, /* is_vector */ &stroke_extents); _cairo_gl_scissor_to_rectangle (setup->dst, &stroke_extents); } glClearStencil (1); glClear (GL_STENCIL_BUFFER_BIT); if (! scissor_was_enabled) glDisable (GL_SCISSOR_TEST); glStencilFunc (GL_EQUAL, 1, 1); } /* This means that once we draw to a particular pixel nothing else can be drawn there until the stencil buffer is reset or the stencil test is disabled. */ glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO); _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer); setup->dst->clip_on_stencil_buffer = NULL; return CAIRO_INT_STATUS_SUCCESS; }
static cairo_bool_t op_reduces_to_source (const cairo_composite_rectangles_t *extents, cairo_bool_t no_mask) { if (extents->op == CAIRO_OPERATOR_SOURCE) return TRUE; if (extents->surface->is_clear) return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD; if (no_mask && extents->op == CAIRO_OPERATOR_OVER) return _cairo_pattern_is_opaque (&extents->source_pattern.base, &extents->source_sample_area); return FALSE; }
static cairo_status_t draw_boxes (cairo_composite_rectangles_t *composite, cairo_boxes_t *boxes) { cairo_win32_display_surface_t *dst = to_win32_display_surface(composite->surface); cairo_operator_t op = composite->op; const cairo_pattern_t *src = &composite->source_pattern.base; cairo_int_status_t status; TRACE ((stderr, "%s\n", __FUNCTION__)); if (boxes->num_boxes == 0 && composite->is_bounded) return CAIRO_STATUS_SUCCESS; if (!boxes->is_pixel_aligned) return CAIRO_STATUS_SUCCESS; //return CAIRO_INT_STATUS_UNSUPPORTED; if (op == CAIRO_OPERATOR_CLEAR) op = CAIRO_OPERATOR_SOURCE; if (op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_opaque (src, &composite->bounded)) op = CAIRO_OPERATOR_SOURCE; if (dst->win32.base.is_clear && (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD)) op = CAIRO_OPERATOR_SOURCE; if (op == CAIRO_OPERATOR_SOURCE) { status = CAIRO_INT_STATUS_UNSUPPORTED; if (src->type == CAIRO_PATTERN_TYPE_SURFACE) { status = copy_boxes (dst, src, boxes); if (status == CAIRO_INT_STATUS_UNSUPPORTED) status = upload_boxes (dst, src, boxes); } else if (src->type == CAIRO_PATTERN_TYPE_SOLID) { status = fill_boxes (dst, src, boxes); } return status; } if (op == CAIRO_OPERATOR_OVER && can_alpha_blend (dst)) return alpha_blend_boxes (dst, src, boxes, 255); return CAIRO_INT_STATUS_UNSUPPORTED; }
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; }