_set_source_rsvg_pattern (RsvgDrawingCtx * ctx,
                          RsvgPattern * rsvg_pattern, guint8 opacity, RsvgBbox bbox)
{
    RsvgCairoRender *render = (RsvgCairoRender *) ctx->render;
    RsvgPattern local_pattern = *rsvg_pattern;
    cairo_t *cr_render, *cr_pattern;
    cairo_pattern_t *pattern;
    cairo_surface_t *surface;
    cairo_matrix_t matrix;
    int i;
    double affine[6], caffine[6], bbwscale, bbhscale, scwscale, schscale;
    double taffine[6], patternw, patternh, patternx, patterny;
    int pw, ph;

    rsvg_pattern = &local_pattern;
    rsvg_pattern_fix_fallback (rsvg_pattern);
    cr_render = render->cr;
    _rsvg_affine_identity (affine);
    _rsvg_affine_identity (caffine);

    if (rsvg_pattern->obj_bbox)
        _rsvg_push_view_box (ctx, 1., 1.);

    patternx = _rsvg_css_normalize_length (&rsvg_pattern->x, ctx, 'h');
    patterny = _rsvg_css_normalize_length (&rsvg_pattern->y, ctx, 'v');
    patternw = _rsvg_css_normalize_length (&rsvg_pattern->width, ctx, 'h');
    patternh = _rsvg_css_normalize_length (&rsvg_pattern->height, ctx, 'v');

    if (rsvg_pattern->obj_bbox)
        _rsvg_pop_view_box (ctx);


    /* Work out the size of the rectangle so it takes into account the object bounding box */


    if (rsvg_pattern->obj_bbox) {
        bbwscale = bbox.w;
        bbhscale = bbox.h;
    } else {
        bbwscale = 1.0;
        bbhscale = 1.0;
    }

    _rsvg_affine_multiply (taffine, rsvg_pattern->affine, rsvg_current_state (ctx)->affine);

    scwscale = sqrt (taffine[0] * taffine[0] + taffine[2] * taffine[2]);
    schscale = sqrt (taffine[1] * taffine[1] + taffine[3] * taffine[3]);

    pw = patternw * bbwscale * scwscale;
    ph = patternh * bbhscale * schscale;

    scwscale = (double) pw / (double) (patternw * bbwscale);
    schscale = (double) ph / (double) (patternh * bbhscale);

    surface = cairo_surface_create_similar (cairo_get_target (cr_render),
                                            CAIRO_CONTENT_COLOR_ALPHA, pw, ph);
    cr_pattern = cairo_create (surface);

    /* Create the pattern coordinate system */
    if (rsvg_pattern->obj_bbox) {
        /* subtract the pattern origin */
        affine[4] = bbox.x + patternx * bbox.w;
        affine[5] = bbox.y + patterny * bbox.h;
    } else {
        /* subtract the pattern origin */
        affine[4] = patternx;
        affine[5] = patterny;
    }
    /* Apply the pattern transform */
    _rsvg_affine_multiply (affine, affine, rsvg_pattern->affine);

    /* Create the pattern contents coordinate system */
    if (rsvg_pattern->vbox.active) {
        /* If there is a vbox, use that */
        double w, h, x, y;
        w = patternw * bbwscale;
        h = patternh * bbhscale;
        x = 0;
        y = 0;
        rsvg_preserve_aspect_ratio (rsvg_pattern->preserve_aspect_ratio,
                                    rsvg_pattern->vbox.w, rsvg_pattern->vbox.h, &w, &h, &x, &y);

        x -= rsvg_pattern->vbox.x * w / rsvg_pattern->vbox.w;
        y -= rsvg_pattern->vbox.y * h / rsvg_pattern->vbox.h;

        caffine[0] = w / rsvg_pattern->vbox.w;
        caffine[3] = h / rsvg_pattern->vbox.h;
        caffine[4] = x;
        caffine[5] = y;
        _rsvg_push_view_box (ctx, rsvg_pattern->vbox.w, rsvg_pattern->vbox.h);
    } else if (rsvg_pattern->obj_cbbox) {
        /* If coords are in terms of the bounding box, use them */
        caffine[0] = bbox.w;
        caffine[3] = bbox.h;
        _rsvg_push_view_box (ctx, 1., 1.);
    }

    if (scwscale != 1.0 || schscale != 1.0) {
        double scalematrix[6];
        _rsvg_affine_scale (scalematrix, scwscale, schscale);
        _rsvg_affine_multiply (caffine, caffine, scalematrix);
        _rsvg_affine_scale (scalematrix, 1. / scwscale, 1. / schscale);
        _rsvg_affine_multiply (affine, scalematrix, affine);
    }

    /* Draw to another surface */
    render->cr = cr_pattern;

    /* Set up transformations to be determined by the contents units */
    rsvg_state_push (ctx);
    for (i = 0; i < 6; i++)
        rsvg_current_state (ctx)->personal_affine[i] =
            rsvg_current_state (ctx)->affine[i] = caffine[i];

    /* Draw everything */
    _rsvg_node_draw_children ((RsvgNode *) rsvg_pattern, ctx, 2);
    /* Return to the original coordinate system */
    rsvg_state_pop (ctx);

    /* Set the render to draw where it used to */
    render->cr = cr_render;

    pattern = cairo_pattern_create_for_surface (surface);
    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);

    cairo_matrix_init (&matrix, affine[0], affine[1], affine[2], affine[3], affine[4], affine[5]);


    cairo_matrix_invert (&matrix);
    cairo_pattern_set_matrix (pattern, &matrix);
    cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST);

    cairo_set_source (cr_render, pattern);

    cairo_pattern_destroy (pattern);
    cairo_destroy (cr_pattern);
    cairo_surface_destroy (surface);
    if (rsvg_pattern->obj_cbbox || rsvg_pattern->vbox.active)
        _rsvg_pop_view_box (ctx);
}
_set_source_rsvg_pattern (RsvgDrawingCtx * ctx,
                          RsvgPattern * rsvg_pattern, guint8 opacity, RsvgBbox bbox)
{
    RsvgCairoRender *render = (RsvgCairoRender *) ctx->render;
    RsvgPattern local_pattern = *rsvg_pattern;
    cairo_t *cr_render, *cr_pattern;
    cairo_pattern_t *pattern;
    cairo_surface_t *surface;
    cairo_matrix_t matrix;
    int i;
    double affine[6], caffine[6], bbwscale, bbhscale, scwscale, schscale;
    double taffine[6], patternw, patternh, patternx, patterny;
    int pw, ph;

    rsvg_pattern = &local_pattern;
    rsvg_pattern_fix_fallback (rsvg_pattern);
    cr_render = render->cr;
    _rsvg_affine_identity (affine);
    _rsvg_affine_identity (caffine);

    if (rsvg_pattern->obj_bbox)
        _rsvg_push_view_box (ctx, 1., 1.);

    patternx = _rsvg_css_normalize_length (&rsvg_pattern->x, ctx, 'h');
    patterny = _rsvg_css_normalize_length (&rsvg_pattern->y, ctx, 'v');
    patternw = _rsvg_css_normalize_length (&rsvg_pattern->width, ctx, 'h');
    patternh = _rsvg_css_normalize_length (&rsvg_pattern->height, ctx, 'v');

    if (rsvg_pattern->obj_bbox)
        _rsvg_pop_view_box (ctx);


     


    if (rsvg_pattern->obj_bbox) {
        bbwscale = bbox.w;
        bbhscale = bbox.h;
    } else {
        bbwscale = 1.0;
        bbhscale = 1.0;
    }

    _rsvg_affine_multiply (taffine, rsvg_pattern->affine, rsvg_current_state (ctx)->affine);

    scwscale = sqrt (taffine[0] * taffine[0] + taffine[2] * taffine[2]);
    schscale = sqrt (taffine[1] * taffine[1] + taffine[3] * taffine[3]);

    pw = patternw * bbwscale * scwscale;
    ph = patternh * bbhscale * schscale;

    scwscale = (double) pw / (double) (patternw * bbwscale);
    schscale = (double) ph / (double) (patternh * bbhscale);

    surface = cairo_surface_create_similar (cairo_get_target (cr_render),
                                            CAIRO_CONTENT_COLOR_ALPHA, pw, ph);
    cr_pattern = cairo_create (surface);

     
    if (rsvg_pattern->obj_bbox) {
         
        affine[4] = bbox.x + patternx * bbox.w;
        affine[5] = bbox.y + patterny * bbox.h;
    } else {
         
        affine[4] = patternx;
        affine[5] = patterny;
    }
     
    _rsvg_affine_multiply (affine, affine, rsvg_pattern->affine);

     
    if (rsvg_pattern->vbox.active) {
         
        double w, h, x, y;
        w = patternw * bbwscale;
        h = patternh * bbhscale;
        x = 0;
        y = 0;
        rsvg_preserve_aspect_ratio (rsvg_pattern->preserve_aspect_ratio,
                                    rsvg_pattern->vbox.w, rsvg_pattern->vbox.h, &w, &h, &x, &y);

        x -= rsvg_pattern->vbox.x * w / rsvg_pattern->vbox.w;
        y -= rsvg_pattern->vbox.y * h / rsvg_pattern->vbox.h;

        caffine[0] = w / rsvg_pattern->vbox.w;
        caffine[3] = h / rsvg_pattern->vbox.h;
        caffine[4] = x;
        caffine[5] = y;
        _rsvg_push_view_box (ctx, rsvg_pattern->vbox.w, rsvg_pattern->vbox.h);
    } else if (rsvg_pattern->obj_cbbox) {
         
        caffine[0] = bbox.w;
        caffine[3] = bbox.h;
        _rsvg_push_view_box (ctx, 1., 1.);
    }

    if (scwscale != 1.0 || schscale != 1.0) {
        double scalematrix[6];
        _rsvg_affine_scale (scalematrix, scwscale, schscale);
        _rsvg_affine_multiply (caffine, caffine, scalematrix);
        _rsvg_affine_scale (scalematrix, 1. / scwscale, 1. / schscale);
        _rsvg_affine_multiply (affine, scalematrix, affine);
    }

     
    render->cr = cr_pattern;

     
    rsvg_state_push (ctx);
    for (i = 0; i < 6; i++)
        rsvg_current_state (ctx)->personal_affine[i] =
            rsvg_current_state (ctx)->affine[i] = caffine[i];

     
    _rsvg_node_draw_children ((RsvgNode *) rsvg_pattern, ctx, 2);
     
    rsvg_state_pop (ctx);

     
    render->cr = cr_render;

    pattern = cairo_pattern_create_for_surface (surface);
    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);

    cairo_matrix_init (&matrix, affine[0], affine[1], affine[2], affine[3], affine[4], affine[5]);


    cairo_matrix_invert (&matrix);
    cairo_pattern_set_matrix (pattern, &matrix);
    cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST);

    cairo_set_source (cr_render, pattern);

    cairo_pattern_destroy (pattern);
    cairo_destroy (cr_pattern);
    cairo_surface_destroy (surface);
    if (rsvg_pattern->obj_cbbox || rsvg_pattern->vbox.active)
        _rsvg_pop_view_box (ctx);
}