rsvg_cairo_generate_mask (cairo_t * cr, RsvgMask * self, RsvgDrawingCtx * ctx, RsvgBbox * bbox)
{
    cairo_surface_t *surface;
    cairo_t *mask_cr, *save_cr;
    RsvgCairoRender *render = (RsvgCairoRender *) ctx->render;
    RsvgState *state = rsvg_current_state (ctx);
    guint8 *pixels;
    guint32 width = render->width, height = render->height;
    guint32 rowstride = width * 4, row, i;
    double affinesave[6];
    double sx, sy, sw, sh;
    gboolean nest = cr != render->initial_cr;

    pixels = g_try_malloc0 (height * rowstride);
    if (pixels == NULL)
          return;

    if (self->maskunits == objectBoundingBox)
        _rsvg_push_view_box (ctx, 1, 1);

    sx = _rsvg_css_normalize_length (&self->x, ctx, 'h');
    sy = _rsvg_css_normalize_length (&self->y, ctx, 'v');
    sw = _rsvg_css_normalize_length (&self->width, ctx, 'h');
    sh = _rsvg_css_normalize_length (&self->height, ctx, 'v');

    if (self->maskunits == objectBoundingBox)
        _rsvg_pop_view_box (ctx);

    surface = cairo_image_surface_create_for_data (pixels,
                                                   CAIRO_FORMAT_ARGB32, width, height, rowstride);
    cairo_surface_set_user_data (surface, &surface_pixel_data_key, pixels, (cairo_destroy_func_t) g_free);

    mask_cr = cairo_create (surface);
    save_cr = render->cr;
    render->cr = mask_cr;

    if (self->maskunits == objectBoundingBox)
        rsvg_cairo_add_clipping_rect (ctx,
                                      sx * bbox->w + bbox->x,
                                      sy * bbox->h + bbox->y, sw * bbox->w, sh * bbox->h);
    else
        rsvg_cairo_add_clipping_rect (ctx, sx, sy, sw, sh);

    /* Horribly dirty hack to have the bbox premultiplied to everything */
    if (self->contentunits == objectBoundingBox) {
        double bbtransform[6];
        bbtransform[0] = bbox->w;
        bbtransform[1] = 0.;
        bbtransform[2] = 0.;
        bbtransform[3] = bbox->h;
        bbtransform[4] = bbox->x;
        bbtransform[5] = bbox->y;
        for (i = 0; i < 6; i++)
            affinesave[i] = self->super.state->affine[i];
        _rsvg_affine_multiply (self->super.state->affine, bbtransform, self->super.state->affine);
        _rsvg_push_view_box (ctx, 1, 1);
    }

    rsvg_state_push (ctx);
    _rsvg_node_draw_children (&self->super, ctx, 0);
    rsvg_state_pop (ctx);

    if (self->contentunits == objectBoundingBox) {
        _rsvg_pop_view_box (ctx);
        for (i = 0; i < 6; i++)
            self->super.state->affine[i] = affinesave[i];
    }

    render->cr = save_cr;

    for (row = 0; row < height; row++) {
        guint8 *row_data = (pixels + (row * rowstride));
        for (i = 0; i < width; i++) {
            guint32 *pixel = (guint32 *) row_data + i;
            *pixel = ((((*pixel & 0x00ff0000) >> 16) * 13817 +
                       ((*pixel & 0x0000ff00) >> 8) * 46518 +
                       ((*pixel & 0x000000ff)) * 4688) * state->opacity);
        }
    }

    cairo_destroy (mask_cr);

    cairo_identity_matrix (cr);
    cairo_mask_surface (cr, surface,
                        nest ? 0 : render->offset_x,
                        nest ? 0 : render->offset_y);
    cairo_surface_destroy (surface);
}
rsvg_cairo_generate_mask (cairo_t * cr, RsvgMask * self, RsvgDrawingCtx * ctx, RsvgBbox * bbox)
{
    cairo_surface_t *surface;
    cairo_t *mask_cr, *save_cr;
    RsvgCairoRender *render = (RsvgCairoRender *) ctx->render;
    RsvgState *state = rsvg_current_state (ctx);
    guint8 *pixels;
    guint32 width = render->width, height = render->height;
    guint32 rowstride = width * 4, row, i;
    double affinesave[6];
    double sx, sy, sw, sh;
    gboolean nest = cr != render->initial_cr;

    pixels = g_try_malloc0 (height * rowstride);
    if (pixels == NULL)
          return;

    if (self->maskunits == objectBoundingBox)
        _rsvg_push_view_box (ctx, 1, 1);

    sx = _rsvg_css_normalize_length (&self->x, ctx, 'h');
    sy = _rsvg_css_normalize_length (&self->y, ctx, 'v');
    sw = _rsvg_css_normalize_length (&self->width, ctx, 'h');
    sh = _rsvg_css_normalize_length (&self->height, ctx, 'v');

    if (self->maskunits == objectBoundingBox)
        _rsvg_pop_view_box (ctx);

    surface = cairo_image_surface_create_for_data (pixels,
                                                   CAIRO_FORMAT_ARGB32, width, height, rowstride);
    cairo_surface_set_user_data (surface, &surface_pixel_data_key, pixels, (cairo_destroy_func_t) g_free);

    mask_cr = cairo_create (surface);
    save_cr = render->cr;
    render->cr = mask_cr;

    if (self->maskunits == objectBoundingBox)
        rsvg_cairo_add_clipping_rect (ctx,
                                      sx * bbox->w + bbox->x,
                                      sy * bbox->h + bbox->y, sw * bbox->w, sh * bbox->h);
    else
        rsvg_cairo_add_clipping_rect (ctx, sx, sy, sw, sh);

     
    if (self->contentunits == objectBoundingBox) {
        double bbtransform[6];
        bbtransform[0] = bbox->w;
        bbtransform[1] = 0.;
        bbtransform[2] = 0.;
        bbtransform[3] = bbox->h;
        bbtransform[4] = bbox->x;
        bbtransform[5] = bbox->y;
        for (i = 0; i < 6; i++)
            affinesave[i] = self->super.state->affine[i];
        _rsvg_affine_multiply (self->super.state->affine, bbtransform, self->super.state->affine);
        _rsvg_push_view_box (ctx, 1, 1);
    }

    rsvg_state_push (ctx);
    _rsvg_node_draw_children (&self->super, ctx, 0);
    rsvg_state_pop (ctx);

    if (self->contentunits == objectBoundingBox) {
        _rsvg_pop_view_box (ctx);
        for (i = 0; i < 6; i++)
            self->super.state->affine[i] = affinesave[i];
    }

    render->cr = save_cr;

    for (row = 0; row < height; row++) {
        guint8 *row_data = (pixels + (row * rowstride));
        for (i = 0; i < width; i++) {
            guint32 *pixel = (guint32 *) row_data + i;
            *pixel = ((((*pixel & 0x00ff0000) >> 16) * 13817 +
                       ((*pixel & 0x0000ff00) >> 8) * 46518 +
                       ((*pixel & 0x000000ff)) * 4688) * state->opacity);
        }
    }

    cairo_destroy (mask_cr);

    cairo_identity_matrix (cr);
    cairo_mask_surface (cr, surface,
                        nest ? 0 : render->offset_x,
                        nest ? 0 : render->offset_y);
    cairo_surface_destroy (surface);
}