1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2002 University of Southern California
5 * Copyright © 2005 Red Hat, Inc.
6 * Copyright © 2011 Intel Corporation
7 * Copyright © 2011 Samsung Electronics
9 * This library is free software; you can redistribute it and/or
10 * modify it either under the terms of the GNU Lesser General Public
11 * License version 2.1 as published by the Free Software Foundation
12 * (the "LGPL") or, at your option, under the terms of the Mozilla
13 * Public License Version 1.1 (the "MPL"). If you do not alter this
14 * notice, a recipient may use your version of this file under either
15 * the MPL or the LGPL.
17 * You should have received a copy of the LGPL along with this library
18 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
20 * You should have received a copy of the MPL along with this library
21 * in the file COPYING-MPL-1.1
23 * The contents of this file are subject to the Mozilla Public License
24 * Version 1.1 (the "License"); you may not use this file except in
25 * compliance with the License. You may obtain a copy of the License at
26 * http://www.mozilla.org/MPL/
28 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
29 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
30 * the specific language governing rights and limitations.
32 * The Original Code is the cairo graphics library.
34 * The Initial Developer of the Original Code is University of Southern
38 * Henry Song <hsong@sisa.samsung.com>
39 * Martin Robinson <mrobinson@igalia.com>
44 #include "cairo-clip-inline.h"
45 #include "cairo-composite-rectangles-private.h"
46 #include "cairo-compositor-private.h"
47 #include "cairo-gl-private.h"
48 #include "cairo-path-private.h"
49 #include "cairo-traps-private.h"
52 can_use_msaa_compositor (cairo_gl_surface_t *surface,
53 cairo_antialias_t antialias);
56 query_surface_capabilities (cairo_gl_surface_t *surface);
58 struct _tristrip_composite_info {
59 cairo_gl_composite_t setup;
60 cairo_gl_context_t *ctx;
64 _is_continuous_single_line (const cairo_path_fixed_t *path,
65 const cairo_stroke_style_t *style)
67 return (_cairo_path_fixed_is_single_line (path) &&
72 static cairo_int_status_t
73 _draw_trap (cairo_gl_context_t *ctx,
74 cairo_gl_composite_t *setup,
75 cairo_trapezoid_t *trap)
77 cairo_point_t quad[4];
79 if (trap->left.p1.x == trap->left.p2.x) {
80 quad[0].x = trap->left.p1.x;
81 quad[1].x = trap->left.p1.x;
85 dy = trap->left.p2.y - trap->left.p1.y;
87 if (trap->top == trap->left.p1.y)
89 else if (trap->top == trap->left.p2.y)
90 quad[0].x = trap->left.p2.x;
92 quad[0].x = x + _cairo_fixed_mul_div_floor (trap->top - trap->left.p1.y,
93 trap->left.p2.x - trap->left.p1.x, dy);
95 if (trap->bottom == trap->left.p2.y)
96 quad[1].x = trap->left.p2.x;
97 else if (trap->bottom == trap->left.p1.y)
100 quad[1].x = x + _cairo_fixed_mul_div_floor (trap->bottom - trap->left.p1.y,
101 trap->left.p2.x - trap->left.p1.x, dy);
103 quad[0].y = trap->top;
104 quad[1].y = trap->bottom;
106 if (trap->right.p1.x == trap->right.p2.x) {
107 quad[2].x = trap->right.p1.x;
108 quad[3].x = trap->right.p1.x;
111 x = trap->right.p1.x;
112 dy = trap->right.p2.y - trap->right.p1.y;
114 if (trap->bottom == trap->right.p2.y)
115 quad[2].x = trap->right.p2.x;
116 else if (trap->bottom == trap->right.p1.y)
119 quad[2].x = x + _cairo_fixed_mul_div_floor (trap->bottom - trap->right.p1.y,
120 trap->right.p2.x - trap->right.p1.x, dy);
122 if (trap->top == trap->right.p1.y)
124 else if (trap->top == trap->right.p2.y)
125 quad[3].x = trap->right.p2.x;
127 quad[3].x = x + _cairo_fixed_mul_div_floor (trap->top - trap->right.p1.y,
128 trap->right.p2.x - trap->right.p1.x, dy);
130 quad[2].y = trap->bottom;
131 quad[3].y = trap->top;
133 return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
136 static cairo_int_status_t
137 _draw_traps (cairo_gl_context_t *ctx,
138 cairo_gl_composite_t *setup,
139 cairo_traps_t *traps)
141 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
144 for (i = 0; i < traps->num_traps; i++) {
145 cairo_trapezoid_t *trap = traps->traps + i;
146 if (unlikely ((status = _draw_trap (ctx, setup, trap))))
153 static cairo_int_status_t
154 _draw_int_rect (cairo_gl_context_t *ctx,
155 cairo_gl_composite_t *setup,
156 cairo_rectangle_int_t *rect)
159 cairo_point_t quad[4];
161 _cairo_box_from_rectangle (&box, rect);
162 quad[0].x = box.p1.x;
163 quad[0].y = box.p1.y;
164 quad[1].x = box.p1.x;
165 quad[1].y = box.p2.y;
166 quad[2].x = box.p2.x;
167 quad[2].y = box.p2.y;
168 quad[3].x = box.p2.x;
169 quad[3].y = box.p1.y;
171 return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
174 static cairo_int_status_t
175 _draw_triangle_fan (cairo_gl_context_t *ctx,
176 cairo_gl_composite_t *setup,
177 const cairo_point_t *midpt,
178 const cairo_point_t *points,
183 /* Our strategy here is to not even try to build a triangle fan, but to
184 draw each triangle as if it was an unconnected member of a triangle strip. */
185 for (i = 1; i < npoints; i++) {
186 cairo_int_status_t status;
187 cairo_point_t triangle[3];
189 triangle[0] = *midpt;
190 triangle[1] = points[i - 1];
191 triangle[2] = points[i];
193 status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
194 if (unlikely (status))
198 return CAIRO_STATUS_SUCCESS;
201 static cairo_int_status_t
202 _clip_to_traps (cairo_clip_t *clip,
203 cairo_traps_t *traps)
205 cairo_int_status_t status;
206 cairo_polygon_t polygon;
207 cairo_antialias_t antialias;
208 cairo_fill_rule_t fill_rule;
210 _cairo_traps_init (traps);
212 if (clip->num_boxes == 1 && clip->path == NULL) {
214 _cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
215 return _cairo_traps_init_boxes (traps, &boxes);
218 status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias);
219 if (unlikely (status))
222 /* We ignore the antialias mode of the clip here, since the user requested
223 * unantialiased rendering of their path and we expect that this stencil
224 * based rendering of the clip to be a reasonable approximation to
225 * the intersection between that clip and the path.
227 * In other words, what the user expects when they try to perform
228 * a geometric intersection between an unantialiased polygon and an
229 * antialiased polygon is open to interpretation. And we choose the fast
233 _cairo_traps_init (traps);
234 status = _cairo_bentley_ottmann_tessellate_polygon (traps,
237 _cairo_polygon_fini (&polygon);
243 _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
244 cairo_gl_composite_t *setup,
247 cairo_int_status_t status;
250 status = _clip_to_traps (clip, &traps);
251 if (unlikely (status))
253 status = _draw_traps (ctx, setup, &traps);
255 _cairo_traps_fini (&traps);
260 _should_use_unbounded_surface (cairo_composite_rectangles_t *composite)
262 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
263 cairo_rectangle_int_t *source = &composite->source;
265 if (composite->is_bounded)
268 /* This isn't just an optimization. It also detects when painting is used
269 to paint back the unbounded surface, preventing infinite recursion. */
270 return ! (source->x <= 0 && source->y <= 0 &&
271 source->height + source->y >= dst->height &&
272 source->width + source->x >= dst->width);
275 static cairo_surface_t*
276 _prepare_unbounded_surface (cairo_gl_surface_t *dst)
279 cairo_surface_t* surface = cairo_gl_surface_create (dst->base.device,
285 if (unlikely (surface->status)) {
286 cairo_surface_destroy (surface);
292 static cairo_int_status_t
293 _paint_back_unbounded_surface (const cairo_compositor_t *compositor,
294 cairo_composite_rectangles_t *composite,
295 cairo_surface_t *surface)
297 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
298 cairo_int_status_t status;
300 cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
301 if (unlikely (pattern->status)) {
302 status = pattern->status;
306 status = _cairo_compositor_paint (compositor, &dst->base,
307 composite->op, pattern,
311 cairo_pattern_destroy (pattern);
312 cairo_surface_destroy (surface);
317 can_use_msaa_compositor (cairo_gl_surface_t *surface,
318 cairo_antialias_t antialias)
320 query_surface_capabilities (surface);
321 if (! surface->supports_stencil)
324 /* Multisampling OpenGL ES surfaces only maintain one multisampling
325 framebuffer and thus must use the spans compositor to do non-antialiased
327 if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES
328 && surface->supports_msaa
329 && antialias == CAIRO_ANTIALIAS_NONE)
332 /* The MSAA compositor has a single-sample mode, so we can
333 support non-antialiased rendering. */
334 if (antialias == CAIRO_ANTIALIAS_NONE)
337 if (antialias == CAIRO_ANTIALIAS_FAST || antialias == CAIRO_ANTIALIAS_DEFAULT)
338 return surface->supports_msaa;
343 _cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite,
344 cairo_gl_composite_t *setup)
348 /* We don't need to check CAIRO_OPERATOR_BOUND_BY_MASK in these
350 is_bounded = composite->is_bounded;
351 composite->is_bounded = CAIRO_OPERATOR_BOUND_BY_SOURCE;
352 if (_cairo_composite_rectangles_can_reduce_clip (composite, composite->clip))
355 _cairo_gl_composite_set_clip (setup, composite->clip);
357 composite->is_bounded = is_bounded;
360 /* Masking with the SOURCE operator requires two passes. In the first
361 * pass we use the mask as the source to get:
362 * result = (1 - ma) * dst
363 * In the second pass we use the add operator to achieve:
364 * result = (src * ma) + dst
365 * Combined this produces:
366 * result = (src * ma) + (1 - ma) * dst
368 static cairo_int_status_t
369 _cairo_gl_msaa_compositor_mask_source_operator (const cairo_compositor_t *compositor,
370 cairo_composite_rectangles_t *composite)
372 cairo_gl_composite_t setup;
373 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
374 cairo_gl_context_t *ctx = NULL;
375 cairo_int_status_t status;
377 cairo_clip_t *clip = composite->clip;
380 /* If we have a non-rectangular clip, we can avoid using the stencil buffer
381 * for clipping and just draw the clip polygon. */
383 status = _clip_to_traps (clip, &traps);
384 if (unlikely (status)) {
385 _cairo_traps_fini (&traps);
390 status = _cairo_gl_composite_init (&setup,
391 CAIRO_OPERATOR_DEST_OUT,
393 FALSE /* assume_component_alpha */);
394 if (unlikely (status))
396 status = _cairo_gl_composite_set_source (&setup,
397 composite->original_mask_pattern,
398 &composite->mask_sample_area,
401 if (unlikely (status))
403 _cairo_gl_composite_set_multisample (&setup);
404 status = _cairo_gl_composite_begin (&setup, &ctx);
405 if (unlikely (status))
409 status = _draw_int_rect (ctx, &setup, &composite->bounded);
411 status = _draw_traps (ctx, &setup, &traps);
413 /* Now draw the second pass. */
414 _cairo_gl_composite_set_operator (&setup, CAIRO_OPERATOR_ADD,
415 FALSE /* assume_component_alpha */);
416 if (unlikely (status))
418 status = _cairo_gl_composite_set_source (&setup,
419 composite->original_source_pattern,
420 &composite->source_sample_area,
423 if (unlikely (status))
425 status = _cairo_gl_composite_set_mask (&setup,
426 composite->original_mask_pattern,
427 &composite->source_sample_area,
428 &composite->bounded);
429 if (unlikely (status))
431 status = _cairo_gl_set_operands_and_operator (&setup, ctx);
432 if (unlikely (status))
436 status = _draw_int_rect (ctx, &setup, &composite->bounded);
438 status = _draw_traps (ctx, &setup, &traps);
441 _cairo_gl_composite_fini (&setup);
443 status = _cairo_gl_context_release (ctx, status);
445 _cairo_traps_fini (&traps);
450 static cairo_int_status_t
451 _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor,
452 cairo_composite_rectangles_t *composite)
454 cairo_gl_composite_t setup;
455 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
456 cairo_gl_context_t *ctx = NULL;
457 cairo_int_status_t status;
458 cairo_operator_t op = composite->op;
459 cairo_bool_t use_color_attribute = FALSE;
460 cairo_clip_t *clip = composite->clip;
462 if (! can_use_msaa_compositor (dst, CAIRO_ANTIALIAS_DEFAULT))
463 return CAIRO_INT_STATUS_UNSUPPORTED;
465 /* GL compositing operators cannot properly represent a mask operation
466 using the SOURCE compositing operator in one pass. This only matters if
467 there actually is a mask (there isn't in a paint operation) and if the
468 mask isn't totally opaque. */
469 if (op == CAIRO_OPERATOR_SOURCE &&
470 composite->original_mask_pattern != NULL &&
471 ! _cairo_pattern_is_opaque (&composite->mask_pattern.base,
472 &composite->mask_sample_area)) {
474 if (! _cairo_pattern_is_opaque (&composite->source_pattern.base,
475 &composite->source_sample_area)) {
476 return _cairo_gl_msaa_compositor_mask_source_operator (compositor, composite);
479 /* If the source is opaque the operation reduces to OVER. */
480 op = CAIRO_OPERATOR_OVER;
483 if (_should_use_unbounded_surface (composite)) {
484 cairo_surface_t* surface = _prepare_unbounded_surface (dst);
486 if (unlikely (surface == NULL))
487 return CAIRO_INT_STATUS_UNSUPPORTED;
489 /* This may be a paint operation. */
490 if (composite->original_mask_pattern == NULL) {
491 status = _cairo_compositor_paint (compositor, surface,
492 CAIRO_OPERATOR_SOURCE,
493 &composite->source_pattern.base,
496 status = _cairo_compositor_mask (compositor, surface,
497 CAIRO_OPERATOR_SOURCE,
498 &composite->source_pattern.base,
499 &composite->mask_pattern.base,
503 if (unlikely (status)) {
504 cairo_surface_destroy (surface);
508 return _paint_back_unbounded_surface (compositor, composite, surface);
511 status = _cairo_gl_composite_init (&setup,
514 FALSE /* assume_component_alpha */);
515 if (unlikely (status))
518 if (! composite->clip ||
519 (composite->clip->num_boxes == 1 && ! composite->clip->path))
520 use_color_attribute = TRUE;
522 status = _cairo_gl_composite_set_source (&setup,
523 composite->original_source_pattern,
524 &composite->source_sample_area,
526 use_color_attribute);
527 if (unlikely (status))
530 if (composite->original_mask_pattern != NULL) {
531 status = _cairo_gl_composite_set_mask (&setup,
532 composite->original_mask_pattern,
533 &composite->mask_sample_area,
534 &composite->bounded);
536 if (unlikely (status))
539 /* We always use multisampling here, because we do not yet have the smarts
540 to calculate when the clip or the source requires it. */
541 _cairo_gl_composite_set_multisample (&setup);
543 status = _cairo_gl_composite_begin (&setup, &ctx);
544 if (unlikely (status))
548 status = _draw_int_rect (ctx, &setup, &composite->bounded);
550 status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, clip);
553 _cairo_gl_composite_fini (&setup);
556 status = _cairo_gl_context_release (ctx, status);
561 static cairo_int_status_t
562 _cairo_gl_msaa_compositor_paint (const cairo_compositor_t *compositor,
563 cairo_composite_rectangles_t *composite)
565 return _cairo_gl_msaa_compositor_mask (compositor, composite);
568 static cairo_status_t
569 _stroke_shaper_add_triangle (void *closure,
570 const cairo_point_t triangle[3])
572 struct _tristrip_composite_info *info = closure;
573 return _cairo_gl_composite_emit_triangle_as_tristrip (info->ctx,
578 static cairo_status_t
579 _stroke_shaper_add_triangle_fan (void *closure,
580 const cairo_point_t *midpoint,
581 const cairo_point_t *points,
584 struct _tristrip_composite_info *info = closure;
585 return _draw_triangle_fan (info->ctx, &info->setup,
586 midpoint, points, npoints);
589 static cairo_status_t
590 _stroke_shaper_add_quad (void *closure,
591 const cairo_point_t quad[4])
593 struct _tristrip_composite_info *info = closure;
594 return _cairo_gl_composite_emit_quad_as_tristrip (info->ctx, &info->setup,
599 _is_continuous_arc (const cairo_path_fixed_t *path,
600 const cairo_stroke_style_t *style)
602 return (_cairo_path_fixed_is_single_arc (path) &&
603 style->dash == NULL);
606 static cairo_int_status_t
607 _prevent_overlapping_strokes (cairo_gl_context_t *ctx,
608 cairo_gl_composite_t *setup,
609 cairo_composite_rectangles_t *composite,
610 const cairo_path_fixed_t *path,
611 const cairo_stroke_style_t *style,
612 const cairo_matrix_t *ctm)
614 cairo_rectangle_int_t stroke_extents;
615 const cairo_pattern_t *pattern = composite->original_source_pattern;
616 cairo_pattern_type_t type = cairo_pattern_get_type ((cairo_pattern_t *) pattern);
618 if (! _cairo_gl_ensure_stencil (ctx, setup->dst))
619 return CAIRO_INT_STATUS_UNSUPPORTED;
622 /* XXX: improve me - since we have lazy init, we cannot use sample
624 if (type == CAIRO_PATTERN_TYPE_SOLID &&
625 _cairo_pattern_is_opaque_solid (pattern))
626 return CAIRO_INT_STATUS_SUCCESS;
628 if (ctx->states_cache.stencil_test_enabled == FALSE) {
629 /* In case we have pending operations we have to flush before
630 adding the stencil buffer. */
631 _cairo_gl_composite_flush (ctx);
633 /* Enable the stencil buffer, even if we are not using it for clipping,
634 so we can use it below to prevent overlapping shapes. We initialize
635 it all to one here which represents infinite clip. */
636 if (! ctx->states_cache.depth_mask) {
637 glDepthMask (GL_TRUE);
638 ctx->states_cache.depth_mask = TRUE;
640 glEnable (GL_STENCIL_TEST);
641 ctx->states_cache.stencil_test_enabled = TRUE;
643 /* We scissor here so that we don't have to clear the entire stencil
644 * buffer. If the scissor test is already enabled, it was enabled
645 * for clipping. In that case, instead of calculating an intersection,
646 * we just reuse it, and risk clearing too much. */
647 if (ctx->states_cache.scissor_test_enabled == FALSE) {
648 _cairo_path_fixed_approximate_stroke_extents (path, style, ctm,
650 _cairo_gl_scissor_to_rectangle (setup->dst, &stroke_extents);
651 glEnable (GL_SCISSOR_TEST);
652 ctx->states_cache.scissor_test_enabled = TRUE;
655 glClear (GL_STENCIL_BUFFER_BIT);
656 _disable_scissor_buffer (ctx);
658 glStencilFunc (GL_EQUAL, 1, 1);
661 /* This means that once we draw to a particular pixel nothing else can
662 be drawn there until the stencil buffer is reset or the stencil test
664 glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO);
666 _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
667 setup->dst->clip_on_stencil_buffer = NULL;
669 return CAIRO_INT_STATUS_SUCCESS;
673 query_surface_capabilities (cairo_gl_surface_t *surface)
675 GLint samples, stencil_bits;
676 cairo_gl_context_t *ctx;
677 cairo_int_status_t status;
679 /* Texture surfaces are create in such a way that they always
680 have stencil and multisample bits if possible, so we don't
681 need to query their capabilities lazily. */
682 if (_cairo_gl_surface_is_texture (surface))
684 if (surface->stencil_and_msaa_caps_initialized)
687 surface->stencil_and_msaa_caps_initialized = TRUE;
688 surface->supports_stencil = FALSE;
689 surface->supports_msaa = FALSE;
691 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
692 if (unlikely (status))
695 _cairo_gl_context_set_destination (ctx, surface, FALSE);
697 glGetIntegerv(GL_SAMPLES, &samples);
698 glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
699 surface->supports_stencil = stencil_bits > 0;
700 surface->supports_msaa = samples > 1;
702 status = _cairo_gl_context_release (ctx, status);
705 static cairo_int_status_t
706 _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor,
707 cairo_composite_rectangles_t *composite,
708 const cairo_path_fixed_t *path,
709 const cairo_stroke_style_t *style,
710 const cairo_matrix_t *ctm,
711 const cairo_matrix_t *ctm_inverse,
713 cairo_antialias_t antialias)
715 cairo_int_status_t status;
716 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
717 struct _tristrip_composite_info info;
718 cairo_bool_t use_color_attribute;
720 if (! can_use_msaa_compositor (dst, antialias))
721 return CAIRO_INT_STATUS_UNSUPPORTED;
723 if (composite->is_bounded == FALSE) {
724 cairo_surface_t* surface = _prepare_unbounded_surface (dst);
726 if (unlikely (surface == NULL))
727 return CAIRO_INT_STATUS_UNSUPPORTED;
729 status = _cairo_compositor_stroke (compositor, surface,
730 CAIRO_OPERATOR_SOURCE,
731 &composite->source_pattern.base,
732 path, style, ctm, ctm_inverse,
733 tolerance, antialias, NULL);
734 if (unlikely (status)) {
735 cairo_surface_destroy (surface);
739 return _paint_back_unbounded_surface (compositor, composite, surface);
742 status = _cairo_gl_composite_init (&info.setup,
745 FALSE /* assume_component_alpha */);
746 if (unlikely (status))
750 use_color_attribute = _cairo_path_fixed_stroke_is_rectilinear (path) ||
751 _cairo_gl_hairline_style_is_hairline (style, ctm);
753 status = _cairo_gl_composite_set_source (&info.setup,
754 composite->original_source_pattern,
755 &composite->source_sample_area,
757 use_color_attribute);
758 if (unlikely (status))
761 _cairo_gl_msaa_compositor_set_clip (composite, &info.setup);
762 if (antialias != CAIRO_ANTIALIAS_NONE)
763 _cairo_gl_composite_set_multisample (&info.setup);
765 status = _cairo_gl_composite_begin (&info.setup, &info.ctx);
766 if (unlikely (status))
769 if (_cairo_gl_hairline_style_is_hairline (style, ctm)) {
770 cairo_gl_hairline_closure_t closure;
772 if (! (_is_continuous_arc (path, style) ||
773 _is_continuous_single_line (path, style))) {
774 status = _prevent_overlapping_strokes (info.ctx, &info.setup,
777 if (unlikely (status))
781 closure.ctx = info.ctx;
783 closure.tolerance = tolerance;
785 status = _cairo_gl_path_fixed_stroke_to_hairline (path, &closure,
788 _cairo_gl_hairline_move_to,
790 _cairo_gl_hairline_line_to_dashed :
791 _cairo_gl_hairline_line_to,
792 _cairo_gl_hairline_curve_to,
793 _cairo_gl_hairline_close_path);
797 if (use_color_attribute) {
800 _cairo_traps_init (&traps);
802 status = _cairo_path_fixed_stroke_polygon_to_traps (path, style,
805 if (unlikely (status)) {
806 _cairo_traps_fini (&traps);
810 status = _draw_traps (info.ctx, &info.setup, &traps);
811 _cairo_traps_fini (&traps);
813 if (!_is_continuous_single_line (path, style)) {
814 status = _prevent_overlapping_strokes (info.ctx, &info.setup,
815 composite, path, style, ctm);
816 if (unlikely (status))
821 _cairo_path_fixed_stroke_to_shaper ((cairo_path_fixed_t *) path,
826 _stroke_shaper_add_triangle,
827 _stroke_shaper_add_triangle_fan,
828 _stroke_shaper_add_quad,
830 if (unlikely (status))
834 _cairo_gl_composite_fini (&info.setup);
837 status = _cairo_gl_context_release (info.ctx, status);
842 static cairo_int_status_t
843 _draw_simple_quad_path (cairo_gl_context_t *ctx,
844 cairo_gl_composite_t *setup,
845 const cairo_path_fixed_t *path)
847 cairo_point_t triangle[3];
848 cairo_int_status_t status;
849 const cairo_point_t *points;
851 points = cairo_path_head (path)->points;
852 triangle[0] = points[0];
853 triangle[1] = points[1];
854 triangle[2] = points[2];
855 status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
859 triangle[0] = points[2];
860 triangle[1] = points[3];
861 triangle[2] = points[0];
862 return _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
865 static cairo_int_status_t
866 _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor,
867 cairo_composite_rectangles_t *composite,
868 const cairo_path_fixed_t *path,
869 cairo_fill_rule_t fill_rule,
871 cairo_antialias_t antialias)
873 cairo_gl_composite_t setup;
874 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
875 cairo_gl_context_t *ctx = NULL;
876 cairo_int_status_t status;
878 cairo_bool_t draw_path_with_traps;
880 if (! can_use_msaa_compositor (dst, antialias))
881 return CAIRO_INT_STATUS_UNSUPPORTED;
883 if (composite->is_bounded == FALSE) {
884 cairo_surface_t* surface = _prepare_unbounded_surface (dst);
886 if (unlikely (surface == NULL))
887 return CAIRO_INT_STATUS_UNSUPPORTED;
890 status = _cairo_compositor_fill (compositor, surface,
891 CAIRO_OPERATOR_SOURCE,
892 &composite->source_pattern.base,
893 path, fill_rule, tolerance,
896 if (unlikely (status)) {
897 cairo_surface_destroy (surface);
901 return _paint_back_unbounded_surface (compositor, composite, surface);
904 draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path);
906 if (draw_path_with_traps) {
907 _cairo_traps_init (&traps);
908 status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
909 if (unlikely (status))
913 status = _cairo_gl_composite_init (&setup,
916 FALSE /* assume_component_alpha */);
917 if (unlikely (status))
920 status = _cairo_gl_composite_set_source (&setup,
921 composite->original_source_pattern,
922 &composite->source_sample_area,
924 !draw_path_with_traps);
925 if (unlikely (status))
928 _cairo_gl_msaa_compositor_set_clip (composite, &setup);
929 if (antialias != CAIRO_ANTIALIAS_NONE)
930 _cairo_gl_composite_set_multisample (&setup);
932 status = _cairo_gl_composite_begin (&setup, &ctx);
933 if (unlikely (status))
936 if (! draw_path_with_traps)
937 status = _draw_simple_quad_path (ctx, &setup, path);
939 status = _draw_traps (ctx, &setup, &traps);
940 if (unlikely (status))
944 _cairo_gl_composite_fini (&setup);
947 status = _cairo_gl_context_release (ctx, status);
950 if (draw_path_with_traps)
951 _cairo_traps_fini (&traps);
956 static cairo_int_status_t
957 _cairo_gl_msaa_compositor_glyphs (const cairo_compositor_t *compositor,
958 cairo_composite_rectangles_t *composite,
959 cairo_scaled_font_t *scaled_font,
960 cairo_glyph_t *glyphs,
962 cairo_bool_t overlap)
964 cairo_int_status_t status;
965 cairo_surface_t *src = NULL;
967 cairo_composite_glyphs_info_t info;
969 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
971 query_surface_capabilities (dst);
972 if (! dst->supports_stencil)
973 return CAIRO_INT_STATUS_UNSUPPORTED;
975 if (composite->is_bounded == FALSE) {
976 cairo_surface_t* surface = _prepare_unbounded_surface (dst);
978 if (unlikely (surface == NULL))
979 return CAIRO_INT_STATUS_UNSUPPORTED;
981 status = _cairo_compositor_glyphs (compositor, surface,
982 CAIRO_OPERATOR_SOURCE,
983 &composite->source_pattern.base,
985 scaled_font, composite->clip);
987 if (unlikely (status)) {
988 cairo_surface_destroy (surface);
992 return _paint_back_unbounded_surface (compositor, composite, surface);
995 src = _cairo_gl_pattern_to_source (&dst->base,
996 composite->original_source_pattern,
999 &composite->source_sample_area,
1001 if (unlikely (src->status)) {
1002 status = src->status;
1006 status = _cairo_gl_check_composite_glyphs (composite,
1007 scaled_font, glyphs,
1009 if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
1012 info.font = scaled_font;
1013 info.glyphs = glyphs;
1014 info.num_glyphs = num_glyphs;
1015 info.use_mask = overlap || ! composite->is_bounded ||
1016 composite->op == CAIRO_OPERATOR_SOURCE;
1017 info.extents = composite->bounded;
1019 _cairo_scaled_font_freeze_cache (scaled_font);
1020 status = _cairo_gl_composite_glyphs_with_clip (dst, composite->op,
1026 _cairo_scaled_font_thaw_cache (scaled_font);
1030 cairo_surface_destroy (src);
1036 _cairo_gl_msaa_compositor_init (cairo_compositor_t *compositor,
1037 const cairo_compositor_t *delegate)
1039 compositor->delegate = delegate;
1040 compositor->lazy_init = TRUE;
1042 compositor->paint = _cairo_gl_msaa_compositor_paint;
1043 compositor->mask = _cairo_gl_msaa_compositor_mask;
1044 compositor->fill = _cairo_gl_msaa_compositor_fill;
1045 compositor->stroke = _cairo_gl_msaa_compositor_stroke;
1046 compositor->glyphs = _cairo_gl_msaa_compositor_glyphs;
1049 const cairo_compositor_t *
1050 _cairo_gl_msaa_compositor_get (void)
1052 static cairo_compositor_t compositor;
1053 if (compositor.delegate == NULL)
1054 _cairo_gl_msaa_compositor_init (&compositor,
1055 _cairo_gl_span_compositor_get ());