third_party/cairo/src/cairo-cogl-surface.c
static CoglTexture *
_cairo_cogl_acquire_generic_surface_texture (cairo_cogl_surface_t *reference_surface,
                                             cairo_surface_t      *surface,
                                             const cairo_matrix_t *pattern_matrix,
                                             cairo_matrix_t       *out_matrix,
                                             const cairo_bool_t    need_mirrored_texture,
                                             cairo_bool_t         *is_mirrored_texture)
{
    CoglTexture *texture = NULL;
    cairo_image_surface_t *image;
    cairo_image_surface_t *acquired_image = NULL;
    void *image_extra;
    cairo_image_surface_t *image_clone = NULL;
    CoglBitmap *bitmap;
    CoglError *error = NULL;
    cairo_surface_t *clone = NULL;
    CoglPixelFormat format;
    cairo_cogl_device_t *dev =
        to_device (reference_surface->base.device);
    ptrdiff_t stride;
    unsigned char *data;
    double xscale, yscale;

    *out_matrix = *pattern_matrix;
    *is_mirrored_texture = FALSE;

    if (_cairo_surface_is_image (surface)) {
        image = (cairo_image_surface_t *)surface;
    } else {
        cairo_status_t status =
            _cairo_surface_acquire_source_image (surface,
                                                 &acquired_image,
                                                 &image_extra);
        if (unlikely (status)) {
            g_warning ("acquire_source_image failed: %s [%d]",
                        cairo_status_to_string (status), status);
            return NULL;
        }
        image = acquired_image;
    }

    format = get_cogl_format_from_cairo_format (image->format);
    if (!format) {
        image_clone = _cairo_image_surface_coerce (image);
        if (unlikely (image_clone->base.status)) {
            g_warning ("image_surface_coerce failed");
            texture = NULL;
            goto BAIL;
        }

        format =
            get_cogl_format_from_cairo_format (image_clone->format);
        assert (format);

        image = image_clone;
    }

    if (image->stride < 0) {
        /* If the stride is negative, this modifies the data pointer so
         * that all of the pixels are read into the texture, but
         * upside-down. We then invert the matrix so the texture is
         * read from the bottom up instead of from the top down. */
        stride = -image->stride;
        data = image->data - stride * (image->height - 1);

        out_matrix->yx *= -1.0;
        out_matrix->yy *= -1.0;
        out_matrix->y0 += image->height;
    } else {
        stride = image->stride;
        data = image->data;
    }

    bitmap = cogl_bitmap_new_for_data (dev->cogl_context,
                                       image->width,
                                       image->height,
                                       format, /* incoming */
                                       stride,
                                       data);

    if (!dev->has_npots)
        texture =
            cogl_texture_2d_sliced_new_from_bitmap (bitmap,
                                                    COGL_TEXTURE_MAX_WASTE);
    else
        texture = cogl_texture_2d_new_from_bitmap (bitmap);

    /* The texture will have taken a reference on the bitmap */
    cogl_object_unref (bitmap);

    cogl_texture_set_components (texture,
        get_components_from_cairo_format (image->format));

    if (unlikely (!cogl_texture_allocate (texture, &error))) {
        g_warning ("Failed to allocate texture: %s", error->message);
        cogl_error_free (error);
        goto BAIL;
    }

    if (need_mirrored_texture) {
        int new_width = image->width;
        int new_height = image->height;

        /* If the device does not support npot textures, scale to the
         * next power of two as well */
        if (!dev->has_npots) {
            new_width = (int)pow (2, ceil (log2 (new_width)));
            new_height = (int)pow (2, ceil (log2 (new_height)));
        }

        texture = _cairo_cogl_scale_texture (dev->cogl_context,
                                             texture,
                                             new_width,
                                             new_height,
                                             TRUE,
                                             FALSE);
        if (unlikely (!texture))
            goto BAIL;

        *is_mirrored_texture = TRUE;
    } else if (!dev->has_npots) {
        /* We need to scale the texture up if the hardware does not
         * support npots */

        /* Get dimensions for the next power of two */
        int new_width = (int)pow (2, ceil (log2 (image->width)));
        int new_height = (int)pow (2, ceil (log2 (image->height)));

        texture = _cairo_cogl_scale_texture (dev->cogl_context,
                                             texture,
                                             new_width,
                                             new_height,
                                             FALSE,
                                             FALSE);
        if (unlikely (!texture))
            goto BAIL;
    }

    clone =
        _cairo_cogl_surface_create_full (dev,
                                         reference_surface->base.content,
                                         NULL,
                                         texture);
    if (unlikely (clone->status)) {
        g_warning ("Unable to create clone surface for texture");
        goto BAIL;
    }

    if (*is_mirrored_texture)
        ((cairo_cogl_surface_t *)clone)->is_mirrored_snapshot = TRUE;

    if (_cairo_surface_is_subsurface (surface))
        _cairo_surface_subsurface_set_snapshot (surface, clone);
    else
        _cairo_surface_attach_snapshot (surface, clone, NULL);

    /* Attaching the snapshot will take a reference on the clone surface... */
    cairo_surface_destroy (clone);
    clone = NULL;

    /* Convert from un-normalized source coordinates in backend
     * coordinates to normalized texture coordinates. */
    if (*is_mirrored_texture) {
        xscale = 0.5 / image->width;
        yscale = 0.5 / image->height;
    } else {
        xscale = 1.0 / image->width;
        yscale = 1.0 / image->height;
    }
    _cairo_cogl_matrix_all_scale (out_matrix, xscale, yscale);

    /* Release intermediate surface representations */
    if (image_clone) {
	cairo_surface_destroy (&image_clone->base);
        image_clone = NULL;
    }
    if (acquired_image) {
	_cairo_surface_release_source_image (surface,
                                             acquired_image,
                                             image_extra);
        acquired_image = NULL;
    }

    return texture;

BAIL:
    if (clone)
        cairo_surface_destroy (clone);
    if (image_clone)
	cairo_surface_destroy (&image_clone->base);
    if (acquired_image)
	_cairo_surface_release_source_image (surface,
                                             acquired_image,
                                             image_extra);
    if (texture)
        cogl_object_unref (texture);

    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_generic_surface_texture (cairo_cogl_surface_t *reference_surface,
                                             cairo_surface_t      *surface,
                                             const cairo_matrix_t *pattern_matrix,
                                             cairo_matrix_t       *out_matrix,
                                             const cairo_bool_t    need_mirrored_texture,
                                             cairo_bool_t         *is_mirrored_texture)
{
    CoglTexture *texture = NULL;
    cairo_image_surface_t *image;
    cairo_image_surface_t *acquired_image = NULL;
    void *image_extra;
    cairo_image_surface_t *image_clone = NULL;
    CoglBitmap *bitmap;
    CoglError *error = NULL;
    cairo_surface_t *clone = NULL;
    CoglPixelFormat format;
    cairo_cogl_device_t *dev =
        to_device (reference_surface->base.device);
    ptrdiff_t stride;
    unsigned char *data;
    double xscale, yscale;
    *out_matrix = *pattern_matrix;
    *is_mirrored_texture = FALSE;
    if (_cairo_surface_is_image (surface)) {
        image = (cairo_image_surface_t *)surface;
    } else {
        cairo_status_t status =
            _cairo_surface_acquire_source_image (surface,
                                                 &acquired_image,
                                                 &image_extra);
        if (unlikely (status)) {
            g_warning ("acquire_source_image failed: %s [%d]",
                        cairo_status_to_string (status), status);
            return NULL;
        }
        image = acquired_image;
    }
    format = get_cogl_format_from_cairo_format (image->format);
    if (!format) {
        image_clone = _cairo_image_surface_coerce (image);
        if (unlikely (image_clone->base.status)) {
            g_warning ("image_surface_coerce failed");
            texture = NULL;
            goto BAIL;
        }
        format =
            get_cogl_format_from_cairo_format (image_clone->format);
        assert (format);
        image = image_clone;
    }
    if (image->stride < 0) {
        stride = -image->stride;
        data = image->data - stride * (image->height - 1);
        out_matrix->yx *= -1.0;
        out_matrix->yy *= -1.0;
        out_matrix->y0 += image->height;
    } else {
        stride = image->stride;
        data = image->data;
    }
    bitmap = cogl_bitmap_new_for_data (dev->cogl_context,
                                       image->width,
                                       image->height,
                                       format, 
                                       stride,
                                       data);
    if (!dev->has_npots)
        texture =
            cogl_texture_2d_sliced_new_from_bitmap (bitmap,
                                                    COGL_TEXTURE_MAX_WASTE);
    else
        texture = cogl_texture_2d_new_from_bitmap (bitmap);
    cogl_object_unref (bitmap);
    cogl_texture_set_components (texture,
        get_components_from_cairo_format (image->format));
    if (unlikely (!cogl_texture_allocate (texture, &error))) {
        g_warning ("Failed to allocate texture: %s", error->message);
        cogl_error_free (error);
        goto BAIL;
    }
    if (need_mirrored_texture) {
        int new_width = image->width;
        int new_height = image->height;
        if (!dev->has_npots) {
            new_width = (int)pow (2, ceil (log2 (new_width)));
            new_height = (int)pow (2, ceil (log2 (new_height)));
        }
        texture = _cairo_cogl_scale_texture (dev->cogl_context,
                                             texture,
                                             new_width,
                                             new_height,
                                             TRUE,
                                             FALSE);
        if (unlikely (!texture))
            goto BAIL;
        *is_mirrored_texture = TRUE;
    } else if (!dev->has_npots) {
        int new_width = (int)pow (2, ceil (log2 (image->width)));
        int new_height = (int)pow (2, ceil (log2 (image->height)));
        texture = _cairo_cogl_scale_texture (dev->cogl_context,
                                             texture,
                                             new_width,
                                             new_height,
                                             FALSE,
                                             FALSE);
        if (unlikely (!texture))
            goto BAIL;
    }
    clone =
        _cairo_cogl_surface_create_full (dev,
                                         reference_surface->base.content,
                                         NULL,
                                         texture);
    if (unlikely (clone->status)) {
        g_warning ("Unable to create clone surface for texture");
        goto BAIL;
    }
    if (*is_mirrored_texture)
        ((cairo_cogl_surface_t *)clone)->is_mirrored_snapshot = TRUE;
    if (_cairo_surface_is_subsurface (surface))
        _cairo_surface_subsurface_set_snapshot (surface, clone);
    else
        _cairo_surface_attach_snapshot (surface, clone, NULL);
    cairo_surface_destroy (clone);
    clone = NULL;
    if (*is_mirrored_texture) {
        xscale = 0.5 / image->width;
        yscale = 0.5 / image->height;
    } else {
        xscale = 1.0 / image->width;
        yscale = 1.0 / image->height;
    }
    _cairo_cogl_matrix_all_scale (out_matrix, xscale, yscale);
    if (image_clone) {
	cairo_surface_destroy (&image_clone->base);
        image_clone = NULL;
    }
    if (acquired_image) {
	_cairo_surface_release_source_image (surface,
                                             acquired_image,
                                             image_extra);
        acquired_image = NULL;
    }
    return texture;
BAIL:
    if (clone)
        cairo_surface_destroy (clone);
    if (image_clone)
	cairo_surface_destroy (&image_clone->base);
    if (acquired_image)
	_cairo_surface_release_source_image (surface,
                                             acquired_image,
                                             image_extra);
    if (texture)
        cogl_object_unref (texture);
    return NULL;
}
static CoglTexture * _cairo_cogl_acquire_generic_surface_texture ( cairo_cogl_surface_t * reference_surface , cairo_surface_t * surface , const cairo_matrix_t * pattern_matrix , cairo_matrix_t * out_matrix , const cairo_bool_t need_mirrored_texture , cairo_bool_t * is_mirrored_texture ) { CoglTexture * texture = NULL ; cairo_image_surface_t * image ; cairo_image_surface_t * acquired_image = NULL ; void * image_extra ; cairo_image_surface_t * image_clone = NULL ; CoglBitmap * bitmap ; CoglError * error = NULL ; cairo_surface_t * clone = NULL ; CoglPixelFormat format ; cairo_cogl_device_t * dev = to_device ( reference_surface -> base . device ) ; ptrdiff_t stride ; unsigned char * data ; double xscale , yscale ; * out_matrix = * pattern_matrix ; * is_mirrored_texture = FALSE ; if ( _cairo_surface_is_image ( surface ) ) { image = ( cairo_image_surface_t * ) surface ; } else { cairo_status_t status = _cairo_surface_acquire_source_image ( surface , & acquired_image , & image_extra ) ; if ( unlikely ( status ) ) { g_warning ( " " , cairo_status_to_string ( status ) , status ) ; return NULL ; } image = acquired_image ; } format = get_cogl_format_from_cairo_format ( image -> format ) ; if ( ! format ) { image_clone = _cairo_image_surface_coerce ( image ) ; if ( unlikely ( image_clone -> base . status ) ) { g_warning ( " " ) ; texture = NULL ; goto BAIL ; } format = get_cogl_format_from_cairo_format ( image_clone -> format ) ; assert ( format ) ; image = image_clone ; } if ( image -> stride < 0 ) { stride = - image -> stride ; data = image -> data - stride * ( image -> height - 1 ) ; out_matrix -> yx *= -1.0 ; out_matrix -> yy *= -1.0 ; out_matrix -> y0 += image -> height ; } else { stride = image -> stride ; data = image -> data ; } bitmap = cogl_bitmap_new_for_data ( dev -> cogl_context , image -> width , image -> height , format , stride , data ) ; if ( ! dev -> has_npots ) texture = cogl_texture_2d_sliced_new_from_bitmap ( bitmap , COGL_TEXTURE_MAX_WASTE ) ; else texture = cogl_texture_2d_new_from_bitmap ( bitmap ) ; cogl_object_unref ( bitmap ) ; cogl_texture_set_components ( texture , get_components_from_cairo_format ( image -> format ) ) ; if ( unlikely ( ! cogl_texture_allocate ( texture , & error ) ) ) { g_warning ( " " , error -> message ) ; cogl_error_free ( error ) ; goto BAIL ; } if ( need_mirrored_texture ) { int new_width = image -> width ; int new_height = image -> height ; if ( ! dev -> has_npots ) { new_width = ( int ) pow ( 2 , ceil ( log2 ( new_width ) ) ) ; new_height = ( int ) pow ( 2 , ceil ( log2 ( new_height ) ) ) ; } texture = _cairo_cogl_scale_texture ( dev -> cogl_context , texture , new_width , new_height , TRUE , FALSE ) ; if ( unlikely ( ! texture ) ) goto BAIL ; * is_mirrored_texture = TRUE ; } else if ( ! dev -> has_npots ) { int new_width = ( int ) pow ( 2 , ceil ( log2 ( image -> width ) ) ) ; int new_height = ( int ) pow ( 2 , ceil ( log2 ( image -> height ) ) ) ; texture = _cairo_cogl_scale_texture ( dev -> cogl_context , texture , new_width , new_height , FALSE , FALSE ) ; if ( unlikely ( ! texture ) ) goto BAIL ; } clone = _cairo_cogl_surface_create_full ( dev , reference_surface -> base . content , NULL , texture ) ; if ( unlikely ( clone -> status ) ) { g_warning ( " " ) ; goto BAIL ; } if ( * is_mirrored_texture ) ( ( cairo_cogl_surface_t * ) clone ) -> is_mirrored_snapshot = TRUE ; if ( _cairo_surface_is_subsurface ( surface ) ) _cairo_surface_subsurface_set_snapshot ( surface , clone ) ; else _cairo_surface_attach_snapshot ( surface , clone , NULL ) ; cairo_surface_destroy ( clone ) ; clone = NULL ; if ( * is_mirrored_texture ) { xscale = 0.5 / image -> width ; yscale = 0.5 / image -> height ; } else { xscale = 1.0 / image -> width ; yscale = 1.0 / image -> height ; } _cairo_cogl_matrix_all_scale ( out_matrix , xscale , yscale ) ; if ( image_clone ) { cairo_surface_destroy ( & image_clone -> base ) ; image_clone = NULL ; } if ( acquired_image ) { _cairo_surface_release_source_image ( surface , acquired_image , image_extra ) ; acquired_image = NULL ; } return texture ; BAIL : if ( clone ) cairo_surface_destroy ( clone ) ; if ( image_clone ) cairo_surface_destroy ( & image_clone -> base ) ; if ( acquired_image ) _cairo_surface_release_source_image ( surface , acquired_image , image_extra ) ; if ( texture ) cogl_object_unref ( texture ) ; 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
/* If the stride is negative, this modifies the data pointer so
         * that all of the pixels are read into the texture, but
         * upside-down. We then invert the matrix so the texture is
         * read from the bottom up instead of from the top down. */ /* incoming */ /* The texture will have taken a reference on the bitmap */ /* If the device does not support npot textures, scale to the
         * next power of two as well */ /* We need to scale the texture up if the hardware does not
         * support npots */ /* Get dimensions for the next power of two */ /* Attaching the snapshot will take a reference on the clone surface... */ /* Convert from un-normalized source coordinates in backend
     * coordinates to normalized texture coordinates. */ /* Release intermediate surface representations */