third_party/cairo/src/cairo-cogl-surface.c
static CoglTexture *
_cairo_cogl_acquire_pattern_texture (const cairo_pattern_t           *pattern,
				     cairo_cogl_surface_t            *destination,
				     const cairo_rectangle_int_t     *extents,
				     cairo_cogl_texture_attributes_t *attributes,
                                     cairo_path_fixed_t              *tex_clip)
{
    CoglTexture *texture = NULL;
    cairo_cogl_device_t *dev = to_device (destination->base.device);
    cairo_bool_t is_mirrored_texture;
    cairo_bool_t need_mirrored_texture =
        (pattern->extend == CAIRO_EXTEND_REFLECT &&
         !dev->has_mirrored_repeat);

    switch ((int)pattern->type)
    {
    case CAIRO_PATTERN_TYPE_SURFACE: {
        cairo_cogl_surface_t *clone;
        cairo_surface_t *surface = ((cairo_surface_pattern_t *)pattern)->surface;

        clone = (cairo_cogl_surface_t *)
            _cairo_surface_has_snapshot (surface,
                                         &_cairo_cogl_surface_backend);
        if (clone && clone->texture)
            if ((!need_mirrored_texture) || clone->is_mirrored_snapshot)
            {
                texture = cogl_object_ref (clone->texture);
                attributes->matrix = pattern->matrix;
                is_mirrored_texture = clone->is_mirrored_snapshot;

                /* Convert from un-normalized source coordinates in
                 * backend coordinates to normalized texture
                 * coordinates. */
                _cairo_cogl_matrix_all_scale (&attributes->matrix,
                                              1.0 / clone->width,
                                              1.0 / clone->height);
            };

        if (!texture) {
            cairo_rectangle_int_t surface_extents;
            cairo_surface_t *unwrapped =
                _cairo_surface_get_source (surface, &surface_extents);

            if (_cairo_surface_is_recording (surface)) {
                texture =
                    _cairo_cogl_acquire_recording_surface_texture (destination,
                                                                   surface,
                                                                   extents,
                                                                   &pattern->matrix,
                                                                   &attributes->matrix,
                                                                   need_mirrored_texture,
                                                                   &is_mirrored_texture);
            } else if (surface->type == CAIRO_SURFACE_TYPE_COGL &&
                       ((cairo_cogl_surface_t *)unwrapped)->texture) {
                texture =
                    _cairo_cogl_acquire_cogl_surface_texture (destination,
                                                              unwrapped,
                                                              &surface_extents,
                                                              &pattern->matrix,
                                                              &attributes->matrix,
                                                              need_mirrored_texture,
                                                              &is_mirrored_texture);
            }
        }

        if (!texture)
            texture =
                _cairo_cogl_acquire_generic_surface_texture (destination,
                                                             surface,
                                                             &pattern->matrix,
                                                             &attributes->matrix,
                                                             need_mirrored_texture,
                                                             &is_mirrored_texture);

        if (unlikely (!texture))
            return NULL;

	attributes->extend = pattern->extend;
	attributes->filter =
            get_cogl_filter_for_filter (pattern->filter);
	attributes->has_component_alpha = pattern->has_component_alpha;

	attributes->s_wrap =
            get_cogl_wrap_mode_for_extend (pattern->extend, dev);
	attributes->t_wrap = attributes->s_wrap;

        /* In order to support CAIRO_EXTEND_NONE, we use the same wrap
         * mode as CAIRO_EXTEND_PAD, but pass a clip to the drawing
         * function to make sure that we never sample anything beyond
         * the texture boundaries. */
        if (pattern->extend == CAIRO_EXTEND_NONE && tex_clip)
            if (_cairo_cogl_create_tex_clip (tex_clip,
                                             attributes->matrix,
                                             is_mirrored_texture))
            {
                cogl_object_unref (texture);
                return NULL;
            }

	return texture;
    }
    case CAIRO_PATTERN_TYPE_RADIAL:
    case CAIRO_PATTERN_TYPE_MESH:
    case CAIRO_PATTERN_TYPE_RASTER_SOURCE: {
	cairo_surface_t *surface;
        cairo_matrix_t new_pattern_matrix;

	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
					      extents->width, extents->height);
	if (_cairo_surface_offset_paint (surface,
					 extents->x, extents->y,
					 CAIRO_OPERATOR_SOURCE,
					 pattern, NULL)) {
	    cairo_surface_destroy (surface);
	    return NULL;
	}

        cairo_matrix_init_translate (&new_pattern_matrix,
                                     -extents->x, -extents->y);

	texture =
            _cairo_cogl_acquire_generic_surface_texture (destination,
                                                         surface,
                                                         &new_pattern_matrix,
                                                         &attributes->matrix,
                                                         need_mirrored_texture,
                                                         &is_mirrored_texture);
	if (unlikely (!texture))
	    goto BAIL;

	attributes->extend = pattern->extend;
	attributes->filter = COGL_PIPELINE_FILTER_NEAREST;
	attributes->has_component_alpha = pattern->has_component_alpha;

	/* any pattern extend modes have already been dealt with... */
	attributes->s_wrap = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
	attributes->t_wrap = attributes->s_wrap;

        /* In order to support CAIRO_EXTEND_NONE, we use the same wrap
         * mode as CAIRO_EXTEND_PAD, but pass a clip to the drawing
         * function to make sure that we never sample anything beyond
         * the texture boundaries. */
        if (pattern->extend == CAIRO_EXTEND_NONE && tex_clip)
            if (_cairo_cogl_create_tex_clip (tex_clip,
                                             attributes->matrix,
                                             is_mirrored_texture))
            {
                cogl_object_unref (texture);
                cairo_surface_destroy (surface);
                return NULL;
            }

BAIL:
	cairo_surface_destroy (surface);

	return texture;
    }
    case CAIRO_PATTERN_TYPE_LINEAR: {
	cairo_linear_pattern_t *linear_pattern = (cairo_linear_pattern_t *)pattern;
	cairo_cogl_linear_gradient_t *gradient;
	cairo_cogl_linear_texture_entry_t *linear_texture;
	cairo_int_status_t status;
        double dist, scale;

	status = _cairo_cogl_get_linear_gradient (to_device(destination->base.device),
						  pattern->extend,
						  linear_pattern->base.n_stops,
						  linear_pattern->base.stops,
                                                  need_mirrored_texture,
						  &gradient);
	if (unlikely (status))
	    return NULL;

	linear_texture = _cairo_cogl_linear_gradient_texture_for_extend (gradient, pattern->extend);

	attributes->extend = pattern->extend;
	attributes->filter =
            get_cogl_filter_for_filter (pattern->filter);
	attributes->has_component_alpha = pattern->has_component_alpha;
	attributes->s_wrap =
            get_cogl_wrap_mode_for_extend (pattern->extend, dev);
	attributes->t_wrap = attributes->s_wrap;

        attributes->matrix = pattern->matrix;

	double a = linear_pattern->pd2.x - linear_pattern->pd1.x;
	double b = linear_pattern->pd2.y - linear_pattern->pd1.y;
	double angle = - atan2f (b, a);

	cairo_matrix_rotate (&attributes->matrix, angle);

	cairo_matrix_translate (&attributes->matrix,
				-linear_pattern->pd1.x,
				-linear_pattern->pd1.y);

	/* Convert from un-normalized source coordinates in backend
	 * coordinates to normalized texture coordinates. */
	dist = sqrtf (a*a + b*b);
        if (need_mirrored_texture)
            scale = 0.5 / dist;
        else
	    scale = 1.0 / dist;
        _cairo_cogl_matrix_all_scale (&attributes->matrix,
                                      scale, scale);

	return cogl_object_ref (linear_texture->texture);
    }
    default:
	g_warning ("Unsupported source type");
	return NULL;
    }
}
/* NB: a reference for the texture is transferred to the caller which should
 * be unrefed */
a reference for the texture is transferred to the caller which should
be unrefed
a reference for the texture is transferred to the caller which should be unrefed
static CoglTexture *
_cairo_cogl_acquire_pattern_texture (const cairo_pattern_t           *pattern,
				     cairo_cogl_surface_t            *destination,
				     const cairo_rectangle_int_t     *extents,
				     cairo_cogl_texture_attributes_t *attributes,
                                     cairo_path_fixed_t              *tex_clip)
{
    CoglTexture *texture = NULL;
    cairo_cogl_device_t *dev = to_device (destination->base.device);
    cairo_bool_t is_mirrored_texture;
    cairo_bool_t need_mirrored_texture =
        (pattern->extend == CAIRO_EXTEND_REFLECT &&
         !dev->has_mirrored_repeat);
    switch ((int)pattern->type)
    {
    case CAIRO_PATTERN_TYPE_SURFACE: {
        cairo_cogl_surface_t *clone;
        cairo_surface_t *surface = ((cairo_surface_pattern_t *)pattern)->surface;
        clone = (cairo_cogl_surface_t *)
            _cairo_surface_has_snapshot (surface,
                                         &_cairo_cogl_surface_backend);
        if (clone && clone->texture)
            if ((!need_mirrored_texture) || clone->is_mirrored_snapshot)
            {
                texture = cogl_object_ref (clone->texture);
                attributes->matrix = pattern->matrix;
                is_mirrored_texture = clone->is_mirrored_snapshot;
                _cairo_cogl_matrix_all_scale (&attributes->matrix,
                                              1.0 / clone->width,
                                              1.0 / clone->height);
            };
        if (!texture) {
            cairo_rectangle_int_t surface_extents;
            cairo_surface_t *unwrapped =
                _cairo_surface_get_source (surface, &surface_extents);
            if (_cairo_surface_is_recording (surface)) {
                texture =
                    _cairo_cogl_acquire_recording_surface_texture (destination,
                                                                   surface,
                                                                   extents,
                                                                   &pattern->matrix,
                                                                   &attributes->matrix,
                                                                   need_mirrored_texture,
                                                                   &is_mirrored_texture);
            } else if (surface->type == CAIRO_SURFACE_TYPE_COGL &&
                       ((cairo_cogl_surface_t *)unwrapped)->texture) {
                texture =
                    _cairo_cogl_acquire_cogl_surface_texture (destination,
                                                              unwrapped,
                                                              &surface_extents,
                                                              &pattern->matrix,
                                                              &attributes->matrix,
                                                              need_mirrored_texture,
                                                              &is_mirrored_texture);
            }
        }
        if (!texture)
            texture =
                _cairo_cogl_acquire_generic_surface_texture (destination,
                                                             surface,
                                                             &pattern->matrix,
                                                             &attributes->matrix,
                                                             need_mirrored_texture,
                                                             &is_mirrored_texture);
        if (unlikely (!texture))
            return NULL;
	attributes->extend = pattern->extend;
	attributes->filter =
            get_cogl_filter_for_filter (pattern->filter);
	attributes->has_component_alpha = pattern->has_component_alpha;
	attributes->s_wrap =
            get_cogl_wrap_mode_for_extend (pattern->extend, dev);
	attributes->t_wrap = attributes->s_wrap;
        if (pattern->extend == CAIRO_EXTEND_NONE && tex_clip)
            if (_cairo_cogl_create_tex_clip (tex_clip,
                                             attributes->matrix,
                                             is_mirrored_texture))
            {
                cogl_object_unref (texture);
                return NULL;
            }
	return texture;
    }
    case CAIRO_PATTERN_TYPE_RADIAL:
    case CAIRO_PATTERN_TYPE_MESH:
    case CAIRO_PATTERN_TYPE_RASTER_SOURCE: {
	cairo_surface_t *surface;
        cairo_matrix_t new_pattern_matrix;
	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
					      extents->width, extents->height);
	if (_cairo_surface_offset_paint (surface,
					 extents->x, extents->y,
					 CAIRO_OPERATOR_SOURCE,
					 pattern, NULL)) {
	    cairo_surface_destroy (surface);
	    return NULL;
	}
        cairo_matrix_init_translate (&new_pattern_matrix,
                                     -extents->x, -extents->y);
	texture =
            _cairo_cogl_acquire_generic_surface_texture (destination,
                                                         surface,
                                                         &new_pattern_matrix,
                                                         &attributes->matrix,
                                                         need_mirrored_texture,
                                                         &is_mirrored_texture);
	if (unlikely (!texture))
	    goto BAIL;
	attributes->extend = pattern->extend;
	attributes->filter = COGL_PIPELINE_FILTER_NEAREST;
	attributes->has_component_alpha = pattern->has_component_alpha;
	attributes->s_wrap = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
	attributes->t_wrap = attributes->s_wrap;
        if (pattern->extend == CAIRO_EXTEND_NONE && tex_clip)
            if (_cairo_cogl_create_tex_clip (tex_clip,
                                             attributes->matrix,
                                             is_mirrored_texture))
            {
                cogl_object_unref (texture);
                cairo_surface_destroy (surface);
                return NULL;
            }
BAIL:
	cairo_surface_destroy (surface);
	return texture;
    }
    case CAIRO_PATTERN_TYPE_LINEAR: {
	cairo_linear_pattern_t *linear_pattern = (cairo_linear_pattern_t *)pattern;
	cairo_cogl_linear_gradient_t *gradient;
	cairo_cogl_linear_texture_entry_t *linear_texture;
	cairo_int_status_t status;
        double dist, scale;
	status = _cairo_cogl_get_linear_gradient (to_device(destination->base.device),
						  pattern->extend,
						  linear_pattern->base.n_stops,
						  linear_pattern->base.stops,
                                                  need_mirrored_texture,
						  &gradient);
	if (unlikely (status))
	    return NULL;
	linear_texture = _cairo_cogl_linear_gradient_texture_for_extend (gradient, pattern->extend);
	attributes->extend = pattern->extend;
	attributes->filter =
            get_cogl_filter_for_filter (pattern->filter);
	attributes->has_component_alpha = pattern->has_component_alpha;
	attributes->s_wrap =
            get_cogl_wrap_mode_for_extend (pattern->extend, dev);
	attributes->t_wrap = attributes->s_wrap;
        attributes->matrix = pattern->matrix;
	double a = linear_pattern->pd2.x - linear_pattern->pd1.x;
	double b = linear_pattern->pd2.y - linear_pattern->pd1.y;
	double angle = - atan2f (b, a);
	cairo_matrix_rotate (&attributes->matrix, angle);
	cairo_matrix_translate (&attributes->matrix,
				-linear_pattern->pd1.x,
				-linear_pattern->pd1.y);
	dist = sqrtf (a*a + b*b);
        if (need_mirrored_texture)
            scale = 0.5 / dist;
        else
	    scale = 1.0 / dist;
        _cairo_cogl_matrix_all_scale (&attributes->matrix,
                                      scale, scale);
	return cogl_object_ref (linear_texture->texture);
    }
    default:
	g_warning ("Unsupported source type");
	return NULL;
    }
}
static CoglTexture * _cairo_cogl_acquire_pattern_texture ( const cairo_pattern_t * pattern , cairo_cogl_surface_t * destination , const cairo_rectangle_int_t * extents , cairo_cogl_texture_attributes_t * attributes , cairo_path_fixed_t * tex_clip ) { CoglTexture * texture = NULL ; cairo_cogl_device_t * dev = to_device ( destination -> base . device ) ; cairo_bool_t is_mirrored_texture ; cairo_bool_t need_mirrored_texture = ( pattern -> extend == CAIRO_EXTEND_REFLECT && ! dev -> has_mirrored_repeat ) ; switch ( ( int ) pattern -> type ) { case CAIRO_PATTERN_TYPE_SURFACE : { cairo_cogl_surface_t * clone ; cairo_surface_t * surface = ( ( cairo_surface_pattern_t * ) pattern ) -> surface ; clone = ( cairo_cogl_surface_t * ) _cairo_surface_has_snapshot ( surface , & _cairo_cogl_surface_backend ) ; if ( clone && clone -> texture ) if ( ( ! need_mirrored_texture ) || clone -> is_mirrored_snapshot ) { texture = cogl_object_ref ( clone -> texture ) ; attributes -> matrix = pattern -> matrix ; is_mirrored_texture = clone -> is_mirrored_snapshot ; _cairo_cogl_matrix_all_scale ( & attributes -> matrix , 1.0 / clone -> width , 1.0 / clone -> height ) ; } ; if ( ! texture ) { cairo_rectangle_int_t surface_extents ; cairo_surface_t * unwrapped = _cairo_surface_get_source ( surface , & surface_extents ) ; if ( _cairo_surface_is_recording ( surface ) ) { texture = _cairo_cogl_acquire_recording_surface_texture ( destination , surface , extents , & pattern -> matrix , & attributes -> matrix , need_mirrored_texture , & is_mirrored_texture ) ; } else if ( surface -> type == CAIRO_SURFACE_TYPE_COGL && ( ( cairo_cogl_surface_t * ) unwrapped ) -> texture ) { texture = _cairo_cogl_acquire_cogl_surface_texture ( destination , unwrapped , & surface_extents , & pattern -> matrix , & attributes -> matrix , need_mirrored_texture , & is_mirrored_texture ) ; } } if ( ! texture ) texture = _cairo_cogl_acquire_generic_surface_texture ( destination , surface , & pattern -> matrix , & attributes -> matrix , need_mirrored_texture , & is_mirrored_texture ) ; if ( unlikely ( ! texture ) ) return NULL ; attributes -> extend = pattern -> extend ; attributes -> filter = get_cogl_filter_for_filter ( pattern -> filter ) ; attributes -> has_component_alpha = pattern -> has_component_alpha ; attributes -> s_wrap = get_cogl_wrap_mode_for_extend ( pattern -> extend , dev ) ; attributes -> t_wrap = attributes -> s_wrap ; if ( pattern -> extend == CAIRO_EXTEND_NONE && tex_clip ) if ( _cairo_cogl_create_tex_clip ( tex_clip , attributes -> matrix , is_mirrored_texture ) ) { cogl_object_unref ( texture ) ; return NULL ; } return texture ; } case CAIRO_PATTERN_TYPE_RADIAL : case CAIRO_PATTERN_TYPE_MESH : case CAIRO_PATTERN_TYPE_RASTER_SOURCE : { cairo_surface_t * surface ; cairo_matrix_t new_pattern_matrix ; surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32 , extents -> width , extents -> height ) ; if ( _cairo_surface_offset_paint ( surface , extents -> x , extents -> y , CAIRO_OPERATOR_SOURCE , pattern , NULL ) ) { cairo_surface_destroy ( surface ) ; return NULL ; } cairo_matrix_init_translate ( & new_pattern_matrix , - extents -> x , - extents -> y ) ; texture = _cairo_cogl_acquire_generic_surface_texture ( destination , surface , & new_pattern_matrix , & attributes -> matrix , need_mirrored_texture , & is_mirrored_texture ) ; if ( unlikely ( ! texture ) ) goto BAIL ; attributes -> extend = pattern -> extend ; attributes -> filter = COGL_PIPELINE_FILTER_NEAREST ; attributes -> has_component_alpha = pattern -> has_component_alpha ; attributes -> s_wrap = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE ; attributes -> t_wrap = attributes -> s_wrap ; if ( pattern -> extend == CAIRO_EXTEND_NONE && tex_clip ) if ( _cairo_cogl_create_tex_clip ( tex_clip , attributes -> matrix , is_mirrored_texture ) ) { cogl_object_unref ( texture ) ; cairo_surface_destroy ( surface ) ; return NULL ; } BAIL : cairo_surface_destroy ( surface ) ; return texture ; } case CAIRO_PATTERN_TYPE_LINEAR : { cairo_linear_pattern_t * linear_pattern = ( cairo_linear_pattern_t * ) pattern ; cairo_cogl_linear_gradient_t * gradient ; cairo_cogl_linear_texture_entry_t * linear_texture ; cairo_int_status_t status ; double dist , scale ; status = _cairo_cogl_get_linear_gradient ( to_device ( destination -> base . device ) , pattern -> extend , linear_pattern -> base . n_stops , linear_pattern -> base . stops , need_mirrored_texture , & gradient ) ; if ( unlikely ( status ) ) return NULL ; linear_texture = _cairo_cogl_linear_gradient_texture_for_extend ( gradient , pattern -> extend ) ; attributes -> extend = pattern -> extend ; attributes -> filter = get_cogl_filter_for_filter ( pattern -> filter ) ; attributes -> has_component_alpha = pattern -> has_component_alpha ; attributes -> s_wrap = get_cogl_wrap_mode_for_extend ( pattern -> extend , dev ) ; attributes -> t_wrap = attributes -> s_wrap ; attributes -> matrix = pattern -> matrix ; double a = linear_pattern -> pd2 . x - linear_pattern -> pd1 . x ; double b = linear_pattern -> pd2 . y - linear_pattern -> pd1 . y ; double angle = - atan2f ( b , a ) ; cairo_matrix_rotate ( & attributes -> matrix , angle ) ; cairo_matrix_translate ( & attributes -> matrix , - linear_pattern -> pd1 . x , - linear_pattern -> pd1 . y ) ; dist = sqrtf ( a * a + b * b ) ; if ( need_mirrored_texture ) scale = 0.5 / dist ; else scale = 1.0 / dist ; _cairo_cogl_matrix_all_scale ( & attributes -> matrix , scale , scale ) ; return cogl_object_ref ( linear_texture -> texture ) ; } default : g_warning ( " " ) ; return NULL ; } }
NB: a reference for the texture is transferred to the caller which should
 be unrefed
NB : a reference for the texture is transferred to the caller which should be unrefed
/* Convert from un-normalized source coordinates in
                 * backend coordinates to normalized texture
                 * coordinates. */ /* In order to support CAIRO_EXTEND_NONE, we use the same wrap
         * mode as CAIRO_EXTEND_PAD, but pass a clip to the drawing
         * function to make sure that we never sample anything beyond
         * the texture boundaries. */ /* any pattern extend modes have already been dealt with... */ /* In order to support CAIRO_EXTEND_NONE, we use the same wrap
         * mode as CAIRO_EXTEND_PAD, but pass a clip to the drawing
         * function to make sure that we never sample anything beyond
         * the texture boundaries. */ /* Convert from un-normalized source coordinates in backend
	 * coordinates to normalized texture coordinates. */