third_party/cairo/src/cairo-cogl-surface.c
static CoglTexture *
_cairo_cogl_acquire_recording_surface_texture (cairo_cogl_surface_t        *reference_surface,
                                               cairo_surface_t             *surface,
                                               const cairo_rectangle_int_t *extents,
                                               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_surface_t *clone = NULL;
    cairo_cogl_device_t *dev =
        to_device (reference_surface->base.device);
    cairo_matrix_t transform;
    int tex_height, tex_width;
    double xscale, yscale;

    *is_mirrored_texture = FALSE;

    /* We will pre-transform all of the drawing by the pattern matrix
     * and confine it to the required extents, so no later transform
     * will be required */
    cairo_matrix_init_translate (out_matrix, -extents->x, -extents->y);

    cairo_matrix_init_translate (&transform, extents->x, extents->y);
    cairo_matrix_multiply (&transform, &transform, pattern_matrix);

    if (!dev->has_npots) {
        /* Record to a texture sized to the next power of two */
        tex_width = (int)pow (2, ceil (log2 (extents->width)));
        tex_height = (int)pow (2, ceil (log2 (extents->height)));

        /* And scale accordingly */
        cairo_matrix_scale (&transform,
                            (double)extents->width / (double)tex_width,
                            (double)extents->height / (double)tex_height);
    } else {
        tex_width = extents->width;
        tex_height = extents->height;
    }

    texture = cogl_texture_2d_new_with_size (dev->cogl_context,
                                             tex_width,
                                             tex_height);
    if (unlikely (!texture)) {
        g_warning ("Failed to create texture for replaying recording "
                   "surface");
        goto BAIL;
    }

    cogl_texture_set_components (texture,
        get_components_from_cairo_content (surface->content));

    /* Do not attach this as a snapshot, as it only represents part of
     * the surface */
    clone =
        _cairo_cogl_surface_create_full (dev,
                                         reference_surface->base.content,
                                         NULL,
                                         texture);
    if (unlikely (_cairo_cogl_surface_ensure_framebuffer ((cairo_cogl_surface_t *)clone)))
    {
        g_warning ("Could not get framebuffer for replaying recording "
                   "surface");
        goto BAIL;
    }

    if (unlikely (_cairo_recording_surface_replay_with_clip (surface,
                                                             &transform,
                                                             clone,
                                                             NULL)))
    {
        g_warning ("Could not replay recording surface");
        goto BAIL;
    }
    _cairo_cogl_journal_flush ((cairo_cogl_surface_t *)clone);
    cairo_surface_destroy (clone);

    if (need_mirrored_texture) {
        /* Scale to the same image extents, but mirror the texture,
         * thereby making it larger */
        texture = _cairo_cogl_scale_texture (dev->cogl_context,
                                             texture,
                                             tex_width,
                                             tex_height,
                                             TRUE,
                                             FALSE);
        if (unlikely (!texture))
            goto BAIL;

        *is_mirrored_texture = TRUE;
    }

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

    return texture;

BAIL:
    if (clone)
        cairo_surface_destroy (clone);
    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_recording_surface_texture (cairo_cogl_surface_t        *reference_surface,
                                               cairo_surface_t             *surface,
                                               const cairo_rectangle_int_t *extents,
                                               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_surface_t *clone = NULL;
    cairo_cogl_device_t *dev =
        to_device (reference_surface->base.device);
    cairo_matrix_t transform;
    int tex_height, tex_width;
    double xscale, yscale;
    *is_mirrored_texture = FALSE;
    cairo_matrix_init_translate (out_matrix, -extents->x, -extents->y);
    cairo_matrix_init_translate (&transform, extents->x, extents->y);
    cairo_matrix_multiply (&transform, &transform, pattern_matrix);
    if (!dev->has_npots) {
        tex_width = (int)pow (2, ceil (log2 (extents->width)));
        tex_height = (int)pow (2, ceil (log2 (extents->height)));
        cairo_matrix_scale (&transform,
                            (double)extents->width / (double)tex_width,
                            (double)extents->height / (double)tex_height);
    } else {
        tex_width = extents->width;
        tex_height = extents->height;
    }
    texture = cogl_texture_2d_new_with_size (dev->cogl_context,
                                             tex_width,
                                             tex_height);
    if (unlikely (!texture)) {
        g_warning ("Failed to create texture for replaying recording "
                   "surface");
        goto BAIL;
    }
    cogl_texture_set_components (texture,
        get_components_from_cairo_content (surface->content));
    clone =
        _cairo_cogl_surface_create_full (dev,
                                         reference_surface->base.content,
                                         NULL,
                                         texture);
    if (unlikely (_cairo_cogl_surface_ensure_framebuffer ((cairo_cogl_surface_t *)clone)))
    {
        g_warning ("Could not get framebuffer for replaying recording "
                   "surface");
        goto BAIL;
    }
    if (unlikely (_cairo_recording_surface_replay_with_clip (surface,
                                                             &transform,
                                                             clone,
                                                             NULL)))
    {
        g_warning ("Could not replay recording surface");
        goto BAIL;
    }
    _cairo_cogl_journal_flush ((cairo_cogl_surface_t *)clone);
    cairo_surface_destroy (clone);
    if (need_mirrored_texture) {
        texture = _cairo_cogl_scale_texture (dev->cogl_context,
                                             texture,
                                             tex_width,
                                             tex_height,
                                             TRUE,
                                             FALSE);
        if (unlikely (!texture))
            goto BAIL;
        *is_mirrored_texture = TRUE;
    }
    if (*is_mirrored_texture) {
        xscale = 0.5 / extents->width;
        yscale = 0.5 / extents->height;
    } else {
        xscale = 1.0 / extents->width;
        yscale = 1.0 / extents->height;
    }
    _cairo_cogl_matrix_all_scale (out_matrix, xscale, yscale);
    return texture;
BAIL:
    if (clone)
        cairo_surface_destroy (clone);
    if (texture)
        cogl_object_unref (texture);
    return NULL;
}
static CoglTexture * _cairo_cogl_acquire_recording_surface_texture ( cairo_cogl_surface_t * reference_surface , cairo_surface_t * surface , const cairo_rectangle_int_t * extents , 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_surface_t * clone = NULL ; cairo_cogl_device_t * dev = to_device ( reference_surface -> base . device ) ; cairo_matrix_t transform ; int tex_height , tex_width ; double xscale , yscale ; * is_mirrored_texture = FALSE ; cairo_matrix_init_translate ( out_matrix , - extents -> x , - extents -> y ) ; cairo_matrix_init_translate ( & transform , extents -> x , extents -> y ) ; cairo_matrix_multiply ( & transform , & transform , pattern_matrix ) ; if ( ! dev -> has_npots ) { tex_width = ( int ) pow ( 2 , ceil ( log2 ( extents -> width ) ) ) ; tex_height = ( int ) pow ( 2 , ceil ( log2 ( extents -> height ) ) ) ; cairo_matrix_scale ( & transform , ( double ) extents -> width / ( double ) tex_width , ( double ) extents -> height / ( double ) tex_height ) ; } else { tex_width = extents -> width ; tex_height = extents -> height ; } texture = cogl_texture_2d_new_with_size ( dev -> cogl_context , tex_width , tex_height ) ; if ( unlikely ( ! texture ) ) { g_warning ( " " " " ) ; goto BAIL ; } cogl_texture_set_components ( texture , get_components_from_cairo_content ( surface -> content ) ) ; clone = _cairo_cogl_surface_create_full ( dev , reference_surface -> base . content , NULL , texture ) ; if ( unlikely ( _cairo_cogl_surface_ensure_framebuffer ( ( cairo_cogl_surface_t * ) clone ) ) ) { g_warning ( " " " " ) ; goto BAIL ; } if ( unlikely ( _cairo_recording_surface_replay_with_clip ( surface , & transform , clone , NULL ) ) ) { g_warning ( " " ) ; goto BAIL ; } _cairo_cogl_journal_flush ( ( cairo_cogl_surface_t * ) clone ) ; cairo_surface_destroy ( clone ) ; if ( need_mirrored_texture ) { texture = _cairo_cogl_scale_texture ( dev -> cogl_context , texture , tex_width , tex_height , TRUE , FALSE ) ; if ( unlikely ( ! texture ) ) goto BAIL ; * is_mirrored_texture = TRUE ; } if ( * is_mirrored_texture ) { xscale = 0.5 / extents -> width ; yscale = 0.5 / extents -> height ; } else { xscale = 1.0 / extents -> width ; yscale = 1.0 / extents -> height ; } _cairo_cogl_matrix_all_scale ( out_matrix , xscale , yscale ) ; return texture ; BAIL : if ( clone ) cairo_surface_destroy ( clone ) ; 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
/* We will pre-transform all of the drawing by the pattern matrix
     * and confine it to the required extents, so no later transform
     * will be required */ /* Record to a texture sized to the next power of two */ /* And scale accordingly */ /* Do not attach this as a snapshot, as it only represents part of
     * the surface */ /* Scale to the same image extents, but mirror the texture,
         * thereby making it larger */ /* Convert from un-normalized source coordinates in backend
     * coordinates to normalized texture coordinates. */