static cairo_int_status_t
set_clip_region (cairo_composite_rectangles_t *extents)
{
    cairo_image_surface_t *dst = (cairo_image_surface_t *) extents->surface;
    cairo_region_t *region = _cairo_clip_get_region (extents->clip);
    pixman_region32_t *rgn = region ? &region->rgn : NULL;
    if (! pixman_image_set_clip_region32 (dst->pixman_image, rgn))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_qt_surface_set_clip (cairo_qt_surface_t *qs,
			    const cairo_clip_t *clip)
{
    cairo_int_status_t status;

    D(fprintf(stderr, "q[%p] intersect_clip_path %s\n", abstract_surface, path ? "(path)" : "(clear)"));

    if (clip == NULL) {
	_cairo_surface_clipper_reset (&qs->clipper);
        // How the clip path is reset depends on whether we own p or not
        if (qs->pixmap || qs->image) {
            // we own p
            qs->p->setClipping (false);
        } else {
            qs->p->restore ();
            qs->p->save ();
        }

        return CAIRO_INT_STATUS_SUCCESS;
    }

#if ENABLE_FAST_CLIP
    // Qt will implicitly enable clipping, and will use ReplaceClip
    // instead of IntersectClip if clipping was disabled before

    // Note: Qt is really bad at dealing with clip paths.  It doesn't
    // seem to usefully recognize rectangular paths, instead going down
    // extremely slow paths whenever a clip path is set.  So,
    // we do a bunch of work here to try to get rectangles or regions
    // down to Qt for clipping.

    cairo_region_t *clip_region = NULL;

    status = _cairo_clip_get_region (clip, &clip_region);
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
	// We weren't able to extract a region from the traps.
	// Just hand the path down to QPainter.
	status = (cairo_int_status_t)
	    _cairo_surface_clipper_set_clip (&qs->clipper, clip);
    } else if (status == CAIRO_INT_STATUS_SUCCESS) {
	_cairo_qt_surface_set_clip_region (qs, clip_region);
	status = CAIRO_INT_STATUS_SUCCESS;
    }
#else
    status = (cairo_int_status_t)
	_cairo_surface_clipper_set_clip (&qs->clipper, clip);
#endif

    return status;
}
cairo_status_t
_cairo_win32_display_surface_set_clip (cairo_win32_display_surface_t *surface,
				       cairo_clip_t *clip)
{
    char stack[512];
    cairo_rectangle_int_t extents;
    int num_rects;
    RGNDATA *data;
    size_t data_size;
    RECT *rects;
    int i;
    HRGN gdi_region;
    cairo_status_t status;
    cairo_region_t *region;

    /* The semantics we want is that any clip set by cairo combines
     * is intersected with the clip on device context that the
     * surface was created for. To implement this, we need to
     * save the original clip when first setting a clip on surface.
     */

    assert (_cairo_clip_is_region (clip));
    region = _cairo_clip_get_region (clip);
    if (region == NULL)
	return CAIRO_STATUS_SUCCESS;

    cairo_region_get_extents (region, &extents);
    num_rects = cairo_region_num_rectangles (region);

    /* XXX see notes in _cairo_win32_save_initial_clip --
     * this code will interact badly with a HDC which had an initial
     * world transform -- we should probably manually transform the
     * region rects, because SelectClipRgn takes device units, not
     * logical units (unlike IntersectClipRect).
     */

    data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT);
    if (data_size > sizeof (stack)) {
	data = malloc (data_size);
	if (!data)
	    return _cairo_error(CAIRO_STATUS_NO_MEMORY);
    } else
	data = (RGNDATA *)stack;

    data->rdh.dwSize = sizeof (RGNDATAHEADER);
    data->rdh.iType = RDH_RECTANGLES;
    data->rdh.nCount = num_rects;
    data->rdh.nRgnSize = num_rects * sizeof (RECT);
    data->rdh.rcBound.left = extents.x;
    data->rdh.rcBound.top = extents.y;
    data->rdh.rcBound.right = extents.x + extents.width;
    data->rdh.rcBound.bottom = extents.y + extents.height;

    rects = (RECT *)data->Buffer;
    for (i = 0; i < num_rects; i++) {
	cairo_rectangle_int_t rect;

	cairo_region_get_rectangle (region, i, &rect);

	rects[i].left   = rect.x;
	rects[i].top    = rect.y;
	rects[i].right  = rect.x + rect.width;
	rects[i].bottom = rect.y + rect.height;
    }

    gdi_region = ExtCreateRegion (NULL, data_size, data);
    if ((char *)data != stack)
	free (data);

    if (!gdi_region)
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    /* AND the new region into our DC */
    status = CAIRO_STATUS_SUCCESS;
    if (ExtSelectClipRgn (surface->win32.dc, gdi_region, RGN_AND) == ERROR)
	status = _cairo_win32_print_gdi_error (__FUNCTION__);

    DeleteObject (gdi_region);

    return status;
}
cairo_span_renderer_t *
_cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
					const cairo_pattern_t	*src,
					void			*abstract_dst,
					cairo_antialias_t	 antialias,
					const cairo_composite_rectangles_t *rects)
{
    cairo_gl_surface_t *dst = abstract_dst;
    cairo_gl_surface_span_renderer_t *renderer;
    cairo_status_t status;
    const cairo_rectangle_int_t *extents;

    status = _cairo_gl_surface_deferred_clear (dst);
    if (unlikely (status))
	return _cairo_span_renderer_create_in_error (status);

    renderer = calloc (1, sizeof (*renderer));
    if (unlikely (renderer == NULL))
	return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);

    renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy;
    if (rects->is_bounded) {
	renderer->base.render_rows = _cairo_gl_render_bounded_spans;
        renderer->base.finish =      _cairo_gl_finish_bounded_spans;
	extents = &rects->bounded;
    } else {
	renderer->base.render_rows = _cairo_gl_render_unbounded_spans;
        renderer->base.finish =      _cairo_gl_finish_unbounded_spans;
	extents = &rects->unbounded;
    }
    renderer->xmin = extents->x;
    renderer->xmax = extents->x + extents->width;
    renderer->ymin = extents->y;
    renderer->ymax = extents->y + extents->height;

    status = _cairo_gl_composite_init (&renderer->setup,
                                       op, dst,
                                       FALSE, extents);
    if (unlikely (status))
        goto FAIL;

    status = _cairo_gl_composite_set_source (&renderer->setup, src,
                                             extents->x, extents->y,
                                             extents->x, extents->y,
                                             extents->width, extents->height);
    if (unlikely (status))
        goto FAIL;

    _cairo_gl_composite_set_spans (&renderer->setup);
    _cairo_gl_composite_set_clip_region (&renderer->setup,
					 _cairo_clip_get_region (rects->clip));

    status = _cairo_gl_composite_begin (&renderer->setup, &renderer->ctx);
    if (unlikely (status))
        goto FAIL;

    return &renderer->base;

FAIL:
    _cairo_gl_composite_fini (&renderer->setup);
    free (renderer);
    return _cairo_span_renderer_create_in_error (status);
}
Beispiel #5
0
static cairo_status_t
i965_spans_init (i965_spans_t *spans,
		 i965_surface_t *dst,
		 cairo_operator_t op,
		 const cairo_pattern_t *pattern,
		 cairo_antialias_t antialias,
		 cairo_clip_t *clip,
		 const cairo_composite_rectangles_t *extents)
{
    cairo_status_t status;

    spans->device = i965_device (dst);
    i965_shader_init (&spans->shader, dst, op);

    spans->is_bounded = extents->is_bounded;
    if (extents->is_bounded) {
	if (antialias == CAIRO_ANTIALIAS_NONE)
	    spans->renderer.render_rows = i965_bounded_spans_mono;
	else
	    spans->renderer.render_rows = i965_bounded_spans;

	spans->extents = &extents->bounded;
    } else {
	if (antialias == CAIRO_ANTIALIAS_NONE)
	    spans->renderer.render_rows = i965_unbounded_spans_mono;
	else
	    spans->renderer.render_rows = i965_unbounded_spans;

	spans->extents = &extents->unbounded;
    }
    spans->xmin = spans->extents->x;
    spans->xmax = spans->extents->x + spans->extents->width;

    spans->clip_region = NULL;
    if (clip != NULL) {
	cairo_region_t *clip_region = NULL;

	status = _cairo_clip_get_region (clip, &clip_region);
	assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);

	if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
	    clip_region = NULL;

	spans->clip_region = clip_region;
	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
	    i965_shader_set_clip (&spans->shader, clip);
    }

    spans->head.next  = NULL;
    spans->head.bo    = NULL;
    spans->head.count = 0;
    spans->tail = &spans->head;

    if (spans->clip_region == NULL) {
	spans->get_rectangle = i965_spans_emit_rectangle;
    } else {
	spans->get_rectangle = i965_spans_accumulate_rectangle;
	spans->head.bo = intel_bo_create (&spans->device->intel,
					  I965_VERTEX_SIZE, I965_VERTEX_SIZE,
					  FALSE, I915_TILING_NONE, 0);
	if (unlikely (spans->head.bo == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	spans->vbo_base = intel_bo_map (&spans->device->intel, spans->head.bo);
    }
    spans->vbo_offset = 0;

    return i965_shader_acquire_pattern (&spans->shader,
					&spans->shader.source,
					pattern, &extents->bounded);
}
cairo_int_status_t
_cairo_gl_surface_show_glyphs (void			*abstract_dst,
			       cairo_operator_t		 op,
			       const cairo_pattern_t	*source,
			       cairo_glyph_t		*glyphs,
			       int			 num_glyphs,
			       cairo_scaled_font_t	*scaled_font,
			       cairo_clip_t		*clip,
			       int			*remaining_glyphs)
{
    cairo_gl_surface_t *dst = abstract_dst;
    cairo_rectangle_int_t surface_extents;
    cairo_rectangle_int_t extents;
    cairo_region_t *clip_region = NULL;
    cairo_solid_pattern_t solid_pattern;
    cairo_bool_t overlap, use_mask = FALSE;
    cairo_status_t status;

    if (! GLEW_ARB_vertex_buffer_object)
	return UNSUPPORTED ("requires ARB_vertex_buffer_object");

    if (! _cairo_gl_operator_is_supported (op))
	return UNSUPPORTED ("unsupported operator");

    if (! _cairo_operator_bounded_by_mask (op))
	use_mask |= TRUE;

    /* For CLEAR, cairo's rendering equation (quoting Owen's description in:
     * http://lists.cairographics.org/archives/cairo/2005-August/004992.html)
     * is:
     *     mask IN clip ? src OP dest : dest
     * or more simply:
     *     mask IN CLIP ? 0 : dest
     *
     * where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
     *
     * The model we use in _cairo_gl_set_operator() is Render's:
     *     src IN mask IN clip OP dest
     * which would boil down to:
     *     0 (bounded by the extents of the drawing).
     *
     * However, we can do a Render operation using an opaque source
     * and DEST_OUT to produce:
     *    1 IN mask IN clip DEST_OUT dest
     * which is
     *    mask IN clip ? 0 : dest
     */
    if (op == CAIRO_OPERATOR_CLEAR) {
	_cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
				   CAIRO_CONTENT_COLOR);
	source = &solid_pattern.base;
	op = CAIRO_OPERATOR_DEST_OUT;
    }

    /* For SOURCE, cairo's rendering equation is:
     *     (mask IN clip) ? src OP dest : dest
     * or more simply:
     *     (mask IN clip) ? src : dest.
     *
     * If we just used the Render equation, we would get:
     *     (src IN mask IN clip) OP dest
     * or:
     *     (src IN mask IN clip) bounded by extents of the drawing.
     *
     * The trick is that for GL blending, we only get our 4 source values
     * into the blender, and since we need all 4 components of source, we
     * can't also get the mask IN clip into the blender.  But if we did
     * two passes we could make it work:
     *     dest = (mask IN clip) DEST_OUT dest
     *     dest = src IN mask IN clip ADD dest
     *
     * But for now, composite via an intermediate mask.
     */
    if (op == CAIRO_OPERATOR_SOURCE)
	use_mask |= TRUE;

    /* XXX we don't need ownership of the font as we use a global
     * glyph cache -- but we do need scaled_glyph eviction notification. :-(
     */
    if (! _cairo_gl_surface_owns_font (dst, scaled_font))
	return UNSUPPORTED ("do not control font");

    /* If the glyphs overlap, we need to build an intermediate mask rather
     * then perform the compositing directly.
     */
    status = _cairo_scaled_font_glyph_device_extents (scaled_font,
						      glyphs, num_glyphs,
						      &extents,
						      &overlap);
    if (unlikely (status))
	return status;

    use_mask |= overlap;

    if (clip != NULL) {
	status = _cairo_clip_get_region (clip, &clip_region);
	/* the empty clip should never be propagated this far */
	assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
	if (unlikely (_cairo_status_is_error (status)))
	    return status;

	use_mask |= status == CAIRO_INT_STATUS_UNSUPPORTED;

	if (! _cairo_rectangle_intersect (&extents,
		                          _cairo_clip_get_extents (clip)))
	    goto EMPTY;
    }

    surface_extents.x = surface_extents.y = 0;
    surface_extents.width = dst->width;
    surface_extents.height = dst->height;
    if (! _cairo_rectangle_intersect (&extents, &surface_extents))
	goto EMPTY;

    if (use_mask) {
	return _cairo_gl_surface_show_glyphs_via_mask (dst, op,
			                               source,
			                               glyphs, num_glyphs,
						       &extents,
						       scaled_font,
						       clip,
						       remaining_glyphs);
    }

    return _render_glyphs (dst, extents.x, extents.y,
	                   op, source,
			   glyphs, num_glyphs, &extents,
			   scaled_font, clip_region, remaining_glyphs);

EMPTY:
    *remaining_glyphs = 0;
    if (! _cairo_operator_bounded_by_mask (op))
	return _cairo_surface_paint (&dst->base, op, source, clip);
    else
	return CAIRO_STATUS_SUCCESS;
}
cairo_rectangle_list_t *
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
{
#define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S))

    cairo_rectangle_list_t *list;
    cairo_rectangle_t *rectangles = NULL;
    cairo_region_t *region = NULL;
    cairo_int_status_t status;
    int n_rects = 0;
    int i;

    if (clip->all_clipped)
	goto DONE;

    if (!clip->path)
	return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);

    status = _cairo_clip_get_region (clip, &region);
    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
	goto DONE;
    } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
	return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
    } else if (unlikely (status)) {
	return ERROR_LIST (status);
    }

    n_rects = cairo_region_num_rectangles (region);
    if (n_rects) {
	rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
	if (unlikely (rectangles == NULL)) {
	    return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
	}

	for (i = 0; i < n_rects; ++i) {
	    cairo_rectangle_int_t clip_rect;

	    cairo_region_get_rectangle (region, i, &clip_rect);

	    if (! _cairo_clip_int_rect_to_user (gstate,
						&clip_rect,
						&rectangles[i]))
	    {
		free (rectangles);
		return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
	    }
	}
    }

 DONE:
    list = malloc (sizeof (cairo_rectangle_list_t));
    if (unlikely (list == NULL)) {
        free (rectangles);
	return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
    }

    list->status = CAIRO_STATUS_SUCCESS;
    list->rectangles = rectangles;
    list->num_rectangles = n_rects;
    return list;

#undef ERROR_LIST
}
Beispiel #8
0
cairo_int_status_t
i965_surface_glyphs (void			*abstract_surface,
		     cairo_operator_t		 op,
		     const cairo_pattern_t	*source,
		     cairo_glyph_t		*g,
		     int			 num_glyphs,
		     cairo_scaled_font_t	*scaled_font,
		     cairo_clip_t		*clip,
		     int *num_remaining)
{
    i965_surface_t *surface = abstract_surface;
    i965_surface_t *mask = NULL;
    i965_device_t *device;
    i965_glyphs_t glyphs;
    cairo_composite_rectangles_t extents;
    cairo_clip_t local_clip;
    cairo_bool_t have_clip = FALSE;
    cairo_bool_t overlap;
    cairo_region_t *clip_region = NULL;
    intel_bo_t *last_bo = NULL;
    cairo_scaled_glyph_t *glyph_cache[64];
    cairo_status_t status;
    int mask_x = 0, mask_y = 0;
    int i = 0;

    *num_remaining = 0;
    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
							  surface->intel.drm.width,
							  surface->intel.drm.height,
							  op, source,
							  scaled_font,
							  g, num_glyphs,
							  clip,
							  &overlap);
    if (unlikely (status))
	return status;

    if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents.mask))
	clip = NULL;

    if (clip != NULL && extents.is_bounded) {
	clip = _cairo_clip_init_copy (&local_clip, clip);
	status = _cairo_clip_rectangle (clip, &extents.bounded);
	if (unlikely (status))
	    return status;

	have_clip = TRUE;
    }

    if (overlap || ! extents.is_bounded) {
	cairo_format_t format;

	format = CAIRO_FORMAT_A8;
	if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
	    format = CAIRO_FORMAT_ARGB32;

	mask = (i965_surface_t *)
	    i965_surface_create_internal (&i965_device (surface)->intel.base,
					  format,
					  extents.bounded.width,
					  extents.bounded.height,
					  I965_TILING_DEFAULT,
					  TRUE);
	if (unlikely (mask->intel.drm.base.status))
	    return mask->intel.drm.base.status;

	status = _cairo_surface_paint (&mask->intel.drm.base,
				       CAIRO_OPERATOR_CLEAR,
				       &_cairo_pattern_clear.base,
				       NULL);
	if (unlikely (status)) {
	    cairo_surface_destroy (&mask->intel.drm.base);
	    return status;
	}

	i965_shader_init (&glyphs.shader, mask, CAIRO_OPERATOR_ADD);

	status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
					      &_cairo_pattern_white.base,
					      &extents.bounded);
	if (unlikely (status)) {
	    cairo_surface_destroy (&mask->intel.drm.base);
	    return status;
	}

	mask_x = -extents.bounded.x;
	mask_y = -extents.bounded.y;
    } else {
	i965_shader_init (&glyphs.shader, surface, op);

	status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
					      source, &extents.bounded);
	if (unlikely (status))
	    return status;

	if (clip != NULL) {
	    status = _cairo_clip_get_region (clip, &clip_region);
	    assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);

	    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
		i965_shader_set_clip (&glyphs.shader, clip);
	}
    }

    glyphs.head.next = NULL;
    glyphs.head.bo = NULL;
    glyphs.head.count = 0;
    glyphs.tail = &glyphs.head;

    device = i965_device (surface);
    if (mask != NULL || clip_region == NULL) {
	glyphs.get_rectangle = i965_glyphs_emit_rectangle;
    } else {
	glyphs.get_rectangle = i965_glyphs_accumulate_rectangle;
	glyphs.head.bo = intel_bo_create (&device->intel,
					  I965_VERTEX_SIZE, I965_VERTEX_SIZE,
					  FALSE, I915_TILING_NONE, 0);
	if (unlikely (glyphs.head.bo == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	glyphs.vbo_base = intel_bo_map (&device->intel, glyphs.head.bo);
    }
    glyphs.vbo_offset = 0;

    status = cairo_device_acquire (&device->intel.base.base);
    if (unlikely (status))
	goto CLEANUP_GLYPHS;

    _cairo_scaled_font_freeze_cache (scaled_font);
    //private = _cairo_scaled_font_get_device (scaled_font, device);
    if (scaled_font->surface_private == NULL) {
	scaled_font->surface_private = device;
	scaled_font->surface_backend = surface->intel.drm.base.backend;
	cairo_list_add (&scaled_font->link, &device->intel.fonts);
    }

    memset (glyph_cache, 0, sizeof (glyph_cache));

    for (i = 0; i < num_glyphs; i++) {
	cairo_scaled_glyph_t *scaled_glyph;
	int x, y, x1, x2, y1, y2;
	int cache_index = g[i].index % ARRAY_LENGTH (glyph_cache);
	intel_glyph_t *glyph;

	scaled_glyph = glyph_cache[cache_index];
	if (scaled_glyph == NULL ||
	    _cairo_scaled_glyph_index (scaled_glyph) != g[i].index)
	{
	    status = _cairo_scaled_glyph_lookup (scaled_font,
						 g[i].index,
						 CAIRO_SCALED_GLYPH_INFO_METRICS,
						 &scaled_glyph);
	    if (unlikely (status))
		goto FINISH;

	    glyph_cache[cache_index] = scaled_glyph;
	}

	if (unlikely (scaled_glyph->metrics.width  == 0 ||
		      scaled_glyph->metrics.height == 0))
	{
	    continue;
	}

	/* XXX glyph images are snapped to pixel locations */
	x = _cairo_lround (g[i].x);
	y = _cairo_lround (g[i].y);

	x1 = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
	y1 = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
	x2 = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
	y2 = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);

	if (x2 < extents.bounded.x ||
	    y2 < extents.bounded.y ||
	    x1 > extents.bounded.x + extents.bounded.width ||
	    y1 > extents.bounded.y + extents.bounded.height)
	{
	    continue;
	}

	if (scaled_glyph->surface_private == NULL) {
	    status = intel_get_glyph (&device->intel, scaled_font, scaled_glyph);
	    if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) {
		status = CAIRO_STATUS_SUCCESS;
		continue;
	    }
	    if (unlikely (status))
		goto FINISH;
	}
	glyph = intel_glyph_pin (scaled_glyph->surface_private);

	if (glyph->cache->buffer.bo != last_bo) {
	    intel_buffer_cache_t *cache = glyph->cache;

	    glyphs.shader.mask.type.vertex   = VS_GLYPHS;
	    glyphs.shader.mask.type.fragment = FS_GLYPHS;
	    glyphs.shader.mask.type.pattern  = PATTERN_BASE;

	    glyphs.shader.mask.base.bo = cache->buffer.bo;
	    glyphs.shader.mask.base.format = cache->buffer.format;
	    glyphs.shader.mask.base.width  = cache->buffer.width;
	    glyphs.shader.mask.base.height = cache->buffer.height;
	    glyphs.shader.mask.base.stride = cache->buffer.stride;
	    glyphs.shader.mask.base.filter = i965_filter (CAIRO_FILTER_NEAREST);
	    glyphs.shader.mask.base.extend = i965_extend (CAIRO_EXTEND_NONE);
	    glyphs.shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */

	    glyphs.shader.committed = FALSE;
	    status = i965_shader_commit (&glyphs.shader, device);
	    if (unlikely (status))
		goto FINISH;

	    last_bo = cache->buffer.bo;
	}

	x2 = x1 + glyph->width;
	y2 = y1 + glyph->height;

	if (mask_x)
	    x1 += mask_x, x2 += mask_x;
	if (mask_y)
	    y1 += mask_y, y2 += mask_y;

	i965_add_glyph_rectangle (&glyphs, x1, y1, x2, y2, glyph);
    }

    if (mask != NULL && clip_region != NULL)
	i965_clipped_vertices (device, &glyphs.head, clip_region);

    status = CAIRO_STATUS_SUCCESS;
  FINISH:
    _cairo_scaled_font_thaw_cache (scaled_font);
    cairo_device_release (surface->intel.drm.base.device);
  CLEANUP_GLYPHS:
    i965_shader_fini (&glyphs.shader);

    if (glyphs.head.bo != NULL) {
	struct i965_vbo *vbo, *next;

	intel_bo_destroy (&device->intel, glyphs.head.bo);
	for (vbo = glyphs.head.next; vbo != NULL; vbo = next) {
	    next = vbo->next;
	    intel_bo_destroy (&device->intel, vbo->bo);
	    free (vbo);
	}
    }

    if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) {
	cairo_path_fixed_t path;

	_cairo_path_fixed_init (&path);
	status = _cairo_scaled_font_glyph_path (scaled_font,
						g + i, num_glyphs - i,
						&path);
	if (mask_x | mask_y) {
	    _cairo_path_fixed_translate (&path,
					 _cairo_fixed_from_int (mask_x),
					 _cairo_fixed_from_int (mask_y));
	}
	if (likely (status == CAIRO_STATUS_SUCCESS)) {
	    status = surface->intel.drm.base.backend->fill (glyphs.shader.target,
							    glyphs.shader.op,
							    mask != NULL ? &_cairo_pattern_white.base : source,
							    &path,
							    CAIRO_FILL_RULE_WINDING,
							    0,
							    scaled_font->options.antialias,
							    clip);
	}
	_cairo_path_fixed_fini (&path);
    }

    if (mask != NULL) {
	if (likely (status == CAIRO_STATUS_SUCCESS)) {
	    status = i965_surface_mask_internal (surface, op, source, mask,
					         clip, &extents);
	}
	cairo_surface_finish (&mask->intel.drm.base);
	cairo_surface_destroy (&mask->intel.drm.base);
    }

    if (have_clip)
	_cairo_clip_fini (&local_clip);

    return status;
}
Beispiel #9
0
static cairo_status_t
i965_surface_mask_internal (i965_surface_t *dst,
			    cairo_operator_t		 op,
			    const cairo_pattern_t	*source,
			    i965_surface_t *mask,
			    cairo_clip_t		*clip,
			    const cairo_composite_rectangles_t *extents)
{
    i965_device_t *device;
    i965_shader_t shader;
    cairo_region_t *clip_region = NULL;
    cairo_status_t status;

    i965_shader_init (&shader, dst, op);

    status = i965_shader_acquire_pattern (&shader, &shader.source,
					  source, &extents->bounded);
    if (unlikely (status))
	return status;

    shader.mask.type.vertex = VS_NONE;
    shader.mask.type.fragment = FS_SURFACE;
    shader.mask.base.content = mask->intel.drm.base.content;
    shader.mask.base.filter = i965_filter (CAIRO_FILTER_NEAREST);
    shader.mask.base.extend = i965_extend (CAIRO_EXTEND_NONE);

    cairo_matrix_init_translate (&shader.mask.base.matrix,
				 -extents->bounded.x,
				 -extents->bounded.y);
    cairo_matrix_scale (&shader.mask.base.matrix,
			1. / mask->intel.drm.width,
			1. / mask->intel.drm.height);

    shader.mask.base.bo = to_intel_bo (mask->intel.drm.bo);
    shader.mask.base.format = mask->intel.drm.format;
    shader.mask.base.width = mask->intel.drm.width;
    shader.mask.base.height = mask->intel.drm.height;
    shader.mask.base.stride = mask->intel.drm.stride;

    if (clip != NULL) {
	status = _cairo_clip_get_region (clip, &clip_region);
	assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);

	if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
	    clip_region = NULL;

	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
	    i965_shader_set_clip (&shader, clip);
    }

    status = cairo_device_acquire (dst->intel.drm.base.device);
    if (unlikely (status))
	goto CLEANUP_SHADER;

    device = i965_device (dst);

    status = i965_shader_commit (&shader, device);
    if (unlikely (status))
	goto CLEANUP_DEVICE;

    if (clip_region != NULL) {
	unsigned int n, num_rectangles;

	num_rectangles = cairo_region_num_rectangles (clip_region);
	for (n = 0; n < num_rectangles; n++) {
	    cairo_rectangle_int_t rect;

	    cairo_region_get_rectangle (clip_region, n, &rect);

	    i965_shader_add_rectangle (&shader,
				       rect.x, rect.y,
				       rect.width, rect.height);
	}
    } else {
	i965_shader_add_rectangle (&shader,
				   extents->bounded.x,
				   extents->bounded.y,
				   extents->bounded.width,
				   extents->bounded.height);
    }

    if (! extents->is_bounded)
	status = i965_fixup_unbounded (dst, extents, clip);

  CLEANUP_DEVICE:
    cairo_device_release (&device->intel.base.base);
  CLEANUP_SHADER:
    i965_shader_fini (&shader);
    return status;
}